Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/element.rs             |   8 
crates/gpui3/src/elements/clickable.rs  |   2 
crates/gpui3/src/elements/div.rs        |   4 
crates/gpui3/src/elements/group.rs      |   4 
crates/gpui3/src/elements/hoverable.rs  |   4 
crates/gpui3/src/elements/identified.rs |   2 
crates/gpui3/src/elements/img.rs        |   2 
crates/gpui3/src/elements/nested.rs     | 276 ++++++++++++++++++--------
crates/gpui3/src/elements/pressable.rs  |   2 
crates/gpui3/src/elements/svg.rs        |   2 
crates/gpui3/src/elements/text.rs       |   2 
crates/gpui3/src/view.rs                |  12 
crates/gpui3/src/window.rs              |   2 
crates/ui2/src/theme.rs                 |   2 
14 files changed, 218 insertions(+), 106 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -11,7 +11,7 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
     type ViewState: 'static + Send + Sync;
     type ElementState: 'static + Send + Sync;
 
-    fn element_id(&self) -> Option<ElementId>;
+    fn id(&self) -> Option<ElementId>;
 
     fn layout(
         &mut self,
@@ -38,7 +38,7 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
 
 pub trait IdentifiedElement: Element {
     fn element_id(&self) -> ElementId {
-        Element::element_id(self).unwrap()
+        Element::id(self).unwrap()
     }
 
     fn on_click(
@@ -126,7 +126,7 @@ impl<E: Element> RenderedElement<E> {
         frame_state: &mut Option<E::ElementState>,
         cx: &mut ViewContext<E::ViewState>,
     ) {
-        if let Some(id) = self.element.element_id() {
+        if let Some(id) = self.element.id() {
             cx.with_element_state(id, |element_state, cx| {
                 let mut element_state = element_state.unwrap();
                 self.element
@@ -146,7 +146,7 @@ where
     S: 'static + Send + Sync,
 {
     fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
-        let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
+        let (layout_id, frame_state) = if let Some(id) = self.element.id() {
             let layout_id = cx.with_element_state(id, |element_state, cx| {
                 self.element.layout(state, element_state, cx)
             });

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

@@ -64,7 +64,7 @@ where
     type ViewState = E::ViewState;
     type ElementState = ClickableState<E::ElementState>;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         Some(IdentifiedElement::element_id(&self.child))
     }
 

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

@@ -47,7 +47,7 @@ where
     type ViewState = S;
     type ElementState = ();
 
-    fn element_id(&self) -> Option<ElementId> {
+    fn id(&self) -> Option<ElementId> {
         self.id.clone()
     }
 
@@ -188,7 +188,7 @@ where
         cx: &mut ViewContext<S>,
         f: impl FnOnce(&mut Self, &mut ViewContext<S>) -> R,
     ) -> R {
-        if let Some(element_id) = self.element_id() {
+        if let Some(element_id) = self.id() {
             cx.with_element_id(element_id, |cx| f(self, cx))
         } else {
             f(self, cx)

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

@@ -37,8 +37,8 @@ impl<E: Element> Element for Group<E> {
     type ViewState = E::ViewState;
     type ElementState = E::ElementState;
 
-    fn element_id(&self) -> Option<ElementId> {
-        self.child.element_id()
+    fn id(&self) -> Option<ElementId> {
+        self.child.id()
     }
 
     fn layout(

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

@@ -71,8 +71,8 @@ where
     type ViewState = E::ViewState;
     type ElementState = E::ElementState;
 
-    fn element_id(&self) -> Option<ElementId> {
-        self.child.element_id()
+    fn id(&self) -> Option<ElementId> {
+        self.child.id()
     }
 
     fn layout(

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

@@ -21,7 +21,7 @@ impl<E: Element> Element for Identified<E> {
     type ViewState = E::ViewState;
     type ElementState = E::ElementState;
 
-    fn element_id(&self) -> Option<ElementId> {
+    fn id(&self) -> Option<ElementId> {
         Some(self.id.clone())
     }
 

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

@@ -48,7 +48,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
     type ViewState = S;
     type ElementState = ();
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         None
     }
 

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

@@ -1,5 +1,5 @@
 use crate::{
-    group_bounds, AnyElement, DispatchPhase, Element, IdentifiedElement, IntoAnyElement,
+    group_bounds, AnyElement, DispatchPhase, Element, ElementId, IdentifiedElement, IntoAnyElement,
     MouseDownEvent, MouseMoveEvent, MouseUpEvent, SharedString, Style, StyleCascade,
     StyleRefinement, ViewContext,
 };
@@ -11,8 +11,8 @@ use std::sync::{
     Arc,
 };
 
-trait LayoutNode<V: 'static + Send + Sync> {
-    fn state(&mut self) -> &mut LayoutNodeState<V>;
+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
@@ -35,26 +35,75 @@ trait LayoutNode<V: 'static + Send + Sync> {
     }
 }
 
-struct LayoutNodeState<V: 'static + Send + Sync> {
+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, 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> IntoAnyElement<V> for LayoutNodeState<V>
+impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, Identified> {
+    fn element_id(&self) -> crate::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> Element for LayoutNodeState<V> {
+impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
     type ViewState = V;
     type ElementState = ();
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         None
     }
 
@@ -94,48 +143,6 @@ pub trait Styled {
     fn computed_style(&mut self) -> &Style;
 }
 
-pub struct StyledElement<E> {
-    child: E,
-}
-
-impl<E> IntoAnyElement<E::ViewState> for StyledElement<E>
-where
-    E: Element + Styled,
-{
-    fn into_any(self) -> AnyElement<E::ViewState> {
-        AnyElement::new(self)
-    }
-}
-
-impl<E: Element + Styled> Element for StyledElement<E> {
-    type ViewState = E::ViewState;
-    type ElementState = E::ElementState;
-
-    fn element_id(&self) -> Option<crate::ElementId> {
-        self.child.element_id()
-    }
-
-    fn layout(
-        &mut self,
-        state: &mut Self::ViewState,
-        element_state: Option<Self::ElementState>,
-        cx: &mut crate::ViewContext<Self::ViewState>,
-    ) -> (crate::LayoutId, Self::ElementState) {
-        self.child.layout(state, element_state, cx)
-    }
-
-    fn paint(
-        &mut self,
-        bounds: crate::Bounds<crate::Pixels>,
-        state: &mut Self::ViewState,
-        element_state: &mut Self::ElementState,
-        cx: &mut crate::ViewContext<Self::ViewState>,
-    ) {
-        self.child.computed_style().paint(bounds, cx);
-        self.child.paint(bounds, state, element_state, cx);
-    }
-}
-
 pub trait Hoverable {
     fn hover_style(&mut self) -> &mut StyleRefinement;
 
@@ -148,15 +155,28 @@ pub trait Hoverable {
     }
 }
 
-struct HoverableElement<Child> {
+struct HoverableElement<E> {
     hover_style: StyleRefinement,
     group: Option<SharedString>,
     cascade_slot: CascadeSlot,
     hovered: Arc<AtomicBool>,
-    child: Child,
+    child: E,
 }
 
-impl<Child: Styled + Element> HoverableElement<Child> {
+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
     }
@@ -164,7 +184,7 @@ impl<Child: Styled + Element> HoverableElement<Child> {
 
 impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
 where
-    E: Element + Styled,
+    E: Styled + Element,
 {
     fn into_any(self) -> AnyElement<E::ViewState> {
         AnyElement::new(self)
@@ -173,13 +193,13 @@ where
 
 impl<E> Element for HoverableElement<E>
 where
-    E: Element + Styled,
+    E: Styled + Element,
 {
     type ViewState = E::ViewState;
     type ElementState = E::ElementState;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
-        self.child.element_id()
+    fn id(&self) -> Option<crate::ElementId> {
+        self.child.id()
     }
 
     fn layout(
@@ -224,7 +244,19 @@ where
     }
 }
 
-pub trait Clickable: IdentifiedElement + Sized {
+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>;
 
@@ -252,26 +284,40 @@ pub trait Clickable: IdentifiedElement + Sized {
 type ClickListeners<V> =
     SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
 
-pub struct ClickableElementState<E: IdentifiedElement> {
+pub struct ClickableElementState<E: 'static + Send + Sync> {
     mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
-    child_state: E::ElementState,
+    child_state: E,
 }
 
 pub struct MouseClickEvent {
-    down: MouseDownEvent,
-    up: MouseUpEvent,
+    pub down: MouseDownEvent,
+    pub up: MouseUpEvent,
 }
 
-pub struct ClickableElement<E: IdentifiedElement> {
+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: IdentifiedElement + Styled,
+    E: Styled + Element,
 {
     fn into_any(self) -> AnyElement<E::ViewState> {
         AnyElement::new(self)
@@ -280,13 +326,13 @@ where
 
 impl<E> Element for ClickableElement<E>
 where
-    E: IdentifiedElement + Styled,
+    E: Styled + Element,
 {
     type ViewState = E::ViewState;
-    type ElementState = ClickableElementState<E>;
+    type ElementState = ClickableElementState<E::ElementState>;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
-        Some(IdentifiedElement::element_id(&self.child))
+    fn id(&self) -> Option<crate::ElementId> {
+        self.child.id()
     }
 
     fn layout(
@@ -371,37 +417,103 @@ where
     }
 }
 
-struct Div<V: 'static + Send + Sync>(HoverableElement<LayoutNodeState<V>>);
+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
+    }
 
-impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {
-    fn state(&mut self) -> &mut LayoutNodeState<V> {
-        &mut self.0.child
+    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState> {
+        &mut self.listeners
     }
 }
 
-impl<V: 'static + Send + Sync> Styled for LayoutNodeState<V> {
-    fn style_cascade(&mut self) -> &mut StyleCascade {
-        &mut self.style_cascade
+pub struct Div<V: 'static + Send + Sync, K: ElementKind>(
+    ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
+);
+
+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))
+        }))
     }
+}
 
-    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, 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> Styled for Div<V> {
+impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
     fn style_cascade(&mut self) -> &mut StyleCascade {
-        self.0.child.style_cascade()
+        self.0.child.child.style_cascade()
     }
 
     fn computed_style(&mut self) -> &Style {
-        self.0.child.computed_style()
+        self.0.child.child.computed_style()
     }
 }
 
-impl<V: 'static + Send + Sync> Hoverable for Div<V> {
+impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
     fn hover_style(&mut self) -> &mut StyleRefinement {
-        self.0.hover_style()
+        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 crate::ViewContext<Self::ViewState>,
+    ) -> (crate::LayoutId, Self::ElementState) {
+        self.0.layout(state, element_state, cx)
+    }
+
+    fn paint(
+        &mut self,
+        bounds: crate::Bounds<crate::Pixels>,
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) {
+        self.0.paint(bounds, state, element_state, cx);
     }
 }

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

@@ -74,7 +74,7 @@ where
     type ViewState = E::ViewState;
     type ElementState = PressableState<E::ElementState>;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         Some(IdentifiedElement::element_id(&self.child))
     }
 

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

@@ -39,7 +39,7 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
     type ViewState = S;
     type ElementState = ();
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         None
     }
 

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

@@ -54,7 +54,7 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
     type ViewState = S;
     type ElementState = Arc<Mutex<Option<TextElementState>>>;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         None
     }
 

crates/gpui3/src/view.rs 🔗

@@ -57,7 +57,7 @@ impl<S: 'static + Send + Sync> Element for View<S> {
     type ViewState = ();
     type ElementState = AnyElement<S>;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         Some(ElementId::View(self.state.id))
     }
 
@@ -112,8 +112,8 @@ where
     type ViewState = ParentViewState;
     type ElementState = AnyBox;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
-        Element::element_id(&self.view)
+    fn id(&self) -> Option<crate::ElementId> {
+        Element::id(&self.view)
     }
 
     fn layout(
@@ -188,7 +188,7 @@ impl Element for AnyView {
     type ViewState = ();
     type ElementState = AnyBox;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
+    fn id(&self) -> Option<crate::ElementId> {
         Some(ElementId::View(self.view.lock().entity_id()))
     }
 
@@ -233,8 +233,8 @@ where
     type ViewState = ParentViewState;
     type ElementState = AnyBox;
 
-    fn element_id(&self) -> Option<crate::ElementId> {
-        Element::element_id(&self.view)
+    fn id(&self) -> Option<crate::ElementId> {
+        Element::id(&self.view)
     }
 
     fn layout(

crates/gpui3/src/window.rs 🔗

@@ -600,7 +600,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
 
             let mut root_view = cx.window.root_view.take().unwrap();
 
-            if let Some(element_id) = root_view.element_id() {
+            if let Some(element_id) = root_view.id() {
                 cx.with_element_state(element_id, |element_state, cx| {
                     let element_state = draw_with_element_state(&mut root_view, element_state, cx);
                     ((), element_state)

crates/ui2/src/theme.rs 🔗

@@ -160,7 +160,7 @@ impl<E: Element> Element for Themed<E> {
     type ViewState = E::ViewState;
     type ElementState = E::ElementState;
 
-    fn element_id(&self) -> Option<gpui3::ElementId> {
+    fn id(&self) -> Option<gpui3::ElementId> {
         None
     }