From 2d17e9685f5bd3f8129839d90ac8cc45b1b1dd92 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 13 Aug 2023 21:20:41 -0600 Subject: [PATCH] Compiling checkpoint --- crates/gpui/playground/src/adapter.rs | 64 ++++++++ .../gpui/playground/src/editor_layout_demo.rs | 151 ------------------ crates/gpui/playground/src/element.rs | 47 ++++-- crates/gpui/playground/src/frame.rs | 42 +++-- crates/gpui/playground/src/playground.rs | 86 +++++++--- crates/gpui/playground/src/style.rs | 100 ++++++------ crates/gpui/playground/src/themes.rs | 24 +-- crates/gpui/playground/src/tokens.rs | 10 -- .../src/playground_macros.rs | 124 +++++++------- crates/gpui/src/app/window.rs | 68 +++++++- crates/gpui/src/gpui.rs | 4 +- 11 files changed, 375 insertions(+), 345 deletions(-) create mode 100644 crates/gpui/playground/src/adapter.rs delete mode 100644 crates/gpui/playground/src/editor_layout_demo.rs delete mode 100644 crates/gpui/playground/src/tokens.rs diff --git a/crates/gpui/playground/src/adapter.rs b/crates/gpui/playground/src/adapter.rs new file mode 100644 index 0000000000..a37a5a6261 --- /dev/null +++ b/crates/gpui/playground/src/adapter.rs @@ -0,0 +1,64 @@ +use util::ResultExt; + +use crate::element::AnyElement; + +struct Adapter(AnyElement); + +impl gpui::Element for Adapter { + type LayoutState = (); + type PaintState = (); + + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + view: &mut V, + cx: &mut gpui::LayoutContext, + ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { + cx.push_layout_engine(); + if let Some(node) = self.0.layout(view, cx).log_err() { + cx.layout_engine() + .unwrap() + .compute_layout(node, constraint.max) + .log_err(); + } + cx.pop_layout_engine(); + + (constraint.max, ()) + } + + fn paint( + &mut self, + scene: &mut gpui::SceneBuilder, + bounds: gpui::geometry::rect::RectF, + visible_bounds: gpui::geometry::rect::RectF, + layout: &mut Self::LayoutState, + view: &mut V, + cx: &mut gpui::PaintContext, + ) -> Self::PaintState { + todo!() + } + + fn rect_for_text_range( + &self, + range_utf16: std::ops::Range, + bounds: gpui::geometry::rect::RectF, + visible_bounds: gpui::geometry::rect::RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> Option { + todo!() + } + + fn debug( + &self, + bounds: gpui::geometry::rect::RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> gpui::serde_json::Value { + todo!() + } +} diff --git a/crates/gpui/playground/src/editor_layout_demo.rs b/crates/gpui/playground/src/editor_layout_demo.rs deleted file mode 100644 index d7c5f01c74..0000000000 --- a/crates/gpui/playground/src/editor_layout_demo.rs +++ /dev/null @@ -1,151 +0,0 @@ -use gpui::{AnyElement, Element, LayoutContext, View, ViewContext}; - -#[derive(Element, Clone, Default)] -pub struct Playground(PhantomData); - -// example layout design here: https://www.figma.com/file/5QLTmxjO0xQpDD3CD4hR6T/Untitled?type=design&node-id=0%3A1&mode=design&t=SoJieVVIvDDDKagv-1 - -impl Playground { - pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext) -> impl Element { - col() // fullscreen container with header and main in it - .width(flex(1.)) - .height(flex(1.)) - .fill(colors(gray.900)) - .children([ - row() // header container - .fill(colors(gray.900)) - .width(flex(1.)) - .children([ - row() // tab bar - .width(flex(1.)) - .gap(spacing(2)) - .padding(spacing(3)) - .overflow_x(scroll()) - .chidren([ - row() // tab - .padding_x(spacing(3)) - .padding_y(spacing(2)) - .corner_radius(6.) - .gap(spacing(3)) - .align(center()) - .fill(colors(gray.800)) - .children([text("Tab title 1"), svg("icon_name")]), - row() // tab - .padding_x(spacing(3)) - .padding_y(spacing(2)) - .corner_radius(6.) - .gap(spacing(3)) - .align(center()) - .fill(colors(gray.800)) - .children([text("Tab title 2"), svg("icon_name")]), - row() // tab - .padding_x(spacing(3)) - .padding_y(spacing(2)) - .corner_radius(6.) - .gap(spacing(3)) - .align(center()) - .fill(colors(gray.800)) - .children([text("Tab title 3"), svg("icon_name")]), - ]), - row() // tab bar actions - .border_left(colors(gray.700)) - .gap(spacing(2)) - .padding(spacing(3)) - .chidren([ - row() - .width(spacing(8)) - .height(spacing(8)) - .corner_radius(6.) - .justify(center()) - .align(center()) - .fill(colors(gray.800)) - .child(svg(icon_name)), - row() - .width(spacing(8)) - .height(spacing(8)) - .corner_radius(6.) - .justify(center()) - .align(center()) - .fill(colors(gray.800)) - .child(svg(icon_name)), - row() - .width(spacing(8)) - .height(spacing(8)) - .corner_radius(6.) - .justify(center()) - .align(center()) - .fill(colors(gray.800)) - .child(svg(icon_name)), - ]), - ]), - row() // main container - .width(flex(1.)) - .height(flex(1.)) - .children([ - col() // left sidebar - .fill(colors(gray.800)) - .border_right(colors(gray.700)) - .height(flex(1.)) - .width(260.) - .children([ - col() // containter to hold list items and notification alert box - .justify(between()) - .padding_x(spacing(6)) - .padding_bottom(3) - .padding_top(spacing(6)) - .children([ - col().gap(spacing(3)).children([ // sidebar list - text("Item"), - text("Item"), - text("Item"), - text("Item"), - text("Item"), - text("Item"), - text("Item"), - text("Item"), - ]), - col().align(center()).gap(spacing(1)).children([ // notification alert box - text("Title text").size("lg"), - text("Description text goes here") - .text_color(colors(rose.200)), - ]), - ]), - row() - .padding_x(spacing(3)) - .padding_y(spacing(2)) - .border_top(1., colors(gray.700)) - .align(center()) - .gap(spacing(2)) - .fill(colors(gray.900)) - .children([ - row() // avatar container - .width(spacing(8)) - .height(spacing(8)) - .corner_radius(spacing(8)) - .justify(center()) - .align(center()) - .child(image(image_url)), - text("FirstName Lastname"), // user name - ]), - ]), - col() // primary content container - .align(center()) - .justify(center()) - .child( - col().justify(center()).gap(spacing(8)).children([ // detail container wrapper for center positioning - col() // blue rectangle - .width(rem(30.)) - .height(rem(20.)) - .corner_radius(16.) - .fill(colors(blue.200)), - col().gap(spacing(1)).children([ // center content text items - text("This is a title").size("lg"), - text("This is a description").text_color(colors(gray.500)), - ]), - ]), - ), - col(), // right sidebar - ]), - ]) - } -} diff --git a/crates/gpui/playground/src/element.rs b/crates/gpui/playground/src/element.rs index 8885df21d4..9ed6926366 100644 --- a/crates/gpui/playground/src/element.rs +++ b/crates/gpui/playground/src/element.rs @@ -1,12 +1,25 @@ -use crate::style::{Display, Length, Overflow, Position, Style}; -use gpui::{LayoutContext, PaintContext}; +use crate::style::{DefinedLength, Display, Overflow, Position, Style}; +use anyhow::Result; +use gpui::{Layout, LayoutContext, PaintContext}; use playground_macros::tailwind_lengths; -pub use taffy::tree::{Layout, NodeId}; +pub use taffy::tree::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); + fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result; + fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut gpui::PaintContext) + -> Result<()>; + + /// Convert to a dynamically-typed element suitable for layout and paint. + fn into_any(self) -> AnyElement + where + Self: 'static + Sized, + { + AnyElement { + element: Box::new(self) as Box>, + layout_node_id: None, + } + } // Display //////////////////// @@ -131,7 +144,7 @@ pub trait Element { } #[tailwind_lengths] - fn inset(mut self, length: Length) -> Self + fn inset(mut self, length: DefinedLength) -> Self where Self: Sized, { @@ -143,7 +156,7 @@ pub trait Element { } #[tailwind_lengths] - fn w(mut self, length: Length) -> Self + fn w(mut self, length: DefinedLength) -> Self where Self: Sized, { @@ -152,7 +165,7 @@ pub trait Element { } #[tailwind_lengths] - fn min_w(mut self, length: Length) -> Self + fn min_w(mut self, length: DefinedLength) -> Self where Self: Sized, { @@ -161,7 +174,7 @@ pub trait Element { } #[tailwind_lengths] - fn h(mut self, length: Length) -> Self + fn h(mut self, length: DefinedLength) -> Self where Self: Sized, { @@ -176,15 +189,19 @@ pub struct AnyElement { } impl AnyElement { - fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> NodeId { - let layout_node_id = self.element.layout(view, cx); + pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { + let layout_node_id = self.element.layout(view, cx)?; self.layout_node_id = Some(layout_node_id); - layout_node_id + Ok(layout_node_id) } - fn paint(&mut self, view: &mut V, cx: &mut PaintContext) { + pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext) -> Result<()> { 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); + 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) } } diff --git a/crates/gpui/playground/src/frame.rs b/crates/gpui/playground/src/frame.rs index e4c650ab72..30ec69dc20 100644 --- a/crates/gpui/playground/src/frame.rs +++ b/crates/gpui/playground/src/frame.rs @@ -1,34 +1,54 @@ -use crate::{element::Element, style::Style}; +use anyhow::{anyhow, Result}; +use gpui::{Layout, LayoutNodeId}; -pub struct Frame { +use crate::{ + element::{AnyElement, Element}, + style::Style, +}; + +pub struct Frame { style: Style, - children: Vec, + children: Vec>, } -impl Element for Frame { +pub fn frame() -> Frame { + Frame { + style: Style::default(), + children: Vec::new(), + } +} + +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 { + fn layout( + &mut self, + view: &mut V, + cx: &mut gpui::LayoutContext, + ) -> Result { let child_layout_node_ids = self .children .iter_mut() .map(|child| child.layout(view, cx)) - .collect::>(); + .collect::>>()?; let rem_size = cx.rem_pixels(); cx.layout_engine() - .new_with_children(self.style.to_taffy(rem_size), &child_layout_node_ids) - .unwrap() + .ok_or_else(|| anyhow!("no layout engine"))? + .add_node(self.style.to_taffy(rem_size), child_layout_node_ids) } fn paint( &mut self, - layout: &taffy::tree::Layout, + layout: Layout, view: &mut V, cx: &mut gpui::PaintContext, - ) { - todo!() + ) -> Result<()> { + for child in &mut self.children { + child.paint(view, cx)?; + } + Ok(()) } } diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index c667d9ceeb..07371d71d0 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -1,52 +1,94 @@ #![allow(dead_code, unused_variables)] - -use gpui::{elements::Empty, Element}; +use element::{AnyElement, Element}; +use frame::frame; use log::LevelFilter; use simplelog::SimpleLogger; +use taffy::tree::NodeId; fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); gpui::App::new(()).unwrap().run(|cx| { cx.platform().activate(true); + // cx.add_window( - // WindowOptions { - // titlebar: Some(TitlebarOptions { - // appears_transparent: true, - // ..Default::default() - // }), - // ..Default::default() - // }, - // |_| view(|_| Playground::new()), + // Default::default(), + // // |_| view(|_| Playground::new()), // ); }); } -use std::marker::PhantomData; -use themes::ThemeColors; +use themes::{rose_pine, ThemeColors}; +mod adapter; mod color; mod element; mod frame; mod style; mod themes; -mod tokens; -#[derive(Element, Clone)] -pub struct Playground(PhantomData); +pub struct Playground(AnyElement); -impl Playground { - pub fn new() -> Self { - Self(PhantomData) +impl gpui::Element for Playground { + type LayoutState = NodeId; + + type PaintState = (); + + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + view: &mut V, + cx: &mut gpui::LayoutContext, + ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { + todo!() } - pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext) -> impl Element { - Empty::new() - // workspace(&rose_pine::dawn()) + fn paint( + &mut self, + scene: &mut gpui::SceneBuilder, + bounds: gpui::geometry::rect::RectF, + visible_bounds: gpui::geometry::rect::RectF, + layout: &mut Self::LayoutState, + view: &mut V, + cx: &mut gpui::PaintContext, + ) -> Self::PaintState { + todo!() + } + + fn rect_for_text_range( + &self, + range_utf16: std::ops::Range, + bounds: gpui::geometry::rect::RectF, + visible_bounds: gpui::geometry::rect::RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> Option { + todo!() + } + + fn debug( + &self, + bounds: gpui::geometry::rect::RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> gpui::serde_json::Value { + todo!() } } -// fn workspace(theme: &ThemeColors) -> impl Element { +impl Playground { + pub fn new() -> Self { + Self(workspace(&rose_pine::moon()).into_any()) + } +} + +fn workspace(theme: &ThemeColors) -> impl Element { + frame() +} // todo!() // // column() // // .size(auto()) diff --git a/crates/gpui/playground/src/style.rs b/crates/gpui/playground/src/style.rs index f7ff929432..8d2a7855d3 100644 --- a/crates/gpui/playground/src/style.rs +++ b/crates/gpui/playground/src/style.rs @@ -19,25 +19,25 @@ pub struct Style { /// What should the `position` value of this struct use as a base offset? pub position: Position, /// How should the position of this element be tweaked relative to the layout defined? - pub inset: Edges, + pub inset: Edges, // Size properies /// Sets the initial size of the item - pub size: Size, + pub size: Size, /// Controls the minimum size of the item - pub min_size: Size, + pub min_size: Size, /// Controls the maximum size of the item - pub max_size: Size, + pub max_size: Size, /// Sets the preferred aspect ratio for the item. The ratio is calculated as width divided by height. pub aspect_ratio: Option, // Spacing Properties /// How large should the margin be on each side? - pub margin: Edges, + pub margin: Edges, /// How large should the padding be on each side? - pub padding: Edges, + pub padding: Edges, /// How large should the border be on each side? - pub border: Edges, + pub border: Edges, // Alignment properties /// How this node's children aligned in the cross/block axis? @@ -49,7 +49,7 @@ pub struct Style { /// How should contained within this item be aligned in the main/inline axis pub justify_content: Option, /// How large should the gaps between items in a flex container be? - pub gap: Size, + pub gap: Size, // Flexbox properies /// Which direction does the main axis flow in? @@ -57,7 +57,7 @@ pub struct Style { /// Should elements wrap, or stay in a single line? pub flex_wrap: FlexWrap, /// Sets the initial main axis size of the item - pub flex_basis: LengthOrAuto, + pub flex_basis: Length, /// The relative rate at which this item grows when it is expanding to fill space, 0.0 is the default value, and this value must be positive. 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. @@ -77,9 +77,9 @@ impl Style { scrollbar_width: 0.0, position: Position::Relative, inset: Edges::auto(), - margin: Edges::::zero(), - padding: Edges::::zero(), - border: Edges::::zero(), + margin: Edges::::zero(), + padding: Edges::::zero(), + border: Edges::::zero(), size: Size::auto(), min_size: Size::auto(), max_size: Size::auto(), @@ -95,7 +95,7 @@ impl Style { flex_wrap: FlexWrap::NoWrap, flex_grow: 0.0, flex_shrink: 1.0, - flex_basis: LengthOrAuto::Auto, + flex_basis: Length::Auto, fill: Fill::Color(Hsla { h: 0., s: 0., @@ -137,6 +137,12 @@ impl Style { } } +impl Default for Style { + fn default() -> Self { + Self::DEFAULT.clone() + } +} + #[derive(Clone)] pub struct Point { pub x: T, @@ -158,11 +164,11 @@ pub struct Size { pub height: T, } -impl Size { +impl Size { pub const fn zero() -> Self { Self { - width: Length::Pixels(0.), - height: Length::Pixels(0.), + width: DefinedLength::Pixels(0.), + height: DefinedLength::Pixels(0.), } } @@ -174,11 +180,11 @@ impl Size { } } -impl Size { +impl Size { pub const fn auto() -> Self { Self { - width: LengthOrAuto::Auto, - height: LengthOrAuto::Auto, + width: Length::Auto, + height: Length::Auto, } } @@ -201,13 +207,13 @@ pub struct Edges { pub left: T, } -impl Edges { +impl Edges { pub const fn zero() -> Self { Self { - top: Length::Pixels(0.0), - right: Length::Pixels(0.0), - bottom: Length::Pixels(0.0), - left: Length::Pixels(0.0), + top: DefinedLength::Pixels(0.0), + right: DefinedLength::Pixels(0.0), + bottom: DefinedLength::Pixels(0.0), + left: DefinedLength::Pixels(0.0), } } @@ -221,22 +227,22 @@ impl Edges { } } -impl Edges { +impl Edges { pub const fn auto() -> Self { Self { - top: LengthOrAuto::Auto, - right: LengthOrAuto::Auto, - bottom: LengthOrAuto::Auto, - left: LengthOrAuto::Auto, + top: Length::Auto, + right: Length::Auto, + bottom: Length::Auto, + left: Length::Auto, } } pub const fn zero() -> Self { Self { - top: LengthOrAuto::Length(Length::Pixels(0.0)), - right: LengthOrAuto::Length(Length::Pixels(0.0)), - bottom: LengthOrAuto::Length(Length::Pixels(0.0)), - left: LengthOrAuto::Length(Length::Pixels(0.0)), + top: Length::Length(DefinedLength::Pixels(0.0)), + right: Length::Length(DefinedLength::Pixels(0.0)), + bottom: Length::Length(DefinedLength::Pixels(0.0)), + left: Length::Length(DefinedLength::Pixels(0.0)), } } @@ -253,41 +259,43 @@ impl Edges { } } +/// A non-auto length that can be defined in pixels, rems, or percent of parent. #[derive(Clone, Copy)] -pub enum Length { +pub enum DefinedLength { Pixels(f32), Rems(f32), Percent(f32), // 0. - 100. } -impl Length { +impl DefinedLength { 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), + 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), } } } +/// A length that can be defined in pixels, rems, percent of parent, or auto. #[derive(Clone, Copy)] -pub enum LengthOrAuto { - Length(Length), +pub enum Length { + Length(DefinedLength), Auto, } -impl LengthOrAuto { +impl Length { 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, + Length::Length(length) => length.to_taffy(rem_size).into(), + Length::Auto => taffy::prelude::LengthPercentageAuto::Auto, } } } -impl From for LengthOrAuto { - fn from(value: Length) -> Self { - LengthOrAuto::Length(value) +impl From for Length { + fn from(value: DefinedLength) -> Self { + Length::Length(value) } } diff --git a/crates/gpui/playground/src/themes.rs b/crates/gpui/playground/src/themes.rs index f82954d94e..320d2c5813 100644 --- a/crates/gpui/playground/src/themes.rs +++ b/crates/gpui/playground/src/themes.rs @@ -1,6 +1,5 @@ use crate::color::{Hsla, Lerp}; -use serde::{Deserialize, Serialize}; -use std::{ops::Range, sync::Arc}; +use std::ops::Range; pub mod rose_pine; @@ -83,24 +82,3 @@ impl ThemeColors { self.modified.lerp(level) } } - -#[derive(Serialize, Deserialize)] -struct Entity { - class: String, - #[serde(rename = "type")] - kind: String, - id: Arc, - name: String, - value: String, - description: String, - category_id: String, - last_updated_by: String, - last_updated: String, - tags: Vec, -} - -#[derive(Serialize, Deserialize)] -struct Category { - id: String, - label: String, -} diff --git a/crates/gpui/playground/src/tokens.rs b/crates/gpui/playground/src/tokens.rs deleted file mode 100644 index 23feba07c6..0000000000 --- a/crates/gpui/playground/src/tokens.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod color { - use crate::color::{scale, ColorScale, Hsla}; - - pub fn ramp(color: impl Into) -> ColorScale { - let color = color.into(); - let end_color = color.desaturate(0.1).brighten(0.5); - let start_color = color.desaturate(0.1).darken(0.4); - scale([start_color, color, end_color]) - } -} diff --git a/crates/gpui/playground_macros/src/playground_macros.rs b/crates/gpui/playground_macros/src/playground_macros.rs index cae50e9457..13b7b14501 100644 --- a/crates/gpui/playground_macros/src/playground_macros.rs +++ b/crates/gpui/playground_macros/src/playground_macros.rs @@ -34,67 +34,67 @@ pub fn tailwind_lengths(_attr: TokenStream, item: TokenStream) -> TokenStream { fn fixed_lengths() -> Vec<(&'static str, TokenStream2)> { vec![ - ("0", quote! { Length::Pixels(0.) }), - ("px", quote! { Length::Pixels(1.) }), - ("0_5", quote! { Length::Rems(0.125) }), - ("1", quote! { Length::Rems(0.25) }), - ("1_5", quote! { Length::Rems(0.375) }), - ("2", quote! { Length::Rems(0.5) }), - ("2_5", quote! { Length::Rems(0.625) }), - ("3", quote! { Length::Rems(0.75) }), - ("3_5", quote! { Length::Rems(0.875) }), - ("4", quote! { Length::Rems(1.) }), - ("5", quote! { Length::Rems(1.25) }), - ("6", quote! { Length::Rems(1.5) }), - ("7", quote! { Length::Rems(1.75) }), - ("8", quote! { Length::Rems(2.) }), - ("9", quote! { Length::Rems(2.25) }), - ("10", quote! { Length::Rems(2.5) }), - ("11", quote! { Length::Rems(2.75) }), - ("12", quote! { Length::Rems(3.) }), - ("14", quote! { Length::Rems(3.5) }), - ("16", quote! { Length::Rems(4.) }), - ("20", quote! { Length::Rems(5.) }), - ("24", quote! { Length::Rems(6.) }), - ("28", quote! { Length::Rems(7.) }), - ("32", quote! { Length::Rems(8.) }), - ("36", quote! { Length::Rems(9.) }), - ("40", quote! { Length::Rems(10.) }), - ("44", quote! { Length::Rems(11.) }), - ("48", quote! { Length::Rems(12.) }), - ("52", quote! { Length::Rems(13.) }), - ("56", quote! { Length::Rems(14.) }), - ("60", quote! { Length::Rems(15.) }), - ("64", quote! { Length::Rems(16.) }), - ("72", quote! { Length::Rems(18.) }), - ("80", quote! { Length::Rems(20.) }), - ("96", quote! { Length::Rems(24.) }), - ("half", quote! { Length::Percent(50.) }), - ("1_3rd", quote! { Length::Percent(33.333333) }), - ("2_3rd", quote! { Length::Percent(66.666667) }), - ("1_4th", quote! { Length::Percent(25.) }), - ("2_4th", quote! { Length::Percent(50.) }), - ("3_4th", quote! { Length::Percent(75.) }), - ("1_5th", quote! { Length::Percent(20.) }), - ("2_5th", quote! { Length::Percent(40.) }), - ("3_5th", quote! { Length::Percent(60.) }), - ("4_5th", quote! { Length::Percent(80.) }), - ("1_6th", quote! { Length::Percent(16.666667) }), - ("2_6th", quote! { Length::Percent(33.333333) }), - ("3_6th", quote! { Length::Percent(50.) }), - ("4_6th", quote! { Length::Percent(66.666667) }), - ("5_6th", quote! { Length::Percent(83.333333) }), - ("1_12th", quote! { Length::Percent(8.333333) }), - ("2_12th", quote! { Length::Percent(16.666667) }), - ("3_12th", quote! { Length::Percent(25.) }), - ("4_12th", quote! { Length::Percent(33.333333) }), - ("5_12th", quote! { Length::Percent(41.666667) }), - ("6_12th", quote! { Length::Percent(50.) }), - ("7_12th", quote! { Length::Percent(58.333333) }), - ("8_12th", quote! { Length::Percent(66.666667) }), - ("9_12th", quote! { Length::Percent(75.) }), - ("10_12th", quote! { Length::Percent(83.333333) }), - ("11_12th", quote! { Length::Percent(91.666667) }), - ("full", quote! { Length::Percent(100.) }), + ("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.) }), ] } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 49d600d6dd..9ff155b760 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -40,7 +40,7 @@ use uuid::Uuid; use super::{Reference, ViewMetadata}; pub struct Window { - layout_engine: Taffy, + layout_engines: Vec, pub(crate) root_view: Option, pub(crate) focused_view_id: Option, pub(crate) parents: HashMap, @@ -75,7 +75,7 @@ impl Window { let titlebar_height = platform_window.titlebar_height(); let appearance = platform_window.appearance(); let mut window = Self { - layout_engine: Taffy::new(), + layout_engines: Vec::new(), root_view: None, focused_view_id: None, parents: Default::default(), @@ -210,8 +210,16 @@ impl<'a> WindowContext<'a> { } } - pub fn layout_engine(&mut self) -> &mut Taffy { - &mut self.window.layout_engine + pub fn layout_engine(&mut self) -> Option<&mut LayoutEngine> { + self.window.layout_engines.last_mut() + } + + pub fn push_layout_engine(&mut self) { + self.window.layout_engines.push(LayoutEngine::new()); + } + + pub fn pop_layout_engine(&mut self) { + self.window.layout_engines.pop(); } pub fn remove_window(&mut self) { @@ -1222,6 +1230,58 @@ impl<'a> WindowContext<'a> { } } +pub struct LayoutEngine(Taffy); +pub use taffy::style::Style as LayoutStyle; + +impl LayoutEngine { + fn new() -> Self { + Self(Taffy::new()) + } + + pub fn add_node(&mut self, style: LayoutStyle, children: C) -> Result + where + C: IntoIterator, + { + Ok(self + .0 + .new_with_children(style, &children.into_iter().collect::>())?) + } + + pub fn compute_layout(&mut self, root: LayoutNodeId, available_space: Vector2F) -> Result<()> { + self.0.compute_layout( + root, + taffy::geometry::Size { + width: available_space.x().into(), + height: available_space.y().into(), + }, + )?; + Ok(()) + } + + pub fn computed_layout(&mut self, node: LayoutNodeId) -> Result { + Ok(self.0.layout(node)?.into()) + } +} + +pub struct Layout { + pub bounds: RectF, + pub order: u32, +} + +impl From<&taffy::tree::Layout> for Layout { + fn from(value: &taffy::tree::Layout) -> Self { + Self { + bounds: RectF::new( + vec2f(value.location.x, value.location.y), + vec2f(value.size.width, value.size.height), + ), + order: value.order, + } + } +} + +pub type LayoutNodeId = taffy::prelude::NodeId; + pub struct RenderParams { pub view_id: usize, pub titlebar_height: f32, diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index c79c793dda..ea8eb830ac 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -27,7 +27,9 @@ pub mod json; pub mod keymap_matcher; pub mod platform; pub use gpui_macros::{test, Element}; -pub use window::{Axis, RectFExt, SizeConstraint, Vector2FExt, WindowContext}; +pub use window::{ + Axis, Layout, LayoutNodeId, RectFExt, SizeConstraint, Vector2FExt, WindowContext, +}; pub use anyhow; pub use serde_json;