Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/element.rs      | 77 ++++++++++++++++++++++++----
crates/gpui3/src/elements/div.rs | 92 ++++-----------------------------
2 files changed, 78 insertions(+), 91 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -81,11 +81,17 @@ pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync
         }
     }
 
-    fn refine_style(&self, style: &mut Style, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
+    fn refine_style(
+        &self,
+        style: &mut Style,
+        bounds: Bounds<Pixels>,
+        active_state: &Mutex<InteractiveElementState>,
+        cx: &mut ViewContext<V>,
+    ) {
         let mouse_position = cx.mouse_position();
         let stateless = self.as_stateless();
-        if let Some(group_hover) = stateless.group_hover.as_ref() {
-            if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
+        if let Some(group_hover) = stateless.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);
                 }
@@ -94,12 +100,25 @@ pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync
         if bounds.contains_point(&mouse_position) {
             style.refine(&stateless.hover_style);
         }
+
+        if let Some(stateful) = self.as_stateful() {
+            let active_state = active_state.lock();
+            if active_state.group {
+                if let Some(group_style) = stateful.group_active_style.as_ref() {
+                    style.refine(&group_style.style);
+                }
+            }
+            if active_state.element {
+                style.refine(&stateful.active_style);
+            }
+        }
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
         pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
+        interactive_state: Arc<Mutex<InteractiveElementState>>,
         cx: &mut ViewContext<V>,
     ) {
         let stateless = self.as_stateless();
@@ -128,7 +147,7 @@ pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync
         }
 
         let hover_group_bounds = stateless
-            .group_hover
+            .group_hover_style
             .as_ref()
             .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
 
@@ -164,7 +183,32 @@ pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync
                         *pending_click.lock() = Some(event.clone());
                     }
                 });
-            };
+            }
+
+            if interactive_state.lock().is_none() {
+                let active_group_bounds = stateful
+                    .group_active_style
+                    .as_ref()
+                    .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
+                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
+                    if phase == DispatchPhase::Bubble {
+                        let group = active_group_bounds
+                            .map_or(false, |bounds| bounds.contains_point(&down.position));
+                        let element = bounds.contains_point(&down.position);
+                        if group || element {
+                            *interactive_state.lock() = InteractiveElementState { group, element };
+                            cx.notify();
+                        }
+                    }
+                });
+            } else {
+                cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
+                    if phase == DispatchPhase::Capture {
+                        *interactive_state.lock() = InteractiveElementState::default();
+                        cx.notify();
+                    }
+                });
+            }
         }
     }
 }
@@ -190,6 +234,8 @@ pub struct StatefulInteractivity<V: 'static + Send + Sync> {
     #[deref_mut]
     stateless: StatelessInteractivity<V>,
     pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
+    pub active_style: StyleRefinement,
+    pub group_active_style: Option<GroupStyle>,
 }
 
 impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
@@ -222,6 +268,8 @@ where
             id,
             stateless: StatelessInteractivity::default(),
             mouse_click_listeners: SmallVec::new(),
+            active_style: StyleRefinement::default(),
+            group_active_style: None,
         }
     }
 }
@@ -233,7 +281,7 @@ pub struct StatelessInteractivity<V> {
     pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
     pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
     pub hover_style: StyleRefinement,
-    pub group_hover: Option<GroupStyle>,
+    pub group_hover_style: Option<GroupStyle>,
 }
 
 pub struct GroupStyle {
@@ -270,11 +318,16 @@ impl GroupBounds {
     }
 }
 
-pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
-    cx.default_global::<GroupBounds>()
-        .0
-        .get(name)
-        .and_then(|bounds_stack| bounds_stack.last().cloned())
+#[derive(Copy, Clone, Default, Eq, PartialEq)]
+pub struct InteractiveElementState {
+    pub group: bool,
+    pub element: bool,
+}
+
+impl InteractiveElementState {
+    pub fn is_none(&self) -> bool {
+        !self.group && !self.element
+    }
 }
 
 impl<V> Default for StatelessInteractivity<V> {
@@ -286,7 +339,7 @@ impl<V> Default for StatelessInteractivity<V> {
             scroll_wheel_listeners: SmallVec::new(),
             key_listeners: SmallVec::new(),
             hover_style: StyleRefinement::default(),
-            group_hover: None,
+            group_hover_style: None,
         }
     }
 }

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

@@ -1,8 +1,8 @@
 use crate::{
-    Active, AnyElement, BorrowWindow, Bounds, DispatchPhase, Element, ElementFocusability,
-    ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners, Focusable,
-    GlobalElementId, GroupBounds, GroupStyle, Hover, IntoAnyElement, LayoutId, MouseDownEvent,
-    MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString,
+    Active, AnyElement, BorrowWindow, Bounds, Element, ElementFocusability, ElementId,
+    ElementInteractivity, Focus, FocusHandle, FocusListeners, Focusable, GlobalElementId,
+    GroupBounds, GroupStyle, Hover, InteractiveElementState, IntoAnyElement, LayoutId,
+    MouseDownEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString,
     StatefulInteractivity, StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive,
     Style, StyleRefinement, Styled, ViewContext,
 };
@@ -13,22 +13,10 @@ use std::sync::Arc;
 
 #[derive(Default)]
 pub struct DivState {
-    active_state: Arc<Mutex<ActiveState>>,
+    active_state: Arc<Mutex<InteractiveElementState>>,
     pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
 }
 
-#[derive(Copy, Clone, Default, Eq, PartialEq)]
-struct ActiveState {
-    group: bool,
-    element: bool,
-}
-
-impl ActiveState {
-    pub fn is_none(&self) -> bool {
-        !self.group && !self.element
-    }
-}
-
 #[derive(Default, Clone)]
 pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
 
@@ -60,8 +48,6 @@ pub struct Div<
     children: SmallVec<[AnyElement<V>; 2]>,
     group: Option<SharedString>,
     base_style: StyleRefinement,
-    active_style: StyleRefinement,
-    group_active: Option<GroupStyle>,
 }
 
 pub fn div<V>() -> Div<V, StatelessInteractivity<V>, NonFocusable>
@@ -74,8 +60,6 @@ where
         children: SmallVec::new(),
         group: None,
         base_style: StyleRefinement::default(),
-        active_style: StyleRefinement::default(),
-        group_active: None,
     }
 }
 
@@ -91,8 +75,6 @@ where
             children: self.children,
             group: self.group,
             base_style: self.base_style,
-            active_style: self.active_style,
-            group_active: self.group_active,
         }
     }
 }
@@ -171,52 +153,11 @@ where
     ) -> Style {
         let mut computed_style = Style::default();
         computed_style.refine(&self.base_style);
-
         self.focusability.refine_style(&mut computed_style, cx);
         self.interactivity
-            .refine_style(&mut computed_style, bounds, cx);
-
-        let active_state = *state.active_state.lock();
-        if active_state.group {
-            if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
-                computed_style.refine(style);
-            }
-        }
-        if active_state.element {
-            computed_style.refine(&self.active_style);
-        }
-
+            .refine_style(&mut computed_style, bounds, &state.active_state, cx);
         computed_style
     }
-
-    fn paint_active_listener(
-        &self,
-        bounds: Bounds<Pixels>,
-        group_bounds: Option<Bounds<Pixels>>,
-        active_state: Arc<Mutex<ActiveState>>,
-        cx: &mut ViewContext<V>,
-    ) {
-        if active_state.lock().is_none() {
-            cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
-                if phase == DispatchPhase::Bubble {
-                    let group =
-                        group_bounds.map_or(false, |bounds| bounds.contains_point(&down.position));
-                    let element = bounds.contains_point(&down.position);
-                    if group || element {
-                        *active_state.lock() = ActiveState { group, element };
-                        cx.notify();
-                    }
-                }
-            });
-        } else {
-            cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
-                if phase == DispatchPhase::Capture {
-                    *active_state.lock() = ActiveState::default();
-                    cx.notify();
-                }
-            });
-        }
-    }
 }
 
 impl<V, I> Div<V, I, NonFocusable>
@@ -231,8 +172,6 @@ where
             children: self.children,
             group: self.group,
             base_style: self.base_style,
-            active_style: self.active_style,
-            group_active: self.group_active,
         }
     }
 }
@@ -325,10 +264,6 @@ where
                 GroupBounds::push(group, bounds, cx);
             }
 
-            let active_group_bounds = this
-                .group_active
-                .as_ref()
-                .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
             let style = this.compute_style(bounds, element_state, cx);
             let z_index = style.z_index.unwrap_or(0);
 
@@ -336,15 +271,14 @@ where
             cx.stack(z_index, |cx| {
                 cx.stack(0, |cx| {
                     style.paint(bounds, cx);
-                    this.paint_active_listener(
+
+                    this.focusability.paint(bounds, cx);
+                    this.interactivity.paint(
                         bounds,
-                        active_group_bounds,
+                        element_state.pending_click.clone(),
                         element_state.active_state.clone(),
                         cx,
                     );
-                    this.focusability.paint(bounds, cx);
-                    this.interactivity
-                        .paint(bounds, element_state.pending_click.clone(), cx);
                 });
 
                 cx.stack(1, |cx| {
@@ -418,7 +352,7 @@ where
     fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
         let stateless = self.interactivity.as_stateless_mut();
         if let Some(group) = group {
-            stateless.group_hover = Some(GroupStyle { group, style });
+            stateless.group_hover_style = Some(GroupStyle { group, style });
         } else {
             stateless.hover_style = style;
         }
@@ -442,9 +376,9 @@ where
 {
     fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
         if let Some(group) = group {
-            self.group_active = Some(GroupStyle { group, style });
+            self.interactivity.group_active_style = Some(GroupStyle { group, style });
         } else {
-            self.active_style = style;
+            self.interactivity.active_style = style;
         }
     }
 }