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