gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 684HTML 640Markdown 12TOML 62286 Definiciones

⎇ 0.1.x src/geometry.rs Rust · 260 líneas · 7.8 KB Historia Quién tocó qué crudo

Document entire crate (#96) de9123e02 · Alice Cecile ·

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