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