WIP

Nathan Sobo created

Change summary

crates/gpui/playground/src/components.rs               |  58 ++++++
crates/gpui/playground/src/element.rs                  |  30 ++
crates/gpui/playground/src/frame.rs                    |   9 
crates/gpui/playground_macros/src/derive_element.rs    |   0 
crates/gpui/playground_macros/src/playground_macros.rs | 101 -----------
crates/gpui/playground_macros/src/tailwind_lengths.rs  |  99 +++++++++++
crates/gpui/src/app/window.rs                          |   6 
crates/gpui/src/gpui.rs                                |   3 
8 files changed, 199 insertions(+), 107 deletions(-)

Detailed changes

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

@@ -0,0 +1,58 @@
+use crate::{element::Element, frame, themes::rose_pine};
+use gpui::ViewContext;
+use std::{any::Any, borrow::Cow, marker::PhantomData, rc::Rc};
+
+pub struct Button<V: 'static, D: 'static> {
+    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 {
+            label: label.into(),
+            data: Rc::new(()),
+            click_handler: None,
+            view_type: PhantomData,
+        }
+    }
+
+    pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
+        Button {
+            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
+    }
+}
+
+pub fn button<V>(label: impl Into<Cow<'static, str>>) -> Button<V, ()> {
+    Button::new(label)
+}
+
+impl<V: 'static, D: 'static> Button<V, D> {
+    fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+        // 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() {
+            let data = self.data.clone();
+            button.click(move |view, event| handler(view, data.as_ref()))
+        } else {
+            button
+        }
+    }
+}

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

@@ -4,7 +4,9 @@ use crate::{
 };
 use anyhow::Result;
 use derive_more::{Deref, DerefMut};
-use gpui::{Layout, LayoutContext as LegacyLayoutContext, PaintContext as LegacyPaintContext};
+use gpui::{
+    EngineLayout, LayoutContext as LegacyLayoutContext, PaintContext as LegacyPaintContext,
+};
 use playground_macros::tailwind_lengths;
 pub use taffy::tree::NodeId;
 
@@ -24,7 +26,8 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
 pub trait Element<V: 'static>: 'static + Clone {
     fn style_mut(&mut self) -> &mut Style;
     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId>;
-    fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut PaintContext<V>) -> Result<()>;
+    fn paint(&mut self, layout: EngineLayout, 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>
@@ -259,7 +262,8 @@ pub trait Element<V: 'static>: 'static + Clone {
 pub trait ElementObject<V> {
     fn style_mut(&mut self) -> &mut Style;
     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId>;
-    fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut PaintContext<V>) -> Result<()>;
+    fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext<V>)
+        -> Result<()>;
     fn clone_object(&self) -> Box<dyn ElementObject<V>>;
 }
 
@@ -272,7 +276,12 @@ impl<V: 'static, E: Element<V>> ElementObject<V> for E {
         self.layout(view, cx)
     }
 
-    fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
+    fn paint(
+        &mut self,
+        layout: EngineLayout,
+        view: &mut V,
+        cx: &mut PaintContext<V>,
+    ) -> Result<()> {
         self.paint(layout, view, cx)
     }
 
@@ -286,6 +295,12 @@ pub struct AnyElement<V> {
     layout_node_id: Option<NodeId>,
 }
 
+// enum LayoutState {
+//     None,
+//     Registered(NodeId, Box<dyn Any>),
+//     Computed(Layout, Box<dyn Any>),
+// }
+
 impl<V> AnyElement<V> {
     pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
         let layout_node_id = self.element.layout(view, cx)?;
@@ -322,7 +337,12 @@ impl<V: 'static> Element<V> for AnyElement<V> {
         self.layout(view, cx)
     }
 
-    fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
+    fn paint(
+        &mut self,
+        layout: EngineLayout,
+        view: &mut V,
+        cx: &mut PaintContext<V>,
+    ) -> Result<()> {
         self.paint(view, cx)
     }
 }

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

@@ -1,5 +1,5 @@
 use anyhow::{anyhow, Result};
-use gpui::{Layout, LayoutNodeId};
+use gpui::{EngineLayout, LayoutNodeId};
 
 use crate::{
     element::{AnyElement, Element, LayoutContext, PaintContext},
@@ -36,7 +36,12 @@ impl<V: 'static> Element<V> for Frame<V> {
             .add_node(self.style.to_taffy(rem_size), child_layout_node_ids)
     }
 
-    fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
+    fn paint(
+        &mut self,
+        layout: EngineLayout,
+        view: &mut V,
+        cx: &mut PaintContext<V>,
+    ) -> Result<()> {
         cx.scene.push_quad(gpui::scene::Quad {
             bounds: layout.bounds,
             background: self.style.fill.color().map(Into::into),

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

@@ -1,100 +1,9 @@
 use proc_macro::TokenStream;
-use proc_macro2::TokenStream as TokenStream2;
-use quote::{format_ident, quote};
-use syn::{parse_macro_input, FnArg, ItemFn, PatType};
 
-#[proc_macro_attribute]
-pub fn tailwind_lengths(_attr: TokenStream, item: TokenStream) -> TokenStream {
-    let input_function = parse_macro_input!(item as ItemFn);
-
-    let visibility = &input_function.vis;
-    let function_signature = input_function.sig.clone();
-    let function_body = input_function.block;
-    let where_clause = &function_signature.generics.where_clause;
-
-    let argument_name = match function_signature.inputs.iter().nth(1) {
-        Some(FnArg::Typed(PatType { pat, .. })) => pat,
-        _ => panic!("Couldn't find the second argument in the function signature"),
-    };
-
-    let mut output_functions = TokenStream2::new();
+mod derive_element;
+mod tailwind_lengths;
 
-    for (length, value) in fixed_lengths() {
-        let function_name = format_ident!("{}{}", function_signature.ident, length);
-        output_functions.extend(quote! {
-            #visibility fn #function_name(mut self) -> Self #where_clause {
-                let #argument_name = #value.into();
-                #function_body
-            }
-        });
-    }
-
-    output_functions.into()
-}
-
-fn fixed_lengths() -> Vec<(&'static str, TokenStream2)> {
-    vec![
-        ("0", quote! { DefinedLength::Pixels(0.) }),
-        ("px", quote! { DefinedLength::Pixels(1.) }),
-        ("0_5", quote! { DefinedLength::Rems(0.125) }),
-        ("1", quote! { DefinedLength::Rems(0.25) }),
-        ("1_5", quote! { DefinedLength::Rems(0.375) }),
-        ("2", quote! { DefinedLength::Rems(0.5) }),
-        ("2_5", quote! { DefinedLength::Rems(0.625) }),
-        ("3", quote! { DefinedLength::Rems(0.75) }),
-        ("3_5", quote! { DefinedLength::Rems(0.875) }),
-        ("4", quote! { DefinedLength::Rems(1.) }),
-        ("5", quote! { DefinedLength::Rems(1.25) }),
-        ("6", quote! { DefinedLength::Rems(1.5) }),
-        ("7", quote! { DefinedLength::Rems(1.75) }),
-        ("8", quote! { DefinedLength::Rems(2.) }),
-        ("9", quote! { DefinedLength::Rems(2.25) }),
-        ("10", quote! { DefinedLength::Rems(2.5) }),
-        ("11", quote! { DefinedLength::Rems(2.75) }),
-        ("12", quote! { DefinedLength::Rems(3.) }),
-        ("14", quote! { DefinedLength::Rems(3.5) }),
-        ("16", quote! { DefinedLength::Rems(4.) }),
-        ("20", quote! { DefinedLength::Rems(5.) }),
-        ("24", quote! { DefinedLength::Rems(6.) }),
-        ("28", quote! { DefinedLength::Rems(7.) }),
-        ("32", quote! { DefinedLength::Rems(8.) }),
-        ("36", quote! { DefinedLength::Rems(9.) }),
-        ("40", quote! { DefinedLength::Rems(10.) }),
-        ("44", quote! { DefinedLength::Rems(11.) }),
-        ("48", quote! { DefinedLength::Rems(12.) }),
-        ("52", quote! { DefinedLength::Rems(13.) }),
-        ("56", quote! { DefinedLength::Rems(14.) }),
-        ("60", quote! { DefinedLength::Rems(15.) }),
-        ("64", quote! { DefinedLength::Rems(16.) }),
-        ("72", quote! { DefinedLength::Rems(18.) }),
-        ("80", quote! { DefinedLength::Rems(20.) }),
-        ("96", quote! { DefinedLength::Rems(24.) }),
-        ("half", quote! { DefinedLength::Percent(50.) }),
-        ("1_3rd", quote! { DefinedLength::Percent(33.333333) }),
-        ("2_3rd", quote! { DefinedLength::Percent(66.666667) }),
-        ("1_4th", quote! { DefinedLength::Percent(25.) }),
-        ("2_4th", quote! { DefinedLength::Percent(50.) }),
-        ("3_4th", quote! { DefinedLength::Percent(75.) }),
-        ("1_5th", quote! { DefinedLength::Percent(20.) }),
-        ("2_5th", quote! { DefinedLength::Percent(40.) }),
-        ("3_5th", quote! { DefinedLength::Percent(60.) }),
-        ("4_5th", quote! { DefinedLength::Percent(80.) }),
-        ("1_6th", quote! { DefinedLength::Percent(16.666667) }),
-        ("2_6th", quote! { DefinedLength::Percent(33.333333) }),
-        ("3_6th", quote! { DefinedLength::Percent(50.) }),
-        ("4_6th", quote! { DefinedLength::Percent(66.666667) }),
-        ("5_6th", quote! { DefinedLength::Percent(83.333333) }),
-        ("1_12th", quote! { DefinedLength::Percent(8.333333) }),
-        ("2_12th", quote! { DefinedLength::Percent(16.666667) }),
-        ("3_12th", quote! { DefinedLength::Percent(25.) }),
-        ("4_12th", quote! { DefinedLength::Percent(33.333333) }),
-        ("5_12th", quote! { DefinedLength::Percent(41.666667) }),
-        ("6_12th", quote! { DefinedLength::Percent(50.) }),
-        ("7_12th", quote! { DefinedLength::Percent(58.333333) }),
-        ("8_12th", quote! { DefinedLength::Percent(66.666667) }),
-        ("9_12th", quote! { DefinedLength::Percent(75.) }),
-        ("10_12th", quote! { DefinedLength::Percent(83.333333) }),
-        ("11_12th", quote! { DefinedLength::Percent(91.666667) }),
-        ("full", quote! { DefinedLength::Percent(100.) }),
-    ]
+#[proc_macro_attribute]
+pub fn tailwind_lengths(attr: TokenStream, item: TokenStream) -> TokenStream {
+    tailwind_lengths::tailwind_lengths(attr, item)
 }

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

@@ -0,0 +1,99 @@
+use proc_macro::TokenStream;
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, FnArg, ItemFn, PatType};
+
+pub fn tailwind_lengths(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    let input_function = parse_macro_input!(item as ItemFn);
+
+    let visibility = &input_function.vis;
+    let function_signature = input_function.sig.clone();
+    let function_body = input_function.block;
+    let where_clause = &function_signature.generics.where_clause;
+
+    let argument_name = match function_signature.inputs.iter().nth(1) {
+        Some(FnArg::Typed(PatType { pat, .. })) => pat,
+        _ => panic!("Couldn't find the second argument in the function signature"),
+    };
+
+    let mut output_functions = TokenStream2::new();
+
+    for (length, value) in fixed_lengths() {
+        let function_name = format_ident!("{}{}", function_signature.ident, length);
+        output_functions.extend(quote! {
+            #visibility fn #function_name(mut self) -> Self #where_clause {
+                let #argument_name = #value.into();
+                #function_body
+            }
+        });
+    }
+
+    output_functions.into()
+}
+
+fn fixed_lengths() -> Vec<(&'static str, TokenStream2)> {
+    vec![
+        ("0", quote! { DefinedLength::Pixels(0.) }),
+        ("px", quote! { DefinedLength::Pixels(1.) }),
+        ("0_5", quote! { DefinedLength::Rems(0.125) }),
+        ("1", quote! { DefinedLength::Rems(0.25) }),
+        ("1_5", quote! { DefinedLength::Rems(0.375) }),
+        ("2", quote! { DefinedLength::Rems(0.5) }),
+        ("2_5", quote! { DefinedLength::Rems(0.625) }),
+        ("3", quote! { DefinedLength::Rems(0.75) }),
+        ("3_5", quote! { DefinedLength::Rems(0.875) }),
+        ("4", quote! { DefinedLength::Rems(1.) }),
+        ("5", quote! { DefinedLength::Rems(1.25) }),
+        ("6", quote! { DefinedLength::Rems(1.5) }),
+        ("7", quote! { DefinedLength::Rems(1.75) }),
+        ("8", quote! { DefinedLength::Rems(2.) }),
+        ("9", quote! { DefinedLength::Rems(2.25) }),
+        ("10", quote! { DefinedLength::Rems(2.5) }),
+        ("11", quote! { DefinedLength::Rems(2.75) }),
+        ("12", quote! { DefinedLength::Rems(3.) }),
+        ("14", quote! { DefinedLength::Rems(3.5) }),
+        ("16", quote! { DefinedLength::Rems(4.) }),
+        ("20", quote! { DefinedLength::Rems(5.) }),
+        ("24", quote! { DefinedLength::Rems(6.) }),
+        ("28", quote! { DefinedLength::Rems(7.) }),
+        ("32", quote! { DefinedLength::Rems(8.) }),
+        ("36", quote! { DefinedLength::Rems(9.) }),
+        ("40", quote! { DefinedLength::Rems(10.) }),
+        ("44", quote! { DefinedLength::Rems(11.) }),
+        ("48", quote! { DefinedLength::Rems(12.) }),
+        ("52", quote! { DefinedLength::Rems(13.) }),
+        ("56", quote! { DefinedLength::Rems(14.) }),
+        ("60", quote! { DefinedLength::Rems(15.) }),
+        ("64", quote! { DefinedLength::Rems(16.) }),
+        ("72", quote! { DefinedLength::Rems(18.) }),
+        ("80", quote! { DefinedLength::Rems(20.) }),
+        ("96", quote! { DefinedLength::Rems(24.) }),
+        ("half", quote! { DefinedLength::Percent(50.) }),
+        ("1_3rd", quote! { DefinedLength::Percent(33.333333) }),
+        ("2_3rd", quote! { DefinedLength::Percent(66.666667) }),
+        ("1_4th", quote! { DefinedLength::Percent(25.) }),
+        ("2_4th", quote! { DefinedLength::Percent(50.) }),
+        ("3_4th", quote! { DefinedLength::Percent(75.) }),
+        ("1_5th", quote! { DefinedLength::Percent(20.) }),
+        ("2_5th", quote! { DefinedLength::Percent(40.) }),
+        ("3_5th", quote! { DefinedLength::Percent(60.) }),
+        ("4_5th", quote! { DefinedLength::Percent(80.) }),
+        ("1_6th", quote! { DefinedLength::Percent(16.666667) }),
+        ("2_6th", quote! { DefinedLength::Percent(33.333333) }),
+        ("3_6th", quote! { DefinedLength::Percent(50.) }),
+        ("4_6th", quote! { DefinedLength::Percent(66.666667) }),
+        ("5_6th", quote! { DefinedLength::Percent(83.333333) }),
+        ("1_12th", quote! { DefinedLength::Percent(8.333333) }),
+        ("2_12th", quote! { DefinedLength::Percent(16.666667) }),
+        ("3_12th", quote! { DefinedLength::Percent(25.) }),
+        ("4_12th", quote! { DefinedLength::Percent(33.333333) }),
+        ("5_12th", quote! { DefinedLength::Percent(41.666667) }),
+        ("6_12th", quote! { DefinedLength::Percent(50.) }),
+        ("7_12th", quote! { DefinedLength::Percent(58.333333) }),
+        ("8_12th", quote! { DefinedLength::Percent(66.666667) }),
+        ("9_12th", quote! { DefinedLength::Percent(75.) }),
+        ("10_12th", quote! { DefinedLength::Percent(83.333333) }),
+        ("11_12th", quote! { DefinedLength::Percent(91.666667) }),
+        ("full", quote! { DefinedLength::Percent(100.) }),
+    ]
+}

crates/gpui/src/app/window.rs 🔗

@@ -1264,17 +1264,17 @@ impl LayoutEngine {
         Ok(())
     }
 
-    pub fn computed_layout(&mut self, node: LayoutNodeId) -> Result<Layout> {
+    pub fn computed_layout(&mut self, node: LayoutNodeId) -> Result<EngineLayout> {
         Ok(self.0.layout(node)?.into())
     }
 }
 
-pub struct Layout {
+pub struct EngineLayout {
     pub bounds: RectF,
     pub order: u32,
 }
 
-impl From<&taffy::tree::Layout> for Layout {
+impl From<&taffy::tree::Layout> for EngineLayout {
     fn from(value: &taffy::tree::Layout) -> Self {
         Self {
             bounds: RectF::new(

crates/gpui/src/gpui.rs 🔗

@@ -28,7 +28,8 @@ pub mod keymap_matcher;
 pub mod platform;
 pub use gpui_macros::{test, Element};
 pub use window::{
-    Axis, Layout, LayoutEngine, LayoutNodeId, RectFExt, SizeConstraint, Vector2FExt, WindowContext,
+    Axis, EngineLayout, LayoutEngine, LayoutNodeId, RectFExt, SizeConstraint, Vector2FExt,
+    WindowContext,
 };
 
 pub use anyhow;