1pub mod callout;
7pub mod clip;
8pub mod container;
9pub mod dim_outside;
10pub mod flex_text;
11pub mod graphics;
12pub mod highlight;
13pub mod mesh;
14pub mod node;
15pub mod path;
16pub mod privacy_blur;
17pub mod sprite;
18pub mod text;
19pub mod transform;
20pub mod vector;
21
22use slotmap::SlotMap;
23
24pub use callout::Callout;
25pub use clip::MaskShape;
26pub use container::Container;
27pub use dim_outside::{DimOutside, DimStrength};
28pub use flex_text::FlexText;
29pub use graphics::{Fill, Graphics, Stroke};
30pub use highlight::Highlight;
31pub use mesh::Mesh;
32pub use node::{Node, NodeId};
33pub use path::{Path, PathBuilder, PathCommand};
34pub use privacy_blur::{BlurStrength, PrivacyBlur};
35pub use sprite::Sprite;
36pub use text::{Font, Text};
37pub use transform::Transform;
38pub use vector::{Vector, VectorShape, VectorStroke};
39
40pub struct Stage {
46 nodes: SlotMap<NodeId, Node>,
47 root: NodeId,
48}
49
50impl Stage {
51 #[must_use]
53 pub fn new() -> Self {
54 let mut nodes = SlotMap::with_key();
55 let root = nodes.insert(Node::from(Container::default()));
56 Self { nodes, root }
57 }
58
59 #[must_use]
61 pub fn root(&self) -> NodeId {
62 self.root
63 }
64
65 #[must_use]
67 pub fn len(&self) -> usize {
68 self.nodes.len()
69 }
70
71 #[must_use]
73 pub fn is_empty(&self) -> bool {
74 self.nodes.len() == 1
75 }
76
77 #[must_use]
79 pub fn get(&self, id: NodeId) -> Option<&Node> {
80 self.nodes.get(id)
81 }
82
83 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut Node> {
85 self.nodes.get_mut(id)
86 }
87
88 pub fn add_child(&mut self, parent: NodeId, child: impl Into<Node>) -> Option<NodeId> {
94 if !self.nodes.contains_key(parent) {
95 return None;
96 }
97 let id = self.nodes.insert(child.into());
98 if let Some(parent_node) = self.nodes.get_mut(parent) {
99 parent_node.container_mut().children.push(id);
100 }
101 if let Some(child_node) = self.nodes.get_mut(id) {
102 child_node.container_mut().parent = Some(parent);
103 }
104 Some(id)
105 }
106
107 pub fn detach(&mut self, child: NodeId) -> bool {
113 let parent_id = self.nodes.get(child).and_then(|n| n.container().parent());
114 let Some(parent_id) = parent_id else {
115 return false;
116 };
117 if let Some(parent) = self.nodes.get_mut(parent_id) {
118 parent.container_mut().children.retain(|&id| id != child);
119 }
120 if let Some(child_node) = self.nodes.get_mut(child) {
121 child_node.container_mut().parent = None;
122 }
123 true
124 }
125
126 pub fn destroy(&mut self, id: NodeId) -> bool {
131 if id == self.root {
132 return false;
133 }
134 if !self.nodes.contains_key(id) {
135 return false;
136 }
137 self.detach(id);
138 let descendants = self.collect_descendants(id);
139 for d in descendants {
140 self.nodes.remove(d);
141 }
142 self.nodes.remove(id);
143 true
144 }
145
146 pub fn traverse_pre_order(&self, start: NodeId, mut visit: impl FnMut(NodeId, &Node)) {
149 let mut stack: Vec<NodeId> = vec![start];
150 while let Some(id) = stack.pop() {
151 let Some(node) = self.nodes.get(id) else {
152 continue;
153 };
154 visit(id, node);
155 for child in node.container().children.iter().rev() {
157 stack.push(*child);
158 }
159 }
160 }
161
162 fn collect_descendants(&self, id: NodeId) -> Vec<NodeId> {
163 let mut out = Vec::new();
164 let mut stack: Vec<NodeId> = self
165 .nodes
166 .get(id)
167 .map(|n| n.container().children.clone())
168 .unwrap_or_default();
169 while let Some(curr) = stack.pop() {
170 out.push(curr);
171 if let Some(node) = self.nodes.get(curr) {
172 stack.extend(node.container().children.iter().copied());
173 }
174 }
175 out
176 }
177}
178
179impl Default for Stage {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn new_stage_has_only_root() {
191 let stage = Stage::new();
192 assert_eq!(stage.len(), 1);
193 assert!(stage.is_empty());
194 assert!(stage.get(stage.root()).is_some());
195 }
196
197 #[test]
198 fn add_child_returns_id_and_links_both_sides() {
199 let mut stage = Stage::new();
200 let root = stage.root();
201 let child = stage.add_child(root, Container::default()).expect("added");
202
203 assert_eq!(stage.len(), 2);
204 assert!(!stage.is_empty());
205 assert_eq!(stage.get(child).unwrap().container().parent(), Some(root));
206 assert_eq!(stage.get(root).unwrap().container().child_count(), 1);
207 }
208
209 #[test]
210 fn add_child_to_destroyed_parent_returns_none() {
211 let mut stage = Stage::new();
214 let temp = stage.add_child(stage.root(), Container::default()).unwrap();
215 assert!(stage.destroy(temp));
216 assert!(stage.add_child(temp, Container::default()).is_none());
217 }
218
219 #[test]
220 fn three_deep_hierarchy_traverses_pre_order() {
221 let mut stage = Stage::new();
222 let root = stage.root();
223 let a = stage.add_child(root, Container::default()).unwrap();
224 let b = stage.add_child(a, Container::default()).unwrap();
225 let c = stage.add_child(b, Container::default()).unwrap();
226 let d = stage.add_child(root, Container::default()).unwrap();
228
229 let mut order = Vec::new();
230 stage.traverse_pre_order(root, |id, _| order.push(id));
231 assert_eq!(order, vec![root, a, b, c, d]);
232 }
233
234 #[test]
235 fn detach_removes_from_parent_but_keeps_node() {
236 let mut stage = Stage::new();
237 let root = stage.root();
238 let child = stage.add_child(root, Container::default()).unwrap();
239
240 assert!(stage.detach(child));
241 assert_eq!(stage.get(root).unwrap().container().child_count(), 0);
242 assert_eq!(stage.get(child).unwrap().container().parent(), None);
243 assert!(stage.get(child).is_some()); }
245
246 #[test]
247 fn destroy_cascades_to_descendants() {
248 let mut stage = Stage::new();
249 let root = stage.root();
250 let a = stage.add_child(root, Container::default()).unwrap();
251 let b = stage.add_child(a, Container::default()).unwrap();
252 let _c = stage.add_child(b, Container::default()).unwrap();
253
254 assert_eq!(stage.len(), 4);
255 assert!(stage.destroy(a));
256 assert_eq!(stage.len(), 1);
258 assert_eq!(stage.get(root).unwrap().container().child_count(), 0);
259 }
260
261 #[test]
262 fn destroy_root_is_rejected() {
263 let mut stage = Stage::new();
264 assert!(!stage.destroy(stage.root()));
265 assert_eq!(stage.len(), 1);
266 }
267}