Compiling checkpoint

Nathan Sobo created

Change summary

crates/gpui/playground/src/element.rs              | 10 +
crates/gpui/playground/src/frame.rs                |  9 +
crates/gpui/playground/src/paint_context.rs        | 42 +++---
crates/gpui/playground/src/playground.rs           |  2 
crates/gpui/playground/src/style.rs                | 12 -
crates/gpui/playground_macros/src/style_methods.rs | 95 ++++++++++++++++
6 files changed, 138 insertions(+), 32 deletions(-)

Detailed changes

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

@@ -408,7 +408,15 @@ pub trait Element<V: 'static>: 'static {
     where
         Self: Sized,
     {
-        self.style_mut().fill = fill.into();
+        self.style_mut().fill = Some(fill.into());
+        self
+    }
+
+    fn hover_fill(mut self, fill: impl Into<Fill>) -> Self
+    where
+        Self: Sized,
+    {
+        self.style_mut().hover_fill = Some(fill.into());
         self
     }
 

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

@@ -2,7 +2,7 @@ use crate::{
     element::{
         AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId, PaintContext,
     },
-    style::ElementStyle,
+    style::{ElementStyle, Fill},
 };
 use anyhow::{anyhow, Result};
 use gpui::LayoutNodeId;
@@ -58,7 +58,12 @@ impl<V: 'static> Element<V> for Frame<V> {
     fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
         cx.scene.push_quad(gpui::scene::Quad {
             bounds: layout.from_engine.bounds,
-            background: self.style.fill.color().map(Into::into),
+            background: self
+                .style
+                .fill
+                .as_ref()
+                .and_then(Fill::color)
+                .map(Into::into),
             border: Default::default(),
             corner_radii: Default::default(),
         });

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

@@ -1,9 +1,7 @@
 use std::{any::TypeId, rc::Rc};
 
 use derive_more::{Deref, DerefMut};
-use gpui::{
-    geometry::rect::RectF, scene::InteractiveRegion, EventContext, RenderContext, ViewContext,
-};
+use gpui::{geometry::rect::RectF, EventContext, RenderContext, ViewContext};
 pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
 pub use taffy::tree::NodeId;
 
@@ -42,24 +40,26 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
         order: u32,
         bounds: RectF,
         outside_bounds: bool,
-        handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
+        event_handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
     ) {
-        // We'll sort these by their order in `take_interactive_regions`.
-        self.scene.interactive_regions.push(InteractiveRegion {
-            order,
-            bounds,
-            outside_bounds,
-            event_handler: Rc::new(move |view, event, window_cx, view_id| {
-                let mut cx = ViewContext::mutable(window_cx, view_id);
-                let mut cx = EventContext::new(&mut cx);
-                handler(
-                    view.downcast_mut().unwrap(),
-                    event.downcast_ref().unwrap(),
-                    &mut cx,
-                )
-            }),
-            event_type: TypeId::of::<E>(),
-            view_id: self.view_id(),
-        });
+        // We'll sort these later when `take_interactive_regions` is called.
+        self.scene
+            .interactive_regions
+            .push(gpui::scene::InteractiveRegion {
+                order,
+                bounds,
+                outside_bounds,
+                event_handler: Rc::new(move |view, event, window_cx, view_id| {
+                    let mut view_context = ViewContext::mutable(window_cx, view_id);
+                    let mut event_context = EventContext::new(&mut view_context);
+                    event_handler(
+                        view.downcast_mut().unwrap(),
+                        event.downcast_ref().unwrap(),
+                        &mut event_context,
+                    );
+                }),
+                event_type: TypeId::of::<E>(),
+                view_id: self.view_id(),
+            });
     }
 }

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

@@ -5,7 +5,7 @@ use element::Element;
 use frame::frame;
 use gpui::{
     geometry::{rect::RectF, vector::vec2f},
-    platform::{MouseButton, WindowOptions},
+    platform::WindowOptions,
 };
 use log::LevelFilter;
 use simplelog::SimpleLogger;

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

@@ -65,7 +65,9 @@ pub struct ElementStyle {
     pub flex_shrink: f32,
 
     /// The fill color of this element
-    pub fill: Fill,
+    pub fill: Option<Fill>,
+    /// The fill color of this element when hovered
+    pub hover_fill: Option<Fill>,
     /// The color of text within this element. Cascades to children unless overridden.
     pub text_color: Option<Hsla>,
 }
@@ -99,12 +101,8 @@ impl ElementStyle {
         flex_grow: 0.0,
         flex_shrink: 1.0,
         flex_basis: Length::Auto,
-        fill: Fill::Color(Hsla {
-            h: 0.,
-            s: 0.,
-            l: 0.,
-            a: 0.,
-        }),
+        fill: None,
+        hover_fill: None,
         text_color: None,
     };
 

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

@@ -0,0 +1,95 @@
+use proc_macro::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{parse_macro_input, Expr, Ident, Token};
+
+struct Args {
+    method_name: Ident,
+    method_suffix: Option<Ident>,
+    field_name: Ident,
+    value: Expr,
+}
+
+impl syn::parse::Parse for Args {
+    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+        let method_name = input.parse()?;
+        let method_suffix = if input.peek(Token![::]) {
+            input.parse::<Token![::]>()?;
+            Some(input.parse()?)
+        } else {
+            None
+        };
+        input.parse::<Token![,]>()?;
+        let field_name = input.parse()?;
+        input.parse::<Token![,]>()?;
+        let value = input.parse()?;
+
+        Ok(Self {
+            method_name,
+            method_suffix,
+            field_name,
+            value,
+        })
+    }
+}
+
+fn fixed_lengths() -> Vec<(&'static str, proc_macro2::TokenStream)> {
+    vec![
+        ("0", quote! { DefinedLength::Pixels(0.) }),
+        ("px", quote! { DefinedLength::Pixels(1.) }),
+        ("0_5", quote! { DefinedLength::Rems(0.125) }),
+        // ...
+    ]
+}
+
+pub fn style_methods(input: TokenStream) -> TokenStream {
+    let Args {
+        method_name,
+        method_suffix,
+        field_name,
+        value,
+    } = parse_macro_input!(input as Args);
+
+    let hover_method_name = format!("hover_{}", method_name);
+    let hover_method_ident = syn::Ident::new(&hover_method_name, method_name.span());
+
+    let mut result = quote! {
+        fn #method_name(mut self) -> Self
+        where
+            Self: Sized,
+        {
+            self.metadata().style.#field_name = #value;
+            self
+        }
+
+        fn #hover_method_ident(mut self) -> Self
+        where
+            Self: Sized,
+        {
+            self.metadata().hover_style.#field_name = Some(#value);
+            self
+        }
+    };
+
+    if let Some(suffix_ident) = method_suffix {
+        if suffix_ident == "_" {
+            let fixed_lengths = fixed_lengths();
+
+            for (suffix, value) in fixed_lengths {
+                let method_ident =
+                    syn::Ident::new(&format!("{}_{}", method_name, suffix), method_name.span());
+                let method = quote! {
+                    fn #method_ident(mut self) -> Self
+                    where
+                        Self: Sized,
+                    {
+                        self.metadata().style.#field_name = #value;
+                        self
+                    }
+                };
+                result.extend(method);
+            }
+        }
+    }
+
+    result.into()
+}