This commit is contained in:
Nathan Sobo 2023-07-27 18:23:23 -06:00
parent 2ef19e48bc
commit 480401d65d
12 changed files with 242 additions and 250 deletions

4
Cargo.lock generated
View File

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

View File

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

View File

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

View File

@ -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 {
layout.margins = self.style.margins.fixed_pixels(rem_pixels);
layout.padding = self.style.padding.fixed_pixels(rem_pixels);
eprintln!(
"{}: max_size = {:?}",
self.id.as_deref().unwrap_or(""),
max_size
);
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 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 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)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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