diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 81b7dbee43..d9fcb168c4 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -47,7 +47,7 @@ serde_derive.workspace = true serde_json.workspace = true smallvec.workspace = true smol.workspace = true -taffy = { git = "https://github.com/DioxusLabs/taffy", rev = "dab541d6104d58e2e10ce90c4a1dad0b703160cd" } +taffy = { git = "https://github.com/DioxusLabs/taffy", rev = "dab541d6104d58e2e10ce90c4a1dad0b703160cd", features = ["flexbox"] } time.workspace = true tiny-skia = "0.5" usvg = { version = "0.14", features = [] } diff --git a/crates/gpui/playground/src/element.rs b/crates/gpui/playground/src/element.rs new file mode 100644 index 0000000000..8885df21d4 --- /dev/null +++ b/crates/gpui/playground/src/element.rs @@ -0,0 +1,190 @@ +use crate::style::{Display, Length, Overflow, Position, Style}; +use gpui::{LayoutContext, PaintContext}; +use playground_macros::tailwind_lengths; +pub use taffy::tree::{Layout, NodeId}; + +pub trait Element { + fn style_mut(&mut self) -> &mut Style; + fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> NodeId; + fn paint(&mut self, layout: &Layout, view: &mut V, cx: &mut gpui::PaintContext); + + // Display //////////////////// + + fn block(mut self) -> Self + where + Self: Sized, + { + self.style_mut().display = Display::Block; + self + } + + fn flex(mut self) -> Self + where + Self: Sized, + { + self.style_mut().display = Display::Flex; + self + } + + fn grid(mut self) -> Self + where + Self: Sized, + { + self.style_mut().display = Display::Grid; + self + } + + // style::Overflow /////////////////// + + fn overflow_visible(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.x = Overflow::Visible; + self.style_mut().overflow.y = Overflow::Visible; + self + } + + fn overflow_hidden(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.x = Overflow::Hidden; + self.style_mut().overflow.y = Overflow::Hidden; + self + } + + fn overflow_scroll(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.x = Overflow::Scroll; + self.style_mut().overflow.y = Overflow::Scroll; + self + } + + fn overflow_x_visible(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.x = Overflow::Visible; + self + } + + fn overflow_x_hidden(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.x = Overflow::Hidden; + self + } + + fn overflow_x_scroll(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.x = Overflow::Scroll; + self + } + + fn overflow_y_visible(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.y = Overflow::Visible; + self + } + + fn overflow_y_hidden(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.y = Overflow::Hidden; + self + } + + fn overflow_y_scroll(mut self) -> Self + where + Self: Sized, + { + self.style_mut().overflow.y = Overflow::Scroll; + self + } + + // Position /////////////////// + + fn relative(mut self) -> Self + where + Self: Sized, + { + self.style_mut().position = Position::Relative; + self + } + + fn absolute(mut self) -> Self + where + Self: Sized, + { + self.style_mut().position = Position::Absolute; + + self + } + + #[tailwind_lengths] + fn inset(mut self, length: Length) -> Self + where + Self: Sized, + { + self.style_mut().inset.top = length; + self.style_mut().inset.right = length; + self.style_mut().inset.bottom = length; + self.style_mut().inset.left = length; + self + } + + #[tailwind_lengths] + fn w(mut self, length: Length) -> Self + where + Self: Sized, + { + self.style_mut().size.width = length; + self + } + + #[tailwind_lengths] + fn min_w(mut self, length: Length) -> Self + where + Self: Sized, + { + self.style_mut().size.width = length; + self + } + + #[tailwind_lengths] + fn h(mut self, length: Length) -> Self + where + Self: Sized, + { + self.style_mut().size.height = length; + self + } +} + +pub struct AnyElement { + element: Box>, + layout_node_id: Option, +} + +impl AnyElement { + fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> NodeId { + let layout_node_id = self.element.layout(view, cx); + self.layout_node_id = Some(layout_node_id); + layout_node_id + } + + fn paint(&mut self, view: &mut V, cx: &mut PaintContext) { + let layout_node_id = self.layout_node_id.expect("paint called before layout"); + let layout = cx.layout_engine().layout(layout_node_id).unwrap().clone(); + self.element.paint(&layout, view, cx); + } +} diff --git a/crates/gpui/playground/src/frame.rs b/crates/gpui/playground/src/frame.rs index 8b13789179..e4c650ab72 100644 --- a/crates/gpui/playground/src/frame.rs +++ b/crates/gpui/playground/src/frame.rs @@ -1 +1,34 @@ +use crate::{element::Element, style::Style}; +pub struct Frame { + style: Style, + children: Vec, +} + +impl Element for Frame { + fn style_mut(&mut self) -> &mut Style { + &mut self.style + } + + fn layout(&mut self, view: &mut V, cx: &mut gpui::LayoutContext) -> taffy::tree::NodeId { + let child_layout_node_ids = self + .children + .iter_mut() + .map(|child| child.layout(view, cx)) + .collect::>(); + + let rem_size = cx.rem_pixels(); + cx.layout_engine() + .new_with_children(self.style.to_taffy(rem_size), &child_layout_node_ids) + .unwrap() + } + + fn paint( + &mut self, + layout: &taffy::tree::Layout, + view: &mut V, + cx: &mut gpui::PaintContext, + ) { + todo!() + } +} diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index 91969a6ae0..c667d9ceeb 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -26,6 +26,7 @@ use std::marker::PhantomData; use themes::ThemeColors; mod color; +mod element; mod frame; mod style; mod themes; diff --git a/crates/gpui/playground/src/style.rs b/crates/gpui/playground/src/style.rs index bab49d10ac..f7ff929432 100644 --- a/crates/gpui/playground/src/style.rs +++ b/crates/gpui/playground/src/style.rs @@ -1,5 +1,5 @@ -use playground_macros::tailwind_lengths; -use taffy::style::{ +use crate::color::Hsla; +pub use taffy::style::{ AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent, Overflow, Position, }; @@ -62,6 +62,9 @@ pub struct Style { pub flex_grow: f32, /// The relative rate at which this item shrinks when it is contracting to fit into space, 1.0 is the default value, and this value must be positive. pub flex_shrink: f32, + + /// The fill color of this element + pub fill: Fill, } impl Style { @@ -93,117 +96,44 @@ impl Style { flex_grow: 0.0, flex_shrink: 1.0, flex_basis: LengthOrAuto::Auto, + fill: Fill::Color(Hsla { + h: 0., + s: 0., + l: 0., + a: 0., + }), }; pub fn new() -> Self { Self::DEFAULT.clone() } - // Display //////////////////// - - fn block(mut self) -> Self { - self.display = Display::Block; - self - } - - fn flex(mut self) -> Self { - self.display = Display::Flex; - self - } - - fn grid(mut self) -> Self { - self.display = Display::Grid; - self - } - - // Overflow /////////////////// - - pub fn overflow_visible(mut self) -> Self { - self.overflow.x = Overflow::Visible; - self.overflow.y = Overflow::Visible; - self - } - - pub fn overflow_hidden(mut self) -> Self { - self.overflow.x = Overflow::Hidden; - self.overflow.y = Overflow::Hidden; - self - } - - pub fn overflow_scroll(mut self) -> Self { - self.overflow.x = Overflow::Scroll; - self.overflow.y = Overflow::Scroll; - self - } - - pub fn overflow_x_visible(mut self) -> Self { - self.overflow.x = Overflow::Visible; - self - } - - pub fn overflow_x_hidden(mut self) -> Self { - self.overflow.x = Overflow::Hidden; - self - } - - pub fn overflow_x_scroll(mut self) -> Self { - self.overflow.x = Overflow::Scroll; - self - } - - pub fn overflow_y_visible(mut self) -> Self { - self.overflow.y = Overflow::Visible; - self - } - - pub fn overflow_y_hidden(mut self) -> Self { - self.overflow.y = Overflow::Hidden; - self - } - - pub fn overflow_y_scroll(mut self) -> Self { - self.overflow.y = Overflow::Scroll; - self - } - - // Position /////////////////// - - pub fn relative(mut self) -> Self { - self.position = Position::Relative; - self - } - - pub fn absolute(mut self) -> Self { - self.position = Position::Absolute; - - self - } - - #[tailwind_lengths] - pub fn inset(mut self, length: Length) -> Self { - self.inset.top = length; - self.inset.right = length; - self.inset.bottom = length; - self.inset.left = length; - self - } - - #[tailwind_lengths] - pub fn w(mut self, length: Length) -> Self { - self.size.width = length; - self - } - - #[tailwind_lengths] - pub fn min_w(mut self, length: Length) -> Self { - self.size.width = length; - self - } - - #[tailwind_lengths] - pub fn h(mut self, length: Length) -> Self { - self.size.height = length; - self + pub fn to_taffy(&self, rem_size: f32) -> taffy::style::Style { + taffy::style::Style { + display: self.display, + overflow: self.overflow.clone().into(), + scrollbar_width: self.scrollbar_width, + position: self.position, + inset: self.inset.to_taffy(rem_size), + size: self.size.to_taffy(rem_size), + min_size: self.min_size.to_taffy(rem_size), + max_size: self.max_size.to_taffy(rem_size), + aspect_ratio: self.aspect_ratio, + margin: self.margin.to_taffy(rem_size), + padding: self.padding.to_taffy(rem_size), + border: self.border.to_taffy(rem_size), + align_items: self.align_items, + align_self: self.align_self, + align_content: self.align_content, + justify_content: self.justify_content, + gap: self.gap.to_taffy(rem_size), + flex_direction: self.flex_direction, + flex_wrap: self.flex_wrap, + flex_basis: self.flex_basis.to_taffy(rem_size).into(), + flex_grow: self.flex_grow, + flex_shrink: self.flex_shrink, + ..Default::default() // Ignore grid properties for now + } } } @@ -213,6 +143,15 @@ pub struct Point { pub y: T, } +impl Into> for Point { + fn into(self) -> taffy::geometry::Point { + taffy::geometry::Point { + x: self.x, + y: self.y, + } + } +} + #[derive(Clone)] pub struct Size { pub width: T, @@ -226,6 +165,13 @@ impl Size { height: Length::Pixels(0.), } } + + pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Size { + taffy::geometry::Size { + width: self.width.to_taffy(rem_size), + height: self.height.to_taffy(rem_size), + } + } } impl Size { @@ -235,6 +181,16 @@ impl Size { height: LengthOrAuto::Auto, } } + + pub fn to_taffy>( + &self, + rem_size: f32, + ) -> taffy::geometry::Size { + taffy::geometry::Size { + width: self.width.to_taffy(rem_size).into(), + height: self.height.to_taffy(rem_size).into(), + } + } } #[derive(Clone)] @@ -254,6 +210,15 @@ impl Edges { left: Length::Pixels(0.0), } } + + pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect { + taffy::geometry::Rect { + top: self.top.to_taffy(rem_size), + right: self.right.to_taffy(rem_size), + bottom: self.bottom.to_taffy(rem_size), + left: self.left.to_taffy(rem_size), + } + } } impl Edges { @@ -274,6 +239,18 @@ impl Edges { left: LengthOrAuto::Length(Length::Pixels(0.0)), } } + + pub fn to_taffy( + &self, + rem_size: f32, + ) -> taffy::geometry::Rect { + taffy::geometry::Rect { + top: self.top.to_taffy(rem_size), + right: self.right.to_taffy(rem_size), + bottom: self.bottom.to_taffy(rem_size), + left: self.left.to_taffy(rem_size), + } + } } #[derive(Clone, Copy)] @@ -283,14 +260,44 @@ pub enum Length { Percent(f32), // 0. - 100. } +impl Length { + fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage { + match self { + Length::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels), + Length::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size), + Length::Percent(percent) => taffy::style::LengthPercentage::Percent(*percent), + } + } +} + #[derive(Clone, Copy)] pub enum LengthOrAuto { Length(Length), Auto, } +impl LengthOrAuto { + fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto { + match self { + LengthOrAuto::Length(length) => length.to_taffy(rem_size).into(), + LengthOrAuto::Auto => taffy::prelude::LengthPercentageAuto::Auto, + } + } +} + impl From for LengthOrAuto { fn from(value: Length) -> Self { LengthOrAuto::Length(value) } } + +#[derive(Clone)] +pub enum Fill { + Color(Hsla), +} + +impl Default for Fill { + fn default() -> Self { + Self::Color(Hsla::default()) + } +} diff --git a/crates/gpui/playground_macros/src/playground_macros.rs b/crates/gpui/playground_macros/src/playground_macros.rs index ab56a2c8dc..cae50e9457 100644 --- a/crates/gpui/playground_macros/src/playground_macros.rs +++ b/crates/gpui/playground_macros/src/playground_macros.rs @@ -6,8 +6,11 @@ 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, @@ -19,7 +22,7 @@ pub fn tailwind_lengths(_attr: TokenStream, item: TokenStream) -> TokenStream { for (length, value) in fixed_lengths() { let function_name = format_ident!("{}_{}", function_signature.ident, length); output_functions.extend(quote! { - pub fn #function_name(mut self) -> Self { + #visibility fn #function_name(mut self) -> Self #where_clause { let #argument_name = #value.into(); #function_body }