1use core::fmt::Debug;
32use embedded_graphics::{geometry::AnchorPoint, prelude::Size, primitives::Rectangle};
33
34use crate::prelude::DeltaResize;
35
36use super::lw_geometry::{LwPoint, LwSize};
37
38#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
69pub struct LwRectangle<T, U> {
70 pub top_left: LwPoint<T>,
72 pub size: LwSize<U>,
74}
75
76impl<T, U> LwRectangle<T, U>
77where
78 T: Copy + Clone + Eq + PartialEq + Debug + Default,
79 U: Copy + Clone + Eq + PartialEq + Debug + Default,
80{
81 pub const fn new(top_left: LwPoint<T>, size: LwSize<U>) -> Self {
92 Self { top_left, size }
93 }
94}
95
96impl LwRectangle<i16, u16> {
97 pub fn center_scale(&self, horizontal_percent: u16, vertical_percent: u16) -> Self {
104 let scale_width_factor = horizontal_percent as i16 - 100;
105 let scale_height_factor = vertical_percent as i16 - 100;
106
107 let delta_width = (self.size.width as i32 * scale_width_factor as i32 / 100) as i16;
108 let delta_height = (self.size.height as i32 * scale_height_factor as i32 / 100) as i16;
109
110 let mut area = self.rectangle();
111 let (size, ap) = DeltaResize::Center(delta_width, delta_height).transform(&area.size);
112 area = area.resized(size, ap);
113
114 area.into()
115 }
116
117 pub fn delta_resize(&self, delta: DeltaResize) -> Self {
119 let area = self.rectangle();
120 let (size, ap) = delta.transform(&area.size);
121 area.resized(size, ap).into()
122 }
123
124 pub fn move_by(&self, dx: i16, dy: i16) -> Self {
126 Self {
127 top_left: self.top_left.offset(dx, dy),
128 size: self.size,
129 }
130 }
131
132 pub fn rectangle(&self) -> Rectangle {
134 (*self).into()
135 }
136
137 pub fn resized(&self, width: u16, height: u16, anchor_point: AnchorPoint) -> Self {
139 let size = Size::new(width as u32, height as u32);
140
141 self.rectangle().resized(size, anchor_point).into()
142 }
143}
144
145impl From<Rectangle> for LwRectangle<i8, u8> {
147 fn from(rect: Rectangle) -> Self {
148 Self {
149 top_left: rect.top_left.into(),
150 size: rect.size.into(),
151 }
152 }
153}
154
155impl From<Rectangle> for LwRectangle<i16, u16> {
157 fn from(rect: Rectangle) -> Self {
158 Self {
159 top_left: rect.top_left.into(),
160 size: rect.size.into(),
161 }
162 }
163}
164
165impl From<LwRectangle<i8, u8>> for Rectangle {
167 fn from(lw_rect: LwRectangle<i8, u8>) -> Self {
168 Rectangle::new(lw_rect.top_left.into(), lw_rect.size.into())
169 }
170}
171
172impl From<LwRectangle<i16, u16>> for Rectangle {
174 fn from(lw_rect: LwRectangle<i16, u16>) -> Self {
175 Rectangle::new(lw_rect.top_left.into(), lw_rect.size.into())
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use embedded_graphics::geometry::Point;
183 use embedded_graphics::geometry::Size;
184
185 #[test]
186 fn test_lw_rect_i8_u8_from_rectangle() {
187 let rect = Rectangle::new(Point::new(10, -20), Size::new(100, 200));
188 let lw_rect: LwRectangle<i8, u8> = rect.into();
189 assert_eq!(lw_rect.top_left.x, 10);
190 assert_eq!(lw_rect.top_left.y, -20);
191 assert_eq!(lw_rect.size.width, 100);
192 assert_eq!(lw_rect.size.height, 200);
193 }
194
195 #[test]
196 fn test_lw_rect_i8_u8_to_rectangle() {
197 let lw_rect = LwRectangle {
198 top_left: LwPoint { x: 5i8, y: -10i8 },
199 size: LwSize {
200 width: 50u8,
201 height: 100u8,
202 },
203 };
204 let rect: Rectangle = lw_rect.into();
205 assert_eq!(rect.top_left, Point::new(5, -10));
206 assert_eq!(rect.size, Size::new(50, 100));
207 }
208
209 #[test]
210 fn test_lw_rect_i16_u16_from_rectangle() {
211 let rect = Rectangle::new(Point::new(1000, -2000), Size::new(5000, 10000));
212 let lw_rect: LwRectangle<i16, u16> = rect.into();
213 assert_eq!(lw_rect.top_left.x, 1000);
214 assert_eq!(lw_rect.top_left.y, -2000);
215 assert_eq!(lw_rect.size.width, 5000);
216 assert_eq!(lw_rect.size.height, 10000);
217 }
218
219 #[test]
220 fn test_lw_rect_i16_u16_to_rectangle() {
221 let lw_rect = LwRectangle {
222 top_left: LwPoint {
223 x: 500i16,
224 y: -1000i16,
225 },
226 size: LwSize {
227 width: 500u16,
228 height: 1000u16,
229 },
230 };
231 let rect: Rectangle = lw_rect.into();
232 assert_eq!(rect.top_left, Point::new(500, -1000));
233 assert_eq!(rect.size, Size::new(500, 1000));
234 }
235
236 #[test]
237 fn test_lw_rect_i16_u16_large_value() {
238 let rect = Rectangle::new(
239 Point::new(i32::MAX, i32::MIN),
240 Size::new(u32::MAX, u32::MAX),
241 );
242 let lw_rect: LwRectangle<i16, u16> = rect.into();
243 assert_eq!(lw_rect.top_left.x, i16::MAX);
244 assert_eq!(lw_rect.top_left.y, i16::MIN);
245 assert_eq!(lw_rect.size.width, u16::MAX);
246 assert_eq!(lw_rect.size.height, u16::MAX);
247 }
248
249 #[test]
250 fn test_lw_rect_i8_u8_overflow() {
251 let rect = Rectangle::new(Point::new(200, -200), Size::new(300, 300));
252 let lw_rect: LwRectangle<i8, u8> = rect.into();
253 assert_eq!(lw_rect.top_left.x, 127);
254 assert_eq!(lw_rect.top_left.y, -128);
255 assert_eq!(lw_rect.size.width, u8::MAX);
256 assert_eq!(lw_rect.size.height, u8::MAX);
257 }
258
259 #[test]
260 fn test_lw_rect_zero() {
261 let rect = Rectangle::new(Point::new(0, 0), Size::new(0, 0));
262 let lw_rect_i8_u8: LwRectangle<i8, u8> = rect.into();
263 let lw_rect_i16_u16: LwRectangle<i16, u16> = rect.into();
264 assert_eq!(lw_rect_i8_u8.top_left.x, 0);
265 assert_eq!(lw_rect_i16_u16.size.width, 0);
266 }
267}