use core::convert::TryFrom;
use tiny_skia_path::{IntRect, IntSize, Rect};
use crate::LengthU32;
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct ScreenIntRect {
x: u32,
y: u32,
width: LengthU32,
height: LengthU32,
}
impl ScreenIntRect {
pub fn from_xywh(x: u32, y: u32, width: u32, height: u32) -> Option<Self> {
i32::try_from(x).ok()?;
i32::try_from(y).ok()?;
i32::try_from(width).ok()?;
i32::try_from(height).ok()?;
x.checked_add(width)?;
y.checked_add(height)?;
let width = LengthU32::new(width)?;
let height = LengthU32::new(height)?;
Some(ScreenIntRect {
x,
y,
width,
height,
})
}
pub const fn from_xywh_safe(x: u32, y: u32, width: LengthU32, height: LengthU32) -> Self {
ScreenIntRect {
x,
y,
width,
height,
}
}
pub fn x(&self) -> u32 {
self.x
}
pub fn y(&self) -> u32 {
self.y
}
pub fn width(&self) -> u32 {
self.width.get()
}
pub fn height(&self) -> u32 {
self.height.get()
}
pub fn width_safe(&self) -> LengthU32 {
self.width
}
pub fn left(&self) -> u32 {
self.x
}
pub fn top(&self) -> u32 {
self.y
}
pub fn right(&self) -> u32 {
self.x + self.width.get()
}
pub fn bottom(&self) -> u32 {
self.y + self.height.get()
}
pub fn size(&self) -> IntSize {
IntSize::from_wh(self.width(), self.height()).unwrap()
}
pub fn contains(&self, other: &Self) -> bool {
self.x <= other.x
&& self.y <= other.y
&& self.right() >= other.right()
&& self.bottom() >= other.bottom()
}
pub fn to_int_rect(&self) -> IntRect {
IntRect::from_xywh(
self.x as i32,
self.y as i32,
self.width.get(),
self.height.get(),
)
.unwrap()
}
pub fn to_rect(&self) -> Rect {
Rect::from_ltrb(
self.x as f32,
self.y as f32,
self.x as f32 + self.width.get() as f32,
self.y as f32 + self.height.get() as f32,
)
.unwrap()
}
}
#[cfg(test)]
mod screen_int_rect_tests {
use super::*;
#[test]
fn tests() {
assert_eq!(ScreenIntRect::from_xywh(0, 0, 0, 0), None);
assert_eq!(ScreenIntRect::from_xywh(0, 0, 1, 0), None);
assert_eq!(ScreenIntRect::from_xywh(0, 0, 0, 1), None);
assert_eq!(ScreenIntRect::from_xywh(0, 0, u32::MAX, u32::MAX), None);
assert_eq!(ScreenIntRect::from_xywh(0, 0, 1, u32::MAX), None);
assert_eq!(ScreenIntRect::from_xywh(0, 0, u32::MAX, 1), None);
assert_eq!(ScreenIntRect::from_xywh(u32::MAX, 0, 1, 1), None);
assert_eq!(ScreenIntRect::from_xywh(0, u32::MAX, 1, 1), None);
assert_eq!(
ScreenIntRect::from_xywh(u32::MAX, u32::MAX, u32::MAX, u32::MAX),
None
);
let r = ScreenIntRect::from_xywh(1, 2, 3, 4).unwrap();
assert_eq!(r.x(), 1);
assert_eq!(r.y(), 2);
assert_eq!(r.width(), 3);
assert_eq!(r.height(), 4);
assert_eq!(r.right(), 4);
assert_eq!(r.bottom(), 6);
}
}
pub trait IntSizeExt {
fn to_screen_int_rect(&self, x: u32, y: u32) -> ScreenIntRect;
}
impl IntSizeExt for IntSize {
fn to_screen_int_rect(&self, x: u32, y: u32) -> ScreenIntRect {
ScreenIntRect::from_xywh(x, y, self.width(), self.height()).unwrap()
}
}
pub trait IntRectExt {
fn to_screen_int_rect(&self) -> Option<ScreenIntRect>;
}
impl IntRectExt for IntRect {
fn to_screen_int_rect(&self) -> Option<ScreenIntRect> {
let x = u32::try_from(self.x()).ok()?;
let y = u32::try_from(self.y()).ok()?;
ScreenIntRect::from_xywh(x, y, self.width(), self.height())
}
}