1use cranpose_ui_layout::{
2 Axis, Constraints, MeasurePolicy, MeasureResult, MeasureScope, ParentData, Placement,
3 bias_offset,
4};
5use smallvec::SmallVec;
6
7use crate::layout::core::{
8 Alignment, Arrangement, HorizontalAlignment, LinearArrangement, Measurable, VerticalAlignment,
9};
10
11#[derive(Clone, Debug, PartialEq)]
13pub struct BoxMeasurePolicy {
14 pub content_alignment: Alignment,
15 pub propagate_min_constraints: bool,
16}
17
18impl BoxMeasurePolicy {
19 pub fn new(content_alignment: Alignment, propagate_min_constraints: bool) -> Self {
20 Self {
21 content_alignment,
22 propagate_min_constraints,
23 }
24 }
25}
26
27impl MeasurePolicy for BoxMeasurePolicy {
28 fn measure(
29 &self,
30 scope: &dyn MeasureScope,
31 measurables: &[Box<dyn Measurable>],
32 constraints: Constraints,
33 ) -> MeasureResult {
34 let mut placements = Vec::new();
35 let measurement = self.measure_into(scope, measurables, constraints, &mut placements);
36 MeasureResult::new(measurement, placements)
37 }
38
39 fn measure_into(
40 &self,
41 scope: &dyn MeasureScope,
42 measurables: &[Box<dyn Measurable>],
43 constraints: Constraints,
44 placements: &mut Vec<Placement>,
45 ) -> cranpose_ui_layout::Measurement {
46 placements.clear();
47 let child_constraints = if self.propagate_min_constraints {
48 constraints
49 } else {
50 Constraints {
51 min_width: 0.0,
52 max_width: constraints.max_width,
53 min_height: 0.0,
54 max_height: constraints.max_height,
55 }
56 };
57
58 let mut max_width = 0.0_f32;
59 let mut max_height = 0.0_f32;
60 let mut placeables: SmallVec<[(cranpose_ui_layout::Placeable, Alignment); 8]> =
61 SmallVec::new();
62
63 for measurable in measurables {
64 let placeable = measurable.measure(child_constraints);
65 max_width = max_width.max(placeable.width());
66 max_height = max_height.max(placeable.height());
67 let alignment = measurable
68 .parent_data()
69 .box_alignment
70 .unwrap_or(self.content_alignment);
71 placeables.push((placeable, alignment));
72 }
73
74 let width = max_width.clamp(constraints.min_width, constraints.max_width);
75 let height = max_height.clamp(constraints.min_height, constraints.max_height);
76
77 placements.reserve(placeables.len());
78 for (placeable, alignment) in placeables {
79 let child_width = placeable.width();
80 let child_height = placeable.height();
81
82 let x = alignment
83 .horizontal
84 .align(width, child_width, scope.density());
85 let y = alignment
86 .vertical
87 .align(height, child_height, scope.density());
88
89 placeable.place(x, y);
90 placements.push(Placement::new(placeable.node_id(), x, y, 0));
91 }
92
93 crate::modifier::Size { width, height }.into()
94 }
95
96 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
97 measurables
98 .iter()
99 .map(|m| m.min_intrinsic_width(height))
100 .fold(0.0, f32::max)
101 }
102
103 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
104 measurables
105 .iter()
106 .map(|m| m.max_intrinsic_width(height))
107 .fold(0.0, f32::max)
108 }
109
110 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
111 measurables
112 .iter()
113 .map(|m| m.min_intrinsic_height(width))
114 .fold(0.0, f32::max)
115 }
116
117 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
118 measurables
119 .iter()
120 .map(|m| m.max_intrinsic_height(width))
121 .fold(0.0, f32::max)
122 }
123}
124
125#[derive(Clone, Debug, PartialEq)]
163pub struct FlexMeasurePolicy {
164 pub axis: Axis,
166 pub main_axis_arrangement: LinearArrangement,
168 pub cross_axis_alignment: CrossAxisAlignment,
170 pub density: f32,
173}
174
175pub(crate) struct WeightShares {
179 density: f32,
180 unit_px: f32,
181 remainder_px: f32,
182}
183
184impl WeightShares {
185 pub(crate) fn new(
186 remaining: f32,
187 weights: impl Iterator<Item = f32> + Clone,
188 density: f32,
189 ) -> Self {
190 let density = if density > 0.0 && density.is_finite() {
191 density
192 } else {
193 1.0
194 };
195 let total_weight: f32 = weights.clone().sum();
196 let remaining_px = (remaining * density).round();
197 let unit_px = if total_weight > 0.0 {
198 remaining_px / total_weight
199 } else {
200 0.0
201 };
202 let rounded_px: f32 = weights.map(|weight| (unit_px * weight + 0.5).floor()).sum();
203 Self {
204 density,
205 unit_px,
206 remainder_px: remaining_px - rounded_px,
207 }
208 }
209
210 pub(crate) fn next_share(&mut self, weight: f32) -> f32 {
212 let step = if self.remainder_px > 0.0 {
213 1.0
214 } else if self.remainder_px < 0.0 {
215 -1.0
216 } else {
217 0.0
218 };
219 self.remainder_px -= step;
220 ((self.unit_px * weight + 0.5).floor() + step).max(0.0) / self.density
221 }
222}
223
224#[derive(Clone, Copy, Debug, PartialEq)]
227pub enum CrossAxisAlignment {
228 Start,
230 Center,
232 End,
234}
235
236impl CrossAxisAlignment {
237 fn align(&self, available: f32, child: f32, density: f32) -> f32 {
239 let bias = match self {
240 CrossAxisAlignment::Start => -1.0,
241 CrossAxisAlignment::Center => 0.0,
242 CrossAxisAlignment::End => 1.0,
243 };
244 bias_offset(bias, available, child, density)
245 }
246}
247
248impl From<HorizontalAlignment> for CrossAxisAlignment {
249 fn from(alignment: HorizontalAlignment) -> Self {
250 match alignment {
251 HorizontalAlignment::Start => CrossAxisAlignment::Start,
252 HorizontalAlignment::CenterHorizontally => CrossAxisAlignment::Center,
253 HorizontalAlignment::End => CrossAxisAlignment::End,
254 }
255 }
256}
257
258impl From<VerticalAlignment> for CrossAxisAlignment {
259 fn from(alignment: VerticalAlignment) -> Self {
260 match alignment {
261 VerticalAlignment::Top => CrossAxisAlignment::Start,
262 VerticalAlignment::CenterVertically => CrossAxisAlignment::Center,
263 VerticalAlignment::Bottom => CrossAxisAlignment::End,
264 }
265 }
266}
267
268impl FlexMeasurePolicy {
269 pub fn new(
271 axis: Axis,
272 main_axis_arrangement: LinearArrangement,
273 cross_axis_alignment: CrossAxisAlignment,
274 density: f32,
275 ) -> Self {
276 Self {
277 axis,
278 main_axis_arrangement,
279 cross_axis_alignment,
280 density,
281 }
282 }
283
284 pub fn row(
286 horizontal_arrangement: LinearArrangement,
287 vertical_alignment: VerticalAlignment,
288 density: f32,
289 ) -> Self {
290 Self::new(
291 Axis::Horizontal,
292 horizontal_arrangement,
293 vertical_alignment.into(),
294 density,
295 )
296 }
297
298 pub fn column(
300 vertical_arrangement: LinearArrangement,
301 horizontal_alignment: HorizontalAlignment,
302 density: f32,
303 ) -> Self {
304 Self::new(
305 Axis::Vertical,
306 vertical_arrangement,
307 horizontal_alignment.into(),
308 density,
309 )
310 }
311
312 fn get_axis_constraints(&self, constraints: Constraints) -> (f32, f32, f32, f32) {
313 match self.axis {
314 Axis::Horizontal => (
315 constraints.min_width,
316 constraints.max_width,
317 constraints.min_height,
318 constraints.max_height,
319 ),
320 Axis::Vertical => (
321 constraints.min_height,
322 constraints.max_height,
323 constraints.min_width,
324 constraints.max_width,
325 ),
326 }
327 }
328
329 fn make_constraints(
330 &self,
331 min_main: f32,
332 max_main: f32,
333 min_cross: f32,
334 max_cross: f32,
335 ) -> Constraints {
336 match self.axis {
337 Axis::Horizontal => Constraints {
338 min_width: min_main,
339 max_width: max_main,
340 min_height: min_cross,
341 max_height: max_cross,
342 },
343 Axis::Vertical => Constraints {
344 min_width: min_cross,
345 max_width: max_cross,
346 min_height: min_main,
347 max_height: max_main,
348 },
349 }
350 }
351
352 fn get_main_axis_size(&self, width: f32, height: f32) -> f32 {
353 match self.axis {
354 Axis::Horizontal => width,
355 Axis::Vertical => height,
356 }
357 }
358
359 fn get_cross_axis_size(&self, width: f32, height: f32) -> f32 {
360 match self.axis {
361 Axis::Horizontal => height,
362 Axis::Vertical => width,
363 }
364 }
365
366 fn measure_fixed_children(
372 &self,
373 measurables: &[Box<dyn Measurable>],
374 fixed_children: &[usize],
375 (max_main, max_cross): (f32, f32),
376 spacing: f32,
377 placeables: &mut [Option<cranpose_ui_layout::Placeable>],
378 ) -> (f32, f32) {
379 let main_axis_bounded = max_main.is_finite();
380 let mut fixed_space = 0.0_f32;
381 let mut max_cross_size = 0.0_f32;
382 for &idx in fixed_children {
383 let available_main = if main_axis_bounded {
384 (max_main - fixed_space).max(0.0)
385 } else {
386 max_main
387 };
388 let placeable = measurables[idx].measure(self.make_constraints(
389 0.0,
390 available_main,
391 0.0,
392 max_cross,
393 ));
394 let main_size = self.get_main_axis_size(placeable.width(), placeable.height());
395 let spacing_after = if main_axis_bounded {
396 spacing.min(available_main - main_size).max(0.0)
397 } else {
398 spacing
399 };
400 fixed_space += main_size + spacing_after;
401 max_cross_size =
402 max_cross_size.max(self.get_cross_axis_size(placeable.width(), placeable.height()));
403 placeables[idx] = Some(placeable);
404 }
405 (fixed_space, max_cross_size)
406 }
407
408 fn get_spacing(&self) -> f32 {
409 self.main_axis_arrangement.spacing(self.density)
410 }
411
412 fn measured_extents(
413 &self,
414 placeables: &[cranpose_ui_layout::Placeable],
415 parent_data: &[cranpose_ui_layout::ParentData],
416 ) -> (f32, f32, f32) {
417 let mut main = 0.0;
418 let mut before = 0.0_f32;
419 let mut after = 0.0_f32;
420 for (placeable, data) in placeables.iter().zip(parent_data) {
421 main += self.get_main_axis_size(placeable.width(), placeable.height());
422 if self.axis == Axis::Horizontal
423 && data.row_baseline
424 && let Some(baseline) = placeable.alignment_lines().first_baseline()
425 {
426 before = before.max(baseline);
427 after = after.max(placeable.height() - baseline);
428 }
429 }
430 (main, before, after)
431 }
432
433 fn cross_axis_position(
434 &self,
435 placeable: &cranpose_ui_layout::Placeable,
436 parent_data: ParentData,
437 container_cross: f32,
438 before_baseline: f32,
439 ) -> f32 {
440 if self.axis == Axis::Horizontal && parent_data.row_baseline {
441 return placeable
442 .alignment_lines()
443 .first_baseline()
444 .map_or(0.0, |baseline| before_baseline - baseline);
445 }
446 let alignment = match self.axis {
447 Axis::Horizontal => parent_data
448 .row_alignment
449 .map_or(self.cross_axis_alignment, Into::into),
450 Axis::Vertical => parent_data
451 .column_alignment
452 .map_or(self.cross_axis_alignment, Into::into),
453 };
454 let child_cross = self.get_cross_axis_size(placeable.width(), placeable.height());
455 alignment.align(container_cross, child_cross, self.density)
456 }
457}
458
459impl MeasurePolicy for FlexMeasurePolicy {
460 fn measure(
461 &self,
462 scope: &dyn MeasureScope,
463 measurables: &[Box<dyn Measurable>],
464 constraints: Constraints,
465 ) -> MeasureResult {
466 let mut placements = Vec::new();
467 let measurement = self.measure_into(scope, measurables, constraints, &mut placements);
468 MeasureResult::new(measurement, placements)
469 }
470
471 fn measure_into(
472 &self,
473 _scope: &dyn MeasureScope,
474 measurables: &[Box<dyn Measurable>],
475 constraints: Constraints,
476 placements: &mut Vec<Placement>,
477 ) -> cranpose_ui_layout::Measurement {
478 placements.clear();
479 if measurables.is_empty() {
480 let (width, height) = constraints.constrain(0.0, 0.0);
481 return crate::modifier::Size { width, height }.into();
482 }
483
484 let (min_main, max_main, min_cross, max_cross) = self.get_axis_constraints(constraints);
485 let main_axis_bounded = max_main.is_finite();
486 let spacing = self.get_spacing();
487
488 let mut fixed_children: SmallVec<[usize; 8]> = SmallVec::new();
489 let parent_data: SmallVec<[ParentData; 8]> = measurables
490 .iter()
491 .map(|child| child.parent_data())
492 .collect();
493 let mut weighted_children: SmallVec<[(usize, ParentData); 8]> = SmallVec::new();
494
495 for (idx, data) in parent_data.iter().copied().enumerate() {
496 if data.has_weight() {
497 weighted_children.push((idx, data));
498 } else {
499 fixed_children.push(idx);
500 }
501 }
502
503 let child_constraints = self.make_constraints(0.0, max_main, 0.0, max_cross);
504
505 let mut placeables: SmallVec<[Option<cranpose_ui_layout::Placeable>; 8]> = SmallVec::new();
506 placeables.resize_with(measurables.len(), || None);
507 let (fixed_space, mut max_cross_size) = self.measure_fixed_children(
508 measurables,
509 &fixed_children,
510 (max_main, max_cross),
511 spacing,
512 &mut placeables,
513 );
514
515 let num_children = measurables.len();
516 let total_spacing = if num_children > 1 {
517 spacing * (num_children - 1) as f32
518 } else {
519 0.0
520 };
521
522 if !weighted_children.is_empty() {
523 if main_axis_bounded {
524 let weighted_spacing = spacing * (weighted_children.len() - 1) as f32;
525 let remaining_main = (max_main - fixed_space - weighted_spacing).max(0.0);
526
527 let mut shares = WeightShares::new(
528 remaining_main,
529 weighted_children.iter().map(|(_, data)| data.weight),
530 self.density,
531 );
532
533 for &(idx, parent_data) in &weighted_children {
534 let measurable = &measurables[idx];
535 let allocated = shares.next_share(parent_data.weight);
536
537 let weighted_constraints = if parent_data.fill {
538 self.make_constraints(allocated, allocated, 0.0, max_cross)
539 } else {
540 self.make_constraints(0.0, allocated, 0.0, max_cross)
541 };
542
543 let placeable = measurable.measure(weighted_constraints);
544 let cross_size =
545 self.get_cross_axis_size(placeable.width(), placeable.height());
546 max_cross_size = max_cross_size.max(cross_size);
547 placeables[idx] = Some(placeable);
548 }
549 } else {
550 for &(idx, _) in &weighted_children {
551 let measurable = &measurables[idx];
552 let placeable = measurable.measure(child_constraints);
553 let cross_size =
554 self.get_cross_axis_size(placeable.width(), placeable.height());
555 max_cross_size = max_cross_size.max(cross_size);
556 placeables[idx] = Some(placeable);
557 }
558 }
559 }
560
561 let placeables: SmallVec<[cranpose_ui_layout::Placeable; 8]> = placeables
562 .into_iter()
563 .enumerate()
564 .map(|(idx, placeable)| {
565 placeable.unwrap_or_else(|| measurables[idx].measure(child_constraints))
566 })
567 .collect();
568
569 let (total_main, before_baseline, after_baseline) =
570 self.measured_extents(&placeables, &parent_data);
571 let total_main = total_main + total_spacing;
572 max_cross_size = max_cross_size.max(before_baseline + after_baseline);
573
574 let container_main = total_main.clamp(min_main, max_main);
575 let container_cross = max_cross_size.clamp(min_cross, max_cross);
576
577 let child_main_sizes: SmallVec<[f32; 8]> = placeables
578 .iter()
579 .map(|p| self.get_main_axis_size(p.width(), p.height()))
580 .collect();
581
582 let mut main_positions: SmallVec<[f32; 8]> =
583 SmallVec::with_capacity(child_main_sizes.len());
584 main_positions.resize(child_main_sizes.len(), 0.0);
585
586 let arrangement = if total_main > container_main && !self.main_axis_arrangement.is_spaced()
587 {
588 LinearArrangement::Start
589 } else {
590 self.main_axis_arrangement
591 };
592 arrangement.arrange(
593 self.density,
594 container_main,
595 &child_main_sizes,
596 &mut main_positions,
597 );
598
599 placements.reserve(placeables.len());
600 for (idx, (placeable, main_pos)) in placeables.into_iter().zip(main_positions).enumerate() {
601 let cross_pos = self.cross_axis_position(
602 &placeable,
603 parent_data[idx],
604 container_cross,
605 before_baseline,
606 );
607
608 let (x, y) = match self.axis {
609 Axis::Horizontal => (main_pos, cross_pos),
610 Axis::Vertical => (cross_pos, main_pos),
611 };
612
613 placeable.place(x, y);
614 placements.push(Placement::new(placeable.node_id(), x, y, 0));
615 }
616
617 let (width, height) = match self.axis {
618 Axis::Horizontal => (container_main, container_cross),
619 Axis::Vertical => (container_cross, container_main),
620 };
621
622 crate::modifier::Size { width, height }.into()
623 }
624
625 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
626 let spacing = self.get_spacing();
627 let total_spacing = if measurables.len() > 1 {
628 spacing * (measurables.len() - 1) as f32
629 } else {
630 0.0
631 };
632
633 match self.axis {
634 Axis::Horizontal => {
635 measurables
636 .iter()
637 .map(|m| m.min_intrinsic_width(height))
638 .sum::<f32>()
639 + total_spacing
640 }
641 Axis::Vertical => measurables
642 .iter()
643 .map(|m| m.min_intrinsic_width(height))
644 .fold(0.0, f32::max),
645 }
646 }
647
648 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
649 let spacing = self.get_spacing();
650 let total_spacing = if measurables.len() > 1 {
651 spacing * (measurables.len() - 1) as f32
652 } else {
653 0.0
654 };
655
656 match self.axis {
657 Axis::Horizontal => {
658 measurables
659 .iter()
660 .map(|m| m.max_intrinsic_width(height))
661 .sum::<f32>()
662 + total_spacing
663 }
664 Axis::Vertical => measurables
665 .iter()
666 .map(|m| m.max_intrinsic_width(height))
667 .fold(0.0, f32::max),
668 }
669 }
670
671 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
672 let spacing = self.get_spacing();
673 let total_spacing = if measurables.len() > 1 {
674 spacing * (measurables.len() - 1) as f32
675 } else {
676 0.0
677 };
678
679 match self.axis {
680 Axis::Horizontal => measurables
681 .iter()
682 .map(|m| m.min_intrinsic_height(width))
683 .fold(0.0, f32::max),
684 Axis::Vertical => {
685 measurables
686 .iter()
687 .map(|m| m.min_intrinsic_height(width))
688 .sum::<f32>()
689 + total_spacing
690 }
691 }
692 }
693
694 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
695 let spacing = self.get_spacing();
696 let total_spacing = if measurables.len() > 1 {
697 spacing * (measurables.len() - 1) as f32
698 } else {
699 0.0
700 };
701
702 match self.axis {
703 Axis::Horizontal => measurables
704 .iter()
705 .map(|m| m.max_intrinsic_height(width))
706 .fold(0.0, f32::max),
707 Axis::Vertical => {
708 measurables
709 .iter()
710 .map(|m| m.max_intrinsic_height(width))
711 .sum::<f32>()
712 + total_spacing
713 }
714 }
715 }
716}
717
718#[derive(Clone, Debug, PartialEq)]
731pub struct FlowRowMeasurePolicy {
732 pub main_axis_spacing: f32,
734 pub cross_axis_spacing: f32,
736}
737
738impl FlowRowMeasurePolicy {
739 pub fn new(main_axis_spacing: f32, cross_axis_spacing: f32) -> Self {
740 Self {
741 main_axis_spacing: main_axis_spacing.max(0.0),
742 cross_axis_spacing: cross_axis_spacing.max(0.0),
743 }
744 }
745
746 fn wrapped_intrinsic_height(
747 &self,
748 measurables: &[Box<dyn Measurable>],
749 available_width: f32,
750 use_min_height: bool,
751 ) -> f32 {
752 let mut cursor_x = 0.0_f32;
753 let mut line_top = 0.0_f32;
754 let mut line_height = 0.0_f32;
755
756 for measurable in measurables {
757 let child_width = measurable.max_intrinsic_width(f32::INFINITY);
758 let child_height = if use_min_height {
759 measurable.min_intrinsic_height(child_width)
760 } else {
761 measurable.max_intrinsic_height(child_width)
762 };
763
764 if cursor_x > 0.0 && cursor_x + self.main_axis_spacing + child_width > available_width {
765 line_top += line_height + self.cross_axis_spacing;
766 cursor_x = 0.0;
767 line_height = 0.0;
768 }
769 cursor_x += if cursor_x > 0.0 {
770 self.main_axis_spacing + child_width
771 } else {
772 child_width
773 };
774 line_height = line_height.max(child_height);
775 }
776
777 line_top + line_height
778 }
779}
780
781impl MeasurePolicy for FlowRowMeasurePolicy {
782 fn measure(
783 &self,
784 scope: &dyn MeasureScope,
785 measurables: &[Box<dyn Measurable>],
786 constraints: Constraints,
787 ) -> MeasureResult {
788 let mut placements = Vec::new();
789 let measurement = self.measure_into(scope, measurables, constraints, &mut placements);
790 MeasureResult::new(measurement, placements)
791 }
792
793 fn measure_into(
794 &self,
795 _scope: &dyn MeasureScope,
796 measurables: &[Box<dyn Measurable>],
797 constraints: Constraints,
798 placements: &mut Vec<Placement>,
799 ) -> cranpose_ui_layout::Measurement {
800 placements.clear();
801 if measurables.is_empty() {
802 let (width, height) = constraints.constrain(0.0, 0.0);
803 return crate::modifier::Size { width, height }.into();
804 }
805
806 let child_constraints = Constraints {
807 min_width: 0.0,
808 max_width: constraints.max_width,
809 min_height: 0.0,
810 max_height: constraints.max_height,
811 };
812
813 let placeables: SmallVec<[cranpose_ui_layout::Placeable; 8]> = measurables
814 .iter()
815 .map(|measurable| measurable.measure(child_constraints))
816 .collect();
817
818 let mut cursor_x = 0.0_f32;
819 let mut line_top = 0.0_f32;
820 let mut line_height = 0.0_f32;
821 let mut max_line_width = 0.0_f32;
822
823 placements.reserve(placeables.len());
824 for placeable in placeables {
825 let child_width = placeable.width();
826 let child_height = placeable.height();
827
828 if cursor_x > 0.0
829 && cursor_x + self.main_axis_spacing + child_width > constraints.max_width
830 {
831 max_line_width = max_line_width.max(cursor_x);
832 line_top += line_height + self.cross_axis_spacing;
833 cursor_x = 0.0;
834 line_height = 0.0;
835 }
836
837 let x = if cursor_x > 0.0 {
838 cursor_x + self.main_axis_spacing
839 } else {
840 0.0
841 };
842 placeable.place(x, line_top);
843 placements.push(Placement::new(placeable.node_id(), x, line_top, 0));
844
845 cursor_x = x + child_width;
846 line_height = line_height.max(child_height);
847 }
848 max_line_width = max_line_width.max(cursor_x);
849
850 let width = max_line_width.clamp(constraints.min_width, constraints.max_width);
851 let height = (line_top + line_height).clamp(constraints.min_height, constraints.max_height);
852 crate::modifier::Size { width, height }.into()
853 }
854
855 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
856 measurables
857 .iter()
858 .map(|m| m.min_intrinsic_width(height))
859 .fold(0.0, f32::max)
860 }
861
862 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
863 let total_spacing = if measurables.len() > 1 {
864 self.main_axis_spacing * (measurables.len() - 1) as f32
865 } else {
866 0.0
867 };
868 measurables
869 .iter()
870 .map(|m| m.max_intrinsic_width(height))
871 .sum::<f32>()
872 + total_spacing
873 }
874
875 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
876 self.wrapped_intrinsic_height(measurables, width, true)
877 }
878
879 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
880 self.wrapped_intrinsic_height(measurables, width, false)
881 }
882}
883
884#[derive(Clone, Debug, PartialEq)]
887pub struct LeafMeasurePolicy {
888 pub intrinsic_size: crate::modifier::Size,
889}
890
891impl LeafMeasurePolicy {
892 pub fn new(intrinsic_size: crate::modifier::Size) -> Self {
893 Self { intrinsic_size }
894 }
895}
896
897impl MeasurePolicy for LeafMeasurePolicy {
898 fn measure(
899 &self,
900 scope: &dyn MeasureScope,
901 _measurables: &[Box<dyn Measurable>],
902 constraints: Constraints,
903 ) -> MeasureResult {
904 let mut placements = Vec::new();
905 let measurement = self.measure_into(scope, &[], constraints, &mut placements);
906 MeasureResult::new(measurement, placements)
907 }
908
909 fn measure_into(
910 &self,
911 _scope: &dyn MeasureScope,
912 _measurables: &[Box<dyn Measurable>],
913 constraints: Constraints,
914 placements: &mut Vec<Placement>,
915 ) -> cranpose_ui_layout::Measurement {
916 placements.clear();
917 let (width, height) =
918 constraints.constrain(self.intrinsic_size.width, self.intrinsic_size.height);
919
920 crate::modifier::Size { width, height }.into()
921 }
922
923 fn min_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
924 self.intrinsic_size.width
925 }
926
927 fn max_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
928 self.intrinsic_size.width
929 }
930
931 fn min_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
932 self.intrinsic_size.height
933 }
934
935 fn max_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
936 self.intrinsic_size.height
937 }
938}
939
940#[derive(Clone, Debug, PartialEq)]
946pub struct EmptyMeasurePolicy;
947
948impl EmptyMeasurePolicy {
949 pub fn new() -> Self {
950 Self
951 }
952}
953
954impl Default for EmptyMeasurePolicy {
955 fn default() -> Self {
956 Self::new()
957 }
958}
959
960impl MeasurePolicy for EmptyMeasurePolicy {
961 fn measure(
962 &self,
963 scope: &dyn MeasureScope,
964 _measurables: &[Box<dyn Measurable>],
965 constraints: Constraints,
966 ) -> MeasureResult {
967 let mut placements = Vec::new();
968 let measurement = self.measure_into(scope, &[], constraints, &mut placements);
969 MeasureResult::new(measurement, placements)
970 }
971
972 fn measure_into(
973 &self,
974 _scope: &dyn MeasureScope,
975 _measurables: &[Box<dyn Measurable>],
976 constraints: Constraints,
977 placements: &mut Vec<Placement>,
978 ) -> cranpose_ui_layout::Measurement {
979 placements.clear();
980 let (width, height) = constraints.constrain(0.0, 0.0);
981
982 crate::modifier::Size { width, height }.into()
983 }
984
985 fn min_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
986 0.0
987 }
988
989 fn max_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
990 0.0
991 }
992
993 fn min_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
994 0.0
995 }
996
997 fn max_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
998 0.0
999 }
1000}
1001
1002#[cfg(test)]
1003#[path = "tests/policies_tests.rs"]
1004mod tests;