gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5364Rust 86Markdown 12TOML 91841 Sutichaykuna

⎇ 495c673d051fa463e506e95cf23db2b4eedcec71 src/style/dimension.rs Rust · 316 siq'ikuna · 10.4 KB Ñawpa willay Pi imata llamkarqan ch'uya

Increase coverage of serde derives 495c673d0 · Nico Burns ·

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}