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
66 .tree_adapter
67 .children_of(&node_id)
68 .into_iter()
69 .map(|id| (node_id, id))
70 .collect::<Vec<(Key, Key)>>();
71 while let Some((parent, child)) = buffer.pop() {
72 let node = self
73 .tree_adapter
74 .get_node(&child)
75 .expect("Node does not exist");
76 let translate = match node.position {
77 Position::Global(_) => false,
78 Position::Absolute(_) => parent != node_id,
79 Position::Stacked(_) => true,
80 };
81 if translate {
82 let layout_node = self
83 .layout
84 .get_mut(&child)
85 .expect("Cached node does not exist");
86
87 layout_node.area.origin.x += offset_x.get();
88 layout_node.area.origin.y += offset_y.get();
89 layout_node.inner_area.origin.x += offset_x.get();
90 layout_node.inner_area.origin.y += offset_y.get();
91
92 buffer.extend(
93 self.tree_adapter
94 .children_of(&child)
95 .into_iter()
96 .map(|id| (node_id, id)),
97 );
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 parent_area: AreaOf<Parent>,
110 initial_parent_area: AreaOf<Parent>,
112 available_parent_area: AreaOf<Available>,
114 must_cache_children: bool,
116 parent_is_dirty: bool,
118 phase: Phase,
120 ) -> (bool, LayoutNode) {
121 let reason = self.layout.dirty.get(&node_id).copied();
122
123 if let Some(layout_node) = self.layout.get_mut(&node_id)
125 && reason == Some(DirtyReason::InnerLayout)
126 && must_cache_children
127 {
128 let offset_x = node.offset_x - layout_node.offset_x;
130 let offset_y = node.offset_y - layout_node.offset_y;
131
132 layout_node.offset_x = node.offset_x;
133 layout_node.offset_y = node.offset_y;
134
135 let layout_node = layout_node.clone();
136
137 self.recursive_translate(node_id, offset_x, offset_y);
138
139 return (must_cache_children, layout_node);
140 }
141
142 let must_revalidate =
146 parent_is_dirty || reason.is_some() || !self.layout.results.contains_key(&node_id);
147 if must_revalidate {
148 let mut area_size = Size2D::new(node.padding.horizontal(), node.padding.vertical());
150
151 area_size.width = node.width.min_max(
153 area_size.width,
154 initial_parent_area.size.width,
155 available_parent_area.size.width,
156 node.margin.left(),
157 node.margin.horizontal(),
158 &node.minimum_width,
159 &node.maximum_width,
160 self.layout_metadata.root_area.width(),
161 phase,
162 );
163 area_size.height = node.height.min_max(
164 area_size.height,
165 initial_parent_area.size.height,
166 available_parent_area.size.height,
167 node.margin.top(),
168 node.margin.vertical(),
169 &node.minimum_height,
170 &node.maximum_height,
171 self.layout_metadata.root_area.height(),
172 phase,
173 );
174
175 let node_data = if let Some(measurer) = self.measurer {
178 if measurer.should_hook_measurement(node_id) {
179 let available_width =
180 Size::Pixels(Length::new(available_parent_area.size.width)).min_max(
181 area_size.width,
182 initial_parent_area.size.width,
183 available_parent_area.size.width,
184 node.margin.left(),
185 node.margin.horizontal(),
186 &node.minimum_width,
187 &node.maximum_width,
188 self.layout_metadata.root_area.width(),
189 phase,
190 );
191 let available_height =
192 Size::Pixels(Length::new(available_parent_area.size.height)).min_max(
193 area_size.height,
194 initial_parent_area.size.height,
195 available_parent_area.size.height,
196 node.margin.top(),
197 node.margin.vertical(),
198 &node.minimum_height,
199 &node.maximum_height,
200 self.layout_metadata.root_area.height(),
201 phase,
202 );
203 let most_fitting_width = *node
204 .width
205 .most_fitting_size(&area_size.width, &available_width);
206 let most_fitting_height = *node
207 .height
208 .most_fitting_size(&area_size.height, &available_height);
209
210 let most_fitting_area_size =
211 Size2D::new(most_fitting_width, most_fitting_height);
212 let res = measurer.measure(node_id, node, &most_fitting_area_size);
213
214 #[allow(clippy::float_cmp)]
216 if let Some((custom_size, node_data)) = res {
217 if node.width.inner_sized() {
218 area_size.width = node.width.min_max(
219 custom_size.width,
220 initial_parent_area.size.width,
221 available_parent_area.size.width,
222 node.margin.left(),
223 node.margin.horizontal(),
224 &node.minimum_width,
225 &node.maximum_width,
226 self.layout_metadata.root_area.width(),
227 phase,
228 );
229 }
230 if node.height.inner_sized() {
231 area_size.height = node.height.min_max(
232 custom_size.height,
233 initial_parent_area.size.height,
234 available_parent_area.size.height,
235 node.margin.top(),
236 node.margin.vertical(),
237 &node.minimum_height,
238 &node.maximum_height,
239 self.layout_metadata.root_area.height(),
240 phase,
241 );
242 }
243
244 Some(node_data)
246 } else {
247 None
248 }
249 } else {
250 None
251 }
252 } else {
253 None
254 };
255
256 let measure_inner_children = if let Some(measurer) = self.measurer {
257 measurer.should_measure_inner_children(node_id)
258 } else {
259 true
260 };
261
262 let phase_measure_inner_children = if phase == Phase::Initial {
265 node.width.inner_sized() || node.height.inner_sized()
266 } else {
267 true
268 };
269
270 let inner_size = {
272 let mut inner_size = area_size;
273
274 if node.width.inner_sized() {
276 inner_size.width = node.width.min_max(
277 available_parent_area.width(),
278 initial_parent_area.size.width,
279 available_parent_area.width(),
280 node.margin.left(),
281 node.margin.horizontal(),
282 &node.minimum_width,
283 &node.maximum_width,
284 self.layout_metadata.root_area.width(),
285 phase,
286 );
287 }
288 if node.height.inner_sized() {
289 inner_size.height = node.height.min_max(
290 available_parent_area.height(),
291 initial_parent_area.size.height,
292 available_parent_area.height(),
293 node.margin.top(),
294 node.margin.vertical(),
295 &node.minimum_height,
296 &node.maximum_height,
297 self.layout_metadata.root_area.height(),
298 phase,
299 );
300 }
301 inner_size
302 };
303
304 let area_origin = node.position.get_origin(
306 &available_parent_area,
307 &parent_area,
308 area_size,
309 &self.layout_metadata.root_area,
310 );
311 let mut area = Area::new(area_origin, area_size);
312 let mut inner_area = Rect::new(area_origin, inner_size)
313 .without_gaps(&node.padding)
314 .without_gaps(&node.margin)
315 .as_inner();
316
317 let mut inner_sizes = Size2D::default();
318
319 if measure_inner_children && phase_measure_inner_children {
320 let mut available_area = inner_area.as_available();
322
323 available_area.move_with_offsets(&node.offset_x, &node.offset_y);
324
325 let mut parent_area = area.as_parent();
326
327 self.measure_children(
329 &node_id,
330 node,
331 &mut parent_area,
332 &mut inner_area,
333 &mut available_area,
334 &mut inner_sizes,
335 must_cache_children,
336 true,
337 );
338
339 if node.width.inner_sized() {
342 parent_area.size.width = node.width.min_max(
343 parent_area.size.width,
344 parent_area.size.width,
345 available_parent_area.size.width,
346 0.,
347 0.,
348 &node.minimum_width,
349 &node.maximum_width,
350 self.layout_metadata.root_area.width(),
351 phase,
352 );
353 }
354 if node.height.inner_sized() {
355 parent_area.size.height = node.height.min_max(
356 parent_area.size.height,
357 parent_area.size.height,
358 available_parent_area.size.height,
359 0.,
360 0.,
361 &node.minimum_height,
362 &node.maximum_height,
363 self.layout_metadata.root_area.height(),
364 phase,
365 );
366 }
367
368 area = parent_area.cast_unit();
369 }
370
371 let layout_node = LayoutNode {
372 area,
373 margin: node.margin,
374 offset_x: node.offset_x,
375 offset_y: node.offset_y,
376 inner_area,
377 data: node_data,
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
494 let mut initial_phase_parent_area = *parent_area;
495 let mut initial_phase_inner_area = *inner_area;
496 let mut initial_phase_available_area = *available_area;
497
498 if needs_initial_phase {
501 for child_id in &children {
503 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
504 continue;
505 };
506
507 if !child_data.position.is_stacked() {
510 continue;
511 }
512
513 let is_last_child = last_child == Some(*child_id);
514
515 let inner_area = initial_phase_inner_area;
516
517 let (_, mut child_areas) = self.measure_node(
518 *child_id,
519 &child_data,
520 inner_area.as_parent(),
521 initial_area.as_parent(),
522 initial_phase_available_area,
523 false,
524 parent_is_dirty,
525 Phase::Initial,
526 );
527
528 child_areas.area.adjust_size(&child_data);
529
530 Self::stack_child(
532 &mut initial_phase_available_area,
533 parent_node,
534 &child_data,
535 &mut initial_phase_parent_area,
536 &mut initial_phase_inner_area,
537 &mut initial_phase_inner_sizes,
538 &child_areas.area,
539 is_last_child,
540 Phase::Initial,
541 );
542
543 if parent_node.cross_alignment.is_not_start()
544 || parent_node.main_alignment.is_spaced()
545 {
546 initial_phase_sizes.insert(*child_id, child_areas.area.size);
547 }
548
549 if parent_node.content.is_flex() {
550 match parent_node.direction {
551 Direction::Vertical => {
552 if let Some(ff) = child_data.height.flex_grow() {
553 initial_phase_flex_grows.insert(*child_id, ff);
554 }
555 }
556 Direction::Horizontal => {
557 if let Some(ff) = child_data.width.flex_grow() {
558 initial_phase_flex_grows.insert(*child_id, ff);
559 }
560 }
561 }
562 }
563 }
564 }
565
566 let initial_available_area = *available_area;
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 = initial_available_area.width() - initial_phase_inner_sizes.width;
578 let flex_available_height =
579 initial_available_area.height() - initial_phase_inner_sizes.height;
580
581 let initial_phase_inner_sizes_with_flex =
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 if needs_initial_phase {
602 if parent_node.main_alignment.is_not_start() {
603 Self::shrink_area_to_fit_when_unbounded(
605 available_area,
606 &initial_phase_parent_area,
607 &mut initial_phase_inner_area,
608 parent_node,
609 AlignmentDirection::Main,
610 );
611
612 Self::align_content(
614 available_area,
615 &initial_phase_inner_area,
616 initial_phase_inner_sizes_with_flex,
617 &parent_node.main_alignment,
618 parent_node.direction,
619 AlignmentDirection::Main,
620 );
621 }
622
623 if parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit() {
624 Self::shrink_area_to_fit_when_unbounded(
626 available_area,
627 &initial_phase_parent_area,
628 &mut initial_phase_inner_area,
629 parent_node,
630 AlignmentDirection::Cross,
631 );
632 }
633 }
634
635 let initial_available_area = *available_area;
636
637 for child_id in children {
639 let Some(child_data) = self.tree_adapter.get_node(&child_id) else {
640 continue;
641 };
642
643 let is_first_child = first_child == Some(child_id);
644 let is_last_child = last_child == Some(child_id);
645
646 let mut adapted_available_area = *available_area;
647
648 if parent_node.content.is_flex() {
649 let flex_grow = initial_phase_flex_grows.get(&child_id);
650
651 if let Some(flex_grow) = flex_grow {
652 let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
653
654 match flex_axis {
655 AlignAxis::Height => {
656 let size = flex_available_height / 100. * flex_grow_per;
657 adapted_available_area.size.height = size;
658 }
659 AlignAxis::Width => {
660 let size = flex_available_width / 100. * flex_grow_per;
661 adapted_available_area.size.width = size;
662 }
663 }
664 }
665 }
666
667 if parent_node.main_alignment.is_spaced() && child_data.position.is_stacked() {
669 Self::align_position(
671 AlignmentDirection::Main,
672 &mut adapted_available_area,
673 &initial_available_area,
674 initial_phase_inner_sizes_with_flex,
675 &parent_node.main_alignment,
676 parent_node.direction,
677 non_absolute_children_len,
678 is_first_child,
679 );
680 }
681
682 if parent_node.cross_alignment.is_not_start() {
683 let initial_phase_size = initial_phase_sizes.get(&child_id);
684
685 if let Some(initial_phase_size) = initial_phase_size {
686 Self::align_content(
688 &mut adapted_available_area,
689 &available_area.as_inner(),
690 *initial_phase_size,
691 &parent_node.cross_alignment,
692 parent_node.direction,
693 AlignmentDirection::Cross,
694 );
695 }
696 }
697
698 let (child_revalidated, mut child_areas) = self.measure_node(
700 child_id,
701 &child_data,
702 inner_area.as_parent(),
703 initial_area.as_parent(),
704 adapted_available_area,
705 must_cache_children,
706 parent_is_dirty,
707 Phase::Final,
708 );
709
710 child_areas.area.adjust_size(&child_data);
712
713 if child_data.position.is_stacked() {
715 Self::stack_child(
716 available_area,
717 parent_node,
718 &child_data,
719 parent_area,
720 inner_area,
721 inner_sizes,
722 &child_areas.area,
723 is_last_child,
724 Phase::Final,
725 );
726 }
727
728 if child_revalidated && must_cache_children {
730 self.layout.cache_node(child_id, child_areas);
732 }
733 }
734 }
735
736 fn align_content(
738 available_area: &mut AreaOf<Available>,
739 inner_area: &AreaOf<Inner>,
740 contents_size: Size2D,
741 alignment: &Alignment,
742 direction: Direction,
743 alignment_direction: AlignmentDirection,
744 ) {
745 let axis = AlignAxis::new(&direction, alignment_direction);
746
747 match axis {
748 AlignAxis::Height => match alignment {
749 Alignment::Center => {
750 let new_origin_y = (inner_area.height() / 2.0) - (contents_size.height / 2.0);
751 available_area.origin.y = inner_area.min_y() + new_origin_y;
752 }
753 Alignment::End => {
754 available_area.origin.y = inner_area.max_y() - contents_size.height;
755 }
756 _ => {}
757 },
758 AlignAxis::Width => match alignment {
759 Alignment::Center => {
760 let new_origin_x = (inner_area.width() / 2.0) - (contents_size.width / 2.0);
761 available_area.origin.x = inner_area.min_x() + new_origin_x;
762 }
763 Alignment::End => {
764 available_area.origin.x = inner_area.max_x() - contents_size.width;
765 }
766 _ => {}
767 },
768 }
769 }
770
771 #[allow(clippy::too_many_arguments)]
773 fn align_position(
774 alignment_direction: AlignmentDirection,
775 available_area: &mut AreaOf<Available>,
776 initial_available_area: &AreaOf<Available>,
777 inner_sizes: Size2D,
778 alignment: &Alignment,
779 direction: Direction,
780 siblings_len: usize,
781 is_first_sibling: bool,
782 ) {
783 let axis = AlignAxis::new(&direction, alignment_direction);
784
785 match axis {
786 AlignAxis::Height => match alignment {
787 Alignment::SpaceBetween if !is_first_sibling => {
788 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
789 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
790 available_area.origin.y += gap_size;
791 }
792 Alignment::SpaceEvenly => {
793 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
794 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
795 available_area.origin.y += gap_size;
796 }
797 Alignment::SpaceAround => {
798 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
799 let one_gap_size = all_gaps_sizes / siblings_len as f32;
800 let gap_size = if is_first_sibling {
801 one_gap_size / 2.
802 } else {
803 one_gap_size
804 };
805 available_area.origin.y += gap_size;
806 }
807 _ => {}
808 },
809 AlignAxis::Width => match alignment {
810 Alignment::SpaceBetween if !is_first_sibling => {
811 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
812 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
813 available_area.origin.x += gap_size;
814 }
815 Alignment::SpaceEvenly => {
816 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
817 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
818 available_area.origin.x += gap_size;
819 }
820 Alignment::SpaceAround => {
821 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
822 let one_gap_size = all_gaps_sizes / siblings_len as f32;
823 let gap_size = if is_first_sibling {
824 one_gap_size / 2.
825 } else {
826 one_gap_size
827 };
828 available_area.origin.x += gap_size;
829 }
830 _ => {}
831 },
832 }
833 }
834
835 #[allow(clippy::too_many_arguments)]
837 fn stack_child(
838 available_area: &mut AreaOf<Available>,
839 parent_node: &Node,
840 child_node: &Node,
841 parent_area: &mut AreaOf<Parent>,
842 inner_area: &mut AreaOf<Inner>,
843 inner_sizes: &mut Size2D,
844 child_area: &Area,
845 is_last_sibiling: bool,
846 phase: Phase,
847 ) {
848 let spacing = if is_last_sibiling {
850 Length::default()
851 } else {
852 parent_node.spacing
853 };
854
855 match parent_node.direction {
856 Direction::Horizontal => {
857 available_area.origin.x = child_area.max_x() + spacing.get();
859 available_area.size.width -= child_area.size.width + spacing.get();
860
861 inner_sizes.height = child_area.height().max(inner_sizes.height);
862 inner_sizes.width += spacing.get();
863 if !child_node.width.is_flex() || phase == Phase::Final {
864 inner_sizes.width += child_area.width();
865 }
866
867 if parent_node.height.inner_sized() {
869 parent_area.size.height = parent_area.size.height.max(
870 child_area.size.height
871 + parent_node.padding.vertical()
872 + parent_node.margin.vertical(),
873 );
874 inner_area.size.height = parent_area.size.height
876 - parent_node.padding.vertical()
877 - parent_node.margin.vertical();
878 }
879
880 if parent_node.width.inner_sized() {
882 parent_area.size.width += child_area.size.width + spacing.get();
883 }
884 }
885 Direction::Vertical => {
886 available_area.origin.y = child_area.max_y() + spacing.get();
888 available_area.size.height -= child_area.size.height + spacing.get();
889
890 inner_sizes.width = child_area.width().max(inner_sizes.width);
891 inner_sizes.height += spacing.get();
892 if !child_node.height.is_flex() || phase == Phase::Final {
893 inner_sizes.height += child_area.height();
894 }
895
896 if parent_node.width.inner_sized() {
898 parent_area.size.width = parent_area.size.width.max(
899 child_area.size.width
900 + parent_node.padding.horizontal()
901 + parent_node.margin.horizontal(),
902 );
903 inner_area.size.width = parent_area.size.width
905 - parent_node.padding.horizontal()
906 - parent_node.margin.horizontal();
907 }
908
909 if parent_node.height.inner_sized() {
911 parent_area.size.height += child_area.size.height + spacing.get();
912 }
913 }
914 }
915 }
916
917 fn shrink_area_to_fit_when_unbounded(
923 available_area: &mut AreaOf<Available>,
924 parent_area: &AreaOf<Parent>,
925 inner_area: &mut AreaOf<Inner>,
926 parent_node: &Node,
927 alignment_direction: AlignmentDirection,
928 ) {
929 struct NodeData<'a> {
930 pub inner_origin: &'a mut f32,
931 pub inner_size: &'a mut f32,
932 pub area_origin: f32,
933 pub area_size: f32,
934 pub one_side_padding: f32,
935 pub two_sides_padding: f32,
936 pub one_side_margin: f32,
937 pub two_sides_margin: f32,
938 pub available_size: &'a mut f32,
939 }
940
941 let axis = AlignAxis::new(&parent_node.direction, alignment_direction);
942 let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction {
943 Direction::Vertical => (
944 parent_node.main_alignment.is_not_start(),
945 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
946 ),
947 Direction::Horizontal => (
948 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
949 parent_node.main_alignment.is_not_start(),
950 ),
951 };
952 let NodeData {
953 inner_origin,
954 inner_size,
955 area_origin,
956 area_size,
957 one_side_padding,
958 two_sides_padding,
959 one_side_margin,
960 two_sides_margin,
961 available_size,
962 } = match axis {
963 AlignAxis::Height if parent_node.height.inner_sized() && is_vertical_not_start => {
964 NodeData {
965 inner_origin: &mut inner_area.origin.y,
966 inner_size: &mut inner_area.size.height,
967 area_origin: parent_area.origin.y,
968 area_size: parent_area.size.height,
969 one_side_padding: parent_node.padding.top(),
970 two_sides_padding: parent_node.padding.vertical(),
971 one_side_margin: parent_node.margin.top(),
972 two_sides_margin: parent_node.margin.vertical(),
973 available_size: &mut available_area.size.height,
974 }
975 }
976 AlignAxis::Width if parent_node.width.inner_sized() && is_horizontal_not_start => {
977 NodeData {
978 inner_origin: &mut inner_area.origin.x,
979 inner_size: &mut inner_area.size.width,
980 area_origin: parent_area.origin.x,
981 area_size: parent_area.size.width,
982 one_side_padding: parent_node.padding.left(),
983 two_sides_padding: parent_node.padding.horizontal(),
984 one_side_margin: parent_node.margin.left(),
985 two_sides_margin: parent_node.margin.horizontal(),
986 available_size: &mut available_area.size.width,
987 }
988 }
989 _ => return,
990 };
991
992 *inner_origin = area_origin + one_side_padding + one_side_margin;
994 *inner_size = area_size - two_sides_padding - two_sides_margin;
996 *available_size = *inner_size;
998 }
999}