diff --git a/Cargo.lock b/Cargo.lock index a791c9f9e9..2bd912446e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1574,6 +1574,12 @@ dependencies = [ "theme", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "copilot" version = "0.1.0" @@ -2105,6 +2111,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + [[package]] name = "dhat" version = "0.3.2" @@ -3050,6 +3069,7 @@ dependencies = [ "core-graphics", "core-text", "ctor", + "derive_more", "dhat", "env_logger 0.9.3", "etagere", @@ -3065,6 +3085,7 @@ dependencies = [ "metal", "num_cpus", "objc", + "optional_struct", "ordered-float", "parking", "parking_lot 0.11.2", @@ -4627,9 +4648,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg 1.1.0", "libm", @@ -4809,6 +4830,34 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "optional_struct" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e60da57c6a9d057c07f1a90ca7abed9d104fca0d0db1a7d7e3304e4567d977fd" +dependencies = [ + "optional_struct_internal", + "optional_struct_macro_impl", +] + +[[package]] +name = "optional_struct_internal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e389cec0df3c934737dadc7b927a8e05b8c8ef792cd1af06a524bd129e9f4d" + +[[package]] +name = "optional_struct_macro_impl" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "286db11c92049709d5fbbe89eecaa2febc0efe6c18d94d9ebf942e592ac80f9f" +dependencies = [ + "optional_struct_internal", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ordered-float" version = "2.10.0" @@ -4990,7 +5039,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff" dependencies = [ - "rustc_version", + "rustc_version 0.3.3", ] [[package]] @@ -6165,7 +6214,16 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver", + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.18", ] [[package]] @@ -6548,6 +6606,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + [[package]] name = "semver-parser" version = "0.10.2" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 31b7db008d..8920f27862 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -31,6 +31,7 @@ itertools = "0.10" lazy_static.workspace = true log.workspace = true num_cpus = "1.13" +optional_struct = "0.3.1" ordered-float.workspace = true parking = "2.0.0" parking_lot.workspace = true @@ -51,6 +52,7 @@ tiny-skia = "0.5" usvg = { version = "0.14", features = [] } uuid = { version = "1.1.2", features = ["v4"] } waker-fn = "1.1.0" +derive_more = "0.99.17" [build-dependencies] bindgen = "0.65.1" diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index a269706cc5..bda70a49dc 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -58,6 +58,7 @@ impl gpui::View for TextView { font_family_id: family, underline: Default::default(), font_properties: Default::default(), + soft_wrap: false, }, ) .with_highlights(vec![(17..26, underline), (34..40, underline)]) diff --git a/crates/gpui/playground/ui/src/playground_ui.rs b/crates/gpui/playground/ui/src/playground_ui.rs index 21608b3edb..f29333a67e 100644 --- a/crates/gpui/playground/ui/src/playground_ui.rs +++ b/crates/gpui/playground/ui/src/playground_ui.rs @@ -1,8 +1,5 @@ use gpui::{ - elements::{ - node::{column, length::auto, row}, - Text, - }, + elements::node::{column, length::auto, row, text}, AnyElement, Element, View, ViewContext, }; use std::{borrow::Cow, marker::PhantomData}; diff --git a/crates/gpui/playground/ui/src/tokens.rs b/crates/gpui/playground/ui/src/tokens.rs index 194f50477d..83d9209489 100644 --- a/crates/gpui/playground/ui/src/tokens.rs +++ b/crates/gpui/playground/ui/src/tokens.rs @@ -7,151 +7,157 @@ pub mod color { } pub mod text { - pub fn xs() -> f32 { - 0.75 + use gpui::elements::node::length::{rems, Rems}; + + pub fn xs() -> Rems { + rems(0.75) } - pub fn sm() -> f32 { - 0.875 + pub fn sm() -> Rems { + rems(0.875) } - pub fn base() -> f32 { - 1.0 + pub fn base() -> Rems { + rems(1.0) } - pub fn lg() -> f32 { - 1.125 + pub fn lg() -> Rems { + rems(1.125) } - pub fn xl() -> f32 { - 1.25 + pub fn xl() -> Rems { + rems(1.25) } - pub fn xxl() -> f32 { - 1.5 + pub fn xxl() -> Rems { + rems(1.5) } - pub fn xxxl() -> f32 { - 1.875 + pub fn xxxl() -> Rems { + rems(1.875) } - pub fn xxxx() -> f32 { - 2.25 + pub fn x4l() -> Rems { + rems(2.25) } - pub fn xxxxx() -> f32 { - 3.0 + pub fn x5l() -> Rems { + rems(3.0) } - pub fn xxxxxx() -> f32 { - 4.0 + pub fn x6l() -> Rems { + rems(4.0) } } pub mod padding { - pub fn p1() -> f32 { - 0.25 + use gpui::elements::node::length::{rems, Rems}; + + pub fn p1() -> Rems { + rems(0.25) } - pub fn p2() -> f32 { - 0.5 + pub fn p2() -> Rems { + rems(0.5) } - pub fn p3() -> f32 { - 0.75 + pub fn p3() -> Rems { + rems(0.75) } - pub fn p4() -> f32 { - 1.0 + pub fn p4() -> Rems { + rems(1.0) } - pub fn p5() -> f32 { - 1.25 + pub fn p5() -> Rems { + rems(1.25) } - pub fn p6() -> f32 { - 1.5 + pub fn p6() -> Rems { + rems(1.5) } - pub fn p8() -> f32 { - 2.0 + pub fn p8() -> Rems { + rems(2.0) } - pub fn p10() -> f32 { - 2.5 + pub fn p10() -> Rems { + rems(2.5) } - pub fn p12() -> f32 { - 3.0 + pub fn p12() -> Rems { + rems(3.0) } - pub fn p16() -> f32 { - 4.0 + pub fn p16() -> Rems { + rems(4.0) } - pub fn p20() -> f32 { - 5.0 + pub fn p20() -> Rems { + rems(5.0) } - pub fn p24() -> f32 { - 6.0 + pub fn p24() -> Rems { + rems(6.0) } - pub fn p32() -> f32 { - 8.0 + pub fn p32() -> Rems { + rems(8.0) } } pub mod margin { - pub fn m1() -> f32 { - 0.25 + use gpui::elements::node::length::{rems, Rems}; + + pub fn m1() -> Rems { + rems(0.25) } - pub fn m2() -> f32 { - 0.5 + pub fn m2() -> Rems { + rems(0.5) } - pub fn m3() -> f32 { - 0.75 + pub fn m3() -> Rems { + rems(0.75) } - pub fn m4() -> f32 { - 1.0 + pub fn m4() -> Rems { + rems(1.0) } - pub fn m5() -> f32 { - 1.25 + pub fn m5() -> Rems { + rems(1.25) } - pub fn m6() -> f32 { - 1.5 + pub fn m6() -> Rems { + rems(1.5) } - pub fn m8() -> f32 { - 2.0 + pub fn m8() -> Rems { + rems(2.0) } - pub fn m10() -> f32 { - 2.5 + pub fn m10() -> Rems { + rems(2.5) } - pub fn m12() -> f32 { - 3.0 + pub fn m12() -> Rems { + rems(3.0) } - pub fn m16() -> f32 { - 4.0 + pub fn m16() -> Rems { + rems(4.0) } - pub fn m20() -> f32 { - 5.0 + pub fn m20() -> Rems { + rems(5.0) } - pub fn m24() -> f32 { - 6.0 + pub fn m24() -> Rems { + rems(6.0) } - pub fn m32() -> f32 { - 8.0 + pub fn m32() -> Rems { + rems(8.0) } } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index fd22dc466e..867e0162f8 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3338,6 +3338,10 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { ) -> ElementStateHandle { self.element_state::(element_id, T::default()) } + + pub fn pixels_per_rem(&self) -> f32 { + 16. + } } impl BorrowAppContext for ViewContext<'_, '_, V> { diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 656847980c..f1e199b652 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -337,8 +337,8 @@ impl ToJson for ContainerStyle { #[derive(Clone, Copy, Debug, Default, JsonSchema)] pub struct Margin { pub top: f32, - pub left: f32, pub bottom: f32, + pub left: f32, pub right: f32, } diff --git a/crates/gpui/src/elements/node.rs b/crates/gpui/src/elements/node.rs index 1efa01dba5..c74032018a 100644 --- a/crates/gpui/src/elements/node.rs +++ b/crates/gpui/src/elements/node.rs @@ -1,5 +1,4 @@ -use log::warn; - +use super::layout_highlighted_chunks; use crate::{ color::Color, fonts::HighlightStyle, @@ -11,15 +10,14 @@ use crate::{ scene, serde_json::Value, text_layout::{Line, ShapedBoundary}, - AnyElement, AppContext, Element, LayoutContext, Quad, SceneBuilder, SizeConstraint, View, - ViewContext, + AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder, + SizeConstraint, View, ViewContext, }; - -use std::{any::Any, borrow::Cow, f32, ops::Range}; - -use self::length::Length; - -use super::layout_highlighted_chunks; +use derive_more::Add; +use length::{Length, Rems}; +use log::warn; +use optional_struct::*; +use std::{any::Any, borrow::Cow, f32, ops::Range, sync::Arc}; pub struct Node { style: NodeStyle, @@ -90,13 +88,44 @@ impl Node { self } - pub fn row(mut self) -> Self { - self.style.axis = Axis3d::X; + pub fn text_size(mut self, text_size: Rems) -> Self { + self.style.text.size = Some(text_size); self } - pub fn stack(mut self) -> Self { - self.style.axis = Axis3d::Z; + pub fn margins( + mut self, + top_bottom: impl Into, + left_right: impl Into, + ) -> Self { + let top_bottom = top_bottom.into(); + let left_right = left_right.into(); + self.style.margin = Edges { + top: top_bottom.top, + bottom: top_bottom.bottom, + left: left_right.left, + right: left_right.right, + }; + self + } + + pub fn margin_top(mut self, top: Length) -> Self { + self.style.margin.top = top; + self + } + + pub fn margin_bottom(mut self, bottom: Length) -> Self { + self.style.margin.bottom = bottom; + self + } + + pub fn margin_left(mut self, left: Length) -> Self { + self.style.margin.left = left; + self + } + + pub fn margin_right(mut self, right: Length) -> Self { + self.style.margin.right = right; self } @@ -261,22 +290,26 @@ impl Node { // size // } - fn inset_size(&self) -> Vector2F { - self.padding_size() + self.border_size() + self.margin_size() + fn inset_size(&self, rem_size: f32) -> Vector2F { + self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size) } - fn margin_size(&self) -> Vector2F { - vec2f( - self.style.margin.left + self.style.margin.right, - self.style.margin.top + self.style.margin.bottom, - ) + fn margin_size(&self, rem_size: f32) -> Vector2F { + // We need to account for auto margins + todo!() + // vec2f( + // (self.style.margin.left + self.style.margin.right).to_pixels(rem_size), + // (self.style.margin.top + self.style.margin.bottom).to_pixels(rem_size), + // ) } - fn padding_size(&self) -> Vector2F { - vec2f( - self.style.padding.left + self.style.padding.right, - self.style.padding.top + self.style.padding.bottom, - ) + fn padding_size(&self, rem_size: f32) -> Vector2F { + // We need to account for auto padding + todo!() + // vec2f( + // (self.style.padding.left + self.style.padding.right).to_pixels(rem_size), + // (self.style.padding.top + self.style.padding.bottom).to_pixels(rem_size), + // ) } fn border_size(&self) -> Vector2F { @@ -310,18 +343,17 @@ impl Element for Node { view: &mut V, cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - dbg!(constraint.max); - let mut size = Vector2F::zero(); - let margin_size = self.margin_size(); + let rem_size = cx.pixels_per_rem(); + let margin_size = self.margin_size(rem_size); match self.style.width { Length::Hug => size.set_x(f32::INFINITY), - Length::Fixed(width) => size.set_x(width + margin_size.x()), + Length::Fixed(width) => size.set_x(width.to_pixels(rem_size) + margin_size.x()), Length::Auto { min, max, .. } => size.set_x(constraint.max.x().max(min).min(max)), } match self.style.height { Length::Hug => size.set_y(f32::INFINITY), - Length::Fixed(height) => size.set_y(height + margin_size.y()), + Length::Fixed(height) => size.set_y(height.to_pixels(rem_size) + margin_size.y()), Length::Auto { min, max, .. } => size.set_y(constraint.max.y().max(min).min(max)), } @@ -337,7 +369,7 @@ impl Element for Node { } size.set_y(size.y().min(constraint.max.y())); - let inset_size = self.inset_size(); + let inset_size = self.inset_size(rem_size); let inner_size = size - inset_size; let size_of_children = match self.style.axis { Axis3d::X => self.layout_2d_children(Axis2d::X, inner_size, view, cx), @@ -362,9 +394,10 @@ impl Element for Node { visible_bounds: RectF, size_of_children: &mut Vector2F, view: &mut V, - cx: &mut ViewContext, + cx: &mut PaintContext, ) -> Self::PaintState { - let margin = &self.style.margin; + let rem_size = cx.pixels_per_rem(); + let margin: Edges = todo!(); // &self.style.margin.to_pixels(rem_size); // Account for margins let content_bounds = RectF::from_points( @@ -414,7 +447,7 @@ impl Element for Node { if !self.content.is_empty() { // Account for padding first. - let padding = &self.style.padding; + let padding: Edges = todo!(); // &self.style.padding.to_pixels(rem_size); let padded_bounds = RectF::from_points( content_bounds.origin() + vec2f(padding.left, padding.top), content_bounds.lower_right() - vec2f(padding.right, padding.top), @@ -480,6 +513,49 @@ impl Element for Node { } } +pub struct TopBottom { + top: Length, + bottom: Length, +} + +impl> From<(T, T)> for TopBottom { + fn from((top, bottom): (T, T)) -> Self { + Self { + top: top.into(), + bottom: bottom.into(), + } + } +} + +impl> From for TopBottom { + fn from(both: T) -> Self { + Self { + top: both.into(), + bottom: both.into(), + } + } +} + +pub struct LeftRight { + left: Length, + right: Length, +} + +impl From<(Length, Length)> for LeftRight { + fn from((left, right): (Length, Length)) -> Self { + Self { left, right } + } +} + +impl From for LeftRight { + fn from(both: Length) -> Self { + Self { + left: both, + right: both, + } + } +} + fn align_child( child_origin: &mut Vector2F, parent_size: Vector2F, @@ -520,14 +596,9 @@ pub struct NodeStyle { width: Length, height: Length, - margin: Edges, - padding: Edges, - - text_color: Option, - font_size: Option, - font_style: Option, - font_weight: Option, - + margin: Edges, + padding: Edges, + text: OptionalTextStyle, opacity: f32, fill: Fill, border: Border, @@ -535,6 +606,20 @@ pub struct NodeStyle { shadows: Vec, } +#[optional_struct] +struct TextStyle { + size: Rems, + font_family: Arc, + weight: FontWeight, + style: FontStyle, +} + +#[derive(Add)] +struct Size { + width: T, + height: T, +} + // Sides? #[derive(Clone, Default)] struct Edges { @@ -544,6 +629,17 @@ struct Edges { right: T, } +impl Edges { + pub fn to_pixels(&self, rem_size: f32) -> Edges { + Edges { + top: self.top.to_pixels(rem_size), + bottom: self.bottom.to_pixels(rem_size), + left: self.left.to_pixels(rem_size), + right: self.right.to_pixels(rem_size), + } + } +} + #[derive(Clone, Default)] struct CornerRadii { top_left: f32, @@ -588,11 +684,26 @@ impl Border { } pub mod length { - #[derive(Clone, Copy, Default)] + use derive_more::{Add, Into}; + + #[derive(Add, Into, Clone, Copy, Default, Debug, PartialEq)] + pub struct Rems(f32); + + pub fn rems(rems: f32) -> Rems { + Rems(rems) + } + + impl Rems { + pub fn to_pixels(&self, root_font_size: f32) -> f32 { + self.0 * root_font_size + } + } + + #[derive(Clone, Copy, Default, Debug)] pub enum Length { #[default] Hug, - Fixed(f32), + Fixed(Rems), Auto { flex: f32, min: f32, @@ -600,8 +711,8 @@ pub mod length { }, } - impl From for Length { - fn from(value: f32) -> Self { + impl From for Length { + fn from(value: Rems) -> Self { Length::Fixed(value) } } @@ -699,7 +810,7 @@ struct Shadow { color: Color, } -#[derive(Clone, Copy, Default)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] enum FontStyle { #[default] Normal, @@ -707,7 +818,7 @@ enum FontStyle { Oblique, } -#[derive(Clone, Copy, Default)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] enum FontWeight { Thin, ExtraLight, @@ -721,6 +832,7 @@ enum FontWeight { Black, } +#[derive(Default)] pub struct Text { text: Cow<'static, str>, highlights: Option, HighlightStyle)]>>, @@ -730,10 +842,11 @@ pub struct Text { )>, } -pub struct TextLayout { - shaped_lines: Vec, - wrap_boundaries: Vec>, - line_height: f32, +pub fn text(text: impl Into>) -> Node { + row().child(Text { + text: text.into(), + ..Default::default() + }) } impl Element for Text { @@ -839,7 +952,7 @@ impl Element for Text { visible_bounds: RectF, layout: &mut Self::LayoutState, _: &mut V, - cx: &mut ViewContext, + cx: &mut PaintContext, ) -> Self::PaintState { let mut origin = bounds.origin(); let empty = Vec::new(); @@ -1004,3 +1117,9 @@ impl Element for Text { }) } } + +pub struct TextLayout { + shaped_lines: Vec, + wrap_boundaries: Vec>, + line_height: f32, +} diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 41e1c94cdb..9e6f8b259a 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -422,7 +422,7 @@ impl Element for Cow<'static, str> { visible_bounds: RectF, layout: &mut Self::LayoutState, view: &mut V, - cx: &mut ViewContext, + cx: &mut PaintContext, ) -> Self::PaintState { todo!() } diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index b003042866..d9a42a84c6 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -69,6 +69,19 @@ pub struct TextStyle { #[schemars(with = "PropertiesDef")] pub font_properties: Properties, pub underline: Underline, + pub soft_wrap: bool, +} + +#[derive(Clone, Debug)] +pub struct TextStyleRefinement { + pub color: Option, + pub font_family_name: Option>, + pub font_family_id: Option, + pub font_id: Option, + pub font_size: Option, + pub font_properties: Option, + pub underline: Option, + pub soft_wrap: Option, } impl TextStyle { @@ -83,20 +96,11 @@ impl TextStyle { font_size: refinement.font_size.unwrap_or(self.font_size), font_properties: refinement.font_properties.unwrap_or(self.font_properties), underline: refinement.underline.unwrap_or(self.underline), + soft_wrap: refinement.soft_wrap.unwrap_or(self.soft_wrap), } } } -pub struct TextStyleRefinement { - pub color: Option, - pub font_family_name: Option>, - pub font_family_id: Option, - pub font_id: Option, - pub font_size: Option, - pub font_properties: Option, - pub underline: Option, -} - #[derive(JsonSchema)] #[serde(remote = "Properties")] pub struct PropertiesDef { @@ -215,6 +219,7 @@ impl TextStyle { font_size, font_properties, underline, + soft_wrap: false, }) } @@ -355,13 +360,14 @@ impl Default for TextStyle { .expect("we loaded this family from the font cache, so this should work"); Self { - color: Default::default(), + color: Color::default(), font_family_name, font_family_id, font_id, font_size: 14., font_properties: Default::default(), underline: Default::default(), + soft_wrap: true, } }) } diff --git a/crates/gpui_macros/src/gpui_macros.rs b/crates/gpui_macros/src/gpui_macros.rs index 11f1b66d2a..de878e9922 100644 --- a/crates/gpui_macros/src/gpui_macros.rs +++ b/crates/gpui_macros/src/gpui_macros.rs @@ -337,7 +337,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream { visible_bounds: gpui::geometry::rect::RectF, element: &mut gpui::elements::AnyElement, view: &mut V, - cx: &mut gpui::ViewContext, + cx: &mut gpui::PaintContext, ) { element.paint(scene, bounds.origin(), visible_bounds, view, cx); }