Break content mask for hoverables (#3409)

Conrad Irwin created

Release Notes:

- N/A

Change summary

crates/editor2/src/element.rs        |  8 ++++++--
crates/gpui2/src/elements/overlay.rs |  8 +++++---
crates/gpui2/src/window.rs           | 18 ++++++++++++++++++
3 files changed, 29 insertions(+), 5 deletions(-)

Detailed changes

crates/editor2/src/element.rs 🔗

@@ -1055,7 +1055,9 @@ impl EditorElement {
                             list_origin.y -= layout.position_map.line_height + list_height;
                         }
 
-                        context_menu.draw(list_origin, available_space, cx);
+                        cx.break_content_mask(|cx| {
+                            context_menu.draw(list_origin, available_space, cx)
+                        });
                     }
 
                     if let Some((position, mut hover_popovers)) = layout.hover_popovers.take() {
@@ -1095,7 +1097,9 @@ impl EditorElement {
                                     popover_origin.x = popover_origin.x + x_out_of_bounds;
                                 }
 
-                                hover_popover.draw(popover_origin, available_space, cx);
+                                cx.break_content_mask(|cx| {
+                                    hover_popover.draw(popover_origin, available_space, cx)
+                                });
 
                                 current_y = popover_origin.y - HOVER_POPOVER_GAP;
                             }

crates/gpui2/src/elements/overlay.rs 🔗

@@ -144,9 +144,11 @@ impl Element for Overlay {
         }
 
         cx.with_element_offset(desired.origin - bounds.origin, |cx| {
-            for child in self.children {
-                child.paint(cx);
-            }
+            cx.break_content_mask(|cx| {
+                for child in self.children {
+                    child.paint(cx);
+                }
+            })
         })
     }
 }

crates/gpui2/src/window.rs 🔗

@@ -1752,6 +1752,24 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
         }
     }
 
+    /// Invoke the given function with the content mask reset to that
+    /// of the window.
+    fn break_content_mask<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
+        let mask = ContentMask {
+            bounds: Bounds {
+                origin: Point::default(),
+                size: self.window().viewport_size,
+            },
+        };
+        self.window_mut()
+            .current_frame
+            .content_mask_stack
+            .push(mask);
+        let result = f(self);
+        self.window_mut().current_frame.content_mask_stack.pop();
+        result
+    }
+
     /// Update the global element offset relative to the current offset. This is used to implement
     /// scrolling.
     fn with_element_offset<R>(