Always pass parent origin when painting elements

Nathan Sobo created

Change summary

crates/gpui2/src/element.rs               | 10 +++--
crates/gpui2/src/elements/div.rs          | 24 +++++++-----
crates/gpui2/src/elements/hoverable.rs    |  6 ++-
crates/gpui2/src/elements/img.rs          |  9 +++-
crates/gpui2/src/elements/pressable.rs    |  6 ++-
crates/gpui2/src/elements/svg.rs          |  4 +
crates/gpui2/src/elements/text.rs         | 20 ++++++++--
crates/gpui2_macros/src/derive_element.rs |  5 +-
crates/storybook/src/collab_panel.rs      |  2 
crates/storybook/src/theme.rs             |  5 +-
crates/storybook/src/workspace.rs         | 50 +++++++++---------------
11 files changed, 79 insertions(+), 62 deletions(-)

Detailed changes

crates/gpui2/src/element.rs 🔗

@@ -19,6 +19,7 @@ pub trait Element<V: 'static>: 'static + IntoElement<V> {
     fn paint(
         &mut self,
         view: &mut V,
+        parent_origin: Vector2F,
         layout: &Layout,
         state: &mut Self::PaintState,
         cx: &mut PaintContext<V>,
@@ -110,9 +111,9 @@ impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
                 layout_id,
                 mut paint_state,
             } => match cx.computed_layout(layout_id) {
-                Ok(mut layout) => {
-                    layout.bounds = layout.bounds + parent_origin;
-                    self.element.paint(view, &layout, &mut paint_state, cx);
+                Ok(layout) => {
+                    self.element
+                        .paint(view, parent_origin, &layout, &mut paint_state, cx);
                     ElementPhase::PostPaint {
                         layout,
                         paint_state,
@@ -124,7 +125,8 @@ impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
                 layout,
                 mut paint_state,
             } => {
-                self.element.paint(view, &layout, &mut paint_state, cx);
+                self.element
+                    .paint(view, parent_origin, &layout, &mut paint_state, cx);
                 ElementPhase::PostPaint {
                     layout,
                     paint_state,

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

@@ -10,6 +10,7 @@ use crate::{
 };
 use anyhow::Result;
 use gpui::{
+    geometry::vector::Vector2F,
     platform::{MouseButton, MouseButtonEvent, MouseMovedEvent},
     scene::{self},
     LayoutId,
@@ -64,42 +65,45 @@ impl<V: 'static> Element<V> for Div<V> {
     fn paint(
         &mut self,
         view: &mut V,
+        parent_origin: Vector2F,
         layout: &Layout,
         _: &mut Self::PaintState,
         cx: &mut PaintContext<V>,
     ) where
         Self: Sized,
     {
+        let order = layout.order;
+        let bounds = layout.bounds + parent_origin;
         let style = self.computed_style();
         let pop_text_style = style.text_style(cx).map_or(false, |style| {
             cx.push_text_style(&style).log_err().is_some()
         });
-        style.paint_background(layout.bounds, cx);
-        self.interaction_handlers()
-            .paint(layout.order, layout.bounds, cx);
+        style.paint_background(bounds, cx);
+        self.interaction_handlers().paint(order, bounds, cx);
         for child in &mut self.children {
-            child.paint(view, layout.bounds.origin(), cx);
+            child.paint(view, bounds.origin(), cx);
         }
-        style.paint_foreground(layout.bounds, cx);
+        style.paint_foreground(bounds, cx);
         if pop_text_style {
             cx.pop_text_style();
         }
 
         if cx.is_inspector_enabled() {
-            self.paint_inspector(layout, cx);
+            self.paint_inspector(parent_origin, layout, cx);
         }
     }
 }
 
 impl<V: 'static> Div<V> {
-    fn paint_inspector(&self, layout: &Layout, cx: &mut PaintContext<V>) {
+    fn paint_inspector(&self, parent_origin: Vector2F, layout: &Layout, cx: &mut PaintContext<V>) {
         let style = self.styles.merged();
+        let bounds = layout.bounds + parent_origin;
 
-        let hovered = layout.bounds.contains_point(cx.mouse_position());
+        let hovered = bounds.contains_point(cx.mouse_position());
         if hovered {
             let rem_size = cx.rem_size();
             cx.scene.push_quad(scene::Quad {
-                bounds: layout.bounds,
+                bounds,
                 background: Some(hsla(0., 0., 1., 0.05).into()),
                 border: gpui::Border {
                     color: hsla(0., 0., 1., 0.2).into(),
@@ -110,7 +114,7 @@ impl<V: 'static> Div<V> {
                 },
                 corner_radii: CornerRadii::default()
                     .refined(&style.corner_radii)
-                    .to_gpui(layout.bounds.size(), rem_size),
+                    .to_gpui(bounds.size(), rem_size),
             })
         }
 

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

@@ -6,7 +6,7 @@ use crate::{
     style::{Style, StyleHelpers, Styleable},
 };
 use anyhow::Result;
-use gpui::{platform::MouseMovedEvent, LayoutId};
+use gpui::{geometry::vector::Vector2F, platform::MouseMovedEvent, LayoutId};
 use refineable::{CascadeSlot, Refineable, RefinementCascade};
 use smallvec::SmallVec;
 use std::{cell::Cell, rc::Rc};
@@ -56,6 +56,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
     fn paint(
         &mut self,
         view: &mut V,
+        parent_origin: Vector2F,
         layout: &Layout,
         paint_state: &mut Self::PaintState,
         cx: &mut PaintContext<V>,
@@ -78,7 +79,8 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
             }
         });
 
-        self.child.paint(view, layout, paint_state, cx);
+        self.child
+            .paint(view, parent_origin, layout, paint_state, cx);
     }
 }
 

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

@@ -2,6 +2,7 @@ use crate as gpui2;
 use crate::style::{StyleHelpers, Styleable};
 use crate::{style::Style, Element};
 use futures::FutureExt;
+use gpui::geometry::vector::Vector2F;
 use gpui::scene;
 use gpui2_macros::IntoElement;
 use refineable::RefinementCascade;
@@ -47,6 +48,7 @@ impl<V: 'static> Element<V> for Img {
     fn paint(
         &mut self,
         _: &mut V,
+        parent_origin: Vector2F,
         layout: &gpui::Layout,
         _: &mut Self::PaintState,
         cx: &mut crate::paint_context::PaintContext<V>,
@@ -54,8 +56,9 @@ impl<V: 'static> Element<V> for Img {
         Self: Sized,
     {
         let style = self.computed_style();
+        let bounds = layout.bounds + parent_origin;
 
-        style.paint_background(layout.bounds, cx);
+        style.paint_background(bounds, cx);
 
         if let Some(uri) = &self.uri {
             let image_future = cx.image_cache.get(uri.clone());
@@ -66,7 +69,7 @@ impl<V: 'static> Element<V> for Img {
             {
                 let rem_size = cx.rem_size();
                 cx.scene.push_image(scene::Image {
-                    bounds: layout.bounds,
+                    bounds,
                     border: gpui::Border {
                         color: style.border_color.unwrap_or_default().into(),
                         top: style.border_widths.top.to_pixels(rem_size),
@@ -74,7 +77,7 @@ impl<V: 'static> Element<V> for Img {
                         bottom: style.border_widths.bottom.to_pixels(rem_size),
                         left: style.border_widths.left.to_pixels(rem_size),
                     },
-                    corner_radii: style.corner_radii.to_gpui(layout.bounds.size(), rem_size),
+                    corner_radii: style.corner_radii.to_gpui(bounds.size(), rem_size),
                     grayscale: false,
                     data,
                 })

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

@@ -6,7 +6,7 @@ use crate::{
     style::{Style, StyleHelpers, Styleable},
 };
 use anyhow::Result;
-use gpui::{platform::MouseButtonEvent, LayoutId};
+use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
 use refineable::{CascadeSlot, Refineable, RefinementCascade};
 use smallvec::SmallVec;
 use std::{cell::Cell, rc::Rc};
@@ -56,6 +56,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
     fn paint(
         &mut self,
         view: &mut V,
+        parent_origin: Vector2F,
         layout: &Layout,
         paint_state: &mut Self::PaintState,
         cx: &mut PaintContext<V>,
@@ -80,7 +81,8 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
             }
         });
 
-        self.child.paint(view, layout, paint_state, cx);
+        self.child
+            .paint(view, parent_origin, layout, paint_state, cx);
     }
 }
 

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

@@ -3,6 +3,7 @@ use crate::{
     style::{Style, StyleHelpers, Styleable},
     Element, IntoElement, Layout, LayoutId, Rgba,
 };
+use gpui::geometry::vector::Vector2F;
 use refineable::RefinementCascade;
 use std::borrow::Cow;
 use util::ResultExt;
@@ -45,6 +46,7 @@ impl<V: 'static> Element<V> for Svg {
     fn paint(
         &mut self,
         _: &mut V,
+        parent_origin: Vector2F,
         layout: &Layout,
         _: &mut Self::PaintState,
         cx: &mut crate::paint_context::PaintContext<V>,
@@ -55,7 +57,7 @@ impl<V: 'static> Element<V> for Svg {
         if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
             if let Some(svg_tree) = cx.asset_cache.svg(path).log_err() {
                 let icon = scene::Icon {
-                    bounds: layout.bounds,
+                    bounds: layout.bounds + parent_origin,
                     svg: svg_tree,
                     path: path.clone(),
                     color: Rgba::from(fill_color).into(),

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

@@ -4,7 +4,11 @@ use crate::{
     paint_context::PaintContext,
 };
 use anyhow::Result;
-use gpui::{geometry::Size, text_layout::LineLayout, LayoutId};
+use gpui::{
+    geometry::{vector::Vector2F, Size},
+    text_layout::LineLayout,
+    LayoutId,
+};
 use parking_lot::Mutex;
 use std::sync::Arc;
 use util::arc_cow::ArcCow;
@@ -64,10 +68,13 @@ impl<V: 'static> Element<V> for Text {
     fn paint<'a>(
         &mut self,
         _view: &mut V,
+        parent_origin: Vector2F,
         layout: &Layout,
         paint_state: &mut Self::PaintState,
         cx: &mut PaintContext<V>,
     ) {
+        let bounds = layout.bounds + parent_origin;
+
         let line_layout;
         let line_height;
         {
@@ -83,10 +90,15 @@ impl<V: 'static> Element<V> for Text {
         let line =
             gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
 
-        let origin = layout.bounds.origin();
         // TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
-        let visible_bounds = layout.bounds;
-        line.paint(cx.scene, origin, visible_bounds, line_height, cx.legacy_cx);
+        let visible_bounds = bounds;
+        line.paint(
+            cx.scene,
+            bounds.origin(),
+            visible_bounds,
+            line_height,
+            cx.legacy_cx,
+        );
     }
 }
 

crates/gpui2_macros/src/derive_element.rs 🔗

@@ -77,11 +77,12 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
             fn paint(
                 &mut self,
                 view: &mut V,
-                layout: &gpui2::element::Layout,
+                parent_origin: gpui2::Vector2F,
+                _: &gpui2::element::Layout,
                 rendered_element: &mut Self::PaintState,
                 cx: &mut gpui2::element::PaintContext<V>,
             ) {
-                rendered_element.paint(view, layout.bounds.origin(), cx);
+                rendered_element.paint(view, parent_origin, cx);
             }
         }
 

crates/storybook/src/collab_panel.rs 🔗

@@ -33,7 +33,7 @@ impl<V: 'static> CollabPanelElement<V> {
             .fill(theme.middle.base.default.background)
             .child(
                 div()
-                    .full()
+                    .w_full()
                     .flex()
                     .flex_col()
                     // List Container

crates/storybook/src/theme.rs 🔗

@@ -2,7 +2,7 @@ use gpui2::{
     color::Hsla,
     element::{Element, PaintContext},
     layout_context::LayoutContext,
-    serde_json, AppContext, IntoElement, WindowContext,
+    serde_json, AppContext, IntoElement, Vector2F, WindowContext,
 };
 use serde::{de::Visitor, Deserialize, Deserializer};
 use std::{collections::HashMap, fmt, marker::PhantomData};
@@ -160,6 +160,7 @@ impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
     fn paint(
         &mut self,
         view: &mut V,
+        parent_origin: Vector2F,
         layout: &gpui2::Layout,
         state: &mut Self::PaintState,
         cx: &mut PaintContext<V>,
@@ -167,7 +168,7 @@ impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
         Self: Sized,
     {
         cx.push_theme(self.theme.clone());
-        self.child.paint(view, layout, state, cx);
+        self.child.paint(view, parent_origin, layout, state, cx);
         cx.pop_theme();
     }
 }

crates/storybook/src/workspace.rs 🔗

@@ -410,37 +410,25 @@ impl WorkspaceElement {
         div()
             .size_full()
             .flex()
-            .flex_row()
-            .child(collab_panel())
-            .child(collab_panel())
-
-        // div()
-        //     .size_full()
-        //     .flex()
-        //     .flex_col()
-        //     .font("Zed Sans Extended")
-        //     .gap_0()
-        //     .justify_start()
-        //     .items_start()
-        //     .text_color(theme.lowest.base.default.foreground)
-        //     // .fill(theme.middle.warning.default.background)
-        //     .child(titlebar())
-        //     .child(
-        //         div()
-        //             .flex_1()
-        //             .w_full()
-        //             .flex()
-        //             .flex_row()
-        //             .child(collab_panel())
-        //             // .child(
-        //             //     div()
-        //             //         .h_full()
-        //             //         .flex_1()
-        //             //         .fill(theme.highest.accent.default.background),
-        //             // )
-        //             .child(collab_panel()),
-        //     )
-        //     .child(statusbar())
+            .flex_col()
+            .font("Zed Sans Extended")
+            .gap_0()
+            .justify_start()
+            .items_start()
+            .text_color(theme.lowest.base.default.foreground)
+            // .fill(theme.middle.warning.default.background)
+            .child(titlebar())
+            .child(
+                div()
+                    .flex_1()
+                    .flex()
+                    .flex_row()
+                    .w_full()
+                    .child(collab_panel())
+                    .child(div().h_full().flex_1())
+                    .child(collab_panel()),
+            )
+            .child(statusbar())
     }
 }