1use num_traits::Float;
4use std::borrow::Borrow;
5use strum_macros::EnumString;
6
7use crate::geometry::Size;
8
9pub mod algorithm;
11mod tree;
12
13pub use algorithm::Algorithm;
14pub use tree::{Layout, LayoutNode, LayoutTree, MeasureFunc};
15
16#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
18pub struct LayoutAnchor<T>
19where
20 T: Float,
21{
22 x: T,
23 y: T,
24}
25
26impl<T> LayoutAnchor<T>
27where
28 T: Float,
29{
30 pub fn new(x: T, y: T) -> LayoutAnchor<T> {
33 LayoutAnchor { x, y }
34 }
35
36 pub fn distance(self, other: Self) -> LayoutDistance<T> {
38 LayoutDistance {
39 dx: other.borrow().x - self.x,
40 dy: other.borrow().y - self.y,
41 }
42 }
43}
44
45#[derive(Copy, Clone, Debug, Eq, PartialEq, EnumString)]
48pub enum LayoutDirection {
49 #[strum(serialize = "ltr")]
52 LTR,
53
54 #[strum(serialize = "rtl")]
56 RTL,
57}
58
59#[derive(Copy, Clone, Debug, Eq, PartialEq)]
61pub enum LayoutAxisX<T> {
62 DirectionDependent {
64 leading: T,
67
68 trailing: T,
71 },
72
73 DirectionIndependent {
75 left: T,
78
79 right: T,
82 },
83}
84
85impl<T> LayoutAxisX<T> {
86 pub fn dependent(leading: T, trailing: T) -> LayoutAxisX<T> {
89 LayoutAxisX::DirectionDependent { leading, trailing }
90 }
91
92 pub fn independent(left: T, right: T) -> LayoutAxisX<T> {
95 LayoutAxisX::DirectionIndependent { left, right }
96 }
97
98 pub fn left(&self, direction: LayoutDirection) -> &T {
101 match self {
102 LayoutAxisX::DirectionDependent { leading, trailing } => match direction {
103 LayoutDirection::LTR => leading,
104 LayoutDirection::RTL => trailing,
105 },
106 LayoutAxisX::DirectionIndependent { left, .. } => left,
107 }
108 }
109
110 pub fn right(&self, direction: LayoutDirection) -> &T {
113 match self {
114 LayoutAxisX::DirectionDependent { leading, trailing } => match direction {
115 LayoutDirection::LTR => trailing,
116 LayoutDirection::RTL => leading,
117 },
118 LayoutAxisX::DirectionIndependent { right, .. } => right,
119 }
120 }
121}
122
123impl<T> Default for LayoutAxisX<T>
124where
125 T: Default,
126{
127 fn default() -> Self {
128 LayoutAxisX::DirectionIndependent {
129 left: T::default(),
130 right: T::default(),
131 }
132 }
133}
134
135#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
137pub struct LayoutAxisY<T> {
138 pub top: T,
140
141 pub bottom: T,
143}
144
145#[derive(Copy, Clone, Debug, Eq, PartialEq)]
147pub struct LayoutGuide<T>
148where
149 T: Float,
150{
151 origin: LayoutAnchor<T>,
152 size: Size<T>,
153 direction: LayoutDirection,
154}
155
156impl<T> LayoutGuide<T>
157where
158 T: Float,
159{
160 pub fn new(
163 origin: LayoutAnchor<T>,
164 size: Size<T>,
165 direction: LayoutDirection,
166 ) -> LayoutGuide<T> {
167 LayoutGuide {
168 origin,
169 size,
170 direction,
171 }
172 }
173
174 pub fn top_left(&self) -> LayoutAnchor<T> {
176 self.origin
177 }
178
179 pub fn top_right(&self) -> LayoutAnchor<T> {
181 let mut anchor = self.origin;
182 anchor.x = anchor.x + self.size.width;
183 anchor
184 }
185
186 pub fn top_leading(&self) -> LayoutAnchor<T> {
190 match self.direction {
191 LayoutDirection::LTR => self.top_left(),
192 LayoutDirection::RTL => self.top_right(),
193 }
194 }
195
196 pub fn top_trailing(&self) -> LayoutAnchor<T> {
200 match self.direction {
201 LayoutDirection::LTR => self.top_right(),
202 LayoutDirection::RTL => self.top_left(),
203 }
204 }
205
206 pub fn bottom_left(&self) -> LayoutAnchor<T> {
208 let mut anchor = self.origin;
209 anchor.y = anchor.y + self.size.height;
210 anchor
211 }
212
213 pub fn bottom_right(&self) -> LayoutAnchor<T> {
215 let mut anchor = self.origin;
216 anchor.x = anchor.x + self.size.width;
217 anchor.y = anchor.y + self.size.height;
218 anchor
219 }
220
221 pub fn bottom_leading(&self) -> LayoutAnchor<T> {
225 match self.direction {
226 LayoutDirection::LTR => self.bottom_left(),
227 LayoutDirection::RTL => self.bottom_right(),
228 }
229 }
230
231 pub fn bottom_trailing(&self) -> LayoutAnchor<T> {
235 match self.direction {
236 LayoutDirection::LTR => self.bottom_right(),
237 LayoutDirection::RTL => self.bottom_left(),
238 }
239 }
240}
241
242#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
244pub struct LayoutDistance<T> {
245 dx: T,
246 dy: T,
247}
248
249impl<T> LayoutDistance<T>
250where
251 T: Float,
252{
253 pub fn l1_norm(&self) -> T
255 where
256 T: Float,
257 {
258 self.dx.abs() + self.dy.abs()
259 }
260
261 pub fn l2_norm(&self) -> T {
263 self.dx * self.dx + self.dy * self.dy
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::LayoutAnchor;
270
271 #[test]
272 fn test_l1_norm() {
273 let a = LayoutAnchor::new(4.0, -42.0);
274 let b = LayoutAnchor::new(-2.0, -8.0);
275
276 assert_eq!(a.distance(b).l1_norm(), 40.0);
277 assert_eq!(b.distance(a).l1_norm(), 40.0);
278 }
279
280 #[test]
281 fn test_l2_norm() {
282 let a = LayoutAnchor::new(4.0, -42.0);
283 let b = LayoutAnchor::new(-2.0, -8.0);
284
285 assert_eq!(a.distance(b).l2_norm(), 1192.0);
286 assert_eq!(b.distance(a).l2_norm(), 1192.0);
287 }
288}