iced_core/layout/
limits.rs

1#![allow(clippy::manual_clamp)]
2use crate::{Length, Size};
3
4/// A set of size constraints for layouting.
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct Limits {
7    min: Size,
8    max: Size,
9    compression: Size<bool>,
10}
11
12impl Limits {
13    /// No limits
14    pub const NONE: Limits = Limits {
15        min: Size::ZERO,
16        max: Size::INFINITE,
17        compression: Size::new(false, false),
18    };
19
20    /// Creates new [`Limits`] with the given minimum and maximum [`Size`].
21    pub const fn new(min: Size, max: Size) -> Limits {
22        Limits::with_compression(min, max, Size::new(false, false))
23    }
24
25    /// Creates new [`Limits`] with the given minimun and maximum [`Size`], and
26    /// whether fluid lengths should be compressed to intrinsic dimensions.
27    pub const fn with_compression(
28        min: Size,
29        max: Size,
30        compress: Size<bool>,
31    ) -> Self {
32        Limits {
33            min,
34            max,
35            compression: compress,
36        }
37    }
38
39    /// Returns the minimum [`Size`] of the [`Limits`].
40    pub fn min(&self) -> Size {
41        self.min
42    }
43
44    /// Returns the maximum [`Size`] of the [`Limits`].
45    pub fn max(&self) -> Size {
46        self.max
47    }
48
49    /// Returns the compression of the [`Limits`].
50    pub fn compression(&self) -> Size<bool> {
51        self.compression
52    }
53
54    /// Applies a width constraint to the current [`Limits`].
55    pub fn width(mut self, width: impl Into<Length>) -> Limits {
56        match width.into() {
57            Length::Shrink => {
58                self.compression.width = true;
59            }
60            Length::Fixed(amount) => {
61                let new_width = amount.min(self.max.width).max(self.min.width);
62
63                self.min.width = new_width;
64                self.max.width = new_width;
65                self.compression.width = false;
66            }
67            Length::Fill | Length::FillPortion(_) => {}
68        }
69
70        self
71    }
72
73    /// Applies a height constraint to the current [`Limits`].
74    pub fn height(mut self, height: impl Into<Length>) -> Limits {
75        match height.into() {
76            Length::Shrink => {
77                self.compression.height = true;
78            }
79            Length::Fixed(amount) => {
80                let new_height =
81                    amount.min(self.max.height).max(self.min.height);
82
83                self.min.height = new_height;
84                self.max.height = new_height;
85                self.compression.height = false;
86            }
87            Length::Fill | Length::FillPortion(_) => {}
88        }
89
90        self
91    }
92
93    /// Applies a minimum width constraint to the current [`Limits`].
94    pub fn min_width(mut self, min_width: f32) -> Limits {
95        self.min.width = self.min.width.max(min_width).min(self.max.width);
96
97        self
98    }
99
100    /// Applies a maximum width constraint to the current [`Limits`].
101    pub fn max_width(mut self, max_width: f32) -> Limits {
102        self.max.width = self.max.width.min(max_width).max(self.min.width);
103
104        self
105    }
106
107    /// Applies a minimum height constraint to the current [`Limits`].
108    pub fn min_height(mut self, min_height: f32) -> Limits {
109        self.min.height = self.min.height.max(min_height).min(self.max.height);
110
111        self
112    }
113
114    /// Applies a maximum height constraint to the current [`Limits`].
115    pub fn max_height(mut self, max_height: f32) -> Limits {
116        self.max.height = self.max.height.min(max_height).max(self.min.height);
117
118        self
119    }
120
121    /// Shrinks the current [`Limits`] by the given [`Size`].
122    pub fn shrink(&self, size: impl Into<Size>) -> Limits {
123        let size = size.into();
124
125        let min = Size::new(
126            (self.min().width - size.width).max(0.0),
127            (self.min().height - size.height).max(0.0),
128        );
129
130        let max = Size::new(
131            (self.max().width - size.width).max(0.0),
132            (self.max().height - size.height).max(0.0),
133        );
134
135        Limits {
136            min,
137            max,
138            compression: self.compression,
139        }
140    }
141
142    /// Removes the minimum width constraint for the current [`Limits`].
143    pub fn loose(&self) -> Limits {
144        Limits {
145            min: Size::ZERO,
146            max: self.max,
147            compression: self.compression,
148        }
149    }
150
151    /// Computes the resulting [`Size`] that fits the [`Limits`] given
152    /// some width and height requirements and the intrinsic size of
153    /// some content.
154    pub fn resolve(
155        &self,
156        width: impl Into<Length>,
157        height: impl Into<Length>,
158        intrinsic_size: Size,
159    ) -> Size {
160        let width = match width.into() {
161            Length::Fill | Length::FillPortion(_)
162                if !self.compression.width =>
163            {
164                self.max.width
165            }
166            Length::Fixed(amount) => {
167                amount.min(self.max.width).max(self.min.width)
168            }
169            _ => intrinsic_size.width.min(self.max.width).max(self.min.width),
170        };
171
172        let height = match height.into() {
173            Length::Fill | Length::FillPortion(_)
174                if !self.compression.height =>
175            {
176                self.max.height
177            }
178            Length::Fixed(amount) => {
179                amount.min(self.max.height).max(self.min.height)
180            }
181            _ => intrinsic_size
182                .height
183                .min(self.max.height)
184                .max(self.min.height),
185        };
186
187        Size::new(width, height)
188    }
189}