1use compose_rt::{Composer, NodeKey};
2#[cfg(feature = "block_layout")]
3use taffy::{compute::compute_block_layout, LayoutBlockContainer};
4#[cfg(feature = "flexbox")]
5use taffy::{compute::compute_flexbox_layout, LayoutFlexboxContainer};
6#[cfg(feature = "grid")]
7use taffy::{compute::compute_grid_layout, LayoutGridContainer};
8use taffy::{
9 compute_cached_layout, compute_hidden_layout, compute_leaf_layout, AvailableSpace, CacheTree,
10 Display, FlexDirection, FlexboxContainerStyle, Layout, LayoutPartialTree, NodeId, PrintTree,
11 RoundTree, RunMode, Size, TraversePartialTree, TraverseTree,
12};
13
14use crate::traits::{IntoNodeId, IntoNodeKey, TaffyConfig, TaffyNode};
15
16pub struct TaffyTreeChildIter<'a>(core::slice::Iter<'a, NodeKey>);
17impl Iterator for TaffyTreeChildIter<'_> {
18 type Item = NodeId;
19
20 fn next(&mut self) -> Option<Self::Item> {
21 self.0.next().copied().map(IntoNodeId::into_node_id)
22 }
23}
24
25pub struct TaffyTreeView<'a, T>
26where
27 T: TaffyNode,
28 T::Context: TaffyConfig,
29{
30 pub composer: &'a Composer<T>,
31}
32
33impl<'a, T> TaffyTreeView<'a, T>
34where
35 T: TaffyNode,
36 T::Context: TaffyConfig,
37{
38 pub fn new(composer: &'a Composer<T>) -> Self {
39 Self { composer }
40 }
41}
42
43impl<T> TraversePartialTree for TaffyTreeView<'_, T>
44where
45 T: TaffyNode,
46 T::Context: TaffyConfig,
47{
48 type ChildIter<'a>
49 = TaffyTreeChildIter<'a>
50 where
51 Self: 'a;
52
53 #[inline(always)]
54 fn child_ids(&self, node_id: NodeId) -> Self::ChildIter<'_> {
55 let node_key = node_id.into_node_key();
56 TaffyTreeChildIter(self.composer.nodes[node_key].children.iter())
57 }
58
59 #[inline(always)]
60 fn child_count(&self, node_id: NodeId) -> usize {
61 let node_key = node_id.into_node_key();
62 self.composer.nodes[node_key].children.len()
63 }
64
65 #[inline(always)]
66 fn get_child_id(&self, node_id: NodeId, child_index: usize) -> NodeId {
67 let node_key = node_id.into_node_key();
68 self.composer.nodes[node_key].children[child_index].into_node_id()
69 }
70}
71
72impl<T> TraverseTree for TaffyTreeView<'_, T>
73where
74 T: TaffyNode,
75 T::Context: TaffyConfig,
76{
77}
78
79impl<T> PrintTree for TaffyTreeView<'_, T>
80where
81 T: TaffyNode,
82 T::Context: TaffyConfig,
83{
84 #[inline(always)]
85 fn get_debug_label(&self, node_id: NodeId) -> &'static str {
86 let node = self.composer.nodes[node_id.into_node_key()]
87 .data
88 .as_ref()
89 .unwrap();
90 let display = node.get_display();
91 let num_children = self.child_count(node_id);
92 match (num_children, display) {
93 (_, Display::None) => "NONE",
94 (0, _) => "LEAF",
95 #[cfg(feature = "block_layout")]
96 (_, Display::Block) => "BLOCK",
97 #[cfg(feature = "flexbox")]
98 (_, Display::Flex) => match node.get_flexbox_container_style().flex_direction() {
99 FlexDirection::Row | FlexDirection::RowReverse => "FLEX ROW",
100 FlexDirection::Column | FlexDirection::ColumnReverse => "FLEX COL",
101 },
102 #[cfg(feature = "grid")]
103 (_, Display::Grid) => "GRID",
104 }
105 }
106
107 #[inline(always)]
108 fn get_final_layout(&self, node_id: NodeId) -> &Layout {
109 if self.composer.context.use_rounding() {
110 self.composer.nodes[node_id.into_node_key()]
111 .data
112 .as_ref()
113 .unwrap()
114 .get_final_layout()
115 } else {
116 self.composer.nodes[node_id.into_node_key()]
117 .data
118 .as_ref()
119 .unwrap()
120 .get_unrounded_layout()
121 }
122 }
123}
124
125pub struct TaffyTree<'a, T, M>
126where
127 T: TaffyNode,
128 T::Context: TaffyConfig,
129 M: FnMut(
130 Size<Option<f32>>,
131 Size<AvailableSpace>,
132 NodeId,
133 Option<&mut T::NodeContext>,
134 &T::CoreContainerStyle,
135 ) -> Size<f32>,
136{
137 pub composer: &'a mut Composer<T>,
138 pub measure_function: M,
139}
140
141impl<'a, T, M> TaffyTree<'a, T, M>
142where
143 T: TaffyNode,
144 T::Context: TaffyConfig,
145 M: FnMut(
146 Size<Option<f32>>,
147 Size<AvailableSpace>,
148 NodeId,
149 Option<&mut T::NodeContext>,
150 &T::CoreContainerStyle,
151 ) -> Size<f32>,
152{
153 pub fn new(composer: &'a mut Composer<T>, measure_function: M) -> Self {
154 Self {
155 composer,
156 measure_function,
157 }
158 }
159}
160
161impl<T, M> TraversePartialTree for TaffyTree<'_, T, M>
162where
163 T: TaffyNode,
164 T::Context: TaffyConfig,
165 M: FnMut(
166 Size<Option<f32>>,
167 Size<AvailableSpace>,
168 NodeId,
169 Option<&mut T::NodeContext>,
170 &T::CoreContainerStyle,
171 ) -> Size<f32>,
172{
173 type ChildIter<'a>
174 = TaffyTreeChildIter<'a>
175 where
176 Self: 'a;
177
178 #[inline(always)]
179 fn child_ids(&self, node_id: NodeId) -> Self::ChildIter<'_> {
180 let node_key = node_id.into_node_key();
181 TaffyTreeChildIter(self.composer.nodes[node_key].children.iter())
182 }
183
184 #[inline(always)]
185 fn child_count(&self, node_id: NodeId) -> usize {
186 let node_key = node_id.into_node_key();
187 self.composer.nodes[node_key].children.len()
188 }
189
190 #[inline(always)]
191 fn get_child_id(&self, node_id: NodeId, child_index: usize) -> NodeId {
192 let node_key = node_id.into_node_key();
193 self.composer.nodes[node_key].children[child_index].into_node_id()
194 }
195}
196
197impl<T, M> TraverseTree for TaffyTree<'_, T, M>
198where
199 T: TaffyNode,
200 T::Context: TaffyConfig,
201 M: FnMut(
202 Size<Option<f32>>,
203 Size<AvailableSpace>,
204 NodeId,
205 Option<&mut T::NodeContext>,
206 &T::CoreContainerStyle,
207 ) -> Size<f32>,
208{
209}
210
211impl<T, M> CacheTree for TaffyTree<'_, T, M>
212where
213 T: TaffyNode,
214 T::Context: TaffyConfig,
215 M: FnMut(
216 Size<Option<f32>>,
217 Size<AvailableSpace>,
218 NodeId,
219 Option<&mut T::NodeContext>,
220 &T::CoreContainerStyle,
221 ) -> Size<f32>,
222{
223 #[inline(always)]
224 fn cache_get(
225 &self,
226 node_id: NodeId,
227 known_dimensions: taffy::Size<Option<f32>>,
228 available_space: taffy::Size<taffy::AvailableSpace>,
229 run_mode: taffy::RunMode,
230 ) -> Option<taffy::LayoutOutput> {
231 self.composer.nodes[node_id.into_node_key()]
232 .data
233 .as_ref()
234 .unwrap()
235 .cache_get(known_dimensions, available_space, run_mode)
236 }
237
238 #[inline(always)]
239 fn cache_store(
240 &mut self,
241 node_id: NodeId,
242 known_dimensions: taffy::Size<Option<f32>>,
243 available_space: taffy::Size<taffy::AvailableSpace>,
244 run_mode: taffy::RunMode,
245 layout_output: taffy::LayoutOutput,
246 ) {
247 self.composer
248 .nodes
249 .get_mut(node_id.into_node_key())
250 .unwrap()
251 .data
252 .as_mut()
253 .unwrap()
254 .cache_store(known_dimensions, available_space, run_mode, layout_output)
255 }
256
257 #[inline(always)]
258 fn cache_clear(&mut self, node_id: NodeId) {
259 self.composer
260 .nodes
261 .get_mut(node_id.into_node_key())
262 .unwrap()
263 .data
264 .as_mut()
265 .unwrap()
266 .cache_clear();
267 }
268}
269
270impl<T, M> PrintTree for TaffyTree<'_, T, M>
271where
272 T: TaffyNode,
273 T::Context: TaffyConfig,
274 M: FnMut(
275 Size<Option<f32>>,
276 Size<AvailableSpace>,
277 NodeId,
278 Option<&mut T::NodeContext>,
279 &T::CoreContainerStyle,
280 ) -> Size<f32>,
281{
282 #[inline(always)]
283 fn get_debug_label(&self, node_id: NodeId) -> &'static str {
284 let node = self.composer.nodes[node_id.into_node_key()]
285 .data
286 .as_ref()
287 .unwrap();
288 let display = node.get_display();
289 let num_children = self.child_count(node_id);
290
291 match (num_children, display) {
292 (_, Display::None) => "NONE",
293 (0, _) => "LEAF",
294 #[cfg(feature = "block_layout")]
295 (_, Display::Block) => "BLOCK",
296 #[cfg(feature = "flexbox")]
297 (_, Display::Flex) => match node.get_flexbox_container_style().flex_direction() {
298 FlexDirection::Row | FlexDirection::RowReverse => "FLEX ROW",
299 FlexDirection::Column | FlexDirection::ColumnReverse => "FLEX COL",
300 },
301 #[cfg(feature = "grid")]
302 (_, Display::Grid) => "GRID",
303 }
304 }
305
306 #[inline(always)]
307 fn get_final_layout(&self, node_id: NodeId) -> &Layout {
308 if self.composer.context.use_rounding() {
309 self.composer.nodes[node_id.into_node_key()]
310 .data
311 .as_ref()
312 .unwrap()
313 .get_final_layout()
314 } else {
315 self.composer.nodes[node_id.into_node_key()]
316 .data
317 .as_ref()
318 .unwrap()
319 .get_unrounded_layout()
320 }
321 }
322}
323
324impl<T, M> LayoutPartialTree for TaffyTree<'_, T, M>
325where
326 T: TaffyNode,
327 T::Context: TaffyConfig,
328 M: FnMut(
329 Size<Option<f32>>,
330 Size<AvailableSpace>,
331 NodeId,
332 Option<&mut T::NodeContext>,
333 &T::CoreContainerStyle,
334 ) -> Size<f32>,
335{
336 type CoreContainerStyle<'a>
337 = &'a T::CoreContainerStyle
338 where
339 Self: 'a;
340
341 #[inline(always)]
342 fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
343 self.composer.nodes[node_id.into_node_key()]
344 .data
345 .as_ref()
346 .unwrap()
347 .get_core_container_style()
348 }
349
350 #[inline(always)]
351 fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
352 self.composer
353 .nodes
354 .get_mut(node_id.into_node_key())
355 .unwrap()
356 .data
357 .as_mut()
358 .unwrap()
359 .set_unrounded_layout(layout);
360 }
361
362 #[inline(always)]
363 fn compute_child_layout(
364 &mut self,
365 node_id: NodeId,
366 inputs: taffy::LayoutInput,
367 ) -> taffy::LayoutOutput {
368 if inputs.run_mode == RunMode::PerformHiddenLayout {
371 return compute_hidden_layout(self, node_id);
372 }
373
374 compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
380 let node_key = node_id.into_node_key();
381 let display_mode = tree.composer.nodes[node_key]
382 .data
383 .as_ref()
384 .unwrap()
385 .get_display();
386 let has_children = tree.child_count(node_id) > 0;
387
388 match (display_mode, has_children) {
390 (Display::None, _) => compute_hidden_layout(tree, node_id),
391 #[cfg(feature = "block_layout")]
392 (Display::Block, true) => compute_block_layout(tree, node_id, inputs),
393 #[cfg(feature = "flexbox")]
394 (Display::Flex, true) => compute_flexbox_layout(tree, node_id, inputs),
395 #[cfg(feature = "grid")]
396 (Display::Grid, true) => compute_grid_layout(tree, node_id, inputs),
397 (_, false) => {
398 let data = tree
399 .composer
400 .nodes
401 .get_mut(node_key)
402 .unwrap()
403 .data
404 .as_mut()
405 .unwrap();
406 let (node_context, style) = data.get_node_context_mut_with_core_style();
407 let measure_function = |known_dimensions, available_space| {
408 (tree.measure_function)(
409 known_dimensions,
410 available_space,
411 node_id,
412 node_context,
413 style,
414 )
415 };
416 compute_leaf_layout(inputs, style, measure_function)
417 }
418 }
419 })
420 }
421}
422
423#[cfg(feature = "block_layout")]
424impl<T, M> LayoutBlockContainer for TaffyTree<'_, T, M>
425where
426 T: TaffyNode,
427 T::Context: TaffyConfig,
428 M: FnMut(
429 Size<Option<f32>>,
430 Size<AvailableSpace>,
431 NodeId,
432 Option<&mut T::NodeContext>,
433 &T::CoreContainerStyle,
434 ) -> Size<f32>,
435{
436 type BlockContainerStyle<'a>
437 = T::BlockContainerStyle<'a>
438 where
439 Self: 'a;
440
441 type BlockItemStyle<'a>
442 = T::BlockItemStyle<'a>
443 where
444 Self: 'a;
445
446 #[inline(always)]
447 fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_> {
448 self.composer.nodes[node_id.into_node_key()]
449 .data
450 .as_ref()
451 .unwrap()
452 .get_block_container_style()
453 }
454
455 #[inline(always)]
456 fn get_block_child_style(&self, node_id: NodeId) -> Self::BlockItemStyle<'_> {
457 self.composer.nodes[node_id.into_node_key()]
458 .data
459 .as_ref()
460 .unwrap()
461 .get_block_item_style()
462 }
463}
464
465#[cfg(feature = "flexbox")]
466impl<T, M> LayoutFlexboxContainer for TaffyTree<'_, T, M>
467where
468 T: TaffyNode,
469 T::Context: TaffyConfig,
470 M: FnMut(
471 Size<Option<f32>>,
472 Size<AvailableSpace>,
473 NodeId,
474 Option<&mut T::NodeContext>,
475 &T::CoreContainerStyle,
476 ) -> Size<f32>,
477{
478 type FlexboxContainerStyle<'a>
479 = T::FlexboxContainerStyle<'a>
480 where
481 Self: 'a;
482
483 type FlexboxItemStyle<'a>
484 = T::FlexboxItemStyle<'a>
485 where
486 Self: 'a;
487
488 #[inline(always)]
489 fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
490 self.composer.nodes[node_id.into_node_key()]
491 .data
492 .as_ref()
493 .unwrap()
494 .get_flexbox_container_style()
495 }
496
497 #[inline(always)]
498 fn get_flexbox_child_style(&self, node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
499 self.composer.nodes[node_id.into_node_key()]
500 .data
501 .as_ref()
502 .unwrap()
503 .get_flexbox_item_style()
504 }
505}
506
507#[cfg(feature = "grid")]
508impl<T, M> LayoutGridContainer for TaffyTree<'_, T, M>
509where
510 T: TaffyNode,
511 T::Context: TaffyConfig,
512 M: FnMut(
513 Size<Option<f32>>,
514 Size<AvailableSpace>,
515 NodeId,
516 Option<&mut T::NodeContext>,
517 &T::CoreContainerStyle,
518 ) -> Size<f32>,
519{
520 type GridContainerStyle<'a>
521 = T::GridContainerStyle<'a>
522 where
523 Self: 'a;
524
525 type GridItemStyle<'a>
526 = T::GridItemStyle<'a>
527 where
528 Self: 'a;
529
530 #[inline(always)]
531 fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
532 self.composer.nodes[node_id.into_node_key()]
533 .data
534 .as_ref()
535 .unwrap()
536 .get_grid_container_style()
537 }
538
539 #[inline(always)]
540 fn get_grid_child_style(&self, node_id: NodeId) -> Self::GridItemStyle<'_> {
541 self.composer.nodes[node_id.into_node_key()]
542 .data
543 .as_ref()
544 .unwrap()
545 .get_grid_item_style()
546 }
547}
548
549impl<T, M> RoundTree for TaffyTree<'_, T, M>
550where
551 T: TaffyNode,
552 T::Context: TaffyConfig,
553 M: FnMut(
554 Size<Option<f32>>,
555 Size<AvailableSpace>,
556 NodeId,
557 Option<&mut T::NodeContext>,
558 &T::CoreContainerStyle,
559 ) -> Size<f32>,
560{
561 #[inline(always)]
562 fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout {
563 self.composer.nodes[node_id.into_node_key()]
564 .data
565 .as_ref()
566 .unwrap()
567 .get_unrounded_layout()
568 }
569
570 #[inline(always)]
571 fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout) {
572 self.composer
573 .nodes
574 .get_mut(node_id.into_node_key())
575 .unwrap()
576 .data
577 .as_mut()
578 .unwrap()
579 .set_final_layout(layout);
580 }
581}