embedded_layout/align/vertical/
mod.rs1use crate::align::{Alignment, VerticalAlignment};
5use embedded_graphics::{geometry::AnchorPoint, primitives::Rectangle};
6
7#[derive(Copy, Clone, Default)]
9pub struct NoAlignment;
10impl VerticalAlignment for NoAlignment {}
11
12impl Alignment for NoAlignment {
13 #[inline]
14 fn align_with_offset(&self, _object: Rectangle, _reference: Rectangle, _offset: i32) -> i32 {
15 0
16 }
17}
18
19#[derive(Copy, Clone, Default)]
24pub struct Center;
25impl VerticalAlignment for Center {}
26
27impl Alignment for Center {
28 #[inline]
29 fn align_with_offset(&self, object: Rectangle, reference: Rectangle, offset: i32) -> i32 {
30 reference.anchor_point(AnchorPoint::Center).y - object.anchor_point(AnchorPoint::Center).y
31 + offset
32 }
33}
34
35#[derive(Copy, Clone, Default)]
37pub struct Top;
38impl VerticalAlignment for Top {}
39
40impl Alignment for Top {
41 #[inline]
42 fn align_with_offset(&self, object: Rectangle, reference: Rectangle, offset: i32) -> i32 {
43 reference.top_left.y - object.top_left.y + offset
44 }
45}
46
47#[derive(Copy, Clone, Default)]
49pub struct Bottom;
50impl VerticalAlignment for Bottom {}
51
52impl Alignment for Bottom {
53 #[inline]
54 fn align_with_offset(&self, object: Rectangle, reference: Rectangle, offset: i32) -> i32 {
55 reference.anchor_point(AnchorPoint::BottomRight).y
56 - object.anchor_point(AnchorPoint::BottomRight).y
57 + offset
58 }
59}
60
61#[derive(Copy, Clone, Default)]
63pub struct TopToBottom;
64impl VerticalAlignment for TopToBottom {}
65
66impl Alignment for TopToBottom {
67 #[inline]
68 fn align_with_offset(&self, object: Rectangle, reference: Rectangle, offset: i32) -> i32 {
69 let offset = if object.size.height == 0 {
70 offset
71 } else {
72 offset + 1
73 };
74 reference.anchor_point(AnchorPoint::BottomRight).y - object.top_left.y + offset
75 }
76}
77
78#[derive(Copy, Clone, Default)]
80pub struct BottomToTop;
81impl VerticalAlignment for BottomToTop {}
82
83impl Alignment for BottomToTop {
84 #[inline]
85 fn align_with_offset(&self, object: Rectangle, reference: Rectangle, offset: i32) -> i32 {
86 let offset = if object.size.height == 0 {
87 offset
88 } else {
89 offset - 1
90 };
91 reference.top_left.y - object.anchor_point(AnchorPoint::BottomRight).y + offset
92 }
93}
94
95#[cfg(test)]
96mod test {
97 use crate::prelude::*;
98 use embedded_graphics::{
99 geometry::{AnchorPoint, Point},
100 prelude::Size,
101 primitives::Rectangle,
102 };
103
104 #[test]
105 fn test_center() {
106 fn check_center_alignment(source: Rectangle, reference: Rectangle, result: Rectangle) {
107 let center_of_reference = reference.top_left + reference.size() / 2;
108 let center_of_result = result.top_left + result.size() / 2;
109
110 assert_eq!(result.size(), source.size());
112
113 assert_eq!(center_of_result.y, center_of_reference.y);
115
116 assert_eq!(result.top_left.x, source.top_left.x);
118 }
119
120 let rect1 = Rectangle::with_corners(Point::new(0, 0), Point::new(10, 10));
121 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
122
123 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::Center);
124 check_center_alignment(rect1, rect2, result);
125
126 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::Center);
129 check_center_alignment(rect2, rect1, result);
130 }
131
132 #[test]
133 fn test_top() {
134 fn check_top_alignment(source: Rectangle, reference: Rectangle, result: Rectangle) {
135 assert_eq!(result.size(), source.size());
137
138 assert_eq!(result.top_left.y, reference.top_left.y);
140
141 assert_eq!(result.top_left.x, source.top_left.x);
143 }
144
145 let rect1 = Rectangle::with_corners(Point::new(0, 0), Point::new(10, 10));
146 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
147
148 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::Top);
149 check_top_alignment(rect1, rect2, result);
150
151 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::Top);
153 check_top_alignment(rect2, rect1, result);
154 }
155
156 #[test]
157 fn test_bottom() {
158 fn check_bottom_alignment(source: Rectangle, reference: Rectangle, result: Rectangle) {
159 assert_eq!(result.size(), source.size());
161
162 assert_eq!(
164 result.anchor_point(AnchorPoint::BottomRight).y,
165 reference.anchor_point(AnchorPoint::BottomRight).y
166 );
167
168 assert_eq!(
170 result.anchor_point(AnchorPoint::BottomRight).x,
171 source.anchor_point(AnchorPoint::BottomRight).x
172 );
173 }
174
175 let rect1 = Rectangle::with_corners(Point::new(0, 0), Point::new(10, 10));
176 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
177
178 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::Bottom);
179 check_bottom_alignment(rect1, rect2, result);
180
181 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::Bottom);
183 check_bottom_alignment(rect2, rect1, result);
184 }
185
186 #[test]
187 fn test_top_to_bottom() {
188 let rect1 = Rectangle::with_corners(Point::new(0, 0), Point::new(10, 10));
189 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
190
191 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::TopToBottom);
192 assert_eq!(result.size(), rect1.size());
194
195 assert_eq!(
197 result.top_left.y,
198 rect2.anchor_point(AnchorPoint::BottomRight).y + 1
199 );
200
201 assert_eq!(
203 result.anchor_point(AnchorPoint::BottomRight).x,
204 rect1.anchor_point(AnchorPoint::BottomRight).x
205 );
206
207 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::TopToBottom);
209 assert_eq!(result.size(), rect2.size());
211
212 assert_eq!(
214 result.top_left.y,
215 rect1.anchor_point(AnchorPoint::BottomRight).y + 1
216 );
217
218 assert_eq!(
220 result.anchor_point(AnchorPoint::BottomRight).x,
221 rect2.anchor_point(AnchorPoint::BottomRight).x
222 );
223 }
224
225 #[test]
226 fn test_top_to_bottom_empty() {
227 let rect1 = Rectangle::new(Point::new(0, 0), Size::zero());
228 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
229
230 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::TopToBottom);
231 assert_eq!(result.size(), rect1.size());
233
234 assert_eq!(
236 result.top_left.y,
237 rect2.anchor_point(AnchorPoint::BottomRight).y
238 );
239
240 assert_eq!(
242 result.anchor_point(AnchorPoint::BottomRight).x,
243 rect1.anchor_point(AnchorPoint::BottomRight).x
244 );
245
246 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::TopToBottom);
248 assert_eq!(result.size(), rect2.size());
250
251 assert_eq!(
253 result.top_left.y,
254 rect1.anchor_point(AnchorPoint::BottomRight).y + 1
255 );
256
257 assert_eq!(
259 result.anchor_point(AnchorPoint::BottomRight).x,
260 rect2.anchor_point(AnchorPoint::BottomRight).x
261 );
262 }
263
264 #[test]
265 fn test_bottom_to_top() {
266 let rect1 = Rectangle::with_corners(Point::new(0, 0), Point::new(10, 10));
267 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
268
269 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::BottomToTop);
270 assert_eq!(result.size(), rect1.size());
272
273 assert_eq!(
275 result.anchor_point(AnchorPoint::BottomRight).y,
276 rect2.top_left.y - 1
277 );
278
279 assert_eq!(
281 result.anchor_point(AnchorPoint::BottomRight).x,
282 rect1.anchor_point(AnchorPoint::BottomRight).x
283 );
284
285 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::BottomToTop);
287 assert_eq!(result.size(), rect2.size());
289
290 assert_eq!(
292 result.anchor_point(AnchorPoint::BottomRight).y,
293 rect1.top_left.y - 1
294 );
295
296 assert_eq!(
298 result.anchor_point(AnchorPoint::BottomRight).x,
299 rect2.anchor_point(AnchorPoint::BottomRight).x
300 );
301 }
302
303 #[test]
304 fn test_bottom_to_top_empty() {
305 let rect1 = Rectangle::new(Point::new(0, 0), Size::zero());
306 let rect2 = Rectangle::with_corners(Point::new(30, 20), Point::new(40, 50));
307
308 let result = rect1.align_to(&rect2, horizontal::NoAlignment, vertical::BottomToTop);
309 assert_eq!(result.size(), rect1.size());
311
312 assert_eq!(
314 result.anchor_point(AnchorPoint::BottomRight).y,
315 rect2.top_left.y
316 );
317
318 assert_eq!(
320 result.anchor_point(AnchorPoint::BottomRight).x,
321 rect1.anchor_point(AnchorPoint::BottomRight).x
322 );
323
324 let result = rect2.align_to(&rect1, horizontal::NoAlignment, vertical::BottomToTop);
326 assert_eq!(result.size(), rect2.size());
328
329 assert_eq!(
331 result.anchor_point(AnchorPoint::BottomRight).y,
332 rect1.top_left.y - 1
333 );
334
335 assert_eq!(
337 result.anchor_point(AnchorPoint::BottomRight).x,
338 rect2.anchor_point(AnchorPoint::BottomRight).x
339 );
340 }
341}