gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 87Markdown 12TOML 91924 Definiciones

⎇ 7762c2490a21a7f3f4e911efd097bdee7b0ef108 src/geometry.rs Rust · 277 líneas · 8.7 KB Historia Quién tocó qué crudo

Unit test `compute_constants()` (#184) 7762c2490 · Andreas Weibye ·

1//! Geometric primitives useful for layout
2
3use crate::style::{Dimension, FlexDirection};
4use core::ops::Add;
5
6/// An axis-aligned UI rectangle
7#[derive(Debug, Copy, Clone, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9#[cfg_attr(feature = "serde", serde(default))]
10pub struct Rect<T> {
11    /// This can represent either the x-coordinate of the starting edge,
12    /// or the amount of padding on the starting side.
13    ///
14    /// The starting edge is the left edge when working with LTR text,
15    /// and the right edge when working with RTL text.
16    pub start: T,
17    /// This can represent either the x-coordinate of the ending edge,
18    /// or the amount of padding on the ending side.
19    ///
20    /// The ending edge is the right edge when working with LTR text,
21    /// and the left edge when working with RTL text.
22    pub end: T,
23    /// This can represent either the y-coordinate of the top edge,
24    /// or the amount of padding on the top side.
25    pub top: T,
26    /// This can represent either the y-coordinate of the bottom edge,
27    /// or the amount of padding on the bottom side.
28    pub bottom: T,
29}
30
31impl<T> Rect<T> {
32    /// Applies the function `f` to all four sides of the rect
33    ///
34    /// When applied to the left and right sides, the width is used
35    /// as the second parameter of `f`.
36    /// When applied to the top or bottom sides, the height is used instead.
37    pub(crate) fn zip_size<R, F, U>(self, size: Size<U>, f: F) -> Rect<R>
38    where
39        F: Fn(T, U) -> R,
40        U: Copy,
41    {
42        Rect {
43            start: f(self.start, size.width),
44            end: f(self.end, size.width),
45            top: f(self.top, size.height),
46            bottom: f(self.bottom, size.height),
47        }
48    }
49}
50
51impl<T> Rect<T>
52where
53    T: Add<Output = T> + Copy + Clone,
54{
55    /// The sum of [`Rect.start`](Rect) and [`Rect.end`](Rect)
56    ///
57    /// This is typically used when computing total padding.
58    ///
59    /// **NOTE:** this is *not* the width of the rectangle.
60    pub(crate) fn horizontal_axis_sum(&self) -> T {
61        self.start + self.end
62    }
63
64    /// The sum of [`Rect.top`](Rect) and [`Rect.bottom`](Rect)
65    ///
66    /// This is typically used when computing total padding.
67    ///
68    /// **NOTE:** this is *not* the height of the rectangle.
69    pub(crate) fn vertical_axis_sum(&self) -> T {
70        self.top + self.bottom
71    }
72
73    /// The sum of the two fields of the [`Rect`] representing the main axis.
74    ///
75    /// This is typically used when computing total padding.
76    ///
77    /// If the [`FlexDirection`] is [`FlexDirection::Row`] or [`FlexDirection::RowReverse`], this is [`Rect::horizontal`].
78    /// Otherwise, this is [`Rect::vertical`].
79    pub(crate) fn main_axis_sum(&self, direction: FlexDirection) -> T {
80        if direction.is_row() {
81            self.horizontal_axis_sum()
82        } else {
83            self.vertical_axis_sum()
84        }
85    }
86
87    /// The sum of the two fields of the [`Rect`] representing the cross axis.
88    ///
89    /// If the [`FlexDirection`] is [`FlexDirection::Row`] or [`FlexDirection::RowReverse`], this is [`Rect::vertical`].
90    /// Otherwise, this is [`Rect::horizontal`].
91    pub(crate) fn cross_axis_sum(&self, direction: FlexDirection) -> T {
92        if direction.is_row() {
93            self.vertical_axis_sum()
94        } else {
95            self.horizontal_axis_sum()
96        }
97    }
98}
99
100impl<T> Rect<T>
101where
102    T: Copy + Clone,
103{
104    /// The `start` or `top` value of the [`Rect`], from the perspective of the main layout axis
105    pub(crate) fn main_start(&self, direction: FlexDirection) -> T {
106        if direction.is_row() {
107            self.start
108        } else {
109            self.top
110        }
111    }
112
113    /// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
114    pub(crate) fn main_end(&self, direction: FlexDirection) -> T {
115        if direction.is_row() {
116            self.end
117        } else {
118            self.bottom
119        }
120    }
121
122    /// The `start` or `top` value of the [`Rect`], from the perspective of the cross layout axis
123    pub(crate) fn cross_start(&self, direction: FlexDirection) -> T {
124        if direction.is_row() {
125            self.top
126        } else {
127            self.start
128        }
129    }
130
131    /// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
132    pub(crate) fn cross_end(&self, direction: FlexDirection) -> T {
133        if direction.is_row() {
134            self.bottom
135        } else {
136            self.end
137        }
138    }
139}
140
141impl Rect<f32> {
142    /// Creates a new Rect with `0.0` as all parameters
143    pub const ZERO: Rect<f32> = Self { start: 0.0, end: 0.0, top: 0.0, bottom: 0.0 };
144
145    /// Creates a new Rect
146    #[must_use]
147    pub fn new(start: f32, end: f32, top: f32, bottom: f32) -> Self {
148        Self { start, end, top, bottom }
149    }
150}
151
152/// The width and height of a [`Rect`]
153#[derive(Debug, Copy, Clone, PartialEq, Eq)]
154#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
155#[cfg_attr(feature = "serde", serde(default))]
156pub struct Size<T> {
157    /// The x extent of the rectangle
158    pub width: T,
159    /// The y extent of the rectangle
160    pub height: T,
161}
162
163impl Size<()> {
164    /// Generates a `Size<Option<f32>>` with undefined width and height
165    #[must_use]
166    pub fn undefined() -> Size<Option<f32>> {
167        Size { width: None, height: None }
168    }
169}
170
171impl<T> Size<T> {
172    /// Applies the function `f` to both the width and height
173    ///
174    /// This is used to transform a `Rect<T>` into a `Rect<R>`.
175    pub fn map<R, F>(self, f: F) -> Size<R>
176    where
177        F: Fn(T) -> R,
178    {
179        Size { width: f(self.width), height: f(self.height) }
180    }
181
182    /// Sets the extent of the main layout axis
183    ///
184    /// Whether this is the width or height depends on the `direction` provided
185    pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
186        if direction.is_row() {
187            self.width = value
188        } else {
189            self.height = value
190        }
191    }
192
193    /// Sets the extent of the cross layout axis
194    ///
195    /// Whether this is the width or height depends on the `direction` provided
196    pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
197        if direction.is_row() {
198            self.height = value
199        } else {
200            self.width = value
201        }
202    }
203
204    /// Gets the extent of the main layout axis
205    ///
206    /// Whether this is the width or height depends on the `direction` provided
207    pub(crate) fn main(self, direction: FlexDirection) -> T {
208        if direction.is_row() {
209            self.width
210        } else {
211            self.height
212        }
213    }
214
215    /// Gets the extent of the cross layout axis
216    ///
217    /// Whether this is the width or height depends on the `direction` provided
218    pub(crate) fn cross(self, direction: FlexDirection) -> T {
219        if direction.is_row() {
220            self.height
221        } else {
222            self.width
223        }
224    }
225}
226
227impl Size<f32> {
228    /// A [`Size`] with zero width and height
229    pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
230}
231
232impl Size<Option<f32>> {
233    /// A [`Size`] with `None` width and height
234    pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
235
236    /// A [`Size<Option<f32>>`] with `Some(width)` and `Some(height)` as parameters
237    #[must_use]
238    pub fn new(width: f32, height: f32) -> Self {
239        Size { width: Some(width), height: Some(height) }
240    }
241}
242
243impl Size<Dimension> {
244    /// Generates a [`Size<Dimension>`] using [`Dimension::Points`] values
245    #[must_use]
246    pub fn from_points(width: f32, height: f32) -> Self {
247        Size { width: Dimension::Points(width), height: Dimension::Points(height) }
248    }
249
250    /// Generates a [`Size<Dimension>`] using [`Dimension::Percent`] values
251    #[must_use]
252    pub fn from_percent(width: f32, height: f32) -> Self {
253        Size { width: Dimension::Percent(width), height: Dimension::Percent(height) }
254    }
255
256    /// Generates a [`Size<Dimension>`] using [`Dimension::Auto`] in both width and height
257    pub const AUTO: Size<Dimension> = Self { width: Dimension::Auto, height: Dimension::Auto };
258
259    /// Generates a [`Size<Dimension>`] using [`Dimension::Undefined`] in both width and height
260    pub const UNDEFINED: Size<Dimension> = Self { width: Dimension::Undefined, height: Dimension::Undefined };
261}
262
263/// A 2-dimensional coordinate.
264///
265/// When used in association with a [`Rect`], represents the bottom-left corner.
266#[derive(Debug, Copy, Clone, PartialEq, Eq)]
267pub struct Point<T> {
268    /// The x-coordinate
269    pub x: T,
270    /// The y-coordinate
271    pub y: T,
272}
273
274impl Point<f32> {
275    /// A [`Point`] with values (0,0), representing the origin
276    pub const ZERO: Point<f32> = Self { x: 0.0, y: 0.0 };
277}