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");
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 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 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 {
372 let new_origin = node.position.get_origin(
373 &available_parent_area,
374 &initial_parent_area,
375 area.size,
376 &self.layout_metadata.root_area,
377 );
378 let diff_x = new_origin.x - area.origin.x;
379 let diff_y = new_origin.y - area.origin.y;
380 area.origin = new_origin;
381 inner_area.origin.x += diff_x;
382 inner_area.origin.y += diff_y;
383
384 if diff_x != 0.0 || diff_y != 0.0 {
385 self.recursive_translate(node_id, Length::new(diff_x), Length::new(diff_y));
386 }
387 }
388 }
389
390 let layout_node = LayoutNode {
391 area,
392 margin: node.margin,
393 offset_x: node.offset_x,
394 offset_y: node.offset_y,
395 inner_area,
396 data: node_data,
397 inner_sizes,
398 };
399
400 if must_cache_children
402 && phase == Phase::Final
403 && node.has_layout_references
404 && let Some(measurer) = self.measurer
405 {
406 inner_sizes.width += node.padding.horizontal();
407 inner_sizes.height += node.padding.vertical();
408 measurer.notify_layout_references(
409 node_id,
410 layout_node.area,
411 layout_node.visible_area(),
412 inner_sizes,
413 );
414 }
415
416 (must_cache_children, layout_node)
417 } else {
418 let layout_node = self
419 .layout
420 .get(&node_id)
421 .expect("Cached node does not exist")
422 .clone();
423
424 let mut inner_sizes = Size2D::default();
425 let mut area = layout_node.area.as_parent();
426 let mut inner_area = layout_node.inner_area.as_inner();
427 let mut available_area = inner_area.as_available();
428
429 let measure_inner_children = if let Some(measurer) = self.measurer {
430 measurer.should_measure_inner_children(node_id)
431 } else {
432 true
433 };
434
435 if measure_inner_children {
436 self.measure_children(
437 &node_id,
438 node,
439 &mut area,
440 &mut inner_area,
441 &mut available_area,
442 &mut inner_sizes,
443 must_cache_children,
444 false,
445 );
446 }
447
448 (false, layout_node)
449 }
450 }
451
452 #[allow(clippy::too_many_arguments)]
454 pub fn measure_children(
455 &mut self,
456 parent_node_id: &Key,
457 parent_node: &Node,
458 parent_area: &mut AreaOf<Parent>,
459 inner_area: &mut AreaOf<Inner>,
460 available_area: &mut AreaOf<Available>,
461 inner_sizes: &mut Size2D,
463 must_cache_children: bool,
465 parent_is_dirty: bool,
467 ) {
468 let children = self.tree_adapter.children_of(parent_node_id);
469
470 let initial_area = *inner_area;
471
472 let mut initial_phase_flex_grows = FxHashMap::default();
473 let mut initial_phase_sizes = FxHashMap::default();
474 let mut initial_phase_inner_sizes = Size2D::default();
475
476 let (non_absolute_children_len, first_child, last_child) = if parent_node.spacing.get() > 0.
478 {
479 let mut last_child = None;
480 let mut first_child = None;
481 let len = children
482 .iter()
483 .filter(|child_id| {
484 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
485 return false;
486 };
487 let is_stacked = child_data.position.is_stacked();
488 if is_stacked {
489 last_child = Some(**child_id);
490
491 if first_child.is_none() {
492 first_child = Some(**child_id);
493 }
494 }
495 is_stacked
496 })
497 .count();
498 (len, first_child, last_child)
499 } else {
500 (
501 children.len(),
502 children.first().copied(),
503 children.last().copied(),
504 )
505 };
506
507 let needs_initial_phase = parent_node.cross_alignment.is_not_start()
508 || parent_node.main_alignment.is_not_start()
509 || parent_node.content.is_fit()
510 || parent_node.content.is_flex()
511 || parent_node.content.is_wrap();
512
513 let mut initial_phase_parent_area = *parent_area;
514 let mut initial_phase_inner_area = *inner_area;
515 let mut initial_phase_available_area = *available_area;
516
517 if needs_initial_phase {
520 for child_id in &children {
522 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
523 continue;
524 };
525
526 if !child_data.position.is_stacked() {
529 continue;
530 }
531
532 let is_last_child = last_child == Some(*child_id);
533
534 let (_, mut child_areas) = self.measure_node(
535 *child_id,
536 &child_data,
537 initial_area.as_parent(),
538 initial_phase_available_area,
539 false,
540 parent_is_dirty,
541 Phase::Initial,
542 );
543
544 child_areas.area.adjust_size(&child_data);
545
546 Self::stack_child(
548 &mut initial_phase_available_area,
549 parent_node,
550 &child_data,
551 &mut initial_phase_parent_area,
552 &mut initial_phase_inner_area,
553 &mut initial_phase_inner_sizes,
554 &child_areas.area,
555 is_last_child,
556 Phase::Initial,
557 );
558
559 if parent_node.cross_alignment.is_not_start()
560 || parent_node.main_alignment.is_spaced()
561 || parent_node.content.is_wrap()
562 {
563 initial_phase_sizes.insert(*child_id, child_areas.area.size);
564 }
565
566 if parent_node.content.is_flex() {
567 match parent_node.direction {
568 Direction::Vertical => {
569 if let Some(ff) = child_data.height.flex_grow() {
570 initial_phase_flex_grows.insert(*child_id, ff);
571 }
572 }
573 Direction::Horizontal => {
574 if let Some(ff) = child_data.width.flex_grow() {
575 initial_phase_flex_grows.insert(*child_id, ff);
576 }
577 }
578 }
579 }
580 }
581 }
582
583 let flex_grows = initial_phase_flex_grows
584 .values()
585 .copied()
586 .reduce(|acc, v| acc + v)
587 .unwrap_or_default()
588 .max(Length::new(1.0));
589
590 let flex_axis = AlignAxis::new(&parent_node.direction, AlignmentDirection::Main);
591
592 let flex_available_width = available_area.width() - initial_phase_inner_sizes.width;
593 let flex_available_height = available_area.height() - initial_phase_inner_sizes.height;
594
595 if parent_node.content.is_flex() {
596 initial_phase_inner_sizes =
597 initial_phase_flex_grows
598 .values()
599 .fold(initial_phase_inner_sizes, |mut acc, f| {
600 let flex_grow_per = f.get() / flex_grows.get() * 100.;
601
602 match flex_axis {
603 AlignAxis::Height => {
604 let size = flex_available_height / 100. * flex_grow_per;
605 acc.height += size;
606 }
607 AlignAxis::Width => {
608 let size = flex_available_width / 100. * flex_grow_per;
609 acc.width += size;
610 }
611 }
612
613 acc
614 });
615 }
616
617 if needs_initial_phase {
618 if parent_node.main_alignment.is_not_start() && parent_node.content.allows_alignments()
619 {
620 Self::shrink_area_to_fit_when_unbounded(
622 available_area,
623 &initial_phase_parent_area,
624 &mut initial_phase_inner_area,
625 parent_node,
626 AlignmentDirection::Main,
627 );
628
629 Self::align_content(
631 available_area,
632 &initial_phase_inner_area,
633 initial_phase_inner_sizes,
634 &parent_node.main_alignment,
635 parent_node.direction,
636 AlignmentDirection::Main,
637 );
638 }
639
640 if (parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit())
641 && parent_node.content.allows_alignments()
642 {
643 Self::shrink_area_to_fit_when_unbounded(
645 available_area,
646 &initial_phase_parent_area,
647 &mut initial_phase_inner_area,
648 parent_node,
649 AlignmentDirection::Cross,
650 );
651 }
652 }
653
654 let initial_available_area = *available_area;
655
656 for child_id in children {
658 let Some(child_data) = self.tree_adapter.get_node(&child_id) else {
659 continue;
660 };
661
662 let is_first_child = first_child == Some(child_id);
663 let is_last_child = last_child == Some(child_id);
664
665 let mut adapted_available_area = *available_area;
666
667 if parent_node.content.is_flex() {
668 let flex_grow = initial_phase_flex_grows.get(&child_id);
669
670 if let Some(flex_grow) = flex_grow {
671 let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
672
673 match flex_axis {
674 AlignAxis::Height => {
675 let size = flex_available_height / 100. * flex_grow_per;
676 adapted_available_area.size.height = size;
677 }
678 AlignAxis::Width => {
679 let size = flex_available_width / 100. * flex_grow_per;
680 adapted_available_area.size.width = size;
681 }
682 }
683 }
684 }
685
686 if parent_node.main_alignment.is_spaced()
688 && child_data.position.is_stacked()
689 && parent_node.content.allows_alignments()
690 {
691 Self::align_position(
693 AlignmentDirection::Main,
694 &mut adapted_available_area,
695 &initial_available_area,
696 initial_phase_inner_sizes,
697 &parent_node.main_alignment,
698 parent_node.direction,
699 non_absolute_children_len,
700 is_first_child,
701 );
702 }
703
704 if parent_node.cross_alignment.is_not_start() && parent_node.content.allows_alignments()
705 {
706 let initial_phase_size = initial_phase_sizes.get(&child_id);
707
708 if let Some(initial_phase_size) = initial_phase_size {
709 Self::align_content(
711 &mut adapted_available_area,
712 &available_area.as_inner(),
713 *initial_phase_size,
714 &parent_node.cross_alignment,
715 parent_node.direction,
716 AlignmentDirection::Cross,
717 );
718 }
719 }
720
721 if let Content::Wrap { wrap_spacing } = parent_node.content {
722 let initial_phase_size = initial_phase_sizes.get(&child_id);
723 Self::wrap_child(
724 wrap_spacing.unwrap_or_default(),
725 parent_node.direction,
726 initial_phase_size,
727 &initial_available_area,
728 parent_area,
729 available_area,
730 &mut adapted_available_area,
731 *inner_sizes,
732 );
733 }
734
735 let (child_revalidated, mut child_areas) = self.measure_node(
737 child_id,
738 &child_data,
739 initial_area.as_parent(),
740 adapted_available_area,
741 must_cache_children,
742 parent_is_dirty,
743 Phase::Final,
744 );
745
746 child_areas.area.adjust_size(&child_data);
748
749 if child_data.position.is_stacked() {
751 Self::stack_child(
752 available_area,
753 parent_node,
754 &child_data,
755 parent_area,
756 inner_area,
757 inner_sizes,
758 &child_areas.area,
759 is_last_child,
760 Phase::Final,
761 );
762 }
763
764 if child_revalidated && must_cache_children {
766 self.layout.cache_node(child_id, child_areas);
768 }
769 }
770 }
771
772 #[allow(clippy::too_many_arguments)]
773 fn wrap_child(
774 wrap_spacing: f32,
775 direction: Direction,
776 initial_phase_size: Option<&Size2D>,
777 initial_available_area: &AreaOf<Available>,
778 parent_area: &mut AreaOf<Parent>,
779 available_area: &mut AreaOf<Available>,
780 adapted_available_area: &mut AreaOf<Available>,
781 inner_sizes: Size2D,
782 ) {
783 if let Some(initial_phase_size) = initial_phase_size {
784 match direction {
785 Direction::Vertical => {
786 if adapted_available_area.height() - initial_phase_size.height < 0. {
787 let advance = inner_sizes.width + wrap_spacing;
788 available_area.origin.y = initial_available_area.origin.y;
789 available_area.size.height = initial_available_area.size.height;
790 available_area.origin.x += advance;
791 adapted_available_area.origin.y = initial_available_area.origin.y;
792 adapted_available_area.size.height = initial_available_area.size.height;
793 adapted_available_area.origin.x += advance;
794 parent_area.size.width += advance;
795 }
796 }
797 Direction::Horizontal => {
798 if adapted_available_area.width() - initial_phase_size.width < 0. {
799 let advance = inner_sizes.height + wrap_spacing;
800 available_area.origin.x = initial_available_area.origin.x;
801 available_area.size.width = initial_available_area.size.width;
802 available_area.origin.y += advance;
803 adapted_available_area.origin.x = initial_available_area.origin.x;
804 adapted_available_area.size.width = initial_available_area.size.width;
805 adapted_available_area.origin.y += advance;
806 parent_area.size.height += advance;
807 }
808 }
809 }
810 }
811 }
812
813 fn align_content(
815 available_area: &mut AreaOf<Available>,
816 inner_area: &AreaOf<Inner>,
817 contents_size: Size2D,
818 alignment: &Alignment,
819 direction: Direction,
820 alignment_direction: AlignmentDirection,
821 ) {
822 let axis = AlignAxis::new(&direction, alignment_direction);
823
824 match axis {
825 AlignAxis::Height => match alignment {
826 Alignment::Center => {
827 let new_origin_y = (inner_area.height() / 2.0) - (contents_size.height / 2.0);
828 available_area.origin.y = inner_area.min_y() + new_origin_y;
829 }
830 Alignment::End => {
831 available_area.origin.y = inner_area.max_y() - contents_size.height;
832 }
833 _ => {}
834 },
835 AlignAxis::Width => match alignment {
836 Alignment::Center => {
837 let new_origin_x = (inner_area.width() / 2.0) - (contents_size.width / 2.0);
838 available_area.origin.x = inner_area.min_x() + new_origin_x;
839 }
840 Alignment::End => {
841 available_area.origin.x = inner_area.max_x() - contents_size.width;
842 }
843 _ => {}
844 },
845 }
846 }
847
848 #[allow(clippy::too_many_arguments)]
850 fn align_position(
851 alignment_direction: AlignmentDirection,
852 available_area: &mut AreaOf<Available>,
853 initial_available_area: &AreaOf<Available>,
854 inner_sizes: Size2D,
855 alignment: &Alignment,
856 direction: Direction,
857 siblings_len: usize,
858 is_first_sibling: bool,
859 ) {
860 let axis = AlignAxis::new(&direction, alignment_direction);
861
862 match axis {
863 AlignAxis::Height => match alignment {
864 Alignment::SpaceBetween if !is_first_sibling => {
865 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
866 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
867 available_area.origin.y += gap_size;
868 }
869 Alignment::SpaceEvenly => {
870 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
871 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
872 available_area.origin.y += gap_size;
873 }
874 Alignment::SpaceAround => {
875 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
876 let one_gap_size = all_gaps_sizes / siblings_len as f32;
877 let gap_size = if is_first_sibling {
878 one_gap_size / 2.
879 } else {
880 one_gap_size
881 };
882 available_area.origin.y += gap_size;
883 }
884 _ => {}
885 },
886 AlignAxis::Width => match alignment {
887 Alignment::SpaceBetween if !is_first_sibling => {
888 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
889 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
890 available_area.origin.x += gap_size;
891 }
892 Alignment::SpaceEvenly => {
893 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
894 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
895 available_area.origin.x += gap_size;
896 }
897 Alignment::SpaceAround => {
898 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
899 let one_gap_size = all_gaps_sizes / siblings_len as f32;
900 let gap_size = if is_first_sibling {
901 one_gap_size / 2.
902 } else {
903 one_gap_size
904 };
905 available_area.origin.x += gap_size;
906 }
907 _ => {}
908 },
909 }
910 }
911
912 #[allow(clippy::too_many_arguments)]
914 fn stack_child(
915 available_area: &mut AreaOf<Available>,
916 parent_node: &Node,
917 child_node: &Node,
918 parent_area: &mut AreaOf<Parent>,
919 inner_area: &mut AreaOf<Inner>,
920 inner_sizes: &mut Size2D,
921 child_area: &Area,
922 is_last_sibilin: bool,
923 phase: Phase,
924 ) {
925 let spacing = if is_last_sibilin {
927 Length::default()
928 } else {
929 parent_node.spacing
930 };
931
932 match parent_node.direction {
933 Direction::Horizontal => {
934 available_area.origin.x = child_area.max_x() + spacing.get();
936 available_area.size.width -= child_area.size.width + spacing.get();
937
938 inner_sizes.height = child_area.height().max(inner_sizes.height);
939 inner_sizes.width += spacing.get();
940 if !child_node.width.is_flex() || phase == Phase::Final {
941 inner_sizes.width += child_area.width();
942 }
943
944 if parent_node.height.inner_sized() {
946 parent_area.size.height = parent_area.size.height.max(
947 child_area.size.height
948 + parent_node.padding.vertical()
949 + parent_node.margin.vertical(),
950 );
951 inner_area.size.height = parent_area.size.height
953 - parent_node.padding.vertical()
954 - parent_node.margin.vertical();
955 }
956
957 if parent_node.width.inner_sized() {
959 parent_area.size.width += child_area.size.width + spacing.get();
960 }
961 }
962 Direction::Vertical => {
963 available_area.origin.y = child_area.max_y() + spacing.get();
965 available_area.size.height -= child_area.size.height + spacing.get();
966
967 inner_sizes.width = child_area.width().max(inner_sizes.width);
968 inner_sizes.height += spacing.get();
969 if !child_node.height.is_flex() || phase == Phase::Final {
970 inner_sizes.height += child_area.height();
971 }
972
973 if parent_node.width.inner_sized() {
975 parent_area.size.width = parent_area.size.width.max(
976 child_area.size.width
977 + parent_node.padding.horizontal()
978 + parent_node.margin.horizontal(),
979 );
980 inner_area.size.width = parent_area.size.width
982 - parent_node.padding.horizontal()
983 - parent_node.margin.horizontal();
984 }
985
986 if parent_node.height.inner_sized() {
988 parent_area.size.height += child_area.size.height + spacing.get();
989 }
990 }
991 }
992 }
993
994 fn shrink_area_to_fit_when_unbounded(
1000 available_area: &mut AreaOf<Available>,
1001 parent_area: &AreaOf<Parent>,
1002 inner_area: &mut AreaOf<Inner>,
1003 parent_node: &Node,
1004 alignment_direction: AlignmentDirection,
1005 ) {
1006 struct NodeData<'a> {
1007 pub inner_origin: &'a mut f32,
1008 pub inner_size: &'a mut f32,
1009 pub area_origin: f32,
1010 pub area_size: f32,
1011 pub one_side_padding: f32,
1012 pub two_sides_padding: f32,
1013 pub one_side_margin: f32,
1014 pub two_sides_margin: f32,
1015 pub available_size: &'a mut f32,
1016 }
1017
1018 let axis = AlignAxis::new(&parent_node.direction, alignment_direction);
1019 let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction {
1020 Direction::Vertical => (
1021 parent_node.main_alignment.is_not_start(),
1022 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1023 ),
1024 Direction::Horizontal => (
1025 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1026 parent_node.main_alignment.is_not_start(),
1027 ),
1028 };
1029 let NodeData {
1030 inner_origin,
1031 inner_size,
1032 area_origin,
1033 area_size,
1034 one_side_padding,
1035 two_sides_padding,
1036 one_side_margin,
1037 two_sides_margin,
1038 available_size,
1039 } = match axis {
1040 AlignAxis::Height if parent_node.height.inner_sized() && is_vertical_not_start => {
1041 NodeData {
1042 inner_origin: &mut inner_area.origin.y,
1043 inner_size: &mut inner_area.size.height,
1044 area_origin: parent_area.origin.y,
1045 area_size: parent_area.size.height,
1046 one_side_padding: parent_node.padding.top(),
1047 two_sides_padding: parent_node.padding.vertical(),
1048 one_side_margin: parent_node.margin.top(),
1049 two_sides_margin: parent_node.margin.vertical(),
1050 available_size: &mut available_area.size.height,
1051 }
1052 }
1053 AlignAxis::Width if parent_node.width.inner_sized() && is_horizontal_not_start => {
1054 NodeData {
1055 inner_origin: &mut inner_area.origin.x,
1056 inner_size: &mut inner_area.size.width,
1057 area_origin: parent_area.origin.x,
1058 area_size: parent_area.size.width,
1059 one_side_padding: parent_node.padding.left(),
1060 two_sides_padding: parent_node.padding.horizontal(),
1061 one_side_margin: parent_node.margin.left(),
1062 two_sides_margin: parent_node.margin.horizontal(),
1063 available_size: &mut available_area.size.width,
1064 }
1065 }
1066 _ => return,
1067 };
1068
1069 *inner_origin = area_origin + one_side_padding + one_side_margin;
1071 *inner_size = area_size - two_sides_padding - two_sides_margin;
1073 *available_size = *inner_size;
1075 }
1076}