Update 0.3.x for 0.3.11 (#455)
1//! Style types for representing lengths / sizes
2
3use crate::geometry::{Rect, Size};
4use crate::style_helpers::{FromPercent, FromPoints, TaffyAuto, TaffyMaxContent, TaffyMinContent, TaffyZero};
5use crate::sys::abs;
6
7/// A unit of linear measurement
8///
9/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`].
10#[derive(Copy, Clone, PartialEq, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub enum LengthPercentage {
13 /// Points are abstract absolute units. Users of Taffy may define what they correspond
14 /// to in their application (pixels, logical pixels, mm, etc) as they see fit.
15 Points(f32),
16 /// The dimension is stored in percentage relative to the parent item.
17 Percent(f32),
18}
19impl TaffyZero for LengthPercentage {
20 const ZERO: Self = Self::Points(0.0);
21}
22impl FromPoints for LengthPercentage {
23 fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
24 Self::Points(points.into())
25 }
26}
27impl FromPercent for LengthPercentage {
28 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
29 Self::Percent(percent.into())
30 }
31}
32
33/// A unit of linear measurement
34///
35/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`].
36#[derive(Copy, Clone, PartialEq, Debug)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38pub enum LengthPercentageAuto {
39 /// Points are abstract absolute units. Users of Taffy may define what they correspond
40 /// to in their application (pixels, logical pixels, mm, etc) as they see fit.
41 Points(f32),
42 /// The dimension is stored in percentage relative to the parent item.
43 Percent(f32),
44 /// The dimension should be automatically computed
45 Auto,
46}
47impl TaffyZero for LengthPercentageAuto {
48 const ZERO: Self = Self::Points(0.0);
49}
50impl TaffyAuto for LengthPercentageAuto {
51 const AUTO: Self = Self::Auto;
52}
53impl FromPoints for LengthPercentageAuto {
54 fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
55 Self::Points(points.into())
56 }
57}
58impl FromPercent for LengthPercentageAuto {
59 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
60 Self::Percent(percent.into())
61 }
62}
63
64impl From<LengthPercentage> for LengthPercentageAuto {
65 fn from(input: LengthPercentage) -> Self {
66 match input {
67 LengthPercentage::Points(value) => Self::Points(value),
68 LengthPercentage::Percent(value) => Self::Percent(value),
69 }
70 }
71}
72
73impl LengthPercentageAuto {
74 /// Returns:
75 /// - Some(points) for Points variants
76 /// - Some(resolved) using the provided context for Percent variants
77 /// - None for Auto variants
78 pub fn resolve_to_option(self, context: f32) -> Option<f32> {
79 match self {
80 Self::Points(points) => Some(points),
81 Self::Percent(percent) => Some(context * percent),
82 Self::Auto => None,
83 }
84 }
85}
86
87/// A unit of linear measurement
88///
89/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`].
90#[derive(Copy, Clone, PartialEq, Debug)]
91#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
92pub enum Dimension {
93 /// Points are abstract absolute units. Users of Taffy may define what they correspond
94 /// to in their application (pixels, logical pixels, mm, etc) as they see fit.
95 Points(f32),
96 /// The dimension is stored in percentage relative to the parent item.
97 Percent(f32),
98 /// The dimension should be automatically computed
99 Auto,
100}
101impl TaffyZero for Dimension {
102 const ZERO: Self = Self::Points(0.0);
103}
104impl TaffyAuto for Dimension {
105 const AUTO: Self = Self::Auto;
106}
107impl FromPoints for Dimension {
108 fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
109 Self::Points(points.into())
110 }
111}
112impl FromPercent for Dimension {
113 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
114 Self::Percent(percent.into())
115 }
116}
117
118impl From<LengthPercentage> for Dimension {
119 fn from(input: LengthPercentage) -> Self {
120 match input {
121 LengthPercentage::Points(value) => Self::Points(value),
122 LengthPercentage::Percent(value) => Self::Percent(value),
123 }
124 }
125}
126
127impl From<LengthPercentageAuto> for Dimension {
128 fn from(input: LengthPercentageAuto) -> Self {
129 match input {
130 LengthPercentageAuto::Points(value) => Self::Points(value),
131 LengthPercentageAuto::Percent(value) => Self::Percent(value),
132 LengthPercentageAuto::Auto => Self::Auto,
133 }
134 }
135}
136
137impl Dimension {
138 /// Get Points value if value is Points variant
139 #[cfg(feature = "grid")]
140 pub fn into_option(self) -> Option<f32> {
141 match self {
142 Dimension::Points(value) => Some(value),
143 _ => None,
144 }
145 }
146}
147
148impl Rect<Dimension> {
149 /// Create a new Rect with [`Dimension::Points`]
150 #[must_use]
151 pub const fn from_points(start: f32, end: f32, top: f32, bottom: f32) -> Self {
152 Rect {
153 left: Dimension::Points(start),
154 right: Dimension::Points(end),
155 top: Dimension::Points(top),
156 bottom: Dimension::Points(bottom),
157 }
158 }
159
160 /// Create a new Rect with [`Dimension::Percent`]
161 #[must_use]
162 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
163 Rect {
164 left: Dimension::Percent(start),
165 right: Dimension::Percent(end),
166 top: Dimension::Percent(top),
167 bottom: Dimension::Percent(bottom),
168 }
169 }
170}
171
172/// The amount of space available to a node in a given axis
173/// <https://www.w3.org/TR/css-sizing-3/#available>
174#[derive(Copy, Clone, Debug, PartialEq)]
175pub enum AvailableSpace {
176 /// The amount of space available is the specified number of pixels
177 Definite(f32),
178 /// The amount of space available is indefinite and the node should be laid out under a min-content constraint
179 MinContent,
180 /// The amount of space available is indefinite and the node should be laid out under a max-content constraint
181 MaxContent,
182}
183impl TaffyZero for AvailableSpace {
184 const ZERO: Self = Self::Definite(0.0);
185}
186impl TaffyMaxContent for AvailableSpace {
187 const MAX_CONTENT: Self = Self::MaxContent;
188}
189impl TaffyMinContent for AvailableSpace {
190 const MIN_CONTENT: Self = Self::MinContent;
191}
192impl FromPoints for AvailableSpace {
193 fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
194 Self::Definite(points.into())
195 }
196}
197
198impl AvailableSpace {
199 /// Returns true for definite values, else false
200 pub fn is_definite(self) -> bool {
201 matches!(self, AvailableSpace::Definite(_))
202 }
203
204 /// Convert to Option
205 /// Definite values become Some(value). Contraints become None.
206 pub fn into_option(self) -> Option<f32> {
207 match self {
208 AvailableSpace::Definite(value) => Some(value),
209 _ => None,
210 }
211 }
212
213 /// Return the definite value or a default value
214 pub fn unwrap_or(self, default: f32) -> f32 {
215 self.into_option().unwrap_or(default)
216 }
217
218 /// Return the definite value. Panic is the value is not definite.
219 #[track_caller]
220 pub fn unwrap(self) -> f32 {
221 self.into_option().unwrap()
222 }
223
224 /// Return self if definite or a default value
225 pub fn or(self, default: AvailableSpace) -> AvailableSpace {
226 match self {
227 AvailableSpace::Definite(_) => self,
228 _ => default,
229 }
230 }
231
232 /// Return self if definite or a the result of the default value callback
233 pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace {
234 match self {
235 AvailableSpace::Definite(_) => self,
236 _ => default_cb(),
237 }
238 }
239
240 /// Return the definite value or the result of the default value callback
241 pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 {
242 self.into_option().unwrap_or_else(default_cb)
243 }
244
245 /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
246 pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
247 match value {
248 Some(value) => AvailableSpace::Definite(value),
249 None => self,
250 }
251 }
252
253 /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
254 pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace {
255 match self {
256 AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)),
257 _ => self,
258 }
259 }
260
261 /// Compute free_space given the passed used_space
262 pub fn compute_free_space(&self, used_space: f32) -> f32 {
263 match self {
264 AvailableSpace::MaxContent => f32::INFINITY,
265 AvailableSpace::MinContent => 0.0,
266 AvailableSpace::Definite(available_space) => available_space - used_space,
267 }
268 }
269
270 /// Compare equality with another AvailableSpace, treating definite values
271 /// that are within f32::EPSILON of each other as equal
272 pub fn is_roughly_equal(self, other: AvailableSpace) -> bool {
273 use AvailableSpace::*;
274 match (self, other) {
275 (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON,
276 (MinContent, MinContent) => true,
277 (MaxContent, MaxContent) => true,
278 _ => false,
279 }
280 }
281}
282
283impl From<f32> for AvailableSpace {
284 fn from(value: f32) -> Self {
285 Self::Definite(value)
286 }
287}
288
289impl From<Option<f32>> for AvailableSpace {
290 fn from(option: Option<f32>) -> Self {
291 match option {
292 Some(value) => Self::Definite(value),
293 None => Self::MaxContent,
294 }
295 }
296}
297
298impl Size<AvailableSpace> {
299 /// Convert `Size<AvailableSpace>` into `Size<Option<f32>>`
300 pub fn into_options(self) -> Size<Option<f32>> {
301 Size { width: self.width.into_option(), height: self.height.into_option() }
302 }
303
304 /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
305 pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> {
306 Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) }
307 }
308}