Detailed changes
@@ -0,0 +1,64 @@
+use util::ResultExt;
+
+use crate::element::AnyElement;
+
+struct Adapter<V>(AnyElement<V>);
+
+impl<V: 'static> gpui::Element<V> for Adapter<V> {
+ type LayoutState = ();
+ type PaintState = ();
+
+ fn layout(
+ &mut self,
+ constraint: gpui::SizeConstraint,
+ view: &mut V,
+ cx: &mut gpui::LayoutContext<V>,
+ ) -> (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<V>,
+ ) -> Self::PaintState {
+ todo!()
+ }
+
+ fn rect_for_text_range(
+ &self,
+ range_utf16: std::ops::Range<usize>,
+ bounds: gpui::geometry::rect::RectF,
+ visible_bounds: gpui::geometry::rect::RectF,
+ layout: &Self::LayoutState,
+ paint: &Self::PaintState,
+ view: &V,
+ cx: &gpui::ViewContext<V>,
+ ) -> Option<gpui::geometry::rect::RectF> {
+ todo!()
+ }
+
+ fn debug(
+ &self,
+ bounds: gpui::geometry::rect::RectF,
+ layout: &Self::LayoutState,
+ paint: &Self::PaintState,
+ view: &V,
+ cx: &gpui::ViewContext<V>,
+ ) -> gpui::serde_json::Value {
+ todo!()
+ }
+}
@@ -1,151 +0,0 @@
-use gpui::{AnyElement, Element, LayoutContext, View, ViewContext};
-
-#[derive(Element, Clone, Default)]
-pub struct Playground<V>(PhantomData<V>);
-
-// example layout design here: https://www.figma.com/file/5QLTmxjO0xQpDD3CD4hR6T/Untitled?type=design&node-id=0%3A1&mode=design&t=SoJieVVIvDDDKagv-1
-
-impl<V> Playground<V> {
- pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
- 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
- ]),
- ])
- }
-}
@@ -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<V> {
fn style_mut(&mut self) -> &mut Style;
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> NodeId;
- fn paint(&mut self, layout: &Layout, view: &mut V, cx: &mut gpui::PaintContext<V>);
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId>;
+ fn paint(&mut self, layout: Layout, view: &mut V, cx: &mut gpui::PaintContext<V>)
+ -> Result<()>;
+
+ /// Convert to a dynamically-typed element suitable for layout and paint.
+ fn into_any(self) -> AnyElement<V>
+ where
+ Self: 'static + Sized,
+ {
+ AnyElement {
+ element: Box::new(self) as Box<dyn Element<V>>,
+ layout_node_id: None,
+ }
+ }
// Display ////////////////////
@@ -131,7 +144,7 @@ pub trait Element<V> {
}
#[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<V> {
}
#[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<V> {
}
#[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<V> {
}
#[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<V> {
}
impl<V> AnyElement<V> {
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> NodeId {
- let layout_node_id = self.element.layout(view, cx);
+ pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
+ 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<V>) {
+ pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> 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)
}
}
@@ -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<V> {
style: Style,
- children: Vec<Frame>,
+ children: Vec<AnyElement<V>>,
+}
+
+pub fn frame<V>() -> Frame<V> {
+ Frame {
+ style: Style::default(),
+ children: Vec::new(),
+ }
}
-impl<V: 'static> Element<V> for Frame {
+impl<V: 'static> Element<V> for Frame<V> {
fn style_mut(&mut self) -> &mut Style {
&mut self.style
}
- fn layout(&mut self, view: &mut V, cx: &mut gpui::LayoutContext<V>) -> taffy::tree::NodeId {
+ fn layout(
+ &mut self,
+ view: &mut V,
+ cx: &mut gpui::LayoutContext<V>,
+ ) -> Result<taffy::tree::NodeId> {
let child_layout_node_ids = self
.children
.iter_mut()
.map(|child| child.layout(view, cx))
- .collect::<Vec<_>>();
+ .collect::<Result<Vec<LayoutNodeId>>>()?;
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<V>,
- ) {
- todo!()
+ ) -> Result<()> {
+ for child in &mut self.children {
+ child.paint(view, cx)?;
+ }
+ Ok(())
}
}
@@ -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<V: 'static>(PhantomData<V>);
+pub struct Playground<V: 'static>(AnyElement<V>);
-impl<V> Playground<V> {
- pub fn new() -> Self {
- Self(PhantomData)
+impl<V: 'static> gpui::Element<V> for Playground<V> {
+ type LayoutState = NodeId;
+
+ type PaintState = ();
+
+ fn layout(
+ &mut self,
+ constraint: gpui::SizeConstraint,
+ view: &mut V,
+ cx: &mut gpui::LayoutContext<V>,
+ ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
+ todo!()
+ }
+
+ 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<V>,
+ ) -> Self::PaintState {
+ todo!()
}
- pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
- Empty::new()
- // workspace(&rose_pine::dawn())
+ fn rect_for_text_range(
+ &self,
+ range_utf16: std::ops::Range<usize>,
+ bounds: gpui::geometry::rect::RectF,
+ visible_bounds: gpui::geometry::rect::RectF,
+ layout: &Self::LayoutState,
+ paint: &Self::PaintState,
+ view: &V,
+ cx: &gpui::ViewContext<V>,
+ ) -> Option<gpui::geometry::rect::RectF> {
+ todo!()
+ }
+
+ fn debug(
+ &self,
+ bounds: gpui::geometry::rect::RectF,
+ layout: &Self::LayoutState,
+ paint: &Self::PaintState,
+ view: &V,
+ cx: &gpui::ViewContext<V>,
+ ) -> gpui::serde_json::Value {
+ todo!()
+ }
+}
+
+impl<V> Playground<V> {
+ pub fn new() -> Self {
+ Self(workspace(&rose_pine::moon()).into_any())
}
}
-// fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+ frame()
+}
// todo!()
// // column()
// // .size(auto())
@@ -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<LengthOrAuto>,
+ pub inset: Edges<Length>,
// Size properies
/// Sets the initial size of the item
- pub size: Size<LengthOrAuto>,
+ pub size: Size<Length>,
/// Controls the minimum size of the item
- pub min_size: Size<LengthOrAuto>,
+ pub min_size: Size<Length>,
/// Controls the maximum size of the item
- pub max_size: Size<LengthOrAuto>,
+ pub max_size: Size<Length>,
/// Sets the preferred aspect ratio for the item. The ratio is calculated as width divided by height.
pub aspect_ratio: Option<f32>,
// Spacing Properties
/// How large should the margin be on each side?
- pub margin: Edges<LengthOrAuto>,
+ pub margin: Edges<Length>,
/// How large should the padding be on each side?
- pub padding: Edges<Length>,
+ pub padding: Edges<DefinedLength>,
/// How large should the border be on each side?
- pub border: Edges<Length>,
+ pub border: Edges<DefinedLength>,
// 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<JustifyContent>,
/// How large should the gaps between items in a flex container be?
- pub gap: Size<Length>,
+ pub gap: Size<DefinedLength>,
// 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::<LengthOrAuto>::zero(),
- padding: Edges::<Length>::zero(),
- border: Edges::<Length>::zero(),
+ margin: Edges::<Length>::zero(),
+ padding: Edges::<DefinedLength>::zero(),
+ border: Edges::<DefinedLength>::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<T> {
pub x: T,
@@ -158,11 +164,11 @@ pub struct Size<T> {
pub height: T,
}
-impl Size<Length> {
+impl Size<DefinedLength> {
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<Length> {
}
}
-impl Size<LengthOrAuto> {
+impl Size<Length> {
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<T> {
pub left: T,
}
-impl Edges<Length> {
+impl Edges<DefinedLength> {
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<Length> {
}
}
-impl Edges<LengthOrAuto> {
+impl Edges<Length> {
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<LengthOrAuto> {
}
}
+/// 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<Length> for LengthOrAuto {
- fn from(value: Length) -> Self {
- LengthOrAuto::Length(value)
+impl From<DefinedLength> for Length {
+ fn from(value: DefinedLength) -> Self {
+ Length::Length(value)
}
}
@@ -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<str>,
- name: String,
- value: String,
- description: String,
- category_id: String,
- last_updated_by: String,
- last_updated: String,
- tags: Vec<String>,
-}
-
-#[derive(Serialize, Deserialize)]
-struct Category {
- id: String,
- label: String,
-}
@@ -1,10 +0,0 @@
-pub mod color {
- use crate::color::{scale, ColorScale, Hsla};
-
- pub fn ramp(color: impl Into<Hsla>) -> 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])
- }
-}
@@ -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.) }),
]
}
@@ -40,7 +40,7 @@ use uuid::Uuid;
use super::{Reference, ViewMetadata};
pub struct Window {
- layout_engine: Taffy,
+ layout_engines: Vec<LayoutEngine>,
pub(crate) root_view: Option<AnyViewHandle>,
pub(crate) focused_view_id: Option<usize>,
pub(crate) parents: HashMap<usize, usize>,
@@ -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<C>(&mut self, style: LayoutStyle, children: C) -> Result<LayoutNodeId>
+ where
+ C: IntoIterator<Item = LayoutNodeId>,
+ {
+ Ok(self
+ .0
+ .new_with_children(style, &children.into_iter().collect::<Vec<_>>())?)
+ }
+
+ 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<Layout> {
+ 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,
@@ -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;