Compiling checkpoint

Nathan Sobo created

Change summary

crates/gpui/playground/src/adapter.rs               |   1 
crates/gpui/playground/src/components.rs            |  72 ++++++-
crates/gpui/playground/src/element.rs               | 140 ++++++++++----
crates/gpui/playground/src/frame.rs                 |  36 +--
crates/gpui/playground/src/playground.rs            |   1 
crates/gpui/playground/src/style.rs                 |   8 
crates/gpui/playground_macros/src/derive_element.rs |  48 +++++
7 files changed, 224 insertions(+), 82 deletions(-)

Detailed changes

crates/gpui/playground/src/adapter.rs 🔗

@@ -4,7 +4,6 @@ use util::ResultExt;
 
 use crate::element::AnyElement;
 
-#[derive(Clone)]
 pub struct Adapter<V>(pub(crate) AnyElement<V>);
 
 impl<V: 'static> gpui::Element<V> for Adapter<V> {

crates/gpui/playground/src/components.rs 🔗

@@ -1,41 +1,57 @@
-use crate::{element::Element, frame, themes::rose_pine};
+use crate::{
+    element::{AnyElement, Element, ElementMetadata},
+    frame,
+    themes::rose_pine,
+};
 use gpui::ViewContext;
-use std::{any::Any, borrow::Cow, marker::PhantomData, rc::Rc};
+use std::{borrow::Cow, marker::PhantomData, rc::Rc};
+
+struct ButtonHandlers<V, D> {
+    click: Option<Rc<dyn Fn(&mut V, &D)>>,
+}
+
+impl<V, D> Default for ButtonHandlers<V, D> {
+    fn default() -> Self {
+        Self { click: None }
+    }
+}
 
 pub struct Button<V: 'static, D: 'static> {
+    metadata: ElementMetadata<V>,
+    button_handlers: ButtonHandlers<V, D>,
     label: Cow<'static, str>,
     data: Rc<D>,
-    click_handler: Option<Rc<dyn Fn(&mut V, &dyn Any)>>,
     view_type: PhantomData<V>,
 }
 
 impl<V: 'static> Button<V, ()> {
     fn new(label: impl Into<Cow<'static, str>>) -> Self {
         Self {
+            metadata: Default::default(),
+            button_handlers: ButtonHandlers::default(),
             label: label.into(),
             data: Rc::new(()),
-            click_handler: None,
             view_type: PhantomData,
         }
     }
 
     pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
         Button {
+            metadata: Default::default(),
+            button_handlers: ButtonHandlers::default(),
             label: self.label,
             data: Rc::new(data),
-            click_handler: None,
             view_type: PhantomData,
         }
     }
 }
 
 impl<V: 'static, D: 'static> Button<V, D> {
-    fn click(mut self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
-        self.click_handler = Some(Rc::new(move |view, data| {
-            let data = data.downcast_ref::<D>().unwrap();
-            handler(view, data);
-        }));
-        self
+    fn click(self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
+        let data = self.data.clone();
+        Element::click(self, move |view, _| {
+            handler(view, data.as_ref());
+        })
     }
 }
 
@@ -48,7 +64,7 @@ impl<V: 'static, D: 'static> Button<V, D> {
         // TODO: Drive from the context
         let button = frame().fill(rose_pine::dawn().error(0.5)).h_5().w_9();
 
-        if let Some(handler) = self.click_handler.clone() {
+        if let Some(handler) = self.button_handlers.click.clone() {
             let data = self.data.clone();
             button.click(move |view, event| handler(view, data.as_ref()))
         } else {
@@ -56,3 +72,35 @@ impl<V: 'static, D: 'static> Button<V, D> {
         }
     }
 }
+
+impl<V: 'static, D> Element<V> for Button<V, D> {
+    type Layout = AnyElement<V>;
+
+    fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
+        &mut self.metadata.style
+    }
+
+    fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
+        &mut self.metadata.handlers
+    }
+
+    fn layout(
+        &mut self,
+        view: &mut V,
+        cx: &mut crate::element::LayoutContext<V>,
+    ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
+        let mut element = self.render(view, cx).into_any();
+        let node_id = element.layout(view, cx)?;
+        Ok((node_id, element))
+    }
+
+    fn paint<'a>(
+        &mut self,
+        layout: crate::element::Layout<'a, Self::Layout>,
+        view: &mut V,
+        cx: &mut crate::element::PaintContext<V>,
+    ) -> anyhow::Result<()> {
+        layout.from_element.paint(view, cx)?;
+        Ok(())
+    }
+}

crates/gpui/playground/src/element.rs 🔗

@@ -1,13 +1,14 @@
-use std::{any::Any, sync::Arc};
+use std::{any::Any, rc::Rc};
 
 use crate::{
     adapter::Adapter,
-    style::{DefinedLength, Display, Fill, Length, Overflow, Position, Style},
+    style::{DefinedLength, Display, ElementStyle, Fill, Length, Overflow, Position},
 };
 use anyhow::Result;
 use derive_more::{Deref, DerefMut};
 use gpui::{
-    EngineLayout, LayoutContext as LegacyLayoutContext, PaintContext as LegacyPaintContext,
+    scene::MouseClick, EngineLayout, LayoutContext as LegacyLayoutContext,
+    PaintContext as LegacyPaintContext,
 };
 use playground_macros::tailwind_lengths;
 pub use taffy::tree::NodeId;
@@ -25,14 +26,48 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
     pub(crate) scene: &'d mut gpui::SceneBuilder,
 }
 
-pub trait Element<V: 'static>: 'static + Clone {
+pub struct Layout<'a, E: ?Sized> {
+    pub from_engine: EngineLayout,
+    pub from_element: &'a mut E,
+}
+
+pub struct ElementHandlers<V> {
+    click: Option<Rc<dyn Fn(&mut V, MouseClick)>>,
+}
+
+pub struct ElementMetadata<V> {
+    pub style: ElementStyle,
+    pub handlers: ElementHandlers<V>,
+}
+
+impl<V> Default for ElementMetadata<V> {
+    fn default() -> Self {
+        Self {
+            style: ElementStyle::default(),
+            handlers: ElementHandlers::default(),
+        }
+    }
+}
+
+impl<V> Default for ElementHandlers<V> {
+    fn default() -> Self {
+        ElementHandlers { click: None }
+    }
+}
+
+pub trait Element<V: 'static>: 'static {
     type Layout: 'static;
 
-    fn style_mut(&mut self) -> &mut Style;
+    fn style_mut(&mut self) -> &mut ElementStyle;
+    fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
         -> Result<(NodeId, Self::Layout)>;
-    fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext<V>)
-        -> Result<()>;
+    fn paint<'a>(
+        &mut self,
+        layout: Layout<Self::Layout>,
+        view: &mut V,
+        cx: &mut PaintContext<V>,
+    ) -> Result<()>;
 
     /// Convert to a dynamically-typed element suitable for layout and paint.
     fn into_any(self) -> AnyElement<V>
@@ -53,6 +88,16 @@ pub trait Element<V: 'static>: 'static + Clone {
         Adapter(self.into_any())
     }
 
+    fn click(mut self, handler: impl Fn(&mut V, MouseClick) + 'static) -> Self
+    where
+        Self: Sized,
+    {
+        self.handlers_mut().click = Some(Rc::new(move |view, event| {
+            handler(view, event);
+        }));
+        self
+    }
+
     // Display ////////////////////
 
     fn block(mut self) -> Self
@@ -265,46 +310,59 @@ pub trait Element<V: 'static>: 'static + Clone {
 }
 
 pub trait ElementObject<V> {
-    fn style_mut(&mut self) -> &mut Style;
+    fn style_mut(&mut self) -> &mut ElementStyle;
+    fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
-        -> Result<(NodeId, Arc<dyn Any>)>;
-    fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext<V>)
-        -> Result<()>;
-    fn clone_object(&self) -> Box<dyn ElementObject<V>>;
+        -> Result<(NodeId, Box<dyn Any>)>;
+    fn paint(
+        &mut self,
+        layout: Layout<dyn Any>,
+        view: &mut V,
+        cx: &mut PaintContext<V>,
+    ) -> Result<()>;
 }
 
 impl<V: 'static, E: Element<V>> ElementObject<V> for E {
-    fn style_mut(&mut self) -> &mut Style {
-        self.style_mut()
+    fn style_mut(&mut self) -> &mut ElementStyle {
+        Element::style_mut(self)
+    }
+
+    fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
+        Element::handlers_mut(self)
     }
 
     fn layout(
         &mut self,
         view: &mut V,
         cx: &mut LayoutContext<V>,
-    ) -> Result<(NodeId, Arc<dyn Any>)> {
+    ) -> Result<(NodeId, Box<dyn Any>)> {
         let (node_id, layout) = self.layout(view, cx)?;
-        let layout = Arc::new(layout) as Arc<dyn Any>;
+        let layout = Box::new(layout) as Box<dyn Any>;
         Ok((node_id, layout))
     }
 
     fn paint(
         &mut self,
-        layout: EngineLayout,
+        layout: Layout<dyn Any>,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Result<()> {
+        let layout = Layout {
+            from_engine: layout.from_engine,
+            from_element: layout.from_element.downcast_mut::<E::Layout>().unwrap(),
+        };
+
         self.paint(layout, view, cx)
     }
 
-    fn clone_object(&self) -> Box<dyn ElementObject<V>> {
-        Box::new(Clone::clone(self))
-    }
+    // fn clone_object(&self) -> Box<dyn ElementObject<V>> {
+    //     Box::new(Clone::clone(self))
+    // }
 }
 
 pub struct AnyElement<V> {
     element: Box<dyn ElementObject<V>>,
-    layout: Option<(NodeId, Arc<dyn Any>)>,
+    layout: Option<(NodeId, Box<dyn Any>)>,
 }
 
 impl<V> AnyElement<V> {
@@ -315,32 +373,33 @@ impl<V> AnyElement<V> {
     }
 
     pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
-        let (layout_node_id, layout) = self.layout.clone().expect("paint called before layout");
-        let layout = cx
-            .layout_engine()
-            .unwrap()
-            .computed_layout(layout_node_id)
-            .expect("you can currently only use playground elements within an adapter");
-        self.element.paint(layout, view, cx)
-    }
-}
+        let (layout_node_id, element_layout) =
+            self.layout.as_mut().expect("paint called before layout");
+
+        let layout = Layout {
+            from_engine: cx
+                .layout_engine()
+                .unwrap()
+                .computed_layout(*layout_node_id)
+                .expect("you can currently only use playground elements within an adapter"),
+            from_element: element_layout.as_mut(),
+        };
 
-impl<V> Clone for AnyElement<V> {
-    fn clone(&self) -> Self {
-        Self {
-            element: self.element.clone_object(),
-            layout: self.layout.clone(),
-        }
+        self.element.paint(layout, view, cx)
     }
 }
 
 impl<V: 'static> Element<V> for AnyElement<V> {
     type Layout = ();
 
-    fn style_mut(&mut self) -> &mut Style {
+    fn style_mut(&mut self) -> &mut ElementStyle {
         self.element.style_mut()
     }
 
+    fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
+        self.element.handlers_mut()
+    }
+
     fn layout(
         &mut self,
         view: &mut V,
@@ -349,12 +408,7 @@ impl<V: 'static> Element<V> for AnyElement<V> {
         Ok((self.layout(view, cx)?, ()))
     }
 
-    fn paint(
-        &mut self,
-        layout: EngineLayout,
-        view: &mut V,
-        cx: &mut PaintContext<V>,
-    ) -> Result<()> {
+    fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
         self.paint(view, cx)
     }
 }

crates/gpui/playground/src/frame.rs 🔗

@@ -1,18 +1,20 @@
 use crate::{
-    element::{AnyElement, Element, LayoutContext, NodeId, PaintContext},
-    style::Style,
+    element::{AnyElement, Element, ElementHandlers, Layout, LayoutContext, NodeId, PaintContext},
+    style::ElementStyle,
 };
 use anyhow::{anyhow, Result};
-use gpui::{EngineLayout, LayoutNodeId};
+use gpui::LayoutNodeId;
 
 pub struct Frame<V> {
-    style: Style,
+    style: ElementStyle,
+    handlers: ElementHandlers<V>,
     children: Vec<AnyElement<V>>,
 }
 
 pub fn frame<V>() -> Frame<V> {
     Frame {
-        style: Style::default(),
+        style: ElementStyle::default(),
+        handlers: ElementHandlers::default(),
         children: Vec::new(),
     }
 }
@@ -20,10 +22,14 @@ pub fn frame<V>() -> Frame<V> {
 impl<V: 'static> Element<V> for Frame<V> {
     type Layout = ();
 
-    fn style_mut(&mut self) -> &mut Style {
+    fn style_mut(&mut self) -> &mut ElementStyle {
         &mut self.style
     }
 
+    fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
+        &mut self.handlers
+    }
+
     fn layout(
         &mut self,
         view: &mut V,
@@ -44,14 +50,9 @@ impl<V: 'static> Element<V> for Frame<V> {
         Ok((node_id, ()))
     }
 
-    fn paint(
-        &mut self,
-        layout: EngineLayout,
-        view: &mut V,
-        cx: &mut PaintContext<V>,
-    ) -> Result<()> {
+    fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
         cx.scene.push_quad(gpui::scene::Quad {
-            bounds: layout.bounds,
+            bounds: layout.from_engine.bounds,
             background: self.style.fill.color().map(Into::into),
             border: Default::default(),
             corner_radii: Default::default(),
@@ -63,12 +64,3 @@ impl<V: 'static> Element<V> for Frame<V> {
         Ok(())
     }
 }
-
-impl<V> Clone for Frame<V> {
-    fn clone(&self) -> Self {
-        Self {
-            style: self.style.clone(),
-            children: self.children.clone(),
-        }
-    }
-}

crates/gpui/playground/src/style.rs 🔗

@@ -5,7 +5,7 @@ pub use taffy::style::{
 };
 
 #[derive(Clone)]
-pub struct Style {
+pub struct ElementStyle {
     /// What layout strategy should be used?
     pub display: Display,
 
@@ -67,8 +67,8 @@ pub struct Style {
     pub fill: Fill,
 }
 
-impl Style {
-    pub const DEFAULT: Style = Style {
+impl ElementStyle {
+    pub const DEFAULT: ElementStyle = ElementStyle {
         display: Display::DEFAULT,
         overflow: Point {
             x: Overflow::Visible,
@@ -137,7 +137,7 @@ impl Style {
     }
 }
 
-impl Default for Style {
+impl Default for ElementStyle {
     fn default() -> Self {
         Self::DEFAULT.clone()
     }

crates/gpui/playground_macros/src/derive_element.rs 🔗

@@ -0,0 +1,48 @@
+// type Result = ();
+// type LayoutContext<> = ();
+
+// trait Element<V: 'static>: 'static + Clone {
+//     type Layout: 'static;
+
+//     fn style_mut(&mut self) -> &mut Style;
+//     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
+//         -> Result<(NodeId, Self::Layout)>;
+//     fn paint<'a>(
+//         &mut self,
+//         layout: Layout<'a, Self::Layout>,
+//         view: &mut V,
+//         cx: &mut PaintContext<V>,
+//     ) -> Result<()>;
+// }
+
+// struct Button {
+//     style: Style,
+// }
+
+// type Style = ();
+
+// impl Button {
+//     fn render<V>() -> impl Element<V> {
+//         todo!()
+//     }
+// }
+
+// impl<V: 'static> Element<V> for Foo {
+//     type Layout = ();
+
+//     fn style_mut(&mut self) -> &mut Style {
+//         unimplemented!()
+//     }
+
+//     fn layout(
+//         &mut self,
+//         view: &mut V,
+//         cx: &mut LayoutContext<V>,
+//     ) -> Result<(NodeId, Self::Layout)> {
+//         unimplemented!()
+//     }
+
+//     fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
+//         unimplemented!()
+//     }
+// }