iced_core/layout/
limits.rs1#![allow(clippy::manual_clamp)]
2use crate::length;
3use crate::{Length, Size};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Limits {
8 pub min: Size,
10 pub max: Size,
12 pub compression: Size<bool>,
14 pub infinite: Size<bool>,
17}
18
19impl Limits {
20 pub const fn new(min: Size, max: Size) -> Limits {
22 Limits::with_flags(min, max, Size::new(false, false), Size::new(false, false))
23 }
24
25 pub const fn with_flags(
29 min: Size,
30 max: Size,
31 compression: Size<bool>,
32 infinite: Size<bool>,
33 ) -> Self {
34 Limits {
35 min,
36 max,
37 compression,
38 infinite,
39 }
40 }
41
42 pub fn bounds(&self) -> Size {
48 Size::new(
49 if self.infinite.width {
50 f32::INFINITY
51 } else {
52 self.max.width
53 },
54 if self.infinite.height {
55 f32::INFINITY
56 } else {
57 self.max.height
58 },
59 )
60 }
61
62 pub fn width(mut self, width: impl Into<Length>) -> Limits {
64 match width.into() {
65 Length::Shrink => {
66 self.compression.width = true;
67 }
68 Length::Fit | Length::Fluid(_) => {
69 self.compression.width = false;
70 }
71 Length::Fixed(amount) => {
72 let new_width = if self.infinite.width {
73 amount
74 } else {
75 amount.min(self.max.width)
76 }
77 .max(self.min.width);
78
79 self.min.width = new_width;
80 self.max.width = new_width;
81 self.compression.width = false;
82 self.infinite.width = false;
83 }
84 Length::Bounded { bounds, sizing } => {
85 match bounds {
86 length::Bounds::Min(min) => {
87 self.min.width = if self.infinite.width {
88 min
89 } else {
90 min.min(self.max.width)
91 };
92 }
93 length::Bounds::Max(max) => {
94 self.max.width = if self.infinite.width {
95 max
96 } else {
97 max.min(self.max.width)
98 }
99 .max(self.min.width);
100
101 self.infinite.width = false;
102 }
103 length::Bounds::Both { min, max } => {
104 self.min.width = min.min(self.max.width).max(self.min.width);
105 self.max.width = max.min(self.max.width).max(self.min.width);
106 }
107 }
108
109 match sizing {
110 length::Sizing::Shrink => {
111 self.compression.width = true;
112 }
113 length::Sizing::Fit => {
114 self.compression.width = false;
115 }
116 length::Sizing::Fill(_) => {}
117 }
118 }
119 Length::Fill | Length::FillPortion(_) => {}
120 }
121
122 self
123 }
124
125 pub fn height(mut self, height: impl Into<Length>) -> Limits {
127 match height.into() {
128 Length::Shrink => {
129 self.compression.height = true;
130 }
131 Length::Fit | Length::Fluid(_) => {
132 self.compression.height = false;
133 }
134 Length::Fixed(amount) => {
135 let new_height = if self.infinite.height {
136 amount
137 } else {
138 amount.min(self.max.height)
139 }
140 .max(self.min.height);
141
142 self.min.height = new_height;
143 self.max.height = new_height;
144 self.compression.height = false;
145 self.infinite.height = false;
146 }
147 Length::Bounded { bounds, sizing } => {
148 match bounds {
149 length::Bounds::Min(min) => {
150 self.min.height = if self.infinite.height {
151 min
152 } else {
153 min.min(self.max.height)
154 };
155 }
156 length::Bounds::Max(max) => {
157 self.max.height = if self.infinite.height {
158 max
159 } else {
160 max.min(self.max.height)
161 }
162 .max(self.min.height);
163
164 self.infinite.height = false;
165 }
166 length::Bounds::Both { min, max } => {
167 self.min.height = min.min(self.max.height).max(self.min.height);
168 self.max.height = max.min(self.max.height).max(self.min.height);
169 }
170 }
171
172 match sizing {
173 length::Sizing::Shrink => {
174 self.compression.height = true;
175 }
176 length::Sizing::Fit => {
177 self.compression.height = false;
178 }
179 length::Sizing::Fill(_) => {}
180 }
181 }
182 Length::Fill | Length::FillPortion(_) => {}
183 }
184
185 self
186 }
187
188 pub fn shrink(&self, size: impl Into<Size>) -> Limits {
190 let size = size.into();
191
192 let min = Size::new(
193 (self.min.width - size.width).max(0.0),
194 (self.min.height - size.height).max(0.0),
195 );
196
197 let max = Size::new(
198 (self.max.width - size.width).max(0.0),
199 (self.max.height - size.height).max(0.0),
200 );
201
202 Limits {
203 min,
204 max,
205 compression: self.compression,
206 infinite: self.infinite,
207 }
208 }
209
210 pub fn loose(&self) -> Limits {
212 Limits {
213 min: Size::ZERO,
214 max: self.max,
215 compression: self.compression,
216 infinite: self.infinite,
217 }
218 }
219
220 pub fn resolve(
224 &self,
225 width: impl Into<Length>,
226 height: impl Into<Length>,
227 intrinsic_size: Size,
228 ) -> Size {
229 Size::new(
230 self.resolve_width(width, intrinsic_size.width),
231 self.resolve_height(height, intrinsic_size.height),
232 )
233 }
234
235 pub fn resolve_width(&self, width: impl Into<Length>, intrinsic_width: f32) -> f32 {
237 resolve(
238 self.min.width,
239 self.max.width,
240 self.compression.width,
241 self.infinite.width,
242 width.into(),
243 intrinsic_width,
244 )
245 }
246
247 pub fn resolve_height(&self, height: impl Into<Length>, intrinsic_height: f32) -> f32 {
249 resolve(
250 self.min.height,
251 self.max.height,
252 self.compression.height,
253 self.infinite.height,
254 height.into(),
255 intrinsic_height,
256 )
257 }
258}
259
260fn resolve(
261 min: f32,
262 max: f32,
263 compression: bool,
264 infinite: bool,
265 length: Length,
266 intrinsic: f32,
267) -> f32 {
268 match length {
269 Length::Fill
270 | Length::FillPortion(_)
271 | Length::Bounded {
272 sizing: length::Sizing::Fill(_),
273 ..
274 } if !compression => if infinite { max.max(intrinsic) } else { max }.max(min),
275 Length::Fixed(amount) => if infinite { amount } else { amount.min(max) }.max(min),
276 _ => if infinite {
277 intrinsic
278 } else {
279 intrinsic.min(max)
280 }
281 .max(min),
282 }
283}