Checkpoint

Nathan Sobo created

Change summary

crates/gpui/playground/src/components.rs               | 246 ++++++------
crates/gpui/playground/src/div.rs                      |  16 
crates/gpui/playground/src/element.rs                  |  92 ----
crates/gpui/playground/src/playground.rs               |  54 +-
crates/gpui/playground/src/style.rs                    | 125 ++++--
crates/gpui/playground_macros/src/styleable_helpers.rs |  50 +-
crates/gpui/src/geometry.rs                            | 118 +++--
7 files changed, 342 insertions(+), 359 deletions(-)

Detailed changes

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

@@ -1,131 +1,131 @@
-use crate::{
-    element::{Element, ElementMetadata, ParentElement},
-    frame,
-    text::ArcCow,
-    themes::rose_pine,
-};
-use gpui::{platform::MouseButton, ViewContext};
-use playground_macros::Element;
-use std::{marker::PhantomData, rc::Rc};
-
-struct ButtonHandlers<V, D> {
-    click: Option<Rc<dyn Fn(&mut V, &D, &mut ViewContext<V>)>>,
-}
-
-impl<V, D> Default for ButtonHandlers<V, D> {
-    fn default() -> Self {
-        Self { click: None }
-    }
-}
-
-#[derive(Element)]
-#[element_crate = "crate"]
-pub struct Button<V: 'static, D: 'static> {
-    metadata: ElementMetadata<V>,
-    handlers: ButtonHandlers<V, D>,
-    label: Option<ArcCow<'static, str>>,
-    icon: Option<ArcCow<'static, str>>,
-    data: Rc<D>,
-    view_type: PhantomData<V>,
-}
-
-// Impl block for buttons without data.
-// See below for an impl block for any button.
-impl<V: 'static> Button<V, ()> {
-    fn new() -> Self {
-        Self {
-            metadata: Default::default(),
-            handlers: ButtonHandlers::default(),
-            label: None,
-            icon: None,
-            data: Rc::new(()),
-            view_type: PhantomData,
-        }
-    }
-
-    pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
-        Button {
-            metadata: Default::default(),
-            handlers: ButtonHandlers::default(),
-            label: self.label,
-            icon: self.icon,
-            data: Rc::new(data),
-            view_type: PhantomData,
-        }
-    }
-}
-
-// Impl block for *any* button.
-impl<V: 'static, D: 'static> Button<V, D> {
-    pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
-        self.label = Some(label.into());
-        self
-    }
-
-    pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
-        self.icon = Some(icon.into());
-        self
-    }
-
-    pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
-        let data = self.data.clone();
-        Element::click(self, MouseButton::Left, move |view, _, cx| {
-            handler(view, data.as_ref(), cx);
-        })
-    }
-}
-
-pub fn button<V>() -> Button<V, ()> {
-    Button::new()
-}
-
-impl<V: 'static, D: 'static> Button<V, D> {
-    fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        // TODO: Drive theme from the context
-        let button = frame()
-            .fill(rose_pine::dawn().error(0.5))
-            .h_4()
-            .children(self.label.clone());
-
-        if let Some(handler) = self.handlers.click.clone() {
-            let data = self.data.clone();
-            button.mouse_down(MouseButton::Left, move |view, event, cx| {
-                handler(view, data.as_ref(), cx)
-            })
-        } else {
-            button
-        }
-    }
-}
-
-// 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
+// use crate::{
+//     element::{Element, ElementMetadata, ParentElement},
+//     frame,
+//     text::ArcCow,
+//     themes::rose_pine,
+// };
+// use gpui::{platform::MouseButton, ViewContext};
+// use playground_macros::Element;
+// use std::{marker::PhantomData, rc::Rc};
+
+// struct ButtonHandlers<V, D> {
+//     click: Option<Rc<dyn Fn(&mut V, &D, &mut ViewContext<V>)>>,
+// }
+
+// impl<V, D> Default for ButtonHandlers<V, D> {
+//     fn default() -> Self {
+//         Self { click: None }
+//     }
+// }
+
+// #[derive(Element)]
+// #[element_crate = "crate"]
+// pub struct Button<V: 'static, D: 'static> {
+//     metadata: ElementMetadata<V>,
+//     handlers: ButtonHandlers<V, D>,
+//     label: Option<ArcCow<'static, str>>,
+//     icon: Option<ArcCow<'static, str>>,
+//     data: Rc<D>,
+//     view_type: PhantomData<V>,
+// }
+
+// // Impl block for buttons without data.
+// // See below for an impl block for any button.
+// impl<V: 'static> Button<V, ()> {
+//     fn new() -> Self {
+//         Self {
+//             metadata: Default::default(),
+//             handlers: ButtonHandlers::default(),
+//             label: None,
+//             icon: None,
+//             data: Rc::new(()),
+//             view_type: PhantomData,
+//         }
+//     }
+
+//     pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
+//         Button {
+//             metadata: Default::default(),
+//             handlers: ButtonHandlers::default(),
+//             label: self.label,
+//             icon: self.icon,
+//             data: Rc::new(data),
+//             view_type: PhantomData,
+//         }
+//     }
+// }
+
+// // Impl block for *any* button.
+// impl<V: 'static, D: 'static> Button<V, D> {
+//     pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
+//         self.label = Some(label.into());
+//         self
 //     }
 
-//     fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
-//         &mut self.metadata.handlers
+//     pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
+//         self.icon = Some(icon.into());
+//         self
 //     }
 
-//     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))
+//     pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
+//         let data = self.data.clone();
+//         Element::click(self, MouseButton::Left, move |view, _, cx| {
+//             handler(view, data.as_ref(), cx);
+//         })
 //     }
+// }
+
+// pub fn button<V>() -> Button<V, ()> {
+//     Button::new()
+// }
 
-//     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(())
+// impl<V: 'static, D: 'static> Button<V, D> {
+//     fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+//         // TODO: Drive theme from the context
+//         let button = frame()
+//             .fill(rose_pine::dawn().error(0.5))
+//             .h_4()
+//             .children(self.label.clone());
+
+//         if let Some(handler) = self.handlers.click.clone() {
+//             let data = self.data.clone();
+//             button.mouse_down(MouseButton::Left, move |view, event, cx| {
+//                 handler(view, data.as_ref(), cx)
+//             })
+//         } else {
+//             button
+//         }
 //     }
 // }
+
+// // 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/div.rs 🔗

@@ -78,7 +78,6 @@ pub trait Element<V> {
     }
 }
 
-use crate as playground; // Macro invocation below references this crate as playground.
 pub trait Styleable {
     type Style: refineable::Refineable;
 
@@ -89,12 +88,15 @@ pub trait Styleable {
         style.refine(self.declared_style());
         style
     }
+}
 
-    // Tailwind-style helpers methods that take and return mut self
-    //
-    // Example:
-    // // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
-    // fn p_2(mut self) -> Self where Self: Sized;
+// Tailwind-style helpers methods that take and return mut self
+//
+// Example:
+// // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
+// fn p_2(mut self) -> Self where Self: Sized;
+use crate as playground; // Macro invocation references this crate as playground.
+pub trait StyleHelpers: Styleable<Style = Style> {
     styleable_helpers!();
 }
 
@@ -139,6 +141,8 @@ impl<V: 'static> Element<V> for Div<V> {
         Self: Sized,
     {
         let style = self.style();
+
+        style.paint_background::<V, Self>(layout, cx);
     }
 }
 

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

@@ -1,17 +1,15 @@
 use crate::{
     adapter::Adapter,
     color::Hsla,
-    hoverable::Hoverable,
     style::{Display, Fill, Overflow, Position, StyleRefinement},
 };
 use anyhow::Result;
 pub use gpui::LayoutContext;
 use gpui::{
-    geometry::{DefinedLength, Length, PointRefinement},
+    geometry::PointRefinement,
     platform::{MouseButton, MouseButtonEvent},
     EngineLayout, EventContext, RenderContext, ViewContext,
 };
-use playground_macros::tailwind_lengths;
 use refineable::Refineable;
 use std::{
     any::{Any, TypeId},
@@ -338,94 +336,6 @@ pub trait Element<V: 'static>: 'static {
         self
     }
 
-    #[tailwind_lengths]
-    fn inset_(mut self, length: DefinedLength) -> Self
-    where
-        Self: Sized,
-    {
-        let inset = &mut self.declared_style().inset;
-        inset.top = Some(length);
-        inset.right = Some(length);
-        inset.bottom = Some(length);
-        inset.left = Some(length);
-        self
-    }
-
-    fn w(mut self, width: impl Into<Length>) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().size.width = Some(width.into());
-        self
-    }
-
-    fn w_auto(mut self) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().size.width = Some(Length::Auto);
-        self
-    }
-
-    #[tailwind_lengths]
-    fn w_(mut self, length: DefinedLength) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().size.width = Some(length);
-        self
-    }
-
-    #[tailwind_lengths]
-    fn min_w_(mut self, length: DefinedLength) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().min_size.width = Some(length);
-        self
-    }
-
-    fn h(mut self, height: impl Into<Length>) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().size.height = Some(height.into());
-        self
-    }
-
-    fn h_auto(mut self) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().size.height = Some(Length::Auto);
-        self
-    }
-
-    #[tailwind_lengths]
-    fn h_(mut self, height: DefinedLength) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().size.height = Some(height);
-        self
-    }
-
-    #[tailwind_lengths]
-    fn min_h_(mut self, length: DefinedLength) -> Self
-    where
-        Self: Sized,
-    {
-        self.declared_style().min_size.height = Some(length);
-        self
-    }
-
-    fn hover(self) -> Hoverable<V, Self>
-    where
-        Self: Sized,
-    {
-        Hoverable::new(self)
-    }
-
     fn fill(mut self, fill: impl Into<Fill>) -> Self
     where
         Self: Sized,

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

@@ -1,17 +1,8 @@
 #![allow(dead_code, unused_variables)]
-use color::black;
-use components::button;
-use element::{Element, ParentElement};
-use frame::frame;
-use gpui::{
-    geometry::{rect::RectF, vector::vec2f},
-    platform::WindowOptions,
-};
 use log::LevelFilter;
 use simplelog::SimpleLogger;
 
-use themes::{rose_pine, ThemeColors};
-use view::view;
+use themes::ThemeColors;
 
 mod adapter;
 mod color;
@@ -31,31 +22,32 @@ fn main() {
     SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
 
     gpui::App::new(()).unwrap().run(|cx| {
-        cx.add_window(
-            WindowOptions {
-                bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
-                    vec2f(0., 0.),
-                    vec2f(400., 300.),
-                )),
-                center: true,
-                ..Default::default()
-            },
-            |_| view(|_| playground(&rose_pine::moon())),
-        );
+        // cx.add_window(
+        //     WindowOptions {
+        //         bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
+        //             vec2f(0., 0.),
+        //             vec2f(400., 300.),
+        //         )),
+        //         center: true,
+        //         ..Default::default()
+        //     },
+        //     |_| view(|_| playground(&rose_pine::moon())),
+        // );
         cx.platform().activate(true);
     });
 }
 
-fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
-    frame()
-        .text_color(black())
-        .h_full()
-        .w_half()
-        .fill(theme.success(0.5))
-        .hover()
-        .fill(theme.error(0.5))
-        .child(button().label("Hello").click(|_, _, _| println!("click!")))
-}
+// fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+//     todo!()
+//     // frame()
+//     //     .text_color(black())
+//     //     .h_full()
+//     //     .w_half()
+//     //     .fill(theme.success(0.5))
+//     //     .hover()
+//     //     .fill(theme.error(0.5))
+//     //     .child(button().label("Hello").click(|_, _, _| println!("click!")))
+// }
 
 //     todo!()
 //     // column()

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

@@ -1,8 +1,13 @@
-use crate::color::Hsla;
+use crate::{
+    color::Hsla,
+    div::{Element, Layout},
+    element::PaintContext,
+};
 use gpui::{
     fonts::TextStyleRefinement,
     geometry::{
-        DefinedLength, Edges, EdgesRefinement, Length, Point, PointRefinement, Size, SizeRefinement,
+        AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length, Point, PointRefinement,
+        Size, SizeRefinement,
     },
 };
 use refineable::Refineable;
@@ -49,10 +54,10 @@ pub struct Style {
     pub margin: Edges<Length>,
     /// How large should the padding be on each side?
     #[refineable]
-    pub padding: Edges<DefinedLength>,
+    pub padding: Edges<DefiniteLength>,
     /// How large should the border be on each side?
     #[refineable]
-    pub border: Edges<DefinedLength>,
+    pub border: Edges<DefiniteLength>,
 
     // Alignment properties
     /// How this node's children aligned in the cross/block axis?
@@ -65,7 +70,7 @@ pub struct Style {
     pub justify_content: Option<JustifyContent>,
     /// How large should the gaps between items in a flex container be?
     #[refineable]
-    pub gap: Size<DefinedLength>,
+    pub gap: Size<DefiniteLength>,
 
     // Flexbox properies
     /// Which direction does the main axis flow in?
@@ -81,47 +86,14 @@ pub struct Style {
 
     /// The fill color of this element
     pub fill: Option<Fill>,
+    /// The radius of the corners of this element
+    #[refineable]
+    pub corner_radii: CornerRadii,
     /// The color of text within this element. Cascades to children unless overridden.
     pub text_color: Option<Hsla>,
 }
 
 impl Style {
-    pub const DEFAULT: Style = Style {
-        display: Display::DEFAULT,
-        overflow: Point {
-            x: Overflow::Visible,
-            y: Overflow::Visible,
-        },
-        scrollbar_width: 0.0,
-        position: Position::Relative,
-        inset: Edges::auto(),
-        margin: Edges::<Length>::zero(),
-        padding: Edges::<DefinedLength>::zero(),
-        border: Edges::<DefinedLength>::zero(),
-        size: Size::auto(),
-        min_size: Size::auto(),
-        max_size: Size::auto(),
-        aspect_ratio: None,
-        gap: Size::zero(),
-        // Aligment
-        align_items: None,
-        align_self: None,
-        align_content: None,
-        justify_content: None,
-        // Flexbox
-        flex_direction: FlexDirection::Row,
-        flex_wrap: FlexWrap::NoWrap,
-        flex_grow: 0.0,
-        flex_shrink: 1.0,
-        flex_basis: Length::Auto,
-        fill: None,
-        text_color: None,
-    };
-
-    pub fn new() -> Self {
-        Self::DEFAULT.clone()
-    }
-
     pub fn to_taffy(&self, rem_size: f32) -> taffy::style::Style {
         taffy::style::Style {
             display: self.display,
@@ -149,11 +121,61 @@ impl Style {
             ..Default::default() // Ignore grid properties for now
         }
     }
+
+    /// Paints the background of an element styled with this style.
+    /// Return the bounds in which to paint the content.
+    pub fn paint_background<V: 'static, E: Element<V>>(
+        &self,
+        layout: &mut Layout<V, E::Layout>,
+        cx: &mut PaintContext<V>,
+    ) {
+        let bounds = layout.bounds(cx);
+        let rem_size = cx.rem_pixels();
+        if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
+            cx.scene.push_quad(gpui::Quad {
+                bounds,
+                background: Some(color.into()),
+                corner_radii: self.corner_radii.to_gpui(rem_size),
+                border: Default::default(),
+            });
+        }
+    }
 }
 
 impl Default for Style {
     fn default() -> Self {
-        Self::DEFAULT.clone()
+        Style {
+            display: Display::DEFAULT,
+            overflow: Point {
+                x: Overflow::Visible,
+                y: Overflow::Visible,
+            },
+            scrollbar_width: 0.0,
+            position: Position::Relative,
+            inset: Edges::auto(),
+            margin: Edges::<Length>::zero(),
+            padding: Edges::<DefiniteLength>::zero(),
+            border: Edges::<DefiniteLength>::zero(),
+            size: Size::auto(),
+            min_size: Size::auto(),
+            max_size: Size::auto(),
+            aspect_ratio: None,
+            gap: Size::zero(),
+            // Aligment
+            align_items: None,
+            align_self: None,
+            align_content: None,
+            justify_content: None,
+            // Flexbox
+            flex_direction: FlexDirection::Row,
+            flex_wrap: FlexWrap::NoWrap,
+            flex_grow: 0.0,
+            flex_shrink: 1.0,
+            flex_basis: Length::Auto,
+            fill: None,
+            text_color: None,
+            corner_radii: CornerRadii::default(),
+        }
     }
 }
 
@@ -202,3 +224,22 @@ impl From<Hsla> for Fill {
         Self::Color(color)
     }
 }
+
+#[derive(Clone, Refineable, Default)]
+pub struct CornerRadii {
+    top_left: AbsoluteLength,
+    top_right: AbsoluteLength,
+    bottom_left: AbsoluteLength,
+    bottom_right: AbsoluteLength,
+}
+
+impl CornerRadii {
+    pub fn to_gpui(&self, rem_size: f32) -> gpui::scene::CornerRadii {
+        gpui::scene::CornerRadii {
+            top_left: self.top_left.to_pixels(rem_size),
+            top_right: self.top_right.to_pixels(rem_size),
+            bottom_left: self.bottom_left.to_pixels(rem_size),
+            bottom_right: self.bottom_right.to_pixels(rem_size),
+        }
+    }
+}

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

@@ -38,7 +38,7 @@ fn generate_methods() -> Vec<TokenStream2> {
                 .iter()
                 .map(|field_tokens| {
                     quote! {
-                        style.#field_tokens = Some(gpui::geometry::#length_tokens.into());
+                        style.#field_tokens = Some(gpui::geometry::#length_tokens);
                     }
                 })
                 .collect::<Vec<_>>();
@@ -60,30 +60,30 @@ fn generate_methods() -> Vec<TokenStream2> {
 
 fn tailwind_lengths() -> Vec<(&'static str, TokenStream2)> {
     vec![
-        ("0", quote! { DefinedLength::Pixels(0.) }),
-        ("1", quote! { DefinedLength::Rems(0.25) }),
-        ("2", quote! { DefinedLength::Rems(0.5) }),
-        ("3", quote! { DefinedLength::Rems(0.75) }),
-        ("4", quote! { DefinedLength::Rems(1.0) }),
-        ("5", quote! { DefinedLength::Rems(1.25) }),
-        ("6", quote! { DefinedLength::Rems(1.5) }),
-        ("8", quote! { DefinedLength::Rems(2.0) }),
-        ("10", quote! { DefinedLength::Rems(2.5) }),
-        ("12", quote! { DefinedLength::Rems(3.0) }),
-        ("16", quote! { DefinedLength::Rems(4.0) }),
-        ("20", quote! { DefinedLength::Rems(5.0) }),
-        ("24", quote! { DefinedLength::Rems(6.0) }),
-        ("32", quote! { DefinedLength::Rems(8.0) }),
-        ("40", quote! { DefinedLength::Rems(10.0) }),
-        ("48", quote! { DefinedLength::Rems(12.0) }),
-        ("56", quote! { DefinedLength::Rems(14.0) }),
-        ("64", quote! { DefinedLength::Rems(16.0) }),
-        ("auto", quote! { Length::Auto }),
-        ("px", quote! { DefinedLength::Pixels(1.0) }),
-        ("full", quote! { DefinedLength::Percent(100.0) }),
-        // ("screen_50", quote! { DefinedLength::Vh(50.0) }),
-        // ("screen_75", quote! { DefinedLength::Vh(75.0) }),
-        // ("screen", quote! { DefinedLength::Vh(100.0) }),
+        ("0", quote! { pixels(0.) }),
+        ("1", quote! { rems(0.25) }),
+        ("2", quote! { rems(0.5) }),
+        ("3", quote! { rems(0.75) }),
+        ("4", quote! { rems(1.) }),
+        ("5", quote! { rems(1.25) }),
+        ("6", quote! { rems(1.5) }),
+        ("8", quote! { rems(2.0) }),
+        ("10", quote! { rems(2.5) }),
+        ("12", quote! { rems(3.) }),
+        ("16", quote! { rems(4.) }),
+        ("20", quote! { rems(5.) }),
+        ("24", quote! { rems(6.) }),
+        ("32", quote! { rems(8.) }),
+        ("40", quote! { rems(10.) }),
+        ("48", quote! { rems(12.) }),
+        ("56", quote! { rems(14.) }),
+        ("64", quote! { rems(16.) }),
+        ("auto", quote! { auto() }),
+        ("px", quote! { pixels(1.) }),
+        ("full", quote! { relative(1.) }),
+        // ("screen_50", quote! { DefiniteLength::Vh(50.0) }),
+        // ("screen_75", quote! { DefiniteLength::Vh(75.0) }),
+        // ("screen", quote! { DefiniteLength::Vh(100.0) }),
     ]
 }
 

crates/gpui/src/geometry.rs 🔗

@@ -187,11 +187,11 @@ where
     }
 }
 
-impl Size<DefinedLength> {
-    pub const fn zero() -> Self {
+impl Size<DefiniteLength> {
+    pub fn zero() -> Self {
         Self {
-            width: DefinedLength::Pixels(0.),
-            height: DefinedLength::Pixels(0.),
+            width: pixels(0.),
+            height: pixels(0.),
         }
     }
 
@@ -204,7 +204,7 @@ impl Size<DefinedLength> {
 }
 
 impl Size<Length> {
-    pub const fn auto() -> Self {
+    pub fn auto() -> Self {
         Self {
             width: Length::Auto,
             height: Length::Auto,
@@ -230,13 +230,13 @@ pub struct Edges<T: Clone + Default> {
     pub left: T,
 }
 
-impl Edges<DefinedLength> {
-    pub const fn zero() -> Self {
+impl Edges<DefiniteLength> {
+    pub fn zero() -> Self {
         Self {
-            top: DefinedLength::Pixels(0.0),
-            right: DefinedLength::Pixels(0.0),
-            bottom: DefinedLength::Pixels(0.0),
-            left: DefinedLength::Pixels(0.0),
+            top: pixels(0.),
+            right: pixels(0.),
+            bottom: pixels(0.),
+            left: pixels(0.),
         }
     }
 
@@ -251,7 +251,7 @@ impl Edges<DefinedLength> {
 }
 
 impl Edges<Length> {
-    pub const fn auto() -> Self {
+    pub fn auto() -> Self {
         Self {
             top: Length::Auto,
             right: Length::Auto,
@@ -260,12 +260,12 @@ impl Edges<Length> {
         }
     }
 
-    pub const fn zero() -> Self {
+    pub fn zero() -> Self {
         Self {
-            top: Length::Defined(DefinedLength::Pixels(0.0)),
-            right: Length::Defined(DefinedLength::Pixels(0.0)),
-            bottom: Length::Defined(DefinedLength::Pixels(0.0)),
-            left: Length::Defined(DefinedLength::Pixels(0.0)),
+            top: pixels(0.),
+            right: pixels(0.),
+            bottom: pixels(0.),
+            left: pixels(0.),
         }
     }
 
@@ -282,72 +282,108 @@ impl Edges<Length> {
     }
 }
 
-/// A non-auto length that can be defined in pixels, rems, or percent of parent.
 #[derive(Clone, Copy)]
-pub enum DefinedLength {
+pub enum AbsoluteLength {
     Pixels(f32),
     Rems(f32),
-    Percent(f32), // 0. - 100.
 }
 
-impl DefinedLength {
+impl AbsoluteLength {
+    pub fn to_pixels(&self, rem_size: f32) -> f32 {
+        match self {
+            AbsoluteLength::Pixels(pixels) => *pixels,
+            AbsoluteLength::Rems(rems) => rems * rem_size,
+        }
+    }
+}
+
+impl Default for AbsoluteLength {
+    fn default() -> Self {
+        Self::Pixels(0.0)
+    }
+}
+
+/// A non-auto length that can be defined in pixels, rems, or percent of parent.
+#[derive(Clone, Copy)]
+pub enum DefiniteLength {
+    Absolute(AbsoluteLength),
+    Relative(f32), // Percent, from 0 to 100.
+}
+
+impl DefiniteLength {
     fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
         match self {
-            DefinedLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
-            DefinedLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
-            DefinedLength::Percent(percent) => {
-                taffy::style::LengthPercentage::Percent(*percent / 100.)
+            DefiniteLength::Absolute(length) => match length {
+                AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
+                AbsoluteLength::Rems(rems) => {
+                    taffy::style::LengthPercentage::Length(rems * rem_size)
+                }
+            },
+            DefiniteLength::Relative(fraction) => {
+                taffy::style::LengthPercentage::Percent(*fraction)
             }
         }
     }
 }
 
-impl Default for DefinedLength {
+impl From<AbsoluteLength> for DefiniteLength {
+    fn from(length: AbsoluteLength) -> Self {
+        Self::Absolute(length)
+    }
+}
+
+impl Default for DefiniteLength {
     fn default() -> Self {
-        Self::Pixels(0.)
+        Self::Absolute(AbsoluteLength::default())
     }
 }
 
 /// A length that can be defined in pixels, rems, percent of parent, or auto.
 #[derive(Clone, Copy)]
 pub enum Length {
-    Defined(DefinedLength),
+    Definite(DefiniteLength),
     Auto,
 }
 
-pub fn auto() -> Length {
-    Length::Auto
+pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
+    DefiniteLength::Relative(fraction).into()
 }
 
-pub fn percent(percent: f32) -> DefinedLength {
-    DefinedLength::Percent(percent)
+pub fn rems<T: From<AbsoluteLength>>(rems: f32) -> T {
+    AbsoluteLength::Rems(rems).into()
 }
 
-pub fn rems(rems: f32) -> DefinedLength {
-    DefinedLength::Rems(rems)
+pub fn pixels<T: From<AbsoluteLength>>(pixels: f32) -> T {
+    AbsoluteLength::Pixels(pixels).into()
 }
 
-pub fn pixels(pixels: f32) -> DefinedLength {
-    DefinedLength::Pixels(pixels)
+pub fn auto() -> Length {
+    Length::Auto
 }
 
 impl Length {
     pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
         match self {
-            Length::Defined(length) => length.to_taffy(rem_size).into(),
+            Length::Definite(length) => length.to_taffy(rem_size).into(),
             Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
         }
     }
 }
 
-impl From<DefinedLength> for Length {
-    fn from(value: DefinedLength) -> Self {
-        Length::Defined(value)
+impl From<DefiniteLength> for Length {
+    fn from(length: DefiniteLength) -> Self {
+        Self::Definite(length)
+    }
+}
+
+impl From<AbsoluteLength> for Length {
+    fn from(length: AbsoluteLength) -> Self {
+        Self::Definite(length.into())
     }
 }
 
 impl Default for Length {
     fn default() -> Self {
-        Self::Defined(DefinedLength::default())
+        Self::Definite(DefiniteLength::default())
     }
 }