Detailed changes
@@ -3085,7 +3085,6 @@ dependencies = [
"metal",
"num_cpus",
"objc",
- "optional_struct",
"ordered-float",
"parking",
"parking_lot 0.11.2",
@@ -5175,7 +5174,10 @@ dependencies = [
name = "playground_ui"
version = "0.1.0"
dependencies = [
+ "derive_more",
"gpui",
+ "log",
+ "optional_struct",
]
[[package]]
@@ -31,7 +31,6 @@ 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
@@ -9,4 +9,7 @@ path = "src/playground_ui.rs"
crate-type = ["dylib"]
[dependencies]
+derive_more = "0.99.17"
gpui = { path = "../.." }
+log.workspace = true
+optional_struct = "0.3.1"
@@ -1,5 +1,6 @@
-use super::layout_highlighted_chunks;
-use crate::{
+use derive_more::Add;
+use gpui::elements::layout_highlighted_chunks;
+use gpui::{
color::Color,
fonts::HighlightStyle,
geometry::{
@@ -11,9 +12,8 @@ use crate::{
serde_json::Value,
text_layout::{Line, ShapedBoundary},
AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
- SizeConstraint, Vector2FExt, View, ViewContext,
+ SizeConstraint, View, ViewContext,
};
-use derive_more::Add;
use length::{Length, Rems};
use log::warn;
use optional_struct::*;
@@ -28,6 +28,7 @@ use std::{
pub struct Node<V: View> {
style: NodeStyle,
children: Vec<AnyElement<V>>,
+ id: Option<Cow<'static, str>>,
}
pub fn node<V: View>(child: impl Element<V>) -> Node<V> {
@@ -44,7 +45,7 @@ pub fn row<V: View>() -> Node<V> {
axis: Axis3d::X,
..Default::default()
},
- children: Default::default(),
+ ..Default::default()
}
}
@@ -54,7 +55,7 @@ pub fn stack<V: View>() -> Node<V> {
axis: Axis3d::Z,
..Default::default()
},
- children: Default::default(),
+ ..Default::default()
}
}
@@ -63,11 +64,17 @@ impl<V: View> Default for Node<V> {
Self {
style: Default::default(),
children: Default::default(),
+ id: None,
}
}
}
impl<V: View> Node<V> {
+ pub fn id(mut self, id: impl Into<Cow<'static, str>>) -> Self {
+ self.id = Some(id.into());
+ self
+ }
+
pub fn child(mut self, child: impl Element<V>) -> Self {
self.children.push(child.into_any());
self
@@ -148,26 +155,65 @@ impl<V: View> Node<V> {
view: &mut V,
cx: &mut LayoutContext<V>,
) -> Vector2F {
+ eprintln!(
+ "{}: max_size = {:?}",
+ self.id.as_deref().unwrap_or(""),
+ max_size
+ );
+
+ let mut remaining_flex: f32 = 0.;
layout.margins = self.style.margins.fixed_pixels(rem_pixels);
+ remaining_flex += self.style.margins.flex().get(axis);
layout.padding = self.style.padding.fixed_pixels(rem_pixels);
+ remaining_flex += self.style.padding.flex().get(axis);
- let padded_max =
- max_size - layout.margins.size() - self.style.borders.width - layout.padding.size();
- let mut remaining_length = padded_max.get(axis);
+ let mut padded_max =
+ max_size - layout.margins.size() - self.style.borders.size() - layout.padding.size();
+
+ match self.style.size.width {
+ Length::Hug => {}
+ Length::Fixed(width) => {
+ padded_max.set_x(width.to_pixels(rem_pixels));
+ }
+ Length::Auto { min, max, .. } => padded_max.set_x(
+ padded_max
+ .x()
+ .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
+ ),
+ };
+ match self.style.size.height {
+ Length::Hug => {}
+ Length::Fixed(height) => padded_max.set_y(height.to_pixels(rem_pixels)),
+ Length::Auto { min, max, .. } => padded_max.set_y(
+ padded_max
+ .y()
+ .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
+ ),
+ };
+
+ let mut remaining_length =
+ padded_max.get(axis) - self.style.size.get(axis).fixed_pixels(rem_pixels);
+ dbg!(padded_max, remaining_length);
// Pass 1: Total up flex units and layout inflexible children.
//
// Consume the remaining length as we layout inflexible children, so that any
// remaining length can be distributed among flexible children in the next pass.
- let mut remaining_flex: f32 = 0.;
let mut cross_axis_max: f32 = 0.;
let cross_axis = axis.rotate();
// Fixed children are unconstrained along the primary axis, and constrained to
// the padded max size along the cross axis.
- let mut child_constraint =
+ let child_constraint =
SizeConstraint::loose(Vector2F::infinity().set(cross_axis, padded_max.get(cross_axis)));
+ eprintln!(
+ "{}: child_max = {:?}, remaining_length: {}",
+ self.id.as_deref().unwrap_or(""),
+ child_constraint.max,
+ remaining_length
+ );
+
for child in &mut self.children {
if let Some(child_flex) = child
.metadata::<NodeStyle>()
@@ -181,14 +227,26 @@ impl<V: View> Node<V> {
}
}
+ eprintln!(
+ "{}: child_max = {:?}, remaining_length: {}",
+ self.id.as_deref().unwrap_or(""),
+ child_constraint.max,
+ remaining_length
+ );
+
// Pass 2: Allocate the remaining space among flexible lengths along the primary axis.
if remaining_flex > 0. {
+ dbg!(self.id.as_deref(), remaining_length, remaining_flex);
+
// Add flex pixels from margin and padding.
*layout.margins.start_mut(axis) += self.style.margins.start(axis).flex_pixels(
rem_pixels,
&mut remaining_flex,
&mut remaining_length,
);
+
+ dbg!(self.id.as_deref(), layout.margins.start(axis));
+
*layout.padding.start_mut(axis) += self.style.padding.start(axis).flex_pixels(
rem_pixels,
&mut remaining_flex,
@@ -224,16 +282,6 @@ impl<V: View> Node<V> {
);
}
- let mut size = max_size;
-
- match self.style.size.get(axis) {
- Length::Hug => {
- size.set(axis, max_size.get(axis) - remaining_length);
- }
- Length::Fixed(_) => {}
- Length::Auto { flex, min, max } => todo!(),
- };
-
let width = match self.style.size.width {
Length::Hug => match axis {
Axis2d::X => max_size.get(axis) - remaining_length,
@@ -245,7 +293,7 @@ impl<V: View> Node<V> {
}
},
Length::Fixed(width) => width.to_pixels(rem_pixels),
- Length::Auto { flex, min, max } => max_size
+ Length::Auto { min, max, .. } => max_size
.x()
.clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
};
@@ -261,16 +309,19 @@ impl<V: View> Node<V> {
}
},
Length::Fixed(height) => height.to_pixels(rem_pixels),
- Length::Auto { flex, min, max } => max_size
+ Length::Auto { min, max, .. } => max_size
.y()
.clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
};
- let length = max_size.get(axis) - remaining_length;
- match axis {
- Axis2d::X => vec2f(length, cross_axis_max),
- Axis2d::Y => vec2f(cross_axis_max, length),
- }
+ eprintln!(
+ "{}: size = {} {}",
+ self.id.as_deref().unwrap_or(""),
+ width,
+ height
+ );
+
+ vec2f(width, height)
}
fn paint_children_xy(
@@ -287,99 +338,45 @@ impl<V: View> Node<V> {
let mut child_origin = bounds.origin();
// Align all children together along the primary axis
- let mut align_horizontally = false;
- let mut align_vertically = false;
- match axis {
- Axis2d::X => align_horizontally = true,
- Axis2d::Y => align_vertically = true,
- }
- align_child(
- &mut child_origin,
- parent_size,
- layout.content_size,
- self.style.align.0,
- align_horizontally,
- align_vertically,
- );
+ // let mut align_horizontally = false;
+ // let mut align_vertically = false;
+ // match axis {
+ // Axis2d::X => align_horizontally = true,
+ // Axis2d::Y => align_vertically = true,
+ // }
+ // align_child(
+ // &mut child_origin,
+ // parent_size,
+ // layout.content_size,
+ // self.style.align.0,
+ // align_horizontally,
+ // align_vertically,
+ // );
for child in &mut self.children {
// Align each child along the cross axis
- align_horizontally = !align_horizontally;
- align_vertically = !align_vertically;
- align_child(
- &mut child_origin,
- parent_size,
- child.size(),
- self.style.align.0,
- align_horizontally,
- align_vertically,
+ // align_horizontally = !align_horizontally;
+ // align_vertically = !align_vertically;
+ // align_child(
+ // &mut child_origin,
+ // parent_size,
+ // child.size(),
+ // self.style.align.0,
+ // align_horizontally,
+ // align_vertically,
+ // );
+ //
+ eprintln!(
+ "{}: child origin {:?}",
+ self.id.as_deref().unwrap_or(""),
+ child_origin
);
-
child.paint(scene, child_origin, visible_bounds, view, cx);
// Advance along the primary axis by the size of this child
- match axis {
- Axis2d::X => child_origin.set_x(child_origin.x() + child.size().x()),
- Axis2d::Y => child_origin.set_y(child_origin.y() + child.size().y()),
- }
+ child_origin.set(axis, child_origin.get(axis) + child.size().get(axis));
}
}
-
- // fn layout_stacked_children(
- // &mut self,
- // constraint: SizeConstraint,
- // view: &mut V,
- // cx: &mut LayoutContext<V>,
- // ) -> Vector2F {
- // let mut size = Vector2F::zero();
-
- // for child in &mut self.children {
- // let child_size = child.layout(constraint, view, cx);
- // size.set_x(size.x().max(child_size.x()));
- // size.set_y(size.y().max(child_size.y()));
- // }
-
- // size
- // }
-
- // fn inset_size(&self, rem_size: f32) -> Vector2F {
- // todo!()
- // // self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size)
- // }
-
- //
- // fn margin_fixed_size(&self, rem_size: f32) -> Vector2F {
- // self.style.margins.fixed().to_pixels(rem_size)
- // }
-
- // 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 {
- // let mut x = 0.0;
- // if self.style.borders.left {
- // x += self.style.borders.width;
- // }
- // if self.style.borders.right {
- // x += self.style.borders.width;
- // }
-
- // let mut y = 0.0;
- // if self.style.borders.top {
- // y += self.style.borders.width;
- // }
- // if self.style.borders.bottom {
- // y += self.style.borders.width;
- // }
-
- // vec2f(x, y)
- // }
}
impl<V: View> Element<V> for Node<V> {
@@ -412,7 +409,8 @@ impl<V: View> Element<V> for Node<V> {
view: &mut V,
cx: &mut PaintContext<V>,
) -> Self::PaintState {
- let rem_pixels = cx.rem_pixels();
+ dbg!(&layout);
+
let margined_bounds = RectF::from_points(
bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
@@ -442,6 +440,12 @@ impl<V: View> Element<V> for Node<V> {
let Fill::Color(fill_color) = self.style.fill;
let is_fill_visible = !fill_color.is_fully_transparent();
if is_fill_visible || self.style.borders.is_visible() {
+ eprintln!(
+ "{}: paint background: {:?}",
+ self.id.as_deref().unwrap_or(""),
+ margined_bounds
+ );
+
scene.push_quad(Quad {
bounds: margined_bounds,
background: is_fill_visible.then_some(fill_color),
@@ -688,8 +692,7 @@ impl Size<Rems> {
}
}
-// Sides?
-#[derive(Clone, Default)]
+#[derive(Clone, Default, Debug)]
struct Edges<T> {
top: T,
bottom: T,
@@ -1083,7 +1086,7 @@ pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
})
}
-#[derive(Default)]
+#[derive(Default, Debug)]
pub struct NodeLayout {
content_size: Vector2F,
margins: Edges<f32>,
@@ -1194,6 +1197,8 @@ impl<V: View> Element<V> for Text {
_: &mut V,
cx: &mut PaintContext<V>,
) -> Self::PaintState {
+ dbg!(bounds);
+
let mut origin = bounds.origin();
let empty = Vec::new();
let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
@@ -1375,3 +1380,53 @@ where
(None, None) => None,
}
}
+
+trait Vector2FExt {
+ fn infinity() -> Self;
+ fn get(self, axis: Axis2d) -> f32;
+ fn set(&mut self, axis: Axis2d, value: f32) -> Self;
+}
+
+impl Vector2FExt for Vector2F {
+ fn infinity() -> Self {
+ vec2f(f32::INFINITY, f32::INFINITY)
+ }
+
+ fn get(self, axis: Axis2d) -> f32 {
+ match axis {
+ Axis2d::X => self.x(),
+ Axis2d::Y => self.y(),
+ }
+ }
+
+ // TODO: It's a bit weird to mutate and return.
+ fn set(&mut self, axis: Axis2d, value: f32) -> Self {
+ match axis {
+ Axis2d::X => self.set_x(value),
+ Axis2d::Y => self.set_y(value),
+ }
+ *self
+ }
+}
+
+trait ElementExt<V: View> {
+ fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
+ where
+ Self: Element<V> + Sized,
+ {
+ node(self).margin_left(margin_left)
+ }
+}
+
+impl<V, E> ElementExt<V> for E
+where
+ V: View,
+ E: Element<V>,
+{
+ fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
+ where
+ Self: Sized,
+ {
+ node(self).margin_left(margin_left)
+ }
+}
@@ -1,10 +1,12 @@
-use gpui::{
- elements::node::{column, length::auto, row, text},
- AnyElement, Element, LayoutContext, View, ViewContext,
+use gpui::{color::Color, AnyElement, Element, LayoutContext, View, ViewContext};
+use node::{
+ length::{auto, rems},
+ *,
};
use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
use tokens::{margin::m4, text::lg};
+mod node;
mod tokens;
#[derive(Element, Clone, Default)]
@@ -13,13 +15,32 @@ pub struct Playground<V: View>(PhantomData<V>);
impl<V: View> Playground<V> {
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
column()
+ .id("red column")
.width(auto())
+ .height(auto())
+ .fill(Color::red())
.child(
- dialog("This is a dialog", "You would see a description here.")
- .button("Button 1", 1, Self::action_1)
- .button("Button 2", 2, Self::action_2),
+ row()
+ .id("green row")
+ .width(auto())
+ .height(rems(20.))
+ .margin_left(auto())
+ .fill(Color::green()), // .child(
+ // row()
+ // .id("blue child")
+ // .height(auto())
+ // .width(rems(20.))
+ // .fill(Color::blue())
+ // .margin_left(auto()),
+ // ),
)
.into_any()
+
+ // .child(
+ // dialog("This is a dialog", "You would see a description here.")
+ // .button("Button 1", 1, Self::action_1)
+ // .button("Button 2", 2, Self::action_2),
+ // )
}
fn action_1(_: &mut V, data: &usize, _: &mut ViewContext<V>) {
@@ -118,7 +139,8 @@ where
F: ClickHandler<V, D>,
{
fn render(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> AnyElement<V> {
- todo!()
+ // TODO! Handle click etc
+ row().child(text(self.label.clone())).into_any()
}
}
@@ -1,13 +1,7 @@
-pub mod color {
- use gpui::color::Color;
-
- pub fn background(elevation: f32) -> Color {
- todo!()
- }
-}
+pub mod color {}
pub mod text {
- use gpui::elements::node::length::{rems, Rems};
+ use crate::node::length::{rems, Rems};
pub fn xs() -> Rems {
rems(0.75)
@@ -37,21 +31,21 @@ pub mod text {
rems(1.875)
}
- pub fn x4l() -> Rems {
+ pub fn xxxxl() -> Rems {
rems(2.25)
}
- pub fn x5l() -> Rems {
+ pub fn xxxxxl() -> Rems {
rems(3.0)
}
- pub fn x6l() -> Rems {
+ pub fn xxxxxxl() -> Rems {
rems(4.0)
}
}
pub mod padding {
- use gpui::elements::node::length::{rems, Rems};
+ use crate::node::length::{rems, Rems};
pub fn p1() -> Rems {
rems(0.25)
@@ -107,7 +101,7 @@ pub mod padding {
}
pub mod margin {
- use gpui::elements::node::length::{rems, Rems};
+ use crate::node::length::{rems, Rems};
pub fn m1() -> Rems {
rems(0.25)
@@ -3440,7 +3440,7 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
self.text_style_stack
.last()
.cloned()
- .unwrap_or(Default::default())
+ .unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
}
pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
@@ -3506,7 +3506,7 @@ impl<'a, 'b, 'c, V: View> PaintContext<'a, 'b, 'c, V> {
self.text_style_stack
.last()
.cloned()
- .unwrap_or(Default::default())
+ .unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
}
pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
@@ -1,5 +1,5 @@
use crate::{
- elements::{node::Axis2d, AnyRootElement},
+ elements::AnyRootElement,
geometry::rect::RectF,
json::ToJson,
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
@@ -1248,38 +1248,16 @@ impl Column for Axis {
}
pub trait Vector2FExt {
- fn infinity() -> Self;
fn along(self, axis: Axis) -> f32;
- fn get(self, axis: Axis2d) -> f32;
- fn set(&mut self, axis: Axis2d, value: f32) -> Self;
}
impl Vector2FExt for Vector2F {
- fn infinity() -> Self {
- Self::new(f32::INFINITY, f32::INFINITY)
- }
-
fn along(self, axis: Axis) -> f32 {
match axis {
Axis::Horizontal => self.x(),
Axis::Vertical => self.y(),
}
}
-
- fn get(self, axis: Axis2d) -> f32 {
- match axis {
- Axis2d::X => self.x(),
- Axis2d::Y => self.y(),
- }
- }
-
- fn set(&mut self, axis: Axis2d, value: f32) -> Self {
- match axis {
- Axis2d::X => self.set_x(value),
- Axis2d::Y => self.set_y(value),
- }
- *self
- }
}
pub trait RectFExt {
@@ -18,7 +18,7 @@ use serde_json::json;
pub struct Color(#[schemars(with = "String")] ColorU);
pub fn color(rgba: u32) -> Color {
- color(rgba)
+ Color::from_u32(rgba)
}
pub fn rgb(r: f32, g: f32, b: f32) -> Color {
@@ -12,7 +12,6 @@ mod keystroke_label;
mod label;
mod list;
mod mouse_event_handler;
-pub mod node;
mod overlay;
mod resizable;
mod stack;
@@ -28,11 +27,7 @@ pub use self::{
};
pub use crate::window::ChildView;
-use self::{
- clipped::Clipped,
- expanded::Expanded,
- node::{length::Length, node, Node},
-};
+use self::{clipped::Clipped, expanded::Expanded};
use crate::{
geometry::{
rect::RectF,
@@ -204,13 +199,6 @@ pub trait Element<V: View>: 'static {
{
MouseEventHandler::for_child(self.into_any(), region_id)
}
-
- fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
- where
- Self: Sized,
- {
- node(self).margin_left(margin_left)
- }
}
trait AnyElementState<V: View> {
@@ -400,58 +400,6 @@ pub fn layout_highlighted_chunks<'a>(
layouts
}
-// Need to figure out how fonts flow through the tree to implement this.
-impl<V: View> Element<V> for Cow<'static, str> {
- type LayoutState = ();
-
- type PaintState = ();
-
- fn layout(
- &mut self,
- constraint: SizeConstraint,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> (Vector2F, Self::LayoutState) {
- todo!()
- }
-
- fn paint(
- &mut self,
- scene: &mut SceneBuilder,
- bounds: RectF,
- visible_bounds: RectF,
- layout: &mut Self::LayoutState,
- view: &mut V,
- cx: &mut PaintContext<V>,
- ) -> Self::PaintState {
- todo!()
- }
-
- fn rect_for_text_range(
- &self,
- range_utf16: Range<usize>,
- bounds: RectF,
- visible_bounds: RectF,
- layout: &Self::LayoutState,
- paint: &Self::PaintState,
- view: &V,
- cx: &ViewContext<V>,
- ) -> Option<RectF> {
- todo!()
- }
-
- fn debug(
- &self,
- bounds: RectF,
- layout: &Self::LayoutState,
- paint: &Self::PaintState,
- view: &V,
- cx: &ViewContext<V>,
- ) -> crate::serde_json::Value {
- todo!()
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -223,6 +223,27 @@ impl TextStyle {
})
}
+ pub fn default(font_cache: &FontCache) -> Self {
+ let font_family_id = font_cache.known_existing_family();
+ let font_id = font_cache
+ .select_font(font_family_id, &Default::default())
+ .expect("did not have any font in system-provided family");
+ let font_family_name = font_cache
+ .family_name(font_family_id)
+ .expect("we loaded this family from the font cache, so this should work");
+
+ Self {
+ color: Color::default(),
+ font_family_name,
+ font_family_id,
+ font_id,
+ font_size: 14.,
+ font_properties: Default::default(),
+ underline: Default::default(),
+ soft_wrap: true,
+ }
+ }
+
pub fn with_font_size(mut self, font_size: f32) -> Self {
self.font_size = font_size;
self
@@ -350,25 +371,7 @@ impl Default for TextStyle {
let font_cache = font_cache
.as_ref()
.expect("TextStyle::default can only be called within a call to with_font_cache");
-
- let font_family_id = font_cache.known_existing_family();
- let font_id = font_cache
- .select_font(font_family_id, &Default::default())
- .expect("did not have any font in system-provided family");
- let font_family_name = font_cache
- .family_name(font_family_id)
- .expect("we loaded this family from the font cache, so this should work");
-
- Self {
- color: Color::default(),
- font_family_name,
- font_family_id,
- font_id,
- font_size: 14.,
- font_properties: Default::default(),
- underline: Default::default(),
- soft_wrap: true,
- }
+ Self::default(font_cache)
})
}
}