gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 497HTML 254C 19JavaScript 81329 Definiciones

⎇ 01babab32d8138f3c3fa05095fb6c65fca0d3967 src/style/dimension.rs Rust · 292 líneas · 9.6 KB Historia Quién tocó qué crudo

Make CSS Grid feature a default feature (#297) 01babab32 · 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::Points(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::Points(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::Points(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(crate) 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    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
230    pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
231        match value {
232            Some(value) => AvailableSpace::Definite(value),
233            None => self,
234        }
235    }
236
237    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
238    pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace {
239        match self {
240            AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)),
241            _ => self,
242        }
243    }
244
245    /// Compute free_space given the passed used_space
246    pub fn compute_free_space(&self, used_space: f32) -> f32 {
247        match self {
248            AvailableSpace::MaxContent => f32::INFINITY,
249            AvailableSpace::MinContent => 0.0,
250            AvailableSpace::Definite(available_space) => available_space - used_space,
251        }
252    }
253
254    /// Compare equality with another AvailableSpace, treating definite values
255    /// that are within f32::EPSILON of each other as equal
256    pub fn is_roughly_equal(self, other: AvailableSpace) -> bool {
257        use AvailableSpace::*;
258        match (self, other) {
259            (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON,
260            (MinContent, MinContent) => true,
261            (MaxContent, MaxContent) => true,
262            _ => false,
263        }
264    }
265}
266
267impl From<f32> for AvailableSpace {
268    fn from(value: f32) -> Self {
269        Self::Definite(value)
270    }
271}
272
273impl From<Option<f32>> for AvailableSpace {
274    fn from(option: Option<f32>) -> Self {
275        match option {
276            Some(value) => Self::Definite(value),
277            None => Self::MaxContent,
278        }
279    }
280}
281
282impl Size<AvailableSpace> {
283    /// Convert Size<AvailableSpace> into Size<Option<f32>>
284    pub fn into_options(self) -> Size<Option<f32>> {
285        Size { width: self.width.into_option(), height: self.height.into_option() }
286    }
287
288    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
289    pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> {
290        Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) }
291    }
292}