polyhorn_ui/
geometry.rs

1//! Primitives to work with concrete geometry.
2
3use std::ops::{Deref, DerefMut};
4use strum_macros::EnumString;
5
6use crate::layout::{LayoutAxisX, LayoutAxisY};
7
8/// Simple wrapper around the coordinates of a 2D object.
9#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
10pub struct Point<T> {
11    /// This is the horizontal coordinate of this point.
12    pub x: T,
13
14    /// This is the vertical coordinate of this point.
15    pub y: T,
16}
17
18impl<T> Point<T> {
19    /// Returns a new point with the given coordinates.
20    pub const fn new(x: T, y: T) -> Point<T> {
21        Point { x, y }
22    }
23}
24
25/// Simple wrapper around the horizontal and vertical dimensions of a 2D object.
26#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
27pub struct Size<T> {
28    /// This is the horizontal component of a size.
29    pub width: T,
30
31    /// This is the vertical component of a size.
32    pub height: T,
33}
34
35impl<T> Size<T> {
36    /// Returns a new size with the given width and height.
37    pub const fn new(width: T, height: T) -> Size<T> {
38        Size { width, height }
39    }
40}
41
42/// Represents an absolute or relative dimension.
43#[derive(Copy, Clone, Debug, Eq, PartialEq, EnumString)]
44pub enum Dimension<T> {
45    /// This is the default value for a dimension and resembles
46    /// `Dimension:::Points(0.0)` and `Dimension::Percentage(0.0)`.
47    #[strum(serialize = "undefined")]
48    Undefined,
49
50    /// Depending on the property that this dimension is used to, this value may
51    /// have a special meaning. Otherwise, it's similar to
52    /// `Dimension::Undefined`.
53    #[strum(serialize = "auto")]
54    Auto,
55
56    /// This is a dimension expressed in absolute units, where each unit
57    /// represents a single pixel.
58    #[strum(disabled)]
59    Points(T),
60
61    /// This is a dimension expressed in relative units, where 1.0 represents
62    /// 100%.
63    #[strum(disabled)]
64    Percentage(T),
65}
66
67impl<T> Default for Dimension<T> {
68    fn default() -> Self {
69        Dimension::Undefined
70    }
71}
72
73/// This is a wrapper that contains a value of the given type for each corner of
74/// a rectangle.
75///
76/// ```rust
77/// use polyhorn_ui::geometry::ByCorner;
78/// use polyhorn_ui::layout::{LayoutAxisX, LayoutDirection};
79///
80/// let mut by_corner = ByCorner::<f32>::default();
81/// by_corner.top = LayoutAxisX::dependent(10.0, 30.0);
82///
83/// assert_eq!(by_corner.top.left(LayoutDirection::LTR), &10.0);
84/// assert_eq!(by_corner.top.left(LayoutDirection::RTL), &30.0);
85/// ```
86#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
87pub struct ByCorner<T> {
88    /// This is a nested field that contains a potentially layout direction
89    /// dependent horizontal axis in a layout direction independent vertical
90    /// axis.
91    pub all: LayoutAxisY<LayoutAxisX<T>>,
92}
93
94impl<T> ByCorner<T> {
95    /// Applies the given operation to every element of this structure and
96    /// returns the result. The operation does not necessarily have to return
97    /// a value of the same type.
98    pub fn map<F, O>(self, mut op: F) -> ByCorner<O>
99    where
100        F: FnMut(T) -> O,
101    {
102        ByCorner {
103            all: LayoutAxisY {
104                top: match self.all.top {
105                    LayoutAxisX::DirectionDependent { leading, trailing } => {
106                        LayoutAxisX::DirectionDependent {
107                            leading: op(leading),
108                            trailing: op(trailing),
109                        }
110                    }
111                    LayoutAxisX::DirectionIndependent { left, right } => {
112                        LayoutAxisX::DirectionIndependent {
113                            left: op(left),
114                            right: op(right),
115                        }
116                    }
117                },
118                bottom: match self.all.bottom {
119                    LayoutAxisX::DirectionDependent { leading, trailing } => {
120                        LayoutAxisX::DirectionDependent {
121                            leading: op(leading),
122                            trailing: op(trailing),
123                        }
124                    }
125                    LayoutAxisX::DirectionIndependent { left, right } => {
126                        LayoutAxisX::DirectionIndependent {
127                            left: op(left),
128                            right: op(right),
129                        }
130                    }
131                },
132            },
133        }
134    }
135}
136
137impl<T> Deref for ByCorner<T> {
138    type Target = LayoutAxisY<LayoutAxisX<T>>;
139
140    fn deref(&self) -> &Self::Target {
141        &self.all
142    }
143}
144
145impl<T> DerefMut for ByCorner<T> {
146    fn deref_mut(&mut self) -> &mut Self::Target {
147        &mut self.all
148    }
149}
150
151/// This is a wrapper that contains a value of the given type for each direction
152/// (i.e. horizontal and vertical).
153#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
154pub struct ByDirection<T> {
155    /// This field contains a value of the given type for the horizontal
156    /// dimension.
157    pub horizontal: T,
158
159    /// This field contains a value of the given type for the vertical
160    /// dimension.
161    pub vertical: T,
162}
163
164impl<T> ByDirection<T>
165where
166    T: Copy,
167{
168    /// Returns a new `ByDirection` with the given value of both horizontal and
169    /// vertical directions.
170    pub fn with_both(value: T) -> ByDirection<T> {
171        ByDirection {
172            horizontal: value,
173            vertical: value,
174        }
175    }
176}
177
178/// This is a wrapper that contains a value of the given type for each edge of a
179/// rectangle.
180#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
181pub struct ByEdge<T> {
182    /// This field contains the horizontal edges (i.e. either left and right, or
183    /// leading and trailing edges).
184    pub horizontal: LayoutAxisX<T>,
185
186    /// This field contains the vertical edges (i.e. top and bottom).
187    pub vertical: LayoutAxisY<T>,
188}