tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Definiciones

⎇ 2e0d1bd2f08d3e477e564acfbed30c9caa2e0440 src/geometry.rs Rust · 269 líneas · 8.5 KB Historia Quién tocó qué crudo

Make library more usable in a `const` context (#203) 3535699e0 · Alice Cecile ·

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 const 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<T> Size<T> {
164    /// Applies the function `f` to both the width and height
165    ///
166    /// This is used to transform a `Rect<T>` into a `Rect<R>`.
167    pub fn map<R, F>(self, f: F) -> Size<R>
168    where
169        F: Fn(T) -> R,
170    {
171        Size { width: f(self.width), height: f(self.height) }
172    }
173
174    /// Sets the extent of the main layout axis
175    ///
176    /// Whether this is the width or height depends on the `direction` provided
177    pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
178        if direction.is_row() {
179            self.width = value
180        } else {
181            self.height = value
182        }
183    }
184
185    /// Sets the extent of the cross layout axis
186    ///
187    /// Whether this is the width or height depends on the `direction` provided
188    pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
189        if direction.is_row() {
190            self.height = value
191        } else {
192            self.width = value
193        }
194    }
195
196    /// Gets the extent of the main layout axis
197    ///
198    /// Whether this is the width or height depends on the `direction` provided
199    pub(crate) fn main(self, direction: FlexDirection) -> T {
200        if direction.is_row() {
201            self.width
202        } else {
203            self.height
204        }
205    }
206
207    /// Gets the extent of the cross layout axis
208    ///
209    /// Whether this is the width or height depends on the `direction` provided
210    pub(crate) fn cross(self, direction: FlexDirection) -> T {
211        if direction.is_row() {
212            self.height
213        } else {
214            self.width
215        }
216    }
217}
218
219impl Size<f32> {
220    /// A [`Size`] with zero width and height
221    pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
222}
223
224impl Size<Option<f32>> {
225    /// A [`Size`] with `None` width and height
226    pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
227
228    /// A [`Size<Option<f32>>`] with `Some(width)` and `Some(height)` as parameters
229    #[must_use]
230    pub const fn new(width: f32, height: f32) -> Self {
231        Size { width: Some(width), height: Some(height) }
232    }
233}
234
235impl Size<Dimension> {
236    /// Generates a [`Size<Dimension>`] using [`Dimension::Points`] values
237    #[must_use]
238    pub const fn from_points(width: f32, height: f32) -> Self {
239        Size { width: Dimension::Points(width), height: Dimension::Points(height) }
240    }
241
242    /// Generates a [`Size<Dimension>`] using [`Dimension::Percent`] values
243    #[must_use]
244    pub const fn from_percent(width: f32, height: f32) -> Self {
245        Size { width: Dimension::Percent(width), height: Dimension::Percent(height) }
246    }
247
248    /// Generates a [`Size<Dimension>`] using [`Dimension::Auto`] in both width and height
249    pub const AUTO: Size<Dimension> = Self { width: Dimension::Auto, height: Dimension::Auto };
250
251    /// Generates a [`Size<Dimension>`] using [`Dimension::Undefined`] in both width and height
252    pub const UNDEFINED: Size<Dimension> = Self { width: Dimension::Undefined, height: Dimension::Undefined };
253}
254
255/// A 2-dimensional coordinate.
256///
257/// When used in association with a [`Rect`], represents the bottom-left corner.
258#[derive(Debug, Copy, Clone, PartialEq, Eq)]
259pub struct Point<T> {
260    /// The x-coordinate
261    pub x: T,
262    /// The y-coordinate
263    pub y: T,
264}
265
266impl Point<f32> {
267    /// A [`Point`] with values (0,0), representing the origin
268    pub const ZERO: Point<f32> = Self { x: 0.0, y: 0.0 };
269}