1pub use euclid::Rect;
2use rustc_hash::FxHashMap;
3
4use crate::{
5 custom_measurer::LayoutMeasurer,
6 geometry::{
7 Area,
8 Size2D,
9 },
10 node::Node,
11 prelude::{
12 AlignAxis,
13 Alignment,
14 AlignmentDirection,
15 AreaConverter,
16 AreaModel,
17 AreaOf,
18 Available,
19 AvailableAreaModel,
20 Content,
21 Direction,
22 Inner,
23 LayoutMetadata,
24 Length,
25 Parent,
26 Position,
27 Torin,
28 },
29 size::Size,
30 torin::DirtyReason,
31 tree_adapter::{
32 LayoutNode,
33 NodeKey,
34 TreeAdapter,
35 },
36};
37
38#[derive(Clone, Copy, PartialEq)]
41pub enum Phase {
42 Initial,
43 Final,
44}
45
46pub struct MeasureContext<'a, Key, L, D>
47where
48 Key: NodeKey,
49 L: LayoutMeasurer<Key>,
50 D: TreeAdapter<Key>,
51{
52 pub layout: &'a mut Torin<Key>,
53 pub measurer: &'a mut Option<L>,
54 pub tree_adapter: &'a mut D,
55 pub layout_metadata: LayoutMetadata,
56}
57
58impl<Key, L, D> MeasureContext<'_, Key, L, D>
59where
60 Key: NodeKey,
61 L: LayoutMeasurer<Key>,
62 D: TreeAdapter<Key>,
63{
64 fn translate_node(&mut self, node_id: Key, offset_x: Length, offset_y: Length) {
66 let Some((area, visible_area, inner_sizes)) =
67 self.layout.get_mut(&node_id).map(|layout_node| {
68 layout_node.area.origin.x += offset_x.get();
69 layout_node.area.origin.y += offset_y.get();
70 layout_node.inner_area.origin.x += offset_x.get();
71 layout_node.inner_area.origin.y += offset_y.get();
72 (
73 layout_node.area,
74 layout_node.visible_area(),
75 layout_node.inner_sizes,
76 )
77 })
78 else {
79 return;
80 };
81
82 if let Some(measurer) = self.measurer {
83 measurer.notify_layout_references(node_id, area, visible_area, inner_sizes);
84 }
85 }
86
87 fn recursive_translate(&mut self, node_id: Key, offset_x: Length, offset_y: Length) {
89 let mut buffer = self.tree_adapter.children_of(&node_id);
90 while let Some(child) = buffer.pop() {
91 let node = self
92 .tree_adapter
93 .get_node(&child)
94 .expect("Node does not exist");
95
96 let translate = match node.position {
97 Position::Global(_) => false,
98 Position::Stacked(_) | Position::Absolute(_) => true,
99 };
100
101 if translate {
102 self.translate_node(child, offset_x, offset_y);
103 buffer.extend(self.tree_adapter.children_of(&child));
104 }
105 }
106 }
107
108 fn set_hidden(&mut self, node_id: Key, hidden: bool) {
110 let mut buffer = vec![node_id];
111 while let Some(child) = buffer.pop() {
112 if let Some(layout_node) = self.layout.get_mut(&child) {
113 layout_node.hidden = hidden;
114 }
115 buffer.extend(self.tree_adapter.children_of(&child));
116 }
117 }
118
119 fn apply_post_measure(&mut self, node_id: Key, node_layout: &LayoutNode) -> Option<Size2D> {
122 let post_measure = {
123 let measurer = self.measurer.as_mut()?;
124 if !measurer.should_post_measure(node_id) {
125 return None;
126 }
127 let children = self.tree_adapter.children_of(&node_id);
128 measurer.post_measure(node_id, node_layout, &children, self.layout)
129 };
130
131 for (child_id, offset_x, offset_y) in post_measure.offsets {
132 self.set_hidden(child_id, false);
133 self.translate_node(child_id, offset_x, offset_y);
134 self.recursive_translate(child_id, offset_x, offset_y);
135 }
136
137 for child_id in post_measure.hidden_children {
138 self.set_hidden(child_id, true);
139 }
140
141 post_measure.content_size
142 }
143
144 #[allow(clippy::too_many_arguments, clippy::missing_panics_doc)]
146 pub fn measure_node(
147 &mut self,
148 node_id: Key,
149 node: &Node,
150 initial_parent_area: AreaOf<Parent>,
152 available_parent_area: AreaOf<Available>,
154 must_cache_children: bool,
156 parent_is_dirty: bool,
158 phase: Phase,
160 ) -> (bool, LayoutNode) {
161 let reason = self.layout.dirty.get(&node_id).copied();
162
163 if let Some(layout_node) = self.layout.get_mut(&node_id)
165 && reason == Some(DirtyReason::InnerLayout)
166 && must_cache_children
167 {
168 let offset_x = node.offset_x - layout_node.offset_x;
170 let offset_y = node.offset_y - layout_node.offset_y;
171
172 layout_node.offset_x = node.offset_x;
173 layout_node.offset_y = node.offset_y;
174
175 let layout_node = layout_node.clone();
176
177 self.recursive_translate(node_id, offset_x, offset_y);
178
179 return (must_cache_children, layout_node);
180 }
181
182 let must_revalidate =
186 parent_is_dirty || reason.is_some() || !self.layout.results.contains_key(&node_id);
187 if must_revalidate {
188 let mut area_size = Size2D::new(node.padding.horizontal(), node.padding.vertical());
190
191 area_size.width = node.width.min_max(
193 area_size.width,
194 initial_parent_area.size.width,
195 available_parent_area.size.width,
196 node.margin.left(),
197 node.margin.horizontal(),
198 &node.minimum_width,
199 &node.maximum_width,
200 self.layout_metadata.root_area.width(),
201 phase,
202 );
203 area_size.height = node.height.min_max(
204 area_size.height,
205 initial_parent_area.size.height,
206 available_parent_area.size.height,
207 node.margin.top(),
208 node.margin.vertical(),
209 &node.minimum_height,
210 &node.maximum_height,
211 self.layout_metadata.root_area.height(),
212 phase,
213 );
214
215 let node_data = if let Some(measurer) = self.measurer {
218 if measurer.should_hook_measurement(node_id) {
219 let available_width =
220 Size::Pixels(Length::new(available_parent_area.size.width)).min_max(
221 area_size.width,
222 initial_parent_area.size.width,
223 available_parent_area.size.width,
224 node.margin.left(),
225 node.margin.horizontal(),
226 &node.minimum_width,
227 &node.maximum_width,
228 self.layout_metadata.root_area.width(),
229 phase,
230 );
231 let available_height =
232 Size::Pixels(Length::new(available_parent_area.size.height)).min_max(
233 area_size.height,
234 initial_parent_area.size.height,
235 available_parent_area.size.height,
236 node.margin.top(),
237 node.margin.vertical(),
238 &node.minimum_height,
239 &node.maximum_height,
240 self.layout_metadata.root_area.height(),
241 phase,
242 );
243 let most_fitting_width = *node
244 .width
245 .most_fitting_size(&area_size.width, &available_width);
246 let most_fitting_height = *node
247 .height
248 .most_fitting_size(&area_size.height, &available_height);
249
250 let most_fitting_area_size =
251 Size2D::new(most_fitting_width, most_fitting_height);
252 let res = measurer.measure(node_id, node, &most_fitting_area_size);
253
254 #[allow(clippy::float_cmp)]
256 if let Some((custom_size, node_data)) = res {
257 if node.width.inner_sized() {
258 area_size.width = node.width.min_max(
259 custom_size.width,
260 initial_parent_area.size.width,
261 available_parent_area.size.width,
262 node.margin.left(),
263 node.margin.horizontal(),
264 &node.minimum_width,
265 &node.maximum_width,
266 self.layout_metadata.root_area.width(),
267 phase,
268 );
269 }
270 if node.height.inner_sized() {
271 area_size.height = node.height.min_max(
272 custom_size.height,
273 initial_parent_area.size.height,
274 available_parent_area.size.height,
275 node.margin.top(),
276 node.margin.vertical(),
277 &node.minimum_height,
278 &node.maximum_height,
279 self.layout_metadata.root_area.height(),
280 phase,
281 );
282 }
283
284 Some(node_data)
286 } else {
287 None
288 }
289 } else {
290 None
291 }
292 } else {
293 None
294 };
295
296 let measure_inner_children = if let Some(measurer) = self.measurer {
297 measurer.should_measure_inner_children(node_id)
298 } else {
299 true
300 };
301
302 let phase_measure_inner_children = if phase == Phase::Initial {
305 node.width.inner_sized() || node.height.inner_sized()
306 } else {
307 true
308 };
309
310 let inner_size = {
312 let mut inner_size = area_size;
313
314 if node.width.inner_sized() {
316 inner_size.width = node.width.min_max(
317 available_parent_area.width(),
318 initial_parent_area.size.width,
319 available_parent_area.width(),
320 node.margin.left(),
321 node.margin.horizontal(),
322 &node.minimum_width,
323 &node.maximum_width,
324 self.layout_metadata.root_area.width(),
325 phase,
326 );
327 }
328 if node.height.inner_sized() {
329 inner_size.height = node.height.min_max(
330 available_parent_area.height(),
331 initial_parent_area.size.height,
332 available_parent_area.height(),
333 node.margin.top(),
334 node.margin.vertical(),
335 &node.minimum_height,
336 &node.maximum_height,
337 self.layout_metadata.root_area.height(),
338 phase,
339 );
340 }
341 inner_size
342 };
343
344 let area_origin = node.position.get_origin(
346 &available_parent_area,
347 &initial_parent_area,
348 area_size,
349 &self.layout_metadata.root_area,
350 );
351 let mut area = Area::new(area_origin, area_size);
352 let mut inner_area = Rect::new(area_origin, inner_size)
353 .without_gaps(&node.padding)
354 .without_gaps(&node.margin)
355 .as_inner();
356 inner_area.move_with_offsets(&node.offset_x, &node.offset_y);
357
358 let mut inner_sizes = Size2D::default();
359
360 if measure_inner_children && phase_measure_inner_children {
361 let mut available_area = inner_area.as_available();
363
364 let mut parent_area = area.as_parent();
365
366 self.measure_children(
368 &node_id,
369 node,
370 &mut parent_area,
371 &mut inner_area,
372 &mut available_area,
373 &mut inner_sizes,
374 must_cache_children,
375 true,
376 );
377
378 if node.width.inner_sized() {
381 parent_area.size.width = node.width.min_max(
382 parent_area.size.width,
383 initial_parent_area.size.width,
384 available_parent_area.size.width,
385 0.,
386 0.,
387 &node.minimum_width,
388 &node.maximum_width,
389 self.layout_metadata.root_area.width(),
390 phase,
391 );
392 }
393 if node.height.inner_sized() {
394 parent_area.size.height = node.height.min_max(
395 parent_area.size.height,
396 initial_parent_area.size.height,
397 available_parent_area.size.height,
398 0.,
399 0.,
400 &node.minimum_height,
401 &node.maximum_height,
402 self.layout_metadata.root_area.height(),
403 phase,
404 );
405 }
406
407 area = parent_area.cast_unit();
408
409 if !node.position.is_stacked()
412 && (node.width.inner_sized() || node.height.inner_sized())
413 && must_cache_children
414 {
415 let new_origin = node.position.get_origin(
416 &available_parent_area,
417 &initial_parent_area,
418 area.size,
419 &self.layout_metadata.root_area,
420 );
421 let diff_x = new_origin.x - area.origin.x;
422 let diff_y = new_origin.y - area.origin.y;
423 area.origin = new_origin;
424 inner_area.origin.x += diff_x;
425 inner_area.origin.y += diff_y;
426
427 if diff_x != 0.0 || diff_y != 0.0 {
428 self.recursive_translate(node_id, Length::new(diff_x), Length::new(diff_y));
429 }
430 }
431 }
432
433 let mut layout_node = LayoutNode {
434 area,
435 margin: node.margin,
436 offset_x: node.offset_x,
437 offset_y: node.offset_y,
438 inner_area,
439 hidden: false,
440 data: node_data,
441 inner_sizes,
442 };
443
444 if must_cache_children
445 && phase == Phase::Final
446 && let Some(content_size) = self.apply_post_measure(node_id, &layout_node)
447 {
448 if node.width.inner_sized() {
451 layout_node.area.size.width = node.width.min_max(
452 content_size.width,
453 initial_parent_area.size.width,
454 available_parent_area.size.width,
455 node.margin.left(),
456 node.margin.horizontal(),
457 &node.minimum_width,
458 &node.maximum_width,
459 self.layout_metadata.root_area.width(),
460 phase,
461 );
462 }
463 if node.height.inner_sized() {
464 layout_node.area.size.height = node.height.min_max(
465 content_size.height,
466 initial_parent_area.size.height,
467 available_parent_area.size.height,
468 node.margin.top(),
469 node.margin.vertical(),
470 &node.minimum_height,
471 &node.maximum_height,
472 self.layout_metadata.root_area.height(),
473 phase,
474 );
475 }
476 }
477
478 if must_cache_children
480 && phase == Phase::Final
481 && node.has_layout_references
482 && let Some(measurer) = self.measurer
483 {
484 inner_sizes.width += node.padding.horizontal();
485 inner_sizes.height += node.padding.vertical();
486 measurer.notify_layout_references(
487 node_id,
488 layout_node.area,
489 layout_node.visible_area(),
490 inner_sizes,
491 );
492 }
493
494 (must_cache_children, layout_node)
495 } else {
496 let layout_node = self
497 .layout
498 .get(&node_id)
499 .expect("Cached node does not exist")
500 .clone();
501
502 let mut inner_sizes = Size2D::default();
503 let mut area = layout_node.area.as_parent();
504 let mut inner_area = layout_node.inner_area.as_inner();
505 let mut available_area = inner_area.as_available();
506
507 let measure_inner_children = if let Some(measurer) = self.measurer {
508 measurer.should_measure_inner_children(node_id)
509 } else {
510 true
511 };
512
513 if measure_inner_children {
514 self.measure_children(
515 &node_id,
516 node,
517 &mut area,
518 &mut inner_area,
519 &mut available_area,
520 &mut inner_sizes,
521 must_cache_children,
522 false,
523 );
524 }
525
526 (false, layout_node)
527 }
528 }
529
530 #[allow(clippy::too_many_arguments)]
532 pub fn measure_children(
533 &mut self,
534 parent_node_id: &Key,
535 parent_node: &Node,
536 parent_area: &mut AreaOf<Parent>,
537 inner_area: &mut AreaOf<Inner>,
538 available_area: &mut AreaOf<Available>,
539 inner_sizes: &mut Size2D,
541 must_cache_children: bool,
543 parent_is_dirty: bool,
545 ) {
546 let children = self.tree_adapter.children_of(parent_node_id);
547
548 let initial_area = *inner_area;
549
550 let mut initial_phase_flex_grows = FxHashMap::default();
551 let mut initial_phase_sizes = FxHashMap::default();
552 let mut initial_phase_inner_sizes = Size2D::default();
553
554 let (non_absolute_children_len, first_child, last_child) = if parent_node.spacing.get() > 0.
556 {
557 let mut last_child = None;
558 let mut first_child = None;
559 let len = children
560 .iter()
561 .filter(|child_id| {
562 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
563 return false;
564 };
565 let is_stacked = child_data.position.is_stacked();
566 if is_stacked {
567 last_child = Some(**child_id);
568
569 if first_child.is_none() {
570 first_child = Some(**child_id);
571 }
572 }
573 is_stacked
574 })
575 .count();
576 (len, first_child, last_child)
577 } else {
578 (
579 children.len(),
580 children.first().copied(),
581 children.last().copied(),
582 )
583 };
584
585 let needs_initial_phase = parent_node.cross_alignment.is_not_start()
586 || parent_node.main_alignment.is_not_start()
587 || parent_node.content.is_fit()
588 || parent_node.content.is_flex()
589 || parent_node.content.is_wrap();
590
591 let mut initial_phase_parent_area = *parent_area;
592 let mut initial_phase_inner_area = *inner_area;
593 let mut initial_phase_available_area = *available_area;
594
595 if needs_initial_phase {
598 for child_id in &children {
600 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
601 continue;
602 };
603
604 if !child_data.position.is_stacked() {
607 continue;
608 }
609
610 let is_last_child = last_child == Some(*child_id);
611
612 let (_, mut child_areas) = self.measure_node(
613 *child_id,
614 &child_data,
615 initial_area.as_parent(),
616 initial_phase_available_area,
617 false,
618 parent_is_dirty,
619 Phase::Initial,
620 );
621
622 child_areas.area.adjust_size(&child_data);
623
624 Self::stack_child(
626 &mut initial_phase_available_area,
627 parent_node,
628 &child_data,
629 &mut initial_phase_parent_area,
630 &mut initial_phase_inner_area,
631 &mut initial_phase_inner_sizes,
632 &child_areas.area,
633 is_last_child,
634 Phase::Initial,
635 );
636
637 if parent_node.cross_alignment.is_not_start()
638 || parent_node.main_alignment.is_spaced()
639 || parent_node.content.is_wrap()
640 {
641 initial_phase_sizes.insert(*child_id, child_areas.area.size);
642 }
643
644 if parent_node.content.is_flex() {
645 match parent_node.direction {
646 Direction::Vertical => {
647 if let Some(ff) = child_data.height.flex_grow() {
648 initial_phase_flex_grows.insert(*child_id, ff);
649 }
650 }
651 Direction::Horizontal => {
652 if let Some(ff) = child_data.width.flex_grow() {
653 initial_phase_flex_grows.insert(*child_id, ff);
654 }
655 }
656 }
657 }
658 }
659 }
660
661 let flex_grows = initial_phase_flex_grows
662 .values()
663 .copied()
664 .reduce(|acc, v| acc + v)
665 .unwrap_or_default()
666 .max(Length::new(1.0));
667
668 let flex_axis = AlignAxis::new(&parent_node.direction, AlignmentDirection::Main);
669
670 let flex_available_width = available_area.width() - initial_phase_inner_sizes.width;
671 let flex_available_height = available_area.height() - initial_phase_inner_sizes.height;
672
673 if parent_node.content.is_flex() {
674 initial_phase_inner_sizes =
675 initial_phase_flex_grows
676 .values()
677 .fold(initial_phase_inner_sizes, |mut acc, f| {
678 let flex_grow_per = f.get() / flex_grows.get() * 100.;
679
680 match flex_axis {
681 AlignAxis::Height => {
682 let size = flex_available_height / 100. * flex_grow_per;
683 acc.height += size;
684 }
685 AlignAxis::Width => {
686 let size = flex_available_width / 100. * flex_grow_per;
687 acc.width += size;
688 }
689 }
690
691 acc
692 });
693
694 if parent_node.cross_alignment.is_not_start() {
706 let cross_axis = AlignAxis::new(&parent_node.direction, AlignmentDirection::Cross);
707
708 for child_id in &children {
709 let Some(flex_grow) = initial_phase_flex_grows.get(child_id) else {
710 continue;
711 };
712 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
713 continue;
714 };
715 if !child_data.position.is_stacked() {
716 continue;
717 }
718
719 let has_inner_cross = match cross_axis {
720 AlignAxis::Height => child_data.height.inner_sized(),
721 AlignAxis::Width => child_data.width.inner_sized(),
722 };
723 if !has_inner_cross {
724 continue;
725 }
726
727 let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
728 let mut corrected_available_area = initial_area.as_available();
729
730 match flex_axis {
731 AlignAxis::Height => {
732 corrected_available_area.size.height =
733 flex_available_height / 100. * flex_grow_per;
734 }
735 AlignAxis::Width => {
736 corrected_available_area.size.width =
737 flex_available_width / 100. * flex_grow_per;
738 }
739 }
740
741 let (_, mut child_areas) = self.measure_node(
742 *child_id,
743 &child_data,
744 initial_area.as_parent(),
745 corrected_available_area,
746 false,
747 parent_is_dirty,
748 Phase::Final,
749 );
750
751 child_areas.area.adjust_size(&child_data);
752 initial_phase_sizes.insert(*child_id, child_areas.area.size);
753 }
754
755 let max_cross = children
757 .iter()
758 .filter_map(|id| initial_phase_sizes.get(id))
759 .map(|size| match cross_axis {
760 AlignAxis::Height => size.height,
761 AlignAxis::Width => size.width,
762 })
763 .fold(0.0, f32::max);
764
765 match cross_axis {
766 AlignAxis::Height if parent_node.height.inner_sized() => {
767 let gaps = parent_node.padding.vertical() + parent_node.margin.vertical();
768 initial_phase_parent_area.size.height = max_cross + gaps;
769 initial_phase_inner_area.size.height = max_cross;
770 }
771 AlignAxis::Width if parent_node.width.inner_sized() => {
772 let gaps =
773 parent_node.padding.horizontal() + parent_node.margin.horizontal();
774 initial_phase_parent_area.size.width = max_cross + gaps;
775 initial_phase_inner_area.size.width = max_cross;
776 }
777 _ => {}
778 }
779 }
780 }
781
782 if needs_initial_phase {
783 if parent_node.main_alignment.is_not_start() && parent_node.content.allows_alignments()
784 {
785 Self::shrink_area_to_fit_when_unbounded(
787 available_area,
788 &initial_phase_parent_area,
789 &mut initial_phase_inner_area,
790 parent_node,
791 AlignmentDirection::Main,
792 );
793
794 Self::align_content(
796 available_area,
797 &initial_phase_inner_area,
798 initial_phase_inner_sizes,
799 &parent_node.main_alignment,
800 parent_node.direction,
801 AlignmentDirection::Main,
802 );
803 }
804
805 if (parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit())
806 && parent_node.content.allows_alignments()
807 {
808 Self::shrink_area_to_fit_when_unbounded(
810 available_area,
811 &initial_phase_parent_area,
812 &mut initial_phase_inner_area,
813 parent_node,
814 AlignmentDirection::Cross,
815 );
816 }
817 }
818
819 let initial_available_area = *available_area;
820
821 for child_id in children {
823 let Some(child_data) = self.tree_adapter.get_node(&child_id) else {
824 continue;
825 };
826
827 let is_first_child = first_child == Some(child_id);
828 let is_last_child = last_child == Some(child_id);
829
830 let mut adapted_available_area = *available_area;
831
832 if parent_node.content.is_flex() {
833 let flex_grow = initial_phase_flex_grows.get(&child_id);
834
835 if let Some(flex_grow) = flex_grow {
836 let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
837
838 match flex_axis {
839 AlignAxis::Height => {
840 let size = flex_available_height / 100. * flex_grow_per;
841 adapted_available_area.size.height = size;
842 }
843 AlignAxis::Width => {
844 let size = flex_available_width / 100. * flex_grow_per;
845 adapted_available_area.size.width = size;
846 }
847 }
848 }
849 }
850
851 if parent_node.main_alignment.is_spaced()
853 && child_data.position.is_stacked()
854 && parent_node.content.allows_alignments()
855 {
856 Self::align_position(
858 AlignmentDirection::Main,
859 &mut adapted_available_area,
860 &initial_available_area,
861 initial_phase_inner_sizes,
862 &parent_node.main_alignment,
863 parent_node.direction,
864 non_absolute_children_len,
865 is_first_child,
866 );
867 }
868
869 if parent_node.cross_alignment.is_not_start() && parent_node.content.allows_alignments()
870 {
871 let initial_phase_size = initial_phase_sizes.get(&child_id);
872
873 if let Some(initial_phase_size) = initial_phase_size {
874 Self::align_content(
876 &mut adapted_available_area,
877 &available_area.as_inner(),
878 *initial_phase_size,
879 &parent_node.cross_alignment,
880 parent_node.direction,
881 AlignmentDirection::Cross,
882 );
883 }
884 }
885
886 if let Content::Wrap { wrap_spacing } = parent_node.content {
887 let initial_phase_size = initial_phase_sizes.get(&child_id);
888 Self::wrap_child(
889 wrap_spacing.unwrap_or_default(),
890 parent_node.direction,
891 initial_phase_size,
892 &initial_available_area,
893 parent_area,
894 available_area,
895 &mut adapted_available_area,
896 *inner_sizes,
897 );
898 }
899
900 let (child_revalidated, mut child_areas) = self.measure_node(
902 child_id,
903 &child_data,
904 initial_area.as_parent(),
905 adapted_available_area,
906 must_cache_children,
907 parent_is_dirty,
908 Phase::Final,
909 );
910
911 child_areas.area.adjust_size(&child_data);
913
914 if child_data.position.is_stacked() {
916 Self::stack_child(
917 available_area,
918 parent_node,
919 &child_data,
920 parent_area,
921 inner_area,
922 inner_sizes,
923 &child_areas.area,
924 is_last_child,
925 Phase::Final,
926 );
927 }
928
929 if child_revalidated && must_cache_children {
931 self.layout.cache_node(child_id, child_areas);
933 }
934 }
935 }
936
937 #[allow(clippy::too_many_arguments)]
938 fn wrap_child(
939 wrap_spacing: f32,
940 direction: Direction,
941 initial_phase_size: Option<&Size2D>,
942 initial_available_area: &AreaOf<Available>,
943 parent_area: &mut AreaOf<Parent>,
944 available_area: &mut AreaOf<Available>,
945 adapted_available_area: &mut AreaOf<Available>,
946 inner_sizes: Size2D,
947 ) {
948 if let Some(initial_phase_size) = initial_phase_size {
949 match direction {
950 Direction::Vertical => {
951 if adapted_available_area.height() - initial_phase_size.height < 0. {
952 let advance = inner_sizes.width + wrap_spacing;
953 available_area.origin.y = initial_available_area.origin.y;
954 available_area.size.height = initial_available_area.size.height;
955 available_area.origin.x += advance;
956 adapted_available_area.origin.y = initial_available_area.origin.y;
957 adapted_available_area.size.height = initial_available_area.size.height;
958 adapted_available_area.origin.x += advance;
959 parent_area.size.width += advance;
960 }
961 }
962 Direction::Horizontal => {
963 if adapted_available_area.width() - initial_phase_size.width < 0. {
964 let advance = inner_sizes.height + wrap_spacing;
965 available_area.origin.x = initial_available_area.origin.x;
966 available_area.size.width = initial_available_area.size.width;
967 available_area.origin.y += advance;
968 adapted_available_area.origin.x = initial_available_area.origin.x;
969 adapted_available_area.size.width = initial_available_area.size.width;
970 adapted_available_area.origin.y += advance;
971 parent_area.size.height += advance;
972 }
973 }
974 }
975 }
976 }
977
978 fn align_content(
980 available_area: &mut AreaOf<Available>,
981 inner_area: &AreaOf<Inner>,
982 contents_size: Size2D,
983 alignment: &Alignment,
984 direction: Direction,
985 alignment_direction: AlignmentDirection,
986 ) {
987 let axis = AlignAxis::new(&direction, alignment_direction);
988
989 match axis {
990 AlignAxis::Height => match alignment {
991 Alignment::Center => {
992 let new_origin_y = (inner_area.height() / 2.0) - (contents_size.height / 2.0);
993 available_area.origin.y = inner_area.min_y() + new_origin_y;
994 }
995 Alignment::End => {
996 available_area.origin.y = inner_area.max_y() - contents_size.height;
997 }
998 _ => {}
999 },
1000 AlignAxis::Width => match alignment {
1001 Alignment::Center => {
1002 let new_origin_x = (inner_area.width() / 2.0) - (contents_size.width / 2.0);
1003 available_area.origin.x = inner_area.min_x() + new_origin_x;
1004 }
1005 Alignment::End => {
1006 available_area.origin.x = inner_area.max_x() - contents_size.width;
1007 }
1008 _ => {}
1009 },
1010 }
1011 }
1012
1013 #[allow(clippy::too_many_arguments)]
1015 fn align_position(
1016 alignment_direction: AlignmentDirection,
1017 available_area: &mut AreaOf<Available>,
1018 initial_available_area: &AreaOf<Available>,
1019 inner_sizes: Size2D,
1020 alignment: &Alignment,
1021 direction: Direction,
1022 siblings_len: usize,
1023 is_first_sibling: bool,
1024 ) {
1025 let axis = AlignAxis::new(&direction, alignment_direction);
1026
1027 match axis {
1028 AlignAxis::Height => match alignment {
1029 Alignment::SpaceBetween if !is_first_sibling => {
1030 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
1031 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
1032 available_area.origin.y += gap_size;
1033 }
1034 Alignment::SpaceEvenly => {
1035 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
1036 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
1037 available_area.origin.y += gap_size;
1038 }
1039 Alignment::SpaceAround => {
1040 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
1041 let one_gap_size = all_gaps_sizes / siblings_len as f32;
1042 let gap_size = if is_first_sibling {
1043 one_gap_size / 2.
1044 } else {
1045 one_gap_size
1046 };
1047 available_area.origin.y += gap_size;
1048 }
1049 _ => {}
1050 },
1051 AlignAxis::Width => match alignment {
1052 Alignment::SpaceBetween if !is_first_sibling => {
1053 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
1054 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
1055 available_area.origin.x += gap_size;
1056 }
1057 Alignment::SpaceEvenly => {
1058 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
1059 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
1060 available_area.origin.x += gap_size;
1061 }
1062 Alignment::SpaceAround => {
1063 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
1064 let one_gap_size = all_gaps_sizes / siblings_len as f32;
1065 let gap_size = if is_first_sibling {
1066 one_gap_size / 2.
1067 } else {
1068 one_gap_size
1069 };
1070 available_area.origin.x += gap_size;
1071 }
1072 _ => {}
1073 },
1074 }
1075 }
1076
1077 #[allow(clippy::too_many_arguments)]
1079 fn stack_child(
1080 available_area: &mut AreaOf<Available>,
1081 parent_node: &Node,
1082 child_node: &Node,
1083 parent_area: &mut AreaOf<Parent>,
1084 inner_area: &mut AreaOf<Inner>,
1085 inner_sizes: &mut Size2D,
1086 child_area: &Area,
1087 is_last_sibilin: bool,
1088 phase: Phase,
1089 ) {
1090 let spacing = if is_last_sibilin {
1092 Length::default()
1093 } else {
1094 parent_node.spacing
1095 };
1096
1097 match parent_node.direction {
1098 Direction::Horizontal => {
1099 available_area.origin.x = child_area.max_x() + spacing.get();
1101 available_area.size.width -= child_area.size.width + spacing.get();
1102
1103 inner_sizes.height = child_area.height().max(inner_sizes.height);
1104 inner_sizes.width += spacing.get();
1105 if !child_node.width.is_flex() || phase == Phase::Final {
1106 inner_sizes.width += child_area.width();
1107 }
1108
1109 if parent_node.height.inner_sized() {
1111 parent_area.size.height = parent_area.size.height.max(
1112 child_area.size.height
1113 + parent_node.padding.vertical()
1114 + parent_node.margin.vertical(),
1115 );
1116 inner_area.size.height = parent_area.size.height
1118 - parent_node.padding.vertical()
1119 - parent_node.margin.vertical();
1120 }
1121
1122 if parent_node.width.inner_sized() {
1124 parent_area.size.width += child_area.size.width + spacing.get();
1125 }
1126 }
1127 Direction::Vertical => {
1128 available_area.origin.y = child_area.max_y() + spacing.get();
1130 available_area.size.height -= child_area.size.height + spacing.get();
1131
1132 inner_sizes.width = child_area.width().max(inner_sizes.width);
1133 inner_sizes.height += spacing.get();
1134 if !child_node.height.is_flex() || phase == Phase::Final {
1135 inner_sizes.height += child_area.height();
1136 }
1137
1138 if parent_node.width.inner_sized() {
1140 parent_area.size.width = parent_area.size.width.max(
1141 child_area.size.width
1142 + parent_node.padding.horizontal()
1143 + parent_node.margin.horizontal(),
1144 );
1145 inner_area.size.width = parent_area.size.width
1147 - parent_node.padding.horizontal()
1148 - parent_node.margin.horizontal();
1149 }
1150
1151 if parent_node.height.inner_sized() {
1153 parent_area.size.height += child_area.size.height + spacing.get();
1154 }
1155 }
1156 }
1157 }
1158
1159 fn shrink_area_to_fit_when_unbounded(
1165 available_area: &mut AreaOf<Available>,
1166 parent_area: &AreaOf<Parent>,
1167 inner_area: &mut AreaOf<Inner>,
1168 parent_node: &Node,
1169 alignment_direction: AlignmentDirection,
1170 ) {
1171 struct NodeData<'a> {
1172 pub inner_origin: &'a mut f32,
1173 pub inner_size: &'a mut f32,
1174 pub area_origin: f32,
1175 pub area_size: f32,
1176 pub one_side_padding: f32,
1177 pub two_sides_padding: f32,
1178 pub one_side_margin: f32,
1179 pub two_sides_margin: f32,
1180 pub available_size: &'a mut f32,
1181 }
1182
1183 let axis = AlignAxis::new(&parent_node.direction, alignment_direction);
1184 let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction {
1185 Direction::Vertical => (
1186 parent_node.main_alignment.is_not_start(),
1187 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1188 ),
1189 Direction::Horizontal => (
1190 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1191 parent_node.main_alignment.is_not_start(),
1192 ),
1193 };
1194 let NodeData {
1195 inner_origin,
1196 inner_size,
1197 area_origin,
1198 area_size,
1199 one_side_padding,
1200 two_sides_padding,
1201 one_side_margin,
1202 two_sides_margin,
1203 available_size,
1204 } = match axis {
1205 AlignAxis::Height if parent_node.height.inner_sized() && is_vertical_not_start => {
1206 NodeData {
1207 inner_origin: &mut inner_area.origin.y,
1208 inner_size: &mut inner_area.size.height,
1209 area_origin: parent_area.origin.y,
1210 area_size: parent_area.size.height,
1211 one_side_padding: parent_node.padding.top(),
1212 two_sides_padding: parent_node.padding.vertical(),
1213 one_side_margin: parent_node.margin.top(),
1214 two_sides_margin: parent_node.margin.vertical(),
1215 available_size: &mut available_area.size.height,
1216 }
1217 }
1218 AlignAxis::Width if parent_node.width.inner_sized() && is_horizontal_not_start => {
1219 NodeData {
1220 inner_origin: &mut inner_area.origin.x,
1221 inner_size: &mut inner_area.size.width,
1222 area_origin: parent_area.origin.x,
1223 area_size: parent_area.size.width,
1224 one_side_padding: parent_node.padding.left(),
1225 two_sides_padding: parent_node.padding.horizontal(),
1226 one_side_margin: parent_node.margin.left(),
1227 two_sides_margin: parent_node.margin.horizontal(),
1228 available_size: &mut available_area.size.width,
1229 }
1230 }
1231 _ => return,
1232 };
1233
1234 *inner_origin = area_origin + one_side_padding + one_side_margin;
1236 *inner_size = area_size - two_sides_padding - two_sides_margin;
1238 *available_size = *inner_size;
1240 }
1241}