Decide whether to clip to visible bounds on a per-element basis

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/editor/src/element.rs                    | 3 ++-
crates/gpui/src/elements.rs                     | 6 ------
crates/gpui/src/elements/flex.rs                | 5 +++--
crates/gpui/src/elements/list.rs                | 3 ++-
crates/gpui/src/elements/mouse_event_handler.rs | 1 +
crates/gpui/src/elements/overlay.rs             | 6 +++++-
crates/gpui/src/elements/uniform_list.rs        | 4 +++-
crates/terminal/src/terminal_element.rs         | 2 ++
8 files changed, 18 insertions(+), 12 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -1729,7 +1729,8 @@ impl Element for EditorElement {
         layout: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
-        cx.scene.push_layer(Some(bounds));
+        let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
+        cx.scene.push_layer(Some(visible_bounds));
 
         let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
         let text_bounds = RectF::new(

crates/gpui/src/elements.rs 🔗

@@ -271,9 +271,6 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                 mut layout,
             } => {
                 let bounds = RectF::new(origin, size);
-                let visible_bounds = visible_bounds
-                    .intersection(bounds)
-                    .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
                 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
                 Lifecycle::PostPaint {
                     element,
@@ -292,9 +289,6 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                 ..
             } => {
                 let bounds = RectF::new(origin, bounds.size());
-                let visible_bounds = visible_bounds
-                    .intersection(bounds)
-                    .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
                 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
                 Lifecycle::PostPaint {
                     element,

crates/gpui/src/elements/flex.rs 🔗

@@ -241,11 +241,12 @@ impl Element for Flex {
         remaining_space: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
-        let mut remaining_space = *remaining_space;
+        let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
+        let mut remaining_space = *remaining_space;
         let overflowing = remaining_space < 0.;
         if overflowing {
-            cx.scene.push_layer(Some(bounds));
+            cx.scene.push_layer(Some(visible_bounds));
         }
 
         if let Some(scroll_state) = &self.scroll_state {

crates/gpui/src/elements/list.rs 🔗

@@ -261,7 +261,8 @@ impl Element for List {
         scroll_top: &mut ListOffset,
         cx: &mut PaintContext,
     ) {
-        cx.scene.push_layer(Some(bounds));
+        let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
+        cx.scene.push_layer(Some(visible_bounds));
 
         cx.scene
             .push_mouse_region(MouseRegion::new::<Self>(10, 0, bounds).on_scroll({

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -169,6 +169,7 @@ impl<Tag> Element for MouseEventHandler<Tag> {
         _: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
+        let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
         let hit_bounds = self.hit_bounds(visible_bounds);
         if let Some(style) = self.cursor_style {
             cx.scene.push_cursor_region(CursorRegion {

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

@@ -217,7 +217,11 @@ impl Element for Overlay {
                 ));
         }
 
-        self.child.paint(bounds.origin(), bounds, cx);
+        self.child.paint(
+            bounds.origin(),
+            RectF::new(Vector2F::zero(), cx.window_size),
+            cx,
+        );
         cx.scene.pop_stacking_context();
     }
 

crates/gpui/src/elements/uniform_list.rs 🔗

@@ -284,7 +284,9 @@ impl Element for UniformList {
         layout: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
-        cx.scene.push_layer(Some(bounds));
+        let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
+
+        cx.scene.push_layer(Some(visible_bounds));
 
         cx.scene.push_mouse_region(
             MouseRegion::new::<Self>(self.view_id, 0, visible_bounds).on_scroll({

crates/terminal/src/terminal_element.rs 🔗

@@ -726,6 +726,8 @@ impl Element for TerminalElement {
         layout: &mut Self::LayoutState,
         cx: &mut gpui::PaintContext,
     ) -> Self::PaintState {
+        let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
+
         //Setup element stuff
         let clip_bounds = Some(visible_bounds);