WIP

Nathan Sobo created

Change summary

crates/editor2/src/element.rs             |   9 -
crates/gpui2/src/element.rs               |  53 --------
crates/gpui2/src/elements/div.rs          |  10 -
crates/gpui2/src/elements/img.rs          |   9 -
crates/gpui2/src/elements/node.rs         | 154 ++++++++++++------------
crates/gpui2/src/elements/svg.rs          |   9 -
crates/gpui2/src/elements/text.rs         |   9 -
crates/gpui2/src/elements/uniform_list.rs |  10 -
crates/gpui2/src/view.rs                  |  29 ----
9 files changed, 78 insertions(+), 214 deletions(-)

Detailed changes

crates/editor2/src/element.rs 🔗

@@ -2640,15 +2640,6 @@ impl Element<Editor> for EditorElement {
         cx.request_layout(&style, None)
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut Editor,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<Editor>,
-    ) {
-    }
-
     fn paint(
         &mut self,
         bounds: Bounds<gpui::Pixels>,

crates/gpui2/src/element.rs 🔗

@@ -26,14 +26,6 @@ pub trait Element<V: 'static> {
         cx: &mut ViewContext<V>,
     ) -> LayoutId;
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    );
-
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
@@ -70,7 +62,6 @@ pub trait ParentElement<V: 'static> {
 trait ElementObject<V> {
     fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
     fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
-    fn prepaint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
     fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
     fn measure(
         &mut self,
@@ -208,36 +199,6 @@ where
         };
     }
 
-    fn prepaint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
-        self.phase = match mem::take(&mut self.phase) {
-            ElementRenderPhase::LayoutRequested {
-                layout_id,
-                mut frame_state,
-            }
-            | ElementRenderPhase::LayoutComputed {
-                layout_id,
-                mut frame_state,
-                ..
-            } => {
-                let bounds = cx.layout_bounds(layout_id);
-                if let Some(id) = self.element.id() {
-                    cx.with_element_state(id, |element_state, cx| {
-                        let mut element_state = element_state.unwrap();
-                        self.element
-                            .prepaint(bounds, view_state, &mut element_state, cx);
-                        ((), element_state)
-                    });
-                } else {
-                    self.element
-                        .prepaint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
-                }
-                ElementRenderPhase::Painted
-            }
-
-            _ => panic!("must call layout before paint"),
-        };
-    }
-
     fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
@@ -322,10 +283,6 @@ impl<V> AnyElement<V> {
         self.0.paint(view_state, cx)
     }
 
-    pub fn prepaint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
-        self.0.prepaint(view_state, cx)
-    }
-
     /// Initializes this element and performs layout within the given available space to determine its size.
     pub fn measure(
         &mut self,
@@ -419,16 +376,6 @@ where
         rendered_element.layout(view_state, cx)
     }
 
-    fn prepaint(
-        &mut self,
-        _bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        rendered_element: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-        rendered_element.prepaint(view_state, cx)
-    }
-
     fn paint(
         &mut self,
         _bounds: Bounds<Pixels>,

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

@@ -265,16 +265,6 @@ where
         })
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-        todo!()
-    }
-
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,

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

@@ -94,15 +94,6 @@ where
         self.base.layout(view_state, element_state, cx)
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-    }
-
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,

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

@@ -274,9 +274,7 @@ pub trait InteractiveComponent<V: 'static> {
     }
 }
 
-pub trait StatefulInteractiveComponent<V: 'static> {
-    fn interactivity(&mut self) -> &mut StatefulInteractivity<V>;
-
+pub trait StatefulInteractiveComponent<V: 'static>: InteractiveComponent<V> {
     fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
     where
         Self: Sized,
@@ -525,23 +523,14 @@ pub struct FocusEvent {
 }
 
 pub struct Node<V> {
-    style: StyleRefinement,
     key_context: KeyContext,
     interactivity: Interactivity<V>,
     children: Vec<AnyElement<V>>,
 }
 
-impl<V> Node<V> {
-    fn compute_style(&self) -> Style {
-        let mut style = Style::default();
-        style.refine(&self.style);
-        style
-    }
-}
-
 impl<V> Styled for Node<V> {
     fn style(&mut self) -> &mut StyleRefinement {
-        &mut self.style
+        &mut self.interactivity.base_style
     }
 }
 
@@ -582,7 +571,7 @@ impl<V: 'static> Element<V> for Node<V> {
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<V>,
     ) -> crate::LayoutId {
-        let style = self.compute_style();
+        let style = self.interactivity().compute_style(None, cx);
         style.with_text_style(cx, |cx| {
             element_state.child_layout_ids = self
                 .children
@@ -593,20 +582,6 @@ impl<V: 'static> Element<V> for Node<V> {
         })
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        _: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-        for child in &mut self.children {
-            child.prepaint(view_state, cx);
-        }
-        self.interactivity
-            .refine_style(&mut self.style, bounds, view_state, cx);
-    }
-
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
@@ -614,7 +589,7 @@ impl<V: 'static> Element<V> for Node<V> {
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<V>,
     ) {
-        let style = self.compute_style();
+        let style = self.interactivity.compute_style(Some(bounds), cx);
         if style.visibility == Visibility::Hidden {
             return;
         }
@@ -671,12 +646,37 @@ impl<V: 'static> Element<V> for Node<V> {
     }
 }
 
+pub struct ComputedStyle {
+    base: StyleRefinement,
+    focus: StyleRefinement,
+    hover: StyleRefinement,
+    active: StyleRefinement,
+}
+
+pub struct StyleCascade {
+    pub base: StyleRefinement,
+    pub focus: StyleRefinement,
+    pub hover: StyleRefinement,
+    pub dragged_over: StyleRefinement,
+    pub active: StyleRefinement,
+}
+
 pub struct Interactivity<V> {
+    pub active: bool,
+    pub group_active: bool,
+    pub hovered: bool,
+    pub group_hovered: bool,
+    pub focused: bool,
+    pub scroll_offset: Point<Pixels>,
+    pub base_style: StyleRefinement,
+    pub focus_style: StyleRefinement,
     pub hover_style: StyleRefinement,
     pub group_hover_style: Option<GroupStyle>,
+    pub active_style: StyleRefinement,
+    pub group_active_style: Option<GroupStyle>,
     pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
     pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
-    group: Option<SharedString>,
+    pub group: Option<SharedString>,
     pub dispatch_context: KeyContext,
     pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
     pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
@@ -685,49 +685,68 @@ pub struct Interactivity<V> {
     pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
     pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
     pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
-    drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
-    scroll_offset: Point<Pixels>,
+    pub drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
+    pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
+    pub drag_listener: Option<DragListener<V>>,
+    pub hover_listener: Option<HoverListener<V>>,
+    pub tooltip_builder: Option<TooltipBuilder<V>>,
 }
 
 impl<V: 'static> Interactivity<V> {
-    fn refine_style(
-        &self,
-        style: &mut StyleRefinement,
-        bounds: Bounds<Pixels>,
-        cx: &mut ViewContext<V>,
-    ) {
-        let mouse_position = cx.mouse_position();
-        if let Some(group_hover) = self.group_hover_style.as_ref() {
-            if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
-                if group_bounds.contains_point(&mouse_position) {
-                    style.refine(&group_hover.style);
+    fn compute_style(&self, bounds: Option<Bounds<Pixels>>, cx: &mut ViewContext<V>) -> Style {
+        let mut style = Style::default();
+        style.refine(&self.base_style);
+        if self.focused {
+            style.refine(&self.focus_style);
+        }
+
+        if let Some(bounds) = bounds {
+            let mouse_position = cx.mouse_position();
+            if let Some(group_hover) = self.group_hover_style.as_ref() {
+                if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
+                    if group_bounds.contains_point(&mouse_position) {
+                        style.refine(&group_hover.style);
+                    }
                 }
             }
-        }
-        if bounds.contains_point(&mouse_position) {
-            style.refine(&self.hover_style);
-        }
+            if bounds.contains_point(&mouse_position) {
+                style.refine(&self.hover_style);
+            }
+
+            if let Some(drag) = cx.active_drag.take() {
+                for (state_type, group_drag_style) in &self.group_drag_over_styles {
+                    if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
+                        if *state_type == drag.view.entity_type()
+                            && group_bounds.contains_point(&mouse_position)
+                        {
+                            style.refine(&group_drag_style.style);
+                        }
+                    }
+                }
 
-        if let Some(drag) = cx.active_drag.take() {
-            for (state_type, group_drag_style) in &self.group_drag_over_styles {
-                if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
+                for (state_type, drag_over_style) in &self.drag_over_styles {
                     if *state_type == drag.view.entity_type()
-                        && group_bounds.contains_point(&mouse_position)
+                        && bounds.contains_point(&mouse_position)
                     {
-                        style.refine(&group_drag_style.style);
+                        style.refine(drag_over_style);
                     }
                 }
+
+                cx.active_drag = Some(drag);
             }
+        }
 
-            for (state_type, drag_over_style) in &self.drag_over_styles {
-                if *state_type == drag.view.entity_type() && bounds.contains_point(&mouse_position)
-                {
-                    style.refine(drag_over_style);
-                }
+        if self.group_active {
+            if let Some(group) = self.group_active_style.as_ref() {
+                style.refine(&group.style)
             }
+        }
 
-            cx.active_drag = Some(drag);
+        if self.active {
+            style.refine(&self.active_style)
         }
+
+        style
     }
 
     fn paint(&mut self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
@@ -863,32 +882,15 @@ impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Focusab
 impl<V: 'static, E: StatefulInteractiveComponent<V>> StatefulInteractiveComponent<V>
     for Focusable<V, E>
 {
-    fn interactivity(&mut self) -> &mut StatefulInteractivity<V> {
-        self.element.interactivity()
-    }
 }
 
 pub struct Stateful<V, E> {
     id: SharedString,
-    interactivity: StatefulInteractivity<V>,
     view_type: PhantomData<V>,
     element: E,
 }
 
-pub struct StatefulInteractivity<V> {
-    click_listeners: SmallVec<[ClickListener<V>; 2]>,
-    active_style: StyleRefinement,
-    group_active_style: Option<GroupStyle>,
-    drag_listener: Option<DragListener<V>>,
-    hover_listener: Option<HoverListener<V>>,
-    tooltip_builder: Option<TooltipBuilder<V>>,
-}
-
-impl<V: 'static, E> StatefulInteractiveComponent<V> for Stateful<V, E> {
-    fn interactivity(&mut self) -> &mut StatefulInteractivity<V> {
-        &mut self.interactivity
-    }
-}
+impl<V: 'static, E: InteractiveComponent<V>> StatefulInteractiveComponent<V> for Stateful<V, E> {}
 
 impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Stateful<V, E> {
     fn interactivity(&mut self) -> &mut Interactivity<V> {

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

@@ -84,15 +84,6 @@ where
         self.base.layout(view_state, element_state, cx)
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-    }
-
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,

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

@@ -121,15 +121,6 @@ impl<V: 'static> Element<V> for Text<V> {
         layout_id
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-    }
-
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,

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

@@ -152,16 +152,6 @@ impl<V: 'static> Element<V> for UniformList<V> {
         )
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
-    ) {
-        todo!()
-    }
-
     fn paint(
         &mut self,
         bounds: crate::Bounds<crate::Pixels>,

crates/gpui2/src/view.rs 🔗

@@ -147,7 +147,6 @@ pub struct AnyView {
     model: AnyModel,
     initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
     layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
-    prepaint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
     paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
 }
 
@@ -157,7 +156,6 @@ impl AnyView {
             model: self.model.downgrade(),
             initialize: self.initialize,
             layout: self.layout,
-            prepaint: self.prepaint,
             paint: self.paint,
         }
     }
@@ -169,7 +167,6 @@ impl AnyView {
                 model,
                 initialize: self.initialize,
                 layout: self.layout,
-                prepaint: self.prepaint,
                 paint: self.paint,
             }),
         }
@@ -201,7 +198,6 @@ impl<V: Render> From<View<V>> for AnyView {
             model: value.model.into_any(),
             initialize: any_view::initialize::<V>,
             layout: any_view::layout::<V>,
-            prepaint: any_view::prepaint::<V>,
             paint: any_view::paint::<V>,
         }
     }
@@ -232,16 +228,6 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
         (self.layout)(self, rendered_element, cx)
     }
 
-    fn prepaint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut ParentViewState,
-        rendered_element: &mut Self::ElementState,
-        cx: &mut ViewContext<ParentViewState>,
-    ) {
-        (self.prepaint)(self, rendered_element, cx)
-    }
-
     fn paint(
         &mut self,
         _bounds: Bounds<Pixels>,
@@ -257,7 +243,6 @@ pub struct AnyWeakView {
     model: AnyWeakModel,
     initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
     layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
-    prepaint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
     paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
 }
 
@@ -268,7 +253,6 @@ impl AnyWeakView {
             model,
             initialize: self.initialize,
             layout: self.layout,
-            prepaint: self.prepaint,
             paint: self.paint,
         })
     }
@@ -280,7 +264,6 @@ impl<V: Render> From<WeakView<V>> for AnyWeakView {
             model: view.model.into(),
             initialize: any_view::initialize::<V>,
             layout: any_view::layout::<V>,
-            prepaint: any_view::prepaint::<V>,
             paint: any_view::paint::<V>,
         }
     }
@@ -326,18 +309,6 @@ mod any_view {
         })
     }
 
-    pub(crate) fn prepaint<V: Render>(
-        view: &AnyView,
-        element: &mut Box<dyn Any>,
-        cx: &mut WindowContext,
-    ) {
-        cx.with_element_id(view.model.entity_id, |_, cx| {
-            let view = view.clone().downcast::<V>().unwrap();
-            let element = element.downcast_mut::<AnyElement<V>>().unwrap();
-            view.update(cx, |view, cx| element.prepaint(view, cx))
-        })
-    }
-
     pub(crate) fn paint<V: Render>(
         view: &AnyView,
         element: &mut Box<dyn Any>,