1use taffy::prelude::*;
8
9use crate::focus::FocusId;
10
11pub struct Layout {
13 tree: TaffyTree<Option<FocusId>>,
14}
15
16impl std::fmt::Debug for Layout {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.debug_struct("Layout").finish_non_exhaustive()
19 }
20}
21
22impl Default for Layout {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl Layout {
29 pub fn new() -> Self {
31 Self {
32 tree: TaffyTree::new(),
33 }
34 }
35
36 pub fn add_node(&mut self, style: Style, id: Option<FocusId>) -> NodeId {
38 self.tree
39 .new_leaf_with_context(style, id)
40 .expect("taffy: failed to create leaf node")
41 }
42
43 pub fn add_child(&mut self, parent: NodeId, child: NodeId) {
45 self.tree
46 .add_child(parent, child)
47 .expect("taffy: failed to add child");
48 }
49
50 pub fn compute(&mut self, root: NodeId, available: Size<AvailableSpace>) {
52 self.tree
53 .compute_layout(root, available)
54 .expect("taffy: layout computation failed");
55 }
56
57 pub fn get_layout(&self, node: NodeId) -> &taffy::tree::Layout {
59 self.tree
60 .layout(node)
61 .expect("taffy: layout not computed for node")
62 }
63
64 pub fn clear(&mut self) {
66 self.tree.clear();
67 }
68}
69
70#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn add_node_and_get_layout() {
80 let mut layout = Layout::new();
81 let root = layout.add_node(
82 Style {
83 size: Size {
84 width: length(100.0),
85 height: length(50.0),
86 },
87 ..Default::default()
88 },
89 None,
90 );
91 layout.compute(root, Size::MAX_CONTENT);
92
93 let result = layout.get_layout(root);
94 assert!((result.size.width - 100.0).abs() < f32::EPSILON);
95 assert!((result.size.height - 50.0).abs() < f32::EPSILON);
96 }
97
98 #[test]
99 fn parent_child_layout() {
100 let mut layout = Layout::new();
101
102 let child = layout.add_node(
103 Style {
104 size: Size {
105 width: length(40.0),
106 height: length(20.0),
107 },
108 ..Default::default()
109 },
110 Some(FocusId(1)),
111 );
112
113 let parent = layout.add_node(
114 Style {
115 size: Size {
116 width: length(200.0),
117 height: length(100.0),
118 },
119 ..Default::default()
120 },
121 None,
122 );
123
124 layout.add_child(parent, child);
125 layout.compute(parent, Size::MAX_CONTENT);
126
127 let child_layout = layout.get_layout(child);
128 assert!((child_layout.size.width - 40.0).abs() < f32::EPSILON);
129 assert!((child_layout.size.height - 20.0).abs() < f32::EPSILON);
130
131 assert!((child_layout.location.x).abs() < f32::EPSILON);
133 assert!((child_layout.location.y).abs() < f32::EPSILON);
134 }
135
136 #[test]
137 fn clear_allows_reuse() {
138 let mut layout = Layout::new();
139 let _node = layout.add_node(Style::default(), None);
140 layout.clear();
141
142 let root = layout.add_node(
144 Style {
145 size: Size {
146 width: length(10.0),
147 height: length(10.0),
148 },
149 ..Default::default()
150 },
151 None,
152 );
153 layout.compute(root, Size::MAX_CONTENT);
154 let result = layout.get_layout(root);
155 assert!((result.size.width - 10.0).abs() < f32::EPSILON);
156 }
157}