Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/element.rs              |  20 
crates/gpui3/src/elements.rs             |   7 
crates/gpui3/src/elements/clickable.rs   | 230 ----------
crates/gpui3/src/elements/div.rs         | 570 ++++++++++++++++++++++---
crates/gpui3/src/elements/div2.rs        | 498 ----------------------
crates/gpui3/src/elements/hoverable.rs   | 149 ------
crates/gpui3/src/elements/img.rs         |  52 -
crates/gpui3/src/elements/layout_node.rs | 193 --------
crates/gpui3/src/elements/svg.rs         |  53 -
crates/gpui3/src/geometry.rs             |   2 
crates/gpui3/src/gpui3.rs                |   2 
crates/gpui3/src/interactive.rs          | 198 ---------
crates/gpui3/src/styled.rs               |  84 +--
crates/gpui3_macros/src/style_helpers.rs |   4 
14 files changed, 586 insertions(+), 1,476 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -33,6 +33,26 @@ pub trait IdentifiedElement: Element {
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
 
+pub trait ElementKind: 'static + Send + Sync {
+    fn id(&self) -> Option<ElementId>;
+}
+
+pub struct IdentifiedElementKind(pub(crate) ElementId);
+pub struct AnonymousElementKind;
+
+impl ElementKind for IdentifiedElementKind {
+    fn id(&self) -> Option<ElementId> {
+        Some(self.0.clone())
+    }
+}
+
+impl ElementKind for AnonymousElementKind {
+    fn id(&self) -> Option<ElementId> {
+        None
+    }
+}
+
+
 pub trait ParentElement: Element {
     fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
     fn group_mut(&mut self) -> &mut Option<SharedString>;

crates/gpui3/src/elements.rs 🔗

@@ -1,16 +1,9 @@
-mod clickable;
 mod div;
-mod hoverable;
 mod img;
-mod layout_node;
 mod svg;
 mod text;
-mod div2;
 
-pub use clickable::*;
 pub use div::*;
-pub use hoverable::*;
 pub use img::*;
-pub use layout_node::*;
 pub use svg::*;
 pub use text::*;

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

@@ -1,230 +0,0 @@
-use crate::{
-    AnyElement, Bounds, DispatchPhase, Element, ElementId, Hoverable, IdentifiedElement,
-    IntoAnyElement, LayoutId, MouseDownEvent, MouseUpEvent, ParentElement, Pixels, SharedString,
-    StyleRefinement, Styled, ViewContext,
-};
-use parking_lot::Mutex;
-use refineable::CascadeSlot;
-use smallvec::SmallVec;
-use std::sync::Arc;
-
-pub trait Clickable: Element + Sized {
-    fn active_style(&mut self) -> &mut StyleRefinement;
-    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
-
-    fn on_click(
-        &mut self,
-        f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
-            + 'static
-            + Send
-            + Sync,
-    ) where
-        Self: Sized,
-    {
-        self.listeners().push(Arc::new(f));
-    }
-
-    fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
-    where
-        Self: Sized,
-    {
-        f(self.active_style());
-        self
-    }
-}
-
-pub type ClickListeners<V> =
-    SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
-
-pub struct ClickableElementState<E: 'static + Send + Sync> {
-    mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
-    child_state: E,
-}
-
-pub struct MouseClickEvent {
-    pub down: MouseDownEvent,
-    pub up: MouseUpEvent,
-}
-
-pub struct ClickableElement<E: Element> {
-    child: E,
-    listeners: ClickListeners<E::ViewState>,
-    active_style: StyleRefinement,
-    cascade_slot: CascadeSlot,
-}
-
-impl<E: Styled + Element> ClickableElement<E> {
-    pub fn new(mut child: E) -> Self {
-        let cascade_slot = child.style_cascade().reserve();
-        ClickableElement {
-            child,
-            listeners: Default::default(),
-            active_style: Default::default(),
-            cascade_slot,
-        }
-    }
-
-    pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
-        self,
-        replace: impl FnOnce(E) -> E2,
-    ) -> ClickableElement<E2> {
-        ClickableElement {
-            child: replace(self.child),
-            listeners: self.listeners,
-            active_style: self.active_style,
-            cascade_slot: self.cascade_slot,
-        }
-    }
-}
-
-impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
-where
-    E: Styled + Element,
-{
-    fn into_any(self) -> AnyElement<E::ViewState> {
-        AnyElement::new(self)
-    }
-}
-
-impl<E> Element for ClickableElement<E>
-where
-    E: Styled + Element,
-{
-    type ViewState = E::ViewState;
-    type ElementState = ClickableElementState<E::ElementState>;
-
-    fn id(&self) -> Option<ElementId> {
-        self.child.id()
-    }
-
-    fn layout(
-        &mut self,
-        state: &mut Self::ViewState,
-        element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) -> (LayoutId, Self::ElementState) {
-        if let Some(element_state) = element_state {
-            if element_state.mouse_down.lock().is_some() {
-                self.child
-                    .style_cascade()
-                    .set(self.cascade_slot, Some(self.active_style.clone()));
-            }
-
-            let (layout_id, child_state) =
-                self.child
-                    .layout(state, Some(element_state.child_state), cx);
-            (
-                layout_id,
-                ClickableElementState {
-                    mouse_down: element_state.mouse_down,
-                    child_state,
-                },
-            )
-        } else {
-            let (layout_id, child_state) = self.child.layout(state, None, cx);
-            (
-                layout_id,
-                ClickableElementState {
-                    mouse_down: Default::default(),
-                    child_state,
-                },
-            )
-        }
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        state: &mut Self::ViewState,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        if !self.listeners.is_empty() || self.active_style.is_some() {
-            if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
-                self.child
-                    .style_cascade()
-                    .set(self.cascade_slot, Some(self.active_style.clone()));
-                let listeners = self.listeners.clone();
-                let mouse_down_mutex = element_state.mouse_down.clone();
-                cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
-                    if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
-                        for listener in &*listeners {
-                            listener(
-                                view,
-                                &MouseClickEvent {
-                                    down: mouse_down.clone(),
-                                    up: up.clone(),
-                                },
-                                cx,
-                            );
-                        }
-                    }
-
-                    mouse_down_mutex.lock().take();
-                    cx.notify();
-                });
-            } else {
-                let mouse_down_mutex = element_state.mouse_down.clone();
-                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
-                    if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
-                        *mouse_down_mutex.lock() = Some(down.clone());
-                        cx.notify();
-                    }
-                });
-            }
-        }
-
-        self.child
-            .paint(bounds, state, &mut element_state.child_state, cx);
-    }
-}
-
-impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
-
-impl<E> ParentElement for ClickableElement<E>
-where
-    E: Styled + ParentElement,
-{
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
-        self.child.children_mut()
-    }
-
-    fn group_mut(&mut self) -> &mut Option<SharedString> {
-        self.child.group_mut()
-    }
-}
-
-impl<E> Styled for ClickableElement<E>
-where
-    E: Styled + Element,
-{
-    fn style_cascade(&mut self) -> &mut crate::StyleCascade {
-        self.child.style_cascade()
-    }
-
-    fn computed_style(&mut self) -> &crate::Style {
-        self.child.computed_style()
-    }
-}
-
-impl<E> Hoverable for ClickableElement<E>
-where
-    E: Element + Hoverable,
-{
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        self.child.hover_style()
-    }
-}
-
-impl<E> Clickable for ClickableElement<E>
-where
-    E: Styled + IdentifiedElement,
-{
-    fn active_style(&mut self) -> &mut StyleRefinement {
-        &mut self.active_style
-    }
-
-    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState> {
-        &mut self.listeners
-    }
-}

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

@@ -1,14 +1,43 @@
 use crate::{
-    AnonymousElementKind, AnyElement, Bounds, ClickListeners, Clickable, ClickableElement,
-    ClickableElementState, Element, ElementId, ElementKind, Hoverable, HoverableElement,
-    IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, LayoutNodeElement,
-    Overflow, ParentElement, Pixels, Point, SharedString, Style, StyleCascade, StyleRefinement,
-    Styled, ViewContext,
+    AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
+    ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
+    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point,
+    ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
 };
+use collections::HashMap;
 use parking_lot::Mutex;
+use refineable::Refineable;
 use smallvec::SmallVec;
 use std::sync::Arc;
 
+#[derive(Default)]
+pub struct DivState {
+    active_state: Arc<Mutex<ActiveState>>,
+    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)]
+struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
+
+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(Default, Clone)]
 pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
 
@@ -34,126 +63,358 @@ pub fn div<S>() -> Div<S, AnonymousElementKind>
 where
     S: 'static + Send + Sync,
 {
-    Div(ClickableElement::new(HoverableElement::new(
-        LayoutNodeElement::new(),
-    )))
+    Div {
+        kind: AnonymousElementKind,
+        children: SmallVec::new(),
+        group: None,
+        base_style: StyleRefinement::default(),
+        hover_style: StyleRefinement::default(),
+        group_hover: None,
+        active_style: StyleRefinement::default(),
+        group_active: None,
+        listeners: MouseEventListeners::default(),
+    }
+}
+
+pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
+    kind: K,
+    children: SmallVec<[AnyElement<V>; 2]>,
+    group: Option<SharedString>,
+    base_style: StyleRefinement,
+    hover_style: StyleRefinement,
+    group_hover: Option<GroupStyle>,
+    active_style: StyleRefinement,
+    group_active: Option<GroupStyle>,
+    listeners: MouseEventListeners<V>,
+}
+
+struct GroupStyle {
+    group: SharedString,
+    style: StyleRefinement,
 }
 
-pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind>(
-    ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
-);
+impl<V> Div<V, AnonymousElementKind>
+where
+    V: 'static + Send + Sync,
+{
+    pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> {
+        Div {
+            kind: IdentifiedElementKind(id.into()),
+            children: self.children,
+            group: self.group,
+            base_style: self.base_style,
+            hover_style: self.hover_style,
+            group_hover: self.group_hover,
+            active_style: self.active_style,
+            group_active: self.group_active,
+            listeners: self.listeners,
+        }
+    }
+}
+
+impl<V> Div<V, IdentifiedElementKind>
+where
+    V: 'static + Send + Sync,
+{
+    pub fn on_mouse_down(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
+    ) -> Self {
+        self.listeners
+            .mouse_down
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble
+                    && event.button == button
+                    && bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx)
+                }
+            }));
+        self
+    }
+
+    pub fn on_mouse_up(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
+    ) -> Self {
+        self.listeners
+            .mouse_up
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble
+                    && event.button == button
+                    && bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx)
+                }
+            }));
+        self
+    }
+
+    pub fn on_mouse_down_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
+    ) -> Self {
+        self.listeners
+            .mouse_down
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Capture
+                    && event.button == button
+                    && !bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx)
+                }
+            }));
+        self
+    }
+
+    pub fn on_mouse_up_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
+    ) -> Self {
+        self.listeners
+            .mouse_up
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Capture
+                    && event.button == button
+                    && !bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx);
+                }
+            }));
+        self
+    }
+
+    pub fn on_mouse_move(
+        mut self,
+        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + Send + Sync + 'static,
+    ) -> Self {
+        self.listeners
+            .mouse_move
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+                    handler(view, event, cx);
+                }
+            }));
+        self
+    }
 
-impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> {
+    pub fn on_scroll_wheel(
+        mut self,
+        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + Send + Sync + 'static,
+    ) -> Self {
+        self.listeners
+            .scroll_wheel
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+                    handler(view, event, cx);
+                }
+            }));
+        self
+    }
+}
+
+impl<V, K> Div<V, K>
+where
+    V: 'static + Send + Sync,
+    K: ElementKind,
+{
     pub fn group(mut self, group: impl Into<SharedString>) -> Self {
-        *self.0.group_mut() = Some(group.into());
+        self.group = Some(group.into());
         self
     }
 
     pub fn z_index(mut self, z_index: u32) -> Self {
-        self.base_style().z_index = Some(z_index);
+        self.base_style.z_index = Some(z_index);
         self
     }
 
     pub fn overflow_hidden(mut self) -> Self {
-        self.base_style().overflow.x = Some(Overflow::Hidden);
-        self.base_style().overflow.y = Some(Overflow::Hidden);
+        self.base_style.overflow.x = Some(Overflow::Hidden);
+        self.base_style.overflow.y = Some(Overflow::Hidden);
         self
     }
 
     pub fn overflow_hidden_x(mut self) -> Self {
-        self.base_style().overflow.x = Some(Overflow::Hidden);
+        self.base_style.overflow.x = Some(Overflow::Hidden);
         self
     }
 
     pub fn overflow_hidden_y(mut self) -> Self {
-        self.base_style().overflow.y = Some(Overflow::Hidden);
+        self.base_style.overflow.y = Some(Overflow::Hidden);
         self
     }
 
     pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
         // todo!("impl scrolling")
         // self.scroll_state = Some(scroll_state);
-        self.base_style().overflow.x = Some(Overflow::Scroll);
-        self.base_style().overflow.y = Some(Overflow::Scroll);
+        self.base_style.overflow.x = Some(Overflow::Scroll);
+        self.base_style.overflow.y = Some(Overflow::Scroll);
         self
     }
 
     pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
         // todo!("impl scrolling")
         // self.scroll_state = Some(scroll_state);
-        self.base_style().overflow.x = Some(Overflow::Scroll);
+        self.base_style.overflow.x = Some(Overflow::Scroll);
         self
     }
 
     pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
         // todo!("impl scrolling")
         // self.scroll_state = Some(scroll_state);
-        self.base_style().overflow.y = Some(Overflow::Scroll);
+        self.base_style.overflow.y = Some(Overflow::Scroll);
         self
     }
 
-    fn base_style(&mut self) -> &mut StyleRefinement {
-        self.style_cascade().base()
+    fn with_element_id<R>(
+        &mut self,
+        cx: &mut ViewContext<V>,
+        f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
+    ) -> R {
+        if let Some(id) = self.id() {
+            cx.with_element_id(id, |cx| f(self, cx))
+        } else {
+            f(self, cx)
+        }
     }
-}
 
-impl<V: 'static + Send + Sync> Div<V, AnonymousElementKind> {
-    pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> {
-        Div(self.0.replace_child(|hoverable| {
-            hoverable.replace_child(|layout_node| layout_node.identify(id))
-        }))
-    }
-}
+    pub fn compute_style(
+        &self,
+        bounds: Bounds<Pixels>,
+        state: &DivState,
+        cx: &mut ViewContext<V>,
+    ) -> Style {
+        let mut computed_style = Style::default();
+        computed_style.refine(&self.base_style);
 
-impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
-    fn id(&self) -> ElementId {
-        IdentifiedElement::id(&self.0)
-    }
-}
+        let mouse_position = cx.mouse_position();
 
-impl<V: 'static + Send + Sync, K: ElementKind> ParentElement for Div<V, K> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
-        self.0.children_mut()
-    }
+        if let Some(group_hover) = self.group_hover.as_ref() {
+            if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
+                if group_bounds.contains_point(&mouse_position) {
+                    computed_style.refine(&group_hover.style);
+                }
+            }
+        }
+        if bounds.contains_point(&mouse_position) {
+            computed_style.refine(&self.hover_style);
+        }
 
-    fn group_mut(&mut self) -> &mut Option<SharedString> {
-        self.0.group_mut()
-    }
-}
+        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);
+            }
+        }
 
-impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
-    fn style_cascade(&mut self) -> &mut StyleCascade {
-        self.0.style_cascade()
-    }
+        if active_state.element {
+            computed_style.refine(&self.active_style);
+        }
 
-    fn computed_style(&mut self) -> &Style {
-        self.0.computed_style()
+        computed_style
     }
-}
 
-impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        self.0.hover_style()
-    }
-}
+    fn paint_hover_listeners(
+        &self,
+        bounds: Bounds<Pixels>,
+        group_bounds: Option<Bounds<Pixels>>,
+        cx: &mut ViewContext<V>,
+    ) {
+        if let Some(group_bounds) = group_bounds {
+            paint_hover_listener(group_bounds, cx);
+        }
 
-impl<V: 'static + Send + Sync> Clickable for Div<V, IdentifiedElementKind> {
-    fn active_style(&mut self) -> &mut StyleRefinement {
-        self.0.active_style()
+        if self.hover_style.is_some() {
+            paint_hover_listener(bounds, cx);
+        }
     }
 
-    fn listeners(&mut self) -> &mut ClickListeners<V> {
-        self.0.listeners()
+    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, K> IntoAnyElement<V> for Div<V, K>
-where
-    V: 'static + Send + Sync,
-    K: ElementKind,
-{
-    fn into_any(self) -> AnyElement<V> {
-        AnyElement::new(self)
+    fn paint_event_listeners(
+        &self,
+        bounds: Bounds<Pixels>,
+        pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
+        cx: &mut ViewContext<V>,
+    ) {
+        let click_listeners = self.listeners.mouse_click.clone();
+        let mouse_down = pending_click.lock().clone();
+        if let Some(mouse_down) = mouse_down {
+            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
+                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+                    let mouse_click = MouseClickEvent {
+                        down: mouse_down.clone(),
+                        up: event.clone(),
+                    };
+                    for listener in &click_listeners {
+                        listener(state, &mouse_click, &bounds, cx);
+                    }
+                }
+
+                *pending_click.lock() = None;
+            });
+        } else {
+            cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
+                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+                    *pending_click.lock() = Some(event.clone());
+                }
+            });
+        }
+
+        for listener in self.listeners.mouse_down.iter().cloned() {
+            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
+                listener(state, event, &bounds, phase, cx);
+            })
+        }
+
+        for listener in self.listeners.mouse_up.iter().cloned() {
+            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
+                listener(state, event, &bounds, phase, cx);
+            })
+        }
+
+        for listener in self.listeners.mouse_move.iter().cloned() {
+            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
+                listener(state, event, &bounds, phase, cx);
+            })
+        }
+
+        for listener in self.listeners.scroll_wheel.iter().cloned() {
+            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
+                listener(state, event, &bounds, phase, cx);
+            })
+        }
     }
 }
 
@@ -163,28 +424,185 @@ where
     K: ElementKind,
 {
     type ViewState = V;
-    type ElementState = ClickableElementState<()>;
+    type ElementState = DivState;
 
     fn id(&self) -> Option<ElementId> {
-        self.0.id()
+        self.kind.id()
     }
 
     fn layout(
         &mut self,
-        state: &mut Self::ViewState,
+        view_state: &mut Self::ViewState,
         element_state: Option<Self::ElementState>,
         cx: &mut ViewContext<Self::ViewState>,
     ) -> (LayoutId, Self::ElementState) {
-        self.0.layout(state, element_state, cx)
+        self.with_element_id(cx, |this, cx| {
+            let layout_ids = this
+                .children
+                .iter_mut()
+                .map(|child| child.layout(view_state, cx))
+                .collect::<Vec<_>>();
+
+            let element_state = element_state.unwrap_or_default();
+            let style = this.compute_style(Bounds::default(), &element_state, cx);
+            let layout_id = cx.request_layout(&style, layout_ids);
+            (layout_id, element_state)
+        })
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        state: &mut Self::ViewState,
+        view_state: &mut Self::ViewState,
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<Self::ViewState>,
     ) {
-        self.0.paint(bounds, state, element_state, cx);
+        self.with_element_id(cx, |this, cx| {
+            if let Some(group) = this.group.clone() {
+                cx.default_global::<GroupBounds>()
+                    .0
+                    .entry(group)
+                    .or_default()
+                    .push(bounds);
+            }
+
+            let hover_group_bounds = this
+                .group_hover
+                .as_ref()
+                .and_then(|group_hover| group_bounds(&group_hover.group, cx));
+            let active_group_bounds = this
+                .group_active
+                .as_ref()
+                .and_then(|group_active| group_bounds(&group_active.group, cx));
+            let style = this.compute_style(bounds, element_state, cx);
+            let z_index = style.z_index.unwrap_or(0);
+
+            // Paint background and event handlers.
+            cx.stack(z_index, |cx| {
+                cx.stack(0, |cx| {
+                    style.paint(bounds, cx);
+                    this.paint_hover_listeners(bounds, hover_group_bounds, cx);
+                    this.paint_active_listener(
+                        bounds,
+                        active_group_bounds,
+                        element_state.active_state.clone(),
+                        cx,
+                    );
+                    this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
+                });
+            });
+
+            style.apply_text_style(cx, |cx| {
+                style.apply_overflow(bounds, cx, |cx| {
+                    cx.stack(z_index + 1, |cx| {
+                        for child in &mut this.children {
+                            child.paint(view_state, None, cx);
+                        }
+                    })
+                })
+            });
+
+            if let Some(group) = this.group.as_ref() {
+                cx.default_global::<GroupBounds>()
+                    .0
+                    .get_mut(group)
+                    .unwrap()
+                    .pop();
+            }
+        })
+    }
+}
+
+impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
+    fn id(&self) -> ElementId {
+        self.kind.0.clone()
     }
 }
+
+impl<V, K> IntoAnyElement<V> for Div<V, K>
+where
+    V: 'static + Send + Sync,
+    K: ElementKind,
+{
+    fn into_any(self) -> AnyElement<V> {
+        AnyElement::new(self)
+    }
+}
+
+impl<V, K> Styled for Div<V, K>
+where
+    V: 'static + Send + Sync,
+    K: ElementKind,
+{
+    fn style(&mut self) -> &mut StyleRefinement {
+        &mut self.base_style
+    }
+}
+
+pub struct MouseClickEvent {
+    pub down: MouseDownEvent,
+    pub up: MouseUpEvent,
+}
+
+type MouseDownHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+type MouseUpHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+type MouseClickHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
+>;
+
+type MouseMoveHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+type ScrollWheelHandler<V> = Arc<
+    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+
+pub struct MouseEventListeners<V: 'static> {
+    mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
+    mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
+    mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
+    mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
+    scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
+}
+
+impl<V> Default for MouseEventListeners<V> {
+    fn default() -> Self {
+        Self {
+            mouse_down: SmallVec::new(),
+            mouse_up: SmallVec::new(),
+            mouse_click: SmallVec::new(),
+            mouse_move: SmallVec::new(),
+            scroll_wheel: SmallVec::new(),
+        }
+    }
+}
+
+fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
+where
+    V: 'static + Send + Sync,
+{
+    let hovered = bounds.contains_point(&cx.mouse_position());
+    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+        if phase == DispatchPhase::Capture {
+            if bounds.contains_point(&event.position) != hovered {
+                cx.notify();
+            }
+        }
+    });
+}

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

@@ -1,498 +0,0 @@
-use crate::{
-    AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
-    ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
-    MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point, ScrollWheelEvent,
-    SharedString, Style, StyleRefinement, ViewContext,
-};
-use collections::HashMap;
-use parking_lot::Mutex;
-use refineable::Refineable;
-use smallvec::SmallVec;
-use std::sync::Arc;
-
-#[derive(Default)]
-pub struct DivState {
-    active_state: Arc<Mutex<ActiveState>>,
-    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)]
-struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
-
-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(Default, Clone)]
-pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
-
-impl ScrollState {
-    pub fn x(&self) -> Pixels {
-        self.0.lock().x
-    }
-
-    pub fn set_x(&self, value: Pixels) {
-        self.0.lock().x = value;
-    }
-
-    pub fn y(&self) -> Pixels {
-        self.0.lock().y
-    }
-
-    pub fn set_y(&self, value: Pixels) {
-        self.0.lock().y = value;
-    }
-}
-
-pub fn div<S>() -> Div<S, AnonymousElementKind>
-where
-    S: 'static + Send + Sync,
-{
-    Div {
-        kind: AnonymousElementKind,
-        children: SmallVec::new(),
-        group: None,
-        base_style: StyleRefinement::default(),
-        hover_style: StyleRefinement::default(),
-        group_hover: None,
-        active_style: StyleRefinement::default(),
-        group_active: None,
-        listeners: MouseEventListeners::default(),
-    }
-}
-
-pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
-    kind: K,
-    children: SmallVec<[AnyElement<V>; 2]>,
-    group: Option<SharedString>,
-    base_style: StyleRefinement,
-    hover_style: StyleRefinement,
-    group_hover: Option<GroupStyle>,
-    active_style: StyleRefinement,
-    group_active: Option<GroupStyle>,
-    listeners: MouseEventListeners<V>,
-}
-
-struct GroupStyle {
-    group: SharedString,
-    style: StyleRefinement,
-}
-
-impl<V> Div<V, AnonymousElementKind>
-where
-    V: 'static + Send + Sync,
-{
-    pub fn id(self, id: ElementId) -> Div<V, IdentifiedElementKind> {
-        Div {
-            kind: IdentifiedElementKind(id),
-            children: self.children,
-            group: self.group,
-            base_style: self.base_style,
-            hover_style: self.hover_style,
-            group_hover: self.group_hover,
-            active_style: self.active_style,
-            group_active: self.group_active,
-            listeners: self.listeners,
-        }
-    }
-}
-
-impl<V, K> Div<V, K>
-where
-    V: 'static + Send + Sync,
-    K: ElementKind,
-{
-    pub fn group(mut self, group: impl Into<SharedString>) -> Self {
-        self.group = Some(group.into());
-        self
-    }
-
-    pub fn z_index(mut self, z_index: u32) -> Self {
-        self.base_style.z_index = Some(z_index);
-        self
-    }
-
-    pub fn overflow_hidden(mut self) -> Self {
-        self.base_style.overflow.x = Some(Overflow::Hidden);
-        self.base_style.overflow.y = Some(Overflow::Hidden);
-        self
-    }
-
-    pub fn overflow_hidden_x(mut self) -> Self {
-        self.base_style.overflow.x = Some(Overflow::Hidden);
-        self
-    }
-
-    pub fn overflow_hidden_y(mut self) -> Self {
-        self.base_style.overflow.y = Some(Overflow::Hidden);
-        self
-    }
-
-    pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
-        // todo!("impl scrolling")
-        // self.scroll_state = Some(scroll_state);
-        self.base_style.overflow.x = Some(Overflow::Scroll);
-        self.base_style.overflow.y = Some(Overflow::Scroll);
-        self
-    }
-
-    pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
-        // todo!("impl scrolling")
-        // self.scroll_state = Some(scroll_state);
-        self.base_style.overflow.x = Some(Overflow::Scroll);
-        self
-    }
-
-    pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
-        // todo!("impl scrolling")
-        // self.scroll_state = Some(scroll_state);
-        self.base_style.overflow.y = Some(Overflow::Scroll);
-        self
-    }
-
-    fn with_element_id<R>(
-        &mut self,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
-    ) -> R {
-        if let Some(id) = self.id() {
-            cx.with_element_id(id, |cx| f(self, cx))
-        } else {
-            f(self, cx)
-        }
-    }
-
-    fn compute_style(
-        &self,
-        bounds: Bounds<Pixels>,
-        group_bounds: Option<Bounds<Pixels>>,
-        active_state: ActiveState,
-        cx: &mut ViewContext<V>,
-    ) -> Style {
-        let mut computed_style = Style::default();
-        computed_style.refine(&self.base_style);
-
-        let mouse_position = cx.mouse_position();
-        if let Some(group_bounds) = group_bounds {
-            if group_bounds.contains_point(mouse_position) {
-                if let Some(GroupStyle { style, .. }) = self.group_hover.as_ref() {
-                    computed_style.refine(style);
-                }
-            }
-        }
-        if bounds.contains_point(mouse_position) {
-            computed_style.refine(&self.hover_style);
-        }
-
-        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);
-        }
-
-        computed_style
-    }
-
-    fn paint_hover_listeners(
-        &self,
-        bounds: Bounds<Pixels>,
-        group_bounds: Option<Bounds<Pixels>>,
-        cx: &mut ViewContext<V>,
-    ) {
-        if let Some(group_bounds) = group_bounds {
-            paint_hover_listener(group_bounds, cx);
-        }
-
-        if self.hover_style.is_some() {
-            paint_hover_listener(bounds, cx);
-        }
-    }
-
-    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();
-                }
-            });
-        }
-    }
-
-    fn paint_event_listeners(
-        &self,
-        bounds: Bounds<Pixels>,
-        pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
-        cx: &mut ViewContext<V>,
-    ) {
-        let click_listeners = self.listeners.mouse_click.clone();
-        let mouse_down = pending_click.lock().clone();
-        if let Some(mouse_down) = mouse_down {
-            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
-                if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
-                    let mouse_click = MouseClickEvent {
-                        down: mouse_down.clone(),
-                        up: event.clone(),
-                    };
-                    for listener in &click_listeners {
-                        listener(state, &mouse_click, &bounds, cx);
-                    }
-                }
-
-                *pending_click.lock() = None;
-            });
-        } else {
-            cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
-                if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
-                    *pending_click.lock() = Some(event.clone());
-                }
-            });
-        }
-
-        for listener in self.listeners.mouse_down.iter().cloned() {
-            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
-            })
-        }
-
-        for listener in self.listeners.mouse_up.iter().cloned() {
-            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
-            })
-        }
-
-        for listener in self.listeners.mouse_move.iter().cloned() {
-            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
-            })
-        }
-
-        for listener in self.listeners.scroll_wheel.iter().cloned() {
-            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
-            })
-        }
-    }
-}
-
-impl<V, K> Element for Div<V, K>
-where
-    V: 'static + Send + Sync,
-    K: ElementKind,
-{
-    type ViewState = V;
-    type ElementState = DivState;
-
-    fn id(&self) -> Option<ElementId> {
-        self.kind.id()
-    }
-
-    fn layout(
-        &mut self,
-        view_state: &mut Self::ViewState,
-        element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) -> (LayoutId, Self::ElementState) {
-        self.with_element_id(cx, |this, cx| {
-            let layout_ids = this
-                .children
-                .iter_mut()
-                .map(|child| child.layout(view_state, cx))
-                .collect::<Vec<_>>();
-
-            let element_state = element_state.unwrap_or_default();
-            let style = this.compute_style(
-                Bounds::default(),
-                None,
-                *element_state.active_state.lock(),
-                cx,
-            );
-            let layout_id = cx.request_layout(&style, layout_ids);
-            (layout_id, element_state)
-        })
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut Self::ViewState,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        self.with_element_id(cx, |this, cx| {
-            if let Some(group) = this.group.clone() {
-                cx.default_global::<GroupBounds>()
-                    .0
-                    .entry(group)
-                    .or_default()
-                    .push(bounds);
-            }
-
-            let hover_group_bounds = this
-                .group_hover
-                .as_ref()
-                .and_then(|group_hover| group_bounds(&group_hover.group, cx));
-            let active_group_bounds = this
-                .group_active
-                .as_ref()
-                .and_then(|group_active| group_bounds(&group_active.group, cx));
-            let active_state = *element_state.active_state.lock();
-            let style = this.compute_style(bounds, hover_group_bounds, active_state, cx);
-            let z_index = style.z_index.unwrap_or(0);
-
-            // Paint background and event handlers.
-            cx.stack(z_index, |cx| {
-                cx.stack(0, |cx| {
-                    style.paint(bounds, cx);
-                    this.paint_hover_listeners(bounds, hover_group_bounds, cx);
-                    this.paint_active_listener(
-                        bounds,
-                        active_group_bounds,
-                        element_state.active_state.clone(),
-                        cx,
-                    );
-                    this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
-                });
-            });
-
-            style.apply_text_style(cx, |cx| {
-                style.apply_overflow(bounds, cx, |cx| {
-                    cx.stack(z_index + 1, |cx| {
-                        for child in &mut this.children {
-                            child.paint(view_state, None, cx);
-                        }
-                    })
-                })
-            });
-
-            if let Some(group) = this.group.as_ref() {
-                cx.default_global::<GroupBounds>()
-                    .0
-                    .get_mut(group)
-                    .unwrap()
-                    .pop();
-            }
-        })
-    }
-}
-
-impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
-    fn id(&self) -> ElementId {
-        self.kind.0.clone()
-    }
-}
-
-impl<V, K> IntoAnyElement<V> for Div<V, K>
-where
-    V: 'static + Send + Sync,
-    K: ElementKind,
-{
-    fn into_any(self) -> AnyElement<V> {
-        AnyElement::new(self)
-    }
-}
-
-pub struct MouseClickEvent {
-    pub down: MouseDownEvent,
-    pub up: MouseUpEvent,
-}
-
-type MouseDownHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type MouseUpHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type MouseClickHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
->;
-
-type MouseMoveHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type ScrollWheelHandler<V> = Arc<
-    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-
-pub struct MouseEventListeners<V: 'static> {
-    mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
-    mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
-    mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
-    mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
-    scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
-}
-
-impl<V> Default for MouseEventListeners<V> {
-    fn default() -> Self {
-        Self {
-            mouse_down: SmallVec::new(),
-            mouse_up: SmallVec::new(),
-            mouse_click: SmallVec::new(),
-            mouse_move: SmallVec::new(),
-            scroll_wheel: SmallVec::new(),
-        }
-    }
-}
-
-fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
-where
-    V: 'static + Send + Sync,
-{
-    let hovered = bounds.contains_point(cx.mouse_position());
-    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
-        if phase == DispatchPhase::Capture {
-            if bounds.contains_point(event.position) != hovered {
-                cx.notify();
-            }
-        }
-    });
-}

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

@@ -1,149 +0,0 @@
-use crate::{
-    group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement,
-    IntoAnyElement, LayoutId, MouseMoveEvent, ParentElement, Pixels, SharedString, Style,
-    StyleCascade, StyleRefinement, Styled, ViewContext,
-};
-use refineable::CascadeSlot;
-use std::sync::{
-    atomic::{AtomicBool, Ordering::SeqCst},
-    Arc,
-};
-
-pub trait Hoverable {
-    fn hover_style(&mut self) -> &mut StyleRefinement;
-
-    fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
-    where
-        Self: Sized,
-    {
-        f(self.hover_style());
-        self
-    }
-}
-
-pub struct HoverableElement<E> {
-    hover_style: StyleRefinement,
-    group: Option<SharedString>,
-    cascade_slot: CascadeSlot,
-    hovered: Arc<AtomicBool>,
-    child: E,
-}
-
-impl<E: Styled + Element> HoverableElement<E> {
-    pub fn new(mut child: E) -> Self {
-        let cascade_slot = child.style_cascade().reserve();
-        HoverableElement {
-            hover_style: StyleRefinement::default(),
-            group: None,
-            cascade_slot,
-            hovered: Arc::new(AtomicBool::new(false)),
-            child,
-        }
-    }
-
-    pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
-        self,
-        replace: impl FnOnce(E) -> E2,
-    ) -> HoverableElement<E2> {
-        HoverableElement {
-            hover_style: self.hover_style,
-            group: self.group,
-            cascade_slot: self.cascade_slot,
-            hovered: self.hovered,
-            child: replace(self.child),
-        }
-    }
-}
-
-impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
-where
-    E: Styled + Element,
-{
-    fn into_any(self) -> AnyElement<E::ViewState> {
-        AnyElement::new(self)
-    }
-}
-
-impl<E> Element for HoverableElement<E>
-where
-    E: Styled + Element,
-{
-    type ViewState = E::ViewState;
-    type ElementState = E::ElementState;
-
-    fn id(&self) -> Option<ElementId> {
-        self.child.id()
-    }
-
-    fn layout(
-        &mut self,
-        state: &mut Self::ViewState,
-        element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) -> (LayoutId, Self::ElementState) {
-        self.child.layout(state, element_state, cx)
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        state: &mut Self::ViewState,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        let target_bounds = self
-            .group
-            .as_ref()
-            .and_then(|group| group_bounds(group, cx))
-            .unwrap_or(bounds);
-
-        let hovered = target_bounds.contains_point(cx.mouse_position());
-
-        let slot = self.cascade_slot;
-        let style = hovered.then_some(self.hover_style.clone());
-        self.child.style_cascade().set(slot, style);
-        self.hovered.store(hovered, SeqCst);
-
-        let hovered = self.hovered.clone();
-        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
-            if phase == DispatchPhase::Capture {
-                if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
-                    cx.notify();
-                }
-            }
-        });
-
-        self.child.paint(bounds, state, element_state, cx);
-    }
-}
-
-impl<E> ParentElement for HoverableElement<E>
-where
-    E: Styled + ParentElement,
-{
-    fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement<E::ViewState>; 2]> {
-        self.child.children_mut()
-    }
-
-    fn group_mut(&mut self) -> &mut Option<SharedString> {
-        self.child.group_mut()
-    }
-}
-
-impl<E: Styled + Element> Hoverable for HoverableElement<E> {
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        &mut self.hover_style
-    }
-}
-
-impl<E: Styled + Element> Styled for HoverableElement<E> {
-    fn style_cascade(&mut self) -> &mut StyleCascade {
-        self.child.style_cascade()
-    }
-
-    fn computed_style(&mut self) -> &Style {
-        self.child.computed_style()
-    }
-}
-
-impl<E: Styled + IdentifiedElement> IdentifiedElement for HoverableElement<E> {}

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

@@ -1,15 +1,13 @@
 use crate::{
-    AnonymousElementKind, AnyElement, BorrowWindow, Bounds, ClickListeners, Clickable,
-    ClickableElement, ClickableElementState, Element, ElementId, ElementKind, Hoverable,
-    HoverableElement, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
-    LayoutNodeElement, Pixels, SharedString, Style, StyleRefinement, Styled, ViewContext,
+    div, AnonymousElementKind, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementId,
+    ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels,
+    SharedString, StyleRefinement, Styled, ViewContext,
 };
 use futures::FutureExt;
-use refineable::Cascade;
 use util::ResultExt;
 
 pub struct Img<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
-    layout_node: ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
+    base: Div<V, K>,
     uri: Option<SharedString>,
     grayscale: bool,
 }
@@ -19,7 +17,7 @@ where
     V: 'static + Send + Sync,
 {
     Img {
-        layout_node: ClickableElement::new(HoverableElement::new(LayoutNodeElement::new())),
+        base: div(),
         uri: None,
         grayscale: false,
     }
@@ -44,9 +42,7 @@ where
 impl<V: 'static + Send + Sync> Img<V, AnonymousElementKind> {
     pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElementKind> {
         Img {
-            layout_node: self.layout_node.replace_child(|hoverable| {
-                hoverable.replace_child(|layout_node| layout_node.identify(id))
-            }),
+            base: self.base.id(id),
             uri: self.uri,
             grayscale: self.grayscale,
         }
@@ -69,10 +65,10 @@ where
     K: ElementKind,
 {
     type ViewState = V;
-    type ElementState = ClickableElementState<()>;
+    type ElementState = DivState;
 
     fn id(&self) -> Option<crate::ElementId> {
-        self.layout_node.id()
+        self.base.id()
     }
 
     fn layout(
@@ -84,7 +80,7 @@ where
     where
         Self: Sized,
     {
-        self.layout_node.layout(view_state, element_state, cx)
+        self.base.layout(view_state, element_state, cx)
     }
 
     fn paint(
@@ -95,10 +91,10 @@ where
         cx: &mut ViewContext<Self::ViewState>,
     ) {
         cx.stack(1, |cx| {
-            self.layout_node.paint(bounds, view, element_state, cx);
+            self.base.paint(bounds, view, element_state, cx);
         });
 
-        let style = self.computed_style();
+        let style = self.base.compute_style(bounds, element_state, cx);
         let corner_radii = style.corner_radii;
 
         if let Some(uri) = self.uri.clone() {
@@ -127,7 +123,7 @@ where
 
 impl<V: 'static + Send + Sync> IdentifiedElement for Img<V, IdentifiedElementKind> {
     fn id(&self) -> ElementId {
-        IdentifiedElement::id(&self.layout_node)
+        IdentifiedElement::id(&self.base)
     }
 }
 
@@ -136,27 +132,7 @@ where
     V: 'static + Send + Sync,
     K: ElementKind,
 {
-    fn style_cascade(&mut self) -> &mut Cascade<Style> {
-        self.layout_node.style_cascade()
-    }
-
-    fn computed_style(&mut self) -> &Style {
-        self.layout_node.computed_style()
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Img<V, K> {
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        self.layout_node.hover_style()
-    }
-}
-
-impl<V: 'static + Send + Sync> Clickable for Img<V, IdentifiedElementKind> {
-    fn active_style(&mut self) -> &mut StyleRefinement {
-        self.layout_node.active_style()
-    }
-
-    fn listeners(&mut self) -> &mut ClickListeners<V> {
-        self.layout_node.listeners()
+    fn style(&mut self) -> &mut StyleRefinement {
+        self.base.style()
     }
 }

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

@@ -1,193 +0,0 @@
-use crate::{
-    AnyElement, AppContext, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement,
-    IntoAnyElement, LayoutId, ParentElement, Pixels, SharedString, Style, StyleCascade, Styled,
-    ViewContext,
-};
-use collections::HashMap;
-use refineable::Refineable;
-use smallvec::SmallVec;
-
-#[derive(Default)]
-struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
-
-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())
-}
-
-pub trait ElementKind: 'static + Send + Sync {
-    fn id(&self) -> Option<ElementId>;
-}
-
-pub struct IdentifiedElementKind(pub(crate) ElementId);
-pub struct AnonymousElementKind;
-
-impl ElementKind for IdentifiedElementKind {
-    fn id(&self) -> Option<ElementId> {
-        Some(self.0.clone())
-    }
-}
-
-impl ElementKind for AnonymousElementKind {
-    fn id(&self) -> Option<ElementId> {
-        None
-    }
-}
-
-pub struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
-    style_cascade: StyleCascade,
-    computed_style: Option<Style>,
-    children: SmallVec<[AnyElement<V>; 2]>,
-    kind: K,
-    group: Option<SharedString>,
-}
-
-impl<V: 'static + Send + Sync> LayoutNodeElement<V, AnonymousElementKind> {
-    pub fn new() -> LayoutNodeElement<V, AnonymousElementKind> {
-        LayoutNodeElement {
-            style_cascade: StyleCascade::default(),
-            computed_style: None,
-            children: SmallVec::new(),
-            kind: AnonymousElementKind,
-            group: None,
-        }
-    }
-
-    pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, IdentifiedElementKind> {
-        LayoutNodeElement {
-            style_cascade: self.style_cascade,
-            computed_style: self.computed_style,
-            children: self.children,
-            kind: IdentifiedElementKind(id.into()),
-            group: self.group,
-        }
-    }
-}
-
-impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
-    pub fn set_group(&mut self, group: impl Into<SharedString>) {
-        self.group = Some(group.into());
-    }
-
-    fn with_element_id<R>(
-        &mut self,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
-    ) -> R {
-        if let Some(id) = self.id() {
-            cx.with_element_id(id, |cx| f(self, cx))
-        } else {
-            f(self, cx)
-        }
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Styled for LayoutNodeElement<V, K> {
-    fn style_cascade(&mut self) -> &mut StyleCascade {
-        &mut self.style_cascade
-    }
-
-    fn computed_style(&mut self) -> &Style {
-        self.computed_style
-            .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
-    }
-}
-
-impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, IdentifiedElementKind> {
-    fn id(&self) -> ElementId {
-        self.kind.0.clone()
-    }
-}
-
-impl<V, K> IntoAnyElement<V> for LayoutNodeElement<V, K>
-where
-    V: 'static + Send + Sync,
-    K: ElementKind,
-{
-    fn into_any(self) -> AnyElement<V> {
-        AnyElement::new(self)
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
-    type ViewState = V;
-    type ElementState = ();
-
-    fn id(&self) -> Option<ElementId> {
-        self.kind.id()
-    }
-
-    fn layout(
-        &mut self,
-        state: &mut Self::ViewState,
-        _: Option<Self::ElementState>,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) -> (LayoutId, Self::ElementState) {
-        self.with_element_id(cx, |this, cx| {
-            let layout_ids = this
-                .children
-                .iter_mut()
-                .map(|child| child.layout(state, cx))
-                .collect::<Vec<_>>();
-
-            let style = this.computed_style();
-            let layout_id = cx.request_layout(style, layout_ids);
-            (layout_id, ())
-        })
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        state: &mut Self::ViewState,
-        _: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        self.with_element_id(cx, |this, cx| {
-            if let Some(group) = this.group.clone() {
-                cx.default_global::<GroupBounds>()
-                    .0
-                    .entry(group)
-                    .or_default()
-                    .push(bounds);
-            }
-
-            let style = this.computed_style().clone();
-            let z_index = style.z_index.unwrap_or(0);
-            cx.stack(z_index, |cx| style.paint(bounds, cx));
-
-            // todo!("implement overflow")
-            // let overflow = &style.overflow;
-
-            style.apply_text_style(cx, |cx| {
-                cx.stack(z_index + 1, |cx| {
-                    style.apply_overflow(bounds, cx, |cx| {
-                        for child in &mut this.children {
-                            child.paint(state, None, cx);
-                        }
-                    })
-                })
-            });
-
-            if let Some(group) = this.group.as_ref() {
-                cx.default_global::<GroupBounds>()
-                    .0
-                    .get_mut(group)
-                    .unwrap()
-                    .pop();
-            }
-        })
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> ParentElement for LayoutNodeElement<V, K> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
-        &mut self.children
-    }
-
-    fn group_mut(&mut self) -> &mut Option<SharedString> {
-        &mut self.group
-    }
-}

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

@@ -1,14 +1,12 @@
 use crate::{
-    AnonymousElementKind, AnyElement, Bounds, ClickListeners, Clickable, ClickableElement,
-    ClickableElementState, Element, ElementId, ElementKind, Hoverable, HoverableElement,
-    IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, LayoutNodeElement, Pixels,
-    SharedString, Style, StyleRefinement, Styled,
+    div, AnonymousElementKind, AnyElement, Bounds, Div, DivState, Element, ElementId, ElementKind,
+    IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels, SharedString,
+    StyleRefinement, Styled,
 };
-use refineable::Cascade;
 use util::ResultExt;
 
 pub struct Svg<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
-    layout_node: ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
+    base: Div<V, K>,
     path: Option<SharedString>,
 }
 
@@ -17,7 +15,7 @@ where
     V: 'static + Send + Sync,
 {
     Svg {
-        layout_node: ClickableElement::new(HoverableElement::new(LayoutNodeElement::new())),
+        base: div(),
         path: None,
     }
 }
@@ -36,9 +34,7 @@ where
 impl<V: 'static + Send + Sync> Svg<V, AnonymousElementKind> {
     pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElementKind> {
         Svg {
-            layout_node: self.layout_node.replace_child(|hoverable| {
-                hoverable.replace_child(|layout_node| layout_node.identify(id))
-            }),
+            base: self.base.id(id),
             path: self.path,
         }
     }
@@ -60,10 +56,10 @@ where
     K: ElementKind,
 {
     type ViewState = V;
-    type ElementState = ClickableElementState<()>;
+    type ElementState = DivState;
 
     fn id(&self) -> Option<crate::ElementId> {
-        self.layout_node.id()
+        self.base.id()
     }
 
     fn layout(
@@ -75,7 +71,7 @@ where
     where
         Self: Sized,
     {
-        self.layout_node.layout(view, element_state, cx)
+        self.base.layout(view, element_state, cx)
     }
 
     fn paint(
@@ -87,9 +83,10 @@ where
     ) where
         Self: Sized,
     {
-        self.layout_node.paint(bounds, view, element_state, cx);
+        self.base.paint(bounds, view, element_state, cx);
         let fill_color = self
-            .computed_style()
+            .base
+            .compute_style(bounds, element_state, cx)
             .fill
             .as_ref()
             .and_then(|fill| fill.color());
@@ -101,7 +98,7 @@ where
 
 impl<V: 'static + Send + Sync> IdentifiedElement for Svg<V, IdentifiedElementKind> {
     fn id(&self) -> ElementId {
-        IdentifiedElement::id(&self.layout_node)
+        IdentifiedElement::id(&self.base)
     }
 }
 
@@ -110,27 +107,7 @@ where
     V: 'static + Send + Sync,
     K: ElementKind,
 {
-    fn style_cascade(&mut self) -> &mut Cascade<Style> {
-        self.layout_node.style_cascade()
-    }
-
-    fn computed_style(&mut self) -> &Style {
-        self.layout_node.computed_style()
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Svg<V, K> {
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        self.layout_node.hover_style()
-    }
-}
-
-impl<V: 'static + Send + Sync> Clickable for Svg<V, IdentifiedElementKind> {
-    fn active_style(&mut self) -> &mut StyleRefinement {
-        self.layout_node.active_style()
-    }
-
-    fn listeners(&mut self) -> &mut ClickListeners<V> {
-        self.layout_node.listeners()
+    fn style(&mut self) -> &mut StyleRefinement {
+        self.base.style()
     }
 }

crates/gpui3/src/geometry.rs 🔗

@@ -413,7 +413,7 @@ impl<T> Bounds<T>
 where
     T: Add<T, Output = T> + PartialOrd + Clone + Default + Debug,
 {
-    pub fn contains_point(&self, point: Point<T>) -> bool {
+    pub fn contains_point(&self, point: &Point<T>) -> bool {
         point.x >= self.origin.x
             && point.x <= self.origin.x.clone() + self.size.width.clone()
             && point.y >= self.origin.y

crates/gpui3/src/gpui3.rs 🔗

@@ -7,7 +7,6 @@ mod events;
 mod executor;
 mod geometry;
 mod image_cache;
-mod interactive;
 mod platform;
 mod scene;
 mod style;
@@ -31,7 +30,6 @@ pub use executor::*;
 pub use geometry::*;
 pub use gpui3_macros::*;
 pub use image_cache::*;
-pub use interactive::*;
 pub use platform::*;
 pub use refineable::*;
 pub use scene::*;

crates/gpui3/src/interactive.rs 🔗

@@ -1,198 +0,0 @@
-use crate::{
-    Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
-    ScrollWheelEvent, ViewContext,
-};
-use smallvec::SmallVec;
-use std::sync::Arc;
-
-pub trait Interactive<S: 'static + Send + Sync> {
-    fn listeners(&mut self) -> &mut MouseEventListeners<S>;
-
-    fn on_mouse_down(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
-    ) -> Self
-    where
-        Self: Sized,
-    {
-        self.listeners()
-            .mouse_down
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble
-                    && event.button == button
-                    && bounds.contains_point(event.position)
-                {
-                    handler(view, event, cx)
-                }
-            }));
-        self
-    }
-
-    fn on_mouse_up(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
-    ) -> Self
-    where
-        Self: Sized,
-    {
-        self.listeners()
-            .mouse_up
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble
-                    && event.button == button
-                    && bounds.contains_point(event.position)
-                {
-                    handler(view, event, cx)
-                }
-            }));
-        self
-    }
-
-    fn on_mouse_down_out(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
-    ) -> Self
-    where
-        Self: Sized,
-    {
-        self.listeners()
-            .mouse_down
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Capture
-                    && event.button == button
-                    && !bounds.contains_point(event.position)
-                {
-                    handler(view, event, cx)
-                }
-            }));
-        self
-    }
-
-    fn on_mouse_up_out(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
-    ) -> Self
-    where
-        Self: Sized,
-    {
-        self.listeners()
-            .mouse_up
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Capture
-                    && event.button == button
-                    && !bounds.contains_point(event.position)
-                {
-                    handler(view, event, cx);
-                }
-            }));
-        self
-    }
-
-    fn on_mouse_move(
-        mut self,
-        handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
-    ) -> Self
-    where
-        Self: Sized,
-    {
-        self.listeners()
-            .mouse_move
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
-                    handler(view, event, cx);
-                }
-            }));
-        self
-    }
-
-    fn on_scroll_wheel(
-        mut self,
-        handler: impl Fn(&mut S, &ScrollWheelEvent, &mut ViewContext<S>) + Send + Sync + 'static,
-    ) -> Self
-    where
-        Self: Sized,
-    {
-        self.listeners()
-            .scroll_wheel
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
-                    handler(view, event, cx);
-                }
-            }));
-        self
-    }
-}
-
-type MouseDownHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type MouseUpHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-
-type MouseMoveHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type ScrollWheelHandler<V> = Arc<
-    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-
-pub struct MouseEventListeners<V: 'static> {
-    mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
-    mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
-    mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
-    scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
-}
-
-impl<S: Send + Sync + 'static> MouseEventListeners<S> {
-    pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
-        for handler in self.mouse_down.iter().cloned() {
-            cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
-                handler(view, event, &bounds, phase, cx);
-            })
-        }
-        for handler in self.mouse_up.iter().cloned() {
-            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
-                handler(view, event, &bounds, phase, cx);
-            })
-        }
-        for handler in self.mouse_move.iter().cloned() {
-            cx.on_mouse_event(move |view, event: &MouseMoveEvent, phase, cx| {
-                handler(view, event, &bounds, phase, cx);
-            })
-        }
-
-        for handler in self.scroll_wheel.iter().cloned() {
-            cx.on_mouse_event(move |view, event: &ScrollWheelEvent, phase, cx| {
-                handler(view, event, &bounds, phase, cx);
-            })
-        }
-    }
-}
-
-impl<V> Default for MouseEventListeners<V> {
-    fn default() -> Self {
-        Self {
-            mouse_down: Default::default(),
-            mouse_up: Default::default(),
-            mouse_move: Default::default(),
-            scroll_wheel: Default::default(),
-        }
-    }
-}

crates/gpui3/src/styled.rs 🔗

@@ -1,16 +1,12 @@
 use crate::{
     self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla,
-    JustifyContent, Length, Position, SharedString, Style, StyleCascade, StyleRefinement,
+    JustifyContent, Length, Position, SharedString, StyleRefinement,
 };
 use crate::{BoxShadow, TextStyleRefinement};
 use smallvec::smallvec;
 
 pub trait Styled {
-    fn style_cascade(&mut self) -> &mut StyleCascade;
-    fn computed_style(&mut self) -> &Style;
-    fn base_style(&mut self) -> &mut StyleRefinement {
-        self.style_cascade().base()
-    }
+    fn style(&mut self) -> &mut StyleRefinement;
 
     gpui3_macros::style_helpers!();
 
@@ -18,8 +14,8 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().size.width = Some(relative(1.).into());
-        self.base_style().size.height = Some(relative(1.).into());
+        self.style().size.width = Some(relative(1.).into());
+        self.style().size.height = Some(relative(1.).into());
         self
     }
 
@@ -27,7 +23,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().position = Some(Position::Relative);
+        self.style().position = Some(Position::Relative);
         self
     }
 
@@ -35,7 +31,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().position = Some(Position::Absolute);
+        self.style().position = Some(Position::Absolute);
         self
     }
 
@@ -43,7 +39,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().display = Some(Display::Block);
+        self.style().display = Some(Display::Block);
         self
     }
 
@@ -51,7 +47,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().display = Some(Display::Flex);
+        self.style().display = Some(Display::Flex);
         self
     }
 
@@ -59,7 +55,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_direction = Some(FlexDirection::Column);
+        self.style().flex_direction = Some(FlexDirection::Column);
         self
     }
 
@@ -67,7 +63,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_direction = Some(FlexDirection::Row);
+        self.style().flex_direction = Some(FlexDirection::Row);
         self
     }
 
@@ -75,9 +71,9 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_grow = Some(1.);
-        self.base_style().flex_shrink = Some(1.);
-        self.base_style().flex_basis = Some(relative(0.).into());
+        self.style().flex_grow = Some(1.);
+        self.style().flex_shrink = Some(1.);
+        self.style().flex_basis = Some(relative(0.).into());
         self
     }
 
@@ -85,9 +81,9 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_grow = Some(1.);
-        self.base_style().flex_shrink = Some(1.);
-        self.base_style().flex_basis = Some(Length::Auto);
+        self.style().flex_grow = Some(1.);
+        self.style().flex_shrink = Some(1.);
+        self.style().flex_basis = Some(Length::Auto);
         self
     }
 
@@ -95,9 +91,9 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_grow = Some(0.);
-        self.base_style().flex_shrink = Some(1.);
-        self.base_style().flex_basis = Some(Length::Auto);
+        self.style().flex_grow = Some(0.);
+        self.style().flex_shrink = Some(1.);
+        self.style().flex_basis = Some(Length::Auto);
         self
     }
 
@@ -105,8 +101,8 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_grow = Some(0.);
-        self.base_style().flex_shrink = Some(0.);
+        self.style().flex_grow = Some(0.);
+        self.style().flex_shrink = Some(0.);
         self
     }
 
@@ -114,7 +110,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().flex_grow = Some(1.);
+        self.style().flex_grow = Some(1.);
         self
     }
 
@@ -122,7 +118,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().align_items = Some(AlignItems::FlexStart);
+        self.style().align_items = Some(AlignItems::FlexStart);
         self
     }
 
@@ -130,7 +126,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().align_items = Some(AlignItems::FlexEnd);
+        self.style().align_items = Some(AlignItems::FlexEnd);
         self
     }
 
@@ -138,7 +134,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().align_items = Some(AlignItems::Center);
+        self.style().align_items = Some(AlignItems::Center);
         self
     }
 
@@ -146,7 +142,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().justify_content = Some(JustifyContent::SpaceBetween);
+        self.style().justify_content = Some(JustifyContent::SpaceBetween);
         self
     }
 
@@ -154,7 +150,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().justify_content = Some(JustifyContent::Center);
+        self.style().justify_content = Some(JustifyContent::Center);
         self
     }
 
@@ -162,7 +158,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().justify_content = Some(JustifyContent::Start);
+        self.style().justify_content = Some(JustifyContent::Start);
         self
     }
 
@@ -170,7 +166,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().justify_content = Some(JustifyContent::End);
+        self.style().justify_content = Some(JustifyContent::End);
         self
     }
 
@@ -178,7 +174,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().justify_content = Some(JustifyContent::SpaceAround);
+        self.style().justify_content = Some(JustifyContent::SpaceAround);
         self
     }
 
@@ -187,7 +183,7 @@ pub trait Styled {
         F: Into<Fill>,
         Self: Sized,
     {
-        self.base_style().fill = Some(fill.into());
+        self.style().fill = Some(fill.into());
         self
     }
 
@@ -196,7 +192,7 @@ pub trait Styled {
         C: Into<Hsla>,
         Self: Sized,
     {
-        self.base_style().border_color = Some(border_color.into());
+        self.style().border_color = Some(border_color.into());
         self
     }
 
@@ -204,7 +200,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(smallvec![
+        self.style().box_shadow = Some(smallvec![
             BoxShadow {
                 color: hsla(0., 0., 0., 0.1),
                 offset: point(px(0.), px(1.)),
@@ -225,7 +221,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(Default::default());
+        self.style().box_shadow = Some(Default::default());
         self
     }
 
@@ -233,7 +229,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(smallvec::smallvec![BoxShadow {
+        self.style().box_shadow = Some(smallvec::smallvec![BoxShadow {
             color: hsla(0., 0., 0., 0.05),
             offset: point(px(0.), px(1.)),
             blur_radius: px(2.),
@@ -246,7 +242,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(smallvec![
+        self.style().box_shadow = Some(smallvec![
             BoxShadow {
                 color: hsla(0.5, 0., 0., 0.1),
                 offset: point(px(0.), px(4.)),
@@ -267,7 +263,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(smallvec![
+        self.style().box_shadow = Some(smallvec![
             BoxShadow {
                 color: hsla(0., 0., 0., 0.1),
                 offset: point(px(0.), px(10.)),
@@ -288,7 +284,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(smallvec![
+        self.style().box_shadow = Some(smallvec![
             BoxShadow {
                 color: hsla(0., 0., 0., 0.1),
                 offset: point(px(0.), px(20.)),
@@ -309,7 +305,7 @@ pub trait Styled {
     where
         Self: Sized,
     {
-        self.base_style().box_shadow = Some(smallvec![BoxShadow {
+        self.style().box_shadow = Some(smallvec![BoxShadow {
             color: hsla(0., 0., 0., 0.25),
             offset: point(px(0.), px(25.)),
             blur_radius: px(50.),
@@ -319,7 +315,7 @@ pub trait Styled {
     }
 
     fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
-        let style: &mut StyleRefinement = self.base_style();
+        let style: &mut StyleRefinement = self.style();
         &mut style.text
     }
 

crates/gpui3_macros/src/style_helpers.rs 🔗

@@ -129,7 +129,7 @@ fn generate_predefined_setter(
     let method = quote! {
         #[doc = #doc_string]
         fn #method_name(mut self) -> Self where Self: std::marker::Sized {
-            let mut style = self.base_style();
+            let style = self.style();
             #(#field_assignments)*
             self
         }
@@ -160,7 +160,7 @@ fn generate_custom_value_setter(
 
     let method = quote! {
         fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui3::#length_type>) -> Self where Self: std::marker::Sized {
-            let mut style = self.base_style();
+            let style = self.style();
             #(#field_assignments)*
             self
         }