1use crate::layout::core::{
2 Alignment, Arrangement, HorizontalAlignment, LinearArrangement, Measurable, VerticalAlignment,
3};
4use cranpose_ui_layout::{
5 Axis, Constraints, FlexParentData, MeasurePolicy, MeasureResult, Placement,
6};
7use smallvec::SmallVec;
8
9#[derive(Clone, Debug, PartialEq)]
11pub struct BoxMeasurePolicy {
12 pub content_alignment: Alignment,
13 pub propagate_min_constraints: bool,
14}
15
16impl BoxMeasurePolicy {
17 pub fn new(content_alignment: Alignment, propagate_min_constraints: bool) -> Self {
18 Self {
19 content_alignment,
20 propagate_min_constraints,
21 }
22 }
23}
24
25impl MeasurePolicy for BoxMeasurePolicy {
26 fn measure(
27 &self,
28 measurables: &[Box<dyn Measurable>],
29 constraints: Constraints,
30 ) -> MeasureResult {
31 let mut placements = Vec::new();
32 let size = self.measure_into(measurables, constraints, &mut placements);
33 MeasureResult::new(size, placements)
34 }
35
36 fn measure_into(
37 &self,
38 measurables: &[Box<dyn Measurable>],
39 constraints: Constraints,
40 placements: &mut Vec<Placement>,
41 ) -> crate::modifier::Size {
42 placements.clear();
43 let child_constraints = if self.propagate_min_constraints {
44 constraints
45 } else {
46 Constraints {
47 min_width: 0.0,
48 max_width: constraints.max_width,
49 min_height: 0.0,
50 max_height: constraints.max_height,
51 }
52 };
53
54 let mut max_width = 0.0_f32;
55 let mut max_height = 0.0_f32;
56 let mut placeables: SmallVec<[cranpose_ui_layout::Placeable; 8]> = SmallVec::new();
57
58 for measurable in measurables {
59 let placeable = measurable.measure(child_constraints);
60 max_width = max_width.max(placeable.width());
61 max_height = max_height.max(placeable.height());
62 placeables.push(placeable);
63 }
64
65 let width = max_width.clamp(constraints.min_width, constraints.max_width);
66 let height = max_height.clamp(constraints.min_height, constraints.max_height);
67
68 placements.reserve(placeables.len());
69 for placeable in placeables {
70 let child_width = placeable.width();
71 let child_height = placeable.height();
72
73 let x = match self.content_alignment.horizontal {
74 HorizontalAlignment::Start => 0.0,
75 HorizontalAlignment::CenterHorizontally => ((width - child_width) / 2.0).max(0.0),
76 HorizontalAlignment::End => (width - child_width).max(0.0),
77 };
78
79 let y = match self.content_alignment.vertical {
80 VerticalAlignment::Top => 0.0,
81 VerticalAlignment::CenterVertically => ((height - child_height) / 2.0).max(0.0),
82 VerticalAlignment::Bottom => (height - child_height).max(0.0),
83 };
84
85 placeable.place(x, y);
86 placements.push(Placement::new(placeable.node_id(), x, y, 0));
87 }
88
89 crate::modifier::Size { width, height }
90 }
91
92 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
93 measurables
94 .iter()
95 .map(|m| m.min_intrinsic_width(height))
96 .fold(0.0, f32::max)
97 }
98
99 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
100 measurables
101 .iter()
102 .map(|m| m.max_intrinsic_width(height))
103 .fold(0.0, f32::max)
104 }
105
106 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
107 measurables
108 .iter()
109 .map(|m| m.min_intrinsic_height(width))
110 .fold(0.0, f32::max)
111 }
112
113 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
114 measurables
115 .iter()
116 .map(|m| m.max_intrinsic_height(width))
117 .fold(0.0, f32::max)
118 }
119}
120
121#[derive(Clone, Debug, PartialEq)]
160pub struct FlexMeasurePolicy {
161 pub axis: Axis,
163 pub main_axis_arrangement: LinearArrangement,
165 pub cross_axis_alignment: CrossAxisAlignment,
167}
168
169#[derive(Clone, Copy, Debug, PartialEq)]
172pub enum CrossAxisAlignment {
173 Start,
175 Center,
177 End,
179}
180
181impl CrossAxisAlignment {
182 fn align(&self, available: f32, child: f32) -> f32 {
184 match self {
185 CrossAxisAlignment::Start => 0.0,
186 CrossAxisAlignment::Center => ((available - child) / 2.0).max(0.0),
187 CrossAxisAlignment::End => (available - child).max(0.0),
188 }
189 }
190}
191
192impl From<HorizontalAlignment> for CrossAxisAlignment {
193 fn from(alignment: HorizontalAlignment) -> Self {
194 match alignment {
195 HorizontalAlignment::Start => CrossAxisAlignment::Start,
196 HorizontalAlignment::CenterHorizontally => CrossAxisAlignment::Center,
197 HorizontalAlignment::End => CrossAxisAlignment::End,
198 }
199 }
200}
201
202impl From<VerticalAlignment> for CrossAxisAlignment {
203 fn from(alignment: VerticalAlignment) -> Self {
204 match alignment {
205 VerticalAlignment::Top => CrossAxisAlignment::Start,
206 VerticalAlignment::CenterVertically => CrossAxisAlignment::Center,
207 VerticalAlignment::Bottom => CrossAxisAlignment::End,
208 }
209 }
210}
211
212impl FlexMeasurePolicy {
213 pub fn new(
214 axis: Axis,
215 main_axis_arrangement: LinearArrangement,
216 cross_axis_alignment: CrossAxisAlignment,
217 ) -> Self {
218 Self {
219 axis,
220 main_axis_arrangement,
221 cross_axis_alignment,
222 }
223 }
224
225 pub fn row(
227 horizontal_arrangement: LinearArrangement,
228 vertical_alignment: VerticalAlignment,
229 ) -> Self {
230 Self::new(
231 Axis::Horizontal,
232 horizontal_arrangement,
233 vertical_alignment.into(),
234 )
235 }
236
237 pub fn column(
239 vertical_arrangement: LinearArrangement,
240 horizontal_alignment: HorizontalAlignment,
241 ) -> Self {
242 Self::new(
243 Axis::Vertical,
244 vertical_arrangement,
245 horizontal_alignment.into(),
246 )
247 }
248
249 fn get_axis_constraints(&self, constraints: Constraints) -> (f32, f32, f32, f32) {
251 match self.axis {
252 Axis::Horizontal => (
253 constraints.min_width,
254 constraints.max_width,
255 constraints.min_height,
256 constraints.max_height,
257 ),
258 Axis::Vertical => (
259 constraints.min_height,
260 constraints.max_height,
261 constraints.min_width,
262 constraints.max_width,
263 ),
264 }
265 }
266
267 fn make_constraints(
269 &self,
270 min_main: f32,
271 max_main: f32,
272 min_cross: f32,
273 max_cross: f32,
274 ) -> Constraints {
275 match self.axis {
276 Axis::Horizontal => Constraints {
277 min_width: min_main,
278 max_width: max_main,
279 min_height: min_cross,
280 max_height: max_cross,
281 },
282 Axis::Vertical => Constraints {
283 min_width: min_cross,
284 max_width: max_cross,
285 min_height: min_main,
286 max_height: max_main,
287 },
288 }
289 }
290
291 fn get_main_axis_size(&self, width: f32, height: f32) -> f32 {
293 match self.axis {
294 Axis::Horizontal => width,
295 Axis::Vertical => height,
296 }
297 }
298
299 fn get_cross_axis_size(&self, width: f32, height: f32) -> f32 {
301 match self.axis {
302 Axis::Horizontal => height,
303 Axis::Vertical => width,
304 }
305 }
306
307 fn get_spacing(&self) -> f32 {
309 match self.main_axis_arrangement {
310 LinearArrangement::SpacedBy(value) => value.max(0.0),
311 _ => 0.0,
312 }
313 }
314}
315
316impl MeasurePolicy for FlexMeasurePolicy {
317 fn measure(
318 &self,
319 measurables: &[Box<dyn Measurable>],
320 constraints: Constraints,
321 ) -> MeasureResult {
322 let mut placements = Vec::new();
323 let size = self.measure_into(measurables, constraints, &mut placements);
324 MeasureResult::new(size, placements)
325 }
326
327 fn measure_into(
328 &self,
329 measurables: &[Box<dyn Measurable>],
330 constraints: Constraints,
331 placements: &mut Vec<Placement>,
332 ) -> crate::modifier::Size {
333 placements.clear();
334 if measurables.is_empty() {
335 let (width, height) = constraints.constrain(0.0, 0.0);
336 return crate::modifier::Size { width, height };
337 }
338
339 let (min_main, max_main, min_cross, max_cross) = self.get_axis_constraints(constraints);
340 let main_axis_bounded = max_main.is_finite();
341 let spacing = self.get_spacing();
342
343 let mut fixed_children: SmallVec<[usize; 8]> = SmallVec::new();
345 let mut weighted_children: SmallVec<[(usize, FlexParentData); 8]> = SmallVec::new();
346
347 for (idx, measurable) in measurables.iter().enumerate() {
348 let parent_data = measurable.flex_parent_data().unwrap_or_default();
349 if parent_data.has_weight() {
350 weighted_children.push((idx, parent_data));
351 } else {
352 fixed_children.push(idx);
353 }
354 }
355
356 let child_constraints = self.make_constraints(0.0, max_main, 0.0, max_cross);
359
360 let mut placeables: SmallVec<[Option<cranpose_ui_layout::Placeable>; 8]> = SmallVec::new();
361 placeables.resize_with(measurables.len(), || None);
362 let mut fixed_main_size = 0.0_f32;
363 let mut max_cross_size = 0.0_f32;
364
365 for &idx in &fixed_children {
366 let measurable = &measurables[idx];
367 let placeable = measurable.measure(child_constraints);
368 let main_size = self.get_main_axis_size(placeable.width(), placeable.height());
369 let cross_size = self.get_cross_axis_size(placeable.width(), placeable.height());
370
371 fixed_main_size += main_size;
372 max_cross_size = max_cross_size.max(cross_size);
373 placeables[idx] = Some(placeable);
374 }
375
376 let num_children = measurables.len();
378 let total_spacing = if num_children > 1 {
379 spacing * (num_children - 1) as f32
380 } else {
381 0.0
382 };
383
384 if !weighted_children.is_empty() {
386 if main_axis_bounded {
387 let used_main = fixed_main_size + total_spacing;
389 let remaining_main = (max_main - used_main).max(0.0);
390
391 let total_weight: f32 = weighted_children.iter().map(|(_, data)| data.weight).sum();
393
394 for &(idx, parent_data) in &weighted_children {
396 let measurable = &measurables[idx];
397 let allocated = if total_weight > 0.0 {
398 remaining_main * (parent_data.weight / total_weight)
399 } else {
400 0.0
401 };
402
403 let weighted_constraints = if parent_data.fill {
404 self.make_constraints(allocated, allocated, 0.0, max_cross)
406 } else {
407 self.make_constraints(0.0, allocated, 0.0, max_cross)
409 };
410
411 let placeable = measurable.measure(weighted_constraints);
412 let cross_size =
413 self.get_cross_axis_size(placeable.width(), placeable.height());
414 max_cross_size = max_cross_size.max(cross_size);
415 placeables[idx] = Some(placeable);
416 }
417 } else {
418 for &(idx, _) in &weighted_children {
420 let measurable = &measurables[idx];
421 let placeable = measurable.measure(child_constraints);
422 let cross_size =
423 self.get_cross_axis_size(placeable.width(), placeable.height());
424 max_cross_size = max_cross_size.max(cross_size);
425 placeables[idx] = Some(placeable);
426 }
427 }
428 }
429
430 let placeables: SmallVec<[cranpose_ui_layout::Placeable; 8]> = placeables
431 .into_iter()
432 .enumerate()
433 .map(|(idx, placeable)| {
434 placeable.unwrap_or_else(|| measurables[idx].measure(child_constraints))
435 })
436 .collect();
437
438 let total_main: f32 = placeables
440 .iter()
441 .map(|p| self.get_main_axis_size(p.width(), p.height()))
442 .sum::<f32>()
443 + total_spacing;
444
445 let container_main = total_main.clamp(min_main, max_main);
447 let container_cross = max_cross_size.clamp(min_cross, max_cross);
448
449 let child_main_sizes: SmallVec<[f32; 8]> = placeables
451 .iter()
452 .map(|p| self.get_main_axis_size(p.width(), p.height()))
453 .collect();
454
455 let mut main_positions: SmallVec<[f32; 8]> =
456 SmallVec::with_capacity(child_main_sizes.len());
457 main_positions.resize(child_main_sizes.len(), 0.0);
458
459 let arrangement = if total_main > container_main {
461 LinearArrangement::Start
462 } else {
463 self.main_axis_arrangement
464 };
465 arrangement.arrange(container_main, &child_main_sizes, &mut main_positions);
466
467 placements.reserve(placeables.len());
469 for (placeable, main_pos) in placeables.into_iter().zip(main_positions) {
470 let child_cross = self.get_cross_axis_size(placeable.width(), placeable.height());
471 let cross_pos = self
472 .cross_axis_alignment
473 .align(container_cross, child_cross);
474
475 let (x, y) = match self.axis {
476 Axis::Horizontal => (main_pos, cross_pos),
477 Axis::Vertical => (cross_pos, main_pos),
478 };
479
480 placeable.place(x, y);
481 placements.push(Placement::new(placeable.node_id(), x, y, 0));
482 }
483
484 let (width, height) = match self.axis {
486 Axis::Horizontal => (container_main, container_cross),
487 Axis::Vertical => (container_cross, container_main),
488 };
489
490 crate::modifier::Size { width, height }
491 }
492
493 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
494 let spacing = self.get_spacing();
495 let total_spacing = if measurables.len() > 1 {
496 spacing * (measurables.len() - 1) as f32
497 } else {
498 0.0
499 };
500
501 match self.axis {
502 Axis::Horizontal => {
503 measurables
505 .iter()
506 .map(|m| m.min_intrinsic_width(height))
507 .sum::<f32>()
508 + total_spacing
509 }
510 Axis::Vertical => {
511 measurables
513 .iter()
514 .map(|m| m.min_intrinsic_width(height))
515 .fold(0.0, f32::max)
516 }
517 }
518 }
519
520 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
521 let spacing = self.get_spacing();
522 let total_spacing = if measurables.len() > 1 {
523 spacing * (measurables.len() - 1) as f32
524 } else {
525 0.0
526 };
527
528 match self.axis {
529 Axis::Horizontal => {
530 measurables
532 .iter()
533 .map(|m| m.max_intrinsic_width(height))
534 .sum::<f32>()
535 + total_spacing
536 }
537 Axis::Vertical => {
538 measurables
540 .iter()
541 .map(|m| m.max_intrinsic_width(height))
542 .fold(0.0, f32::max)
543 }
544 }
545 }
546
547 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
548 let spacing = self.get_spacing();
549 let total_spacing = if measurables.len() > 1 {
550 spacing * (measurables.len() - 1) as f32
551 } else {
552 0.0
553 };
554
555 match self.axis {
556 Axis::Horizontal => {
557 measurables
559 .iter()
560 .map(|m| m.min_intrinsic_height(width))
561 .fold(0.0, f32::max)
562 }
563 Axis::Vertical => {
564 measurables
566 .iter()
567 .map(|m| m.min_intrinsic_height(width))
568 .sum::<f32>()
569 + total_spacing
570 }
571 }
572 }
573
574 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
575 let spacing = self.get_spacing();
576 let total_spacing = if measurables.len() > 1 {
577 spacing * (measurables.len() - 1) as f32
578 } else {
579 0.0
580 };
581
582 match self.axis {
583 Axis::Horizontal => {
584 measurables
586 .iter()
587 .map(|m| m.max_intrinsic_height(width))
588 .fold(0.0, f32::max)
589 }
590 Axis::Vertical => {
591 measurables
593 .iter()
594 .map(|m| m.max_intrinsic_height(width))
595 .sum::<f32>()
596 + total_spacing
597 }
598 }
599 }
600}
601
602#[derive(Clone, Debug, PartialEq)]
605pub struct LeafMeasurePolicy {
606 pub intrinsic_size: crate::modifier::Size,
607}
608
609impl LeafMeasurePolicy {
610 pub fn new(intrinsic_size: crate::modifier::Size) -> Self {
611 Self { intrinsic_size }
612 }
613}
614
615impl MeasurePolicy for LeafMeasurePolicy {
616 fn measure(
617 &self,
618 _measurables: &[Box<dyn Measurable>],
619 constraints: Constraints,
620 ) -> MeasureResult {
621 let mut placements = Vec::new();
622 let size = self.measure_into(&[], constraints, &mut placements);
623 MeasureResult::new(size, placements)
624 }
625
626 fn measure_into(
627 &self,
628 _measurables: &[Box<dyn Measurable>],
629 constraints: Constraints,
630 placements: &mut Vec<Placement>,
631 ) -> crate::modifier::Size {
632 placements.clear();
633 let (width, height) =
635 constraints.constrain(self.intrinsic_size.width, self.intrinsic_size.height);
636
637 crate::modifier::Size { width, height }
638 }
639
640 fn min_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
641 self.intrinsic_size.width
642 }
643
644 fn max_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
645 self.intrinsic_size.width
646 }
647
648 fn min_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
649 self.intrinsic_size.height
650 }
651
652 fn max_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
653 self.intrinsic_size.height
654 }
655}
656
657#[derive(Clone, Debug, PartialEq)]
663pub struct EmptyMeasurePolicy;
664
665impl EmptyMeasurePolicy {
666 pub fn new() -> Self {
667 Self
668 }
669}
670
671impl Default for EmptyMeasurePolicy {
672 fn default() -> Self {
673 Self::new()
674 }
675}
676
677impl MeasurePolicy for EmptyMeasurePolicy {
678 fn measure(
679 &self,
680 _measurables: &[Box<dyn Measurable>],
681 constraints: Constraints,
682 ) -> MeasureResult {
683 let mut placements = Vec::new();
684 let size = self.measure_into(&[], constraints, &mut placements);
685 MeasureResult::new(size, placements)
686 }
687
688 fn measure_into(
689 &self,
690 _measurables: &[Box<dyn Measurable>],
691 constraints: Constraints,
692 placements: &mut Vec<Placement>,
693 ) -> crate::modifier::Size {
694 placements.clear();
695 let (width, height) = constraints.constrain(0.0, 0.0);
698
699 crate::modifier::Size { width, height }
700 }
701
702 fn min_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
703 0.0
704 }
705
706 fn max_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
707 0.0
708 }
709
710 fn min_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
711 0.0
712 }
713
714 fn max_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
715 0.0
716 }
717}
718
719#[cfg(test)]
720#[path = "tests/policies_tests.rs"]
721mod tests;