From c9115fa8a39612fc7f027ce7c791cec810832f19 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sat, 14 Oct 2023 14:11:08 +0200 Subject: [PATCH 01/26] feat: WIP Enhanced alignments --- crates/components/src/button.rs | 1 - crates/dom/src/dom_adapter.rs | 2 + crates/elements/src/elements.rs | 2 + crates/state/src/layout.rs | 18 ++ crates/state/src/values/alignment.rs | 17 ++ crates/state/src/values/mod.rs | 2 + crates/torin/src/node.rs | 6 +- crates/torin/src/torin.rs | 310 ++++++++++++++++----------- crates/torin/src/values/alignment.rs | 16 ++ crates/torin/src/values/mod.rs | 2 + examples/canvas.rs | 64 ++---- 11 files changed, 272 insertions(+), 168 deletions(-) create mode 100644 crates/state/src/values/alignment.rs create mode 100644 crates/torin/src/values/alignment.rs diff --git a/crates/components/src/button.rs b/crates/components/src/button.rs index cef514f0c..9c54e57e2 100644 --- a/crates/components/src/button.rs +++ b/crates/components/src/button.rs @@ -88,7 +88,6 @@ pub fn Button<'a>(cx: Scope<'a, ButtonProps<'a>>) -> Element { role: "button", width: "auto", height: "auto", - direction: "both", color: "{color}", shadow: "0 2 10 1 rgb(0, 0, 0, 45)", corner_radius: "5", diff --git a/crates/dom/src/dom_adapter.rs b/crates/dom/src/dom_adapter.rs index e97279bb4..c8e99b534 100644 --- a/crates/dom/src/dom_adapter.rs +++ b/crates/dom/src/dom_adapter.rs @@ -50,6 +50,8 @@ impl DOMAdapter for DioxusDOMAdapter<'_> { padding: size.padding, margin: size.margin, display: size.display, + main_alignment: size.main_alignment, + cross_alignment: size.cross_alignment, offset_x: Length::new(size.offset_x), offset_y: Length::new(size.offset_y), has_layout_references: size.node_ref.is_some(), diff --git a/crates/elements/src/elements.rs b/crates/elements/src/elements.rs index b0f2d4488..1738f24d0 100644 --- a/crates/elements/src/elements.rs +++ b/crates/elements/src/elements.rs @@ -178,6 +178,8 @@ builder_constructors! { font_weight: String, font_width: String, display: String, + main_alignment: String, + cross_alignment: String, reference: Reference, cursor_reference: CursorReference, rotate: String, diff --git a/crates/state/src/layout.rs b/crates/state/src/layout.rs index 3ace17f4b..9275af441 100644 --- a/crates/state/src/layout.rs +++ b/crates/state/src/layout.rs @@ -29,6 +29,8 @@ pub struct LayoutState { pub offset_y: f32, pub offset_x: f32, pub display: DisplayMode, + pub main_alignment: Alignment, + pub cross_alignment: Alignment, pub node_ref: Option>, } @@ -53,6 +55,8 @@ impl State for LayoutState { "offset_y", "offset_x", "display", + "main_alignment", + "cross_alignment", "reference", "margin", ])) @@ -182,6 +186,20 @@ impl State for LayoutState { } } } + "main_alignment" => { + if let Some(value) = attr.value.as_text() { + if let Ok(alignment) = Alignment::parse(value) { + layout.main_alignment = alignment; + } + } + } + "cross_alignment" => { + if let Some(value) = attr.value.as_text() { + if let Ok(alignment) = Alignment::parse(value) { + layout.cross_alignment = alignment; + } + } + } "reference" => { if let OwnedAttributeValue::Custom(CustomAttributeValues::Reference( reference, diff --git a/crates/state/src/values/alignment.rs b/crates/state/src/values/alignment.rs new file mode 100644 index 000000000..3bcf3fb4c --- /dev/null +++ b/crates/state/src/values/alignment.rs @@ -0,0 +1,17 @@ +use crate::Parse; +use torin::alignment::Alignment; + +#[derive(Debug, PartialEq, Eq)] +pub struct ParseAlignmentError; + +impl Parse for Alignment { + type Err = ParseAlignmentError; + + fn parse(value: &str) -> Result { + Ok(match value { + "center" => Alignment::Center, + "end" => Alignment::End, + _ => Alignment::Start, + }) + } +} diff --git a/crates/state/src/values/mod.rs b/crates/state/src/values/mod.rs index 9a7c8a2fc..b9465d980 100644 --- a/crates/state/src/values/mod.rs +++ b/crates/state/src/values/mod.rs @@ -1,4 +1,5 @@ mod accessibility; +mod alignment; mod border; mod color; mod corner_radius; @@ -15,6 +16,7 @@ mod size; mod text_shadow; pub use accessibility::*; +pub use alignment::*; pub use border::*; pub use color::*; pub use corner_radius::*; diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index d4960c034..d17213aa8 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -1,7 +1,8 @@ pub use euclid::Rect; use crate::{ - direction::DirectionMode, display::DisplayMode, gaps::Gaps, geometry::Length, size::Size, + direction::DirectionMode, display::DisplayMode, gaps::Gaps, geometry::Length, + prelude::Alignment, size::Size, }; /// Node layout configuration @@ -22,6 +23,9 @@ pub struct Node { /// Inner layout mode pub display: DisplayMode, + pub main_alignment: Alignment, + pub cross_alignment: Alignment, + /// Inner padding pub padding: Gaps, diff --git a/crates/torin/src/torin.rs b/crates/torin/src/torin.rs index 8b3803580..4b84f8fa9 100644 --- a/crates/torin/src/torin.rs +++ b/crates/torin/src/torin.rs @@ -11,7 +11,7 @@ use crate::{ dom_adapter::{DOMAdapter, NodeAreas, NodeKey}, geometry::{Area, Size2D}, node::Node, - prelude::{BoxModel, Gaps}, + prelude::{Alignment, BoxModel, Gaps}, size::Size, }; @@ -497,6 +497,59 @@ impl<'a> MeasureMode<'a> { } } +#[derive(Debug)] +enum OwnedMeasureMode { + ParentIsCached { + inner_area: Area, + }, + ParentIsNotCached { + area: Area, + inner_area: Area, + vertical_padding: f32, + horizontal_padding: f32, + }, +} + +impl OwnedMeasureMode { + pub fn ref_mut<'a>(&'a mut self) -> MeasureMode<'a> { + match self { + Self::ParentIsCached { inner_area } => MeasureMode::ParentIsCached { inner_area }, + Self::ParentIsNotCached { + area, + inner_area, + vertical_padding, + horizontal_padding, + } => MeasureMode::ParentIsNotCached { + area, + inner_area, + vertical_padding: *vertical_padding, + horizontal_padding: *horizontal_padding, + }, + } + } +} + +impl MeasureMode<'_> { + pub fn to_owned(&self) -> OwnedMeasureMode { + match self { + MeasureMode::ParentIsCached { inner_area } => OwnedMeasureMode::ParentIsCached { + inner_area: *inner_area.to_owned(), + }, + MeasureMode::ParentIsNotCached { + area, + inner_area, + vertical_padding, + horizontal_padding, + } => OwnedMeasureMode::ParentIsNotCached { + area: **area.clone(), + inner_area: **inner_area.clone(), + vertical_padding: *vertical_padding, + horizontal_padding: *horizontal_padding, + }, + } + } +} + /// Measure the inner Nodes of a Node #[allow(clippy::too_many_arguments)] #[inline(always)] @@ -511,160 +564,175 @@ fn measure_inner_nodes( mode: &mut MeasureMode, dom_adapter: &mut impl DOMAdapter, ) { - let children = dom_adapter.children_of(node_id); + let mut measure_children = |mode: &mut MeasureMode, + available_area: &mut Area, + inner_sizes: &mut Size2D, + must_cache: bool| { + let children = dom_adapter.children_of(node_id); - // Center display - - if node.display == DisplayMode::Center { - let child_id = children.first(); - - if let Some(child_id) = child_id { + for child_id in children { let inner_area = *mode.inner_area(); - let child_data = dom_adapter.get_node(child_id).unwrap(); - let (_, child_areas) = measure_node( - *child_id, + let child_data = dom_adapter.get_node(&child_id).unwrap(); + + let (child_revalidated, child_areas) = measure_node( + child_id, &child_data, layout, &inner_area, available_area, measurer, - false, + must_cache, dom_adapter, ); - // TODO(marc2332): Should I also reduce the width and heights? match node.direction { DirectionMode::Horizontal => { - let new_origin_x = - (inner_area.width() / 2.0) - (child_areas.area.width() / 2.0); - available_area.origin.x = inner_area.min_x() + new_origin_x; + // Move the available area + available_area.origin.x = child_areas.area.max_x(); + available_area.size.width -= child_areas.area.size.width; + + if let MeasureMode::ParentIsNotCached { + area, + vertical_padding, + inner_area, + .. + } = mode + { + inner_sizes.height = child_areas.area.height().max(inner_sizes.height); + inner_sizes.width += child_areas.area.width(); + + // Keep the biggest height + if node.height == Size::Inner { + area.size.height = area + .size + .height + .max(child_areas.area.size.height + *vertical_padding); + // Keep the inner area in sync + inner_area.size.height = area.size.height - *vertical_padding; + } + + // Accumulate width + if node.width == Size::Inner { + area.size.width += child_areas.area.size.width; + } + } } DirectionMode::Vertical => { - let new_origin_y = - (inner_area.height() / 2.0) - (child_areas.area.height() / 2.0); - available_area.origin.y = inner_area.min_y() + new_origin_y; - } - DirectionMode::Both => { - let new_origin_x = - (inner_area.width() / 2.0) - (child_areas.area.width() / 2.0); - let new_origin_y = - (inner_area.height() / 2.0) - (child_areas.area.height() / 2.0); - available_area.origin.x = inner_area.min_x() + new_origin_x; - available_area.origin.y = inner_area.min_y() + new_origin_y; + // Move the available area + available_area.origin.y = child_areas.area.max_y(); + available_area.size.height -= child_areas.area.size.height; + + if let MeasureMode::ParentIsNotCached { + area, + horizontal_padding, + inner_area, + .. + } = mode + { + inner_sizes.width = child_areas.area.width().max(inner_sizes.width); + inner_sizes.height += child_areas.area.height(); + + // Keep the biggest width + if node.width == Size::Inner { + area.size.width = area + .size + .width + .max(child_areas.area.size.width + *horizontal_padding); + // Keep the inner area in sync + inner_area.size.width = area.size.width - *horizontal_padding; + } + + // Accumulate height + if node.height == Size::Inner { + area.size.height += child_areas.area.size.height; + } + } } + DirectionMode::Both => {} + } + + if child_revalidated && must_cache { + layout.cache_node(child_id, child_areas); } } - } + }; - // Normal display + // KEy concepts: + // When using special alignments elements are assumed that they will have the same size in first measure and the second one - for child_id in children { - let inner_area = *mode.inner_area(); + // Center display - let child_data = dom_adapter.get_node(&child_id).unwrap().clone(); + // TODO: Only clone when necessary (center or end) - let (child_revalidated, child_areas) = measure_node( - child_id, - &child_data, - layout, - &inner_area, - available_area, - measurer, - must_cache, - dom_adapter, - ); + { + let mut alignment_mode = mode.to_owned(); + let mut alignment_mode = alignment_mode.ref_mut(); + let mut inner_sizes = inner_sizes.clone(); - match node.direction { - DirectionMode::Horizontal => { - // Move the available area - available_area.origin.x = child_areas.area.max_x(); - available_area.size.width -= child_areas.area.size.width; - - if let MeasureMode::ParentIsNotCached { - area, - vertical_padding, - inner_area, - .. - } = mode - { - inner_sizes.height = child_areas.area.height(); - inner_sizes.width += child_areas.area.width(); - - // Keep the biggest height - if node.height == Size::Inner { - area.size.height = area - .size - .height - .max(child_areas.area.size.height + *vertical_padding); - // Keep the inner area in sync - inner_area.size.height = area.size.height - *vertical_padding; - } + if node.main_alignment.is_not_start() || node.cross_alignment.is_not_start() { + measure_children( + &mut alignment_mode, + &mut available_area.clone(), + &mut inner_sizes, + false, + ); - // Accumulate width - if node.width == Size::Inner { - area.size.width += child_areas.area.size.width; - } - } - } - DirectionMode::Vertical => { - // Move the available area - available_area.origin.y = child_areas.area.max_y(); - available_area.size.height -= child_areas.area.size.height; - - if let MeasureMode::ParentIsNotCached { - area, - horizontal_padding, - inner_area, - .. - } = mode - { - inner_sizes.width = child_areas.area.width(); - inner_sizes.height += child_areas.area.height(); - - // Keep the biggest width - if node.width == Size::Inner { - area.size.width = area - .size - .width - .max(child_areas.area.size.width + *horizontal_padding); - // Keep the inner area in sync - inner_area.size.width = area.size.width - *horizontal_padding; - } + match node.direction { + DirectionMode::Horizontal => { + match node.main_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_x = + (inner_area.width() / 2.0) - (inner_sizes.width / 2.0); - // Accumulate height - if node.height == Size::Inner { - area.size.height += child_areas.area.size.height; + available_area.origin.x = inner_area.min_x() + new_origin_x; + } + Alignment::End => {} + _ => {} } - } - } - DirectionMode::Both => { - // Move the available area - available_area.origin.x = child_areas.area.max_x(); - available_area.origin.y = child_areas.area.max_y(); - available_area.size.width -= child_areas.area.size.width; - available_area.size.height -= child_areas.area.size.height; + match node.cross_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_y = + (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); - if let MeasureMode::ParentIsNotCached { area, .. } = mode { - inner_sizes.width += child_areas.area.width(); - inner_sizes.height += child_areas.area.height(); + available_area.origin.y = inner_area.min_y() + new_origin_y; + } + Alignment::End => {} + _ => {} + } + } + DirectionMode::Vertical => { + match node.main_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_y = + (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); - // Accumulate width - if node.width == Size::Inner { - area.size.width += child_areas.area.size.width; + available_area.origin.y = inner_area.min_y() + new_origin_y; + } + Alignment::End => {} + _ => {} } - // Accumulate height - if node.height == Size::Inner { - area.size.height += child_areas.area.size.height; + match node.cross_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_x = + (inner_area.width() / 2.0) - (inner_sizes.width / 2.0); + + available_area.origin.x = inner_area.min_x() + new_origin_x; + } + Alignment::End => {} + _ => {} } } + _ => {} } } - - if child_revalidated && must_cache { - layout.cache_node(child_id, child_areas); - } } + + measure_children(mode, available_area, inner_sizes, must_cache); } diff --git a/crates/torin/src/values/alignment.rs b/crates/torin/src/values/alignment.rs new file mode 100644 index 000000000..e26507db8 --- /dev/null +++ b/crates/torin/src/values/alignment.rs @@ -0,0 +1,16 @@ +#[derive(PartialEq, Clone, Debug, Default)] +pub enum Alignment { + #[default] + Start, + Center, + End, +} + +impl Alignment { + pub fn is_not_start(&self) -> bool { + match self { + Self::Start => false, + _ => true, + } + } +} diff --git a/crates/torin/src/values/mod.rs b/crates/torin/src/values/mod.rs index f69f06c73..ae7ee506a 100644 --- a/crates/torin/src/values/mod.rs +++ b/crates/torin/src/values/mod.rs @@ -1,9 +1,11 @@ +pub mod alignment; pub mod direction; pub mod display; pub mod gaps; pub mod size; pub mod prelude { + pub use crate::alignment::*; pub use crate::direction::*; pub use crate::display::*; pub use crate::gaps::*; diff --git a/examples/canvas.rs b/examples/canvas.rs index 0e2f1e55f..c9c532e17 100644 --- a/examples/canvas.rs +++ b/examples/canvas.rs @@ -122,8 +122,8 @@ fn app(cx: Scope) -> Element { background: "rgb(35, 35, 35)", height: "100", width: "100%", - display: "center", - direction: "horizontal", + main_alignment: "center", + cross_alignment: "center", padding: "15", rect { layer: "-100", @@ -132,8 +132,8 @@ fn app(cx: Scope) -> Element { width: "170", height: "100%", corner_radius: "15", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", background: "rgb(20, 20, 20)", Button { onclick: create_node, @@ -210,11 +210,11 @@ fn Editor(cx: Scope) -> Element { height: "100%", width: "100%", direction: "horizontal", + cross_alignment: "center", padding: "5", rect { - height: "40%", - display: "center", width: "130", + cross_alignment: "center", Slider { width: 100.0, value: *font_size_percentage.get(), @@ -222,21 +222,14 @@ fn Editor(cx: Scope) -> Element { font_size_percentage.set(p); } } - rect { - height: "auto", + label { width: "100%", - display: "center", - direction: "horizontal", - label { - "Font size" - } + "Font size" } } rect { - height: "40%", - display: "center", - direction: "vertical", width: "130", + cross_alignment: "center", Slider { width: 100.0, value: *line_height_percentage.get(), @@ -244,56 +237,37 @@ fn Editor(cx: Scope) -> Element { line_height_percentage.set(p); } } - rect { - height: "auto", + label { width: "100%", - display: "center", - direction: "horizontal", - label { - "Line height" - } + "Line height" } } rect { - height: "40%", - display: "center", - direction: "vertical", - width: "60", + width: "80", + cross_alignment: "center", Switch { enabled: *is_bold.get(), ontoggled: |_| { is_bold.set(!is_bold.get()); } } - rect { - height: "auto", + label { width: "100%", - display: "center", - direction: "horizontal", - label { - "Bold" - } + "Bold" } } rect { - height: "40%", - display: "center", - direction: "vertical", - width: "60", + width: "80", + cross_alignment: "center", Switch { enabled: *is_italic.get(), ontoggled: |_| { is_italic.set(!is_italic.get()); } } - rect { - height: "auto", + label { width: "100%", - display: "center", - direction: "horizontal", - label { - "Italic" - } + "Italic" } } } From 5d67298026dc73eb2712a79ab5e0272b31b73b9f Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sat, 14 Oct 2023 17:01:27 +0200 Subject: [PATCH 02/26] improvements --- crates/torin/src/torin.rs | 133 +++++++++++++++++---------- crates/torin/src/values/alignment.rs | 5 +- examples/alignment.rs | 53 +++++++++++ examples/canvas.rs | 104 ++++++++++----------- 4 files changed, 183 insertions(+), 112 deletions(-) create mode 100644 examples/alignment.rs diff --git a/crates/torin/src/torin.rs b/crates/torin/src/torin.rs index 4b84f8fa9..9448fac57 100644 --- a/crates/torin/src/torin.rs +++ b/crates/torin/src/torin.rs @@ -7,7 +7,6 @@ use tracing::info; use crate::{ custom_measurer::LayoutMeasurer, direction::DirectionMode, - display::DisplayMode, dom_adapter::{DOMAdapter, NodeAreas, NodeKey}, geometry::{Area, Size2D}, node::Node, @@ -511,7 +510,7 @@ enum OwnedMeasureMode { } impl OwnedMeasureMode { - pub fn ref_mut<'a>(&'a mut self) -> MeasureMode<'a> { + pub fn ref_mut(&mut self) -> MeasureMode<'_> { match self { Self::ParentIsCached { inner_area } => MeasureMode::ParentIsCached { inner_area }, Self::ParentIsNotCached { @@ -567,6 +566,7 @@ fn measure_inner_nodes( let mut measure_children = |mode: &mut MeasureMode, available_area: &mut Area, inner_sizes: &mut Size2D, + measure_cross_axis: bool, must_cache: bool| { let children = dom_adapter.children_of(node_id); @@ -575,12 +575,57 @@ fn measure_inner_nodes( let child_data = dom_adapter.get_node(&child_id).unwrap(); + let mut adapted_available_area = *available_area; + + if measure_cross_axis { + let (_, child_areas) = measure_node( + child_id, + &child_data, + layout, + &inner_area, + available_area, + measurer, + false, + dom_adapter, + ); + + match node.direction { + DirectionMode::Horizontal => match node.cross_alignment { + Alignment::Center => { + let new_origin_y = + (available_area.height() / 2.0) - (child_areas.area.height() / 2.0); + + adapted_available_area.origin.y = available_area.min_y() + new_origin_y; + } + Alignment::End => { + adapted_available_area.origin.y = + available_area.max_y() - child_areas.area.height(); + } + _ => {} + }, + DirectionMode::Vertical => match node.cross_alignment { + Alignment::Center => { + let new_origin_x = + (available_area.width() / 2.0) - (child_areas.area.width() / 2.0); + + adapted_available_area.origin.x = available_area.min_x() + new_origin_x; + } + Alignment::End => { + adapted_available_area.origin.x = + available_area.max_x() - child_areas.area.width(); + } + _ => {} + }, + _ => {} + } + } + let (child_revalidated, child_areas) = measure_node( child_id, &child_data, layout, &inner_area, - available_area, + &adapted_available_area, measurer, must_cache, dom_adapter, @@ -665,74 +710,60 @@ fn measure_inner_nodes( // TODO: Only clone when necessary (center or end) + let has_special_alignments = + node.main_alignment.is_not_start() || node.cross_alignment.is_not_start(); + { let mut alignment_mode = mode.to_owned(); let mut alignment_mode = alignment_mode.ref_mut(); - let mut inner_sizes = inner_sizes.clone(); + let mut inner_sizes = *inner_sizes; - if node.main_alignment.is_not_start() || node.cross_alignment.is_not_start() { + if has_special_alignments { measure_children( &mut alignment_mode, &mut available_area.clone(), &mut inner_sizes, + true, false, ); match node.direction { - DirectionMode::Horizontal => { - match node.main_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_x = - (inner_area.width() / 2.0) - (inner_sizes.width / 2.0); + DirectionMode::Horizontal => match node.main_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_x = (inner_area.width() / 2.0) - (inner_sizes.width / 2.0); - available_area.origin.x = inner_area.min_x() + new_origin_x; - } - Alignment::End => {} - _ => {} + available_area.origin.x = inner_area.min_x() + new_origin_x; } - - match node.cross_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_y = - (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); - - available_area.origin.y = inner_area.min_y() + new_origin_y; - } - Alignment::End => {} - _ => {} + Alignment::End => { + let inner_area = alignment_mode.inner_area(); + available_area.origin.x = inner_area.max_x() - inner_sizes.width; } - } - DirectionMode::Vertical => { - match node.main_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_y = - (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); - - available_area.origin.y = inner_area.min_y() + new_origin_y; - } - Alignment::End => {} - _ => {} + _ => {} + }, + DirectionMode::Vertical => match node.main_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_y = (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); + + available_area.origin.y = inner_area.min_y() + new_origin_y; } - - match node.cross_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_x = - (inner_area.width() / 2.0) - (inner_sizes.width / 2.0); - - available_area.origin.x = inner_area.min_x() + new_origin_x; - } - Alignment::End => {} - _ => {} + Alignment::End => { + let inner_area = alignment_mode.inner_area(); + available_area.origin.y = inner_area.max_y() - inner_sizes.height; } - } + _ => {} + }, _ => {} } } } - measure_children(mode, available_area, inner_sizes, must_cache); + measure_children( + mode, + available_area, + inner_sizes, + has_special_alignments, + must_cache, + ); } diff --git a/crates/torin/src/values/alignment.rs b/crates/torin/src/values/alignment.rs index e26507db8..8e96a5db3 100644 --- a/crates/torin/src/values/alignment.rs +++ b/crates/torin/src/values/alignment.rs @@ -8,9 +8,6 @@ pub enum Alignment { impl Alignment { pub fn is_not_start(&self) -> bool { - match self { - Self::Start => false, - _ => true, - } + *self != Self::Start } } diff --git a/examples/alignment.rs b/examples/alignment.rs new file mode 100644 index 000000000..719cea921 --- /dev/null +++ b/examples/alignment.rs @@ -0,0 +1,53 @@ +#![cfg_attr( + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" +)] + +use freya::prelude::*; + +fn main() { + launch(app); +} + +fn app(cx: Scope) -> Element { + render!( + rect { + height: "100%", + width: "100%", + background: "blue", + cross_alignment: "end", + main_alignment: "end", + rect { + width: "300", + height: "300", + background: "yellow", + main_alignment: "start", + cross_alignment: "start", + rect { + main_alignment: "end", + cross_alignment: "center", + background: "red", + direction: "horizontal", + width: "150", + height: "150", + rect { + width: "50", + height: "50", + background: "green" + } + rect { + width: "50", + height: "50", + background: "orange" + } + } + label { + "🦀🦀🦀🦀🦀🦀" + } + } + label { + "Hello, World!" + } + } + ) +} diff --git a/examples/canvas.rs b/examples/canvas.rs index c9c532e17..7ae9e0f3d 100644 --- a/examples/canvas.rs +++ b/examples/canvas.rs @@ -203,73 +203,63 @@ fn Editor(cx: Scope) -> Element { height: "100%", rect { width: "100%", - height: "50", - padding: "10", + height: "70", + padding: "5", direction: "horizontal", + cross_alignment: "center", rect { - height: "100%", - width: "100%", - direction: "horizontal", + width: "130", cross_alignment: "center", - padding: "5", - rect { - width: "130", - cross_alignment: "center", - Slider { - width: 100.0, - value: *font_size_percentage.get(), - onmoved: |p| { - font_size_percentage.set(p); - } - } - label { - width: "100%", - "Font size" + Slider { + width: 100.0, + value: *font_size_percentage.get(), + onmoved: |p| { + font_size_percentage.set(p); } } - rect { - width: "130", - cross_alignment: "center", - Slider { - width: 100.0, - value: *line_height_percentage.get(), - onmoved: |p| { - line_height_percentage.set(p); - } - } - label { - width: "100%", - "Line height" - } + label { + "Font size" } - rect { - width: "80", - cross_alignment: "center", - Switch { - enabled: *is_bold.get(), - ontoggled: |_| { - is_bold.set(!is_bold.get()); - } - } - label { - width: "100%", - "Bold" + } + rect { + width: "130", + cross_alignment: "center", + Slider { + width: 100.0, + value: *line_height_percentage.get(), + onmoved: |p| { + line_height_percentage.set(p); } } - rect { - width: "80", - cross_alignment: "center", - Switch { - enabled: *is_italic.get(), - ontoggled: |_| { - is_italic.set(!is_italic.get()); - } + label { + "Line height" + } + } + rect { + width: "80", + cross_alignment: "center", + Switch { + enabled: *is_bold.get(), + ontoggled: |_| { + is_bold.set(!is_bold.get()); } - label { - width: "100%", - "Italic" + } + label { + "Bold" + } + } + rect { + width: "80", + cross_alignment: "center", + Switch { + enabled: *is_italic.get(), + ontoggled: |_| { + is_italic.set(!is_italic.get()); } } + label { + "Italic" + } } } rect { @@ -344,7 +334,7 @@ fn Editor(cx: Scope) -> Element { rect { width: "{font_size * 2.0}", height: "100%", - display: "center", + main_alignment: "center", direction: "horizontal", label { font_size: "{font_size}", From c926baa4b010d5964b699a618b9140eebf06cdc7 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sat, 14 Oct 2023 20:00:37 +0200 Subject: [PATCH 03/26] tweak --- examples/alignment.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/alignment.rs b/examples/alignment.rs index 719cea921..7d71a097f 100644 --- a/examples/alignment.rs +++ b/examples/alignment.rs @@ -14,7 +14,6 @@ fn app(cx: Scope) -> Element { rect { height: "100%", width: "100%", - background: "blue", cross_alignment: "end", main_alignment: "end", rect { From 74544bf981238c0e98befea6a213347987930398 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sat, 14 Oct 2023 20:46:22 +0200 Subject: [PATCH 04/26] remove display attribute, remove 'both' direction, fix tests, fix docs, fix examples, fix components --- book/src/guides/layout.md | 19 ++++++++++---- book/src/guides/testing.md | 1 - crates/components/src/external_link.rs | 1 - crates/components/src/input.rs | 2 -- crates/components/src/network_image.rs | 7 +++--- crates/components/src/progress_bar.rs | 3 ++- crates/components/src/slider.rs | 4 +-- crates/components/src/switch.rs | 1 - crates/components/src/tooltip.rs | 5 ++-- crates/core/src/node.rs | 35 +++++++++++++++----------- crates/devtools/src/tabs/layout.rs | 24 +++++++++--------- crates/devtools/src/tabs/style.rs | 4 +-- crates/dom/src/dom_adapter.rs | 1 - crates/elements/src/elements.rs | 1 - crates/state/src/layout.rs | 13 ++-------- crates/state/src/values/display.rs | 16 ------------ crates/state/src/values/mod.rs | 2 -- crates/state/tests/parse_display.rs | 26 +++++++++++-------- crates/testing/tests/test.rs | 1 - crates/torin/src/node.rs | 24 ++++++++---------- crates/torin/src/torin.rs | 3 --- crates/torin/src/values/alignment.rs | 4 +++ crates/torin/src/values/direction.rs | 2 -- crates/torin/src/values/display.rs | 15 ----------- crates/torin/src/values/mod.rs | 2 -- crates/torin/tests/test.rs | 19 +++++++------- examples/animation.rs | 9 +++---- examples/drag.rs | 1 - examples/frameless_window.rs | 4 +-- examples/i18n.rs | 4 +-- examples/image.rs | 4 +-- examples/material_design_app.rs | 4 +-- examples/mouse_trace.rs | 8 +++--- examples/rotate.rs | 12 ++++----- examples/sidebar.rs | 1 - examples/text.rs | 1 - examples/tic_tac_toe.rs | 8 +++--- examples/touch.rs | 4 +-- 38 files changed, 130 insertions(+), 165 deletions(-) delete mode 100644 crates/state/src/values/display.rs delete mode 100644 crates/torin/src/values/display.rs diff --git a/book/src/guides/layout.md b/book/src/guides/layout.md index bec69624c..f111a3b24 100644 --- a/book/src/guides/layout.md +++ b/book/src/guides/layout.md @@ -12,7 +12,7 @@ Learn how the layout attributes work. - [`direction`](#direction) - [`padding`](#padding) - [`margin`](#margin) -- [`display`](#display) +- [`main_alignment & cross_alignment`](#main_alignment_&_cross_alignment) > ⚠️ Freya's layout is still somewhat limited. @@ -168,9 +168,18 @@ fn app(cx: Scope) -> Element { ``` -### display +### main_alignment & cross_alignment -Control how the inner elements are displayed, possible values are `normal` (default) or `center`. +Control how the inner elements are positioned inside the element. You can combine it with the `direction` attribute to create complex flows. +Possible values for both are: +- `start` (default): At the begining of the axis +- `center`: At the center of the axis +- `end`: At the end of the axis + +When using the `vertical` direction, `main_alignment` will be the Y axis and `cross_alignment` will be the X axis. But when using the `horizontal` direction, the +`main_alignment` will be the X axis and the `cross_alignment` will be the Y axis. + +Example on how to center the inner elements in both axis: ```rust, no_run fn app(cx: Scope) -> Element { @@ -178,8 +187,8 @@ fn app(cx: Scope) -> Element { rect { width: "100%", height: "100%", - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", rect { width: "50%", height: "50%", diff --git a/book/src/guides/testing.md b/book/src/guides/testing.md index 3f9a31129..aa2d05d9e 100644 --- a/book/src/guides/testing.md +++ b/book/src/guides/testing.md @@ -84,7 +84,6 @@ async fn event_test() { width: "100%", height: "100%", background: "red", - direction: "both", onclick: |_| { enabled.set(true); }, diff --git a/crates/components/src/external_link.rs b/crates/components/src/external_link.rs index ba35751d6..bd7e1e5c9 100644 --- a/crates/components/src/external_link.rs +++ b/crates/components/src/external_link.rs @@ -74,7 +74,6 @@ pub fn ExternalLink<'a>(cx: Scope<'a, ExternalLinkProps<'a>>) -> Element { render!( rect { - direction: "both", onmouseover: onmouseover, onmouseleave: onmouseleave, onclick: onclick, diff --git a/crates/components/src/input.rs b/crates/components/src/input.rs index 6ed575227..7457d7e65 100644 --- a/crates/components/src/input.rs +++ b/crates/components/src/input.rs @@ -156,13 +156,11 @@ pub fn Input<'a>(cx: Scope<'a, InputProps<'a>>) -> Element { onclick: onclick, width: "auto", height: "auto", - direction: "both", padding: "1.5", rect { width: "{width}", height: "{height}", direction: "vertical", - display: "center", color: "{color}", background: "{background}", shadow: "0 3 15 0 rgb(0, 0, 0, 70)", diff --git a/crates/components/src/network_image.rs b/crates/components/src/network_image.rs index b52ffbef6..440527691 100644 --- a/crates/components/src/network_image.rs +++ b/crates/components/src/network_image.rs @@ -99,8 +99,8 @@ pub fn NetworkImage<'a>(cx: Scope<'a, NetworkImageProps<'a>>) -> Element<'a> { rect { height: "{height}", width: "{width}", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", Loader { } @@ -115,7 +115,8 @@ pub fn NetworkImage<'a>(cx: Scope<'a, NetworkImageProps<'a>>) -> Element<'a> { rect { height: "{height}", width: "{width}", - display: "center", + main_alignment: "center", + cross_alignment: "center", label { align: "center", "Error" diff --git a/crates/components/src/progress_bar.rs b/crates/components/src/progress_bar.rs index df8df6930..2d18a9113 100644 --- a/crates/components/src/progress_bar.rs +++ b/crates/components/src/progress_bar.rs @@ -72,7 +72,8 @@ pub fn ProgressBar(cx: Scope) -> Element { width: "{progress}%", height: "100%", background: "{progress_background}", - display: "center", + main_alignment: "center", + cross_alignment: "center", overflow: "clip", if show_progress { rsx!( diff --git a/crates/components/src/slider.rs b/crates/components/src/slider.rs index e54c66235..e4e71d5b7 100644 --- a/crates/components/src/slider.rs +++ b/crates/components/src/slider.rs @@ -122,8 +122,8 @@ pub fn Slider<'a>(cx: Scope<'a, SliderProps>) -> Element<'a> { onglobalmouseover: onmouseover, onmouseleave: onmouseleave, onwheel: onwheel, - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", padding: "1", rect { background: "{theme.background}", diff --git a/crates/components/src/switch.rs b/crates/components/src/switch.rs index 31ce004b1..ea72aa8bd 100644 --- a/crates/components/src/switch.rs +++ b/crates/components/src/switch.rs @@ -108,7 +108,6 @@ pub fn Switch<'a>(cx: Scope<'a, SwitchProps<'a>>) -> Element<'a> { corner_radius: "50", rect { background: "{circle}", - direction: "both", width: "18", height: "18", corner_radius: "50", diff --git a/crates/components/src/tooltip.rs b/crates/components/src/tooltip.rs index 757103de4..ec5ee916b 100644 --- a/crates/components/src/tooltip.rs +++ b/crates/components/src/tooltip.rs @@ -27,15 +27,14 @@ pub fn Tooltip<'a>(cx: Scope<'a, TooltipProps<'a>>) -> Element { height: "30", padding: "2", width: "170", - direction: "both", rect { - direction: "both", width: "100%", height: "100%", shadow: "0 0 10 5 rgb(0, 0, 0, 50)", corner_radius: "8", background: "{background}", - display: "center", + main_alignment: "center", + cross_alignment: "center", label { max_lines: "1", color: "{color}", diff --git a/crates/core/src/node.rs b/crates/core/src/node.rs index 7d8d4c103..6a1aaedc7 100644 --- a/crates/core/src/node.rs +++ b/crates/core/src/node.rs @@ -5,7 +5,7 @@ use freya_node_state::{ Border, CornerRadius, CursorSettings, Fill, FontStyleState, LayoutState, References, Shadow, Style, Transform, }; -use torin::{direction::DirectionMode, display::DisplayMode, gaps::Gaps, size::Size}; +use torin::{alignment::Alignment, direction::DirectionMode, gaps::Gaps, size::Size}; #[derive(Clone)] pub struct NodeState { @@ -77,8 +77,15 @@ impl<'a> Iterator for NodeStateIterator<'a> { AttributeType::Direction(&self.state.size.direction), )), 7 => Some(("padding", AttributeType::Measures(self.state.size.padding))), - 8 => Some(("display", AttributeType::Display(&self.state.size.display))), - 9 => { + 8 => Some(( + "main_alignment", + AttributeType::Alignment(&self.state.size.main_alignment), + )), + 9 => Some(( + "cross_alignment", + AttributeType::Alignment(&self.state.size.cross_alignment), + )), + 10 => { let background = &self.state.style.background; let fill = match *background { Fill::Color(_) => AttributeType::Color(background.clone()), @@ -86,33 +93,33 @@ impl<'a> Iterator for NodeStateIterator<'a> { }; Some(("background", fill)) } - 10 => Some(("border", AttributeType::Border(&self.state.style.border))), - 11 => Some(( + 11 => Some(("border", AttributeType::Border(&self.state.style.border))), + 12 => Some(( "corner_radius", AttributeType::CornerRadius(self.state.style.corner_radius), )), - 12 => Some(( + 13 => Some(( "color", AttributeType::Color(self.state.font_style.color.into()), )), - 13 => Some(( + 14 => Some(( "font_family", AttributeType::Text(self.state.font_style.font_family.join(",")), )), - 14 => Some(( + 15 => Some(( "font_size", AttributeType::Measure(self.state.font_style.font_size), )), - 15 => Some(( + 16 => Some(( "line_height", AttributeType::Measure(self.state.font_style.line_height), )), - 16 => Some(("offset_x", AttributeType::Measure(self.state.size.offset_x))), - 17 => Some(("offset_y", AttributeType::Measure(self.state.size.offset_y))), + 17 => Some(("offset_x", AttributeType::Measure(self.state.size.offset_x))), + 18 => Some(("offset_y", AttributeType::Measure(self.state.size.offset_y))), n => { let shadows = &self.state.style.shadows; let shadow = shadows - .get(n - 18) + .get(n - 19) .map(|shadow| ("shadow", AttributeType::Shadow(shadow))); if shadow.is_some() { @@ -120,7 +127,7 @@ impl<'a> Iterator for NodeStateIterator<'a> { } else { let text_shadows = &self.state.font_style.text_shadows; text_shadows - .get(n - 18 + shadows.len()) + .get(n - 19 + shadows.len()) .map(|text_shadow| ("text_shadow", AttributeType::TextShadow(text_shadow))) } } @@ -143,7 +150,7 @@ pub enum AttributeType<'a> { Measures(Gaps), CornerRadius(CornerRadius), Direction(&'a DirectionMode), - Display(&'a DisplayMode), + Alignment(&'a Alignment), Shadow(&'a Shadow), TextShadow(&'a TextShadow), Text(String), diff --git a/crates/devtools/src/tabs/layout.rs b/crates/devtools/src/tabs/layout.rs index 636cfb7d3..d5c328d38 100644 --- a/crates/devtools/src/tabs/layout.rs +++ b/crates/devtools/src/tabs/layout.rs @@ -42,8 +42,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { rect { width: "100%", height: "calc(100% - 25)", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", background: "rgb(40, 40, 40)", rect { width: "100%", @@ -51,8 +51,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { background: "rgb(71, 180, 240)", corner_radius: "5", rect { - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", width: "100%", height: "25", label { @@ -66,8 +66,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { height: "calc(100% - 50)", direction: "horizontal", rect { - direction: "vertical", - display: "center", + main_alignment: "center", + cross_alignment: "center", width: "25", height: "100%", label { @@ -79,8 +79,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { rect { width: "calc(100% - 50)", height: "100%", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", background: "rgb(40, 40, 40)", corner_radius: "5", label { @@ -88,8 +88,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { } } rect { - direction: "vertical", - display: "center", + main_alignment: "center", + cross_alignment: "center", width: "25", height: "100%", label { @@ -100,8 +100,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { } } rect { - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", width: "100%", height: "25", label { diff --git a/crates/devtools/src/tabs/style.rs b/crates/devtools/src/tabs/style.rs index da54b1f50..fe1758324 100644 --- a/crates/devtools/src/tabs/style.rs +++ b/crates/devtools/src/tabs/style.rs @@ -114,12 +114,12 @@ pub fn NodeInspectorStyle(cx: Scope, node_id: NodeId) -> Element { } } } - AttributeType::Display(display) => { + AttributeType::Alignment(alignment) => { rsx!{ Property { key: "{i}", name: "{name}", - value: display.pretty() + value: alignment.pretty() } } } diff --git a/crates/dom/src/dom_adapter.rs b/crates/dom/src/dom_adapter.rs index c8e99b534..dbd95c85a 100644 --- a/crates/dom/src/dom_adapter.rs +++ b/crates/dom/src/dom_adapter.rs @@ -49,7 +49,6 @@ impl DOMAdapter for DioxusDOMAdapter<'_> { direction: size.direction, padding: size.padding, margin: size.margin, - display: size.display, main_alignment: size.main_alignment, cross_alignment: size.cross_alignment, offset_x: Length::new(size.offset_x), diff --git a/crates/elements/src/elements.rs b/crates/elements/src/elements.rs index 1738f24d0..197d4ffa2 100644 --- a/crates/elements/src/elements.rs +++ b/crates/elements/src/elements.rs @@ -177,7 +177,6 @@ builder_constructors! { font_style: String, font_weight: String, font_width: String, - display: String, main_alignment: String, cross_alignment: String, reference: Reference, diff --git a/crates/state/src/layout.rs b/crates/state/src/layout.rs index 9275af441..97557463f 100644 --- a/crates/state/src/layout.rs +++ b/crates/state/src/layout.rs @@ -28,7 +28,6 @@ pub struct LayoutState { pub node_id: NodeId, pub offset_y: f32, pub offset_x: f32, - pub display: DisplayMode, pub main_alignment: Alignment, pub cross_alignment: Alignment, pub node_ref: Option>, @@ -54,7 +53,6 @@ impl State for LayoutState { "direction", "offset_y", "offset_x", - "display", "main_alignment", "cross_alignment", "reference", @@ -160,7 +158,6 @@ impl State for LayoutState { if let Some(value) = attr.value.as_text() { layout.direction = match value { "horizontal" => DirectionMode::Horizontal, - "both" => DirectionMode::Both, _ => DirectionMode::Vertical, } } @@ -179,13 +176,6 @@ impl State for LayoutState { } } } - "display" => { - if let Some(value) = attr.value.as_text() { - if let Ok(display) = DisplayMode::parse(value) { - layout.display = display; - } - } - } "main_alignment" => { if let Some(value) = attr.value.as_text() { if let Ok(alignment) = Alignment::parse(value) { @@ -226,7 +216,8 @@ impl State for LayoutState { || (layout.direction != self.direction) || (layout.offset_x != self.offset_x) || (layout.offset_y != self.offset_y) - || (layout.display != self.display); + || (layout.main_alignment != self.main_alignment) + || (layout.cross_alignment != self.cross_alignment); if changed { torin_layout.lock().unwrap().invalidate(node_view.node_id()); diff --git a/crates/state/src/values/display.rs b/crates/state/src/values/display.rs deleted file mode 100644 index 083c6880e..000000000 --- a/crates/state/src/values/display.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::Parse; -use torin::display::DisplayMode; - -#[derive(Debug, PartialEq, Eq)] -pub struct ParseDisplayModeError; - -impl Parse for DisplayMode { - type Err = ParseDisplayModeError; - - fn parse(value: &str) -> Result { - Ok(match value { - "center" => DisplayMode::Center, - _ => DisplayMode::Normal, - }) - } -} diff --git a/crates/state/src/values/mod.rs b/crates/state/src/values/mod.rs index b9465d980..3891a5e41 100644 --- a/crates/state/src/values/mod.rs +++ b/crates/state/src/values/mod.rs @@ -5,7 +5,6 @@ mod color; mod corner_radius; mod cursor; mod decoration; -mod display; mod fill; mod font; mod gaps; @@ -22,7 +21,6 @@ pub use color::*; pub use corner_radius::*; pub use cursor::*; pub use decoration::*; -pub use display::*; pub use fill::*; pub use font::*; pub use gaps::*; diff --git a/crates/state/tests/parse_display.rs b/crates/state/tests/parse_display.rs index c475adc3d..47960e2a0 100644 --- a/crates/state/tests/parse_display.rs +++ b/crates/state/tests/parse_display.rs @@ -1,20 +1,26 @@ use freya_node_state::Parse; -use torin::display::DisplayMode; +use torin::alignment::Alignment; #[test] -fn parse_normal_display() { - let display = DisplayMode::parse("normal"); - assert_eq!(display, Ok(DisplayMode::Normal)); +fn parse_normal_alignment() { + let alignment = Alignment::parse("start"); + assert_eq!(alignment, Ok(Alignment::Start)); } #[test] -fn parse_center_display() { - let display = DisplayMode::parse("center"); - assert_eq!(display, Ok(DisplayMode::Center)); +fn parse_center_alignment() { + let alignment = Alignment::parse("center"); + assert_eq!(alignment, Ok(Alignment::Center)); } #[test] -fn parse_fallback_display() { - let display = DisplayMode::parse("freya!!"); - assert_eq!(display, Ok(DisplayMode::Normal)); +fn parse_end_alignment() { + let alignment = Alignment::parse("end"); + assert_eq!(alignment, Ok(Alignment::End)); +} + +#[test] +fn parse_fallback_alignment() { + let alignment = Alignment::parse("Hello, World!"); + assert_eq!(alignment, Ok(Alignment::Start)); } diff --git a/crates/testing/tests/test.rs b/crates/testing/tests/test.rs index ca00f5533..182a27ed6 100644 --- a/crates/testing/tests/test.rs +++ b/crates/testing/tests/test.rs @@ -75,7 +75,6 @@ async fn simulate_events() { width: "100%", height: "100%", background: "red", - direction: "both", onclick: |_| { enabled.set(true); }, diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index d17213aa8..a696a3d8c 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -1,8 +1,7 @@ pub use euclid::Rect; use crate::{ - direction::DirectionMode, display::DisplayMode, gaps::Gaps, geometry::Length, - prelude::Alignment, size::Size, + alignment::Alignment, direction::DirectionMode, gaps::Gaps, geometry::Length, size::Size, }; /// Node layout configuration @@ -20,9 +19,7 @@ pub struct Node { pub maximum_width: Size, pub maximum_height: Size, - /// Inner layout mode - pub display: DisplayMode, - + // Axis alignments for the children pub main_alignment: Alignment, pub cross_alignment: Alignment, @@ -85,17 +82,19 @@ impl Node { } } - /// Construct a new Node given a size and a display - pub fn from_size_and_display_and_direction( + /// Construct a new Node given a size, alignments and a direction + pub fn from_size_and_alignments_and_direction( width: Size, height: Size, - display: DisplayMode, + main_alignment: Alignment, + cross_alignment: Alignment, direction: DirectionMode, ) -> Self { Self { width, height, - display, + main_alignment, + cross_alignment, direction, ..Default::default() } @@ -113,9 +112,8 @@ impl Node { /// Has properties that depend on the inner Nodes? pub fn does_depend_on_inner(&self) -> bool { - Size::Inner == self.width - || Size::Inner == self.height - || self.has_layout_references - || self.display == DisplayMode::Center + Size::Inner == self.width || Size::Inner == self.height || self.has_layout_references + // || self.main_alignment.is_not_start() + // || self.cross_alignment.is_not_start() } } diff --git a/crates/torin/src/torin.rs b/crates/torin/src/torin.rs index 9448fac57..08b766e52 100644 --- a/crates/torin/src/torin.rs +++ b/crates/torin/src/torin.rs @@ -616,7 +616,6 @@ fn measure_inner_nodes( } _ => {} }, - _ => {} } } @@ -694,7 +693,6 @@ fn measure_inner_nodes( } } } - DirectionMode::Both => {} } if child_revalidated && must_cache { @@ -754,7 +752,6 @@ fn measure_inner_nodes( } _ => {} }, - _ => {} } } } diff --git a/crates/torin/src/values/alignment.rs b/crates/torin/src/values/alignment.rs index 8e96a5db3..083677313 100644 --- a/crates/torin/src/values/alignment.rs +++ b/crates/torin/src/values/alignment.rs @@ -10,4 +10,8 @@ impl Alignment { pub fn is_not_start(&self) -> bool { *self != Self::Start } + + pub fn pretty(&self) -> String { + format!("{self:?}") + } } diff --git a/crates/torin/src/values/direction.rs b/crates/torin/src/values/direction.rs index 2553d93f1..b219e1433 100644 --- a/crates/torin/src/values/direction.rs +++ b/crates/torin/src/values/direction.rs @@ -3,7 +3,6 @@ pub enum DirectionMode { #[default] Vertical, Horizontal, - Both, } impl DirectionMode { @@ -11,7 +10,6 @@ impl DirectionMode { match self { DirectionMode::Horizontal => "horizontal".to_string(), DirectionMode::Vertical => "vertical".to_string(), - DirectionMode::Both => "both".to_string(), } } } diff --git a/crates/torin/src/values/display.rs b/crates/torin/src/values/display.rs deleted file mode 100644 index 142a2d5a4..000000000 --- a/crates/torin/src/values/display.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[derive(PartialEq, Clone, Debug, Copy, Default)] -pub enum DisplayMode { - #[default] - Normal, - Center, -} - -impl DisplayMode { - pub fn pretty(&self) -> String { - match self { - DisplayMode::Normal => "Normal".to_string(), - DisplayMode::Center => "Center".to_string(), - } - } -} diff --git a/crates/torin/src/values/mod.rs b/crates/torin/src/values/mod.rs index ae7ee506a..24128385b 100644 --- a/crates/torin/src/values/mod.rs +++ b/crates/torin/src/values/mod.rs @@ -1,13 +1,11 @@ pub mod alignment; pub mod direction; -pub mod display; pub mod gaps; pub mod size; pub mod prelude { pub use crate::alignment::*; pub use crate::direction::*; - pub use crate::display::*; pub use crate::gaps::*; pub use crate::size::*; } diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index a0efbf200..fb2f661eb 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -720,10 +720,11 @@ pub fn display_horizontal() { 0, None, vec![1], - Node::from_size_and_display_and_direction( + Node::from_size_and_alignments_and_direction( Size::Pixels(Length::new(200.0)), Size::Pixels(Length::new(200.0)), - DisplayMode::Center, + Alignment::Center, + Alignment::Center, DirectionMode::Horizontal, ), ); @@ -752,7 +753,7 @@ pub fn display_horizontal() { assert_eq!( layout.get(1).unwrap().area, - Rect::new(Point2D::new(50.0, 0.0), Size2D::new(100.0, 100.0)), + Rect::new(Point2D::new(50.0, 50.0), Size2D::new(100.0, 100.0)), ); } @@ -765,10 +766,11 @@ pub fn display_vertical_with_inner_children() { 0, None, vec![1], - Node::from_size_and_display_and_direction( + Node::from_size_and_alignments_and_direction( Size::Pixels(Length::new(200.0)), Size::Pixels(Length::new(200.0)), - DisplayMode::Center, + Alignment::Center, + Alignment::Center, DirectionMode::Vertical, ), ); @@ -808,12 +810,12 @@ pub fn display_vertical_with_inner_children() { assert_eq!( layout.get(1).unwrap().area, - Rect::new(Point2D::new(0.0, 50.0), Size2D::new(100.0, 100.0)), + Rect::new(Point2D::new(50.0, 50.0), Size2D::new(100.0, 100.0)), ); assert_eq!( layout.get(2).unwrap().area, - Rect::new(Point2D::new(5.0, 55.0), Size2D::new(90.0, 90.0)), + Rect::new(Point2D::new(55.0, 55.0), Size2D::new(90.0, 90.0)), ); } @@ -826,10 +828,9 @@ pub fn deep_tree() { 0, None, vec![1], - Node::from_size_and_display_and_direction( + Node::from_size_and_direction( Size::Pixels(Length::new(200.0)), Size::Pixels(Length::new(200.0)), - DisplayMode::Center, DirectionMode::Vertical, ), ); diff --git a/examples/animation.rs b/examples/animation.rs index b43a01106..ed1d3608d 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -33,13 +33,12 @@ fn app(cx: Scope) -> Element { rect { overflow: "clip", background: "black", - direction: "both", width: "100%", height: "100%", offset_x: "{progress}", rect { - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", height: "100%", width: "200", rect { @@ -48,8 +47,8 @@ fn app(cx: Scope) -> Element { background: "rgb(100, 100, 100)", padding: "25", corner_radius: "100", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", onclick: anim, label { font_size: "30", diff --git a/examples/drag.rs b/examples/drag.rs index 3466d2f52..90011468e 100644 --- a/examples/drag.rs +++ b/examples/drag.rs @@ -54,7 +54,6 @@ fn app(cx: Scope) -> Element { rect { overflow: "clip", background: "rgb(255, 166, 0)", - direction: "both", width: "100", height: "100", corner_radius: "15", diff --git a/examples/frameless_window.rs b/examples/frameless_window.rs index 3f3d40e8e..7417d6c7e 100644 --- a/examples/frameless_window.rs +++ b/examples/frameless_window.rs @@ -23,8 +23,8 @@ fn app(cx: Scope) -> Element { rect { background: "white", padding: "10", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", width: "100%", height: "100%", corner_radius: "15", diff --git a/examples/i18n.rs b/examples/i18n.rs index 1e7a01816..5b5907193 100644 --- a/examples/i18n.rs +++ b/examples/i18n.rs @@ -26,8 +26,8 @@ fn Body(cx: Scope) -> Element { render!( rect { - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", width: "100%", height: "100%", rect { diff --git a/examples/image.rs b/examples/image.rs index 86bfbafb4..1b4b4c7e4 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -29,8 +29,8 @@ fn app(cx: Scope) -> Element { width: "100%", height: "100%", padding: "50", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", onwheel: onwheel, image { image_data: image_data, diff --git a/examples/material_design_app.rs b/examples/material_design_app.rs index 48109d559..d6e9a20c3 100644 --- a/examples/material_design_app.rs +++ b/examples/material_design_app.rs @@ -53,8 +53,8 @@ fn FloatingButton<'a>(cx: Scope<'a, FloatingButtonProps<'a>>) -> Element<'a> { rect { height: "100%", width: "100%", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", height: "50", width: "50", background: "rgb(104, 24, 245)", diff --git a/examples/mouse_trace.rs b/examples/mouse_trace.rs index 27c54a25f..55c3c6a47 100644 --- a/examples/mouse_trace.rs +++ b/examples/mouse_trace.rs @@ -24,15 +24,15 @@ fn Box(cx: Scope) -> Element { background: "rgb(65, 53, 67)", width: "250", height: "250", - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", corner_radius: "100", rect { background: "rgb(143, 67, 238)", width: "180", height: "180", - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", corner_radius: "100", rect { background: "rgb(240, 235, 141)", diff --git a/examples/rotate.rs b/examples/rotate.rs index d9f5a0289..c0a470cd8 100644 --- a/examples/rotate.rs +++ b/examples/rotate.rs @@ -49,8 +49,8 @@ fn app(cx: Scope) -> Element { render!( rect { - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", width: "100%", height: "100%", rect { @@ -58,15 +58,15 @@ fn app(cx: Scope) -> Element { background: "rgb(65, 53, 67)", width: "250", height: "250", - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", rect { rotate: "{degrees.1}deg", background: "rgb(143, 67, 238)", width: "180", height: "180", - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", rect { rotate: "{degrees.2}deg", background: "rgb(240, 235, 141)", diff --git a/examples/sidebar.rs b/examples/sidebar.rs index 55d6b41ef..2dec6bef0 100644 --- a/examples/sidebar.rs +++ b/examples/sidebar.rs @@ -92,7 +92,6 @@ fn SidebarItem<'a>( onmouseleave: onmouseleave, width: "100%", height: "auto", - direction: "both", color: "{color}", shadow: "0 2 10 1 rgb(0, 0, 0, 45)", corner_radius: "10", diff --git a/examples/text.rs b/examples/text.rs index 5fb1a8b8c..87df9d6f1 100644 --- a/examples/text.rs +++ b/examples/text.rs @@ -46,7 +46,6 @@ fn app(cx: Scope) -> Element { height: "calc(100% - 60)", rect { background: "red", - direction: "both", label { font_size: "{font_size}", font_family: "Inter", diff --git a/examples/tic_tac_toe.rs b/examples/tic_tac_toe.rs index 296e07b6d..b87c795ba 100644 --- a/examples/tic_tac_toe.rs +++ b/examples/tic_tac_toe.rs @@ -160,8 +160,8 @@ fn app(cx: Scope) -> Element { rect { width: "100%", height: "100%", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", rect { width: "150", height: "170", @@ -184,8 +184,8 @@ fn app(cx: Scope) -> Element { corner_radius: "6", border: "2 solid rgb(40, 40, 40)", background: "rgb(250, 250, 250)", - display: "center", - direction: "both", + main_alignment: "center", + cross_alignment: "center", onclick: move |_| { let mut board = board.write(); if board.winner.is_none(){ diff --git a/examples/touch.rs b/examples/touch.rs index cac7372ba..22dd567ae 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -32,8 +32,8 @@ fn app(cx: Scope) -> Element { rect { width: "100%", height: "100%", - direction: "both", - display: "center", + main_alignment: "center", + cross_alignment: "center", background: "rgb(35, 35, 35)", ontouchcancel: ontouchcancel, ontouchend: ontouchend, From 2cfc46af7931e2510d0f45cfcfc17be2a8066191 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 15 Oct 2023 10:33:59 +0200 Subject: [PATCH 05/26] feat: Updated examples --- examples/alignment.rs | 34 ++++++++++++++---- examples/cloned_editor.rs | 4 +-- examples/custom_font.rs | 3 +- examples/editor.rs | 63 +++++++++------------------------ examples/gesture_area.rs | 2 +- examples/material_design_app.rs | 2 +- examples/paragraph.rs | 3 +- examples/transition.rs | 4 +-- 8 files changed, 53 insertions(+), 62 deletions(-) diff --git a/examples/alignment.rs b/examples/alignment.rs index 7d71a097f..f1264b9f7 100644 --- a/examples/alignment.rs +++ b/examples/alignment.rs @@ -17,18 +17,20 @@ fn app(cx: Scope) -> Element { cross_alignment: "end", main_alignment: "end", rect { - width: "300", - height: "300", + width: "65%", + height: "65%", background: "yellow", main_alignment: "start", cross_alignment: "start", + overflow: "clip", rect { main_alignment: "end", cross_alignment: "center", background: "red", direction: "horizontal", - width: "150", - height: "150", + width: "50%%", + height: "50%", + overflow: "clip", rect { width: "50", height: "50", @@ -40,8 +42,28 @@ fn app(cx: Scope) -> Element { background: "orange" } } - label { - "🦀🦀🦀🦀🦀🦀" + rect { + cross_alignment: "end", + width: "100%%", + height: "50%", + rect { + main_alignment: "end", + cross_alignment: "center", + width: "50%", + height: "100%", + label { + "Some crabs" + } + label { + "🦀🦀" + } + label { + "Even more crabs" + } + label { + "🦀🦀🦀🦀🦀" + } + } } } label { diff --git a/examples/cloned_editor.rs b/examples/cloned_editor.rs index e1cab0b05..420bd7ae7 100644 --- a/examples/cloned_editor.rs +++ b/examples/cloned_editor.rs @@ -112,7 +112,7 @@ fn Body(cx: Scope) -> Element { rect { width: "30", height: "100%", - display: "center", + main_alignment: "center", direction: "horizontal", label { font_size: "15", @@ -196,7 +196,7 @@ fn Body(cx: Scope) -> Element { rect { width: "30", height: "100%", - display: "center", + main_alignment: "center", direction: "horizontal", label { font_size: "15", diff --git a/examples/custom_font.rs b/examples/custom_font.rs index d0b28fc0f..9d0d73970 100644 --- a/examples/custom_font.rs +++ b/examples/custom_font.rs @@ -21,7 +21,8 @@ fn main() { fn app(cx: Scope) -> Element { render!( rect { - display: "center", + main_alignment: "center", + cross_alignment: "center", height: "100%", width: "100%", label { diff --git a/examples/editor.rs b/examples/editor.rs index ef7428b2b..bebb96c10 100644 --- a/examples/editor.rs +++ b/examples/editor.rs @@ -70,7 +70,7 @@ fn Body(cx: Scope) -> Element { height: "100%", width: "100%", direction: "horizontal", - padding: "5", + cross_alignment: "center", label { font_size: "30", "Editor" @@ -79,9 +79,8 @@ fn Body(cx: Scope) -> Element { width: "20", } rect { - height: "40%", - display: "center", width: "130", + cross_alignment: "center", Slider { width: 100.0, value: *font_size_percentage.get(), @@ -89,21 +88,13 @@ fn Body(cx: Scope) -> Element { font_size_percentage.set(p); } } - rect { - height: "auto", - width: "100%", - display: "center", - direction: "horizontal", - label { - "Font size" - } + label { + "Font size" } } rect { - height: "40%", - display: "center", - direction: "vertical", width: "130", + cross_alignment: "center", Slider { width: 100.0, value: *line_height_percentage.get(), @@ -111,56 +102,34 @@ fn Body(cx: Scope) -> Element { line_height_percentage.set(p); } } - rect { - height: "auto", - width: "100%", - display: "center", - direction: "horizontal", - label { - "Line height" - } + label { + "Line height" } } rect { - height: "40%", - display: "center", - direction: "vertical", - width: "60", + width: "80", + cross_alignment: "center", Switch { enabled: *is_bold.get(), ontoggled: |_| { is_bold.set(!is_bold.get()); } } - rect { - height: "auto", - width: "100%", - display: "center", - direction: "horizontal", - label { - "Bold" - } + label { + "Bold" } } rect { - height: "40%", - display: "center", - direction: "vertical", - width: "60", + width: "80", + cross_alignment: "center", Switch { enabled: *is_italic.get(), ontoggled: |_| { is_italic.set(!is_italic.get()); } } - rect { - height: "auto", - width: "100%", - display: "center", - direction: "horizontal", - label { - "Italic" - } + label { + "Italic" } } } @@ -238,7 +207,7 @@ fn Body(cx: Scope) -> Element { rect { width: "{font_size * 2.0}", height: "100%", - display: "center", + main_alignment: "center", direction: "horizontal", label { font_size: "{font_size}", diff --git a/examples/gesture_area.rs b/examples/gesture_area.rs index dee0e15f1..a744cd284 100644 --- a/examples/gesture_area.rs +++ b/examples/gesture_area.rs @@ -18,7 +18,7 @@ fn app(cx: Scope) -> Element { width: "100%", height: "100%", direction: "vertical", - display: "center", + main_alignment: "center", label { align: "center", width: "100%", diff --git a/examples/material_design_app.rs b/examples/material_design_app.rs index d6e9a20c3..a7e806e16 100644 --- a/examples/material_design_app.rs +++ b/examples/material_design_app.rs @@ -127,7 +127,7 @@ fn Navbar<'a>(cx: Scope<'a, NavbarProps<'a>>) -> Element<'a> { background: "rgb(104, 24, 245)", direction: "vertical", color: "white", - display: "center", + main_alignment: "center", rect { width: "100%", direction: "horizontal", diff --git a/examples/paragraph.rs b/examples/paragraph.rs index 217e3d146..e5fe0806c 100644 --- a/examples/paragraph.rs +++ b/examples/paragraph.rs @@ -17,8 +17,7 @@ fn app(cx: Scope) -> Element { color: "black", width: "100%", height: "100%", - display: "center", - direction: "horizontal", + cross_alignment: "center", rect { width: "50%", height: "100%", diff --git a/examples/transition.rs b/examples/transition.rs index d51dc16d2..11b3a3c8d 100644 --- a/examples/transition.rs +++ b/examples/transition.rs @@ -38,7 +38,7 @@ fn app(cx: Scope) -> Element { rect { overflow: "clip", background: "black", - display: "center", + main_alignment: "center", width: "100%", height: "100%", offset_x: "{size}", @@ -48,7 +48,7 @@ fn app(cx: Scope) -> Element { background: "{background}", padding: "25", corner_radius: "100", - display: "center", + main_alignment: "center", onclick: anim, label { width: "100%", From 736dda187ec5cf9ca18b51e2afbba226d1b1c119 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 15 Oct 2023 10:38:05 +0200 Subject: [PATCH 06/26] tests --- crates/torin/tests/test.rs | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index fb2f661eb..2ac053c51 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1114,3 +1114,119 @@ pub fn margin() { Rect::new(Point2D::new(5.0, 5.0), Size2D::new(200.0, 200.0)), ); } + +#[test] +pub fn double_center_alignment() { + let (mut layout, mut measurer) = test_utils(); + + let mut mocked_dom = TestingDOM::default(); + mocked_dom.add( + 0, + None, + vec![1], + Node::from_size_and_alignments_and_direction( + Size::Percentage(Length::new(100.0)), + Size::Percentage(Length::new(100.0)), + Alignment::Center, + Alignment::Center, + DirectionMode::Vertical, + ), + ); + mocked_dom.add( + 1, + Some(0), + vec![], + Node::from_size_and_direction( + Size::Pixels(Length::new(200.0)), + Size::Pixels(Length::new(200.0)), + DirectionMode::Vertical, + ), + ); + mocked_dom.add( + 2, + Some(0), + vec![], + Node::from_size_and_direction( + Size::Pixels(Length::new(300.0)), + Size::Pixels(Length::new(300.0)), + DirectionMode::Vertical, + ), + ); + + layout.measure( + 0, + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)), + &mut measurer, + &mut mocked_dom, + ); + + let node_areas = layout.get(1).unwrap(); + + assert_eq!( + node_areas.area, + Rect::new(Point2D::new(250.0, 250.0), Size2D::new(200.0, 200.0)), + ); + + assert_eq!( + node_areas.box_area(), + Rect::new(Point2D::new(450.0, 450.0), Size2D::new(300.0, 300.0)), + ); +} + +#[test] +pub fn double_end_alignment() { + let (mut layout, mut measurer) = test_utils(); + + let mut mocked_dom = TestingDOM::default(); + mocked_dom.add( + 0, + None, + vec![1], + Node::from_size_and_alignments_and_direction( + Size::Percentage(Length::new(100.0)), + Size::Percentage(Length::new(100.0)), + Alignment::End, + Alignment::End, + DirectionMode::Vertical, + ), + ); + mocked_dom.add( + 1, + Some(0), + vec![], + Node::from_size_and_direction( + Size::Pixels(Length::new(200.0)), + Size::Pixels(Length::new(200.0)), + DirectionMode::Vertical, + ), + ); + mocked_dom.add( + 2, + Some(0), + vec![], + Node::from_size_and_direction( + Size::Pixels(Length::new(300.0)), + Size::Pixels(Length::new(300.0)), + DirectionMode::Vertical, + ), + ); + + layout.measure( + 0, + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)), + &mut measurer, + &mut mocked_dom, + ); + + let node_areas = layout.get(1).unwrap(); + + assert_eq!( + node_areas.area, + Rect::new(Point2D::new(500.0, 500.0), Size2D::new(200.0, 200.0)), + ); + + assert_eq!( + node_areas.box_area(), + Rect::new(Point2D::new(700.0, 700.0), Size2D::new(300.0, 300.0)), + ); +} From da4a1a2f80681ec52cb60dbf90d25f5135bead70 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 15 Oct 2023 10:44:47 +0200 Subject: [PATCH 07/26] fixed tests --- crates/torin/tests/test.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index 2ac053c51..5be2300be 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1067,7 +1067,7 @@ pub fn margin() { mocked_dom.add( 0, None, - vec![1], + vec![1, 2], Node::from_size_and_direction( Size::Percentage(Length::new(100.0)), Size::Percentage(Length::new(100.0)), @@ -1123,7 +1123,7 @@ pub fn double_center_alignment() { mocked_dom.add( 0, None, - vec![1], + vec![1, 2], Node::from_size_and_alignments_and_direction( Size::Percentage(Length::new(100.0)), Size::Percentage(Length::new(100.0)), @@ -1160,16 +1160,14 @@ pub fn double_center_alignment() { &mut mocked_dom, ); - let node_areas = layout.get(1).unwrap(); - assert_eq!( - node_areas.area, - Rect::new(Point2D::new(250.0, 250.0), Size2D::new(200.0, 200.0)), + layout.get(1).unwrap().area, + Rect::new(Point2D::new(400.0, 250.0), Size2D::new(200.0, 200.0)), ); assert_eq!( - node_areas.box_area(), - Rect::new(Point2D::new(450.0, 450.0), Size2D::new(300.0, 300.0)), + layout.get(2).unwrap().area, + Rect::new(Point2D::new(350.0, 450.0), Size2D::new(300.0, 300.0)), ); } @@ -1181,7 +1179,7 @@ pub fn double_end_alignment() { mocked_dom.add( 0, None, - vec![1], + vec![1, 2], Node::from_size_and_alignments_and_direction( Size::Percentage(Length::new(100.0)), Size::Percentage(Length::new(100.0)), @@ -1218,15 +1216,13 @@ pub fn double_end_alignment() { &mut mocked_dom, ); - let node_areas = layout.get(1).unwrap(); - assert_eq!( - node_areas.area, - Rect::new(Point2D::new(500.0, 500.0), Size2D::new(200.0, 200.0)), + layout.get(1).unwrap().area, + Rect::new(Point2D::new(800.0, 500.0), Size2D::new(200.0, 200.0)), ); assert_eq!( - node_areas.box_area(), + layout.get(2).unwrap().area, Rect::new(Point2D::new(700.0, 700.0), Size2D::new(300.0, 300.0)), ); } From 3d49e1d93ff999ab01baa07221c1c95363451370 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Mon, 16 Oct 2023 23:46:58 +0200 Subject: [PATCH 08/26] update table component and example --- crates/components/src/table.rs | 3 ++- examples/table.rs | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/components/src/table.rs b/crates/components/src/table.rs index dee8fea24..701dd420e 100644 --- a/crates/components/src/table.rs +++ b/crates/components/src/table.rs @@ -154,7 +154,8 @@ pub fn TableCell<'a>(cx: Scope<'a, TableCellProps<'a>>) -> Element { overflow: "clip", padding: "5 25", width: "{width}%", - display: "center", + main_alignment: "center", + cross_alignment: "center", height: "35", align: "right", onclick: |e| { diff --git a/examples/table.rs b/examples/table.rs index 40acff1f4..929a0c5b9 100644 --- a/examples/table.rs +++ b/examples/table.rs @@ -100,8 +100,6 @@ fn app(cx: Scope) -> Element { order_direction: if *order.get() == *order_by { Some(*order_direction.get()) } else { None }, onclick: move |_| on_column_head_click(order_by), label { - width: "100%", - align: "center", "{text}" } } From bb1de2882236951d86a2cb29d98fdaa8ac45cd76 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Tue, 17 Oct 2023 23:26:28 +0200 Subject: [PATCH 09/26] clean up --- crates/torin/src/torin.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/torin/src/torin.rs b/crates/torin/src/torin.rs index 08b766e52..318f64185 100644 --- a/crates/torin/src/torin.rs +++ b/crates/torin/src/torin.rs @@ -577,6 +577,7 @@ fn measure_inner_nodes( let mut adapted_available_area = *available_area; + // If required, make a previous measure to adapt the position if measure_cross_axis { let (_, child_areas) = measure_node( child_id, @@ -701,13 +702,7 @@ fn measure_inner_nodes( } }; - // KEy concepts: - // When using special alignments elements are assumed that they will have the same size in first measure and the second one - - // Center display - - // TODO: Only clone when necessary (center or end) - + // If any of the alignments isn't "start", it needs to run a measurement to get the aligned position, before caching the value let has_special_alignments = node.main_alignment.is_not_start() || node.cross_alignment.is_not_start(); From 981fe9ad517f5f8277157fdb38abc1ed646b7921 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Tue, 17 Oct 2023 23:28:12 +0200 Subject: [PATCH 10/26] clean up --- crates/torin/src/node.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index a696a3d8c..d311a9fb5 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -113,7 +113,5 @@ impl Node { /// Has properties that depend on the inner Nodes? pub fn does_depend_on_inner(&self) -> bool { Size::Inner == self.width || Size::Inner == self.height || self.has_layout_references - // || self.main_alignment.is_not_start() - // || self.cross_alignment.is_not_start() } } From dcc3c57a3b49649ad9873db1ae581c6faf8ddb7f Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 19 Oct 2023 00:24:46 +0200 Subject: [PATCH 11/26] improvements --- crates/components/src/button.rs | 41 ++++++++++++++++---- crates/core/src/render.rs | 2 +- crates/hooks/src/use_theme.rs | 4 +- crates/renderer/src/app.rs | 2 +- crates/torin/src/dom_adapter.rs | 9 +---- crates/torin/src/geometry.rs | 21 ----------- crates/torin/src/node.rs | 6 ++- crates/torin/src/torin.rs | 66 +++++++++++++++++++++++++++------ crates/torin/src/values/size.rs | 19 ++++++---- examples/counter.rs | 33 +++++++++++------ 10 files changed, 130 insertions(+), 73 deletions(-) diff --git a/crates/components/src/button.rs b/crates/components/src/button.rs index 9c54e57e2..a061e0c8e 100644 --- a/crates/components/src/button.rs +++ b/crates/components/src/button.rs @@ -6,6 +6,21 @@ use freya_hooks::{use_focus, use_get_theme}; /// [`Button`] component properties. #[derive(Props)] pub struct ButtonProps<'a> { + /// Padding for the Button. + #[props(default = "10".to_string(), into)] + pub padding: String, + /// Margin for the Button. + #[props(default = "4".to_string(), into)] + pub margin: String, + /// Corner radius for the Button. + #[props(default = "10".to_string(), into)] + pub corner_radius: String, + /// Width size for the Button. + #[props(default = "auto".to_string(), into)] + pub width: String, + /// Inner children for the Button. + #[props(default = "auto".to_string(), into)] + pub height: String, /// Inner children for the Button. pub children: Element<'a>, /// Handler for the `onclick` event. @@ -75,24 +90,36 @@ pub fn Button<'a>(cx: Scope<'a, ButtonProps<'a>>) -> Element { ButtonStatus::Idle => theme.button.background, }; let color = theme.button.font_theme.color; + let ButtonProps { + width, + height, + corner_radius, + padding, + margin, + .. + } = &cx.props; render!( rect { - overflow: "clip", - margin: "2", onclick: onclick, onmouseenter: onmouseenter, onmouseleave: onmouseleave, focus_id: focus_id, + width: "{width}", + height: "{height}", + padding: "{padding}", + margin: "{margin}", focusable: "true", + overflow: "clip", role: "button", - width: "auto", - height: "auto", color: "{color}", - shadow: "0 2 10 1 rgb(0, 0, 0, 45)", - corner_radius: "5", - padding: "8", + shadow: "0 4 5 0 rgb(0, 0, 0, 30)", + border: "1 solid rgb(210, 210, 210)", + corner_radius: "{corner_radius}", background: "{background}", + align: "center", + main_alignment: "center", + cross_alignment: "center", &cx.props.children } ) diff --git a/crates/core/src/render.rs b/crates/core/src/render.rs index dc4501b95..d45421e7e 100644 --- a/crates/core/src/render.rs +++ b/crates/core/src/render.rs @@ -52,7 +52,7 @@ pub fn process_render( render_hook( dom, node_id, - &areas.box_area(), + &areas.area, font_collection, viewports_collection, hook_options, diff --git a/crates/hooks/src/use_theme.rs b/crates/hooks/src/use_theme.rs index 310a7a0e3..8c797221a 100644 --- a/crates/hooks/src/use_theme.rs +++ b/crates/hooks/src/use_theme.rs @@ -174,8 +174,8 @@ pub const LIGHT_THEME: Theme = Theme { thumb_inner_background: "rgb(103, 80, 164)", }, button: ButtonTheme { - background: "rgb(220, 220, 220)", - hover_background: "rgb(200, 200, 200)", + background: "rgb(245, 245, 245)", + hover_background: "rgb(235, 235, 235)", font_theme: FontTheme { color: "rgb(10, 10, 10)", }, diff --git a/crates/renderer/src/app.rs b/crates/renderer/src/app.rs index 885b1b33c..5e731863b 100644 --- a/crates/renderer/src/app.rs +++ b/crates/renderer/src/app.rs @@ -91,7 +91,7 @@ impl App { } let mgr: FontMgr = provider.into(); - font_collection.set_default_font_manager(def_mgr, "Fira Sans"); + font_collection.set_default_font_manager(def_mgr, "Inter"); font_collection.set_dynamic_font_manager(mgr); let (event_emitter, event_receiver) = mpsc::unbounded_channel::(); diff --git a/crates/torin/src/dom_adapter.rs b/crates/torin/src/dom_adapter.rs index 965a24c4d..bc705af66 100644 --- a/crates/torin/src/dom_adapter.rs +++ b/crates/torin/src/dom_adapter.rs @@ -3,7 +3,7 @@ pub use euclid::Rect; use crate::{ geometry::{Area, Size2D}, node::Node, - prelude::{BoxModel, Gaps}, + prelude::Gaps, }; /// Cached layout results of a Node @@ -22,13 +22,6 @@ pub struct NodeAreas { pub margin: Gaps, } -impl NodeAreas { - // The area without any outer gap (e.g margin) - pub fn box_area(&self) -> Area { - self.area.box_area(&self.margin) - } -} - pub trait NodeKey: Clone + PartialEq + Eq + std::hash::Hash + Copy + std::fmt::Debug {} impl NodeKey for usize {} diff --git a/crates/torin/src/geometry.rs b/crates/torin/src/geometry.rs index 98735c3b7..f554ae00a 100644 --- a/crates/torin/src/geometry.rs +++ b/crates/torin/src/geometry.rs @@ -1,5 +1,3 @@ -use crate::prelude::Gaps; - #[derive(PartialEq)] pub struct Measure; @@ -8,22 +6,3 @@ pub type Size2D = euclid::Size2D; pub type Point2D = euclid::Point2D; pub type CursorPoint = euclid::Point2D; pub type Length = euclid::Length; - -pub trait BoxModel { - // The area without any outer gap (e.g margin) - fn box_area(&self, margin: &Gaps) -> Area; -} - -impl BoxModel for Area { - fn box_area(&self, margin: &Gaps) -> Area { - let origin = self.origin; - let size = self.size; - Area::new( - Point2D::new(origin.x + margin.left(), origin.y + margin.top()), - Size2D::new( - size.width - margin.horizontal(), - size.height - margin.vertical(), - ), - ) - } -} diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index d311a9fb5..0483cbe3a 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -112,6 +112,10 @@ impl Node { /// Has properties that depend on the inner Nodes? pub fn does_depend_on_inner(&self) -> bool { - Size::Inner == self.width || Size::Inner == self.height || self.has_layout_references + Size::Inner == self.width + || Size::Inner == self.height + || self.has_layout_references + || self.cross_alignment.is_not_start() + || self.main_alignment.is_not_start() } } diff --git a/crates/torin/src/torin.rs b/crates/torin/src/torin.rs index 318f64185..ecedc7da7 100644 --- a/crates/torin/src/torin.rs +++ b/crates/torin/src/torin.rs @@ -10,7 +10,7 @@ use crate::{ dom_adapter::{DOMAdapter, NodeAreas, NodeKey}, geometry::{Area, Size2D}, node::Node, - prelude::{Alignment, BoxModel, Gaps}, + prelude::{Alignment, Gaps}, size::Size, }; @@ -341,9 +341,13 @@ fn measure_node( Size2D::new(horizontal_padding, vertical_padding), ); + area.origin.x += node.margin.left(); + area.origin.y += node.margin.top(); + area.size.width = node.width.min_max( area.size.width, parent_area.size.width, + node.margin.left(), node.margin.horizontal(), &node.minimum_width, &node.maximum_width, @@ -351,6 +355,7 @@ fn measure_node( area.size.height = node.height.min_max( area.size.height, parent_area.size.height, + node.margin.top(), node.margin.vertical(), &node.minimum_height, &node.maximum_height, @@ -365,6 +370,7 @@ fn measure_node( area.size.width = node.width.min_max( new_area.width(), parent_area.size.width, + node.margin.left(), node.margin.horizontal(), &node.minimum_width, &node.maximum_width, @@ -374,6 +380,7 @@ fn measure_node( area.size.height = node.height.min_max( new_area.height(), parent_area.size.height, + node.margin.top(), node.margin.vertical(), &node.minimum_height, &node.maximum_height, @@ -389,7 +396,7 @@ fn measure_node( // Node's inner area let mut inner_area = { - let mut inner_area = area.box_area(&node.margin); + let mut inner_area = area; if Size::Inner == node.width { inner_area.size.width = available_parent_area.width() } @@ -734,19 +741,54 @@ fn measure_inner_nodes( } _ => {} }, - DirectionMode::Vertical => match node.main_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_y = (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); + DirectionMode::Vertical => { + // If the height is auto, we set the inner area to the parent area + // TODO: CLEAN THIS UP LOL + if Size::Inner == node.height && node.main_alignment.is_not_start() { + if let MeasureMode::ParentIsNotCached { + area, + inner_area, + vertical_padding, + .. + } = &mut alignment_mode + { + inner_area.origin.y = area.origin.y + node.padding.top(); + inner_area.size.height = area.size.height - *vertical_padding; + available_area.size.height = inner_area.size.height; + } + } - available_area.origin.y = inner_area.min_y() + new_origin_y; + // If the width is auto, we set the inner area to the parent area + // TODO: CLEAN THIS UP LOL + if Size::Inner == node.width && node.cross_alignment.is_not_start() { + if let MeasureMode::ParentIsNotCached { + area, + inner_area, + horizontal_padding, + .. + } = &mut alignment_mode + { + inner_area.origin.x = area.origin.x + node.padding.left(); + inner_area.size.width = area.size.width - *horizontal_padding; + available_area.size.width = inner_area.size.width; + } } - Alignment::End => { - let inner_area = alignment_mode.inner_area(); - available_area.origin.y = inner_area.max_y() - inner_sizes.height; + + match node.main_alignment { + Alignment::Center => { + let inner_area = alignment_mode.inner_area(); + let new_origin_y = + (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); + + available_area.origin.y = inner_area.min_y() + new_origin_y; + } + Alignment::End => { + let inner_area = alignment_mode.inner_area(); + available_area.origin.y = inner_area.max_y() - inner_sizes.height; + } + _ => {} } - _ => {} - }, + } } } } diff --git a/crates/torin/src/values/size.rs b/crates/torin/src/values/size.rs index 7e59fe483..d9148afd3 100644 --- a/crates/torin/src/values/size.rs +++ b/crates/torin/src/values/size.rs @@ -34,12 +34,12 @@ impl Size { } } - pub fn eval(&self, parent_value: f32) -> Option { + pub fn eval(&self, parent_value: f32, parent_margin: f32) -> Option { match self { Size::Pixels(px) => Some(px.get()), - Size::Percentage(per) => Some(parent_value / 100.0 * per.get()), + Size::Percentage(per) => Some((parent_value / 100.0 * per.get()) - parent_margin), Size::DynamicCalculations(calculations) => { - Some(run_calculations(calculations, parent_value)) + Some(run_calculations(calculations, parent_value, parent_margin)) } _ => None, } @@ -49,14 +49,17 @@ impl Size { &self, value: f32, parent_value: f32, + single_margin: f32, margin: f32, minimum: &Self, maximum: &Self, ) -> f32 { - let value = self.eval(parent_value).unwrap_or(value) + margin; + let value = self.eval(parent_value, margin).unwrap_or(value); - let minimum_value = minimum.eval(parent_value); - let maximum_value = maximum.eval(parent_value); + let minimum_value = minimum + .eval(parent_value, margin) + .map(|v| v + single_margin); + let maximum_value = maximum.eval(parent_value, margin); let mut final_value = value; @@ -121,7 +124,7 @@ impl std::fmt::Display for DynamicCalculation { /// Calculate some chained operations with a given value. /// This value could be for example the width of a node's parent area. -pub fn run_calculations(calcs: &[DynamicCalculation], value: f32) -> f32 { +pub fn run_calculations(calcs: &[DynamicCalculation], value: f32, parent_margin: f32) -> f32 { let mut prev_number: Option = None; let mut prev_op: Option = None; @@ -150,7 +153,7 @@ pub fn run_calculations(calcs: &[DynamicCalculation], value: f32) -> f32 { for calc in calcs { match calc { DynamicCalculation::Percentage(per) => { - let val = (value / 100.0 * per).round(); + let val = (value / 100.0 * per).round() - parent_margin; calc_with_op(val, prev_op); diff --git a/examples/counter.rs b/examples/counter.rs index fa7d24dfd..80e2797cd 100644 --- a/examples/counter.rs +++ b/examples/counter.rs @@ -14,24 +14,33 @@ fn app(cx: Scope) -> Element { render!( rect { - height: "20%", + height: "50%", width: "100%", - background: "rgb(233, 196, 106)", - padding: "12", - color: "rgb(20, 33, 61)", + main_alignment: "center", + cross_alignment: "center", + background: "rgb(0, 119, 182)", + color: "white", + shadow: "0 4 20 5 rgb(0, 0, 0, 80)", label { - font_size: "20", - "Number is: {count}" + font_size: "75", + font_weight: "bold", + "{count}" } } rect { - height: "80%", + height: "50%", width: "100%", - background: "rgb(168, 218, 220)", - color: "black", - padding: "12", - onclick: move |_| count += 1, - label { "Click to increase!" } + main_alignment: "center", + cross_alignment: "center", + direction: "horizontal", + Button { + onclick: move |_| count += 1, + label { "Increase" } + } + Button { + onclick: move |_| count -= 1, + label { "Decrease" } + } } ) } From 60e0ebfe7de03ef230d0b8cb770755c9841ed529 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 19 Oct 2023 19:32:33 +0200 Subject: [PATCH 12/26] improvements --- crates/components/src/button.rs | 5 +- crates/hooks/src/use_theme.rs | 5 +- crates/torin/src/geometry.rs | 78 +++++ crates/torin/src/lib.rs | 2 + crates/torin/src/measure.rs | 290 ++++++++++++++++++ crates/torin/src/measure_mode.rs | 222 ++++++++++++++ crates/torin/src/torin.rs | 491 +------------------------------ crates/torin/tests/test.rs | 2 +- examples/alignment.rs | 4 +- examples/app_dog.rs | 12 +- examples/canvas.rs | 29 +- examples/custom_theme.rs | 1 + 12 files changed, 622 insertions(+), 519 deletions(-) create mode 100644 crates/torin/src/measure.rs create mode 100644 crates/torin/src/measure_mode.rs diff --git a/crates/components/src/button.rs b/crates/components/src/button.rs index a061e0c8e..06c2701ac 100644 --- a/crates/components/src/button.rs +++ b/crates/components/src/button.rs @@ -7,7 +7,7 @@ use freya_hooks::{use_focus, use_get_theme}; #[derive(Props)] pub struct ButtonProps<'a> { /// Padding for the Button. - #[props(default = "10".to_string(), into)] + #[props(default = "10 14".to_string(), into)] pub padding: String, /// Margin for the Button. #[props(default = "4".to_string(), into)] @@ -90,6 +90,7 @@ pub fn Button<'a>(cx: Scope<'a, ButtonProps<'a>>) -> Element { ButtonStatus::Idle => theme.button.background, }; let color = theme.button.font_theme.color; + let border_fill = theme.button.border_fill; let ButtonProps { width, height, @@ -114,7 +115,7 @@ pub fn Button<'a>(cx: Scope<'a, ButtonProps<'a>>) -> Element { role: "button", color: "{color}", shadow: "0 4 5 0 rgb(0, 0, 0, 30)", - border: "1 solid rgb(210, 210, 210)", + border: "1 solid {border_fill}", corner_radius: "{corner_radius}", background: "{background}", align: "center", diff --git a/crates/hooks/src/use_theme.rs b/crates/hooks/src/use_theme.rs index 8c797221a..cf30d109a 100644 --- a/crates/hooks/src/use_theme.rs +++ b/crates/hooks/src/use_theme.rs @@ -49,6 +49,7 @@ pub struct ButtonTheme { pub background: &'static str, pub hover_background: &'static str, pub font_theme: FontTheme, + pub border_fill: &'static str, } /// Theming properties for Fonts. @@ -179,6 +180,7 @@ pub const LIGHT_THEME: Theme = Theme { font_theme: FontTheme { color: "rgb(10, 10, 10)", }, + border_fill: "rgb(210, 210, 210)", }, switch: SwitchTheme { background: "rgb(121, 116, 126)", @@ -252,8 +254,9 @@ pub const DARK_THEME: Theme = Theme { }, button: ButtonTheme { background: "rgb(35, 35, 35)", - hover_background: "rgb(80, 80, 80)", + hover_background: "rgb(45, 45, 45)", font_theme: FontTheme { color: "white" }, + border_fill: "rgb(80, 80, 80)", }, switch: SwitchTheme { background: "rgb(60, 60, 60)", diff --git a/crates/torin/src/geometry.rs b/crates/torin/src/geometry.rs index f554ae00a..7b3e0bd36 100644 --- a/crates/torin/src/geometry.rs +++ b/crates/torin/src/geometry.rs @@ -1,3 +1,5 @@ +use crate::prelude::{Alignment, DirectionMode}; + #[derive(PartialEq)] pub struct Measure; @@ -6,3 +8,79 @@ pub type Size2D = euclid::Size2D; pub type Point2D = euclid::Point2D; pub type CursorPoint = euclid::Point2D; pub type Length = euclid::Length; + +pub trait AreaModel { + fn align_content( + &mut self, + available_area: &Area, + contents_area: &Size2D, + alignment: &Alignment, + direction: &DirectionMode, + alignment_direction: AlignmentDirection, + ); +} + +impl AreaModel for Area { + fn align_content( + &mut self, + available_area: &Area, + contents_size: &Size2D, + alignment: &Alignment, + direction: &DirectionMode, + alignment_direction: AlignmentDirection, + ) { + let axis = get_align_axis(direction, alignment_direction); + + match axis { + AlignAxis::Height => match alignment { + Alignment::Center => { + let new_origin_y = + (available_area.height() / 2.0) - (contents_size.height / 2.0); + + self.origin.y = available_area.min_y() + new_origin_y; + } + Alignment::End => { + self.origin.y = available_area.max_y() - contents_size.height; + } + _ => {} + }, + AlignAxis::Width => match alignment { + Alignment::Center => { + let new_origin_x = (available_area.width() / 2.0) - (contents_size.width / 2.0); + + self.origin.x = available_area.min_x() + new_origin_x; + } + Alignment::End => { + self.origin.x = available_area.max_x() - contents_size.width; + } + _ => {} + }, + } + } +} + +pub fn get_align_axis( + direction: &DirectionMode, + alignment_direction: AlignmentDirection, +) -> AlignAxis { + match direction { + DirectionMode::Vertical => match alignment_direction { + AlignmentDirection::Main => AlignAxis::Height, + AlignmentDirection::Cross => AlignAxis::Width, + }, + DirectionMode::Horizontal => match alignment_direction { + AlignmentDirection::Main => AlignAxis::Width, + AlignmentDirection::Cross => AlignAxis::Height, + }, + } +} + +pub enum AlignmentDirection { + Main, + Cross, +} + +pub enum AlignAxis { + Height, + Width, +} diff --git a/crates/torin/src/lib.rs b/crates/torin/src/lib.rs index cd26c9db1..688e9ccc5 100644 --- a/crates/torin/src/lib.rs +++ b/crates/torin/src/lib.rs @@ -1,6 +1,8 @@ pub mod custom_measurer; pub mod dom_adapter; pub mod geometry; +mod measure; +mod measure_mode; pub mod node; pub mod scaled; pub mod torin; diff --git a/crates/torin/src/measure.rs b/crates/torin/src/measure.rs new file mode 100644 index 000000000..f1ded169a --- /dev/null +++ b/crates/torin/src/measure.rs @@ -0,0 +1,290 @@ +pub use euclid::Rect; + +use crate::{ + custom_measurer::LayoutMeasurer, + dom_adapter::{DOMAdapter, NodeAreas, NodeKey}, + geometry::{Area, Size2D}, + measure_mode::MeasureMode, + node::Node, + prelude::{AlignmentDirection, AreaModel, Torin}, + size::Size, +}; + +/// Measure this node and all it's children +/// The caller of this function is responsible of caching the Node's layout results +#[allow(clippy::too_many_arguments)] +#[inline(always)] +pub fn measure_node( + node_id: Key, + node: &Node, + layout: &mut Torin, + parent_area: &Area, + available_parent_area: &Area, + measurer: &mut Option>, + must_cache: bool, + dom_adapter: &mut impl DOMAdapter, +) -> (bool, NodeAreas) { + let must_run = layout.dirty.contains(&node_id) || layout.results.get(&node_id).is_none(); + if must_run { + let horizontal_padding = node.padding.horizontal(); + let vertical_padding = node.padding.vertical(); + + let mut area = Rect::new( + available_parent_area.origin, + Size2D::new(horizontal_padding, vertical_padding), + ); + + area.origin.x += node.margin.left(); + area.origin.y += node.margin.top(); + + area.size.width = node.width.min_max( + area.size.width, + parent_area.size.width, + node.margin.left(), + node.margin.horizontal(), + &node.minimum_width, + &node.maximum_width, + ); + area.size.height = node.height.min_max( + area.size.height, + parent_area.size.height, + node.margin.top(), + node.margin.vertical(), + &node.minimum_height, + &node.maximum_height, + ); + + // Custom measure + let skip_inner = if let Some(measurer) = measurer { + let custom_measure = + measurer.measure(node_id, node, &area, parent_area, available_parent_area); + if let Some(new_area) = custom_measure { + if Size::Inner == node.width { + area.size.width = node.width.min_max( + new_area.width(), + parent_area.size.width, + node.margin.left(), + node.margin.horizontal(), + &node.minimum_width, + &node.maximum_width, + ); + } + if Size::Inner == node.height { + area.size.height = node.height.min_max( + new_area.height(), + parent_area.size.height, + node.margin.top(), + node.margin.vertical(), + &node.minimum_height, + &node.maximum_height, + ); + } + } + custom_measure.is_some() + } else { + false + }; + + let mut inner_sizes = Size2D::default(); + + // Node's inner area + let mut inner_area = { + let mut inner_area = area; + if Size::Inner == node.width { + inner_area.size.width = available_parent_area.width() + } + if Size::Inner == node.height { + inner_area.size.height = available_parent_area.height() + } + inner_area + }; + + // Apply padding + inner_area.origin.x += node.padding.left(); + inner_area.origin.y += node.padding.top(); + inner_area.size.width -= horizontal_padding; + inner_area.size.height -= vertical_padding; + + // Node's available inner area + let mut available_area = inner_area; + + // Apply scroll + available_area.origin.x += node.offset_x.get(); + available_area.origin.y += node.offset_y.get(); + + let mut measurement_mode = MeasureMode::ParentIsNotCached { + area: &mut area, + inner_area: &mut inner_area, + vertical_padding, + horizontal_padding, + }; + + if !skip_inner { + measure_inner_nodes( + &node_id, + node, + layout, + &mut available_area, + &mut inner_sizes, + measurer, + must_cache, + &mut measurement_mode, + dom_adapter, + ); + } + + ( + must_cache, + NodeAreas { + area, + margin: node.margin, + inner_area, + inner_sizes, + }, + ) + } else { + let areas = layout.get(node_id).unwrap().clone(); + + let mut inner_sizes = areas.inner_sizes; + let mut available_area = areas.inner_area; + + available_area.origin.x += node.offset_x.get(); + available_area.origin.y += node.offset_y.get(); + + let mut measurement_mode = MeasureMode::ParentIsCached { + inner_area: &areas.inner_area, + }; + + measure_inner_nodes( + &node_id, + node, + layout, + &mut available_area, + &mut inner_sizes, + measurer, + must_cache, + &mut measurement_mode, + dom_adapter, + ); + + (false, areas) + } +} + +/// Measure the inner Nodes of a Node +#[allow(clippy::too_many_arguments)] +#[inline(always)] +pub fn measure_inner_nodes( + node_id: &Key, + node: &Node, + layout: &mut Torin, + available_area: &mut Area, + inner_sizes: &mut Size2D, + measurer: &mut Option>, + must_cache: bool, + mode: &mut MeasureMode, + dom_adapter: &mut impl DOMAdapter, +) { + let mut measure_children = |mode: &mut MeasureMode, + available_area: &mut Area, + inner_sizes: &mut Size2D, + must_cache: bool| { + let children = dom_adapter.children_of(node_id); + + for child_id in children { + let inner_area = *mode.inner_area(); + + let child_data = dom_adapter.get_node(&child_id).unwrap(); + + let mut adapted_available_area = *available_area; + + if node.cross_alignment.is_not_start() { + // 1. First measure: Cross axis is not aligned + let (_, child_areas) = measure_node( + child_id, + &child_data, + layout, + &inner_area, + available_area, + measurer, + false, + dom_adapter, + ); + + // 2. Align the Cross axis + adapted_available_area.align_content( + available_area, + &child_areas.area.size, + &node.cross_alignment, + &node.direction, + AlignmentDirection::Cross, + ); + } + + // 3. Second measure + let (child_revalidated, child_areas) = measure_node( + child_id, + &child_data, + layout, + &inner_area, + &adapted_available_area, + measurer, + must_cache, + dom_adapter, + ); + + // Stack the child node + mode.stack_node(node, available_area, &child_areas.area, inner_sizes); + + if child_revalidated && must_cache { + layout.cache_node(child_id, child_areas); + } + } + }; + + { + let mut alignment_mode = mode.to_owned(); + let mut alignment_mode = alignment_mode.to_mut(); + let mut inner_sizes = *inner_sizes; + + if node.main_alignment.is_not_start() || node.cross_alignment.is_not_start() { + // 1. First measure: Main axis is not aligned + measure_children( + &mut alignment_mode, + &mut available_area.clone(), + &mut inner_sizes, + false, + ); + } + + if node.cross_alignment.is_not_start() { + // 2. Adjust the available and inner areas of the Cross axis + alignment_mode.fit_bounds_when_unspecified_and_aligned( + node, + AlignmentDirection::Cross, + available_area, + ); + } + + if node.main_alignment.is_not_start() { + // 3. Adjust the available and inner areas of the Main axis + alignment_mode.fit_bounds_when_unspecified_and_aligned( + node, + AlignmentDirection::Main, + available_area, + ); + + // 4. Align the Main axis + available_area.align_content( + alignment_mode.inner_area(), + &inner_sizes, + &node.main_alignment, + &node.direction, + AlignmentDirection::Main, + ); + } + } + + // 5. Second measure + measure_children(mode, available_area, inner_sizes, must_cache); +} diff --git a/crates/torin/src/measure_mode.rs b/crates/torin/src/measure_mode.rs new file mode 100644 index 000000000..94dbbd1e1 --- /dev/null +++ b/crates/torin/src/measure_mode.rs @@ -0,0 +1,222 @@ +use crate::prelude::{ + get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Node, Size, Size2D, +}; + +/// Measurement data for the inner Nodes of a Node +#[derive(Debug)] +pub enum MeasureMode<'a> { + ParentIsCached { + inner_area: &'a Area, + }, + ParentIsNotCached { + area: &'a mut Area, + inner_area: &'a mut Area, + vertical_padding: f32, + horizontal_padding: f32, + }, +} + +impl<'a> MeasureMode<'a> { + /// Get a reference to the inner area + pub fn inner_area(&'a self) -> &'a Area { + match self { + Self::ParentIsCached { inner_area } => inner_area, + Self::ParentIsNotCached { inner_area, .. } => inner_area, + } + } + + pub fn to_owned(&self) -> OwnedMeasureMode { + match self { + MeasureMode::ParentIsCached { inner_area } => OwnedMeasureMode::ParentIsCached { + inner_area: *inner_area.to_owned(), + }, + MeasureMode::ParentIsNotCached { + area, + inner_area, + vertical_padding, + horizontal_padding, + } => OwnedMeasureMode::ParentIsNotCached { + area: **area.clone(), + inner_area: **inner_area.clone(), + vertical_padding: *vertical_padding, + horizontal_padding: *horizontal_padding, + }, + } + } + + /// This will fit the available area and inner area of a parent node when for example height is set to "auto", + /// direction is vertical and main_alignment is set to "center" or "end". + /// The intended usage is to call this after the first measurement and before the second, + /// this way the second measurement will align the content relatively to the parent element instead + /// of overflowing due to being aligned relatively to the upper parent element + pub fn fit_bounds_when_unspecified_and_aligned( + &mut self, + node: &Node, + alignment_direction: AlignmentDirection, + available_area: &mut Area, + ) { + let axis = get_align_axis(&node.direction, alignment_direction); + let (is_vertical_not_start, is_horizontal_not_start) = match node.direction { + DirectionMode::Vertical => ( + node.main_alignment.is_not_start(), + node.cross_alignment.is_not_start(), + ), + DirectionMode::Horizontal => ( + node.cross_alignment.is_not_start(), + node.main_alignment.is_not_start(), + ), + }; + let params = if let MeasureMode::ParentIsNotCached { + area, + inner_area, + horizontal_padding, + vertical_padding, + } = self + { + match axis { + AlignAxis::Height if Size::Inner == node.height && is_vertical_not_start => Some(( + &mut inner_area.origin.y, + &mut inner_area.size.height, + &mut area.origin.y, + &mut area.size.height, + node.padding.top(), + *vertical_padding, + &mut available_area.size.height, + )), + AlignAxis::Width if Size::Inner == node.width && is_horizontal_not_start => Some(( + &mut inner_area.origin.x, + &mut inner_area.size.width, + &mut area.origin.x, + &mut area.size.width, + node.padding.left(), + *horizontal_padding, + &mut available_area.size.width, + )), + _ => None, + } + } else { + None + }; + + if let Some(( + inner_origin, + inner_size, + area_origin, + area_size, + one_side_padding, + two_sides_padding, + available_size, + )) = params + { + *inner_origin = *area_origin + one_side_padding; + *inner_size = *area_size - two_sides_padding; + *available_size = *inner_size; + } + } + + /// Stack a Node into another Node + pub fn stack_node( + &mut self, + node: &Node, + available_area: &mut Area, + content_area: &Area, + inner_sizes: &mut Size2D, + ) { + match node.direction { + DirectionMode::Horizontal => { + // Move the available area + available_area.origin.x = content_area.max_x(); + available_area.size.width -= content_area.size.width; + + if let MeasureMode::ParentIsNotCached { + area, + vertical_padding, + inner_area, + .. + } = self + { + inner_sizes.height = content_area.height().max(inner_sizes.height); + inner_sizes.width += content_area.width(); + + // Keep the biggest height + if node.height == Size::Inner { + area.size.height = area + .size + .height + .max(content_area.size.height + *vertical_padding); + // Keep the inner area in sync + inner_area.size.height = area.size.height - *vertical_padding; + } + + // Accumulate width + if node.width == Size::Inner { + area.size.width += content_area.size.width; + } + } + } + DirectionMode::Vertical => { + // Move the available area + available_area.origin.y = content_area.max_y(); + available_area.size.height -= content_area.size.height; + + if let MeasureMode::ParentIsNotCached { + area, + horizontal_padding, + inner_area, + .. + } = self + { + inner_sizes.width = content_area.width().max(inner_sizes.width); + inner_sizes.height += content_area.height(); + + // Keep the biggest width + if node.width == Size::Inner { + area.size.width = area + .size + .width + .max(content_area.size.width + *horizontal_padding); + // Keep the inner area in sync + inner_area.size.width = area.size.width - *horizontal_padding; + } + + // Accumulate height + if node.height == Size::Inner { + area.size.height += content_area.size.height; + } + } + } + } + } +} + +#[derive(Debug)] +pub enum OwnedMeasureMode { + ParentIsCached { + inner_area: Area, + }, + ParentIsNotCached { + area: Area, + inner_area: Area, + vertical_padding: f32, + horizontal_padding: f32, + }, +} + +impl OwnedMeasureMode { + pub fn to_mut(&mut self) -> MeasureMode<'_> { + match self { + Self::ParentIsCached { inner_area } => MeasureMode::ParentIsCached { inner_area }, + Self::ParentIsNotCached { + area, + inner_area, + vertical_padding, + horizontal_padding, + } => MeasureMode::ParentIsNotCached { + area, + inner_area, + vertical_padding: *vertical_padding, + horizontal_padding: *horizontal_padding, + }, + } + } +} diff --git a/crates/torin/src/torin.rs b/crates/torin/src/torin.rs index ecedc7da7..a3efc52dc 100644 --- a/crates/torin/src/torin.rs +++ b/crates/torin/src/torin.rs @@ -6,12 +6,10 @@ use tracing::info; use crate::{ custom_measurer::LayoutMeasurer, - direction::DirectionMode, dom_adapter::{DOMAdapter, NodeAreas, NodeKey}, geometry::{Area, Size2D}, - node::Node, - prelude::{Alignment, Gaps}, - size::Size, + measure::measure_node, + prelude::Gaps, }; /// Contains the best Root node candidate from where to start measuring @@ -316,488 +314,3 @@ impl Torin { self.results.insert(node_id, areas); } } - -/// Measure this node and all it's children -/// The caller of this function is responsible of caching the Node's layout results -#[allow(clippy::too_many_arguments)] -#[inline(always)] -fn measure_node( - node_id: Key, - node: &Node, - layout: &mut Torin, - parent_area: &Area, - available_parent_area: &Area, - measurer: &mut Option>, - must_cache: bool, - dom_adapter: &mut impl DOMAdapter, -) -> (bool, NodeAreas) { - let must_run = layout.dirty.contains(&node_id) || layout.results.get(&node_id).is_none(); - if must_run { - let horizontal_padding = node.padding.horizontal(); - let vertical_padding = node.padding.vertical(); - - let mut area = Rect::new( - available_parent_area.origin, - Size2D::new(horizontal_padding, vertical_padding), - ); - - area.origin.x += node.margin.left(); - area.origin.y += node.margin.top(); - - area.size.width = node.width.min_max( - area.size.width, - parent_area.size.width, - node.margin.left(), - node.margin.horizontal(), - &node.minimum_width, - &node.maximum_width, - ); - area.size.height = node.height.min_max( - area.size.height, - parent_area.size.height, - node.margin.top(), - node.margin.vertical(), - &node.minimum_height, - &node.maximum_height, - ); - - // Custom measure - let skip_inner = if let Some(measurer) = measurer { - let custom_measure = - measurer.measure(node_id, node, &area, parent_area, available_parent_area); - if let Some(new_area) = custom_measure { - if Size::Inner == node.width { - area.size.width = node.width.min_max( - new_area.width(), - parent_area.size.width, - node.margin.left(), - node.margin.horizontal(), - &node.minimum_width, - &node.maximum_width, - ); - } - if Size::Inner == node.height { - area.size.height = node.height.min_max( - new_area.height(), - parent_area.size.height, - node.margin.top(), - node.margin.vertical(), - &node.minimum_height, - &node.maximum_height, - ); - } - } - custom_measure.is_some() - } else { - false - }; - - let mut inner_sizes = Size2D::default(); - - // Node's inner area - let mut inner_area = { - let mut inner_area = area; - if Size::Inner == node.width { - inner_area.size.width = available_parent_area.width() - } - if Size::Inner == node.height { - inner_area.size.height = available_parent_area.height() - } - inner_area - }; - - // Apply padding - inner_area.origin.x += node.padding.left(); - inner_area.origin.y += node.padding.top(); - inner_area.size.width -= horizontal_padding; - inner_area.size.height -= vertical_padding; - - // Node's available inner area - let mut available_area = inner_area; - - // Apply scroll - available_area.origin.x += node.offset_x.get(); - available_area.origin.y += node.offset_y.get(); - - let mut measurement_mode = MeasureMode::ParentIsNotCached { - area: &mut area, - inner_area: &mut inner_area, - vertical_padding, - horizontal_padding, - }; - - if !skip_inner { - measure_inner_nodes( - &node_id, - node, - layout, - &mut available_area, - &mut inner_sizes, - measurer, - must_cache, - &mut measurement_mode, - dom_adapter, - ); - } - - ( - must_cache, - NodeAreas { - area, - margin: node.margin, - inner_area, - inner_sizes, - }, - ) - } else { - let areas = layout.get(node_id).unwrap().clone(); - - let mut inner_sizes = areas.inner_sizes; - let mut available_area = areas.inner_area; - - // TODO(marc2332): Should I also cache these? - available_area.origin.x += node.offset_x.get(); - available_area.origin.y += node.offset_y.get(); - - let mut measurement_mode = MeasureMode::ParentIsCached { - inner_area: &areas.inner_area, - }; - - measure_inner_nodes( - &node_id, - node, - layout, - &mut available_area, - &mut inner_sizes, - measurer, - must_cache, - &mut measurement_mode, - dom_adapter, - ); - - (false, areas) - } -} - -/// Measurement data for the inner Nodes of a Node -#[derive(Debug)] -enum MeasureMode<'a> { - ParentIsCached { - inner_area: &'a Area, - }, - ParentIsNotCached { - area: &'a mut Area, - inner_area: &'a mut Area, - vertical_padding: f32, - horizontal_padding: f32, - }, -} - -impl<'a> MeasureMode<'a> { - /// Get a reference to the inner area - pub fn inner_area(&'a self) -> &'a Area { - match self { - Self::ParentIsCached { inner_area } => inner_area, - Self::ParentIsNotCached { inner_area, .. } => inner_area, - } - } -} - -#[derive(Debug)] -enum OwnedMeasureMode { - ParentIsCached { - inner_area: Area, - }, - ParentIsNotCached { - area: Area, - inner_area: Area, - vertical_padding: f32, - horizontal_padding: f32, - }, -} - -impl OwnedMeasureMode { - pub fn ref_mut(&mut self) -> MeasureMode<'_> { - match self { - Self::ParentIsCached { inner_area } => MeasureMode::ParentIsCached { inner_area }, - Self::ParentIsNotCached { - area, - inner_area, - vertical_padding, - horizontal_padding, - } => MeasureMode::ParentIsNotCached { - area, - inner_area, - vertical_padding: *vertical_padding, - horizontal_padding: *horizontal_padding, - }, - } - } -} - -impl MeasureMode<'_> { - pub fn to_owned(&self) -> OwnedMeasureMode { - match self { - MeasureMode::ParentIsCached { inner_area } => OwnedMeasureMode::ParentIsCached { - inner_area: *inner_area.to_owned(), - }, - MeasureMode::ParentIsNotCached { - area, - inner_area, - vertical_padding, - horizontal_padding, - } => OwnedMeasureMode::ParentIsNotCached { - area: **area.clone(), - inner_area: **inner_area.clone(), - vertical_padding: *vertical_padding, - horizontal_padding: *horizontal_padding, - }, - } - } -} - -/// Measure the inner Nodes of a Node -#[allow(clippy::too_many_arguments)] -#[inline(always)] -fn measure_inner_nodes( - node_id: &Key, - node: &Node, - layout: &mut Torin, - available_area: &mut Area, - inner_sizes: &mut Size2D, - measurer: &mut Option>, - must_cache: bool, - mode: &mut MeasureMode, - dom_adapter: &mut impl DOMAdapter, -) { - let mut measure_children = |mode: &mut MeasureMode, - available_area: &mut Area, - inner_sizes: &mut Size2D, - measure_cross_axis: bool, - must_cache: bool| { - let children = dom_adapter.children_of(node_id); - - for child_id in children { - let inner_area = *mode.inner_area(); - - let child_data = dom_adapter.get_node(&child_id).unwrap(); - - let mut adapted_available_area = *available_area; - - // If required, make a previous measure to adapt the position - if measure_cross_axis { - let (_, child_areas) = measure_node( - child_id, - &child_data, - layout, - &inner_area, - available_area, - measurer, - false, - dom_adapter, - ); - - match node.direction { - DirectionMode::Horizontal => match node.cross_alignment { - Alignment::Center => { - let new_origin_y = - (available_area.height() / 2.0) - (child_areas.area.height() / 2.0); - - adapted_available_area.origin.y = available_area.min_y() + new_origin_y; - } - Alignment::End => { - adapted_available_area.origin.y = - available_area.max_y() - child_areas.area.height(); - } - _ => {} - }, - DirectionMode::Vertical => match node.cross_alignment { - Alignment::Center => { - let new_origin_x = - (available_area.width() / 2.0) - (child_areas.area.width() / 2.0); - - adapted_available_area.origin.x = available_area.min_x() + new_origin_x; - } - Alignment::End => { - adapted_available_area.origin.x = - available_area.max_x() - child_areas.area.width(); - } - _ => {} - }, - } - } - - let (child_revalidated, child_areas) = measure_node( - child_id, - &child_data, - layout, - &inner_area, - &adapted_available_area, - measurer, - must_cache, - dom_adapter, - ); - - match node.direction { - DirectionMode::Horizontal => { - // Move the available area - available_area.origin.x = child_areas.area.max_x(); - available_area.size.width -= child_areas.area.size.width; - - if let MeasureMode::ParentIsNotCached { - area, - vertical_padding, - inner_area, - .. - } = mode - { - inner_sizes.height = child_areas.area.height().max(inner_sizes.height); - inner_sizes.width += child_areas.area.width(); - - // Keep the biggest height - if node.height == Size::Inner { - area.size.height = area - .size - .height - .max(child_areas.area.size.height + *vertical_padding); - // Keep the inner area in sync - inner_area.size.height = area.size.height - *vertical_padding; - } - - // Accumulate width - if node.width == Size::Inner { - area.size.width += child_areas.area.size.width; - } - } - } - DirectionMode::Vertical => { - // Move the available area - available_area.origin.y = child_areas.area.max_y(); - available_area.size.height -= child_areas.area.size.height; - - if let MeasureMode::ParentIsNotCached { - area, - horizontal_padding, - inner_area, - .. - } = mode - { - inner_sizes.width = child_areas.area.width().max(inner_sizes.width); - inner_sizes.height += child_areas.area.height(); - - // Keep the biggest width - if node.width == Size::Inner { - area.size.width = area - .size - .width - .max(child_areas.area.size.width + *horizontal_padding); - // Keep the inner area in sync - inner_area.size.width = area.size.width - *horizontal_padding; - } - - // Accumulate height - if node.height == Size::Inner { - area.size.height += child_areas.area.size.height; - } - } - } - } - - if child_revalidated && must_cache { - layout.cache_node(child_id, child_areas); - } - } - }; - - // If any of the alignments isn't "start", it needs to run a measurement to get the aligned position, before caching the value - let has_special_alignments = - node.main_alignment.is_not_start() || node.cross_alignment.is_not_start(); - - { - let mut alignment_mode = mode.to_owned(); - let mut alignment_mode = alignment_mode.ref_mut(); - let mut inner_sizes = *inner_sizes; - - if has_special_alignments { - measure_children( - &mut alignment_mode, - &mut available_area.clone(), - &mut inner_sizes, - true, - false, - ); - - match node.direction { - DirectionMode::Horizontal => match node.main_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_x = (inner_area.width() / 2.0) - (inner_sizes.width / 2.0); - - available_area.origin.x = inner_area.min_x() + new_origin_x; - } - Alignment::End => { - let inner_area = alignment_mode.inner_area(); - available_area.origin.x = inner_area.max_x() - inner_sizes.width; - } - _ => {} - }, - DirectionMode::Vertical => { - // If the height is auto, we set the inner area to the parent area - // TODO: CLEAN THIS UP LOL - if Size::Inner == node.height && node.main_alignment.is_not_start() { - if let MeasureMode::ParentIsNotCached { - area, - inner_area, - vertical_padding, - .. - } = &mut alignment_mode - { - inner_area.origin.y = area.origin.y + node.padding.top(); - inner_area.size.height = area.size.height - *vertical_padding; - available_area.size.height = inner_area.size.height; - } - } - - // If the width is auto, we set the inner area to the parent area - // TODO: CLEAN THIS UP LOL - if Size::Inner == node.width && node.cross_alignment.is_not_start() { - if let MeasureMode::ParentIsNotCached { - area, - inner_area, - horizontal_padding, - .. - } = &mut alignment_mode - { - inner_area.origin.x = area.origin.x + node.padding.left(); - inner_area.size.width = area.size.width - *horizontal_padding; - available_area.size.width = inner_area.size.width; - } - } - - match node.main_alignment { - Alignment::Center => { - let inner_area = alignment_mode.inner_area(); - let new_origin_y = - (inner_area.height() / 2.0) - (inner_sizes.height / 2.0); - - available_area.origin.y = inner_area.min_y() + new_origin_y; - } - Alignment::End => { - let inner_area = alignment_mode.inner_area(); - available_area.origin.y = inner_area.max_y() - inner_sizes.height; - } - _ => {} - } - } - } - } - } - - measure_children( - mode, - available_area, - inner_sizes, - has_special_alignments, - must_cache, - ); -} diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index 5be2300be..7bdd326ef 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1110,7 +1110,7 @@ pub fn margin() { ); assert_eq!( - node_areas.box_area(), + node_areas.area, Rect::new(Point2D::new(5.0, 5.0), Size2D::new(200.0, 200.0)), ); } diff --git a/examples/alignment.rs b/examples/alignment.rs index f1264b9f7..188e8f9c7 100644 --- a/examples/alignment.rs +++ b/examples/alignment.rs @@ -28,7 +28,7 @@ fn app(cx: Scope) -> Element { cross_alignment: "center", background: "red", direction: "horizontal", - width: "50%%", + width: "50%", height: "50%", overflow: "clip", rect { @@ -47,7 +47,7 @@ fn app(cx: Scope) -> Element { width: "100%%", height: "50%", rect { - main_alignment: "end", + main_alignment: "start", cross_alignment: "center", width: "50%", height: "100%", diff --git a/examples/app_dog.rs b/examples/app_dog.rs index 0f0b4cbb7..1b25aed9a 100644 --- a/examples/app_dog.rs +++ b/examples/app_dog.rs @@ -39,16 +39,13 @@ fn app(cx: Scope) -> Element { render!( rect { - overflow: "clip", background: "rgb(15, 15, 15)", width: "100%", height: "100%", - color: "white", rect { overflow: "clip", width: "100%", - height: "calc(100% - 58)", - corner_radius: "25", + height: "calc(100% - 60)", if let Some(dog_url) = dog_url.get() { rsx!( NetworkImage { @@ -59,11 +56,12 @@ fn app(cx: Scope) -> Element { } rect { overflow: "clip", - padding: "10", - height: "58", + height: "60", width: "100%", - direction: "horizontal", + main_alignment: "center", + cross_alignment: "center", Button { + margin: "0", onclick: move |_| fetch(), label { "Fetch random Doggo!" diff --git a/examples/canvas.rs b/examples/canvas.rs index 7ae9e0f3d..05241fd91 100644 --- a/examples/canvas.rs +++ b/examples/canvas.rs @@ -119,28 +119,23 @@ fn app(cx: Scope) -> Element { }) } rect { - background: "rgb(35, 35, 35)", + background: "rgb(25, 25, 25)", height: "100", width: "100%", main_alignment: "center", cross_alignment: "center", padding: "15", - rect { - layer: "-100", - padding: "10", - corner_radius: "7", - width: "170", - height: "100%", - corner_radius: "15", - main_alignment: "center", - cross_alignment: "center", - background: "rgb(20, 20, 20)", - Button { - onclick: create_node, - label { - color: "white", - "Create new node" - } + layer: "-100", + shadow: "0 -2 5 0 rgb(0, 0, 0, 30)", + direction: "horizontal", + label { + "Create as many editors you want!" + } + Button { + margin: "0 20", + onclick: create_node, + label { + "New Editor" } } } diff --git a/examples/custom_theme.rs b/examples/custom_theme.rs index ce0d5f452..4d62d301a 100644 --- a/examples/custom_theme.rs +++ b/examples/custom_theme.rs @@ -9,6 +9,7 @@ const CUSTOM_THEME: Theme = Theme { button: ButtonTheme { background: "rgb(230, 0, 0)", hover_background: "rgb(150, 0, 0)", + border_fill: "rgb(120, 0, 0)", font_theme: FontTheme { color: "white" }, }, ..LIGHT_THEME From 2e8056a928676d7364caed9f011da06640c7f01d Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 19 Oct 2023 22:03:45 +0200 Subject: [PATCH 13/26] fixes --- crates/core/src/render.rs | 2 +- crates/torin/src/dom_adapter.rs | 9 ++++++++- crates/torin/src/geometry.rs | 17 ++++++++++++++++- crates/torin/src/measure.rs | 5 +---- crates/torin/src/measure_mode.rs | 32 ++++++++++++++++++++------------ crates/torin/src/values/size.rs | 4 ++-- examples/counter.rs | 2 +- 7 files changed, 49 insertions(+), 22 deletions(-) diff --git a/crates/core/src/render.rs b/crates/core/src/render.rs index d45421e7e..37519df12 100644 --- a/crates/core/src/render.rs +++ b/crates/core/src/render.rs @@ -52,7 +52,7 @@ pub fn process_render( render_hook( dom, node_id, - &areas.area, + &areas.visible_area(), font_collection, viewports_collection, hook_options, diff --git a/crates/torin/src/dom_adapter.rs b/crates/torin/src/dom_adapter.rs index bc705af66..cd27574b5 100644 --- a/crates/torin/src/dom_adapter.rs +++ b/crates/torin/src/dom_adapter.rs @@ -3,7 +3,7 @@ pub use euclid::Rect; use crate::{ geometry::{Area, Size2D}, node::Node, - prelude::Gaps, + prelude::{AreaModel, Gaps}, }; /// Cached layout results of a Node @@ -22,6 +22,13 @@ pub struct NodeAreas { pub margin: Gaps, } +impl NodeAreas { + // The area without any outer gap (e.g margin) + pub fn visible_area(&self) -> Area { + self.area.visible_area(&self.margin) + } +} + pub trait NodeKey: Clone + PartialEq + Eq + std::hash::Hash + Copy + std::fmt::Debug {} impl NodeKey for usize {} diff --git a/crates/torin/src/geometry.rs b/crates/torin/src/geometry.rs index 7b3e0bd36..0de3a677e 100644 --- a/crates/torin/src/geometry.rs +++ b/crates/torin/src/geometry.rs @@ -1,4 +1,4 @@ -use crate::prelude::{Alignment, DirectionMode}; +use crate::prelude::{Alignment, DirectionMode, Gaps}; #[derive(PartialEq)] pub struct Measure; @@ -10,6 +10,9 @@ pub type CursorPoint = euclid::Point2D; pub type Length = euclid::Length; pub trait AreaModel { + // The area without any outer gap (e.g margin) + fn visible_area(&self, margin: &Gaps) -> Area; + fn align_content( &mut self, available_area: &Area, @@ -21,6 +24,18 @@ pub trait AreaModel { } impl AreaModel for Area { + fn visible_area(&self, margin: &Gaps) -> Area { + let origin = self.origin; + let size = self.size; + Area::new( + Point2D::new(origin.x + margin.left(), origin.y + margin.top()), + Size2D::new( + size.width - margin.horizontal(), + size.height - margin.vertical(), + ), + ) + } + fn align_content( &mut self, available_area: &Area, diff --git a/crates/torin/src/measure.rs b/crates/torin/src/measure.rs index f1ded169a..00fc36ce3 100644 --- a/crates/torin/src/measure.rs +++ b/crates/torin/src/measure.rs @@ -34,9 +34,6 @@ pub fn measure_node( Size2D::new(horizontal_padding, vertical_padding), ); - area.origin.x += node.margin.left(); - area.origin.y += node.margin.top(); - area.size.width = node.width.min_max( area.size.width, parent_area.size.width, @@ -89,7 +86,7 @@ pub fn measure_node( // Node's inner area let mut inner_area = { - let mut inner_area = area; + let mut inner_area = area.visible_area(&node.margin); if Size::Inner == node.width { inner_area.size.width = available_parent_area.width() } diff --git a/crates/torin/src/measure_mode.rs b/crates/torin/src/measure_mode.rs index 94dbbd1e1..9525bd170 100644 --- a/crates/torin/src/measure_mode.rs +++ b/crates/torin/src/measure_mode.rs @@ -81,6 +81,8 @@ impl<'a> MeasureMode<'a> { &mut area.size.height, node.padding.top(), *vertical_padding, + node.margin.top(), + node.margin.vertical(), &mut available_area.size.height, )), AlignAxis::Width if Size::Inner == node.width && is_horizontal_not_start => Some(( @@ -90,6 +92,8 @@ impl<'a> MeasureMode<'a> { &mut area.size.width, node.padding.left(), *horizontal_padding, + node.margin.left(), + node.margin.horizontal(), &mut available_area.size.width, )), _ => None, @@ -105,11 +109,13 @@ impl<'a> MeasureMode<'a> { area_size, one_side_padding, two_sides_padding, + one_side_margin, + two_sides_margin, available_size, )) = params { - *inner_origin = *area_origin + one_side_padding; - *inner_size = *area_size - two_sides_padding; + *inner_origin = *area_origin + one_side_padding + one_side_margin; + *inner_size = *area_size - two_sides_padding - two_sides_margin; *available_size = *inner_size; } } @@ -140,12 +146,12 @@ impl<'a> MeasureMode<'a> { // Keep the biggest height if node.height == Size::Inner { - area.size.height = area - .size - .height - .max(content_area.size.height + *vertical_padding); + area.size.height = area.size.height.max( + content_area.size.height + *vertical_padding + node.margin.vertical(), + ); // Keep the inner area in sync - inner_area.size.height = area.size.height - *vertical_padding; + inner_area.size.height = + area.size.height - *vertical_padding - node.margin.vertical(); } // Accumulate width @@ -171,12 +177,14 @@ impl<'a> MeasureMode<'a> { // Keep the biggest width if node.width == Size::Inner { - area.size.width = area - .size - .width - .max(content_area.size.width + *horizontal_padding); + area.size.width = area.size.width.max( + content_area.size.width + + *horizontal_padding + + node.margin.horizontal(), + ); // Keep the inner area in sync - inner_area.size.width = area.size.width - *horizontal_padding; + inner_area.size.width = + area.size.width - *horizontal_padding - node.margin.horizontal(); } // Accumulate height diff --git a/crates/torin/src/values/size.rs b/crates/torin/src/values/size.rs index d9148afd3..41f7e7d73 100644 --- a/crates/torin/src/values/size.rs +++ b/crates/torin/src/values/size.rs @@ -36,7 +36,7 @@ impl Size { pub fn eval(&self, parent_value: f32, parent_margin: f32) -> Option { match self { - Size::Pixels(px) => Some(px.get()), + Size::Pixels(px) => Some(px.get() + parent_margin), Size::Percentage(per) => Some((parent_value / 100.0 * per.get()) - parent_margin), Size::DynamicCalculations(calculations) => { Some(run_calculations(calculations, parent_value, parent_margin)) @@ -54,7 +54,7 @@ impl Size { minimum: &Self, maximum: &Self, ) -> f32 { - let value = self.eval(parent_value, margin).unwrap_or(value); + let value = self.eval(parent_value, margin).unwrap_or(value + margin); let minimum_value = minimum .eval(parent_value, margin) diff --git a/examples/counter.rs b/examples/counter.rs index 80e2797cd..dec89f871 100644 --- a/examples/counter.rs +++ b/examples/counter.rs @@ -6,7 +6,7 @@ use freya::prelude::*; fn main() { - launch(app); + launch_with_props(app, "Counter", (400.0, 350.0)); } fn app(cx: Scope) -> Element { From f9e43b07e6f0b65fa0b31cd2f1f8fb045823082e Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 19 Oct 2023 22:10:54 +0200 Subject: [PATCH 14/26] fix tests --- crates/torin/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index 7bdd326ef..954521584 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1110,7 +1110,7 @@ pub fn margin() { ); assert_eq!( - node_areas.area, + node_areas.visible_area(), Rect::new(Point2D::new(5.0, 5.0), Size2D::new(200.0, 200.0)), ); } From e9acaa3da06071f4af2d485a44a99812d4946905 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Fri, 20 Oct 2023 00:05:36 +0200 Subject: [PATCH 15/26] tweak --- crates/renderer/src/app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/renderer/src/app.rs b/crates/renderer/src/app.rs index 5e731863b..885b1b33c 100644 --- a/crates/renderer/src/app.rs +++ b/crates/renderer/src/app.rs @@ -91,7 +91,7 @@ impl App { } let mgr: FontMgr = provider.into(); - font_collection.set_default_font_manager(def_mgr, "Inter"); + font_collection.set_default_font_manager(def_mgr, "Fira Sans"); font_collection.set_dynamic_font_manager(mgr); let (event_emitter, event_receiver) = mpsc::unbounded_channel::(); From 6503c07e37ebb27dffb9c46b5af6d1feadaa53da Mon Sep 17 00:00:00 2001 From: marc2332 Date: Fri, 20 Oct 2023 14:55:42 +0200 Subject: [PATCH 16/26] tweaks --- examples/app_dog.rs | 1 - examples/sidebar.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/app_dog.rs b/examples/app_dog.rs index 1b25aed9a..045dec46c 100644 --- a/examples/app_dog.rs +++ b/examples/app_dog.rs @@ -61,7 +61,6 @@ fn app(cx: Scope) -> Element { main_alignment: "center", cross_alignment: "center", Button { - margin: "0", onclick: move |_| fetch(), label { "Fetch random Doggo!" diff --git a/examples/sidebar.rs b/examples/sidebar.rs index 2dec6bef0..5e3afb45d 100644 --- a/examples/sidebar.rs +++ b/examples/sidebar.rs @@ -27,7 +27,7 @@ fn Sidebar<'a>(cx: Scope<'a>, children: Element<'a>, sidebar: Element<'a>) -> El overflow: "clip", width: "200", height: "100%", - background: "rgb(50, 50, 50)", + background: "rgb(20, 20, 20)", corner_radius: "0 7 0 7", padding: "20", color: "{color}", From 2419b51c2acc0fcbaa4a3286d4f7069a4e216c08 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sat, 21 Oct 2023 16:20:29 +0200 Subject: [PATCH 17/26] unsized alignment test --- crates/torin/src/node.rs | 31 ++++++++++++++++++++ crates/torin/tests/test.rs | 60 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index 0483cbe3a..92216d964 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -110,6 +110,37 @@ impl Node { } } + /// Construct a new Node given a size and a direction and some margin, + pub fn from_size_and_direction_and_margin(width: Size, height: Size, direction: DirectionMode, margin: Gaps) -> Self { + Self { + width, + height, + direction, + margin, + ..Default::default() + } + } + + /// Construct a new Node given a size, alignments and a direction + pub fn from_size_and_alignments_and_direction_and_padding( + width: Size, + height: Size, + main_alignment: Alignment, + cross_alignment: Alignment, + direction: DirectionMode, + padding: Gaps, + ) -> Self { + Self { + width, + height, + main_alignment, + cross_alignment, + direction, + padding, + ..Default::default() + } + } + /// Has properties that depend on the inner Nodes? pub fn does_depend_on_inner(&self) -> bool { Size::Inner == self.width diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index 954521584..936fd8edf 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1226,3 +1226,63 @@ pub fn double_end_alignment() { Rect::new(Point2D::new(700.0, 700.0), Size2D::new(300.0, 300.0)), ); } + + + +#[test] +pub fn unsized_alignment() { + let (mut layout, mut measurer) = test_utils(); + + let mut mocked_dom = TestingDOM::default(); + mocked_dom.add( + 0, + None, + vec![1, 2], + Node::from_size_and_alignments_and_direction_and_padding( + Size::Inner, + Size::Inner, + Alignment::Center, + Alignment::End, + DirectionMode::Horizontal, + Gaps::new(15.0, 15.0, 15.0, 15.0) + ), + ); + mocked_dom.add( + 1, + Some(0), + vec![], + Node::from_size_and_direction( + Size::Pixels(Length::new(100.0)), + Size::Pixels(Length::new(50.0)), + DirectionMode::Vertical, + ), + ); + mocked_dom.add( + 2, + Some(0), + vec![], + Node::from_size_and_direction_and_margin( + Size::Pixels(Length::new(150.0)), + Size::Pixels(Length::new(80.0)), + DirectionMode::Vertical, + Gaps::new(10.0, 50.0, 20.0, 0.0) + ), + ); + + layout.measure( + 0, + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(350.0, 190.0)), + &mut measurer, + &mut mocked_dom, + ); + + assert_eq!( + layout.get(1).unwrap().visible_area(), + Rect::new(Point2D::new(15.0, 75.0), Size2D::new(100.0, 50.0)), + ); + + assert_eq!( + layout.get(2).unwrap().visible_area(), + Rect::new(Point2D::new(115.0, 25.0), Size2D::new(150.0, 80.0)), + ); +} From 9645714f8f7df192680dd3b47752ca7ae02f462c Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sat, 21 Oct 2023 20:39:15 +0200 Subject: [PATCH 18/26] document code --- crates/torin/src/dom_adapter.rs | 4 +- crates/torin/src/geometry.rs | 13 +++- crates/torin/src/measure.rs | 104 ++++++++++++++++-------------- crates/torin/src/measure_mode.rs | 106 +++++++++++++++++-------------- crates/torin/src/node.rs | 11 +++- crates/torin/tests/test.rs | 6 +- 6 files changed, 139 insertions(+), 105 deletions(-) diff --git a/crates/torin/src/dom_adapter.rs b/crates/torin/src/dom_adapter.rs index cd27574b5..98e94c004 100644 --- a/crates/torin/src/dom_adapter.rs +++ b/crates/torin/src/dom_adapter.rs @@ -23,9 +23,9 @@ pub struct NodeAreas { } impl NodeAreas { - // The area without any outer gap (e.g margin) + // The area without any margin pub fn visible_area(&self) -> Area { - self.area.visible_area(&self.margin) + self.area.after_gaps(&self.margin) } } diff --git a/crates/torin/src/geometry.rs b/crates/torin/src/geometry.rs index 0de3a677e..b7f5f61d7 100644 --- a/crates/torin/src/geometry.rs +++ b/crates/torin/src/geometry.rs @@ -11,7 +11,9 @@ pub type Length = euclid::Length; pub trait AreaModel { // The area without any outer gap (e.g margin) - fn visible_area(&self, margin: &Gaps) -> Area; + fn after_gaps(&self, margin: &Gaps) -> Area; + + fn move_with_offsets(&mut self, offset_x: &Length, offset_y: &Length); fn align_content( &mut self, @@ -24,7 +26,8 @@ pub trait AreaModel { } impl AreaModel for Area { - fn visible_area(&self, margin: &Gaps) -> Area { + /// Get the area inside after including the gaps (margins or paddings) + fn after_gaps(&self, margin: &Gaps) -> Area { let origin = self.origin; let size = self.size; Area::new( @@ -36,6 +39,12 @@ impl AreaModel for Area { ) } + /// Get the area inside after including the gaps (margins or paddings) + fn move_with_offsets(&mut self, offset_x: &Length, offset_y: &Length) { + self.origin.x += offset_x.get(); + self.origin.y += offset_y.get(); + } + fn align_content( &mut self, available_area: &Area, diff --git a/crates/torin/src/measure.rs b/crates/torin/src/measure.rs index 00fc36ce3..49cdf6003 100644 --- a/crates/torin/src/measure.rs +++ b/crates/torin/src/measure.rs @@ -10,30 +10,32 @@ use crate::{ size::Size, }; -/// Measure this node and all it's children -/// The caller of this function is responsible of caching the Node's layout results +/// Measure a Node layout #[allow(clippy::too_many_arguments)] #[inline(always)] pub fn measure_node( node_id: Key, node: &Node, layout: &mut Torin, + // Area occupied by it's parent parent_area: &Area, + // Area that is available to use by the children of the parent available_parent_area: &Area, measurer: &mut Option>, - must_cache: bool, + // Whether to cache the measurements of this Node's children + must_cache_inner_nodes: bool, + // Adapter for the provided DOM dom_adapter: &mut impl DOMAdapter, ) -> (bool, NodeAreas) { let must_run = layout.dirty.contains(&node_id) || layout.results.get(&node_id).is_none(); if must_run { - let horizontal_padding = node.padding.horizontal(); - let vertical_padding = node.padding.vertical(); - + // 1. Create the initial Node area let mut area = Rect::new( available_parent_area.origin, - Size2D::new(horizontal_padding, vertical_padding), + Size2D::new(node.padding.horizontal(), node.padding.vertical()), ); + // 2. Compute the width and height given the size, the minimum size, the maximum size and margins area.size.width = node.width.min_max( area.size.width, parent_area.size.width, @@ -51,14 +53,18 @@ pub fn measure_node( &node.maximum_height, ); - // Custom measure - let skip_inner = if let Some(measurer) = measurer { - let custom_measure = + // 3. If available, run a custom layout measure function + // This is useful when you use third-party libraries (e.g. rust-skia, cosmic-text) to measure text layouts + // When a Node is measured by a custom measurer function the inner children will be skipped + let measure_inner_children = if let Some(measurer) = measurer { + let custom_area = measurer.measure(node_id, node, &area, parent_area, available_parent_area); - if let Some(new_area) = custom_measure { + + // 3.1. Compute the width and height again using the new custom area sizes + if let Some(custom_area) = custom_area { if Size::Inner == node.width { area.size.width = node.width.min_max( - new_area.width(), + custom_area.width(), parent_area.size.width, node.margin.left(), node.margin.horizontal(), @@ -68,7 +74,7 @@ pub fn measure_node( } if Size::Inner == node.height { area.size.height = node.height.min_max( - new_area.height(), + custom_area.height(), parent_area.size.height, node.margin.top(), node.margin.vertical(), @@ -77,46 +83,44 @@ pub fn measure_node( ); } } - custom_measure.is_some() + + // Do not measure inner children + custom_area.is_none() } else { - false + true }; - let mut inner_sizes = Size2D::default(); - - // Node's inner area + // 4. Compute the inner area of the Node, which is basically the area inside the margins and paddings let mut inner_area = { - let mut inner_area = area.visible_area(&node.margin); + let mut inner_area = area.after_gaps(&node.margin).after_gaps(&node.padding); + + // 4.1. When having an unsized bound we set it to whatever it is still available in the parent's area if Size::Inner == node.width { inner_area.size.width = available_parent_area.width() } if Size::Inner == node.height { inner_area.size.height = available_parent_area.height() } + inner_area }; - // Apply padding - inner_area.origin.x += node.padding.left(); - inner_area.origin.y += node.padding.top(); - inner_area.size.width -= horizontal_padding; - inner_area.size.height -= vertical_padding; + let mut inner_sizes = Size2D::default(); - // Node's available inner area - let mut available_area = inner_area; + if measure_inner_children { + // 5. Create an area containin the available space inside the inner area + let mut available_area = inner_area; - // Apply scroll - available_area.origin.x += node.offset_x.get(); - available_area.origin.y += node.offset_y.get(); + // 5.1. Adjust the available area with the node offsets (mainly used by scrollviews) + available_area.move_with_offsets(&node.offset_x, &node.offset_y); - let mut measurement_mode = MeasureMode::ParentIsNotCached { - area: &mut area, - inner_area: &mut inner_area, - vertical_padding, - horizontal_padding, - }; + let mut measurement_mode = MeasureMode::ParentIsNotCached { + area: &mut area, + inner_area: &mut inner_area, + padding: node.padding, + }; - if !skip_inner { + // 6. Measure the layout of this Node's children measure_inner_nodes( &node_id, node, @@ -124,14 +128,14 @@ pub fn measure_node( &mut available_area, &mut inner_sizes, measurer, - must_cache, + must_cache_inner_nodes, &mut measurement_mode, dom_adapter, ); } ( - must_cache, + must_cache_inner_nodes, NodeAreas { area, margin: node.margin, @@ -145,8 +149,7 @@ pub fn measure_node( let mut inner_sizes = areas.inner_sizes; let mut available_area = areas.inner_area; - available_area.origin.x += node.offset_x.get(); - available_area.origin.y += node.offset_y.get(); + available_area.move_with_offsets(&node.offset_x, &node.offset_y); let mut measurement_mode = MeasureMode::ParentIsCached { inner_area: &areas.inner_area, @@ -159,7 +162,7 @@ pub fn measure_node( &mut available_area, &mut inner_sizes, measurer, - must_cache, + must_cache_inner_nodes, &mut measurement_mode, dom_adapter, ); @@ -168,24 +171,28 @@ pub fn measure_node( } } -/// Measure the inner Nodes of a Node +/// Measure the children layouts of a Node #[allow(clippy::too_many_arguments)] #[inline(always)] pub fn measure_inner_nodes( node_id: &Key, node: &Node, layout: &mut Torin, + // Area available inside the Node available_area: &mut Area, + // Accumulated sizes in both axis in the Node inner_sizes: &mut Size2D, measurer: &mut Option>, - must_cache: bool, + // Whether to cache the measurements of this Node's children + must_cache_inner_nodes: bool, mode: &mut MeasureMode, + // Adapter for the provided DOM dom_adapter: &mut impl DOMAdapter, ) { let mut measure_children = |mode: &mut MeasureMode, available_area: &mut Area, inner_sizes: &mut Size2D, - must_cache: bool| { + must_cache_inner_nodes: bool| { let children = dom_adapter.children_of(node_id); for child_id in children { @@ -226,20 +233,23 @@ pub fn measure_inner_nodes( &inner_area, &adapted_available_area, measurer, - must_cache, + must_cache_inner_nodes, dom_adapter, ); // Stack the child node mode.stack_node(node, available_area, &child_areas.area, inner_sizes); - if child_revalidated && must_cache { + // Cache the child layout if it was mutated and inner nodes must be cache + if child_revalidated && must_cache_inner_nodes { layout.cache_node(child_id, child_areas); } } }; { + // This is no the final measure, hence we make a temporary measurement mode + // so the affected values are not reused by the final measurement let mut alignment_mode = mode.to_owned(); let mut alignment_mode = alignment_mode.to_mut(); let mut inner_sizes = *inner_sizes; @@ -283,5 +293,5 @@ pub fn measure_inner_nodes( } // 5. Second measure - measure_children(mode, available_area, inner_sizes, must_cache); + measure_children(mode, available_area, inner_sizes, must_cache_inner_nodes); } diff --git a/crates/torin/src/measure_mode.rs b/crates/torin/src/measure_mode.rs index 9525bd170..18d013218 100644 --- a/crates/torin/src/measure_mode.rs +++ b/crates/torin/src/measure_mode.rs @@ -1,5 +1,5 @@ use crate::prelude::{ - get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Node, Size, Size2D, + get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Gaps, Node, Size, Size2D, }; /// Measurement data for the inner Nodes of a Node @@ -11,8 +11,7 @@ pub enum MeasureMode<'a> { ParentIsNotCached { area: &'a mut Area, inner_area: &'a mut Area, - vertical_padding: f32, - horizontal_padding: f32, + padding: Gaps, }, } @@ -25,6 +24,7 @@ impl<'a> MeasureMode<'a> { } } + /// Create an owned version of [MeasureMode] pub fn to_owned(&self) -> OwnedMeasureMode { match self { MeasureMode::ParentIsCached { inner_area } => OwnedMeasureMode::ParentIsCached { @@ -33,13 +33,11 @@ impl<'a> MeasureMode<'a> { MeasureMode::ParentIsNotCached { area, inner_area, - vertical_padding, - horizontal_padding, + padding, } => OwnedMeasureMode::ParentIsNotCached { area: **area.clone(), inner_area: **inner_area.clone(), - vertical_padding: *vertical_padding, - horizontal_padding: *horizontal_padding, + padding: *padding, }, } } @@ -55,6 +53,18 @@ impl<'a> MeasureMode<'a> { alignment_direction: AlignmentDirection, available_area: &mut Area, ) { + struct NodeData<'a> { + pub inner_origin: &'a mut f32, + pub inner_size: &'a mut f32, + pub area_origin: &'a mut f32, + pub area_size: &'a mut f32, + pub one_side_padding: f32, + pub two_sides_padding: f32, + pub one_side_margin: f32, + pub two_sides_margin: f32, + pub available_size: &'a mut f32, + } + let axis = get_align_axis(&node.direction, alignment_direction); let (is_vertical_not_start, is_horizontal_not_start) = match node.direction { DirectionMode::Vertical => ( @@ -69,40 +79,43 @@ impl<'a> MeasureMode<'a> { let params = if let MeasureMode::ParentIsNotCached { area, inner_area, - horizontal_padding, - vertical_padding, + padding, } = self { match axis { - AlignAxis::Height if Size::Inner == node.height && is_vertical_not_start => Some(( - &mut inner_area.origin.y, - &mut inner_area.size.height, - &mut area.origin.y, - &mut area.size.height, - node.padding.top(), - *vertical_padding, - node.margin.top(), - node.margin.vertical(), - &mut available_area.size.height, - )), - AlignAxis::Width if Size::Inner == node.width && is_horizontal_not_start => Some(( - &mut inner_area.origin.x, - &mut inner_area.size.width, - &mut area.origin.x, - &mut area.size.width, - node.padding.left(), - *horizontal_padding, - node.margin.left(), - node.margin.horizontal(), - &mut available_area.size.width, - )), + AlignAxis::Height if Size::Inner == node.height && is_vertical_not_start => { + Some(NodeData { + inner_origin: &mut inner_area.origin.y, + inner_size: &mut inner_area.size.height, + area_origin: &mut area.origin.y, + area_size: &mut area.size.height, + one_side_padding: node.padding.top(), + two_sides_padding: padding.vertical(), + one_side_margin: node.margin.top(), + two_sides_margin: node.margin.vertical(), + available_size: &mut available_area.size.height, + }) + } + AlignAxis::Width if Size::Inner == node.width && is_horizontal_not_start => { + Some(NodeData { + inner_origin: &mut inner_area.origin.x, + inner_size: &mut inner_area.size.width, + area_origin: &mut area.origin.x, + area_size: &mut area.size.width, + one_side_padding: node.padding.left(), + two_sides_padding: padding.horizontal(), + one_side_margin: node.margin.left(), + two_sides_margin: node.margin.horizontal(), + available_size: &mut available_area.size.width, + }) + } _ => None, } } else { None }; - if let Some(( + if let Some(NodeData { inner_origin, inner_size, area_origin, @@ -112,10 +125,13 @@ impl<'a> MeasureMode<'a> { one_side_margin, two_sides_margin, available_size, - )) = params + }) = params { + // Set the origin of the inner area to the origin of the area plus the padding and margin for the given axis *inner_origin = *area_origin + one_side_padding + one_side_margin; + // Set the size of the inner area to the size of the area minus the padding and margin for the given axis *inner_size = *area_size - two_sides_padding - two_sides_margin; + // Set the same available size as the inner area for the given axis *available_size = *inner_size; } } @@ -136,9 +152,8 @@ impl<'a> MeasureMode<'a> { if let MeasureMode::ParentIsNotCached { area, - vertical_padding, + padding, inner_area, - .. } = self { inner_sizes.height = content_area.height().max(inner_sizes.height); @@ -147,11 +162,11 @@ impl<'a> MeasureMode<'a> { // Keep the biggest height if node.height == Size::Inner { area.size.height = area.size.height.max( - content_area.size.height + *vertical_padding + node.margin.vertical(), + content_area.size.height + padding.vertical() + node.margin.vertical(), ); // Keep the inner area in sync inner_area.size.height = - area.size.height - *vertical_padding - node.margin.vertical(); + area.size.height - padding.vertical() - node.margin.vertical(); } // Accumulate width @@ -167,9 +182,8 @@ impl<'a> MeasureMode<'a> { if let MeasureMode::ParentIsNotCached { area, - horizontal_padding, + padding, inner_area, - .. } = self { inner_sizes.width = content_area.width().max(inner_sizes.width); @@ -179,12 +193,12 @@ impl<'a> MeasureMode<'a> { if node.width == Size::Inner { area.size.width = area.size.width.max( content_area.size.width - + *horizontal_padding + + padding.horizontal() + node.margin.horizontal(), ); // Keep the inner area in sync inner_area.size.width = - area.size.width - *horizontal_padding - node.margin.horizontal(); + area.size.width - padding.horizontal() - node.margin.horizontal(); } // Accumulate height @@ -197,6 +211,7 @@ impl<'a> MeasureMode<'a> { } } +/// Just an owned version of [MeasureMode] #[derive(Debug)] pub enum OwnedMeasureMode { ParentIsCached { @@ -205,8 +220,7 @@ pub enum OwnedMeasureMode { ParentIsNotCached { area: Area, inner_area: Area, - vertical_padding: f32, - horizontal_padding: f32, + padding: Gaps, }, } @@ -217,13 +231,11 @@ impl OwnedMeasureMode { Self::ParentIsNotCached { area, inner_area, - vertical_padding, - horizontal_padding, + padding, } => MeasureMode::ParentIsNotCached { area, inner_area, - vertical_padding: *vertical_padding, - horizontal_padding: *horizontal_padding, + padding: *padding, }, } } diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index 92216d964..cd439cc7d 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -111,7 +111,12 @@ impl Node { } /// Construct a new Node given a size and a direction and some margin, - pub fn from_size_and_direction_and_margin(width: Size, height: Size, direction: DirectionMode, margin: Gaps) -> Self { + pub fn from_size_and_direction_and_margin( + width: Size, + height: Size, + direction: DirectionMode, + margin: Gaps, + ) -> Self { Self { width, height, @@ -121,8 +126,8 @@ impl Node { } } - /// Construct a new Node given a size, alignments and a direction - pub fn from_size_and_alignments_and_direction_and_padding( + /// Construct a new Node given a size, alignments and a direction + pub fn from_size_and_alignments_and_direction_and_padding( width: Size, height: Size, main_alignment: Alignment, diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index 936fd8edf..1502af1e6 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1227,8 +1227,6 @@ pub fn double_end_alignment() { ); } - - #[test] pub fn unsized_alignment() { let (mut layout, mut measurer) = test_utils(); @@ -1244,7 +1242,7 @@ pub fn unsized_alignment() { Alignment::Center, Alignment::End, DirectionMode::Horizontal, - Gaps::new(15.0, 15.0, 15.0, 15.0) + Gaps::new(15.0, 15.0, 15.0, 15.0), ), ); mocked_dom.add( @@ -1265,7 +1263,7 @@ pub fn unsized_alignment() { Size::Pixels(Length::new(150.0)), Size::Pixels(Length::new(80.0)), DirectionMode::Vertical, - Gaps::new(10.0, 50.0, 20.0, 0.0) + Gaps::new(10.0, 50.0, 20.0, 0.0), ), ); From bbf6c204b403d1a83280dfc7013d7aba7f23823b Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 22 Oct 2023 00:03:50 +0200 Subject: [PATCH 19/26] tweak --- crates/components/src/input.rs | 54 ++++++++++++++++------------------ 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/crates/components/src/input.rs b/crates/components/src/input.rs index 7457d7e65..29352ee6d 100644 --- a/crates/components/src/input.rs +++ b/crates/components/src/input.rs @@ -38,7 +38,7 @@ pub struct InputProps<'a> { #[props(default = "150".to_string(), into)] width: String, /// Height of the Input. Default 100. - #[props(default = "35".to_string(), into)] + #[props(default = "38".to_string(), into)] height: String, /// Max lines for the Input. Default 1. #[props(default = "1".to_string(), into)] @@ -154,34 +154,30 @@ pub fn Input<'a>(cx: Scope<'a, InputProps<'a>>) -> Element { rect { onkeydown: onkeydown, onclick: onclick, - width: "auto", - height: "auto", - padding: "1.5", - rect { - width: "{width}", - height: "{height}", - direction: "vertical", - color: "{color}", - background: "{background}", - shadow: "0 3 15 0 rgb(0, 0, 0, 70)", - corner_radius: "5", - padding: "8", - cursor_reference: cursor_attr, - ScrollView { - scroll_with_arrows: false, - paragraph { - width: "100%", - cursor_id: "0", - cursor_index: "{cursor_char}", - cursor_mode: "editable", - cursor_color: "{color}", - max_lines: "{max_lines}", - onmouseover: onmouseover, - onmousedown: onmousedown, - highlights: highlights_attr, - text { - "{text}" - } + width: "{width}", + height: "{height}", + direction: "vertical", + color: "{color}", + background: "{background}", + shadow: "0 3 15 0 rgb(0, 0, 0, 70)", + corner_radius: "5", + padding: "8", + margin: "4", + cursor_reference: cursor_attr, + ScrollView { + scroll_with_arrows: false, + paragraph { + width: "100%", + cursor_id: "0", + cursor_index: "{cursor_char}", + cursor_mode: "editable", + cursor_color: "{color}", + max_lines: "{max_lines}", + onmouseover: onmouseover, + onmousedown: onmousedown, + highlights: highlights_attr, + text { + "{text}" } } } From 00455d0ffcb148fee8f6c8420f807002707243fa Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 22 Oct 2023 10:12:00 +0200 Subject: [PATCH 20/26] rename attributes --- book/src/guides/layout.md | 4 ++-- crates/components/src/button.rs | 4 ++-- crates/components/src/network_image.rs | 8 ++++---- crates/components/src/progress_bar.rs | 4 ++-- crates/components/src/slider.rs | 4 ++-- crates/components/src/table.rs | 4 ++-- crates/components/src/tooltip.rs | 4 ++-- crates/devtools/src/tabs/layout.rs | 24 ++++++++++++------------ crates/elements/src/elements.rs | 4 ++-- crates/state/src/layout.rs | 4 ++-- examples/alignment.rs | 18 +++++++++--------- examples/animation.rs | 8 ++++---- examples/app_dog.rs | 4 ++-- examples/canvas.rs | 16 ++++++++-------- examples/cloned_editor.rs | 4 ++-- examples/counter.rs | 8 ++++---- examples/custom_font.rs | 4 ++-- examples/editor.rs | 12 ++++++------ examples/frameless_window.rs | 4 ++-- examples/gesture_area.rs | 2 +- examples/i18n.rs | 4 ++-- examples/image.rs | 4 ++-- examples/material_design_app.rs | 6 +++--- examples/mouse_trace.rs | 8 ++++---- examples/paragraph.rs | 2 +- examples/rotate.rs | 12 ++++++------ examples/tic_tac_toe.rs | 8 ++++---- examples/touch.rs | 4 ++-- examples/transition.rs | 4 ++-- 29 files changed, 98 insertions(+), 98 deletions(-) diff --git a/book/src/guides/layout.md b/book/src/guides/layout.md index f111a3b24..d68bc8494 100644 --- a/book/src/guides/layout.md +++ b/book/src/guides/layout.md @@ -187,8 +187,8 @@ fn app(cx: Scope) -> Element { rect { width: "100%", height: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", rect { width: "50%", height: "50%", diff --git a/crates/components/src/button.rs b/crates/components/src/button.rs index 06c2701ac..888362b60 100644 --- a/crates/components/src/button.rs +++ b/crates/components/src/button.rs @@ -119,8 +119,8 @@ pub fn Button<'a>(cx: Scope<'a, ButtonProps<'a>>) -> Element { corner_radius: "{corner_radius}", background: "{background}", align: "center", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", &cx.props.children } ) diff --git a/crates/components/src/network_image.rs b/crates/components/src/network_image.rs index 440527691..13ce7c260 100644 --- a/crates/components/src/network_image.rs +++ b/crates/components/src/network_image.rs @@ -99,8 +99,8 @@ pub fn NetworkImage<'a>(cx: Scope<'a, NetworkImageProps<'a>>) -> Element<'a> { rect { height: "{height}", width: "{width}", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", Loader { } @@ -115,8 +115,8 @@ pub fn NetworkImage<'a>(cx: Scope<'a, NetworkImageProps<'a>>) -> Element<'a> { rect { height: "{height}", width: "{width}", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", label { align: "center", "Error" diff --git a/crates/components/src/progress_bar.rs b/crates/components/src/progress_bar.rs index 91eba304f..a43aa1b27 100644 --- a/crates/components/src/progress_bar.rs +++ b/crates/components/src/progress_bar.rs @@ -73,8 +73,8 @@ pub fn ProgressBar(cx: Scope) -> Element { width: "{progress}%", height: "100%", background: "{progress_background}", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", overflow: "clip", if show_progress { rsx!( diff --git a/crates/components/src/slider.rs b/crates/components/src/slider.rs index e4e71d5b7..97ad7c309 100644 --- a/crates/components/src/slider.rs +++ b/crates/components/src/slider.rs @@ -122,8 +122,8 @@ pub fn Slider<'a>(cx: Scope<'a, SliderProps>) -> Element<'a> { onglobalmouseover: onmouseover, onmouseleave: onmouseleave, onwheel: onwheel, - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", padding: "1", rect { background: "{theme.background}", diff --git a/crates/components/src/table.rs b/crates/components/src/table.rs index 701dd420e..da75853f5 100644 --- a/crates/components/src/table.rs +++ b/crates/components/src/table.rs @@ -154,8 +154,8 @@ pub fn TableCell<'a>(cx: Scope<'a, TableCellProps<'a>>) -> Element { overflow: "clip", padding: "5 25", width: "{width}%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", height: "35", align: "right", onclick: |e| { diff --git a/crates/components/src/tooltip.rs b/crates/components/src/tooltip.rs index ec5ee916b..18b731fd4 100644 --- a/crates/components/src/tooltip.rs +++ b/crates/components/src/tooltip.rs @@ -33,8 +33,8 @@ pub fn Tooltip<'a>(cx: Scope<'a, TooltipProps<'a>>) -> Element { shadow: "0 0 10 5 rgb(0, 0, 0, 50)", corner_radius: "8", background: "{background}", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", label { max_lines: "1", color: "{color}", diff --git a/crates/devtools/src/tabs/layout.rs b/crates/devtools/src/tabs/layout.rs index d5c328d38..90e1e2209 100644 --- a/crates/devtools/src/tabs/layout.rs +++ b/crates/devtools/src/tabs/layout.rs @@ -42,8 +42,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { rect { width: "100%", height: "calc(100% - 25)", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", background: "rgb(40, 40, 40)", rect { width: "100%", @@ -51,8 +51,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { background: "rgb(71, 180, 240)", corner_radius: "5", rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "100%", height: "25", label { @@ -66,8 +66,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { height: "calc(100% - 50)", direction: "horizontal", rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "25", height: "100%", label { @@ -79,8 +79,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { rect { width: "calc(100% - 50)", height: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", background: "rgb(40, 40, 40)", corner_radius: "5", label { @@ -88,8 +88,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { } } rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "25", height: "100%", label { @@ -100,8 +100,8 @@ pub fn NodeInspectorLayout(cx: Scope, node_id: NodeId) -> Element { } } rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "100%", height: "25", label { diff --git a/crates/elements/src/elements.rs b/crates/elements/src/elements.rs index 54f6d84cf..e61c7bba0 100644 --- a/crates/elements/src/elements.rs +++ b/crates/elements/src/elements.rs @@ -177,8 +177,8 @@ builder_constructors! { font_style: String, font_weight: String, font_width: String, - main_alignment: String, - cross_alignment: String, + main_align: String, + cross_align: String, align: String, reference: Reference, cursor_reference: CursorReference, diff --git a/crates/state/src/layout.rs b/crates/state/src/layout.rs index 97557463f..bc9febcf6 100644 --- a/crates/state/src/layout.rs +++ b/crates/state/src/layout.rs @@ -176,14 +176,14 @@ impl State for LayoutState { } } } - "main_alignment" => { + "main_align" => { if let Some(value) = attr.value.as_text() { if let Ok(alignment) = Alignment::parse(value) { layout.main_alignment = alignment; } } } - "cross_alignment" => { + "cross_align" => { if let Some(value) = attr.value.as_text() { if let Ok(alignment) = Alignment::parse(value) { layout.cross_alignment = alignment; diff --git a/examples/alignment.rs b/examples/alignment.rs index 188e8f9c7..72b75cbe1 100644 --- a/examples/alignment.rs +++ b/examples/alignment.rs @@ -14,18 +14,18 @@ fn app(cx: Scope) -> Element { rect { height: "100%", width: "100%", - cross_alignment: "end", - main_alignment: "end", + cross_align: "end", + main_align: "end", rect { width: "65%", height: "65%", background: "yellow", - main_alignment: "start", - cross_alignment: "start", + main_align: "start", + cross_align: "start", overflow: "clip", rect { - main_alignment: "end", - cross_alignment: "center", + main_align: "end", + cross_align: "center", background: "red", direction: "horizontal", width: "50%", @@ -43,12 +43,12 @@ fn app(cx: Scope) -> Element { } } rect { - cross_alignment: "end", + cross_align: "end", width: "100%%", height: "50%", rect { - main_alignment: "start", - cross_alignment: "center", + main_align: "start", + cross_align: "center", width: "50%", height: "100%", label { diff --git a/examples/animation.rs b/examples/animation.rs index ed1d3608d..f60b121dd 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -37,8 +37,8 @@ fn app(cx: Scope) -> Element { height: "100%", offset_x: "{progress}", rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", height: "100%", width: "200", rect { @@ -47,8 +47,8 @@ fn app(cx: Scope) -> Element { background: "rgb(100, 100, 100)", padding: "25", corner_radius: "100", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", onclick: anim, label { font_size: "30", diff --git a/examples/app_dog.rs b/examples/app_dog.rs index 045dec46c..95431d94c 100644 --- a/examples/app_dog.rs +++ b/examples/app_dog.rs @@ -58,8 +58,8 @@ fn app(cx: Scope) -> Element { overflow: "clip", height: "60", width: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", Button { onclick: move |_| fetch(), label { diff --git a/examples/canvas.rs b/examples/canvas.rs index 05241fd91..faa0b7b05 100644 --- a/examples/canvas.rs +++ b/examples/canvas.rs @@ -122,8 +122,8 @@ fn app(cx: Scope) -> Element { background: "rgb(25, 25, 25)", height: "100", width: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", padding: "15", layer: "-100", shadow: "0 -2 5 0 rgb(0, 0, 0, 30)", @@ -201,10 +201,10 @@ fn Editor(cx: Scope) -> Element { height: "70", padding: "5", direction: "horizontal", - cross_alignment: "center", + cross_align: "center", rect { width: "130", - cross_alignment: "center", + cross_align: "center", Slider { width: 100.0, value: *font_size_percentage.get(), @@ -218,7 +218,7 @@ fn Editor(cx: Scope) -> Element { } rect { width: "130", - cross_alignment: "center", + cross_align: "center", Slider { width: 100.0, value: *line_height_percentage.get(), @@ -232,7 +232,7 @@ fn Editor(cx: Scope) -> Element { } rect { width: "80", - cross_alignment: "center", + cross_align: "center", Switch { enabled: *is_bold.get(), ontoggled: |_| { @@ -245,7 +245,7 @@ fn Editor(cx: Scope) -> Element { } rect { width: "80", - cross_alignment: "center", + cross_align: "center", Switch { enabled: *is_italic.get(), ontoggled: |_| { @@ -329,7 +329,7 @@ fn Editor(cx: Scope) -> Element { rect { width: "{font_size * 2.0}", height: "100%", - main_alignment: "center", + main_align: "center", direction: "horizontal", label { font_size: "{font_size}", diff --git a/examples/cloned_editor.rs b/examples/cloned_editor.rs index 420bd7ae7..59a0739e7 100644 --- a/examples/cloned_editor.rs +++ b/examples/cloned_editor.rs @@ -112,7 +112,7 @@ fn Body(cx: Scope) -> Element { rect { width: "30", height: "100%", - main_alignment: "center", + main_align: "center", direction: "horizontal", label { font_size: "15", @@ -196,7 +196,7 @@ fn Body(cx: Scope) -> Element { rect { width: "30", height: "100%", - main_alignment: "center", + main_align: "center", direction: "horizontal", label { font_size: "15", diff --git a/examples/counter.rs b/examples/counter.rs index dec89f871..1b06b9622 100644 --- a/examples/counter.rs +++ b/examples/counter.rs @@ -16,8 +16,8 @@ fn app(cx: Scope) -> Element { rect { height: "50%", width: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", background: "rgb(0, 119, 182)", color: "white", shadow: "0 4 20 5 rgb(0, 0, 0, 80)", @@ -30,8 +30,8 @@ fn app(cx: Scope) -> Element { rect { height: "50%", width: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", direction: "horizontal", Button { onclick: move |_| count += 1, diff --git a/examples/custom_font.rs b/examples/custom_font.rs index 9d0d73970..554a2b5d6 100644 --- a/examples/custom_font.rs +++ b/examples/custom_font.rs @@ -21,8 +21,8 @@ fn main() { fn app(cx: Scope) -> Element { render!( rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", height: "100%", width: "100%", label { diff --git a/examples/editor.rs b/examples/editor.rs index bebb96c10..269492a0d 100644 --- a/examples/editor.rs +++ b/examples/editor.rs @@ -70,7 +70,7 @@ fn Body(cx: Scope) -> Element { height: "100%", width: "100%", direction: "horizontal", - cross_alignment: "center", + cross_align: "center", label { font_size: "30", "Editor" @@ -80,7 +80,7 @@ fn Body(cx: Scope) -> Element { } rect { width: "130", - cross_alignment: "center", + cross_align: "center", Slider { width: 100.0, value: *font_size_percentage.get(), @@ -94,7 +94,7 @@ fn Body(cx: Scope) -> Element { } rect { width: "130", - cross_alignment: "center", + cross_align: "center", Slider { width: 100.0, value: *line_height_percentage.get(), @@ -108,7 +108,7 @@ fn Body(cx: Scope) -> Element { } rect { width: "80", - cross_alignment: "center", + cross_align: "center", Switch { enabled: *is_bold.get(), ontoggled: |_| { @@ -121,7 +121,7 @@ fn Body(cx: Scope) -> Element { } rect { width: "80", - cross_alignment: "center", + cross_align: "center", Switch { enabled: *is_italic.get(), ontoggled: |_| { @@ -207,7 +207,7 @@ fn Body(cx: Scope) -> Element { rect { width: "{font_size * 2.0}", height: "100%", - main_alignment: "center", + main_align: "center", direction: "horizontal", label { font_size: "{font_size}", diff --git a/examples/frameless_window.rs b/examples/frameless_window.rs index 7417d6c7e..2a806bca6 100644 --- a/examples/frameless_window.rs +++ b/examples/frameless_window.rs @@ -23,8 +23,8 @@ fn app(cx: Scope) -> Element { rect { background: "white", padding: "10", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "100%", height: "100%", corner_radius: "15", diff --git a/examples/gesture_area.rs b/examples/gesture_area.rs index a744cd284..a645267d9 100644 --- a/examples/gesture_area.rs +++ b/examples/gesture_area.rs @@ -18,7 +18,7 @@ fn app(cx: Scope) -> Element { width: "100%", height: "100%", direction: "vertical", - main_alignment: "center", + main_align: "center", label { align: "center", width: "100%", diff --git a/examples/i18n.rs b/examples/i18n.rs index 5b5907193..aaa106198 100644 --- a/examples/i18n.rs +++ b/examples/i18n.rs @@ -26,8 +26,8 @@ fn Body(cx: Scope) -> Element { render!( rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "100%", height: "100%", rect { diff --git a/examples/image.rs b/examples/image.rs index 1b4b4c7e4..c5e37f4e7 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -29,8 +29,8 @@ fn app(cx: Scope) -> Element { width: "100%", height: "100%", padding: "50", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", onwheel: onwheel, image { image_data: image_data, diff --git a/examples/material_design_app.rs b/examples/material_design_app.rs index a7e806e16..cb4d73631 100644 --- a/examples/material_design_app.rs +++ b/examples/material_design_app.rs @@ -53,8 +53,8 @@ fn FloatingButton<'a>(cx: Scope<'a, FloatingButtonProps<'a>>) -> Element<'a> { rect { height: "100%", width: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", height: "50", width: "50", background: "rgb(104, 24, 245)", @@ -127,7 +127,7 @@ fn Navbar<'a>(cx: Scope<'a, NavbarProps<'a>>) -> Element<'a> { background: "rgb(104, 24, 245)", direction: "vertical", color: "white", - main_alignment: "center", + main_align: "center", rect { width: "100%", direction: "horizontal", diff --git a/examples/mouse_trace.rs b/examples/mouse_trace.rs index 55c3c6a47..f0aa75490 100644 --- a/examples/mouse_trace.rs +++ b/examples/mouse_trace.rs @@ -24,15 +24,15 @@ fn Box(cx: Scope) -> Element { background: "rgb(65, 53, 67)", width: "250", height: "250", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", corner_radius: "100", rect { background: "rgb(143, 67, 238)", width: "180", height: "180", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", corner_radius: "100", rect { background: "rgb(240, 235, 141)", diff --git a/examples/paragraph.rs b/examples/paragraph.rs index e5fe0806c..ecb1e972b 100644 --- a/examples/paragraph.rs +++ b/examples/paragraph.rs @@ -17,7 +17,7 @@ fn app(cx: Scope) -> Element { color: "black", width: "100%", height: "100%", - cross_alignment: "center", + cross_align: "center", rect { width: "50%", height: "100%", diff --git a/examples/rotate.rs b/examples/rotate.rs index c0a470cd8..a50800984 100644 --- a/examples/rotate.rs +++ b/examples/rotate.rs @@ -49,8 +49,8 @@ fn app(cx: Scope) -> Element { render!( rect { - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", width: "100%", height: "100%", rect { @@ -58,15 +58,15 @@ fn app(cx: Scope) -> Element { background: "rgb(65, 53, 67)", width: "250", height: "250", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", rect { rotate: "{degrees.1}deg", background: "rgb(143, 67, 238)", width: "180", height: "180", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", rect { rotate: "{degrees.2}deg", background: "rgb(240, 235, 141)", diff --git a/examples/tic_tac_toe.rs b/examples/tic_tac_toe.rs index b87c795ba..fef9d5660 100644 --- a/examples/tic_tac_toe.rs +++ b/examples/tic_tac_toe.rs @@ -160,8 +160,8 @@ fn app(cx: Scope) -> Element { rect { width: "100%", height: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", rect { width: "150", height: "170", @@ -184,8 +184,8 @@ fn app(cx: Scope) -> Element { corner_radius: "6", border: "2 solid rgb(40, 40, 40)", background: "rgb(250, 250, 250)", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", onclick: move |_| { let mut board = board.write(); if board.winner.is_none(){ diff --git a/examples/touch.rs b/examples/touch.rs index 22dd567ae..a1df8ff75 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -32,8 +32,8 @@ fn app(cx: Scope) -> Element { rect { width: "100%", height: "100%", - main_alignment: "center", - cross_alignment: "center", + main_align: "center", + cross_align: "center", background: "rgb(35, 35, 35)", ontouchcancel: ontouchcancel, ontouchend: ontouchend, diff --git a/examples/transition.rs b/examples/transition.rs index 11b3a3c8d..65f4de7d7 100644 --- a/examples/transition.rs +++ b/examples/transition.rs @@ -38,7 +38,7 @@ fn app(cx: Scope) -> Element { rect { overflow: "clip", background: "black", - main_alignment: "center", + main_align: "center", width: "100%", height: "100%", offset_x: "{size}", @@ -48,7 +48,7 @@ fn app(cx: Scope) -> Element { background: "{background}", padding: "25", corner_radius: "100", - main_alignment: "center", + main_align: "center", onclick: anim, label { width: "100%", From d6e548fc09bb5d03294b64312d627bd6a9dc7728 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 22 Oct 2023 10:20:10 +0200 Subject: [PATCH 21/26] fixes and cleanup --- book/src/guides/layout.md | 17 +++++++++-------- crates/state/src/layout.rs | 4 ++-- examples/alignment.rs | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/book/src/guides/layout.md b/book/src/guides/layout.md index d68bc8494..fb98c2ceb 100644 --- a/book/src/guides/layout.md +++ b/book/src/guides/layout.md @@ -2,9 +2,9 @@ Learn how the layout attributes work. -- [`width & height`](#width_&_height) -- [`min_width & min_height`](#min_width_&_min_height) -- [`max_width & max_height`](#max_width_&_max_height) +- [`width & height`](#width--height) +- [`min_width & min_height`](#min_width--min_height) +- [`max_width & max_height`](#max_width--max_height) - [`Size units`](#size_units) - [`Logical pixels`](#logical-pixels) - [`Percentages`](#percentages) @@ -12,7 +12,7 @@ Learn how the layout attributes work. - [`direction`](#direction) - [`padding`](#padding) - [`margin`](#margin) -- [`main_alignment & cross_alignment`](#main_alignment_&_cross_alignment) +- [`main_align & cross_align`](#main_align--cross_align) > ⚠️ Freya's layout is still somewhat limited. @@ -168,16 +168,17 @@ fn app(cx: Scope) -> Element { ``` -### main_alignment & cross_alignment +### main_align & cross_align Control how the inner elements are positioned inside the element. You can combine it with the `direction` attribute to create complex flows. -Possible values for both are: + +Possible values for both attributes are: - `start` (default): At the begining of the axis - `center`: At the center of the axis - `end`: At the end of the axis -When using the `vertical` direction, `main_alignment` will be the Y axis and `cross_alignment` will be the X axis. But when using the `horizontal` direction, the -`main_alignment` will be the X axis and the `cross_alignment` will be the Y axis. +When using the `vertical` direction, `main_align` will be the Y axis and `cross_align` will be the X axis. But when using the `horizontal` direction, the +`main_align` will be the X axis and the `cross_align` will be the Y axis. Example on how to center the inner elements in both axis: diff --git a/crates/state/src/layout.rs b/crates/state/src/layout.rs index bc9febcf6..0870e90cc 100644 --- a/crates/state/src/layout.rs +++ b/crates/state/src/layout.rs @@ -53,8 +53,8 @@ impl State for LayoutState { "direction", "offset_y", "offset_x", - "main_alignment", - "cross_alignment", + "main_align", + "cross_align", "reference", "margin", ])) diff --git a/examples/alignment.rs b/examples/alignment.rs index 72b75cbe1..136a977c9 100644 --- a/examples/alignment.rs +++ b/examples/alignment.rs @@ -37,9 +37,20 @@ fn app(cx: Scope) -> Element { background: "green" } rect { - width: "50", - height: "50", - background: "orange" + main_align: "center", + cross_align: "center", + background: "orange", + padding: "15", + rect { + width: "20", + height: "20", + background: "black" + } + rect { + width: "20", + height: "20", + background: "white" + } } } rect { From b0194ef81fcf2a5790b5c3a3bb9d837e90b26600 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 22 Oct 2023 11:49:46 +0200 Subject: [PATCH 22/26] fixes and improvements --- book/src/guides/layout.md | 2 +- crates/torin/src/measure.rs | 55 ++++++++----- crates/torin/src/measure_mode.rs | 127 ++++++++++++------------------- crates/torin/src/values/size.rs | 8 +- crates/torin/tests/test.rs | 80 +++++++++++++++++++ 5 files changed, 170 insertions(+), 102 deletions(-) diff --git a/book/src/guides/layout.md b/book/src/guides/layout.md index fb98c2ceb..f9fdcf1e1 100644 --- a/book/src/guides/layout.md +++ b/book/src/guides/layout.md @@ -125,7 +125,7 @@ fn app(cx: Scope) -> Element { ### direction -Control how the inner elements will be stacked, possible values are `horizontal`, `vertical` (default) or `both` (default for text elements, e.g label, paragraph, text, etc). +Control how the inner elements will be stacked, possible values are `vertical` (default) and `horizontal`. ##### Usage diff --git a/crates/torin/src/measure.rs b/crates/torin/src/measure.rs index 49cdf6003..0d892461d 100644 --- a/crates/torin/src/measure.rs +++ b/crates/torin/src/measure.rs @@ -92,17 +92,33 @@ pub fn measure_node( // 4. Compute the inner area of the Node, which is basically the area inside the margins and paddings let mut inner_area = { - let mut inner_area = area.after_gaps(&node.margin).after_gaps(&node.padding); + let mut inner_area = area; - // 4.1. When having an unsized bound we set it to whatever it is still available in the parent's area + // 4.1. When having an unsized bound we set it to whatever is still available in the parent's area if Size::Inner == node.width { - inner_area.size.width = available_parent_area.width() + inner_area.size.width = node.width.min_max( + available_parent_area.width(), + parent_area.size.width, + node.margin.left(), + node.margin.horizontal(), + &node.minimum_width, + &node.maximum_width, + ); } if Size::Inner == node.height { - inner_area.size.height = available_parent_area.height() + inner_area.size.height = node.height.min_max( + available_parent_area.height(), + parent_area.size.height, + node.margin.top(), + node.margin.vertical(), + &node.minimum_height, + &node.maximum_height, + ); } inner_area + .after_gaps(&node.padding) + .after_gaps(&node.margin) }; let mut inner_sizes = Size2D::default(); @@ -117,7 +133,6 @@ pub fn measure_node( let mut measurement_mode = MeasureMode::ParentIsNotCached { area: &mut area, inner_area: &mut inner_area, - padding: node.padding, }; // 6. Measure the layout of this Node's children @@ -175,8 +190,8 @@ pub fn measure_node( #[allow(clippy::too_many_arguments)] #[inline(always)] pub fn measure_inner_nodes( - node_id: &Key, - node: &Node, + parent_node_id: &Key, + parent_node: &Node, layout: &mut Torin, // Area available inside the Node available_area: &mut Area, @@ -193,7 +208,7 @@ pub fn measure_inner_nodes( available_area: &mut Area, inner_sizes: &mut Size2D, must_cache_inner_nodes: bool| { - let children = dom_adapter.children_of(node_id); + let children = dom_adapter.children_of(parent_node_id); for child_id in children { let inner_area = *mode.inner_area(); @@ -202,7 +217,7 @@ pub fn measure_inner_nodes( let mut adapted_available_area = *available_area; - if node.cross_alignment.is_not_start() { + if parent_node.cross_alignment.is_not_start() { // 1. First measure: Cross axis is not aligned let (_, child_areas) = measure_node( child_id, @@ -219,8 +234,8 @@ pub fn measure_inner_nodes( adapted_available_area.align_content( available_area, &child_areas.area.size, - &node.cross_alignment, - &node.direction, + &parent_node.cross_alignment, + &parent_node.direction, AlignmentDirection::Cross, ); } @@ -237,8 +252,8 @@ pub fn measure_inner_nodes( dom_adapter, ); - // Stack the child node - mode.stack_node(node, available_area, &child_areas.area, inner_sizes); + // Stack the child into its parent + mode.stack_into_node(parent_node, available_area, &child_areas.area, inner_sizes); // Cache the child layout if it was mutated and inner nodes must be cache if child_revalidated && must_cache_inner_nodes { @@ -254,7 +269,7 @@ pub fn measure_inner_nodes( let mut alignment_mode = alignment_mode.to_mut(); let mut inner_sizes = *inner_sizes; - if node.main_alignment.is_not_start() || node.cross_alignment.is_not_start() { + if parent_node.main_alignment.is_not_start() || parent_node.cross_alignment.is_not_start() { // 1. First measure: Main axis is not aligned measure_children( &mut alignment_mode, @@ -264,19 +279,19 @@ pub fn measure_inner_nodes( ); } - if node.cross_alignment.is_not_start() { + if parent_node.cross_alignment.is_not_start() { // 2. Adjust the available and inner areas of the Cross axis alignment_mode.fit_bounds_when_unspecified_and_aligned( - node, + parent_node, AlignmentDirection::Cross, available_area, ); } - if node.main_alignment.is_not_start() { + if parent_node.main_alignment.is_not_start() { // 3. Adjust the available and inner areas of the Main axis alignment_mode.fit_bounds_when_unspecified_and_aligned( - node, + parent_node, AlignmentDirection::Main, available_area, ); @@ -285,8 +300,8 @@ pub fn measure_inner_nodes( available_area.align_content( alignment_mode.inner_area(), &inner_sizes, - &node.main_alignment, - &node.direction, + &parent_node.main_alignment, + &parent_node.direction, AlignmentDirection::Main, ); } diff --git a/crates/torin/src/measure_mode.rs b/crates/torin/src/measure_mode.rs index 18d013218..d320077ad 100644 --- a/crates/torin/src/measure_mode.rs +++ b/crates/torin/src/measure_mode.rs @@ -1,5 +1,5 @@ use crate::prelude::{ - get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Gaps, Node, Size, Size2D, + get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Node, Size, Size2D, }; /// Measurement data for the inner Nodes of a Node @@ -11,7 +11,6 @@ pub enum MeasureMode<'a> { ParentIsNotCached { area: &'a mut Area, inner_area: &'a mut Area, - padding: Gaps, }, } @@ -30,15 +29,12 @@ impl<'a> MeasureMode<'a> { MeasureMode::ParentIsCached { inner_area } => OwnedMeasureMode::ParentIsCached { inner_area: *inner_area.to_owned(), }, - MeasureMode::ParentIsNotCached { - area, - inner_area, - padding, - } => OwnedMeasureMode::ParentIsNotCached { - area: **area.clone(), - inner_area: **inner_area.clone(), - padding: *padding, - }, + MeasureMode::ParentIsNotCached { area, inner_area } => { + OwnedMeasureMode::ParentIsNotCached { + area: **area.clone(), + inner_area: **inner_area.clone(), + } + } } } @@ -49,7 +45,7 @@ impl<'a> MeasureMode<'a> { /// of overflowing due to being aligned relatively to the upper parent element pub fn fit_bounds_when_unspecified_and_aligned( &mut self, - node: &Node, + parent_node: &Node, alignment_direction: AlignmentDirection, available_area: &mut Area, ) { @@ -65,47 +61,42 @@ impl<'a> MeasureMode<'a> { pub available_size: &'a mut f32, } - let axis = get_align_axis(&node.direction, alignment_direction); - let (is_vertical_not_start, is_horizontal_not_start) = match node.direction { + let axis = get_align_axis(&parent_node.direction, alignment_direction); + let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction { DirectionMode::Vertical => ( - node.main_alignment.is_not_start(), - node.cross_alignment.is_not_start(), + parent_node.main_alignment.is_not_start(), + parent_node.cross_alignment.is_not_start(), ), DirectionMode::Horizontal => ( - node.cross_alignment.is_not_start(), - node.main_alignment.is_not_start(), + parent_node.cross_alignment.is_not_start(), + parent_node.main_alignment.is_not_start(), ), }; - let params = if let MeasureMode::ParentIsNotCached { - area, - inner_area, - padding, - } = self - { + let params = if let MeasureMode::ParentIsNotCached { area, inner_area } = self { match axis { - AlignAxis::Height if Size::Inner == node.height && is_vertical_not_start => { + AlignAxis::Height if Size::Inner == parent_node.height && is_vertical_not_start => { Some(NodeData { inner_origin: &mut inner_area.origin.y, inner_size: &mut inner_area.size.height, area_origin: &mut area.origin.y, area_size: &mut area.size.height, - one_side_padding: node.padding.top(), - two_sides_padding: padding.vertical(), - one_side_margin: node.margin.top(), - two_sides_margin: node.margin.vertical(), + one_side_padding: parent_node.padding.top(), + two_sides_padding: parent_node.padding.vertical(), + one_side_margin: parent_node.margin.top(), + two_sides_margin: parent_node.margin.vertical(), available_size: &mut available_area.size.height, }) } - AlignAxis::Width if Size::Inner == node.width && is_horizontal_not_start => { + AlignAxis::Width if Size::Inner == parent_node.width && is_horizontal_not_start => { Some(NodeData { inner_origin: &mut inner_area.origin.x, inner_size: &mut inner_area.size.width, area_origin: &mut area.origin.x, area_size: &mut area.size.width, - one_side_padding: node.padding.left(), - two_sides_padding: padding.horizontal(), - one_side_margin: node.margin.left(), - two_sides_margin: node.margin.horizontal(), + one_side_padding: parent_node.padding.left(), + two_sides_padding: parent_node.padding.horizontal(), + one_side_margin: parent_node.margin.left(), + two_sides_margin: parent_node.margin.horizontal(), available_size: &mut available_area.size.width, }) } @@ -137,40 +128,38 @@ impl<'a> MeasureMode<'a> { } /// Stack a Node into another Node - pub fn stack_node( + pub fn stack_into_node( &mut self, - node: &Node, + parent_node: &Node, available_area: &mut Area, content_area: &Area, inner_sizes: &mut Size2D, ) { - match node.direction { + match parent_node.direction { DirectionMode::Horizontal => { // Move the available area available_area.origin.x = content_area.max_x(); available_area.size.width -= content_area.size.width; - if let MeasureMode::ParentIsNotCached { - area, - padding, - inner_area, - } = self - { + if let MeasureMode::ParentIsNotCached { area, inner_area } = self { inner_sizes.height = content_area.height().max(inner_sizes.height); inner_sizes.width += content_area.width(); // Keep the biggest height - if node.height == Size::Inner { + if parent_node.height == Size::Inner { area.size.height = area.size.height.max( - content_area.size.height + padding.vertical() + node.margin.vertical(), + content_area.size.height + + parent_node.padding.vertical() + + parent_node.margin.vertical(), ); // Keep the inner area in sync - inner_area.size.height = - area.size.height - padding.vertical() - node.margin.vertical(); + inner_area.size.height = area.size.height + - parent_node.padding.vertical() + - parent_node.margin.vertical(); } // Accumulate width - if node.width == Size::Inner { + if parent_node.width == Size::Inner { area.size.width += content_area.size.width; } } @@ -180,29 +169,25 @@ impl<'a> MeasureMode<'a> { available_area.origin.y = content_area.max_y(); available_area.size.height -= content_area.size.height; - if let MeasureMode::ParentIsNotCached { - area, - padding, - inner_area, - } = self - { + if let MeasureMode::ParentIsNotCached { area, inner_area } = self { inner_sizes.width = content_area.width().max(inner_sizes.width); inner_sizes.height += content_area.height(); // Keep the biggest width - if node.width == Size::Inner { + if parent_node.width == Size::Inner { area.size.width = area.size.width.max( content_area.size.width - + padding.horizontal() - + node.margin.horizontal(), + + parent_node.padding.horizontal() + + parent_node.margin.horizontal(), ); // Keep the inner area in sync - inner_area.size.width = - area.size.width - padding.horizontal() - node.margin.horizontal(); + inner_area.size.width = area.size.width + - parent_node.padding.horizontal() + - parent_node.margin.horizontal(); } // Accumulate height - if node.height == Size::Inner { + if parent_node.height == Size::Inner { area.size.height += content_area.size.height; } } @@ -214,29 +199,17 @@ impl<'a> MeasureMode<'a> { /// Just an owned version of [MeasureMode] #[derive(Debug)] pub enum OwnedMeasureMode { - ParentIsCached { - inner_area: Area, - }, - ParentIsNotCached { - area: Area, - inner_area: Area, - padding: Gaps, - }, + ParentIsCached { inner_area: Area }, + ParentIsNotCached { area: Area, inner_area: Area }, } impl OwnedMeasureMode { pub fn to_mut(&mut self) -> MeasureMode<'_> { match self { Self::ParentIsCached { inner_area } => MeasureMode::ParentIsCached { inner_area }, - Self::ParentIsNotCached { - area, - inner_area, - padding, - } => MeasureMode::ParentIsNotCached { - area, - inner_area, - padding: *padding, - }, + Self::ParentIsNotCached { area, inner_area } => { + MeasureMode::ParentIsNotCached { area, inner_area } + } } } } diff --git a/crates/torin/src/values/size.rs b/crates/torin/src/values/size.rs index 41f7e7d73..8dafc118f 100644 --- a/crates/torin/src/values/size.rs +++ b/crates/torin/src/values/size.rs @@ -37,9 +37,9 @@ impl Size { pub fn eval(&self, parent_value: f32, parent_margin: f32) -> Option { match self { Size::Pixels(px) => Some(px.get() + parent_margin), - Size::Percentage(per) => Some((parent_value / 100.0 * per.get()) - parent_margin), + Size::Percentage(per) => Some(parent_value / 100.0 * per.get()), Size::DynamicCalculations(calculations) => { - Some(run_calculations(calculations, parent_value, parent_margin)) + Some(run_calculations(calculations, parent_value)) } _ => None, } @@ -124,7 +124,7 @@ impl std::fmt::Display for DynamicCalculation { /// Calculate some chained operations with a given value. /// This value could be for example the width of a node's parent area. -pub fn run_calculations(calcs: &[DynamicCalculation], value: f32, parent_margin: f32) -> f32 { +pub fn run_calculations(calcs: &[DynamicCalculation], value: f32) -> f32 { let mut prev_number: Option = None; let mut prev_op: Option = None; @@ -153,7 +153,7 @@ pub fn run_calculations(calcs: &[DynamicCalculation], value: f32, parent_margin: for calc in calcs { match calc { DynamicCalculation::Percentage(per) => { - let val = (value / 100.0 * per).round() - parent_margin; + let val = (value / 100.0 * per).round(); calc_with_op(val, prev_op); diff --git a/crates/torin/tests/test.rs b/crates/torin/tests/test.rs index 1502af1e6..28b40508a 100644 --- a/crates/torin/tests/test.rs +++ b/crates/torin/tests/test.rs @@ -1284,3 +1284,83 @@ pub fn unsized_alignment() { Rect::new(Point2D::new(115.0, 25.0), Size2D::new(150.0, 80.0)), ); } + +#[test] +pub fn unsized_parent_with_child_with_margin() { + let (mut layout, mut measurer) = test_utils(); + + let mut mocked_dom = TestingDOM::default(); + mocked_dom.add( + 0, + None, + vec![1], + Node::from_size_and_direction(Size::Inner, Size::Inner, DirectionMode::Vertical), + ); + mocked_dom.add( + 1, + Some(0), + vec![], + Node::from_size_and_margin( + Size::Percentage(Length::new(100.0)), + Size::Percentage(Length::new(100.0)), + Gaps::new(10.0, 20.0, 30.0, 40.0), + ), + ); + + layout.measure( + 0, + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)), + &mut measurer, + &mut mocked_dom, + ); + + assert_eq!( + layout.get(0).unwrap().visible_area(), + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)), + ); + + assert_eq!( + layout.get(1).unwrap().visible_area(), + Rect::new(Point2D::new(40.0, 10.0), Size2D::new(940.0, 960.0)), + ); +} + +#[test] +pub fn unsized_parent_with_padding() { + let (mut layout, mut measurer) = test_utils(); + + let mut mocked_dom = TestingDOM::default(); + mocked_dom.add( + 0, + None, + vec![1], + Node::from_size_and_padding(Size::Inner, Size::Inner, Gaps::new(10.0, 20.0, 30.0, 40.0)), + ); + mocked_dom.add( + 1, + Some(0), + vec![], + Node::from_size_and_direction( + Size::Percentage(Length::new(100.0)), + Size::Percentage(Length::new(100.0)), + DirectionMode::Vertical, + ), + ); + + layout.measure( + 0, + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)), + &mut measurer, + &mut mocked_dom, + ); + + assert_eq!( + layout.get(0).unwrap().visible_area().round(), + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)), + ); + + assert_eq!( + layout.get(1).unwrap().visible_area().round(), + Rect::new(Point2D::new(40.0, 10.0), Size2D::new(940.0, 960.0)), + ); +} From 19b61aaad9e5b4fd6b8319a50adbb131ee761d93 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 22 Oct 2023 13:16:52 +0200 Subject: [PATCH 23/26] typo --- crates/torin/src/measure.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/torin/src/measure.rs b/crates/torin/src/measure.rs index 0d892461d..20f87eae6 100644 --- a/crates/torin/src/measure.rs +++ b/crates/torin/src/measure.rs @@ -124,7 +124,7 @@ pub fn measure_node( let mut inner_sizes = Size2D::default(); if measure_inner_children { - // 5. Create an area containin the available space inside the inner area + // 5. Create an area containing the available space inside the inner area let mut available_area = inner_area; // 5.1. Adjust the available area with the node offsets (mainly used by scrollviews) From 04bba37ff4b4a21f06bac566cb45d6eafaa626a0 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 22 Oct 2023 21:53:40 +0200 Subject: [PATCH 24/26] feat: Improve and optimize elements clipping --- crates/core/src/viewports.rs | 18 ++++++++++++------ crates/renderer/src/renderer.rs | 29 ++++++++++++++++++----------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/crates/core/src/viewports.rs b/crates/core/src/viewports.rs index 3417314b1..4688a4afd 100644 --- a/crates/core/src/viewports.rs +++ b/crates/core/src/viewports.rs @@ -36,19 +36,25 @@ pub fn calculate_viewports( viewports_collection .entry(*node_id) .or_insert_with(|| (None, Vec::new())) - .0 = Some(node_areas.area); + .0 = Some(node_areas.visible_area()); } // Pass viewports to the children if let Some((_, mut inherited_viewports)) = viewports_collection.get(node_id).cloned() { - // Add the itself - inherited_viewports.push(*node_id); + if !inherited_viewports.is_empty() { + // Add itself + inherited_viewports.push(*node_id); - for child in node.children() { - viewports_collection - .insert(child.id(), (None, inherited_viewports.clone())); + for child in node.children() { + if let NodeType::Element(..) = *child.node_type() { + viewports_collection + .entry(child.id()) + .or_insert_with(|| (None, Vec::new())) + .1 = inherited_viewports.clone(); + } + } } } } diff --git a/crates/renderer/src/renderer.rs b/crates/renderer/src/renderer.rs index c73f4609d..b04f03b97 100644 --- a/crates/renderer/src/renderer.rs +++ b/crates/renderer/src/renderer.rs @@ -10,6 +10,19 @@ use torin::geometry::Area; use crate::elements::{render_image, render_label, render_paragraph, render_rect, render_svg}; +fn clip_viewpot(canvas: &mut Canvas, viewport: &Area) { + canvas.clip_rect( + Rect::new( + viewport.min_x(), + viewport.min_y(), + viewport.max_x(), + viewport.max_y(), + ), + ClipOp::Intersect, + true, + ); +} + /// Render a node into the Skia canvas #[allow(clippy::too_many_arguments)] pub fn render_skia( @@ -53,20 +66,14 @@ pub fn render_skia( let viewports = viewports_collection.get(&dioxus_node.id()); // Clip all elements with their corresponding viewports - if let Some((_, viewports)) = viewports { + if let Some((element_viewport, viewports)) = viewports { + if let Some(element_viewport) = element_viewport { + clip_viewpot(canvas, element_viewport); + } for viewport_id in viewports { let viewport = viewports_collection.get(viewport_id).unwrap().0; if let Some(viewport) = viewport { - canvas.clip_rect( - Rect::new( - viewport.min_x(), - viewport.min_y(), - viewport.max_x(), - viewport.max_y(), - ), - ClipOp::Intersect, - true, - ); + clip_viewpot(canvas, &viewport); } } } From b2ae3117b3a17dda0ba9da913bac6799eca94a74 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Tue, 24 Oct 2023 18:02:46 +0200 Subject: [PATCH 25/26] improvements --- crates/core/src/viewports.rs | 10 ++++++---- crates/renderer/src/renderer.rs | 9 +++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/core/src/viewports.rs b/crates/core/src/viewports.rs index 4688a4afd..51d5008ea 100644 --- a/crates/core/src/viewports.rs +++ b/crates/core/src/viewports.rs @@ -33,17 +33,19 @@ pub fn calculate_viewports( // Clip any overflow from it's children if style.overflow == OverflowMode::Clip { - viewports_collection + let viewport = viewports_collection .entry(*node_id) - .or_insert_with(|| (None, Vec::new())) - .0 = Some(node_areas.visible_area()); + .or_insert_with(|| (None, Vec::new())); + viewport.0 = Some(node_areas.visible_area()); } // Pass viewports to the children if let Some((_, mut inherited_viewports)) = viewports_collection.get(node_id).cloned() { - if !inherited_viewports.is_empty() { + // Only pass the inherited viewports if they are not empty + // or this same element has a clipped overflow + if !inherited_viewports.is_empty() || style.overflow == OverflowMode::Clip { // Add itself inherited_viewports.push(*node_id); diff --git a/crates/renderer/src/renderer.rs b/crates/renderer/src/renderer.rs index b04f03b97..3cff5858d 100644 --- a/crates/renderer/src/renderer.rs +++ b/crates/renderer/src/renderer.rs @@ -67,8 +67,13 @@ pub fn render_skia( // Clip all elements with their corresponding viewports if let Some((element_viewport, viewports)) = viewports { - if let Some(element_viewport) = element_viewport { - clip_viewpot(canvas, element_viewport); + // Only clip the element iself when it's paragraph because + // it will render the inner text spans on it's own, so if these spans overflow the paragraph, + // It is the paragraph job to make sure they are clipped + if tag.as_str() == "paragraph" { + if let Some(element_viewport) = element_viewport { + clip_viewpot(canvas, element_viewport); + } } for viewport_id in viewports { let viewport = viewports_collection.get(viewport_id).unwrap().0; From fe8118328b832cef62c2f04a2fc934838f719701 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 26 Oct 2023 23:13:19 +0200 Subject: [PATCH 26/26] fix --- crates/renderer/src/renderer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/renderer/src/renderer.rs b/crates/renderer/src/renderer.rs index c5768a6c6..258d8d7a9 100644 --- a/crates/renderer/src/renderer.rs +++ b/crates/renderer/src/renderer.rs @@ -10,7 +10,7 @@ use torin::geometry::Area; use crate::elements::{render_image, render_label, render_paragraph, render_rect, render_svg}; -fn clip_viewpot(canvas: &mut Canvas, viewport: &Area) { +fn clip_viewport(canvas: &Canvas, viewport: &Area) { canvas.clip_rect( Rect::new( viewport.min_x(), @@ -72,13 +72,13 @@ pub fn render_skia( // It is the paragraph job to make sure they are clipped if tag.as_str() == "paragraph" { if let Some(element_viewport) = element_viewport { - clip_viewpot(canvas, element_viewport); + clip_viewport(canvas, element_viewport); } } for viewport_id in viewports { let viewport = viewports_collection.get(viewport_id).unwrap().0; if let Some(viewport) = viewport { - clip_viewpot(canvas, &viewport); + clip_viewport(canvas, &viewport); } } }