diff --git a/crates/gpui/playground/src/element.rs b/crates/gpui/playground/src/element.rs index 9840569582..b81df22a4b 100644 --- a/crates/gpui/playground/src/element.rs +++ b/crates/gpui/playground/src/element.rs @@ -2,13 +2,14 @@ use std::{any::Any, rc::Rc}; use crate::{ adapter::Adapter, - style::{DefinedLength, Display, ElementStyle, Fill, Length, Overflow, Position}, + style::{Display, ElementStyle, Fill, Overflow, Position}, }; use anyhow::Result; use derive_more::{Deref, DerefMut}; use gpui::{ - scene::MouseClick, EngineLayout, LayoutContext as LegacyLayoutContext, - PaintContext as LegacyPaintContext, + geometry::{DefinedLength, Length}, + scene::MouseClick, + EngineLayout, LayoutContext as LegacyLayoutContext, PaintContext as LegacyPaintContext, }; use playground_macros::tailwind_lengths; pub use taffy::tree::NodeId; diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index 3d668857d2..2c68f6caf6 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -3,13 +3,12 @@ use components::button; use element::Element; use frame::frame; use gpui::{ - geometry::{rect::RectF, vector::vec2f}, + geometry::{percent, rect::RectF, vector::vec2f}, platform::WindowOptions, }; use log::LevelFilter; use simplelog::SimpleLogger; -use style::percent; use themes::{rose_pine, ThemeColors}; use view::view; diff --git a/crates/gpui/playground/src/style.rs b/crates/gpui/playground/src/style.rs index 91408d816b..08f914f69a 100644 --- a/crates/gpui/playground/src/style.rs +++ b/crates/gpui/playground/src/style.rs @@ -1,4 +1,5 @@ use crate::color::Hsla; +use gpui::geometry::{DefinedLength, Edges, Length, Point, Size}; pub use taffy::style::{ AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent, Overflow, Position, @@ -143,180 +144,6 @@ impl Default for ElementStyle { } } -#[derive(Clone)] -pub struct Point { - pub x: T, - 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, - pub height: T, -} - -impl Size { - pub const fn zero() -> Self { - Self { - width: DefinedLength::Pixels(0.), - height: DefinedLength::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 { - pub const fn auto() -> Self { - Self { - width: Length::Auto, - height: Length::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)] -pub struct Edges { - pub top: T, - pub right: T, - pub bottom: T, - pub left: T, -} - -impl Edges { - pub const fn zero() -> Self { - Self { - top: DefinedLength::Pixels(0.0), - right: DefinedLength::Pixels(0.0), - bottom: DefinedLength::Pixels(0.0), - left: DefinedLength::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 { - pub const fn auto() -> Self { - Self { - top: Length::Auto, - right: Length::Auto, - bottom: Length::Auto, - left: Length::Auto, - } - } - - pub const fn zero() -> Self { - Self { - top: Length::Defined(DefinedLength::Pixels(0.0)), - right: Length::Defined(DefinedLength::Pixels(0.0)), - bottom: Length::Defined(DefinedLength::Pixels(0.0)), - left: Length::Defined(DefinedLength::Pixels(0.0)), - } - } - - 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), - } - } -} - -/// A non-auto length that can be defined in pixels, rems, or percent of parent. -#[derive(Clone, Copy)] -pub enum DefinedLength { - Pixels(f32), - Rems(f32), - Percent(f32), // 0. - 100. -} - -impl DefinedLength { - fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage { - match self { - DefinedLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels), - DefinedLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size), - DefinedLength::Percent(percent) => { - taffy::style::LengthPercentage::Percent(*percent / 100.) - } - } - } -} - -/// A length that can be defined in pixels, rems, percent of parent, or auto. -#[derive(Clone, Copy)] -pub enum Length { - Defined(DefinedLength), - Auto, -} - -pub fn auto() -> Length { - Length::Auto -} - -pub fn percent(percent: f32) -> DefinedLength { - DefinedLength::Percent(percent) -} - -pub fn rems(rems: f32) -> DefinedLength { - DefinedLength::Rems(rems) -} - -pub fn pixels(pixels: f32) -> DefinedLength { - DefinedLength::Pixels(pixels) -} - -impl Length { - fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto { - match self { - Length::Defined(length) => length.to_taffy(rem_size).into(), - Length::Auto => taffy::prelude::LengthPercentageAuto::Auto, - } - } -} - -impl From for Length { - fn from(value: DefinedLength) -> Self { - Length::Defined(value) - } -} - #[derive(Clone)] pub enum Fill { Color(Hsla), diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 65071d89ed..d8a6c2d55e 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1,6 +1,6 @@ use crate::{ elements::AnyRootElement, - geometry::rect::RectF, + geometry::{rect::RectF, Size}, json::ToJson, keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult}, platform::{ @@ -33,7 +33,10 @@ use std::{ mem, ops::{Deref, DerefMut, Range, Sub}, }; -use taffy::Taffy; +use taffy::{ + tree::{Measurable, MeasureFunc}, + Taffy, +}; use util::ResultExt; use uuid::Uuid; @@ -1253,6 +1256,15 @@ impl LayoutEngine { .new_with_children(style, &children.into_iter().collect::>())?) } + pub fn add_measured_node(&mut self, style: LayoutStyle, measure: F) -> Result + where + F: Fn(MeasureParams) -> Size + Sync + Send + 'static, + { + Ok(self + .0 + .new_leaf_with_measure(style, MeasureFunc::Boxed(Box::new(MeasureFn(measure))))?) + } + pub fn compute_layout(&mut self, root: LayoutNodeId, available_space: Vector2F) -> Result<()> { self.0.compute_layout( root, @@ -1269,11 +1281,54 @@ impl LayoutEngine { } } +pub struct MeasureFn(F); + +impl Measurable for MeasureFn +where + F: Fn(MeasureParams) -> Size, +{ + fn measure( + &self, + known_dimensions: taffy::prelude::Size>, + available_space: taffy::prelude::Size, + ) -> taffy::prelude::Size { + (self.0)(MeasureParams { + known_dimensions: known_dimensions.into(), + available_space: available_space.into(), + }) + .into() + } +} + pub struct EngineLayout { pub bounds: RectF, pub order: u32, } +pub struct MeasureParams { + pub known_dimensions: Size>, + pub available_space: Size, +} + +pub enum AvailableSpace { + /// The amount of space available is the specified number of pixels + Pixels(f32), + /// The amount of space available is indefinite and the node should be laid out under a min-content constraint + MinContent, + /// The amount of space available is indefinite and the node should be laid out under a max-content constraint + MaxContent, +} + +impl From for AvailableSpace { + fn from(value: taffy::prelude::AvailableSpace) -> Self { + match value { + taffy::prelude::AvailableSpace::Definite(pixels) => Self::Pixels(pixels), + taffy::prelude::AvailableSpace::MinContent => Self::MinContent, + taffy::prelude::AvailableSpace::MaxContent => Self::MaxContent, + } + } +} + impl From<&taffy::tree::Layout> for EngineLayout { fn from(value: &taffy::tree::Layout) -> Self { Self { diff --git a/crates/gpui/src/geometry.rs b/crates/gpui/src/geometry.rs index fb93c26b0f..3dfb65bb58 100644 --- a/crates/gpui/src/geometry.rs +++ b/crates/gpui/src/geometry.rs @@ -131,3 +131,201 @@ impl ToJson for RectF { json!({"origin": self.origin().to_json(), "size": self.size().to_json()}) } } + +#[derive(Clone)] +pub struct Point { + pub x: T, + 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, + pub height: T, +} + +impl From> for Size +where + S: Into, +{ + fn from(value: taffy::geometry::Size) -> Self { + Self { + width: value.width.into(), + height: value.height.into(), + } + } +} + +impl Into> for Size +where + T: Into, +{ + fn into(self) -> taffy::geometry::Size { + taffy::geometry::Size { + width: self.width.into(), + height: self.height.into(), + } + } +} + +impl Size { + pub const fn zero() -> Self { + Self { + width: DefinedLength::Pixels(0.), + height: DefinedLength::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 { + pub const fn auto() -> Self { + Self { + width: Length::Auto, + height: Length::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)] +pub struct Edges { + pub top: T, + pub right: T, + pub bottom: T, + pub left: T, +} + +impl Edges { + pub const fn zero() -> Self { + Self { + top: DefinedLength::Pixels(0.0), + right: DefinedLength::Pixels(0.0), + bottom: DefinedLength::Pixels(0.0), + left: DefinedLength::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 { + pub const fn auto() -> Self { + Self { + top: Length::Auto, + right: Length::Auto, + bottom: Length::Auto, + left: Length::Auto, + } + } + + pub const fn zero() -> Self { + Self { + top: Length::Defined(DefinedLength::Pixels(0.0)), + right: Length::Defined(DefinedLength::Pixels(0.0)), + bottom: Length::Defined(DefinedLength::Pixels(0.0)), + left: Length::Defined(DefinedLength::Pixels(0.0)), + } + } + + 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), + } + } +} + +/// A non-auto length that can be defined in pixels, rems, or percent of parent. +#[derive(Clone, Copy)] +pub enum DefinedLength { + Pixels(f32), + Rems(f32), + Percent(f32), // 0. - 100. +} + +impl DefinedLength { + fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage { + match self { + DefinedLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels), + DefinedLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size), + DefinedLength::Percent(percent) => { + taffy::style::LengthPercentage::Percent(*percent / 100.) + } + } + } +} + +/// A length that can be defined in pixels, rems, percent of parent, or auto. +#[derive(Clone, Copy)] +pub enum Length { + Defined(DefinedLength), + Auto, +} + +pub fn auto() -> Length { + Length::Auto +} + +pub fn percent(percent: f32) -> DefinedLength { + DefinedLength::Percent(percent) +} + +pub fn rems(rems: f32) -> DefinedLength { + DefinedLength::Rems(rems) +} + +pub fn pixels(pixels: f32) -> DefinedLength { + DefinedLength::Pixels(pixels) +} + +impl Length { + pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto { + match self { + Length::Defined(length) => length.to_taffy(rem_size).into(), + Length::Auto => taffy::prelude::LengthPercentageAuto::Auto, + } + } +} + +impl From for Length { + fn from(value: DefinedLength) -> Self { + Length::Defined(value) + } +}