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 }
83 Length::Bounded { bounds, sizing } => {
84 match bounds {
85 length::Bounds::Min(min) => {
86 self.min.width = min.min(self.max.width).max(self.min.width);
87 }
88 length::Bounds::Max(max) => {
89 self.max.width = if self.infinite.width {
90 max
91 } else {
92 max.min(self.max.width)
93 }
94 .max(self.min.width);
95
96 self.infinite.width = false;
97 }
98 length::Bounds::Both { min, max } => {
99 self.min.width = min.min(self.max.width).max(self.min.width);
100 self.max.width = max.min(self.max.width).max(self.min.width);
101 }
102 }
103
104 match sizing {
105 length::Sizing::Shrink => {
106 self.compression.width = true;
107 }
108 length::Sizing::Fit => {
109 self.compression.width = false;
110 }
111 length::Sizing::Fill(_) => {}
112 }
113 }
114 Length::Fill | Length::FillPortion(_) => {}
115 }
116
117 self
118 }
119
120 pub fn height(mut self, height: impl Into<Length>) -> Limits {
122 match height.into() {
123 Length::Shrink => {
124 self.compression.height = true;
125 }
126 Length::Fit | Length::Fluid(_) => {
127 self.compression.height = false;
128 }
129 Length::Fixed(amount) => {
130 let new_height = if self.infinite.height {
131 amount
132 } else {
133 amount.min(self.max.height)
134 }
135 .max(self.min.height);
136
137 self.min.height = new_height;
138 self.max.height = new_height;
139 self.compression.height = false;
140 }
141 Length::Bounded { bounds, sizing } => {
142 match bounds {
143 length::Bounds::Min(min) => {
144 self.min.height = min.min(self.max.height).max(self.min.height);
145 }
146 length::Bounds::Max(max) => {
147 self.max.height = if self.infinite.height {
148 max
149 } else {
150 max.min(self.max.height)
151 }
152 .max(self.min.height);
153
154 self.infinite.height = false;
155 }
156 length::Bounds::Both { min, max } => {
157 self.min.height = min.min(self.max.height).max(self.min.height);
158 self.max.height = max.min(self.max.height).max(self.min.height);
159 }
160 }
161
162 match sizing {
163 length::Sizing::Shrink => {
164 self.compression.height = true;
165 }
166 length::Sizing::Fit => {
167 self.compression.height = false;
168 }
169 length::Sizing::Fill(_) => {}
170 }
171 }
172 Length::Fill | Length::FillPortion(_) => {}
173 }
174
175 self
176 }
177
178 pub fn shrink(&self, size: impl Into<Size>) -> Limits {
180 let size = size.into();
181
182 let min = Size::new(
183 (self.min.width - size.width).max(0.0),
184 (self.min.height - size.height).max(0.0),
185 );
186
187 let max = Size::new(
188 (self.max.width - size.width).max(0.0),
189 (self.max.height - size.height).max(0.0),
190 );
191
192 Limits {
193 min,
194 max,
195 compression: self.compression,
196 infinite: self.infinite,
197 }
198 }
199
200 pub fn loose(&self) -> Limits {
202 Limits {
203 min: Size::ZERO,
204 max: self.max,
205 compression: self.compression,
206 infinite: self.infinite,
207 }
208 }
209
210 pub fn resolve(
214 &self,
215 width: impl Into<Length>,
216 height: impl Into<Length>,
217 intrinsic_size: Size,
218 ) -> Size {
219 Size::new(
220 self.resolve_width(width, intrinsic_size.width),
221 self.resolve_height(height, intrinsic_size.height),
222 )
223 }
224
225 pub fn resolve_width(&self, width: impl Into<Length>, intrinsic_width: f32) -> f32 {
227 resolve(
228 self.min.width,
229 self.max.width,
230 self.compression.width,
231 self.infinite.width,
232 width.into(),
233 intrinsic_width,
234 )
235 }
236
237 pub fn resolve_height(&self, height: impl Into<Length>, intrinsic_height: f32) -> f32 {
239 resolve(
240 self.min.height,
241 self.max.height,
242 self.compression.height,
243 self.infinite.height,
244 height.into(),
245 intrinsic_height,
246 )
247 }
248}
249
250fn resolve(
251 min: f32,
252 max: f32,
253 compression: bool,
254 infinite: bool,
255 length: Length,
256 intrinsic: f32,
257) -> f32 {
258 match length {
259 Length::Fill
260 | Length::FillPortion(_)
261 | Length::Bounded {
262 sizing: length::Sizing::Fill(_),
263 ..
264 } if !compression => if infinite { max.max(intrinsic) } else { max }.max(min),
265 Length::Fixed(amount) => if infinite { amount } else { amount.min(max) }.max(min),
266 _ => if infinite {
267 intrinsic
268 } else {
269 intrinsic.min(max)
270 }
271 .max(min),
272 }
273}