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(min: Size, max: Size, compress: Size<bool>) -> Self {
28        Limits {
29            min,
30            max,
31            compression: compress,
32        }
33    }
34
35    /// Returns the minimum [`Size`] of the [`Limits`].
36    pub fn min(&self) -> Size {
37        self.min
38    }
39
40    /// Returns the maximum [`Size`] of the [`Limits`].
41    pub fn max(&self) -> Size {
42        self.max
43    }
44
45    /// Returns the compression of the [`Limits`].
46    pub fn compression(&self) -> Size<bool> {
47        self.compression
48    }
49
50    /// Applies a width constraint to the current [`Limits`].
51    pub fn width(mut self, width: impl Into<Length>) -> Limits {
52        match width.into() {
53            Length::Shrink => {
54                self.compression.width = true;
55            }
56            Length::Fixed(amount) => {
57                let new_width = amount.min(self.max.width).max(self.min.width);
58
59                self.min.width = new_width;
60                self.max.width = new_width;
61                self.compression.width = false;
62            }
63            Length::Fill | Length::FillPortion(_) => {}
64        }
65
66        self
67    }
68
69    /// Applies a height constraint to the current [`Limits`].
70    pub fn height(mut self, height: impl Into<Length>) -> Limits {
71        match height.into() {
72            Length::Shrink => {
73                self.compression.height = true;
74            }
75            Length::Fixed(amount) => {
76                let new_height = amount.min(self.max.height).max(self.min.height);
77
78                self.min.height = new_height;
79                self.max.height = new_height;
80                self.compression.height = false;
81            }
82            Length::Fill | Length::FillPortion(_) => {}
83        }
84
85        self
86    }
87
88    /// Applies a minimum width constraint to the current [`Limits`].
89    pub fn min_width(mut self, min_width: f32) -> Limits {
90        self.min.width = self.min.width.max(min_width).min(self.max.width);
91
92        self
93    }
94
95    /// Applies a maximum width constraint to the current [`Limits`].
96    pub fn max_width(mut self, max_width: f32) -> Limits {
97        self.max.width = self.max.width.min(max_width).max(self.min.width);
98
99        self
100    }
101
102    /// Applies a minimum height constraint to the current [`Limits`].
103    pub fn min_height(mut self, min_height: f32) -> Limits {
104        self.min.height = self.min.height.max(min_height).min(self.max.height);
105
106        self
107    }
108
109    /// Applies a maximum height constraint to the current [`Limits`].
110    pub fn max_height(mut self, max_height: f32) -> Limits {
111        self.max.height = self.max.height.min(max_height).max(self.min.height);
112
113        self
114    }
115
116    /// Shrinks the current [`Limits`] by the given [`Size`].
117    pub fn shrink(&self, size: impl Into<Size>) -> Limits {
118        let size = size.into();
119
120        let min = Size::new(
121            (self.min().width - size.width).max(0.0),
122            (self.min().height - size.height).max(0.0),
123        );
124
125        let max = Size::new(
126            (self.max().width - size.width).max(0.0),
127            (self.max().height - size.height).max(0.0),
128        );
129
130        Limits {
131            min,
132            max,
133            compression: self.compression,
134        }
135    }
136
137    /// Removes the minimum [`Size`] constraint for the current [`Limits`].
138    pub fn loose(&self) -> Limits {
139        Limits {
140            min: Size::ZERO,
141            max: self.max,
142            compression: self.compression,
143        }
144    }
145
146    /// Computes the resulting [`Size`] that fits the [`Limits`] given
147    /// some width and height requirements and the intrinsic size of
148    /// some content.
149    pub fn resolve(
150        &self,
151        width: impl Into<Length>,
152        height: impl Into<Length>,
153        intrinsic_size: Size,
154    ) -> Size {
155        let width = match width.into() {
156            Length::Fill | Length::FillPortion(_) if !self.compression.width => self.max.width,
157            Length::Fixed(amount) => amount.min(self.max.width).max(self.min.width),
158            _ => intrinsic_size.width.min(self.max.width).max(self.min.width),
159        };
160
161        let height = match height.into() {
162            Length::Fill | Length::FillPortion(_) if !self.compression.height => self.max.height,
163            Length::Fixed(amount) => amount.min(self.max.height).max(self.min.height),
164            _ => intrinsic_size
165                .height
166                .min(self.max.height)
167                .max(self.min.height),
168        };
169
170        Size::new(width, height)
171    }
172}