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 Direction,
21 Inner,
22 LayoutMetadata,
23 Length,
24 Parent,
25 Position,
26 Torin,
27 },
28 size::Size,
29 torin::DirtyReason,
30 tree_adapter::{
31 LayoutNode,
32 NodeKey,
33 TreeAdapter,
34 },
35};
36
37#[derive(Clone, Copy, PartialEq)]
40pub enum Phase {
41 Initial,
42 Final,
43}
44
45pub struct MeasureContext<'a, Key, L, D>
46where
47 Key: NodeKey,
48 L: LayoutMeasurer<Key>,
49 D: TreeAdapter<Key>,
50{
51 pub layout: &'a mut Torin<Key>,
52 pub measurer: &'a mut Option<L>,
53 pub tree_adapter: &'a mut D,
54 pub layout_metadata: LayoutMetadata,
55}
56
57impl<Key, L, D> MeasureContext<'_, Key, L, D>
58where
59 Key: NodeKey,
60 L: LayoutMeasurer<Key>,
61 D: TreeAdapter<Key>,
62{
63 fn recursive_translate(&mut self, node_id: Key, offset_x: Length, offset_y: Length) {
65 let mut buffer = self.tree_adapter.children_of(&node_id);
66 while let Some(child) = buffer.pop() {
67 let node = self
68 .tree_adapter
69 .get_node(&child)
70 .expect("Node does not exist");
71
72 let translate = match node.position {
73 Position::Global(_) => false,
74 Position::Stacked(_) | Position::Absolute(_) => true,
75 };
76
77 if translate {
78 let layout_node = self
79 .layout
80 .get_mut(&child)
81 .expect("Cached node does not exist");
82 layout_node.area.origin.x += offset_x.get();
83 layout_node.area.origin.y += offset_y.get();
84 layout_node.inner_area.origin.x += offset_x.get();
85 layout_node.inner_area.origin.y += offset_y.get();
86
87 if let Some(measurer) = self.measurer {
88 measurer.notify_layout_references(
89 child,
90 layout_node.area,
91 layout_node.visible_area(),
92 layout_node.inner_sizes,
93 );
94 }
95
96 buffer.extend(self.tree_adapter.children_of(&child));
97 }
98 }
99 }
100
101 #[allow(clippy::too_many_arguments, clippy::missing_panics_doc)]
103 pub fn measure_node(
104 &mut self,
105 node_id: Key,
106 node: &Node,
107 parent_area: AreaOf<Parent>,
109 initial_parent_area: AreaOf<Parent>,
111 available_parent_area: AreaOf<Available>,
113 must_cache_children: bool,
115 parent_is_dirty: bool,
117 phase: Phase,
119 ) -> (bool, LayoutNode) {
120 let reason = self.layout.dirty.get(&node_id).copied();
121
122 if let Some(layout_node) = self.layout.get_mut(&node_id)
124 && reason == Some(DirtyReason::InnerLayout)
125 && must_cache_children
126 {
127 let offset_x = node.offset_x - layout_node.offset_x;
129 let offset_y = node.offset_y - layout_node.offset_y;
130
131 layout_node.offset_x = node.offset_x;
132 layout_node.offset_y = node.offset_y;
133
134 let layout_node = layout_node.clone();
135
136 self.recursive_translate(node_id, offset_x, offset_y);
137
138 return (must_cache_children, layout_node);
139 }
140
141 let must_revalidate =
145 parent_is_dirty || reason.is_some() || !self.layout.results.contains_key(&node_id);
146 if must_revalidate {
147 let mut area_size = Size2D::new(node.padding.horizontal(), node.padding.vertical());
149
150 area_size.width = node.width.min_max(
152 area_size.width,
153 initial_parent_area.size.width,
154 available_parent_area.size.width,
155 node.margin.left(),
156 node.margin.horizontal(),
157 &node.minimum_width,
158 &node.maximum_width,
159 self.layout_metadata.root_area.width(),
160 phase,
161 );
162 area_size.height = node.height.min_max(
163 area_size.height,
164 initial_parent_area.size.height,
165 available_parent_area.size.height,
166 node.margin.top(),
167 node.margin.vertical(),
168 &node.minimum_height,
169 &node.maximum_height,
170 self.layout_metadata.root_area.height(),
171 phase,
172 );
173
174 let node_data = if let Some(measurer) = self.measurer {
177 if measurer.should_hook_measurement(node_id) {
178 let available_width =
179 Size::Pixels(Length::new(available_parent_area.size.width)).min_max(
180 area_size.width,
181 initial_parent_area.size.width,
182 available_parent_area.size.width,
183 node.margin.left(),
184 node.margin.horizontal(),
185 &node.minimum_width,
186 &node.maximum_width,
187 self.layout_metadata.root_area.width(),
188 phase,
189 );
190 let available_height =
191 Size::Pixels(Length::new(available_parent_area.size.height)).min_max(
192 area_size.height,
193 initial_parent_area.size.height,
194 available_parent_area.size.height,
195 node.margin.top(),
196 node.margin.vertical(),
197 &node.minimum_height,
198 &node.maximum_height,
199 self.layout_metadata.root_area.height(),
200 phase,
201 );
202 let most_fitting_width = *node
203 .width
204 .most_fitting_size(&area_size.width, &available_width);
205 let most_fitting_height = *node
206 .height
207 .most_fitting_size(&area_size.height, &available_height);
208
209 let most_fitting_area_size =
210 Size2D::new(most_fitting_width, most_fitting_height);
211 let res = measurer.measure(node_id, node, &most_fitting_area_size);
212
213 #[allow(clippy::float_cmp)]
215 if let Some((custom_size, node_data)) = res {
216 if node.width.inner_sized() {
217 area_size.width = node.width.min_max(
218 custom_size.width,
219 initial_parent_area.size.width,
220 available_parent_area.size.width,
221 node.margin.left(),
222 node.margin.horizontal(),
223 &node.minimum_width,
224 &node.maximum_width,
225 self.layout_metadata.root_area.width(),
226 phase,
227 );
228 }
229 if node.height.inner_sized() {
230 area_size.height = node.height.min_max(
231 custom_size.height,
232 initial_parent_area.size.height,
233 available_parent_area.size.height,
234 node.margin.top(),
235 node.margin.vertical(),
236 &node.minimum_height,
237 &node.maximum_height,
238 self.layout_metadata.root_area.height(),
239 phase,
240 );
241 }
242
243 Some(node_data)
245 } else {
246 None
247 }
248 } else {
249 None
250 }
251 } else {
252 None
253 };
254
255 let measure_inner_children = if let Some(measurer) = self.measurer {
256 measurer.should_measure_inner_children(node_id)
257 } else {
258 true
259 };
260
261 let phase_measure_inner_children = if phase == Phase::Initial {
264 node.width.inner_sized() || node.height.inner_sized()
265 } else {
266 true
267 };
268
269 let inner_size = {
271 let mut inner_size = area_size;
272
273 if node.width.inner_sized() {
275 inner_size.width = node.width.min_max(
276 available_parent_area.width(),
277 initial_parent_area.size.width,
278 available_parent_area.width(),
279 node.margin.left(),
280 node.margin.horizontal(),
281 &node.minimum_width,
282 &node.maximum_width,
283 self.layout_metadata.root_area.width(),
284 phase,
285 );
286 }
287 if node.height.inner_sized() {
288 inner_size.height = node.height.min_max(
289 available_parent_area.height(),
290 initial_parent_area.size.height,
291 available_parent_area.height(),
292 node.margin.top(),
293 node.margin.vertical(),
294 &node.minimum_height,
295 &node.maximum_height,
296 self.layout_metadata.root_area.height(),
297 phase,
298 );
299 }
300 inner_size
301 };
302
303 let area_origin = node.position.get_origin(
305 &available_parent_area,
306 &parent_area,
307 area_size,
308 &self.layout_metadata.root_area,
309 );
310 let mut area = Area::new(area_origin, area_size);
311 let mut inner_area = Rect::new(area_origin, inner_size)
312 .without_gaps(&node.padding)
313 .without_gaps(&node.margin)
314 .as_inner();
315
316 let mut inner_sizes = Size2D::default();
317
318 if measure_inner_children && phase_measure_inner_children {
319 let mut available_area = inner_area.as_available();
321
322 available_area.move_with_offsets(&node.offset_x, &node.offset_y);
323
324 let mut parent_area = area.as_parent();
325
326 self.measure_children(
328 &node_id,
329 node,
330 &mut parent_area,
331 &mut inner_area,
332 &mut available_area,
333 &mut inner_sizes,
334 must_cache_children,
335 true,
336 );
337
338 if node.width.inner_sized() {
341 parent_area.size.width = node.width.min_max(
342 parent_area.size.width,
343 parent_area.size.width,
344 available_parent_area.size.width,
345 0.,
346 0.,
347 &node.minimum_width,
348 &node.maximum_width,
349 self.layout_metadata.root_area.width(),
350 phase,
351 );
352 }
353 if node.height.inner_sized() {
354 parent_area.size.height = node.height.min_max(
355 parent_area.size.height,
356 parent_area.size.height,
357 available_parent_area.size.height,
358 0.,
359 0.,
360 &node.minimum_height,
361 &node.maximum_height,
362 self.layout_metadata.root_area.height(),
363 phase,
364 );
365 }
366
367 area = parent_area.cast_unit();
368 }
369
370 let layout_node = LayoutNode {
371 area,
372 margin: node.margin,
373 offset_x: node.offset_x,
374 offset_y: node.offset_y,
375 inner_area,
376 data: node_data,
377 inner_sizes,
378 };
379
380 if must_cache_children
382 && phase == Phase::Final
383 && node.has_layout_references
384 && let Some(measurer) = self.measurer
385 {
386 inner_sizes.width += node.padding.horizontal();
387 inner_sizes.height += node.padding.vertical();
388 measurer.notify_layout_references(
389 node_id,
390 layout_node.area,
391 layout_node.visible_area(),
392 inner_sizes,
393 );
394 }
395
396 (must_cache_children, layout_node)
397 } else {
398 let layout_node = self
399 .layout
400 .get(&node_id)
401 .expect("Cached node does not exist")
402 .clone();
403
404 let mut inner_sizes = Size2D::default();
405 let mut available_area = layout_node.inner_area.as_available();
406 let mut area = layout_node.area.as_parent();
407 let mut inner_area = layout_node.inner_area.as_inner();
408
409 available_area.move_with_offsets(&node.offset_x, &node.offset_y);
410
411 let measure_inner_children = if let Some(measurer) = self.measurer {
412 measurer.should_measure_inner_children(node_id)
413 } else {
414 true
415 };
416
417 if measure_inner_children {
418 self.measure_children(
419 &node_id,
420 node,
421 &mut area,
422 &mut inner_area,
423 &mut available_area,
424 &mut inner_sizes,
425 must_cache_children,
426 false,
427 );
428 }
429
430 (false, layout_node)
431 }
432 }
433
434 #[allow(clippy::too_many_arguments)]
436 pub fn measure_children(
437 &mut self,
438 parent_node_id: &Key,
439 parent_node: &Node,
440 parent_area: &mut AreaOf<Parent>,
441 inner_area: &mut AreaOf<Inner>,
442 available_area: &mut AreaOf<Available>,
443 inner_sizes: &mut Size2D,
445 must_cache_children: bool,
447 parent_is_dirty: bool,
449 ) {
450 let children = self.tree_adapter.children_of(parent_node_id);
451
452 let initial_area = *inner_area;
453
454 let mut initial_phase_flex_grows = FxHashMap::default();
455 let mut initial_phase_sizes = FxHashMap::default();
456 let mut initial_phase_inner_sizes = Size2D::default();
457
458 let (non_absolute_children_len, first_child, last_child) = if parent_node.spacing.get() > 0.
460 {
461 let mut last_child = None;
462 let mut first_child = None;
463 let len = children
464 .iter()
465 .filter(|child_id| {
466 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
467 return false;
468 };
469 let is_stacked = child_data.position.is_stacked();
470 if is_stacked {
471 last_child = Some(**child_id);
472
473 if first_child.is_none() {
474 first_child = Some(**child_id);
475 }
476 }
477 is_stacked
478 })
479 .count();
480 (len, first_child, last_child)
481 } else {
482 (
483 children.len(),
484 children.first().copied(),
485 children.last().copied(),
486 )
487 };
488
489 let needs_initial_phase = parent_node.cross_alignment.is_not_start()
490 || parent_node.main_alignment.is_not_start()
491 || parent_node.content.is_fit()
492 || parent_node.content.is_flex()
493 || parent_node.content.is_wrap();
494
495 let mut initial_phase_parent_area = *parent_area;
496 let mut initial_phase_inner_area = *inner_area;
497 let mut initial_phase_available_area = *available_area;
498
499 if needs_initial_phase {
502 for child_id in &children {
504 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
505 continue;
506 };
507
508 if !child_data.position.is_stacked() {
511 continue;
512 }
513
514 let is_last_child = last_child == Some(*child_id);
515
516 let inner_area = initial_phase_inner_area;
517
518 let (_, mut child_areas) = self.measure_node(
519 *child_id,
520 &child_data,
521 inner_area.as_parent(),
522 initial_area.as_parent(),
523 initial_phase_available_area,
524 false,
525 parent_is_dirty,
526 Phase::Initial,
527 );
528
529 child_areas.area.adjust_size(&child_data);
530
531 Self::stack_child(
533 &mut initial_phase_available_area,
534 parent_node,
535 &child_data,
536 &mut initial_phase_parent_area,
537 &mut initial_phase_inner_area,
538 &mut initial_phase_inner_sizes,
539 &child_areas.area,
540 is_last_child,
541 Phase::Initial,
542 );
543
544 if parent_node.cross_alignment.is_not_start()
545 || parent_node.main_alignment.is_spaced()
546 || parent_node.content.is_wrap()
547 {
548 initial_phase_sizes.insert(*child_id, child_areas.area.size);
549 }
550
551 if parent_node.content.is_flex() {
552 match parent_node.direction {
553 Direction::Vertical => {
554 if let Some(ff) = child_data.height.flex_grow() {
555 initial_phase_flex_grows.insert(*child_id, ff);
556 }
557 }
558 Direction::Horizontal => {
559 if let Some(ff) = child_data.width.flex_grow() {
560 initial_phase_flex_grows.insert(*child_id, ff);
561 }
562 }
563 }
564 }
565 }
566 }
567
568 let flex_grows = initial_phase_flex_grows
569 .values()
570 .copied()
571 .reduce(|acc, v| acc + v)
572 .unwrap_or_default()
573 .max(Length::new(1.0));
574
575 let flex_axis = AlignAxis::new(&parent_node.direction, AlignmentDirection::Main);
576
577 let flex_available_width = available_area.width() - initial_phase_inner_sizes.width;
578 let flex_available_height = available_area.height() - initial_phase_inner_sizes.height;
579
580 if parent_node.content.is_flex() {
581 initial_phase_inner_sizes =
582 initial_phase_flex_grows
583 .values()
584 .fold(initial_phase_inner_sizes, |mut acc, f| {
585 let flex_grow_per = f.get() / flex_grows.get() * 100.;
586
587 match flex_axis {
588 AlignAxis::Height => {
589 let size = flex_available_height / 100. * flex_grow_per;
590 acc.height += size;
591 }
592 AlignAxis::Width => {
593 let size = flex_available_width / 100. * flex_grow_per;
594 acc.width += size;
595 }
596 }
597
598 acc
599 });
600 }
601
602 if needs_initial_phase {
603 if parent_node.content.is_wrap() {
604 Self::wrap_adjust_initial(
605 &children,
606 parent_node,
607 &initial_phase_sizes,
608 &mut initial_phase_inner_sizes,
609 &mut initial_phase_available_area,
610 &mut initial_phase_parent_area,
611 &mut initial_phase_inner_area,
612 );
613 }
614
615 if parent_node.main_alignment.is_not_start() && parent_node.content.allows_alignments()
616 {
617 Self::shrink_area_to_fit_when_unbounded(
619 available_area,
620 &initial_phase_parent_area,
621 &mut initial_phase_inner_area,
622 parent_node,
623 AlignmentDirection::Main,
624 );
625
626 Self::align_content(
628 available_area,
629 &initial_phase_inner_area,
630 initial_phase_inner_sizes,
631 &parent_node.main_alignment,
632 parent_node.direction,
633 AlignmentDirection::Main,
634 );
635 }
636
637 if (parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit())
638 && parent_node.content.allows_alignments()
639 {
640 Self::shrink_area_to_fit_when_unbounded(
642 available_area,
643 &initial_phase_parent_area,
644 &mut initial_phase_inner_area,
645 parent_node,
646 AlignmentDirection::Cross,
647 );
648 }
649 }
650
651 let initial_available_area = *available_area;
652
653 for child_id in children {
655 let Some(child_data) = self.tree_adapter.get_node(&child_id) else {
656 continue;
657 };
658
659 let is_first_child = first_child == Some(child_id);
660 let is_last_child = last_child == Some(child_id);
661
662 let mut adapted_available_area = *available_area;
663
664 if parent_node.content.is_flex() {
665 let flex_grow = initial_phase_flex_grows.get(&child_id);
666
667 if let Some(flex_grow) = flex_grow {
668 let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
669
670 match flex_axis {
671 AlignAxis::Height => {
672 let size = flex_available_height / 100. * flex_grow_per;
673 adapted_available_area.size.height = size;
674 }
675 AlignAxis::Width => {
676 let size = flex_available_width / 100. * flex_grow_per;
677 adapted_available_area.size.width = size;
678 }
679 }
680 }
681 }
682
683 if parent_node.main_alignment.is_spaced()
685 && child_data.position.is_stacked()
686 && parent_node.content.allows_alignments()
687 {
688 Self::align_position(
690 AlignmentDirection::Main,
691 &mut adapted_available_area,
692 &initial_available_area,
693 initial_phase_inner_sizes,
694 &parent_node.main_alignment,
695 parent_node.direction,
696 non_absolute_children_len,
697 is_first_child,
698 );
699 }
700
701 if parent_node.cross_alignment.is_not_start() && parent_node.content.allows_alignments()
702 {
703 let initial_phase_size = initial_phase_sizes.get(&child_id);
704
705 if let Some(initial_phase_size) = initial_phase_size {
706 Self::align_content(
708 &mut adapted_available_area,
709 &available_area.as_inner(),
710 *initial_phase_size,
711 &parent_node.cross_alignment,
712 parent_node.direction,
713 AlignmentDirection::Cross,
714 );
715 }
716 }
717
718 if parent_node.content.is_wrap() {
719 let initial_phase_size = initial_phase_sizes.get(&child_id);
720 Self::wrap_handle_final(
721 parent_node,
722 initial_phase_size,
723 &initial_available_area,
724 available_area,
725 &mut adapted_available_area,
726 *inner_sizes,
727 );
728 }
729
730 let (child_revalidated, mut child_areas) = self.measure_node(
732 child_id,
733 &child_data,
734 inner_area.as_parent(),
735 initial_area.as_parent(),
736 adapted_available_area,
737 must_cache_children,
738 parent_is_dirty,
739 Phase::Final,
740 );
741
742 child_areas.area.adjust_size(&child_data);
744
745 if child_data.position.is_stacked() {
747 Self::stack_child(
748 available_area,
749 parent_node,
750 &child_data,
751 parent_area,
752 inner_area,
753 inner_sizes,
754 &child_areas.area,
755 is_last_child,
756 Phase::Final,
757 );
758 }
759
760 if child_revalidated && must_cache_children {
762 self.layout.cache_node(child_id, child_areas);
764 }
765 }
766 }
767
768 fn wrap_adjust_initial(
771 children: &[Key],
772 parent_node: &Node,
773 initial_phase_sizes: &FxHashMap<Key, Size2D>,
774 initial_phase_inner_sizes: &mut Size2D,
775 available_area: &mut AreaOf<Available>,
776 parent_area: &mut AreaOf<Parent>,
777 _initial_phase_inner_area: &mut AreaOf<Inner>,
778 ) {
779 let mut used_area = Area::zero();
780 let break_size = *initial_phase_inner_sizes;
781 for child_id in children {
782 let initial_phase_size = initial_phase_sizes.get(child_id);
783 if let Some(initial_phase_size) = initial_phase_size {
784 match parent_node.direction {
785 Direction::Vertical => {
786 if available_area.height() - used_area.height() - initial_phase_size.height
787 < 0.
788 {
789 used_area.size.height = initial_phase_size.height;
791 available_area.size.width += break_size.width;
792 initial_phase_inner_sizes.width += break_size.width;
794 if parent_node.width.inner_sized() {
795 parent_area.size.width += break_size.width;
796 }
797 } else {
798 used_area.size.height += initial_phase_size.height;
800 }
801 }
802 Direction::Horizontal => {
803 if available_area.width() - used_area.width() - initial_phase_size.width
804 < 0.
805 {
806 used_area.size.width = initial_phase_size.width;
808 available_area.size.height += break_size.height;
809 initial_phase_inner_sizes.height += break_size.height;
811 if parent_node.height.inner_sized() {
812 parent_area.size.height += break_size.height;
813 }
814 } else {
815 used_area.size.width += initial_phase_size.width;
817 }
818 }
819 }
820 }
821 }
822 }
823
824 fn wrap_handle_final(
826 parent_node: &Node,
827 initial_phase_size: Option<&Size2D>,
828 initial_available_area: &AreaOf<Available>,
829 available_area: &mut AreaOf<Available>,
830 adapted_available_area: &mut AreaOf<Available>,
831 inner_sizes: Size2D,
832 ) {
833 if let Some(initial_phase_size) = initial_phase_size {
834 match parent_node.direction {
835 Direction::Vertical => {
836 if adapted_available_area.height() - initial_phase_size.height < 0. {
837 available_area.origin.y = initial_available_area.origin.y;
838 available_area.size.height = initial_available_area.size.height;
839 available_area.origin.x += inner_sizes.width;
840 adapted_available_area.origin.y = initial_available_area.origin.y;
841 adapted_available_area.size.height = initial_available_area.size.height;
842 adapted_available_area.origin.x += inner_sizes.width;
843 }
844 }
845 Direction::Horizontal => {
846 if adapted_available_area.width() - initial_phase_size.width < 0. {
847 available_area.origin.x = initial_available_area.origin.x;
848 available_area.size.width = initial_available_area.size.width;
849 available_area.origin.y += inner_sizes.height;
850 adapted_available_area.origin.x = initial_available_area.origin.x;
851 adapted_available_area.size.width = initial_available_area.size.width;
852 adapted_available_area.origin.y += inner_sizes.height;
853 }
854 }
855 }
856 }
857 }
858
859 fn align_content(
861 available_area: &mut AreaOf<Available>,
862 inner_area: &AreaOf<Inner>,
863 contents_size: Size2D,
864 alignment: &Alignment,
865 direction: Direction,
866 alignment_direction: AlignmentDirection,
867 ) {
868 let axis = AlignAxis::new(&direction, alignment_direction);
869
870 match axis {
871 AlignAxis::Height => match alignment {
872 Alignment::Center => {
873 let new_origin_y = (inner_area.height() / 2.0) - (contents_size.height / 2.0);
874 available_area.origin.y = inner_area.min_y() + new_origin_y;
875 }
876 Alignment::End => {
877 available_area.origin.y = inner_area.max_y() - contents_size.height;
878 }
879 _ => {}
880 },
881 AlignAxis::Width => match alignment {
882 Alignment::Center => {
883 let new_origin_x = (inner_area.width() / 2.0) - (contents_size.width / 2.0);
884 available_area.origin.x = inner_area.min_x() + new_origin_x;
885 }
886 Alignment::End => {
887 available_area.origin.x = inner_area.max_x() - contents_size.width;
888 }
889 _ => {}
890 },
891 }
892 }
893
894 #[allow(clippy::too_many_arguments)]
896 fn align_position(
897 alignment_direction: AlignmentDirection,
898 available_area: &mut AreaOf<Available>,
899 initial_available_area: &AreaOf<Available>,
900 inner_sizes: Size2D,
901 alignment: &Alignment,
902 direction: Direction,
903 siblings_len: usize,
904 is_first_sibling: bool,
905 ) {
906 let axis = AlignAxis::new(&direction, alignment_direction);
907
908 match axis {
909 AlignAxis::Height => match alignment {
910 Alignment::SpaceBetween if !is_first_sibling => {
911 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
912 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
913 available_area.origin.y += gap_size;
914 }
915 Alignment::SpaceEvenly => {
916 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
917 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
918 available_area.origin.y += gap_size;
919 }
920 Alignment::SpaceAround => {
921 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
922 let one_gap_size = all_gaps_sizes / siblings_len as f32;
923 let gap_size = if is_first_sibling {
924 one_gap_size / 2.
925 } else {
926 one_gap_size
927 };
928 available_area.origin.y += gap_size;
929 }
930 _ => {}
931 },
932 AlignAxis::Width => match alignment {
933 Alignment::SpaceBetween if !is_first_sibling => {
934 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
935 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
936 available_area.origin.x += gap_size;
937 }
938 Alignment::SpaceEvenly => {
939 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
940 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
941 available_area.origin.x += gap_size;
942 }
943 Alignment::SpaceAround => {
944 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
945 let one_gap_size = all_gaps_sizes / siblings_len as f32;
946 let gap_size = if is_first_sibling {
947 one_gap_size / 2.
948 } else {
949 one_gap_size
950 };
951 available_area.origin.x += gap_size;
952 }
953 _ => {}
954 },
955 }
956 }
957
958 #[allow(clippy::too_many_arguments)]
960 fn stack_child(
961 available_area: &mut AreaOf<Available>,
962 parent_node: &Node,
963 child_node: &Node,
964 parent_area: &mut AreaOf<Parent>,
965 inner_area: &mut AreaOf<Inner>,
966 inner_sizes: &mut Size2D,
967 child_area: &Area,
968 is_last_sibilin: bool,
969 phase: Phase,
970 ) {
971 let spacing = if is_last_sibilin {
973 Length::default()
974 } else {
975 parent_node.spacing
976 };
977
978 match parent_node.direction {
979 Direction::Horizontal => {
980 available_area.origin.x = child_area.max_x() + spacing.get();
982 available_area.size.width -= child_area.size.width + spacing.get();
983
984 inner_sizes.height = child_area.height().max(inner_sizes.height);
985 inner_sizes.width += spacing.get();
986 if !child_node.width.is_flex() || phase == Phase::Final {
987 inner_sizes.width += child_area.width();
988 }
989
990 if parent_node.height.inner_sized() {
992 parent_area.size.height = parent_area.size.height.max(
993 child_area.size.height
994 + parent_node.padding.vertical()
995 + parent_node.margin.vertical(),
996 );
997 inner_area.size.height = parent_area.size.height
999 - parent_node.padding.vertical()
1000 - parent_node.margin.vertical();
1001 }
1002
1003 if parent_node.width.inner_sized() {
1005 parent_area.size.width += child_area.size.width + spacing.get();
1006 }
1007 }
1008 Direction::Vertical => {
1009 available_area.origin.y = child_area.max_y() + spacing.get();
1011 available_area.size.height -= child_area.size.height + spacing.get();
1012
1013 inner_sizes.width = child_area.width().max(inner_sizes.width);
1014 inner_sizes.height += spacing.get();
1015 if !child_node.height.is_flex() || phase == Phase::Final {
1016 inner_sizes.height += child_area.height();
1017 }
1018
1019 if parent_node.width.inner_sized() {
1021 parent_area.size.width = parent_area.size.width.max(
1022 child_area.size.width
1023 + parent_node.padding.horizontal()
1024 + parent_node.margin.horizontal(),
1025 );
1026 inner_area.size.width = parent_area.size.width
1028 - parent_node.padding.horizontal()
1029 - parent_node.margin.horizontal();
1030 }
1031
1032 if parent_node.height.inner_sized() {
1034 parent_area.size.height += child_area.size.height + spacing.get();
1035 }
1036 }
1037 }
1038 }
1039
1040 fn shrink_area_to_fit_when_unbounded(
1046 available_area: &mut AreaOf<Available>,
1047 parent_area: &AreaOf<Parent>,
1048 inner_area: &mut AreaOf<Inner>,
1049 parent_node: &Node,
1050 alignment_direction: AlignmentDirection,
1051 ) {
1052 struct NodeData<'a> {
1053 pub inner_origin: &'a mut f32,
1054 pub inner_size: &'a mut f32,
1055 pub area_origin: f32,
1056 pub area_size: f32,
1057 pub one_side_padding: f32,
1058 pub two_sides_padding: f32,
1059 pub one_side_margin: f32,
1060 pub two_sides_margin: f32,
1061 pub available_size: &'a mut f32,
1062 }
1063
1064 let axis = AlignAxis::new(&parent_node.direction, alignment_direction);
1065 let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction {
1066 Direction::Vertical => (
1067 parent_node.main_alignment.is_not_start(),
1068 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1069 ),
1070 Direction::Horizontal => (
1071 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1072 parent_node.main_alignment.is_not_start(),
1073 ),
1074 };
1075 let NodeData {
1076 inner_origin,
1077 inner_size,
1078 area_origin,
1079 area_size,
1080 one_side_padding,
1081 two_sides_padding,
1082 one_side_margin,
1083 two_sides_margin,
1084 available_size,
1085 } = match axis {
1086 AlignAxis::Height if parent_node.height.inner_sized() && is_vertical_not_start => {
1087 NodeData {
1088 inner_origin: &mut inner_area.origin.y,
1089 inner_size: &mut inner_area.size.height,
1090 area_origin: parent_area.origin.y,
1091 area_size: parent_area.size.height,
1092 one_side_padding: parent_node.padding.top(),
1093 two_sides_padding: parent_node.padding.vertical(),
1094 one_side_margin: parent_node.margin.top(),
1095 two_sides_margin: parent_node.margin.vertical(),
1096 available_size: &mut available_area.size.height,
1097 }
1098 }
1099 AlignAxis::Width if parent_node.width.inner_sized() && is_horizontal_not_start => {
1100 NodeData {
1101 inner_origin: &mut inner_area.origin.x,
1102 inner_size: &mut inner_area.size.width,
1103 area_origin: parent_area.origin.x,
1104 area_size: parent_area.size.width,
1105 one_side_padding: parent_node.padding.left(),
1106 two_sides_padding: parent_node.padding.horizontal(),
1107 one_side_margin: parent_node.margin.left(),
1108 two_sides_margin: parent_node.margin.horizontal(),
1109 available_size: &mut available_area.size.width,
1110 }
1111 }
1112 _ => return,
1113 };
1114
1115 *inner_origin = area_origin + one_side_padding + one_side_margin;
1117 *inner_size = area_size - two_sides_padding - two_sides_margin;
1119 *available_size = *inner_size;
1121 }
1122}