Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/elements.rs        |   1 
crates/gpui3/src/elements/nested.rs | 133 +++++++++++++++++++++++++++++++
crates/gpui3/src/style.rs           |   4 
crates/gpui3/src/taffy.rs           |   6 +
crates/gpui3/src/view.rs            |   2 
5 files changed, 144 insertions(+), 2 deletions(-)

Detailed changes

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

@@ -0,0 +1,133 @@
+use crate::{AnyElement, Element, IntoAnyElement, Style, StyleCascade, StyleRefinement};
+use refineable::Refineable;
+use smallvec::SmallVec;
+
+trait LayoutNode<V: 'static + Send + Sync> {
+    fn state(&mut self) -> &mut LayoutNodeState<V>;
+
+    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
+    }
+}
+
+struct LayoutNodeState<V: 'static + Send + Sync> {
+    style_cascade: StyleCascade,
+    children: SmallVec<[AnyElement<V>; 2]>,
+}
+
+impl<V> IntoAnyElement<V> for LayoutNodeState<V>
+where
+    V: 'static + Send + Sync,
+{
+    fn into_any(self) -> AnyElement<V> {
+        AnyElement::new(self)
+    }
+}
+
+impl<V: 'static + Send + Sync> Element for LayoutNodeState<V> {
+    type ViewState = V;
+    type ElementState = ();
+
+    fn element_id(&self) -> Option<crate::ElementId> {
+        None
+    }
+
+    fn layout(
+        &mut self,
+        state: &mut Self::ViewState,
+        _: Option<Self::ElementState>,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) -> (crate::LayoutId, Self::ElementState) {
+        let layout_ids = self
+            .children
+            .iter_mut()
+            .map(|child| child.layout(state, cx))
+            .collect::<Vec<_>>();
+
+        // todo!("pass just the style cascade")
+        let style = Style::from_refinement(&self.style_cascade().merged());
+        let layout_id = cx.request_layout(style, layout_ids);
+        (layout_id, ())
+    }
+
+    fn paint(
+        &mut self,
+        _: crate::Bounds<crate::Pixels>,
+        state: &mut Self::ViewState,
+        _: &mut Self::ElementState,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) {
+        for child in &mut self.children {
+            child.paint(state, None, cx);
+        }
+    }
+}
+
+pub trait Styled {
+    fn style_cascade(&mut self) -> &mut StyleCascade;
+}
+
+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 HoverableState<Child: Styled + Element> {
+    hover_style: StyleRefinement,
+    child: Child,
+}
+
+impl<Child: Styled + Element> HoverableState<Child> {
+    fn hover_style(&mut self) -> &mut StyleRefinement {
+        &mut self.hover_style
+    }
+}
+
+struct Div<V: 'static + Send + Sync>(HoverableState<LayoutNodeState<V>>);
+
+impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {
+    fn state(&mut self) -> &mut LayoutNodeState<V> {
+        &mut self.0.child
+    }
+}
+
+impl<V: 'static + Send + Sync> Styled for LayoutNodeState<V> {
+    fn style_cascade(&mut self) -> &mut StyleCascade {
+        &mut self.style_cascade
+    }
+}
+
+impl<V: 'static + Send + Sync> Styled for Div<V> {
+    fn style_cascade(&mut self) -> &mut StyleCascade {
+        &mut self.0.child.style_cascade
+    }
+}
+
+impl<V: 'static + Send + Sync> Hoverable for Div<V> {
+    fn hover_style(&mut self) -> &mut StyleRefinement {
+        self.0.hover_style()
+    }
+}

crates/gpui3/src/style.rs 🔗

@@ -4,13 +4,15 @@ use crate::{
     FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, Result, RunStyle, SharedString,
     Size, SizeRefinement, ViewContext, WindowContext,
 };
-use refineable::Refineable;
+use refineable::{Cascade, Refineable};
 use smallvec::SmallVec;
 pub use taffy::style::{
     AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
     Overflow, Position,
 };
 
+pub type StyleCascade = Cascade<Style>;
+
 #[derive(Clone, Refineable, Debug)]
 #[refineable(debug)]
 pub struct Style {

crates/gpui3/src/taffy.rs 🔗

@@ -67,6 +67,8 @@ impl TaffyLayoutEngine {
             .into()
     }
 
+    // Used to understand performance
+    #[allow(dead_code)]
     fn count_all_children(&self, parent: LayoutId) -> anyhow::Result<u32> {
         let mut count = 0;
 
@@ -81,6 +83,8 @@ impl TaffyLayoutEngine {
         Ok(count)
     }
 
+    // Used to understand performance
+    #[allow(dead_code)]
     fn max_depth(&self, depth: u32, parent: LayoutId) -> anyhow::Result<u32> {
         println!(
             "{parent:?} at depth {depth} has {} children",
@@ -96,6 +100,8 @@ impl TaffyLayoutEngine {
         Ok(depth + 1 + max_child_depth)
     }
 
+    // Used to understand performance
+    #[allow(dead_code)]
     fn get_edges(&self, parent: LayoutId) -> anyhow::Result<Vec<(LayoutId, LayoutId)>> {
         let mut edges = Vec::new();
 

crates/gpui3/src/view.rs 🔗

@@ -4,7 +4,7 @@ use crate::{
     AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle,
     IdentifiedElement, IntoAnyElement, LayoutId, Pixels, ViewContext, WindowContext,
 };
-use std::{any::Any, marker::PhantomData, sync::Arc};
+use std::{marker::PhantomData, sync::Arc};
 
 pub struct View<S: Send + Sync> {
     state: Handle<S>,