Compiling checkpoint

This commit is contained in:
Nathan Sobo 2023-08-13 21:20:41 -06:00
parent be7a43c81c
commit 2d17e9685f
11 changed files with 375 additions and 345 deletions

View File

@ -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!()
}
}

View File

@ -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
]),
])
}
}

View File

@ -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)
}
}

View File

@ -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>>,
}
impl<V: 'static> Element<V> for Frame {
pub fn frame<V>() -> Frame<V> {
Frame {
style: Style::default(),
children: Vec::new(),
}
}
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(())
}
}

View File

@ -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!()
}
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
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<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!()
}
}
// fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
impl<V> Playground<V> {
pub fn new() -> Self {
Self(workspace(&rose_pine::moon()).into_any())
}
}
fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
frame()
}
// todo!()
// // column()
// // .size(auto())

View File

@ -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)
}
}

View File

@ -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,
}

View File

@ -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])
}
}

View File

@ -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.) }),
]
}

View File

@ -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,

View File

@ -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;