WIP

Antonio Scandurra created

Change summary

crates/gpui3/src/element.rs              |  32 -
crates/gpui3/src/elements.rs             |   9 
crates/gpui3/src/elements/clickable.rs   | 235 ++++++---
crates/gpui3/src/elements/div.rs         | 278 ++++-------
crates/gpui3/src/elements/group.rs       | 103 ----
crates/gpui3/src/elements/hoverable.rs   | 136 +++--
crates/gpui3/src/elements/identified.rs  |  69 ---
crates/gpui3/src/elements/img.rs         |  16 
crates/gpui3/src/elements/layout_node.rs | 207 +++++++++
crates/gpui3/src/elements/nested.rs      | 598 --------------------------
crates/gpui3/src/elements/svg.rs         |  16 
crates/gpui3/src/gpui3.rs                |   2 
crates/gpui3/src/style_helpers.rs        | 364 ---------------
crates/gpui3/src/styled.rs               | 507 ++++++++++++++++++++-
crates/gpui3/src/view.rs                 |   4 
crates/gpui3_macros/src/style_helpers.rs |   4 
16 files changed, 1,041 insertions(+), 1,539 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -1,9 +1,4 @@
-use std::sync::Arc;
-
-use crate::{
-    BorrowWindow, Bounds, Clickable, ElementId, Group, LayoutId, MouseDownEvent, MouseUpEvent,
-    Pixels, Point, SharedString, ViewContext,
-};
+use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
 
@@ -27,35 +22,12 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<Self::ViewState>,
     );
-
-    fn group(self, name: impl Into<SharedString>) -> Group<Self>
-    where
-        Self: Sized,
-    {
-        Group::new(name.into(), self)
-    }
 }
 
 pub trait IdentifiedElement: Element {
-    fn element_id(&self) -> ElementId {
+    fn id(&self) -> ElementId {
         Element::id(self).unwrap()
     }
-
-    fn on_click(
-        self,
-        listener: impl Fn(
-                &mut Self::ViewState,
-                (&MouseDownEvent, &MouseUpEvent),
-                &mut ViewContext<Self::ViewState>,
-            ) + Send
-            + Sync
-            + 'static,
-    ) -> Clickable<Self>
-    where
-        Self: Sized,
-    {
-        Clickable::new(self, Arc::from(listener))
-    }
 }
 
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]

crates/gpui3/src/elements.rs 🔗

@@ -1,20 +1,15 @@
 mod clickable;
 mod div;
-mod group;
 mod hoverable;
-mod identified;
 mod img;
-mod nested;
-mod pressable;
+mod layout_node;
 mod svg;
 mod text;
 
 pub use clickable::*;
 pub use div::*;
-pub use group::*;
 pub use hoverable::*;
-pub use identified::*;
 pub use img::*;
-pub use pressable::*;
+pub use layout_node::*;
 pub use svg::*;
 pub use text::*;

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

@@ -1,71 +1,90 @@
 use crate::{
-    AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, IntoAnyElement,
-    MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
+    AnyElement, Bounds, DispatchPhase, Element, ElementId, ElementKind, Hoverable,
+    IdentifiedElement, IntoAnyElement, LayoutId, LayoutNode, MouseDownEvent, MouseUpEvent, Pixels,
+    SharedString, StyleRefinement, Styled, ViewContext,
 };
 use parking_lot::Mutex;
-use refineable::Cascade;
+use refineable::CascadeSlot;
 use smallvec::SmallVec;
 use std::sync::Arc;
 
-pub type ClickListener<S> =
-    dyn Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>) + Send + Sync + 'static;
+pub trait Clickable: Element + Sized {
+    fn active_style(&mut self) -> &mut StyleRefinement;
+    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
 
-pub struct Clickable<E: Element> {
-    child: E,
-    listener: Arc<ClickListener<E::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));
+    }
 
-pub struct ClickableState<S> {
-    last_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
-    child_state: S,
+    fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
+    where
+        Self: Sized,
+    {
+        f(self.active_style());
+        self
+    }
 }
 
-impl<E: Element> Clickable<E> {
-    pub fn new(child: E, listener: Arc<ClickListener<E::ViewState>>) -> Self {
-        Self { child, listener }
-    }
+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,
 }
 
-impl<E> Styled for Clickable<E>
-where
-    E: Styled + IdentifiedElement,
-{
-    type Style = E::Style;
+pub struct MouseClickEvent {
+    pub down: MouseDownEvent,
+    pub up: MouseUpEvent,
+}
 
-    fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
-        self.child.style_cascade()
-    }
+pub struct ClickableElement<E: Element> {
+    child: E,
+    listeners: ClickListeners<E::ViewState>,
+    active_style: StyleRefinement,
+    cascade_slot: CascadeSlot,
+}
 
-    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
-        self.child.declared_style()
+impl<E: Element> ClickableElement<E> {
+    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<S, E> Interactive<S> for Clickable<E>
+impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
 where
-    S: 'static + Send + Sync,
-    E: IdentifiedElement + Interactive<S>,
+    E: Styled + Element,
 {
-    fn listeners(&mut self) -> &mut MouseEventListeners<S> {
-        self.child.listeners()
-    }
-}
-
-impl<E: IdentifiedElement> IntoAnyElement<E::ViewState> for Clickable<E> {
     fn into_any(self) -> AnyElement<E::ViewState> {
         AnyElement::new(self)
     }
 }
 
-impl<E> Element for Clickable<E>
+impl<E> Element for ClickableElement<E>
 where
-    E: IdentifiedElement,
+    E: Styled + Element,
 {
     type ViewState = E::ViewState;
-    type ElementState = ClickableState<E::ElementState>;
+    type ElementState = ClickableElementState<E::ElementState>;
 
-    fn id(&self) -> Option<crate::ElementId> {
-        Some(IdentifiedElement::element_id(&self.child))
+    fn id(&self) -> Option<ElementId> {
+        self.child.id()
     }
 
     fn layout(
@@ -73,24 +92,33 @@ where
         state: &mut Self::ViewState,
         element_state: Option<Self::ElementState>,
         cx: &mut ViewContext<Self::ViewState>,
-    ) -> (crate::LayoutId, Self::ElementState) {
+    ) -> (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);
-
-            let element_state = ClickableState {
-                last_mouse_down: element_state.last_mouse_down,
-                child_state,
-            };
-            (layout_id, element_state)
+            (
+                layout_id,
+                ClickableElementState {
+                    mouse_down: element_state.mouse_down,
+                    child_state,
+                },
+            )
         } else {
             let (layout_id, child_state) = self.child.layout(state, None, cx);
-            let element_state = ClickableState {
-                last_mouse_down: Default::default(),
-                child_state,
-            };
-            (layout_id, element_state)
+            (
+                layout_id,
+                ClickableElementState {
+                    mouse_down: Default::default(),
+                    child_state,
+                },
+            )
         }
     }
 
@@ -101,31 +129,39 @@ where
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<Self::ViewState>,
     ) {
-        let last_mouse_down = element_state.last_mouse_down.clone();
-        let is_some = last_mouse_down.lock().is_some();
-
-        if is_some {
-            let listener = self.listener.clone();
-            cx.on_mouse_event(move |view, up_event: &MouseUpEvent, phase, cx| {
-                if phase == DispatchPhase::Capture && !bounds.contains_point(up_event.position) {
-                    *last_mouse_down.lock() = None;
-                } else if phase == DispatchPhase::Bubble && bounds.contains_point(up_event.position)
-                {
-                    if let Some(down_event) = last_mouse_down.lock().take() {
-                        listener(view, (&down_event, up_event), cx);
-                    } else {
-                        log::error!("No mouse down event found for click event");
+        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,
+                            );
+                        }
                     }
-                }
-            })
-        } else {
-            cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, _| {
-                if phase == DispatchPhase::Bubble {
-                    if bounds.contains_point(event.position) {
-                        *last_mouse_down.lock() = Some(event.clone());
+
+                    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
@@ -133,12 +169,53 @@ where
     }
 }
 
-impl<E: IdentifiedElement + ParentElement> ParentElement for Clickable<E> {
-    type State = E::State;
+impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
 
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+impl<E, K> LayoutNode<E::ViewState, K> for ClickableElement<E>
+where
+    E: Element + LayoutNode<E::ViewState, K>,
+    K: ElementKind,
+{
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<E::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> IdentifiedElement for Clickable<E> where E: IdentifiedElement + Styled {}
+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,246 +1,174 @@
 use crate::{
-    AnyElement, BorrowWindow, Bounds, Cascade, Element, ElementId, IdentifiedElement, Interactive,
-    IntoAnyElement, LayoutId, MouseEventListeners, Overflow, ParentElement, Pixels, Point,
-    Refineable, Style, Styled, ViewContext,
+    AnonymousElementKind, AnyElement, Bounds, Clickable, ClickableElement, ClickableElementState,
+    Element, ElementId, ElementKind, Hoverable, HoverableElement, IdentifiedElementKind,
+    IntoAnyElement, LayoutId, LayoutNode, LayoutNodeElement, Overflow, Pixels, Point, SharedString,
+    Style, StyleCascade, StyleRefinement, Styled, ViewContext, ClickListeners,
 };
 use parking_lot::Mutex;
 use smallvec::SmallVec;
-use std::{marker::PhantomData, sync::Arc};
+use std::sync::Arc;
 
-pub enum HasId {}
-
-pub struct Div<S: 'static, I = ()> {
-    styles: Cascade<Style>,
-    id: Option<ElementId>,
-    listeners: MouseEventListeners<S>,
-    children: SmallVec<[AnyElement<S>; 2]>,
-    scroll_state: Option<ScrollState>,
-    identified: PhantomData<I>,
-}
-
-pub fn div<S>() -> Div<S> {
-    Div {
-        styles: Default::default(),
-        id: None,
-        listeners: Default::default(),
-        children: Default::default(),
-        scroll_state: None,
-        identified: PhantomData,
-    }
-}
+#[derive(Default, Clone)]
+pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
 
-impl<S, Marker> IntoAnyElement<S> for Div<S, Marker>
-where
-    S: 'static + Send + Sync,
-    Marker: 'static + Send + Sync,
-{
-    fn into_any(self) -> AnyElement<S> {
-        AnyElement::new(self)
+impl ScrollState {
+    pub fn x(&self) -> Pixels {
+        self.0.lock().x
     }
-}
 
-impl<S, Marker> Element for Div<S, Marker>
-where
-    S: 'static + Send + Sync,
-    Marker: 'static + Send + Sync,
-{
-    type ViewState = S;
-    type ElementState = ();
-
-    fn id(&self) -> Option<ElementId> {
-        self.id.clone()
+    pub fn set_x(&self, value: Pixels) {
+        self.0.lock().x = value;
     }
 
-    fn layout(
-        &mut self,
-        view: &mut S,
-        _: Option<Self::ElementState>,
-        cx: &mut ViewContext<S>,
-    ) -> (LayoutId, Self::ElementState) {
-        let style = self.computed_style();
-        let child_layout_ids = style.apply_text_style(cx, |cx| {
-            self.with_element_id(cx, |this, cx| this.layout_children(view, cx))
-        });
-        let layout_id = cx.request_layout(&style, child_layout_ids.clone());
-        (layout_id, ())
+    pub fn y(&self) -> Pixels {
+        self.0.lock().y
     }
 
-    fn paint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        state: &mut S,
-        _: &mut (),
-        cx: &mut ViewContext<S>,
-    ) {
-        let style = self.computed_style();
-        let z_index = style.z_index.unwrap_or(0);
-        cx.stack(z_index, |cx| style.paint(bounds, cx));
-
-        let overflow = &style.overflow;
-
-        style.apply_text_style(cx, |cx| {
-            cx.stack(z_index + 1, |cx| {
-                style.apply_overflow(bounds, cx, |cx| {
-                    self.with_element_id(cx, |this, cx| {
-                        this.listeners.paint(bounds, cx);
-                        this.paint_children(overflow, state, cx)
-                    });
-                })
-            })
-        });
+    pub fn set_y(&self, value: Pixels) {
+        self.0.lock().y = value;
     }
 }
 
-impl<S> Div<S, ()>
-where
-    S: 'static + Send + Sync,
-{
-    pub fn id(self, id: impl Into<ElementId>) -> Div<S, HasId> {
-        Div {
-            styles: self.styles,
-            id: Some(id.into()),
-            listeners: self.listeners,
-            children: self.children,
-            scroll_state: self.scroll_state,
-            identified: PhantomData,
-        }
+pub struct Div<V: 'static + Send + Sync, K: ElementKind>(
+    ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
+);
+
+impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> {
+    pub fn group(mut self, group: impl Into<SharedString>) -> Self {
+        *self.0.group_mut() = Some(group.into());
+        self
     }
-}
 
-impl<S, Marker> Div<S, Marker>
-where
-    S: 'static + Send + Sync,
-    Marker: 'static + Send + Sync,
-{
     pub fn z_index(mut self, z_index: u32) -> Self {
-        self.declared_style().z_index = Some(z_index);
+        self.base_style().z_index = Some(z_index);
         self
     }
 
     pub fn overflow_hidden(mut self) -> Self {
-        self.declared_style().overflow.x = Some(Overflow::Hidden);
-        self.declared_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.declared_style().overflow.x = Some(Overflow::Hidden);
+        self.base_style().overflow.x = Some(Overflow::Hidden);
         self
     }
 
     pub fn overflow_hidden_y(mut self) -> Self {
-        self.declared_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 {
-        self.scroll_state = Some(scroll_state);
-        self.declared_style().overflow.x = Some(Overflow::Scroll);
-        self.declared_style().overflow.y = Some(Overflow::Scroll);
+    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 {
-        self.scroll_state = Some(scroll_state);
-        self.declared_style().overflow.x = Some(Overflow::Scroll);
+    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 {
-        self.scroll_state = Some(scroll_state);
-        self.declared_style().overflow.y = Some(Overflow::Scroll);
+    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 scroll_offset(&self, overflow: &Point<Overflow>) -> Point<Pixels> {
-        let mut offset = Point::default();
-        if overflow.y == Overflow::Scroll {
-            offset.y = self.scroll_state.as_ref().unwrap().y();
-        }
-        if overflow.x == Overflow::Scroll {
-            offset.x = self.scroll_state.as_ref().unwrap().x();
-        }
-
-        offset
+    fn base_style(&mut self) -> &mut StyleRefinement {
+        self.style_cascade().base()
     }
+}
 
-    fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Vec<LayoutId> {
-        self.children
-            .iter_mut()
-            .map(|child| child.layout(view, cx))
-            .collect()
+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))
+        }))
     }
+}
 
-    fn paint_children(
-        &mut self,
-        overflow: &Point<Overflow>,
-        state: &mut S,
-        cx: &mut ViewContext<S>,
-    ) {
-        let scroll_offset = self.scroll_offset(overflow);
-        for child in &mut self.children {
-            child.paint(state, Some(scroll_offset), cx);
-        }
+impl<V: 'static + Send + Sync, K: ElementKind> LayoutNode<V, K> for Div<V, K> {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+        self.0.children_mut()
     }
 
-    fn with_element_id<R>(
-        &mut self,
-        cx: &mut ViewContext<S>,
-        f: impl FnOnce(&mut Self, &mut ViewContext<S>) -> R,
-    ) -> R {
-        if let Some(element_id) = self.id() {
-            cx.with_element_id(element_id, |cx| f(self, cx))
-        } else {
-            f(self, cx)
-        }
+    fn group_mut(&mut self) -> &mut Option<SharedString> {
+        self.0.group_mut()
     }
 }
 
-impl<V: 'static + Send + Sync, Marker: 'static + Send + Sync> Styled for Div<V, Marker> {
-    type Style = Style;
-
-    fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
-        &mut self.styles
+impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
+    fn style_cascade(&mut self) -> &mut StyleCascade {
+        self.0.style_cascade()
     }
 
-    fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
-        self.styles.base()
+    fn computed_style(&mut self) -> &Style {
+        self.0.computed_style()
     }
 }
 
-impl<V: Send + Sync + 'static> IdentifiedElement for Div<V, HasId> {}
-
-impl<V: Send + Sync + 'static, Marker: 'static + Send + Sync> Interactive<V> for Div<V, Marker> {
-    fn listeners(&mut self) -> &mut MouseEventListeners<V> {
-        &mut self.listeners
+impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
+    fn hover_style(&mut self) -> &mut StyleRefinement {
+        self.0.hover_style()
     }
 }
 
-impl<V: 'static, Marker: 'static + Send + Sync> ParentElement for Div<V, Marker> {
-    type State = V;
+impl<V: 'static + Send + Sync> Clickable for Div<V, IdentifiedElementKind> {
+    fn active_style(&mut self) -> &mut StyleRefinement {
+        self.0.active_style()
+    }
 
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
-        &mut self.children
+    fn listeners(&mut self) -> &mut ClickListeners<V> {
+        self.0.listeners()
     }
 }
 
-#[derive(Default, Clone)]
-pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
-
-impl ScrollState {
-    pub fn x(&self) -> Pixels {
-        self.0.lock().x
+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 fn set_x(&self, value: Pixels) {
-        self.0.lock().x = value;
+impl<V, K> Element for Div<V, K>
+where
+    V: 'static + Send + Sync,
+    K: ElementKind,
+{
+    type ViewState = V;
+    type ElementState = ClickableElementState<()>;
+
+    fn id(&self) -> Option<ElementId> {
+        self.0.id()
     }
 
-    pub fn y(&self) -> Pixels {
-        self.0.lock().y
+    fn layout(
+        &mut self,
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (LayoutId, Self::ElementState) {
+        self.0.layout(state, element_state, cx)
     }
 
-    pub fn set_y(&self, value: Pixels) {
-        self.0.lock().y = value;
+    fn paint(
+        &mut self,
+        bounds: Bounds<Pixels>,
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
+        self.0.paint(bounds, state, element_state, cx);
     }
 }

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

@@ -1,103 +0,0 @@
-use crate::{
-    AnyElement, AppContext, Bounds, Element, ElementId, IdentifiedElement, Interactive,
-    IntoAnyElement, MouseEventListeners, ParentElement, Pixels, SharedString, Styled, ViewContext,
-};
-use collections::HashMap;
-use refineable::Cascade;
-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 struct Group<E> {
-    name: SharedString,
-    child: E,
-}
-
-impl<E> Group<E> {
-    pub fn new(name: SharedString, child: E) -> Self {
-        Group { name, child }
-    }
-}
-
-impl<E: Element> IntoAnyElement<E::ViewState> for Group<E> {
-    fn into_any(self) -> AnyElement<E::ViewState> {
-        AnyElement::new(self)
-    }
-}
-
-impl<E: Element> Element for Group<E> {
-    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>,
-    ) -> (crate::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>,
-    ) {
-        cx.default_global::<GroupBounds>()
-            .0
-            .entry(self.name.clone())
-            .or_default()
-            .push(bounds);
-        self.child.paint(bounds, state, element_state, cx);
-        cx.default_global::<GroupBounds>()
-            .0
-            .get_mut(&self.name)
-            .unwrap()
-            .pop();
-    }
-}
-
-impl<E: ParentElement> ParentElement for Group<E> {
-    type State = E::State;
-
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
-        self.child.children_mut()
-    }
-}
-
-impl<E> IdentifiedElement for Group<E> where E: IdentifiedElement {}
-
-impl<E> Styled for Group<E>
-where
-    E: Styled,
-{
-    type Style = E::Style;
-
-    fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
-        self.child.style_cascade()
-    }
-
-    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
-        self.child.declared_style()
-    }
-}
-
-impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Group<E> {
-    fn listeners(&mut self) -> &mut MouseEventListeners<S> {
-        self.child.listeners()
-    }
-}

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

@@ -1,72 +1,61 @@
 use crate::{
-    group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement,
-    Interactive, IntoAnyElement, MouseEventListeners, MouseMoveEvent, ParentElement, Pixels,
-    SharedString, Styled, ViewContext,
+    group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, ElementKind,
+    IdentifiedElement, IntoAnyElement, LayoutId, LayoutNode, MouseMoveEvent, Pixels, SharedString,
+    Style, StyleCascade, StyleRefinement, Styled, ViewContext,
 };
-use refineable::{Cascade, CascadeSlot, Refineable};
-use smallvec::SmallVec;
+use refineable::CascadeSlot;
 use std::sync::{
     atomic::{AtomicBool, Ordering::SeqCst},
     Arc,
 };
 
-pub struct Hoverable<E: Styled> {
-    group: Option<SharedString>,
-    hovered: Arc<AtomicBool>,
-    cascade_slot: CascadeSlot,
-    hovered_style: <E::Style as Refineable>::Refinement,
-    child: E,
-}
+pub trait Hoverable {
+    fn hover_style(&mut self) -> &mut StyleRefinement;
 
-impl<E: Styled> Hoverable<E> {
-    pub fn new(mut child: E, hover_group: Option<SharedString>) -> Self {
-        Self {
-            group: hover_group,
-            hovered: Arc::new(AtomicBool::new(false)),
-            cascade_slot: child.style_cascade().reserve(),
-            hovered_style: Default::default(),
-            child,
-        }
+    fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
+    where
+        Self: Sized,
+    {
+        f(self.hover_style());
+        self
     }
 }
 
-impl<E> Styled for Hoverable<E>
-where
-    E: Styled,
-{
-    type Style = E::Style;
-
-    fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
-        self.child.style_cascade()
-    }
-
-    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
-        &mut self.hovered_style
-    }
+pub struct HoverableElement<E> {
+    hover_style: StyleRefinement,
+    group: Option<SharedString>,
+    cascade_slot: CascadeSlot,
+    hovered: Arc<AtomicBool>,
+    child: E,
 }
 
-impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Hoverable<E> {
-    fn listeners(&mut self) -> &mut MouseEventListeners<S> {
-        self.child.listeners()
+impl<E: Styled + Element> HoverableElement<E> {
+    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 Hoverable<E>
+impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
 where
-    E: Element + Styled,
-    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
-    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+    E: Styled + Element,
 {
     fn into_any(self) -> AnyElement<E::ViewState> {
         AnyElement::new(self)
     }
 }
 
-impl<E> Element for Hoverable<E>
+impl<E> Element for HoverableElement<E>
 where
-    E: Element + Styled,
-    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
-    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+    E: Styled + Element,
 {
     type ViewState = E::ViewState;
     type ElementState = E::ElementState;
@@ -80,7 +69,7 @@ where
         state: &mut Self::ViewState,
         element_state: Option<Self::ElementState>,
         cx: &mut ViewContext<Self::ViewState>,
-    ) -> (crate::LayoutId, Self::ElementState) {
+    ) -> (LayoutId, Self::ElementState) {
         self.child.layout(state, element_state, cx)
     }
 
@@ -100,19 +89,15 @@ where
         let hovered = target_bounds.contains_point(cx.mouse_position());
 
         let slot = self.cascade_slot;
-        let style = hovered.then_some(self.hovered_style.clone());
-        self.style_cascade().set(slot, style);
+        let style = hovered.then_some(self.hover_style.clone());
+        self.child.style_cascade().set(slot, style);
         self.hovered.store(hovered, SeqCst);
 
-        cx.on_mouse_event({
-            let hovered = self.hovered.clone();
-
-            move |_, event: &MouseMoveEvent, phase, cx| {
-                if phase == DispatchPhase::Bubble {
-                    if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
-                        cx.notify();
-                        cx.stop_propagation();
-                    }
+        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();
                 }
             }
         });
@@ -121,18 +106,35 @@ where
     }
 }
 
-impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
-    type State = E::State;
-
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+impl<E, K, V> LayoutNode<V, K> for HoverableElement<E>
+where
+    E: LayoutNode<V, K>,
+    K: ElementKind,
+    V: 'static + Send + Sync,
+{
+    fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement<V>; 2]> {
         self.child.children_mut()
     }
+
+    fn group_mut(&mut self) -> &mut Option<SharedString> {
+        self.child.group_mut()
+    }
 }
 
-impl<E> IdentifiedElement for Hoverable<E>
-where
-    E: IdentifiedElement + Styled,
-    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
-    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
-{
+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/identified.rs 🔗

@@ -1,69 +0,0 @@
-use refineable::{Cascade, Refineable};
-use smallvec::SmallVec;
-
-use crate::{
-    AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, IntoAnyElement,
-    LayoutId, ParentElement, Styled, ViewContext,
-};
-
-pub struct Identified<E> {
-    pub(crate) element: E,
-    pub(crate) id: ElementId,
-}
-
-impl<E: Element> IntoAnyElement<E::ViewState> for Identified<E> {
-    fn into_any(self) -> AnyElement<E::ViewState> {
-        AnyElement::new(self)
-    }
-}
-
-impl<E: Element> Element for Identified<E> {
-    type ViewState = E::ViewState;
-    type ElementState = E::ElementState;
-
-    fn id(&self) -> Option<ElementId> {
-        Some(self.id.clone())
-    }
-
-    fn layout(
-        &mut self,
-        state: &mut Self::ViewState,
-        element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) -> (LayoutId, Self::ElementState) {
-        self.element.layout(state, element_state, cx)
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<crate::Pixels>,
-        state: &mut Self::ViewState,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        cx.with_element_id(self.id.clone(), |cx| {
-            self.element.paint(bounds, state, element_state, cx)
-        })
-    }
-}
-
-impl<E: Element> IdentifiedElement for Identified<E> {}
-
-impl<E: Styled> Styled for Identified<E> {
-    type Style = E::Style;
-
-    fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
-        self.element.style_cascade()
-    }
-    fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
-        self.element.declared_style()
-    }
-}
-
-impl<E: ParentElement> ParentElement for Identified<E> {
-    type State = E::State;
-
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
-        self.element.children_mut()
-    }
-}

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

@@ -74,7 +74,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
         cx: &mut ViewContext<Self::ViewState>,
     ) {
         let style = self.computed_style();
-
+        let corner_radii = style.corner_radii;
         style.paint(bounds, cx);
 
         if let Some(uri) = self.uri.clone() {
@@ -84,7 +84,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
                 .now_or_never()
                 .and_then(ResultExt::log_err)
             {
-                let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
+                let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
                 cx.stack(1, |cx| {
                     cx.paint_image(bounds, corner_radii, data, self.grayscale)
                         .log_err()
@@ -102,13 +102,13 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
 }
 
 impl<S> Styled for Img<S> {
-    type Style = Style;
-
-    fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
-        &mut self.style
+    fn style_cascade(&mut self) -> &mut Cascade<Style> {
+        todo!("use layout node")
+        // &mut self.style
     }
 
-    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
-        self.style.base()
+    fn computed_style(&mut self) -> &Style {
+        todo!("use layout node")
+        // self.style.compute()
     }
 }

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

@@ -0,0 +1,207 @@
+use crate::{
+    AnyElement, AppContext, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement,
+    IntoAnyElement, LayoutId, 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 LayoutNode<V: 'static + Send + Sync, K: ElementKind> {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
+    fn group_mut(&mut self) -> &mut Option<SharedString>;
+
+    fn child(mut self, child: impl IntoAnyElement<V>) -> Self
+    where
+        Self: Sized,
+    {
+        self.children_mut().push(child.into_any());
+        self
+    }
+
+    fn children<C, E>(mut self, children: C) -> Self
+    where
+        C: IntoIterator<Item = E>,
+        E: IntoAnyElement<V>,
+        Self: Sized,
+    {
+        for child in children {
+            self.children_mut().push(child.into_any());
+        }
+        self
+    }
+}
+
+pub trait ElementKind: 'static + Send + Sync {
+    fn id(&self) -> Option<ElementId>;
+}
+
+pub struct IdentifiedElementKind(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 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> LayoutNode<V, K> 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/nested.rs 🔗

@@ -1,598 +0,0 @@
-use crate::{
-    group_bounds, AnyElement, BorrowWindow, Bounds, DispatchPhase, Element, ElementId,
-    IdentifiedElement, IntoAnyElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow,
-    ScrollState, SharedString, Style, StyleCascade, StyleRefinement, ViewContext,
-};
-use parking_lot::Mutex;
-use refineable::{CascadeSlot, Refineable};
-use smallvec::SmallVec;
-use std::sync::{
-    atomic::{AtomicBool, Ordering::SeqCst},
-    Arc,
-};
-
-trait LayoutNode<V: 'static + Send + Sync, K: ElementKind> {
-    fn state(&mut self) -> &mut LayoutNodeElement<V, K>;
-
-    fn child(mut self, child: impl IntoAnyElement<V>) -> Self
-    where
-        Self: Sized,
-    {
-        self.state().children.push(child.into_any());
-        self
-    }
-
-    fn children<C, E>(mut self, children: C) -> Self
-    where
-        C: IntoIterator<Item = E>,
-        E: IntoAnyElement<V>,
-        Self: Sized,
-    {
-        for child in children {
-            self.state().children.push(child.into_any());
-        }
-        self
-    }
-}
-
-pub trait ElementKind: 'static + Send + Sync {
-    fn id(&self) -> Option<ElementId>;
-}
-
-pub struct Identified(ElementId);
-pub struct Anonymous;
-
-impl ElementKind for Identified {
-    fn id(&self) -> Option<ElementId> {
-        Some(self.0.clone())
-    }
-}
-
-impl ElementKind for Anonymous {
-    fn id(&self) -> Option<ElementId> {
-        None
-    }
-}
-
-struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
-    style_cascade: StyleCascade,
-    computed_style: Option<Style>,
-    children: SmallVec<[AnyElement<V>; 2]>,
-    kind: K,
-}
-
-impl<V: 'static + Send + Sync> LayoutNodeElement<V, Anonymous> {
-    pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, Identified> {
-        LayoutNodeElement {
-            style_cascade: self.style_cascade,
-            computed_style: self.computed_style,
-            children: self.children,
-            kind: Identified(id.into()),
-        }
-    }
-}
-
-impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
-    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, Identified> {
-    fn element_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>,
-    ) -> (crate::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<crate::Pixels>,
-        state: &mut Self::ViewState,
-        _: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        self.with_element_id(cx, |this, cx| {
-            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);
-                        }
-                    })
-                })
-            });
-        })
-    }
-}
-
-pub trait Styled {
-    fn style_cascade(&mut self) -> &mut StyleCascade;
-    fn computed_style(&mut self) -> &Style;
-}
-
-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
-    }
-}
-
-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 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),
-        }
-    }
-
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        &mut self.hover_style
-    }
-}
-
-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>,
-    ) -> (crate::LayoutId, Self::ElementState) {
-        self.child.layout(state, element_state, cx)
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<crate::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: 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> {}
-
-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
-    }
-}
-
-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: Element> ClickableElement<E> {
-    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>,
-    ) -> (crate::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<crate::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> 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
-    }
-}
-
-pub struct Div<V: 'static + Send + Sync, K: ElementKind>(
-    ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
-);
-
-impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> {
-    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 base_style(&mut self) -> &mut StyleRefinement {
-        self.style_cascade().base()
-    }
-}
-
-impl<V: 'static + Send + Sync> Div<V, Anonymous> {
-    pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified> {
-        Div(self.0.replace_child(|hoverable| {
-            hoverable.replace_child(|layout_node| layout_node.identify(id))
-        }))
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> LayoutNode<V, K> for Div<V, K> {
-    fn state(&mut self) -> &mut LayoutNodeElement<V, K> {
-        &mut self.0.child.child
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
-    fn style_cascade(&mut self) -> &mut StyleCascade {
-        self.0.child.child.style_cascade()
-    }
-
-    fn computed_style(&mut self) -> &Style {
-        self.0.child.child.computed_style()
-    }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
-    fn hover_style(&mut self) -> &mut StyleRefinement {
-        self.0.child.hover_style()
-    }
-}
-
-impl<V: 'static + Send + Sync> Clickable for Div<V, Identified> {
-    fn active_style(&mut self) -> &mut StyleRefinement {
-        self.0.active_style()
-    }
-
-    fn listeners(&mut self) -> &mut ClickListeners<V> {
-        self.0.listeners()
-    }
-}
-
-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> Element for Div<V, K>
-where
-    V: 'static + Send + Sync,
-    K: ElementKind,
-{
-    type ViewState = V;
-    type ElementState = ClickableElementState<()>;
-
-    fn id(&self) -> Option<ElementId> {
-        self.0.id()
-    }
-
-    fn layout(
-        &mut self,
-        state: &mut Self::ViewState,
-        element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) -> (crate::LayoutId, Self::ElementState) {
-        self.0.layout(state, element_state, cx)
-    }
-
-    fn paint(
-        &mut self,
-        bounds: Bounds<crate::Pixels>,
-        state: &mut Self::ViewState,
-        element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<Self::ViewState>,
-    ) {
-        self.0.paint(bounds, state, element_state, cx);
-    }
-}

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

@@ -65,7 +65,11 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
     ) where
         Self: Sized,
     {
-        let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
+        let fill_color = self
+            .computed_style()
+            .fill
+            .as_ref()
+            .and_then(|fill| fill.color());
         if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
             cx.paint_svg(bounds, path.clone(), fill_color).log_err();
         }
@@ -73,13 +77,11 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
 }
 
 impl<S: 'static + Send + Sync> Styled for Svg<S> {
-    type Style = Style;
-
-    fn style_cascade(&mut self) -> &mut refineable::Cascade<Self::Style> {
-        &mut self.style
+    fn style_cascade(&mut self) -> &mut crate::StyleCascade {
+        todo!("use layout node")
     }
 
-    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
-        self.style.base()
+    fn computed_style(&mut self) -> &Style {
+        todo!("use layout node")
     }
 }

crates/gpui3/src/gpui3.rs 🔗

@@ -11,7 +11,6 @@ mod interactive;
 mod platform;
 mod scene;
 mod style;
-mod style_helpers;
 mod styled;
 mod subscription;
 mod svg_renderer;
@@ -41,7 +40,6 @@ pub use serde_json;
 pub use smallvec;
 pub use smol::Timer;
 pub use style::*;
-pub use style_helpers::*;
 pub use styled::*;
 pub use subscription::*;
 pub use svg_renderer::*;

crates/gpui3/src/style_helpers.rs 🔗

@@ -1,364 +0,0 @@
-use crate::{
-    self as gpui3, hsla, point, px, relative, rems, AlignItems, BoxShadow, Display, Fill,
-    FlexDirection, Hsla, JustifyContent, Length, Position, SharedString, Style, StyleRefinement,
-    Styled, TextStyleRefinement,
-};
-use smallvec::smallvec;
-
-pub trait StyleHelpers: Sized + Styled<Style = Style> {
-    gpui3_macros::style_helpers!();
-
-    fn full(mut self) -> Self {
-        self.declared_style().size.width = Some(relative(1.).into());
-        self.declared_style().size.height = Some(relative(1.).into());
-        self
-    }
-
-    fn relative(mut self) -> Self {
-        self.declared_style().position = Some(Position::Relative);
-        self
-    }
-
-    fn absolute(mut self) -> Self {
-        self.declared_style().position = Some(Position::Absolute);
-        self
-    }
-
-    fn block(mut self) -> Self {
-        self.declared_style().display = Some(Display::Block);
-        self
-    }
-
-    fn flex(mut self) -> Self {
-        self.declared_style().display = Some(Display::Flex);
-        self
-    }
-
-    fn flex_col(mut self) -> Self {
-        self.declared_style().flex_direction = Some(FlexDirection::Column);
-        self
-    }
-
-    fn flex_row(mut self) -> Self {
-        self.declared_style().flex_direction = Some(FlexDirection::Row);
-        self
-    }
-
-    fn flex_1(mut self) -> Self {
-        self.declared_style().flex_grow = Some(1.);
-        self.declared_style().flex_shrink = Some(1.);
-        self.declared_style().flex_basis = Some(relative(0.).into());
-        self
-    }
-
-    fn flex_auto(mut self) -> Self {
-        self.declared_style().flex_grow = Some(1.);
-        self.declared_style().flex_shrink = Some(1.);
-        self.declared_style().flex_basis = Some(Length::Auto);
-        self
-    }
-
-    fn flex_initial(mut self) -> Self {
-        self.declared_style().flex_grow = Some(0.);
-        self.declared_style().flex_shrink = Some(1.);
-        self.declared_style().flex_basis = Some(Length::Auto);
-        self
-    }
-
-    fn flex_none(mut self) -> Self {
-        self.declared_style().flex_grow = Some(0.);
-        self.declared_style().flex_shrink = Some(0.);
-        self
-    }
-
-    fn grow(mut self) -> Self {
-        self.declared_style().flex_grow = Some(1.);
-        self
-    }
-
-    fn items_start(mut self) -> Self {
-        self.declared_style().align_items = Some(AlignItems::FlexStart);
-        self
-    }
-
-    fn items_end(mut self) -> Self {
-        self.declared_style().align_items = Some(AlignItems::FlexEnd);
-        self
-    }
-
-    fn items_center(mut self) -> Self {
-        self.declared_style().align_items = Some(AlignItems::Center);
-        self
-    }
-
-    fn justify_between(mut self) -> Self {
-        self.declared_style().justify_content = Some(JustifyContent::SpaceBetween);
-        self
-    }
-
-    fn justify_center(mut self) -> Self {
-        self.declared_style().justify_content = Some(JustifyContent::Center);
-        self
-    }
-
-    fn justify_start(mut self) -> Self {
-        self.declared_style().justify_content = Some(JustifyContent::Start);
-        self
-    }
-
-    fn justify_end(mut self) -> Self {
-        self.declared_style().justify_content = Some(JustifyContent::End);
-        self
-    }
-
-    fn justify_around(mut self) -> Self {
-        self.declared_style().justify_content = Some(JustifyContent::SpaceAround);
-        self
-    }
-
-    fn fill<F>(mut self, fill: F) -> Self
-    where
-        F: Into<Fill>,
-        Self: Sized,
-    {
-        self.declared_style().fill = Some(fill.into());
-        self
-    }
-
-    fn border_color<C>(mut self, border_color: C) -> Self
-    where
-        C: Into<Hsla>,
-        Self: Sized,
-    {
-        self.declared_style().border_color = Some(border_color.into());
-        self
-    }
-
-    fn shadow(mut self) -> Self {
-        self.declared_style().box_shadow = Some(smallvec![
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(1.)),
-                blur_radius: px(3.),
-                spread_radius: px(0.),
-            },
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(1.)),
-                blur_radius: px(2.),
-                spread_radius: px(-1.),
-            }
-        ]);
-        self
-    }
-
-    fn shadow_none(mut self) -> Self {
-        self.declared_style().box_shadow = Some(Default::default());
-        self
-    }
-
-    fn shadow_sm(mut self) -> Self {
-        self.declared_style().box_shadow = Some(smallvec![BoxShadow {
-            color: hsla(0., 0., 0., 0.05),
-            offset: point(px(0.), px(1.)),
-            blur_radius: px(2.),
-            spread_radius: px(0.),
-        }]);
-        self
-    }
-
-    fn shadow_md(mut self) -> Self {
-        self.declared_style().box_shadow = Some(smallvec![
-            BoxShadow {
-                color: hsla(0.5, 0., 0., 0.1),
-                offset: point(px(0.), px(4.)),
-                blur_radius: px(6.),
-                spread_radius: px(-1.),
-            },
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(2.)),
-                blur_radius: px(4.),
-                spread_radius: px(-2.),
-            }
-        ]);
-        self
-    }
-
-    fn shadow_lg(mut self) -> Self {
-        self.declared_style().box_shadow = Some(smallvec![
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(10.)),
-                blur_radius: px(15.),
-                spread_radius: px(-3.),
-            },
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(4.)),
-                blur_radius: px(6.),
-                spread_radius: px(-4.),
-            }
-        ]);
-        self
-    }
-
-    fn shadow_xl(mut self) -> Self {
-        self.declared_style().box_shadow = Some(smallvec![
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(20.)),
-                blur_radius: px(25.),
-                spread_radius: px(-5.),
-            },
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(8.)),
-                blur_radius: px(10.),
-                spread_radius: px(-6.),
-            }
-        ]);
-        self
-    }
-
-    fn shadow_2xl(mut self) -> Self {
-        self.declared_style().box_shadow = Some(smallvec![BoxShadow {
-            color: hsla(0., 0., 0., 0.25),
-            offset: point(px(0.), px(25.)),
-            blur_radius: px(50.),
-            spread_radius: px(-12.),
-        }]);
-        self
-    }
-
-    fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
-        let style: &mut StyleRefinement = self.declared_style();
-        &mut style.text
-    }
-
-    fn text_color(mut self, color: impl Into<Hsla>) -> Self {
-        self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
-        self
-    }
-
-    fn text_xs(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(0.75));
-        self
-    }
-
-    fn text_sm(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(0.875));
-        self
-    }
-
-    fn text_base(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(1.0));
-        self
-    }
-
-    fn text_lg(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(1.125));
-        self
-    }
-
-    fn text_xl(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(1.25));
-        self
-    }
-
-    fn text_2xl(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(1.5));
-        self
-    }
-
-    fn text_3xl(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_size = Some(rems(1.875));
-        self
-    }
-
-    fn text_decoration_none(mut self) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .underline = None;
-        self
-    }
-
-    fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.color = Some(color.into());
-        self
-    }
-
-    fn text_decoration_solid(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.wavy = false;
-        self
-    }
-
-    fn text_decoration_wavy(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.wavy = true;
-        self
-    }
-
-    fn text_decoration_0(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.thickness = px(0.);
-        self
-    }
-
-    fn text_decoration_1(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.thickness = px(1.);
-        self
-    }
-
-    fn text_decoration_2(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.thickness = px(2.);
-        self
-    }
-
-    fn text_decoration_4(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.thickness = px(4.);
-        self
-    }
-
-    fn text_decoration_8(mut self) -> Self {
-        let style = self.text_style().get_or_insert_with(Default::default);
-        let underline = style.underline.get_or_insert_with(Default::default);
-        underline.thickness = px(8.);
-        self
-    }
-
-    fn font(mut self, family_name: impl Into<SharedString>) -> Self {
-        self.text_style()
-            .get_or_insert_with(Default::default)
-            .font_family = Some(family_name.into());
-        self
-    }
-}
-
-impl<E: Styled<Style = Style>> StyleHelpers for E {}

crates/gpui3/src/styled.rs 🔗

@@ -1,48 +1,503 @@
-use crate::{Cascade, Hoverable, Pressable, Refineable, SharedString};
+use crate::{
+    self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla,
+    JustifyContent, Length, Position, SharedString, Style, StyleCascade, StyleRefinement,
+};
+use crate::{BoxShadow, TextStyleRefinement};
+use smallvec::smallvec;
 
 pub trait Styled {
-    type Style: 'static + Refineable + Send + Sync + Default;
+    fn style_cascade(&mut self) -> &mut StyleCascade;
+    fn computed_style(&mut self) -> &Style;
+    fn base_style(&mut self) -> &mut StyleRefinement {
+        self.style_cascade().base()
+    }
+
+    gpui3_macros::style_helpers!();
+
+    fn full(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().size.width = Some(relative(1.).into());
+        self.base_style().size.height = Some(relative(1.).into());
+        self
+    }
+
+    fn relative(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().position = Some(Position::Relative);
+        self
+    }
+
+    fn absolute(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().position = Some(Position::Absolute);
+        self
+    }
+
+    fn block(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().display = Some(Display::Block);
+        self
+    }
+
+    fn flex(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().display = Some(Display::Flex);
+        self
+    }
 
-    fn style_cascade(&mut self) -> &mut Cascade<Self::Style>;
-    fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
+    fn flex_col(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().flex_direction = Some(FlexDirection::Column);
+        self
+    }
+
+    fn flex_row(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().flex_direction = Some(FlexDirection::Row);
+        self
+    }
+
+    fn flex_1(mut self) -> Self
+    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
+    }
 
-    fn computed_style(&mut self) -> Self::Style {
-        Self::Style::default().refined(self.style_cascade().merged())
+    fn flex_auto(mut self) -> Self
+    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
+    }
+
+    fn flex_initial(mut self) -> Self
+    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
+    }
+
+    fn flex_none(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().flex_grow = Some(0.);
+        self.base_style().flex_shrink = Some(0.);
+        self
+    }
+
+    fn grow(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().flex_grow = Some(1.);
+        self
+    }
+
+    fn items_start(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().align_items = Some(AlignItems::FlexStart);
+        self
+    }
+
+    fn items_end(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().align_items = Some(AlignItems::FlexEnd);
+        self
+    }
+
+    fn items_center(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().align_items = Some(AlignItems::Center);
+        self
+    }
+
+    fn justify_between(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().justify_content = Some(JustifyContent::SpaceBetween);
+        self
+    }
+
+    fn justify_center(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().justify_content = Some(JustifyContent::Center);
+        self
+    }
+
+    fn justify_start(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().justify_content = Some(JustifyContent::Start);
+        self
+    }
+
+    fn justify_end(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().justify_content = Some(JustifyContent::End);
+        self
+    }
+
+    fn justify_around(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().justify_content = Some(JustifyContent::SpaceAround);
+        self
+    }
+
+    fn fill<F>(mut self, fill: F) -> Self
+    where
+        F: Into<Fill>,
+        Self: Sized,
+    {
+        self.base_style().fill = Some(fill.into());
+        self
+    }
+
+    fn border_color<C>(mut self, border_color: C) -> Self
+    where
+        C: Into<Hsla>,
+        Self: Sized,
+    {
+        self.base_style().border_color = Some(border_color.into());
+        self
+    }
+
+    fn shadow(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(smallvec![
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(1.)),
+                blur_radius: px(3.),
+                spread_radius: px(0.),
+            },
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(1.)),
+                blur_radius: px(2.),
+                spread_radius: px(-1.),
+            }
+        ]);
+        self
+    }
+
+    fn shadow_none(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(Default::default());
+        self
+    }
+
+    fn shadow_sm(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(smallvec::smallvec![BoxShadow {
+            color: hsla(0., 0., 0., 0.05),
+            offset: point(px(0.), px(1.)),
+            blur_radius: px(2.),
+            spread_radius: px(0.),
+        }]);
+        self
+    }
+
+    fn shadow_md(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(smallvec![
+            BoxShadow {
+                color: hsla(0.5, 0., 0., 0.1),
+                offset: point(px(0.), px(4.)),
+                blur_radius: px(6.),
+                spread_radius: px(-1.),
+            },
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(2.)),
+                blur_radius: px(4.),
+                spread_radius: px(-2.),
+            }
+        ]);
+        self
+    }
+
+    fn shadow_lg(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(smallvec![
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(10.)),
+                blur_radius: px(15.),
+                spread_radius: px(-3.),
+            },
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(4.)),
+                blur_radius: px(6.),
+                spread_radius: px(-4.),
+            }
+        ]);
+        self
+    }
+
+    fn shadow_xl(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(smallvec![
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(20.)),
+                blur_radius: px(25.),
+                spread_radius: px(-5.),
+            },
+            BoxShadow {
+                color: hsla(0., 0., 0., 0.1),
+                offset: point(px(0.), px(8.)),
+                blur_radius: px(10.),
+                spread_radius: px(-6.),
+            }
+        ]);
+        self
+    }
+
+    fn shadow_2xl(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.base_style().box_shadow = Some(smallvec![BoxShadow {
+            color: hsla(0., 0., 0., 0.25),
+            offset: point(px(0.), px(25.)),
+            blur_radius: px(50.),
+            spread_radius: px(-12.),
+        }]);
+        self
+    }
+
+    fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
+        let style: &mut StyleRefinement = self.base_style();
+        &mut style.text
+    }
+
+    fn text_color(mut self, color: impl Into<Hsla>) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
+        self
+    }
+
+    fn text_xs(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(0.75));
+        self
+    }
+
+    fn text_sm(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(0.875));
+        self
+    }
+
+    fn text_base(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(1.0));
+        self
+    }
+
+    fn text_lg(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(1.125));
+        self
+    }
+
+    fn text_xl(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(1.25));
+        self
+    }
+
+    fn text_2xl(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(1.5));
+        self
+    }
+
+    fn text_3xl(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_size = Some(rems(1.875));
+        self
+    }
+
+    fn text_decoration_none(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .underline = None;
+        self
+    }
+
+    fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self
+    where
+        Self: Sized,
+    {
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.color = Some(color.into());
+        self
+    }
+
+    fn text_decoration_solid(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.wavy = false;
+        self
+    }
+
+    fn text_decoration_wavy(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.wavy = true;
+        self
+    }
+
+    fn text_decoration_0(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.thickness = px(0.);
+        self
+    }
+
+    fn text_decoration_1(mut self) -> Self
+    where
+        Self: Sized,
+    {
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.thickness = px(1.);
+        self
     }
 
-    fn hover(self) -> Hoverable<Self>
+    fn text_decoration_2(mut self) -> Self
     where
-        Self: 'static + Sized + Send + Sync,
-        Self::Style: 'static + Refineable + Default + Send + Sync,
-        <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+        Self: Sized,
     {
-        Hoverable::new(self, None)
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.thickness = px(2.);
+        self
     }
 
-    fn group_hover(self, group_name: impl Into<SharedString>) -> Hoverable<Self>
+    fn text_decoration_4(mut self) -> Self
     where
-        Self: 'static + Sized + Send + Sync,
-        Self::Style: 'static + Refineable + Default + Send + Sync,
-        <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+        Self: Sized,
     {
-        Hoverable::new(self, Some(group_name.into()))
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.thickness = px(4.);
+        self
     }
 
-    fn active(self) -> Pressable<Self>
+    fn text_decoration_8(mut self) -> Self
     where
-        Self: 'static + Sized + Send + Sync,
-        Self::Style: 'static + Refineable + Default + Send + Sync,
-        <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+        Self: Sized,
     {
-        Pressable::new(self, None)
+        let style = self.text_style().get_or_insert_with(Default::default);
+        let underline = style.underline.get_or_insert_with(Default::default);
+        underline.thickness = px(8.);
+        self
     }
 
-    fn group_active(self, group_name: impl Into<SharedString>) -> Pressable<Self>
+    fn font(mut self, family_name: impl Into<SharedString>) -> Self
     where
-        Self: 'static + Sized + Send + Sync,
-        Self::Style: 'static + Refineable + Default + Send + Sync,
-        <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+        Self: Sized,
     {
-        Pressable::new(self, Some(group_name.into()))
+        self.text_style()
+            .get_or_insert_with(Default::default)
+            .font_family = Some(family_name.into());
+        self
     }
 }

crates/gpui3/src/view.rs 🔗

@@ -148,7 +148,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
     }
 
     fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
-        cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
+        cx.with_element_id(IdentifiedElement::id(self), |cx| {
             self.state.update(cx, |state, cx| {
                 let mut element = (self.render)(state, cx);
                 let layout_id = element.layout(state, cx);
@@ -159,7 +159,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
     }
 
     fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
-        cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
+        cx.with_element_id(IdentifiedElement::id(self), |cx| {
             self.state.update(cx, |state, cx| {
                 let element = element.downcast_mut::<AnyElement<S>>().unwrap();
                 element.paint(state, None, cx);

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.declared_style();
+            let mut style = self.base_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.declared_style();
+            let mut style = self.base_style();
             #(#field_assignments)*
             self
         }