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}