orbtk_utils/
constraint.rs

1use std::f64;
2
3/// Used to capture constraint properties.
4#[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
14/// The `ConstraintBuilder` is used to crate the constraint porperties of an entity.
15///
16/// Constraints will provide properties that are used to determine the
17/// size requirements of an entity. It will store `minimum` and
18/// `maximim` values for its height and width, next to the current values.
19impl ConstraintBuilder {
20    /// Creates a new `ConstraintBuilder` with default values.
21    pub fn new() -> Self {
22        ConstraintBuilder::default()
23    }
24
25    /// Inserts a new width.
26    pub fn width(mut self, width: impl Into<f64>) -> Self {
27        self.width = width.into();
28        self
29    }
30
31    /// Inserts a new height.
32    pub fn height(mut self, height: impl Into<f64>) -> Self {
33        self.height = height.into();
34        self
35    }
36
37    /// Inserts a new size.
38    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    /// Inserts a new min_width.
45    pub fn min_width(mut self, min_width: impl Into<f64>) -> Self {
46        self.min_width = min_width.into();
47        self
48    }
49
50    /// Inserts a new min_height.
51    pub fn min_height(mut self, min_height: impl Into<f64>) -> Self {
52        self.min_height = min_height.into();
53        self
54    }
55
56    /// Inserts a new min_size.
57    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    /// Inserts a new max_width.
64    pub fn max_width(mut self, max_width: impl Into<f64>) -> Self {
65        self.max_width = max_width.into();
66        self
67    }
68
69    /// Inserts a new max_height.
70    pub fn max_height(mut self, max_height: impl Into<f64>) -> Self {
71        self.max_height = max_height.into();
72        self
73    }
74
75    /// Inserts a new min_size.
76    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    /// Builds the constraint.
83    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/// `Constraint` describes the constraints properties of a `box` entity.
96#[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
119/// The `Constraint` is used to manage the constraint porperties of an entity.
120///
121/// Constraints will provide properties that are used to determine the
122/// size requirements of an entity. It will store `minimum` and
123/// `maximim` values for its height and width, next to the current values.
124impl Constraint {
125    /// Returns a constraint builder.
126    #[inline]
127    pub fn create() -> ConstraintBuilder {
128        ConstraintBuilder::new()
129    }
130
131    /// Gets width.
132    pub fn width(&self) -> f64 {
133        self.width
134    }
135
136    /// Sets width.
137    pub fn set_width(&mut self, width: f64) {
138        self.width = width;
139
140        // adjust min and max
141        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    /// Gets height.
151    pub fn height(&self) -> f64 {
152        self.height
153    }
154
155    /// Sets height.
156    pub fn set_height(&mut self, height: f64) {
157        self.height = height;
158
159        // adjust min and max
160        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    /// Gets the size.
170    pub fn size(&self) -> (f64, f64) {
171        (self.width, self.height)
172    }
173
174    /// Sets the size.
175    pub fn set_size(&mut self, width: f64, height: f64) {
176        self.set_width(width);
177        self.set_height(height);
178    }
179
180    /// Gets min_width.
181    pub fn min_width(&self) -> f64 {
182        self.min_width
183    }
184
185    /// Sets min_width and set width to 0.0.
186    pub fn set_min_width(&mut self, min_width: f64) {
187        self.min_width = min_width;
188
189        self.width = 0.;
190    }
191
192    /// Gets min_height.
193    pub fn min_height(&self) -> f64 {
194        self.min_height
195    }
196
197    /// Sets min_height and set height to min_height if height < min_height.
198    pub fn set_min_height(&mut self, min_height: f64) {
199        self.min_height = min_height;
200
201        self.height = 0.;
202    }
203
204    /// Gets the min_size.
205    pub fn min_size(&self) -> (f64, f64) {
206        (self.min_width, self.min_height)
207    }
208
209    /// Sets the min size.
210    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    /// Gets max_width.
216    pub fn max_width(&self) -> f64 {
217        self.max_width
218    }
219
220    /// Sets max_width and set width to 0.0.
221    pub fn set_max_width(&mut self, max_width: f64) {
222        self.max_width = max_width;
223
224        self.width = 0.;
225    }
226
227    /// Gets max_height.
228    pub fn max_height(&self) -> f64 {
229        self.max_height
230    }
231
232    /// Sets max_height and set height to 0.0.
233    pub fn set_max_height(&mut self, max_height: f64) {
234        self.max_height = max_height;
235
236        self.height = 0.;
237    }
238
239    /// Gets the max_size.
240    pub fn max_size(&self) -> (f64, f64) {
241        (self.max_width, self.max_height)
242    }
243
244    /// Sets the max size.
245    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    /// Adjust the given `size`.
251    ///
252    /// Asures that size will respect the defined `box` values for min
253    /// and max constraints. The value will be adapted if outside of a bound.
254    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            // check `width` value to meet the constraint requirement
268            constrain(size.0, self.min_width, self.max_width, self.width),
269            // check `height` value to meet the constraint requirement
270            constrain(size.1, self.min_height, self.max_height, self.height),
271        )
272    }
273}
274
275// Check constraint for the given
276fn 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}