tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Definiciones

⎇ 4e1c35c5d40729fdaafc40afeea863aa12ed1d5a src/style/dimension.rs Rust · 313 líneas · 10.3 KB Historia Quién tocó qué crudo

Implement head-to-head benchmarks against Yoga (#337) 4e1c35c5d · 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    /// Is this value defined?
139    pub(crate) fn is_defined(self) -> bool {
140        matches!(self, Dimension::Points(_) | Dimension::Percent(_))
141    }
142
143    /// Get Points value if value is Points variant
144    #[cfg(feature = "grid")]
145    pub fn into_option(self) -> Option<f32> {
146        match self {
147            Dimension::Points(value) => Some(value),
148            _ => None,
149        }
150    }
151}
152
153impl Rect<Dimension> {
154    /// Create a new Rect with [`Dimension::Points`]
155    #[must_use]
156    pub const fn from_points(start: f32, end: f32, top: f32, bottom: f32) -> Self {
157        Rect {
158            left: Dimension::Points(start),
159            right: Dimension::Points(end),
160            top: Dimension::Points(top),
161            bottom: Dimension::Points(bottom),
162        }
163    }
164
165    /// Create a new Rect with [`Dimension::Percent`]
166    #[must_use]
167    pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
168        Rect {
169            left: Dimension::Percent(start),
170            right: Dimension::Percent(end),
171            top: Dimension::Percent(top),
172            bottom: Dimension::Percent(bottom),
173        }
174    }
175}
176
177/// The amount of space available to a node in a given axis
178/// https://www.w3.org/TR/css-sizing-3/#available
179#[derive(Copy, Clone, Debug, PartialEq)]
180pub enum AvailableSpace {
181    /// The amount of space available is the specified number of pixels
182    Definite(f32),
183    /// The amount of space available is indefinite and the node should be laid out under a min-content constraint
184    MinContent,
185    /// The amount of space available is indefinite and the node should be laid out under a max-content constraint
186    MaxContent,
187}
188impl TaffyZero for AvailableSpace {
189    const ZERO: Self = Self::Definite(0.0);
190}
191impl TaffyMaxContent for AvailableSpace {
192    const MAX_CONTENT: Self = Self::MaxContent;
193}
194impl TaffyMinContent for AvailableSpace {
195    const MIN_CONTENT: Self = Self::MinContent;
196}
197impl FromPoints for AvailableSpace {
198    fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
199        Self::Definite(points.into())
200    }
201}
202
203impl AvailableSpace {
204    /// Returns true for definite values, else false
205    pub fn is_definite(self) -> bool {
206        matches!(self, AvailableSpace::Definite(_))
207    }
208
209    /// Convert to Option
210    /// Definite values become Some(value). Contraints become None.
211    pub fn into_option(self) -> Option<f32> {
212        match self {
213            AvailableSpace::Definite(value) => Some(value),
214            _ => None,
215        }
216    }
217
218    /// Return the definite value or a default value
219    pub fn unwrap_or(self, default: f32) -> f32 {
220        self.into_option().unwrap_or(default)
221    }
222
223    /// Return the definite value. Panic is the value is not definite.
224    #[track_caller]
225    pub fn unwrap(self) -> f32 {
226        self.into_option().unwrap()
227    }
228
229    /// Return self if definite or a default value
230    pub fn or(self, default: AvailableSpace) -> AvailableSpace {
231        match self {
232            AvailableSpace::Definite(_) => self,
233            _ => default,
234        }
235    }
236
237    /// Return self if definite or a the result of the default value callback
238    pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace {
239        match self {
240            AvailableSpace::Definite(_) => self,
241            _ => default_cb(),
242        }
243    }
244
245    /// Return the definite value or the result of the default value callback
246    pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 {
247        self.into_option().unwrap_or_else(default_cb)
248    }
249
250    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
251    pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
252        match value {
253            Some(value) => AvailableSpace::Definite(value),
254            None => self,
255        }
256    }
257
258    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
259    pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace {
260        match self {
261            AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)),
262            _ => self,
263        }
264    }
265
266    /// Compute free_space given the passed used_space
267    pub fn compute_free_space(&self, used_space: f32) -> f32 {
268        match self {
269            AvailableSpace::MaxContent => f32::INFINITY,
270            AvailableSpace::MinContent => 0.0,
271            AvailableSpace::Definite(available_space) => available_space - used_space,
272        }
273    }
274
275    /// Compare equality with another AvailableSpace, treating definite values
276    /// that are within f32::EPSILON of each other as equal
277    pub fn is_roughly_equal(self, other: AvailableSpace) -> bool {
278        use AvailableSpace::*;
279        match (self, other) {
280            (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON,
281            (MinContent, MinContent) => true,
282            (MaxContent, MaxContent) => true,
283            _ => false,
284        }
285    }
286}
287
288impl From<f32> for AvailableSpace {
289    fn from(value: f32) -> Self {
290        Self::Definite(value)
291    }
292}
293
294impl From<Option<f32>> for AvailableSpace {
295    fn from(option: Option<f32>) -> Self {
296        match option {
297            Some(value) => Self::Definite(value),
298            None => Self::MaxContent,
299        }
300    }
301}
302
303impl Size<AvailableSpace> {
304    /// Convert Size<AvailableSpace> into Size<Option<f32>>
305    pub fn into_options(self) -> Size<Option<f32>> {
306        Size { width: self.width.into_option(), height: self.height.into_option() }
307    }
308
309    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
310    pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> {
311        Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) }
312    }
313}