use core::fmt::Debug;
use embedded_graphics::{geometry::AnchorPoint, prelude::Size, primitives::Rectangle};
use crate::prelude::DeltaResize;
use super::lw_geometry::{LwPoint, LwSize};
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub struct LwRectangle<T, U> {
pub top_left: LwPoint<T>,
pub size: LwSize<U>,
}
impl<T, U> LwRectangle<T, U>
where
T: Copy + Clone + Eq + PartialEq + Debug + Default,
U: Copy + Clone + Eq + PartialEq + Debug + Default,
{
pub const fn new(top_left: LwPoint<T>, size: LwSize<U>) -> Self {
Self { top_left, size }
}
}
impl LwRectangle<i16, u16> {
pub fn center_scale(&self, horizontal_percent: u16, vertical_percent: u16) -> Self {
let scale_width_factor = horizontal_percent as i16 - 100;
let scale_height_factor = vertical_percent as i16 - 100;
let delta_width = (self.size.width as i32 * scale_width_factor as i32 / 100) as i16;
let delta_height = (self.size.height as i32 * scale_height_factor as i32 / 100) as i16;
let mut area = self.rectangle();
let (size, ap) = DeltaResize::Center(delta_width, delta_height).transform(&area.size);
area = area.resized(size, ap);
area.into()
}
pub fn delta_resize(&self, delta: DeltaResize) -> Self {
let area = self.rectangle();
let (size, ap) = delta.transform(&area.size);
area.resized(size, ap).into()
}
pub fn move_by(&self, dx: i16, dy: i16) -> Self {
Self {
top_left: self.top_left.offset(dx, dy),
size: self.size,
}
}
pub fn rectangle(&self) -> Rectangle {
(*self).into()
}
pub fn resized(&self, width: u16, height: u16, anchor_point: AnchorPoint) -> Self {
let size = Size::new(width as u32, height as u32);
self.rectangle().resized(size, anchor_point).into()
}
}
impl From<Rectangle> for LwRectangle<i8, u8> {
fn from(rect: Rectangle) -> Self {
Self {
top_left: rect.top_left.into(),
size: rect.size.into(),
}
}
}
impl From<Rectangle> for LwRectangle<i16, u16> {
fn from(rect: Rectangle) -> Self {
Self {
top_left: rect.top_left.into(),
size: rect.size.into(),
}
}
}
impl From<LwRectangle<i8, u8>> for Rectangle {
fn from(lw_rect: LwRectangle<i8, u8>) -> Self {
Rectangle::new(lw_rect.top_left.into(), lw_rect.size.into())
}
}
impl From<LwRectangle<i16, u16>> for Rectangle {
fn from(lw_rect: LwRectangle<i16, u16>) -> Self {
Rectangle::new(lw_rect.top_left.into(), lw_rect.size.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use embedded_graphics::geometry::Point;
use embedded_graphics::geometry::Size;
#[test]
fn test_lw_rect_i8_u8_from_rectangle() {
let rect = Rectangle::new(Point::new(10, -20), Size::new(100, 200));
let lw_rect: LwRectangle<i8, u8> = rect.into();
assert_eq!(lw_rect.top_left.x, 10);
assert_eq!(lw_rect.top_left.y, -20);
assert_eq!(lw_rect.size.width, 100);
assert_eq!(lw_rect.size.height, 200);
}
#[test]
fn test_lw_rect_i8_u8_to_rectangle() {
let lw_rect = LwRectangle {
top_left: LwPoint { x: 5i8, y: -10i8 },
size: LwSize {
width: 50u8,
height: 100u8,
},
};
let rect: Rectangle = lw_rect.into();
assert_eq!(rect.top_left, Point::new(5, -10));
assert_eq!(rect.size, Size::new(50, 100));
}
#[test]
fn test_lw_rect_i16_u16_from_rectangle() {
let rect = Rectangle::new(Point::new(1000, -2000), Size::new(5000, 10000));
let lw_rect: LwRectangle<i16, u16> = rect.into();
assert_eq!(lw_rect.top_left.x, 1000);
assert_eq!(lw_rect.top_left.y, -2000);
assert_eq!(lw_rect.size.width, 5000);
assert_eq!(lw_rect.size.height, 10000);
}
#[test]
fn test_lw_rect_i16_u16_to_rectangle() {
let lw_rect = LwRectangle {
top_left: LwPoint {
x: 500i16,
y: -1000i16,
},
size: LwSize {
width: 500u16,
height: 1000u16,
},
};
let rect: Rectangle = lw_rect.into();
assert_eq!(rect.top_left, Point::new(500, -1000));
assert_eq!(rect.size, Size::new(500, 1000));
}
#[test]
fn test_lw_rect_i16_u16_large_value() {
let rect = Rectangle::new(
Point::new(i32::MAX, i32::MIN),
Size::new(u32::MAX, u32::MAX),
);
let lw_rect: LwRectangle<i16, u16> = rect.into();
assert_eq!(lw_rect.top_left.x, i16::MAX);
assert_eq!(lw_rect.top_left.y, i16::MIN);
assert_eq!(lw_rect.size.width, u16::MAX);
assert_eq!(lw_rect.size.height, u16::MAX);
}
#[test]
fn test_lw_rect_i8_u8_overflow() {
let rect = Rectangle::new(Point::new(200, -200), Size::new(300, 300));
let lw_rect: LwRectangle<i8, u8> = rect.into();
assert_eq!(lw_rect.top_left.x, 127);
assert_eq!(lw_rect.top_left.y, -128);
assert_eq!(lw_rect.size.width, u8::MAX);
assert_eq!(lw_rect.size.height, u8::MAX);
}
#[test]
fn test_lw_rect_zero() {
let rect = Rectangle::new(Point::new(0, 0), Size::new(0, 0));
let lw_rect_i8_u8: LwRectangle<i8, u8> = rect.into();
let lw_rect_i16_u16: LwRectangle<i16, u16> = rect.into();
assert_eq!(lw_rect_i8_u8.top_left.x, 0);
assert_eq!(lw_rect_i16_u16.size.width, 0);
}
}