1use std::f64;
2
3#[derive(Default)]
5pub struct ConstraintBuilder {
6 width: f64,
7 height: f64,
8 min_width: f64,
9 min_height: f64,
10 max_width: f64,
11 max_height: f64,
12}
13
14impl ConstraintBuilder {
20 pub fn new() -> Self {
22 ConstraintBuilder::default()
23 }
24
25 pub fn width(mut self, width: impl Into<f64>) -> Self {
27 self.width = width.into();
28 self
29 }
30
31 pub fn height(mut self, height: impl Into<f64>) -> Self {
33 self.height = height.into();
34 self
35 }
36
37 pub fn size(mut self, width: impl Into<f64>, height: impl Into<f64>) -> Self {
39 self.width = width.into();
40 self.height = height.into();
41 self
42 }
43
44 pub fn min_width(mut self, min_width: impl Into<f64>) -> Self {
46 self.min_width = min_width.into();
47 self
48 }
49
50 pub fn min_height(mut self, min_height: impl Into<f64>) -> Self {
52 self.min_height = min_height.into();
53 self
54 }
55
56 pub fn min_size(mut self, min_width: impl Into<f64>, min_height: impl Into<f64>) -> Self {
58 self.min_width = min_width.into();
59 self.min_height = min_height.into();
60 self
61 }
62
63 pub fn max_width(mut self, max_width: impl Into<f64>) -> Self {
65 self.max_width = max_width.into();
66 self
67 }
68
69 pub fn max_height(mut self, max_height: impl Into<f64>) -> Self {
71 self.max_height = max_height.into();
72 self
73 }
74
75 pub fn max_size(mut self, max_width: impl Into<f64>, max_height: impl Into<f64>) -> Self {
77 self.max_width = max_width.into();
78 self.max_height = max_height.into();
79 self
80 }
81
82 pub fn build(self) -> Constraint {
84 Constraint {
85 width: self.width,
86 height: self.height,
87 min_width: self.min_width,
88 min_height: self.min_height,
89 max_width: self.max_width,
90 max_height: self.max_height,
91 }
92 }
93}
94
95#[derive(Copy, Clone, Debug, PartialEq)]
97pub struct Constraint {
98 width: f64,
99 height: f64,
100 min_width: f64,
101 min_height: f64,
102 max_width: f64,
103 max_height: f64,
104}
105
106impl Default for Constraint {
107 fn default() -> Self {
108 Constraint {
109 width: 0.0,
110 height: 0.0,
111 min_width: 0.0,
112 min_height: 0.0,
113 max_width: f64::MAX,
114 max_height: f64::MAX,
115 }
116 }
117}
118
119impl Constraint {
125 #[inline]
127 pub fn create() -> ConstraintBuilder {
128 ConstraintBuilder::new()
129 }
130
131 pub fn width(&self) -> f64 {
133 self.width
134 }
135
136 pub fn set_width(&mut self, width: f64) {
138 self.width = width;
139
140 if self.min_width > width {
142 self.min_width = width;
143 }
144
145 if self.max_width < width {
146 self.max_width = width;
147 }
148 }
149
150 pub fn height(&self) -> f64 {
152 self.height
153 }
154
155 pub fn set_height(&mut self, height: f64) {
157 self.height = height;
158
159 if self.min_height > height {
161 self.min_height = height;
162 }
163
164 if self.max_height < height {
165 self.max_height = height;
166 }
167 }
168
169 pub fn size(&self) -> (f64, f64) {
171 (self.width, self.height)
172 }
173
174 pub fn set_size(&mut self, width: f64, height: f64) {
176 self.set_width(width);
177 self.set_height(height);
178 }
179
180 pub fn min_width(&self) -> f64 {
182 self.min_width
183 }
184
185 pub fn set_min_width(&mut self, min_width: f64) {
187 self.min_width = min_width;
188
189 self.width = 0.;
190 }
191
192 pub fn min_height(&self) -> f64 {
194 self.min_height
195 }
196
197 pub fn set_min_height(&mut self, min_height: f64) {
199 self.min_height = min_height;
200
201 self.height = 0.;
202 }
203
204 pub fn min_size(&self) -> (f64, f64) {
206 (self.min_width, self.min_height)
207 }
208
209 pub fn set_min_size(&mut self, min_width: f64, min_height: f64) {
211 self.set_min_width(min_width);
212 self.set_min_height(min_height);
213 }
214
215 pub fn max_width(&self) -> f64 {
217 self.max_width
218 }
219
220 pub fn set_max_width(&mut self, max_width: f64) {
222 self.max_width = max_width;
223
224 self.width = 0.;
225 }
226
227 pub fn max_height(&self) -> f64 {
229 self.max_height
230 }
231
232 pub fn set_max_height(&mut self, max_height: f64) {
234 self.max_height = max_height;
235
236 self.height = 0.;
237 }
238
239 pub fn max_size(&self) -> (f64, f64) {
241 (self.max_width, self.max_height)
242 }
243
244 pub fn set_max_size(&mut self, max_width: f64, max_height: f64) {
246 self.set_max_width(max_width);
247 self.set_max_height(max_height);
248 }
249
250 pub fn perform(&self, size: (f64, f64)) -> (f64, f64) {
255 let size = {
256 let width = if self.width > 0.0 { self.width } else { size.0 };
257 let height = if self.height > 0.0 {
258 self.height
259 } else {
260 size.1
261 };
262
263 (width, height)
264 };
265
266 (
267 constrain(size.0, self.min_width, self.max_width, self.width),
269 constrain(size.1, self.min_height, self.max_height, self.height),
271 )
272 }
273}
274
275fn constrain(val: f64, min: f64, max: f64, size: f64) -> f64 {
277 if min == 0.0 && max == 0.0 && size > 0.0 {
278 size
279 } else if val < min && min > 0.0 {
280 min
281 } else if val > max && max > 0.0 {
282 max
283 } else {
284 val
285 }
286}
287
288impl From<ConstraintBuilder> for Constraint {
289 fn from(builder: ConstraintBuilder) -> Self {
290 builder.build()
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 const ERROR: f64 = f64::EPSILON;
299
300 #[test]
301 fn test_builder_width() {
302 let width = 12.0;
303
304 let constraint = Constraint::create().width(width).build();
305
306 assert!((constraint.width() - width).abs() < ERROR);
307 }
308
309 #[test]
310 fn test_builder_height() {
311 let height = 12.0;
312
313 let constraint = Constraint::create().height(height).build();
314
315 assert!((constraint.height() - height).abs() < ERROR);
316 }
317
318 #[test]
319 fn test_builder_min_width() {
320 let width = 12.0;
321
322 let constraint = Constraint::create().min_width(width).build();
323
324 assert!((constraint.min_width() - width).abs() < ERROR);
325 }
326
327 #[test]
328 fn test_builder_min_height() {
329 let height = 12.0;
330
331 let constraint = Constraint::create().min_height(height).build();
332
333 assert!((constraint.min_height() - height).abs() < ERROR);
334 }
335
336 #[test]
337 fn test_builder_max_width() {
338 let width = 12.0;
339
340 let constraint = Constraint::create().max_width(width).build();
341
342 assert!((constraint.max_width() - width).abs() < ERROR);
343 }
344
345 #[test]
346 fn test_builder_max_height() {
347 let height = 12.0;
348
349 let constraint = Constraint::create().max_height(height).build();
350
351 assert!((constraint.max_height() - height).abs() < ERROR);
352 }
353
354 #[test]
355 fn test_set_width() {
356 let width = 12.0;
357
358 let mut constraint = Constraint::default();
359 constraint.set_width(width);
360 assert!((constraint.width() - width).abs() < ERROR);
361 }
362
363 #[test]
364 fn test_set_height() {
365 let height = 12.0;
366
367 let mut constraint = Constraint::default();
368 constraint.set_height(height);
369
370 assert!((constraint.height() - height).abs() < ERROR);
371 }
372
373 #[test]
374 fn test_set_size() {
375 let width = 12.0;
376 let height = 14.0;
377
378 let mut constraint = Constraint::default();
379 constraint.set_size(width, height);
380
381 assert_eq!(constraint.size(), (width, height));
382 }
383
384 #[test]
385 fn test_set_min_width() {
386 let min_width = 12.0;
387
388 let mut constraint = Constraint::default();
389 constraint.set_min_width(min_width);
390
391 assert!((constraint.min_width() - min_width).abs() < ERROR);
392 }
393
394 #[test]
395 fn test_set_min_height() {
396 let min_height = 12.0;
397
398 let mut constraint = Constraint::default();
399 constraint.set_min_height(min_height);
400
401 assert!((constraint.min_height() - min_height).abs() < ERROR);
402 }
403
404 #[test]
405 fn test_set_min_size() {
406 let min_width = 12.0;
407 let min_height = 14.0;
408
409 let mut constraint = Constraint::default();
410 constraint.set_min_size(min_width, min_height);
411
412 assert_eq!(constraint.min_size(), (min_width, min_height));
413 }
414
415 #[test]
416 fn test_set_max_width() {
417 let max_width = 12.0;
418
419 let mut constraint = Constraint::default();
420 constraint.set_max_width(max_width);
421
422 assert!((constraint.max_width() - max_width).abs() < ERROR);
423 }
424
425 #[test]
426 fn test_set_max_height() {
427 let max_height = 12.0;
428
429 let mut constraint = Constraint::default();
430 constraint.set_max_height(max_height);
431
432 assert!((constraint.max_height() - max_height).abs() < ERROR);
433 }
434
435 #[test]
436 fn test_set_max_size() {
437 let max_width = 12.0;
438 let max_height = 14.0;
439
440 let mut constraint = Constraint::default();
441 constraint.set_max_size(max_width, max_height);
442
443 assert_eq!(constraint.max_size(), (max_width, max_height));
444 }
445
446 #[test]
447 fn test_perform() {
448 let mut constraint = Constraint::default();
449
450 constraint.set_min_width(10.0);
451 constraint.set_min_height(10.0);
452 constraint.set_max_width(50.0);
453 constraint.set_max_height(60.0);
454
455 assert_eq!(constraint.perform((10.0, 59.0)), (10.0, 59.0));
456 assert_eq!(constraint.perform((5.0, 40.0)), (10.0, 40.0));
457 assert_eq!(constraint.perform((10.0, 70.0)), (10.0, 60.0));
458 }
459}