use embedded_graphics::geometry::AnchorPoint;
use embedded_graphics::geometry::Point;
use embedded_graphics::geometry::Size;
use saturating_cast::SaturatingCast;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct LwPoint<T> {
pub x: T,
pub y: T,
}
impl<T> LwPoint<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl LwPoint<i8> {
pub const fn offset(&self, dx: i8, dy: i8) -> Self {
Self {
x: self.x + dx,
y: self.y + dy,
}
}
}
impl LwPoint<i16> {
pub const fn offset(&self, dx: i16, dy: i16) -> Self {
Self {
x: self.x + dx,
y: self.y + dy,
}
}
}
impl From<Point> for LwPoint<i8> {
fn from(point: Point) -> Self {
Self {
x: point.x.saturating_cast(),
y: point.y.saturating_cast(),
}
}
}
impl From<Point> for LwPoint<i16> {
fn from(point: Point) -> Self {
Self {
x: point.x.saturating_cast(),
y: point.y.saturating_cast(),
}
}
}
impl From<LwPoint<i8>> for Point {
fn from(lw_point: LwPoint<i8>) -> Self {
Point::new(lw_point.x as i32, lw_point.y as i32)
}
}
impl From<LwPoint<i16>> for Point {
fn from(lw_point: LwPoint<i16>) -> Self {
Point::new(lw_point.x as i32, lw_point.y as i32)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct LwSize<T> {
pub width: T,
pub height: T,
}
impl<T> LwSize<T> {
pub const fn new(width: T, height: T) -> Self {
Self { width, height }
}
}
impl From<Size> for LwSize<u8> {
fn from(size: Size) -> Self {
Self {
width: size.width.saturating_cast(),
height: size.height.saturating_cast(),
}
}
}
impl From<Size> for LwSize<u16> {
fn from(size: Size) -> Self {
Self {
width: size.width.saturating_cast(),
height: size.height.saturating_cast(),
}
}
}
impl From<LwSize<u8>> for Size {
fn from(lw_size: LwSize<u8>) -> Self {
Size::new(lw_size.width as u32, lw_size.height as u32)
}
}
impl From<LwSize<u16>> for Size {
fn from(lw_size: LwSize<u16>) -> Self {
Size::new(lw_size.width as u32, lw_size.height as u32)
}
}
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
pub enum DeltaResize {
TopLeft(i16, i16),
TopCenter(i16, i16),
TopRight(i16, i16),
CenterLeft(i16, i16),
Center(i16, i16),
CenterRight(i16, i16),
BottomLeft(i16, i16),
BottomCenter(i16, i16),
BottomRight(i16, i16),
}
impl DeltaResize {
pub const fn unwrap(&self) -> (i32, i32, AnchorPoint) {
let (delta_w, delta_h, ap) = match *self {
DeltaResize::TopLeft(w, h) => (w, h, AnchorPoint::TopLeft),
DeltaResize::TopCenter(w, h) => (w, h, AnchorPoint::TopCenter),
DeltaResize::TopRight(w, h) => (w, h, AnchorPoint::TopRight),
DeltaResize::CenterLeft(w, h) => (w, h, AnchorPoint::CenterLeft),
DeltaResize::Center(w, h) => (w, h, AnchorPoint::Center),
DeltaResize::CenterRight(w, h) => (w, h, AnchorPoint::CenterRight),
DeltaResize::BottomLeft(w, h) => (w, h, AnchorPoint::BottomLeft),
DeltaResize::BottomCenter(w, h) => (w, h, AnchorPoint::BottomCenter),
DeltaResize::BottomRight(w, h) => (w, h, AnchorPoint::BottomRight),
};
(delta_w as i32, delta_h as i32, ap)
}
pub const fn transform(&self, size: &Size) -> (Size, AnchorPoint) {
let (delta_w, delta_h, anchor_point) = self.unwrap();
let width = size.width as i32 + delta_w;
let height = size.height as i32 + delta_h;
(Size::new(width as u32, height as u32), anchor_point)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lw_point_i8_from_point() {
let point = Point::new(10, -20);
let lw_point: LwPoint<i8> = point.into();
assert_eq!(lw_point.x, 10);
assert_eq!(lw_point.y, -20);
}
#[test]
fn test_lw_point_i8_to_point() {
let lw_point = LwPoint { x: 5i8, y: -10i8 };
let point: Point = lw_point.into();
assert_eq!(point, Point::new(5, -10));
}
#[test]
fn test_lw_point_i8_overflow() {
let point = Point::new(200, -200);
let lw_point: LwPoint<i8> = point.into();
assert_eq!(lw_point.x, 127);
assert_eq!(lw_point.y, -128);
}
#[test]
fn test_lw_point_i16_from_point() {
let point = Point::new(1000, -2000);
let lw_point: LwPoint<i16> = point.into();
assert_eq!(lw_point.x, 1000);
assert_eq!(lw_point.y, -2000);
}
#[test]
fn test_lw_point_i16_to_point() {
let lw_point = LwPoint {
x: 500i16,
y: -1000i16,
};
let point: Point = lw_point.into();
assert_eq!(point, Point::new(500, -1000));
}
#[test]
fn test_lw_point_i16_large_value() {
let point = Point::new(i32::MAX, i32::MIN);
let lw_point: LwPoint<i16> = point.into();
assert_eq!(lw_point.x, i16::MAX);
assert_eq!(lw_point.y, i16::MIN);
}
#[test]
fn test_lw_point_zero() {
let point = Point::new(0, 0);
let lw_point_i8: LwPoint<i8> = point.into();
let lw_point_i16: LwPoint<i16> = point.into();
assert_eq!(lw_point_i8.x, 0);
assert_eq!(lw_point_i16.y, 0);
}
#[test]
fn test_lw_point_into_i8() {
let point = Point::new(10, -20);
let lw_point: LwPoint<i8> = point.into();
assert_eq!(lw_point.x, 10);
assert_eq!(lw_point.y, -20);
}
#[test]
fn test_lw_point_into_i16() {
let point = Point::new(1000, -2000);
let lw_point: LwPoint<i16> = point.into();
assert_eq!(lw_point.x, 1000);
assert_eq!(lw_point.y, -2000);
}
#[test]
fn test_lw_point_from_i8() {
let lw_point = LwPoint { x: 5i8, y: -10i8 };
let point: Point = lw_point.into();
assert_eq!(point, Point::new(5, -10));
}
#[test]
fn test_lw_point_from_i16() {
let lw_point = LwPoint {
x: 500i16,
y: -1000i16,
};
let point: Point = lw_point.into();
assert_eq!(point, Point::new(500, -1000));
}
#[test]
fn test_lw_size_u8_from_size() {
let size = Size::new(100, 200);
let lw_size: LwSize<u8> = size.into();
assert_eq!(lw_size.width, 100);
assert_eq!(lw_size.height, 200);
}
#[test]
fn test_lw_size_u8_to_size() {
let lw_size = LwSize {
width: 50u8,
height: 100u8,
};
let size: Size = lw_size.into();
assert_eq!(size, Size::new(50, 100));
}
#[test]
fn test_lw_size_u8_overflow() {
let size = Size::new(300, 300);
let lw_size: LwSize<u8> = size.into();
assert_eq!(lw_size.width, u8::MAX);
assert_eq!(lw_size.height, u8::MAX);
}
#[test]
fn test_lw_size_u16_from_size() {
let size = Size::new(1000, 2000);
let lw_size: LwSize<u16> = size.into();
assert_eq!(lw_size.width, 1000);
assert_eq!(lw_size.height, 2000);
}
#[test]
fn test_lw_size_u16_to_size() {
let lw_size = LwSize {
width: 500u16,
height: 1000u16,
};
let size: Size = lw_size.into();
assert_eq!(size, Size::new(500, 1000));
}
#[test]
fn test_lw_size_u16_large_value() {
let size = Size::new(u32::MAX, u32::MAX);
let lw_size: LwSize<u16> = size.into();
assert_eq!(lw_size.width, u16::MAX);
assert_eq!(lw_size.height, u16::MAX);
}
#[test]
fn test_lw_size_zero() {
let size = Size::new(0, 0);
let lw_size_u8: LwSize<u8> = size.into();
let lw_size_u16: LwSize<u16> = size.into();
assert_eq!(lw_size_u8.width, 0);
assert_eq!(lw_size_u16.height, 0);
}
}