polyhorn_ui/layout/
tree.rs

1use std::collections::HashMap;
2use std::sync::{Arc, RwLock};
3
4use super::algorithm::{Algorithm, Flexbox, Node};
5use crate::geometry::{Dimension, Point, Size};
6use crate::styles::ViewStyle;
7
8/// Measure function that is called to obtain the intrinsic content size of a
9/// leaf node (e.g. images or text).
10#[derive(Clone)]
11pub enum MeasureFunc {
12    /// Measure function backed by a boxed closure.
13    Boxed(Arc<dyn Fn(Size<Dimension<f32>>) -> Size<f32> + Send + Sync>),
14}
15
16impl std::fmt::Debug for MeasureFunc {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_tuple("MeasureFunc").finish()
19    }
20}
21
22/// Computed layout of a node.
23pub struct Layout {
24    /// The origin of a node.
25    pub origin: Point<f32>,
26
27    /// The size of a node.
28    pub size: Size<f32>,
29}
30
31/// LayoutTree that manages the flexbox algorithm and some additional details,
32/// like the roots of the layout tree.
33pub struct LayoutTree {
34    flexbox: Flexbox,
35    parents: HashMap<Node, Node>,
36    roots: Vec<Node>,
37}
38
39impl LayoutTree {
40    /// Returns a new layout tree.
41    pub fn new() -> LayoutTree {
42        LayoutTree {
43            flexbox: Flexbox::new(),
44            parents: HashMap::new(),
45            roots: vec![],
46        }
47    }
48
49    /// Returns a reference to the underlying flexbox implementation.
50    pub fn flexbox(&self) -> &Flexbox {
51        &self.flexbox
52    }
53
54    /// Returns a mutable reference to the underlying flexbox implementation.
55    pub fn flexbox_mut(&mut self) -> &mut Flexbox {
56        &mut self.flexbox
57    }
58
59    /// Returns a reference to the roots of the layout tree.
60    pub fn roots(&self) -> &[Node] {
61        self.roots.as_slice()
62    }
63
64    /// Returns a mutable reference to the roots of the layout tree.
65    pub fn roots_mut(&mut self) -> &mut Vec<Node> {
66        &mut self.roots
67    }
68
69    /// Adds a child node to a parent node within the layout tree. It also keeps
70    /// track of the parent by itself, so that we don't need to remember which
71    /// parent the child belongs to when we want to remove it.
72    pub fn add_child(&mut self, parent: Node, child: Node) {
73        self.parents.insert(child, parent);
74        self.flexbox.add_child(parent, child);
75    }
76
77    /// Removes the given node from the layout tree. Note that the layout tree
78    /// internally stores a reference to the parent node of every child node, so
79    /// we don't have to pass that to this function.
80    pub fn remove(&mut self, node: Node) {
81        if let Some(parent) = self.parents.remove(&node) {
82            self.flexbox.remove_child(parent, node);
83        }
84
85        assert_eq!(self.flexbox.child_count(node), 0);
86
87        self.flexbox.remove(node);
88    }
89
90    /// Recomputes the layout of all roots of the layout tree.
91    pub fn recompute_roots(&mut self) {
92        for node in self.roots().to_owned() {
93            let size = self.flexbox().layout(node).size;
94
95            self.flexbox_mut().compute_layout(
96                node,
97                Size {
98                    width: Dimension::Points(size.width),
99                    height: Dimension::Points(size.height),
100                },
101            );
102        }
103    }
104}
105
106/// Handle to a node within the layout tree.
107#[derive(Clone)]
108pub struct LayoutNode {
109    layouter: Arc<RwLock<LayoutTree>>,
110    node: Node,
111}
112
113impl LayoutNode {
114    /// Creates a new branch in the layout tree.
115    pub fn new(layouter: Arc<RwLock<LayoutTree>>) -> LayoutNode {
116        let node = layouter
117            .write()
118            .unwrap()
119            .flexbox_mut()
120            .new_node(Default::default(), &[]);
121
122        LayoutNode { layouter, node }
123    }
124
125    /// Creates a new leaf in the layout tree.
126    pub fn leaf(layouter: Arc<RwLock<LayoutTree>>) -> LayoutNode {
127        let node = layouter.write().unwrap().flexbox_mut().new_leaf(
128            Default::default(),
129            MeasureFunc::Boxed(Arc::new(|_| Size {
130                width: 0.0,
131                height: 0.0,
132            })),
133        );
134
135        LayoutNode { layouter, node }
136    }
137
138    /// Returns a shared reference to the layout tree.
139    pub fn layouter(&self) -> &Arc<RwLock<LayoutTree>> {
140        &self.layouter
141    }
142
143    /// Returns the ID of this node.
144    pub fn node(&self) -> Node {
145        self.node
146    }
147
148    /// Updates the measure function of this node without recomputing its layout
149    /// or any of its ancestors' layouts.
150    pub fn set_measure(&self, measure: MeasureFunc) {
151        self.layouter
152            .write()
153            .unwrap()
154            .flexbox_mut()
155            .set_measure(self.node, measure);
156    }
157
158    /// Updates the style of this node without recomputing its layout or any of
159    /// its ancestors' layouts.
160    pub fn set_style(&self, style: ViewStyle) {
161        self.layouter
162            .write()
163            .unwrap()
164            .flexbox_mut()
165            .set_style(self.node, style)
166    }
167
168    /// Recomputes the layout of this node, respecting the given container size.
169    pub fn compute(&mut self, size: Option<(f32, f32)>) {
170        let size = match size {
171            Some((width, height)) => Size {
172                width: Dimension::Points(width),
173                height: Dimension::Points(height),
174            },
175            None => Size {
176                width: Dimension::Undefined,
177                height: Dimension::Undefined,
178            },
179        };
180
181        self.layouter
182            .write()
183            .unwrap()
184            .flexbox_mut()
185            .compute_layout(self.node, size);
186    }
187
188    /// Returns the current computed layout.
189    pub fn current(&self) -> Layout {
190        self.layouter.read().unwrap().flexbox().layout(self.node)
191    }
192}