Skip to main content

cranpose_ui/layout/
policies.rs

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/// MeasurePolicy for Box layout - overlays children according to alignment.
10#[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// Row and Column use FlexMeasurePolicy with axis-specific configuration.
122
123/// Unified Flex layout policy that powers both Row and Column.
124///
125/// This policy implements Jetpack Compose's flex layout semantics:
126/// - Measures children with proper loose constraints (min = 0 on both axes)
127/// - Supports weighted distribution of remaining space
128/// - Handles bounded/unbounded main axis correctly
129/// - Implements correct intrinsics for both axes
130///
131/// ## Overflow Behavior
132///
133/// Like Jetpack Compose, this policy **allows children to overflow** their container bounds:
134/// - Children can be positioned outside the parent's measured size
135/// - Overflowing content is rendered (unless clipped by a modifier)
136/// - When content overflows, distribution arrangements switch to `Start` to avoid negative spacing
137/// - `SpacedBy` keeps its fixed inter-child spacing even when content overflows
138///
139/// Example: A Row with 300px of content in a 200px container will:
140/// 1. Measure children at their natural sizes
141/// 2. Detect overflow (300px > 200px)
142/// 3. Switch to Start arrangement (pack children at the start)
143/// 4. Position last children beyond the 200px boundary
144///
145/// To prevent overflow:
146/// - Use weights for flexible sizing: `.weight(1.0, true)`
147/// - Use `fillMaxWidth()`/`fillMaxHeight()` modifiers
148/// - Design UI to fit within available space
149/// - Add a clip modifier to hide overflowing content
150///
151/// ## Weighted Children
152///
153/// When the main axis is bounded and children have weights:
154/// 1. Fixed children (no weight) are measured first
155/// 2. Remaining space is distributed proportionally to weights
156/// 3. Each weighted child gets: `remaining * (weight / total_weight)`
157/// 4. If `fill=true`, child gets tight constraints; if `fill=false`, loose constraints
158///
159/// When the main axis is unbounded, weights are ignored (all children wrap content).
160#[derive(Clone, Debug, PartialEq)]
161pub struct FlexMeasurePolicy {
162    /// Main axis direction (Horizontal for Row, Vertical for Column)
163    pub axis: Axis,
164    /// Arrangement along the main axis
165    pub main_axis_arrangement: LinearArrangement,
166    /// Alignment along the cross axis (used as default for children without explicit alignment)
167    pub cross_axis_alignment: CrossAxisAlignment,
168}
169
170/// Cross-axis alignment for flex layouts.
171/// This is axis-agnostic and gets interpreted based on the flex axis.
172#[derive(Clone, Copy, Debug, PartialEq)]
173pub enum CrossAxisAlignment {
174    /// Align to the start of the cross axis (Top for Row, Start for Column)
175    Start,
176    /// Align to the center of the cross axis
177    Center,
178    /// Align to the end of the cross axis (Bottom for Row, End for Column)
179    End,
180}
181
182impl CrossAxisAlignment {
183    /// Calculate the offset for positioning a child on the cross axis.
184    fn align(&self, available: f32, child: f32) -> f32 {
185        match self {
186            CrossAxisAlignment::Start => 0.0,
187            CrossAxisAlignment::Center => ((available - child) / 2.0).max(0.0),
188            CrossAxisAlignment::End => (available - child).max(0.0),
189        }
190    }
191}
192
193impl From<HorizontalAlignment> for CrossAxisAlignment {
194    fn from(alignment: HorizontalAlignment) -> Self {
195        match alignment {
196            HorizontalAlignment::Start => CrossAxisAlignment::Start,
197            HorizontalAlignment::CenterHorizontally => CrossAxisAlignment::Center,
198            HorizontalAlignment::End => CrossAxisAlignment::End,
199        }
200    }
201}
202
203impl From<VerticalAlignment> for CrossAxisAlignment {
204    fn from(alignment: VerticalAlignment) -> Self {
205        match alignment {
206            VerticalAlignment::Top => CrossAxisAlignment::Start,
207            VerticalAlignment::CenterVertically => CrossAxisAlignment::Center,
208            VerticalAlignment::Bottom => CrossAxisAlignment::End,
209        }
210    }
211}
212
213impl FlexMeasurePolicy {
214    pub fn new(
215        axis: Axis,
216        main_axis_arrangement: LinearArrangement,
217        cross_axis_alignment: CrossAxisAlignment,
218    ) -> Self {
219        Self {
220            axis,
221            main_axis_arrangement,
222            cross_axis_alignment,
223        }
224    }
225
226    /// Creates a FlexMeasurePolicy for Row (horizontal main axis).
227    pub fn row(
228        horizontal_arrangement: LinearArrangement,
229        vertical_alignment: VerticalAlignment,
230    ) -> Self {
231        Self::new(
232            Axis::Horizontal,
233            horizontal_arrangement,
234            vertical_alignment.into(),
235        )
236    }
237
238    /// Creates a FlexMeasurePolicy for Column (vertical main axis).
239    pub fn column(
240        vertical_arrangement: LinearArrangement,
241        horizontal_alignment: HorizontalAlignment,
242    ) -> Self {
243        Self::new(
244            Axis::Vertical,
245            vertical_arrangement,
246            horizontal_alignment.into(),
247        )
248    }
249
250    /// Extract main and cross axis values from constraints.
251    fn get_axis_constraints(&self, constraints: Constraints) -> (f32, f32, f32, f32) {
252        match self.axis {
253            Axis::Horizontal => (
254                constraints.min_width,
255                constraints.max_width,
256                constraints.min_height,
257                constraints.max_height,
258            ),
259            Axis::Vertical => (
260                constraints.min_height,
261                constraints.max_height,
262                constraints.min_width,
263                constraints.max_width,
264            ),
265        }
266    }
267
268    /// Create constraints from main and cross axis values.
269    fn make_constraints(
270        &self,
271        min_main: f32,
272        max_main: f32,
273        min_cross: f32,
274        max_cross: f32,
275    ) -> Constraints {
276        match self.axis {
277            Axis::Horizontal => Constraints {
278                min_width: min_main,
279                max_width: max_main,
280                min_height: min_cross,
281                max_height: max_cross,
282            },
283            Axis::Vertical => Constraints {
284                min_width: min_cross,
285                max_width: max_cross,
286                min_height: min_main,
287                max_height: max_main,
288            },
289        }
290    }
291
292    /// Get the main axis size from width/height.
293    fn get_main_axis_size(&self, width: f32, height: f32) -> f32 {
294        match self.axis {
295            Axis::Horizontal => width,
296            Axis::Vertical => height,
297        }
298    }
299
300    /// Get the cross axis size from width/height.
301    fn get_cross_axis_size(&self, width: f32, height: f32) -> f32 {
302        match self.axis {
303            Axis::Horizontal => height,
304            Axis::Vertical => width,
305        }
306    }
307
308    /// Calculate spacing between children based on arrangement.
309    fn get_spacing(&self) -> f32 {
310        match self.main_axis_arrangement {
311            LinearArrangement::SpacedBy(value) => value.max(0.0),
312            _ => 0.0,
313        }
314    }
315}
316
317impl MeasurePolicy for FlexMeasurePolicy {
318    fn measure(
319        &self,
320        measurables: &[Box<dyn Measurable>],
321        constraints: Constraints,
322    ) -> MeasureResult {
323        let mut placements = Vec::new();
324        let size = self.measure_into(measurables, constraints, &mut placements);
325        MeasureResult::new(size, placements)
326    }
327
328    fn measure_into(
329        &self,
330        measurables: &[Box<dyn Measurable>],
331        constraints: Constraints,
332        placements: &mut Vec<Placement>,
333    ) -> crate::modifier::Size {
334        placements.clear();
335        if measurables.is_empty() {
336            let (width, height) = constraints.constrain(0.0, 0.0);
337            return crate::modifier::Size { width, height };
338        }
339
340        let (min_main, max_main, min_cross, max_cross) = self.get_axis_constraints(constraints);
341        let main_axis_bounded = max_main.is_finite();
342        let spacing = self.get_spacing();
343
344        // Separate children into fixed and weighted
345        let mut fixed_children: SmallVec<[usize; 8]> = SmallVec::new();
346        let mut weighted_children: SmallVec<[(usize, FlexParentData); 8]> = SmallVec::new();
347
348        for (idx, measurable) in measurables.iter().enumerate() {
349            let parent_data = measurable.flex_parent_data().unwrap_or_default();
350            if parent_data.has_weight() {
351                weighted_children.push((idx, parent_data));
352            } else {
353                fixed_children.push(idx);
354            }
355        }
356
357        // Measure fixed children first
358        // Children get loose constraints on both axes (min = 0)
359        let child_constraints = self.make_constraints(0.0, max_main, 0.0, max_cross);
360
361        let mut placeables: SmallVec<[Option<cranpose_ui_layout::Placeable>; 8]> = SmallVec::new();
362        placeables.resize_with(measurables.len(), || None);
363        let mut fixed_main_size = 0.0_f32;
364        let mut max_cross_size = 0.0_f32;
365
366        for &idx in &fixed_children {
367            let measurable = &measurables[idx];
368            let placeable = measurable.measure(child_constraints);
369            let main_size = self.get_main_axis_size(placeable.width(), placeable.height());
370            let cross_size = self.get_cross_axis_size(placeable.width(), placeable.height());
371
372            fixed_main_size += main_size;
373            max_cross_size = max_cross_size.max(cross_size);
374            placeables[idx] = Some(placeable);
375        }
376
377        // Calculate spacing
378        let num_children = measurables.len();
379        let total_spacing = if num_children > 1 {
380            spacing * (num_children - 1) as f32
381        } else {
382            0.0
383        };
384
385        // Measure weighted children
386        if !weighted_children.is_empty() {
387            if main_axis_bounded {
388                // Calculate remaining space for weighted children
389                let used_main = fixed_main_size + total_spacing;
390                let remaining_main = (max_main - used_main).max(0.0);
391
392                // Calculate total weight
393                let total_weight: f32 = weighted_children.iter().map(|(_, data)| data.weight).sum();
394
395                // Measure each weighted child with its allocated space
396                for &(idx, parent_data) in &weighted_children {
397                    let measurable = &measurables[idx];
398                    let allocated = if total_weight > 0.0 {
399                        remaining_main * (parent_data.weight / total_weight)
400                    } else {
401                        0.0
402                    };
403
404                    let weighted_constraints = if parent_data.fill {
405                        // fill=true: child gets tight constraints on main axis
406                        self.make_constraints(allocated, allocated, 0.0, max_cross)
407                    } else {
408                        // fill=false: child gets loose constraints on main axis
409                        self.make_constraints(0.0, allocated, 0.0, max_cross)
410                    };
411
412                    let placeable = measurable.measure(weighted_constraints);
413                    let cross_size =
414                        self.get_cross_axis_size(placeable.width(), placeable.height());
415                    max_cross_size = max_cross_size.max(cross_size);
416                    placeables[idx] = Some(placeable);
417                }
418            } else {
419                // Main axis unbounded: ignore weights, measure like fixed children
420                for &(idx, _) in &weighted_children {
421                    let measurable = &measurables[idx];
422                    let placeable = measurable.measure(child_constraints);
423                    let cross_size =
424                        self.get_cross_axis_size(placeable.width(), placeable.height());
425                    max_cross_size = max_cross_size.max(cross_size);
426                    placeables[idx] = Some(placeable);
427                }
428            }
429        }
430
431        let placeables: SmallVec<[cranpose_ui_layout::Placeable; 8]> = placeables
432            .into_iter()
433            .enumerate()
434            .map(|(idx, placeable)| {
435                placeable.unwrap_or_else(|| measurables[idx].measure(child_constraints))
436            })
437            .collect();
438
439        // Calculate total main size
440        let total_main: f32 = placeables
441            .iter()
442            .map(|p| self.get_main_axis_size(p.width(), p.height()))
443            .sum::<f32>()
444            + total_spacing;
445
446        // Container size
447        let container_main = total_main.clamp(min_main, max_main);
448        let container_cross = max_cross_size.clamp(min_cross, max_cross);
449
450        // Arrange children along main axis
451        let child_main_sizes: SmallVec<[f32; 8]> = placeables
452            .iter()
453            .map(|p| self.get_main_axis_size(p.width(), p.height()))
454            .collect();
455
456        let mut main_positions: SmallVec<[f32; 8]> =
457            SmallVec::with_capacity(child_main_sizes.len());
458        main_positions.resize(child_main_sizes.len(), 0.0);
459
460        // If distribution arrangements overflow, use Start arrangement to avoid negative spacing.
461        // Fixed SpacedBy gaps stay valid under overflow and must remain part of layout.
462        let arrangement = if total_main > container_main
463            && !matches!(self.main_axis_arrangement, LinearArrangement::SpacedBy(_))
464        {
465            LinearArrangement::Start
466        } else {
467            self.main_axis_arrangement
468        };
469        arrangement.arrange(container_main, &child_main_sizes, &mut main_positions);
470
471        // Place children
472        placements.reserve(placeables.len());
473        for (placeable, main_pos) in placeables.into_iter().zip(main_positions) {
474            let child_cross = self.get_cross_axis_size(placeable.width(), placeable.height());
475            let cross_pos = self
476                .cross_axis_alignment
477                .align(container_cross, child_cross);
478
479            let (x, y) = match self.axis {
480                Axis::Horizontal => (main_pos, cross_pos),
481                Axis::Vertical => (cross_pos, main_pos),
482            };
483
484            placeable.place(x, y);
485            placements.push(Placement::new(placeable.node_id(), x, y, 0));
486        }
487
488        // Create final size
489        let (width, height) = match self.axis {
490            Axis::Horizontal => (container_main, container_cross),
491            Axis::Vertical => (container_cross, container_main),
492        };
493
494        crate::modifier::Size { width, height }
495    }
496
497    fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
498        let spacing = self.get_spacing();
499        let total_spacing = if measurables.len() > 1 {
500            spacing * (measurables.len() - 1) as f32
501        } else {
502            0.0
503        };
504
505        match self.axis {
506            Axis::Horizontal => {
507                // Row: sum of children's min intrinsic widths + spacing
508                measurables
509                    .iter()
510                    .map(|m| m.min_intrinsic_width(height))
511                    .sum::<f32>()
512                    + total_spacing
513            }
514            Axis::Vertical => {
515                // Column: max of children's min intrinsic widths
516                measurables
517                    .iter()
518                    .map(|m| m.min_intrinsic_width(height))
519                    .fold(0.0, f32::max)
520            }
521        }
522    }
523
524    fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32 {
525        let spacing = self.get_spacing();
526        let total_spacing = if measurables.len() > 1 {
527            spacing * (measurables.len() - 1) as f32
528        } else {
529            0.0
530        };
531
532        match self.axis {
533            Axis::Horizontal => {
534                // Row: sum of children's max intrinsic widths + spacing
535                measurables
536                    .iter()
537                    .map(|m| m.max_intrinsic_width(height))
538                    .sum::<f32>()
539                    + total_spacing
540            }
541            Axis::Vertical => {
542                // Column: max of children's max intrinsic widths
543                measurables
544                    .iter()
545                    .map(|m| m.max_intrinsic_width(height))
546                    .fold(0.0, f32::max)
547            }
548        }
549    }
550
551    fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
552        let spacing = self.get_spacing();
553        let total_spacing = if measurables.len() > 1 {
554            spacing * (measurables.len() - 1) as f32
555        } else {
556            0.0
557        };
558
559        match self.axis {
560            Axis::Horizontal => {
561                // Row: max of children's min intrinsic heights
562                measurables
563                    .iter()
564                    .map(|m| m.min_intrinsic_height(width))
565                    .fold(0.0, f32::max)
566            }
567            Axis::Vertical => {
568                // Column: sum of children's min intrinsic heights + spacing
569                measurables
570                    .iter()
571                    .map(|m| m.min_intrinsic_height(width))
572                    .sum::<f32>()
573                    + total_spacing
574            }
575        }
576    }
577
578    fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32 {
579        let spacing = self.get_spacing();
580        let total_spacing = if measurables.len() > 1 {
581            spacing * (measurables.len() - 1) as f32
582        } else {
583            0.0
584        };
585
586        match self.axis {
587            Axis::Horizontal => {
588                // Row: max of children's max intrinsic heights
589                measurables
590                    .iter()
591                    .map(|m| m.max_intrinsic_height(width))
592                    .fold(0.0, f32::max)
593            }
594            Axis::Vertical => {
595                // Column: sum of children's max intrinsic heights + spacing
596                measurables
597                    .iter()
598                    .map(|m| m.max_intrinsic_height(width))
599                    .sum::<f32>()
600                    + total_spacing
601            }
602        }
603    }
604}
605
606/// MeasurePolicy for leaf nodes with fixed intrinsic size (like Spacer).
607/// This policy respects the provided constraints but has a preferred intrinsic size.
608#[derive(Clone, Debug, PartialEq)]
609pub struct LeafMeasurePolicy {
610    pub intrinsic_size: crate::modifier::Size,
611}
612
613impl LeafMeasurePolicy {
614    pub fn new(intrinsic_size: crate::modifier::Size) -> Self {
615        Self { intrinsic_size }
616    }
617}
618
619impl MeasurePolicy for LeafMeasurePolicy {
620    fn measure(
621        &self,
622        _measurables: &[Box<dyn Measurable>],
623        constraints: Constraints,
624    ) -> MeasureResult {
625        let mut placements = Vec::new();
626        let size = self.measure_into(&[], constraints, &mut placements);
627        MeasureResult::new(size, placements)
628    }
629
630    fn measure_into(
631        &self,
632        _measurables: &[Box<dyn Measurable>],
633        constraints: Constraints,
634        placements: &mut Vec<Placement>,
635    ) -> crate::modifier::Size {
636        placements.clear();
637        // Use intrinsic size but constrain to provided constraints
638        let (width, height) =
639            constraints.constrain(self.intrinsic_size.width, self.intrinsic_size.height);
640
641        crate::modifier::Size { width, height }
642    }
643
644    fn min_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
645        self.intrinsic_size.width
646    }
647
648    fn max_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
649        self.intrinsic_size.width
650    }
651
652    fn min_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
653        self.intrinsic_size.height
654    }
655
656    fn max_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
657        self.intrinsic_size.height
658    }
659}
660
661/// EmptyMeasurePolicy that delegates all measurement to modifier nodes.
662///
663/// This is used when a Layout has no child layout logic - all measurement
664/// is handled by modifier nodes (e.g., TextModifierNode for Text widgets).
665/// Matches Jetpack Compose's EmptyMeasurePolicy pattern used in BasicText.
666#[derive(Clone, Debug, PartialEq)]
667pub struct EmptyMeasurePolicy;
668
669impl EmptyMeasurePolicy {
670    pub fn new() -> Self {
671        Self
672    }
673}
674
675impl Default for EmptyMeasurePolicy {
676    fn default() -> Self {
677        Self::new()
678    }
679}
680
681impl MeasurePolicy for EmptyMeasurePolicy {
682    fn measure(
683        &self,
684        _measurables: &[Box<dyn Measurable>],
685        constraints: Constraints,
686    ) -> MeasureResult {
687        let mut placements = Vec::new();
688        let size = self.measure_into(&[], constraints, &mut placements);
689        MeasureResult::new(size, placements)
690    }
691
692    fn measure_into(
693        &self,
694        _measurables: &[Box<dyn Measurable>],
695        constraints: Constraints,
696        placements: &mut Vec<Placement>,
697    ) -> crate::modifier::Size {
698        placements.clear();
699        // Empty policy returns the maximum available space
700        // The actual measurement is handled by modifier nodes in the chain
701        let (width, height) = constraints.constrain(0.0, 0.0);
702
703        crate::modifier::Size { width, height }
704    }
705
706    fn min_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
707        0.0
708    }
709
710    fn max_intrinsic_width(&self, _measurables: &[Box<dyn Measurable>], _height: f32) -> f32 {
711        0.0
712    }
713
714    fn min_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
715        0.0
716    }
717
718    fn max_intrinsic_height(&self, _measurables: &[Box<dyn Measurable>], _width: f32) -> f32 {
719        0.0
720    }
721}
722
723#[cfg(test)]
724#[path = "tests/policies_tests.rs"]
725mod tests;