gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 87Markdown 12TOML 91924 Sutichaykuna

fix re-computing layout moves children of non-zero positioned parent

b5db37a5a102ba70f70baba27a38fd63a2233cef · ruwaq Evan Almloff · (4 wata ñawpaq) · tayta f4b815e8e · kay commitpi sach'ata qhaway

Semántico sayk'uy · 7

src/algo.rs

src/result.rs

  • silq'uyninpi t'ikrakurqan struct Layout pub
  • ukhunpi t'ikrakurqan def new

tests/relayout.rs

3 qillqakuna · +78 −8

diff --git a/src/algo.rs b/src/algo.rs
index 758a3a862..e40e1cb0b 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -89,7 +89,8 @@ impl Forest {
             self.compute_internal(root, style.size.resolve(size), size, true, true)
         };
 
-        self.nodes[root].layout = result::Layout { order: 0, size: result.size, location: Point::zero() };
+        self.nodes[root].layout =
+            result::Layout { order: 0, size: result.size, location: Point::zero(), relative_location: Point::zero() };
 
         Self::round_layout(&mut self.nodes, &self.children, root, 0.0, 0.0);
     }
@@ -102,15 +103,15 @@ impl Forest {
         abs_y: f32,
     ) {
         let layout = &mut nodes[root].layout;
-        let abs_x = abs_x + layout.location.x;
-        let abs_y = abs_y + layout.location.y;
+        let abs_x = abs_x + layout.relative_location.x;
+        let abs_y = abs_y + layout.relative_location.y;
 
         layout.location.x = sys::round(abs_x);
         layout.location.y = sys::round(abs_y);
 
         layout.size.width = sys::round(abs_x + layout.size.width) - sys::round(abs_x);
         layout.size.height = sys::round(abs_y + layout.size.height) - sys::round(abs_y);
-        
+
         for child in &children[root] {
             Self::round_layout(nodes, children, *child, abs_x, abs_y);
         }
@@ -748,6 +749,7 @@ impl Forest {
                             order: self.children[node].iter().position(|n| *n == child.node).unwrap() as u32,
                             size: result.size,
                             location: Point::zero(),
+                            relative_location: Point::zero(),
                         },
                     );
                 }
@@ -1154,7 +1156,8 @@ impl Forest {
                     self.nodes[child.node].layout = result::Layout {
                         order: self.children[node].iter().position(|n| *n == child.node).unwrap() as u32,
                         size: result.size,
-                        location: Point {
+                        location: Point::zero(),
+                        relative_location: Point {
                             x: if is_row { offset_main } else { offset_cross },
                             y: if is_column { offset_main } else { offset_cross },
                         },
@@ -1303,16 +1306,18 @@ impl Forest {
                 self.nodes[child].layout = result::Layout {
                     order: order as u32,
                     size: result.size,
-                    location: Point {
+                    relative_location: Point {
                         x: if is_row { offset_main } else { offset_cross },
                         y: if is_column { offset_main } else { offset_cross },
                     },
+                    location: Point::zero(),
                 };
             }
         }
 
         fn hidden_layout(nodes: &mut [NodeData], children: &[sys::ChildrenVec<NodeId>], node: NodeId, order: u32) {
-            nodes[node].layout = result::Layout { order, size: Size::zero(), location: Point::zero() };
+            nodes[node].layout =
+                result::Layout { order, size: Size::zero(), location: Point::zero(), relative_location: Point::zero() };
 
             for (order, child) in children[node].iter().enumerate() {
                 hidden_layout(nodes, children, *child, order as _);
diff --git a/src/result.rs b/src/result.rs
index ff3619fe3..3ca8da767 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -8,11 +8,12 @@ pub struct Layout {
     pub(crate) order: u32,
     pub size: Size<f32>,
     pub location: Point<f32>,
+    pub(crate) relative_location: Point<f32>,
 }
 
 impl Layout {
     pub(crate) fn new() -> Self {
-        Self { order: 0, size: Size::zero(), location: Point::zero() }
+        Self { order: 0, size: Size::zero(), location: Point::zero(), relative_location: Point::zero() }
     }
 }
 
diff --git a/tests/relayout.rs b/tests/relayout.rs
new file mode 100644
index 000000000..2ed73901a
--- /dev/null
+++ b/tests/relayout.rs
@@ -0,0 +1,64 @@
+use stretch::style::Dimension;
+use stretch2 as stretch;
+
+#[test]
+fn relayout() {
+    let mut stretch = stretch::Stretch::new();
+    let node1 = stretch
+        .new_node(
+            stretch::style::Style {
+                size: stretch::geometry::Size { width: Dimension::Points(8f32), height: Dimension::Points(80f32) },
+                ..Default::default()
+            },
+            &[],
+        )
+        .unwrap();
+    let node0 = stretch
+        .new_node(
+            stretch::style::Style {
+                align_self: stretch::prelude::AlignSelf::Center,
+                size: stretch::geometry::Size { width: Dimension::Auto, height: Dimension::Auto },
+                // size: stretch::geometry::Size { width: Dimension::Percent(1.0), height: Dimension::Percent(1.0) },
+                ..Default::default()
+            },
+            &[node1],
+        )
+        .unwrap();
+    let node = stretch
+        .new_node(
+            stretch::style::Style {
+                size: stretch::geometry::Size { width: Dimension::Percent(1f32), height: Dimension::Percent(1f32) },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    println!("0:");
+    stretch
+        .compute_layout(
+            node,
+            stretch::geometry::Size {
+                width: stretch::prelude::Number::Defined(100f32),
+                height: stretch::prelude::Number::Defined(100f32),
+            },
+        )
+        .unwrap();
+    let initial = stretch.layout(node).unwrap().location;
+    let initial0 = stretch.layout(node0).unwrap().location;
+    let initial1 = stretch.layout(node1).unwrap().location;
+    for i in 1..10 {
+        println!("\n\n{i}:");
+        stretch
+            .compute_layout(
+                node,
+                stretch::geometry::Size {
+                    width: stretch::prelude::Number::Defined(100f32),
+                    height: stretch::prelude::Number::Defined(100f32),
+                },
+            )
+            .unwrap();
+        assert_eq!(stretch.layout(node).unwrap().location, initial);
+        assert_eq!(stretch.layout(node0).unwrap().location, initial0);
+        assert_eq!(stretch.layout(node1).unwrap().location, initial1);
+    }
+}