tidy_tree/layout/
basic_layout.rs

1use num::Float;
2
3use super::Layout;
4use crate::{geometry::Coord, node::Node};
5use std::cmp::{max, min};
6
7/// <img src="https://i.ibb.co/BLCfz0g/image.png" width="300" alt="Relative position"/>
8///
9/// Relative position illustration
10pub struct BasicLayout {
11    pub parent_child_margin: Coord,
12    pub peer_margin: Coord,
13}
14
15/// <img src="https://i.ibb.co/BLCfz0g/image.png" width="300" alt="Relative position"/>
16///
17/// Relative position illustration
18#[derive(Debug, Clone)]
19pub struct BoundingBox {
20    pub total_width: Coord,
21    pub total_height: Coord,
22}
23
24impl Default for BoundingBox {
25    fn default() -> Self {
26        Self {
27            total_height: 0.,
28            total_width: 0.,
29        }
30    }
31}
32
33impl Layout for BasicLayout {
34    fn layout(&mut self, root: &mut Node) {
35        root.pre_order_traversal_mut(|node| {
36            node.tidy = None;
37            node.x = 0.;
38            node.y = 0.;
39            node.relative_x = 0.;
40            node.relative_y = 0.;
41        });
42        root.post_order_traversal_mut(|node| {
43            self.update_meta(node);
44        });
45        root.pre_order_traversal_mut(|node| {
46            if let Some(mut parent) = node.parent {
47                let parent = unsafe { parent.as_mut() };
48                node.x = parent.x + node.relative_x;
49                node.y = parent.y + node.relative_y;
50            }
51        });
52    }
53
54    fn partial_layout(&mut self, root: &mut Node, changed: &[std::ptr::NonNull<Node>]) {
55        todo!()
56    }
57
58    fn parent_child_margin(&self) -> Coord {
59        self.parent_child_margin
60    }
61
62    fn peer_margin(&self) -> Coord {
63        self.peer_margin
64    }
65}
66
67impl BasicLayout {
68    fn update_meta(&mut self, node: &mut Node) {
69        node.bbox = BoundingBox {
70            total_height: node.height,
71            total_width: node.width,
72        };
73        let children: *mut _ = &mut node.children;
74        let children = unsafe { &mut *children };
75        let n = children.len() as Coord;
76        if n > 0. {
77            let mut temp_x = 0.;
78            let mut max_height = 0.;
79            let n = children.len();
80            for (i, child) in children.iter_mut().enumerate() {
81                child.relative_y = node.height + self.parent_child_margin;
82                child.relative_x = temp_x + child.bbox.total_width / 2.;
83                temp_x += child.bbox.total_width + self.peer_margin;
84                max_height = Float::max(child.bbox.total_height, max_height);
85            }
86
87            let children_width = temp_x - self.peer_margin;
88            let shift_x = -children_width / 2.;
89            for child in children.iter_mut() {
90                child.relative_x += shift_x;
91            }
92
93            node.bbox.total_width = Float::max(children_width, node.width);
94            node.bbox.total_height = node.height + self.parent_child_margin + max_height;
95        }
96    }
97}
98
99#[cfg(test)]
100mod basic_layout_test {
101    use super::{BasicLayout, BoundingBox};
102    use crate::{layout::Layout, Node};
103
104    #[test]
105    fn easy_test_0() {
106        let mut root = Node::new(0, 10., 10.);
107        root.append_child(Node::new(1, 10., 10.));
108        let mut second = Node::new(2, 10., 10.);
109        second.append_child(Node::new(3, 10., 10.));
110        root.append_child(second);
111        root.append_child(Node::new(4, 10., 10.));
112        let mut layout = BasicLayout {
113            parent_child_margin: 10.,
114            peer_margin: 5.,
115        };
116        layout.layout(&mut root);
117        println!("{:#?}", root);
118    }
119}