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