From 7f7d447e5e5f70db42013b29d599ddb3b6b93005 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 5 Nov 2023 22:07:31 +0100 Subject: [PATCH] feat: Absolute positioning --- crates/dom/src/dom_adapter.rs | 35 ++++++++++++------------ crates/elements/src/elements.rs | 1 + crates/state/src/layout.rs | 9 +++++++ crates/state/src/values/mod.rs | 2 ++ crates/state/src/values/position.rs | 16 +++++++++++ crates/torin/src/measure.rs | 17 +++++++++--- crates/torin/src/measure_mode.rs | 8 +++++- crates/torin/src/node.rs | 5 +++- crates/torin/src/values/mod.rs | 2 ++ crates/torin/src/values/position.rs | 7 +++++ examples/position.rs | 41 +++++++++++++++++++++++++++++ 11 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 crates/state/src/values/position.rs create mode 100644 crates/torin/src/values/position.rs create mode 100644 examples/position.rs diff --git a/crates/dom/src/dom_adapter.rs b/crates/dom/src/dom_adapter.rs index dbd95c85a..5f7430b9b 100644 --- a/crates/dom/src/dom_adapter.rs +++ b/crates/dom/src/dom_adapter.rs @@ -31,29 +31,30 @@ impl<'a> DioxusDOMAdapter<'a> { impl DOMAdapter for DioxusDOMAdapter<'_> { fn get_node(&self, node_id: &NodeId) -> Option { let node = self.rdom.get(*node_id)?; - let mut size = node.get::().unwrap().clone(); + let mut layout = node.get::().unwrap().clone(); // The root node expands by default if *node_id == self.rdom.root_id() { - size.width = Size::Percentage(Length::new(100.0)); - size.height = Size::Percentage(Length::new(100.0)); + layout.width = Size::Percentage(Length::new(100.0)); + layout.height = Size::Percentage(Length::new(100.0)); } Some(Node { - width: size.width, - height: size.height, - minimum_width: size.minimum_width, - minimum_height: size.minimum_height, - maximum_width: size.maximum_width, - maximum_height: size.maximum_height, - direction: size.direction, - padding: size.padding, - margin: size.margin, - 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(), + width: layout.width, + height: layout.height, + minimum_width: layout.minimum_width, + minimum_height: layout.minimum_height, + maximum_width: layout.maximum_width, + maximum_height: layout.maximum_height, + direction: layout.direction, + padding: layout.padding, + margin: layout.margin, + main_alignment: layout.main_alignment, + cross_alignment: layout.cross_alignment, + offset_x: Length::new(layout.offset_x), + offset_y: Length::new(layout.offset_y), + has_layout_references: layout.node_ref.is_some(), + position: layout.position, }) } diff --git a/crates/elements/src/elements.rs b/crates/elements/src/elements.rs index 524a71d0a..49a31c051 100644 --- a/crates/elements/src/elements.rs +++ b/crates/elements/src/elements.rs @@ -191,6 +191,7 @@ builder_constructors! { name: String, focusable: String, margin: String, + position: String, }; label { color: String, diff --git a/crates/state/src/layout.rs b/crates/state/src/layout.rs index 0870e90cc..a94a33eb5 100644 --- a/crates/state/src/layout.rs +++ b/crates/state/src/layout.rs @@ -30,6 +30,7 @@ pub struct LayoutState { pub offset_x: f32, pub main_alignment: Alignment, pub cross_alignment: Alignment, + pub position: Position, pub node_ref: Option>, } @@ -57,6 +58,7 @@ impl State for LayoutState { "cross_align", "reference", "margin", + "position", ])) .with_tag() .with_text(); @@ -190,6 +192,13 @@ impl State for LayoutState { } } } + "position" => { + if let Some(value) = attr.value.as_text() { + if let Ok(position) = Position::parse(value) { + layout.position = position; + } + } + } "reference" => { if let OwnedAttributeValue::Custom(CustomAttributeValues::Reference( reference, diff --git a/crates/state/src/values/mod.rs b/crates/state/src/values/mod.rs index 3891a5e41..6d851aaaf 100644 --- a/crates/state/src/values/mod.rs +++ b/crates/state/src/values/mod.rs @@ -10,6 +10,7 @@ mod font; mod gaps; mod gradient; mod overflow; +mod position; mod shadow; mod size; mod text_shadow; @@ -26,6 +27,7 @@ pub use font::*; pub use gaps::*; pub use gradient::*; pub use overflow::*; +pub use position::*; pub use shadow::*; pub use size::*; pub use text_shadow::*; diff --git a/crates/state/src/values/position.rs b/crates/state/src/values/position.rs new file mode 100644 index 000000000..6ad86ad4b --- /dev/null +++ b/crates/state/src/values/position.rs @@ -0,0 +1,16 @@ +use crate::Parse; +use torin::position::Position; + +#[derive(Debug, PartialEq, Eq)] +pub struct ParsePositionError; + +impl Parse for Position { + type Err = ParsePositionError; + + fn parse(value: &str) -> Result { + Ok(match value { + "absolute" => Position::Absolute, + _ => Position::Stacked, + }) + } +} diff --git a/crates/torin/src/measure.rs b/crates/torin/src/measure.rs index 20f87eae6..4b85cf259 100644 --- a/crates/torin/src/measure.rs +++ b/crates/torin/src/measure.rs @@ -6,7 +6,7 @@ use crate::{ geometry::{Area, Size2D}, measure_mode::MeasureMode, node::Node, - prelude::{AlignmentDirection, AreaModel, Torin}, + prelude::{AlignmentDirection, AreaModel, Position, Torin}, size::Size, }; @@ -29,9 +29,14 @@ pub fn measure_node( ) -> (bool, NodeAreas) { let must_run = layout.dirty.contains(&node_id) || layout.results.get(&node_id).is_none(); if must_run { + let origin = match node.position { + Position::Stacked => available_parent_area.origin, + Position::Absolute => parent_area.origin, + }; + // 1. Create the initial Node area let mut area = Rect::new( - available_parent_area.origin, + origin, Size2D::new(node.padding.horizontal(), node.padding.vertical()), ); @@ -253,7 +258,13 @@ pub fn measure_inner_nodes( ); // Stack the child into its parent - mode.stack_into_node(parent_node, available_area, &child_areas.area, inner_sizes); + mode.stack_into_node( + parent_node, + available_area, + &child_areas.area, + inner_sizes, + &child_data, + ); // Cache the child layout if it was mutated and inner nodes must be cache if child_revalidated && must_cache_inner_nodes { diff --git a/crates/torin/src/measure_mode.rs b/crates/torin/src/measure_mode.rs index 78cd6c464..a9c73dc3c 100644 --- a/crates/torin/src/measure_mode.rs +++ b/crates/torin/src/measure_mode.rs @@ -1,5 +1,6 @@ use crate::prelude::{ - get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Node, Size, Size2D, + get_align_axis, AlignAxis, AlignmentDirection, Area, DirectionMode, Node, Position, Size, + Size2D, }; /// Measurement data for the inner Nodes of a Node @@ -134,7 +135,12 @@ impl<'a> MeasureMode<'a> { available_area: &mut Area, content_area: &Area, inner_sizes: &mut Size2D, + node_data: &Node, ) { + if node_data.position == Position::Absolute { + return; + } + match parent_node.direction { DirectionMode::Horizontal => { // Move the available area diff --git a/crates/torin/src/node.rs b/crates/torin/src/node.rs index cd439cc7d..3ed12a587 100644 --- a/crates/torin/src/node.rs +++ b/crates/torin/src/node.rs @@ -1,7 +1,8 @@ pub use euclid::Rect; use crate::{ - alignment::Alignment, direction::DirectionMode, gaps::Gaps, geometry::Length, size::Size, + alignment::Alignment, direction::DirectionMode, gaps::Gaps, geometry::Length, + prelude::Position, size::Size, }; /// Node layout configuration @@ -36,6 +37,8 @@ pub struct Node { /// Direction in which it's inner Nodes will be stacked pub direction: DirectionMode, + pub position: Position, + /// A Node might depend on inner sizes but have a fixed position, like scroll views. pub has_layout_references: bool, } diff --git a/crates/torin/src/values/mod.rs b/crates/torin/src/values/mod.rs index 24128385b..4f5c75fbc 100644 --- a/crates/torin/src/values/mod.rs +++ b/crates/torin/src/values/mod.rs @@ -1,11 +1,13 @@ pub mod alignment; pub mod direction; pub mod gaps; +pub mod position; pub mod size; pub mod prelude { pub use crate::alignment::*; pub use crate::direction::*; pub use crate::gaps::*; + pub use crate::position::*; pub use crate::size::*; } diff --git a/crates/torin/src/values/position.rs b/crates/torin/src/values/position.rs new file mode 100644 index 000000000..9b33904f7 --- /dev/null +++ b/crates/torin/src/values/position.rs @@ -0,0 +1,7 @@ +#[derive(Default, PartialEq, Eq, Debug, Clone)] +pub enum Position { + #[default] + Stacked, + + Absolute, +} diff --git a/examples/position.rs b/examples/position.rs new file mode 100644 index 000000000..34623782e --- /dev/null +++ b/examples/position.rs @@ -0,0 +1,41 @@ +#![cfg_attr( + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" +)] + +use freya::prelude::*; + +fn main() { + launch_with_props(app, "Position", (400.0, 350.0)); +} + +fn app(cx: Scope) -> Element { + render!( + rect { + height: "100%", + width: "100%", + rect { + height: "20%", + width: "100%", + background: "green", + } + rect { + height: "100", + width: "100", + background: "red", + position: "absolute", + layer: "-1" + } + rect { + height: "20%", + width: "100%", + background: "orange", + } + rect { + height: "20%", + width: "100%", + background: "yellow", + } + } + ) +}