⎇ 23ff477566b0239f04d3b89a2b3a4da2495e9577
src/tree/taffy_tree/tree.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
Remove `LayoutAlgorithm` trait (#562)
1//! UI node types and related data structures.
2//!
3//! Layouts are composed of multiple nodes, which live in a tree-like data structure.
4use slotmap::{DefaultKey, SlotMap, SparseSecondaryMap};
5
6use crate::compute::taffy_tree::{compute_layout, compute_node_layout};
7use crate::geometry::{Line, Size};
8use crate::prelude::LayoutTree;
9use crate::style::{AvailableSpace, Style};
10use crate::tree::{Layout, LayoutInput, LayoutOutput, NodeData, NodeId, RunMode, SizingMode};
11use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec};
12
13use super::{TaffyError, TaffyResult};
14
15/// Global configuration values for a Taffy instance
16pub(crate) struct TaffyConfig {
17 /// Whether to round layout values
18 pub(crate) use_rounding: bool,
19}
20
21impl Default for TaffyConfig {
22 fn default() -> Self {
23 Self { use_rounding: true }
24 }
25}
26
27/// A tree of UI nodes suitable for UI layout
28pub struct Taffy<NodeContext = ()> {
29 /// The [`NodeData`] for each node stored in this tree
30 pub(crate) nodes: SlotMap<DefaultKey, NodeData>,
31
32 /// Functions/closures that compute the intrinsic size of leaf nodes
33 pub(crate) node_context_data: SparseSecondaryMap<DefaultKey, NodeContext>,
34
35 /// The children of each node
36 ///
37 /// The indexes in the outer vector correspond to the position of the parent [`NodeData`]
38 pub(crate) children: SlotMap<DefaultKey, ChildrenVec<NodeId>>,
39
40 /// The parents of each node
41 ///
42 /// The indexes in the outer vector correspond to the position of the child [`NodeData`]
43 pub(crate) parents: SlotMap<DefaultKey, Option<NodeId>>,
44
45 /// Layout mode configuration
46 pub(crate) config: TaffyConfig,
47}
48
49impl Default for Taffy {
50 fn default() -> Taffy<()> {
51 Taffy::new()
52 }
53}
54
55/// Iterator that wraps a slice of nodes, lazily converting them to u64
56pub struct TaffyChildIter<'a>(core::slice::Iter<'a, NodeId>);
57impl<'a> Iterator for TaffyChildIter<'a> {
58 type Item = NodeId;
59
60 fn next(&mut self) -> Option<Self::Item> {
61 self.0.next().copied()
62 }
63}
64
65/// View over the Taffy tree that holds the tree itself along with a reference to the context
66/// and implements LayoutTree. This allows the context to be stored outside of the Taffy struct
67/// which makes the lifetimes of the context much more flexible.
68pub struct TaffyView<'t, NodeContext, MeasureFunction>
69where
70 MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
71{
72 /// A reference to the Taffy tree
73 pub(crate) taffy: &'t mut Taffy<NodeContext>,
74 /// The context provided for passing to measure functions if layout is run over this struct
75 pub(crate) measure_function: MeasureFunction,
76}
77
78impl<'t, NodeContext, MeasureFunction> LayoutTree for TaffyView<'t, NodeContext, MeasureFunction>
79where
80 MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
81{
82 type ChildIter<'a> = TaffyChildIter<'a> where Self: 'a;
83
84 #[inline(always)]
85 fn children(&self, node: NodeId) -> Self::ChildIter<'_> {
86 TaffyChildIter(self.taffy.children[node.into()].iter())
87 }
88
89 #[inline(always)]
90 fn child_count(&self, node: NodeId) -> usize {
91 self.taffy.children[node.into()].len()
92 }
93
94 #[inline(always)]
95 fn style(&self, node: NodeId) -> &Style {
96 &self.taffy.nodes[node.into()].style
97 }
98
99 #[inline(always)]
100 fn layout(&self, node: NodeId) -> &Layout {
101 if self.taffy.config.use_rounding {
102 &self.taffy.nodes[node.into()].unrounded_layout
103 } else {
104 &self.taffy.nodes[node.into()].final_layout
105 }
106 }
107
108 #[inline(always)]
109 fn layout_mut(&mut self, node: NodeId) -> &mut Layout {
110 if self.taffy.config.use_rounding {
111 &mut self.taffy.nodes[node.into()].unrounded_layout
112 } else {
113 &mut self.taffy.nodes[node.into()].final_layout
114 }
115 }
116
117 #[inline(always)]
118 fn child(&self, node: NodeId, id: usize) -> NodeId {
119 self.taffy.children[node.into()][id]
120 }
121
122 #[inline(always)]
123 fn measure_child_size(
124 &mut self,
125 node: NodeId,
126 known_dimensions: Size<Option<f32>>,
127 parent_size: Size<Option<f32>>,
128 available_space: Size<AvailableSpace>,
129 sizing_mode: SizingMode,
130 vertical_margins_are_collapsible: Line<bool>,
131 ) -> Size<f32> {
132 compute_node_layout(
133 self,
134 node,
135 LayoutInput {
136 known_dimensions,
137 parent_size,
138 available_space,
139 sizing_mode,
140 run_mode: RunMode::ComputeSize,
141 vertical_margins_are_collapsible,
142 },
143 )
144 .size
145 }
146
147 #[inline(always)]
148 fn perform_child_layout(
149 &mut self,
150 node: NodeId,
151 known_dimensions: Size<Option<f32>>,
152 parent_size: Size<Option<f32>>,
153 available_space: Size<AvailableSpace>,
154 sizing_mode: SizingMode,
155 vertical_margins_are_collapsible: Line<bool>,
156 ) -> LayoutOutput {
157 compute_node_layout(
158 self,
159 node,
160 LayoutInput {
161 known_dimensions,
162 parent_size,
163 available_space,
164 sizing_mode,
165 run_mode: RunMode::PerformLayout,
166 vertical_margins_are_collapsible,
167 },
168 )
169 }
170}
171
172#[allow(clippy::iter_cloned_collect)] // due to no-std support, we need to use `iter_cloned` instead of `collect`
173impl<NodeContext> Taffy<NodeContext> {
174 /// Creates a new [`Taffy`]
175 ///
176 /// The default capacity of a [`Taffy`] is 16 nodes.
177 #[must_use]
178 pub fn new() -> Self {
179 Self::with_capacity(16)
180 }
181
182 /// Creates a new [`Taffy`] that can store `capacity` nodes before reallocation
183 #[must_use]
184 pub fn with_capacity(capacity: usize) -> Self {
185 Taffy {
186 // TODO: make this method const upstream,
187 // so constructors here can be const
188 nodes: SlotMap::with_capacity(capacity),
189 children: SlotMap::with_capacity(capacity),
190 parents: SlotMap::with_capacity(capacity),
191 node_context_data: SparseSecondaryMap::with_capacity(capacity),
192 config: TaffyConfig::default(),
193 }
194 }
195
196 /// Enable rounding of layout values. Rounding is enabled by default.
197 pub fn enable_rounding(&mut self) {
198 self.config.use_rounding = true;
199 }
200
201 /// Disable rounding of layout values. Rounding is enabled by default.
202 pub fn disable_rounding(&mut self) {
203 self.config.use_rounding = false;
204 }
205
206 /// Creates and adds a new unattached leaf node to the tree, and returns the node of the new node
207 pub fn new_leaf(&mut self, layout: Style) -> TaffyResult<NodeId> {
208 let id = self.nodes.insert(NodeData::new(layout));
209 let _ = self.children.insert(new_vec_with_capacity(0));
210 let _ = self.parents.insert(None);
211
212 Ok(id.into())
213 }
214
215 /// Creates and adds a new unattached leaf node to the tree, and returns the [`NodeId`] of the new node
216 ///
217 /// Creates and adds a new leaf node with a supplied context
218 pub fn new_leaf_with_context(&mut self, layout: Style, context: NodeContext) -> TaffyResult<NodeId> {
219 let mut data = NodeData::new(layout);
220 data.needs_measure = true;
221
222 let id = self.nodes.insert(data);
223 self.node_context_data.insert(id, context);
224
225 let _ = self.children.insert(new_vec_with_capacity(0));
226 let _ = self.parents.insert(None);
227
228 Ok(id.into())
229 }
230
231 /// Creates and adds a new node, which may have any number of `children`
232 pub fn new_with_children(&mut self, layout: Style, children: &[NodeId]) -> TaffyResult<NodeId> {
233 let id = NodeId::from(self.nodes.insert(NodeData::new(layout)));
234
235 for child in children {
236 self.parents[(*child).into()] = Some(id);
237 }
238
239 let _ = self.children.insert(children.iter().copied().collect::<_>());
240 let _ = self.parents.insert(None);
241
242 Ok(id)
243 }
244
245 /// Drops all nodes in the tree
246 pub fn clear(&mut self) {
247 self.nodes.clear();
248 self.children.clear();
249 self.parents.clear();
250 }
251
252 /// Remove a specific node from the tree and drop it
253 ///
254 /// Returns the id of the node removed.
255 pub fn remove(&mut self, node: NodeId) -> TaffyResult<NodeId> {
256 let key = node.into();
257 if let Some(parent) = self.parents[key] {
258 if let Some(children) = self.children.get_mut(parent.into()) {
259 children.retain(|f| *f != node);
260 }
261 }
262
263 // Remove "parent" references to a node when removing that node
264 if let Some(children) = self.children.get(key) {
265 for child in children.iter().copied() {
266 self.parents[child.into()] = None;
267 }
268 }
269
270 let _ = self.children.remove(key);
271 let _ = self.parents.remove(key);
272 let _ = self.nodes.remove(key);
273
274 Ok(node)
275 }
276
277 /// Sets the context data associated with the node
278 pub fn set_node_context(&mut self, node: NodeId, measure: Option<NodeContext>) -> TaffyResult<()> {
279 let key = node.into();
280 if let Some(measure) = measure {
281 self.nodes[key].needs_measure = true;
282 self.node_context_data.insert(key, measure);
283 } else {
284 self.nodes[key].needs_measure = false;
285 self.node_context_data.remove(key);
286 }
287
288 self.mark_dirty(node)?;
289
290 Ok(())
291 }
292
293 /// Get's a mutable reference to the the context data associated with the node
294 pub fn get_node_context_mut(&mut self, node: NodeId) -> Option<&mut NodeContext> {
295 self.node_context_data.get_mut(node.into())
296 }
297
298 /// Adds a `child` node under the supplied `parent`
299 pub fn add_child(&mut self, parent: NodeId, child: NodeId) -> TaffyResult<()> {
300 let parent_key = parent.into();
301 let child_key = child.into();
302 self.parents[child_key] = Some(parent);
303 self.children[parent_key].push(child);
304 self.mark_dirty(parent)?;
305
306 Ok(())
307 }
308
309 /// Inserts a `child` node at the given `child_index` under the supplied `parent`, shifting all children after it to the right.
310 pub fn insert_child_at_index(&mut self, parent: NodeId, child_index: usize, child: NodeId) -> TaffyResult<()> {
311 let parent_key = parent.into();
312
313 let child_count = self.children[parent_key].len();
314 if child_index > child_count {
315 return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
316 }
317
318 self.parents[child.into()] = Some(parent);
319 self.children[parent_key].insert(child_index, child);
320 self.mark_dirty(parent)?;
321
322 Ok(())
323 }
324
325 /// Directly sets the `children` of the supplied `parent`
326 pub fn set_children(&mut self, parent: NodeId, children: &[NodeId]) -> TaffyResult<()> {
327 let parent_key = parent.into();
328
329 // Remove node as parent from all its current children.
330 for child in &self.children[parent_key] {
331 self.parents[(*child).into()] = None;
332 }
333
334 // Build up relation node <-> child
335 for child in children {
336 self.parents[(*child).into()] = Some(parent);
337 }
338
339 let parent_children = &mut self.children[parent_key];
340 parent_children.clear();
341 children.iter().for_each(|child| parent_children.push(*child));
342
343 self.mark_dirty(parent)?;
344
345 Ok(())
346 }
347
348 /// Removes the `child` of the parent `node`
349 ///
350 /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
351 pub fn remove_child(&mut self, parent: NodeId, child: NodeId) -> TaffyResult<NodeId> {
352 let index = self.children[parent.into()].iter().position(|n| *n == child).unwrap();
353 self.remove_child_at_index(parent, index)
354 }
355
356 /// Removes the child at the given `index` from the `parent`
357 ///
358 /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
359 pub fn remove_child_at_index(&mut self, parent: NodeId, child_index: usize) -> TaffyResult<NodeId> {
360 let parent_key = parent.into();
361 let child_count = self.children[parent_key].len();
362 if child_index >= child_count {
363 return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
364 }
365
366 let child = self.children[parent_key].remove(child_index);
367 self.parents[child.into()] = None;
368
369 self.mark_dirty(parent)?;
370
371 Ok(child)
372 }
373
374 /// Replaces the child at the given `child_index` from the `parent` node with the new `child` node
375 ///
376 /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
377 pub fn replace_child_at_index(
378 &mut self,
379 parent: NodeId,
380 child_index: usize,
381 new_child: NodeId,
382 ) -> TaffyResult<NodeId> {
383 let parent_key = parent.into();
384
385 let child_count = self.children[parent_key].len();
386 if child_index >= child_count {
387 return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
388 }
389
390 self.parents[new_child.into()] = Some(parent);
391 let old_child = core::mem::replace(&mut self.children[parent_key][child_index], new_child);
392 self.parents[old_child.into()] = None;
393
394 self.mark_dirty(parent)?;
395
396 Ok(old_child)
397 }
398
399 /// Returns the child node of the parent `node` at the provided `child_index`
400 pub fn child_at_index(&self, parent: NodeId, child_index: usize) -> TaffyResult<NodeId> {
401 let parent_key = parent.into();
402 let child_count = self.children[parent_key].len();
403 if child_index >= child_count {
404 return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
405 }
406
407 Ok(self.children[parent_key][child_index])
408 }
409
410 /// Returns the total number of nodes in the tree
411 pub fn total_node_count(&self) -> usize {
412 self.nodes.len()
413 }
414
415 /// Returns the number of children of the `parent` node
416 pub fn child_count(&self, parent: NodeId) -> TaffyResult<usize> {
417 Ok(self.children[parent.into()].len())
418 }
419
420 /// Returns a list of children that belong to the parent node
421 pub fn children(&self, parent: NodeId) -> TaffyResult<Vec<NodeId>> {
422 Ok(self.children[parent.into()].iter().copied().collect::<_>())
423 }
424
425 /// Sets the [`Style`] of the provided `node`
426 pub fn set_style(&mut self, node: NodeId, style: Style) -> TaffyResult<()> {
427 self.nodes[node.into()].style = style;
428 self.mark_dirty(node)?;
429 Ok(())
430 }
431
432 /// Gets the [`Style`] of the provided `node`
433 pub fn style(&self, node: NodeId) -> TaffyResult<&Style> {
434 Ok(&self.nodes[node.into()].style)
435 }
436
437 /// Return this node layout relative to its parent
438 pub fn layout(&self, node: NodeId) -> TaffyResult<&Layout> {
439 Ok(&self.nodes[node.into()].final_layout)
440 }
441
442 /// Marks the layout computation of this node and its children as outdated
443 ///
444 /// Performs a recursive depth-first search up the tree until the root node is reached
445 ///
446 /// WARNING: this will stack-overflow if the tree contains a cycle
447 pub fn mark_dirty(&mut self, node: NodeId) -> TaffyResult<()> {
448 /// WARNING: this will stack-overflow if the tree contains a cycle
449 fn mark_dirty_recursive(
450 nodes: &mut SlotMap<DefaultKey, NodeData>,
451 parents: &SlotMap<DefaultKey, Option<NodeId>>,
452 node_key: DefaultKey,
453 ) {
454 nodes[node_key].mark_dirty();
455
456 if let Some(Some(node)) = parents.get(node_key) {
457 mark_dirty_recursive(nodes, parents, (*node).into());
458 }
459 }
460
461 mark_dirty_recursive(&mut self.nodes, &self.parents, node.into());
462
463 Ok(())
464 }
465
466 /// Indicates whether the layout of this node (and its children) need to be recomputed
467 pub fn dirty(&self, node: NodeId) -> TaffyResult<bool> {
468 Ok(self.nodes[node.into()].cache.is_empty())
469 }
470
471 /// Updates the stored layout of the provided `node` and its children
472 pub fn compute_layout_with_measure<MeasureFunction>(
473 &mut self,
474 node: NodeId,
475 available_space: Size<AvailableSpace>,
476 measure_function: MeasureFunction,
477 ) -> Result<(), TaffyError>
478 where
479 MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
480 {
481 let mut taffy_view = TaffyView { taffy: self, measure_function };
482 compute_layout(&mut taffy_view, node, available_space)
483 }
484
485 /// Updates the stored layout of the provided `node` and its children
486 pub fn compute_layout(&mut self, node: NodeId, available_space: Size<AvailableSpace>) -> Result<(), TaffyError> {
487 self.compute_layout_with_measure(node, available_space, |_, _, _, _| Size::ZERO)
488 }
489
490 /// Prints a debug representation of the tree's layout
491 #[cfg(feature = "std")]
492 pub fn print_tree(&mut self, root: NodeId) {
493 let taffy_view = TaffyView { taffy: self, measure_function: |_, _, _, _| Size::ZERO };
494 crate::util::print_tree(&taffy_view, root)
495 }
496}
497
498#[cfg(test)]
499mod tests {
500 #![allow(clippy::bool_assert_comparison)]
501
502 use super::*;
503 use crate::style::{Dimension, Display, FlexDirection};
504 use crate::style_helpers::*;
505 use crate::util::sys;
506
507 fn size_measure_function(
508 known_dimensions: Size<Option<f32>>,
509 _available_space: Size<AvailableSpace>,
510 _node_id: NodeId,
511 node_context: Option<&mut Size<f32>>,
512 ) -> Size<f32> {
513 known_dimensions.unwrap_or(node_context.cloned().unwrap_or(Size::ZERO))
514 }
515
516 #[test]
517 fn new_should_allocate_default_capacity() {
518 const DEFAULT_CAPACITY: usize = 16; // This is the capacity defined in the `impl Default`
519 let taffy: Taffy<()> = Taffy::new();
520
521 assert!(taffy.children.capacity() >= DEFAULT_CAPACITY);
522 assert!(taffy.parents.capacity() >= DEFAULT_CAPACITY);
523 assert!(taffy.nodes.capacity() >= DEFAULT_CAPACITY);
524 }
525
526 #[test]
527 fn test_with_capacity() {
528 const CAPACITY: usize = 8;
529 let taffy: Taffy<()> = Taffy::with_capacity(CAPACITY);
530
531 assert!(taffy.children.capacity() >= CAPACITY);
532 assert!(taffy.parents.capacity() >= CAPACITY);
533 assert!(taffy.nodes.capacity() >= CAPACITY);
534 }
535
536 #[test]
537 fn test_new_leaf() {
538 let mut taffy: Taffy<()> = Taffy::new();
539
540 let res = taffy.new_leaf(Style::default());
541 assert!(res.is_ok());
542 let node = res.unwrap();
543
544 // node should be in the taffy tree and have no children
545 assert!(taffy.child_count(node).unwrap() == 0);
546 }
547
548 #[test]
549 fn new_leaf_with_context() {
550 let mut taffy: Taffy<Size<f32>> = Taffy::new();
551
552 let res = taffy.new_leaf_with_context(Style::default(), Size::ZERO);
553 assert!(res.is_ok());
554 let node = res.unwrap();
555
556 // node should be in the taffy tree and have no children
557 assert!(taffy.child_count(node).unwrap() == 0);
558 }
559
560 /// Test that new_with_children works as expected
561 #[test]
562 fn test_new_with_children() {
563 let mut taffy: Taffy<()> = Taffy::new();
564 let child0 = taffy.new_leaf(Style::default()).unwrap();
565 let child1 = taffy.new_leaf(Style::default()).unwrap();
566 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
567
568 // node should have two children
569 assert_eq!(taffy.child_count(node).unwrap(), 2);
570 assert_eq!(taffy.children(node).unwrap()[0], child0);
571 assert_eq!(taffy.children(node).unwrap()[1], child1);
572 }
573
574 #[test]
575 fn remove_node_should_remove() {
576 let mut taffy: Taffy<()> = Taffy::new();
577
578 let node = taffy.new_leaf(Style::default()).unwrap();
579
580 let _ = taffy.remove(node).unwrap();
581 }
582
583 #[test]
584 fn remove_node_should_detach_herarchy() {
585 let mut taffy: Taffy<()> = Taffy::new();
586
587 // Build a linear tree layout: <0> <- <1> <- <2>
588 let node2 = taffy.new_leaf(Style::default()).unwrap();
589 let node1 = taffy.new_with_children(Style::default(), &[node2]).unwrap();
590 let node0 = taffy.new_with_children(Style::default(), &[node1]).unwrap();
591
592 // Both node0 and node1 should have 1 child nodes
593 assert_eq!(taffy.children(node0).unwrap().as_slice(), &[node1]);
594 assert_eq!(taffy.children(node1).unwrap().as_slice(), &[node2]);
595
596 // Disconnect the tree: <0> <2>
597 let _ = taffy.remove(node1).unwrap();
598
599 // Both remaining nodes should have no child nodes
600 assert!(taffy.children(node0).unwrap().is_empty());
601 assert!(taffy.children(node2).unwrap().is_empty());
602 }
603
604 #[test]
605 fn remove_last_node() {
606 let mut taffy: Taffy<()> = Taffy::new();
607
608 let parent = taffy.new_leaf(Style::default()).unwrap();
609 let child = taffy.new_leaf(Style::default()).unwrap();
610 taffy.add_child(parent, child).unwrap();
611
612 taffy.remove(child).unwrap();
613 taffy.remove(parent).unwrap();
614 }
615
616 #[test]
617 fn set_measure() {
618 let mut taffy: Taffy<Size<f32>> = Taffy::new();
619 let node = taffy.new_leaf_with_context(Style::default(), Size { width: 200.0, height: 200.0 }).unwrap();
620 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
621 assert_eq!(taffy.layout(node).unwrap().size.width, 200.0);
622
623 taffy.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
624 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
625 assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
626 }
627
628 #[test]
629 fn set_measure_of_previously_unmeasured_node() {
630 let mut taffy: Taffy<Size<f32>> = Taffy::new();
631 let node = taffy.new_leaf(Style::default()).unwrap();
632 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
633 assert_eq!(taffy.layout(node).unwrap().size.width, 0.0);
634
635 taffy.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
636 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
637 assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
638 }
639
640 /// Test that adding `add_child()` works
641 #[test]
642 fn add_child() {
643 let mut taffy: Taffy<()> = Taffy::new();
644 let node = taffy.new_leaf(Style::default()).unwrap();
645 assert_eq!(taffy.child_count(node).unwrap(), 0);
646
647 let child0 = taffy.new_leaf(Style::default()).unwrap();
648 taffy.add_child(node, child0).unwrap();
649 assert_eq!(taffy.child_count(node).unwrap(), 1);
650
651 let child1 = taffy.new_leaf(Style::default()).unwrap();
652 taffy.add_child(node, child1).unwrap();
653 assert_eq!(taffy.child_count(node).unwrap(), 2);
654 }
655
656 #[test]
657 fn insert_child_at_index() {
658 let mut taffy: Taffy<()> = Taffy::new();
659
660 let child0 = taffy.new_leaf(Style::default()).unwrap();
661 let child1 = taffy.new_leaf(Style::default()).unwrap();
662 let child2 = taffy.new_leaf(Style::default()).unwrap();
663
664 let node = taffy.new_leaf(Style::default()).unwrap();
665 assert_eq!(taffy.child_count(node).unwrap(), 0);
666
667 taffy.insert_child_at_index(node, 0, child0).unwrap();
668 assert_eq!(taffy.child_count(node).unwrap(), 1);
669 assert_eq!(taffy.children(node).unwrap()[0], child0);
670
671 taffy.insert_child_at_index(node, 0, child1).unwrap();
672 assert_eq!(taffy.child_count(node).unwrap(), 2);
673 assert_eq!(taffy.children(node).unwrap()[0], child1);
674 assert_eq!(taffy.children(node).unwrap()[1], child0);
675
676 taffy.insert_child_at_index(node, 1, child2).unwrap();
677 assert_eq!(taffy.child_count(node).unwrap(), 3);
678 assert_eq!(taffy.children(node).unwrap()[0], child1);
679 assert_eq!(taffy.children(node).unwrap()[1], child2);
680 assert_eq!(taffy.children(node).unwrap()[2], child0);
681 }
682
683 #[test]
684 fn set_children() {
685 let mut taffy: Taffy<()> = Taffy::new();
686
687 let child0 = taffy.new_leaf(Style::default()).unwrap();
688 let child1 = taffy.new_leaf(Style::default()).unwrap();
689 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
690
691 assert_eq!(taffy.child_count(node).unwrap(), 2);
692 assert_eq!(taffy.children(node).unwrap()[0], child0);
693 assert_eq!(taffy.children(node).unwrap()[1], child1);
694
695 let child2 = taffy.new_leaf(Style::default()).unwrap();
696 let child3 = taffy.new_leaf(Style::default()).unwrap();
697 taffy.set_children(node, &[child2, child3]).unwrap();
698
699 assert_eq!(taffy.child_count(node).unwrap(), 2);
700 assert_eq!(taffy.children(node).unwrap()[0], child2);
701 assert_eq!(taffy.children(node).unwrap()[1], child3);
702 }
703
704 /// Test that removing a child works
705 #[test]
706 fn remove_child() {
707 let mut taffy: Taffy<()> = Taffy::new();
708 let child0 = taffy.new_leaf(Style::default()).unwrap();
709 let child1 = taffy.new_leaf(Style::default()).unwrap();
710 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
711
712 assert_eq!(taffy.child_count(node).unwrap(), 2);
713
714 taffy.remove_child(node, child0).unwrap();
715 assert_eq!(taffy.child_count(node).unwrap(), 1);
716 assert_eq!(taffy.children(node).unwrap()[0], child1);
717
718 taffy.remove_child(node, child1).unwrap();
719 assert_eq!(taffy.child_count(node).unwrap(), 0);
720 }
721
722 #[test]
723 fn remove_child_at_index() {
724 let mut taffy: Taffy<()> = Taffy::new();
725 let child0 = taffy.new_leaf(Style::default()).unwrap();
726 let child1 = taffy.new_leaf(Style::default()).unwrap();
727 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
728
729 assert_eq!(taffy.child_count(node).unwrap(), 2);
730
731 taffy.remove_child_at_index(node, 0).unwrap();
732 assert_eq!(taffy.child_count(node).unwrap(), 1);
733 assert_eq!(taffy.children(node).unwrap()[0], child1);
734
735 taffy.remove_child_at_index(node, 0).unwrap();
736 assert_eq!(taffy.child_count(node).unwrap(), 0);
737 }
738
739 // Related to: https://github.com/DioxusLabs/taffy/issues/510
740 #[test]
741 fn remove_child_updates_parents() {
742 let mut taffy: Taffy<()> = Taffy::new();
743
744 let parent = taffy.new_leaf(Style::default()).unwrap();
745 let child = taffy.new_leaf(Style::default()).unwrap();
746
747 taffy.add_child(parent, child).unwrap();
748
749 taffy.remove(parent).unwrap();
750
751 // Once the parent is removed this shouldn't panic.
752 assert!(taffy.set_children(child, &[]).is_ok());
753 }
754
755 #[test]
756 fn replace_child_at_index() {
757 let mut taffy: Taffy<()> = Taffy::new();
758
759 let child0 = taffy.new_leaf(Style::default()).unwrap();
760 let child1 = taffy.new_leaf(Style::default()).unwrap();
761
762 let node = taffy.new_with_children(Style::default(), &[child0]).unwrap();
763 assert_eq!(taffy.child_count(node).unwrap(), 1);
764 assert_eq!(taffy.children(node).unwrap()[0], child0);
765
766 taffy.replace_child_at_index(node, 0, child1).unwrap();
767 assert_eq!(taffy.child_count(node).unwrap(), 1);
768 assert_eq!(taffy.children(node).unwrap()[0], child1);
769 }
770 #[test]
771 fn test_child_at_index() {
772 let mut taffy: Taffy<()> = Taffy::new();
773 let child0 = taffy.new_leaf(Style::default()).unwrap();
774 let child1 = taffy.new_leaf(Style::default()).unwrap();
775 let child2 = taffy.new_leaf(Style::default()).unwrap();
776 let node = taffy.new_with_children(Style::default(), &[child0, child1, child2]).unwrap();
777
778 assert!(if let Ok(result) = taffy.child_at_index(node, 0) { result == child0 } else { false });
779 assert!(if let Ok(result) = taffy.child_at_index(node, 1) { result == child1 } else { false });
780 assert!(if let Ok(result) = taffy.child_at_index(node, 2) { result == child2 } else { false });
781 }
782 #[test]
783 fn test_child_count() {
784 let mut taffy: Taffy<()> = Taffy::new();
785 let child0 = taffy.new_leaf(Style::default()).unwrap();
786 let child1 = taffy.new_leaf(Style::default()).unwrap();
787 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
788
789 assert!(if let Ok(count) = taffy.child_count(node) { count == 2 } else { false });
790 assert!(if let Ok(count) = taffy.child_count(child0) { count == 0 } else { false });
791 assert!(if let Ok(count) = taffy.child_count(child1) { count == 0 } else { false });
792 }
793
794 #[allow(clippy::vec_init_then_push)]
795 #[test]
796 fn test_children() {
797 let mut taffy: Taffy<()> = Taffy::new();
798 let child0 = taffy.new_leaf(Style::default()).unwrap();
799 let child1 = taffy.new_leaf(Style::default()).unwrap();
800 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
801
802 let mut children = sys::Vec::new();
803 children.push(child0);
804 children.push(child1);
805
806 let children_result = taffy.children(node).unwrap();
807 assert_eq!(children_result, children);
808
809 assert!(taffy.children(child0).unwrap().is_empty());
810 }
811 #[test]
812 fn test_set_style() {
813 let mut taffy: Taffy<()> = Taffy::new();
814
815 let node = taffy.new_leaf(Style::default()).unwrap();
816 assert_eq!(taffy.style(node).unwrap().display, Display::Flex);
817
818 taffy.set_style(node, Style { display: Display::None, ..Style::default() }).unwrap();
819 assert_eq!(taffy.style(node).unwrap().display, Display::None);
820 }
821 #[test]
822 fn test_style() {
823 let mut taffy: Taffy<()> = Taffy::new();
824
825 let style = Style { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() };
826
827 let node = taffy.new_leaf(style.clone()).unwrap();
828
829 let res = taffy.style(node);
830 assert!(res.is_ok());
831 assert!(res.unwrap() == &style);
832 }
833 #[test]
834 fn test_layout() {
835 let mut taffy: Taffy<()> = Taffy::new();
836 let node = taffy.new_leaf(Style::default()).unwrap();
837
838 // TODO: Improve this test?
839 let res = taffy.layout(node);
840 assert!(res.is_ok());
841 }
842
843 #[test]
844 fn test_mark_dirty() {
845 let mut taffy: Taffy<()> = Taffy::new();
846 let child0 = taffy.new_leaf(Style::default()).unwrap();
847 let child1 = taffy.new_leaf(Style::default()).unwrap();
848 let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
849
850 taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
851
852 assert_eq!(taffy.dirty(child0).unwrap(), false);
853 assert_eq!(taffy.dirty(child1).unwrap(), false);
854 assert_eq!(taffy.dirty(node).unwrap(), false);
855
856 taffy.mark_dirty(node).unwrap();
857 assert_eq!(taffy.dirty(child0).unwrap(), false);
858 assert_eq!(taffy.dirty(child1).unwrap(), false);
859 assert_eq!(taffy.dirty(node).unwrap(), true);
860
861 taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
862 taffy.mark_dirty(child0).unwrap();
863 assert_eq!(taffy.dirty(child0).unwrap(), true);
864 assert_eq!(taffy.dirty(child1).unwrap(), false);
865 assert_eq!(taffy.dirty(node).unwrap(), true);
866 }
867
868 #[test]
869 fn compute_layout_should_produce_valid_result() {
870 let mut taffy: Taffy<()> = Taffy::new();
871 let node_result = taffy.new_leaf(Style {
872 size: Size { width: Dimension::Length(10f32), height: Dimension::Length(10f32) },
873 ..Default::default()
874 });
875 assert!(node_result.is_ok());
876 let node = node_result.unwrap();
877 let layout_result = taffy.compute_layout(
878 node,
879 Size { width: AvailableSpace::Definite(100.), height: AvailableSpace::Definite(100.) },
880 );
881 assert!(layout_result.is_ok());
882 }
883
884 #[test]
885 fn make_sure_layout_location_is_top_left() {
886 use crate::prelude::Rect;
887
888 let mut taffy: Taffy<()> = Taffy::new();
889
890 let node = taffy
891 .new_leaf(Style {
892 size: Size { width: Dimension::Percent(1f32), height: Dimension::Percent(1f32) },
893 ..Default::default()
894 })
895 .unwrap();
896
897 let root = taffy
898 .new_with_children(
899 Style {
900 size: Size { width: Dimension::Length(100f32), height: Dimension::Length(100f32) },
901 padding: Rect {
902 left: length(10f32),
903 right: length(20f32),
904 top: length(30f32),
905 bottom: length(40f32),
906 },
907 ..Default::default()
908 },
909 &[node],
910 )
911 .unwrap();
912
913 taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
914
915 // If Layout::location represents top-left coord, 'node' location
916 // must be (due applied 'root' padding): {x: 10, y: 30}.
917 //
918 // It's important, since result will be different for each other
919 // coordinate space:
920 // - bottom-left: {x: 10, y: 40}
921 // - top-right: {x: 20, y: 30}
922 // - bottom-right: {x: 20, y: 40}
923 let layout = taffy.layout(node).unwrap();
924 assert_eq!(layout.location.x, 10f32);
925 assert_eq!(layout.location.y, 30f32);
926 }
927}