gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 497HTML 254C 19JavaScript 81329 Sutichaykuna

⎇ 0.3.x src/style/dimension.rs Rust · 308 siq'ikuna · 10.2 KB Ñawpa willay Pi imata llamkarqan ch'uya

Update 0.3.x for 0.3.11 (#455) 1cc940684 · Nico Burns ·

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}