use core::fmt::Debug; use derive_more::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; use refineable::Refineable; use std::{ cmp::{self, PartialOrd}, fmt, ops::{Add, Div, Mul, MulAssign, Sub}, }; #[derive(Refineable, Default, Add, AddAssign, Sub, SubAssign, Copy, Debug, PartialEq, Eq, Hash)] #[refineable(debug)] #[repr(C)] pub struct Point { pub x: T, pub y: T, } pub fn point(x: T, y: T) -> Point { Point { x, y } } impl Point { pub fn new(x: T, y: T) -> Self { Self { x, y } } pub fn map(&self, f: impl Fn(T) -> U) -> Point { Point { x: f(self.x.clone()), y: f(self.y.clone()), } } } impl Point { pub fn scale(&self, factor: f32) -> Point { Point { x: self.x.scale(factor), y: self.y.scale(factor), } } } impl Mul for Point where T: Mul + Clone + Default + Debug, Rhs: Clone + Debug, { type Output = Point; fn mul(self, rhs: Rhs) -> Self::Output { Point { x: self.x * rhs.clone(), y: self.y * rhs, } } } impl MulAssign for Point where T: Clone + Mul + Default + Debug, S: Clone, { fn mul_assign(&mut self, rhs: S) { self.x = self.x.clone() * rhs.clone(); self.y = self.y.clone() * rhs; } } impl Div for Point where T: Div + Clone + Default + Debug, S: Clone, { type Output = Self; fn div(self, rhs: S) -> Self::Output { Self { x: self.x / rhs.clone(), y: self.y / rhs, } } } impl Point where T: PartialOrd + Clone + Default + Debug, { pub fn max(&self, other: &Self) -> Self { Point { x: if self.x >= other.x { self.x.clone() } else { other.x.clone() }, y: if self.y >= other.y { self.y.clone() } else { other.y.clone() }, } } pub fn min(&self, other: &Self) -> Self { Point { x: if self.x <= other.x { self.x.clone() } else { other.x.clone() }, y: if self.y <= other.y { self.y.clone() } else { other.y.clone() }, } } } impl Clone for Point { fn clone(&self) -> Self { Self { x: self.x.clone(), y: self.y.clone(), } } } #[derive(Refineable, Default, Clone, Copy, PartialEq, Div, Hash)] #[refineable(debug)] #[repr(C)] pub struct Size { pub width: T, pub height: T, } pub fn size(width: T, height: T) -> Size where T: Clone + Default + Debug, { Size { width, height } } impl Size where T: Clone + Default + Debug, { pub fn map(&self, f: impl Fn(T) -> U) -> Size where U: Clone + Default + Debug, { Size { width: f(self.width.clone()), height: f(self.height.clone()), } } } impl Size { pub fn scale(&self, factor: f32) -> Size { Size { width: self.width.scale(factor), height: self.height.scale(factor), } } } impl Size where T: PartialOrd + Clone + Default + Debug, { pub fn max(&self, other: &Self) -> Self { Size { width: if self.width >= other.width { self.width.clone() } else { other.width.clone() }, height: if self.height >= other.height { self.height.clone() } else { other.height.clone() }, } } } impl Sub for Size where T: Sub + Clone + Default + Debug, { type Output = Size; fn sub(self, rhs: Self) -> Self::Output { Size { width: self.width - rhs.width, height: self.height - rhs.height, } } } impl Mul for Size where T: Mul + Clone + Default + Debug, Rhs: Clone + Default + Debug, { type Output = Size; fn mul(self, rhs: Rhs) -> Self::Output { Size { width: self.width * rhs.clone(), height: self.height * rhs, } } } impl MulAssign for Size where T: Mul + Clone + Default + Debug, S: Clone, { fn mul_assign(&mut self, rhs: S) { self.width = self.width.clone() * rhs.clone(); self.height = self.height.clone() * rhs; } } impl Eq for Size where T: Eq + Default + Debug + Clone {} impl Debug for Size where T: Clone + Default + Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Size {{ {:?} × {:?} }}", self.width, self.height) } } impl From> for Size { fn from(point: Point) -> Self { Self { width: point.x, height: point.y, } } } impl From> for Size { fn from(size: Size) -> Self { Size { width: GlobalPixels(size.width.0), height: GlobalPixels(size.height.0), } } } impl Size { pub fn full() -> Self { Self { width: relative(1.).into(), height: relative(1.).into(), } } } impl Size { pub fn zero() -> Self { Self { width: px(0.).into(), height: px(0.).into(), } } } impl Size { pub fn auto() -> Self { Self { width: Length::Auto, height: Length::Auto, } } } #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)] #[refineable(debug)] #[repr(C)] pub struct Bounds { pub origin: Point, pub size: Size, } impl Bounds where T: Clone + Debug + Sub + Default, { pub fn from_corners(upper_left: Point, lower_right: Point) -> Self { let origin = Point { x: upper_left.x.clone(), y: upper_left.y.clone(), }; let size = Size { width: lower_right.x - upper_left.x, height: lower_right.y - upper_left.y, }; Bounds { origin, size } } } impl Bounds where T: Clone + Debug + PartialOrd + Add + Sub + Default, { pub fn intersects(&self, other: &Bounds) -> bool { let my_lower_right = self.lower_right(); let their_lower_right = other.lower_right(); self.origin.x < their_lower_right.x && my_lower_right.x > other.origin.x && self.origin.y < their_lower_right.y && my_lower_right.y > other.origin.y } pub fn dilate(&mut self, amount: T) { self.origin.x = self.origin.x.clone() - amount.clone(); self.origin.y = self.origin.y.clone() - amount.clone(); let double_amount = amount.clone() + amount; self.size.width = self.size.width.clone() + double_amount.clone(); self.size.height = self.size.height.clone() + double_amount; } } impl + Sub> Bounds { pub fn intersect(&self, other: &Self) -> Self { let upper_left = self.origin.max(&other.origin); let lower_right = self.lower_right().min(&other.lower_right()); Self::from_corners(upper_left, lower_right) } pub fn union(&self, other: &Self) -> Self { let top_left = self.origin.min(&other.origin); let bottom_right = self.lower_right().max(&other.lower_right()); Bounds::from_corners(top_left, bottom_right) } } impl Mul for Bounds where T: Mul + Clone + Default + Debug, Point: Mul>, Rhs: Clone + Default + Debug, { type Output = Bounds; fn mul(self, rhs: Rhs) -> Self::Output { Bounds { origin: self.origin * rhs.clone(), size: self.size * rhs, } } } impl MulAssign for Bounds where T: Mul + Clone + Default + Debug, S: Clone, { fn mul_assign(&mut self, rhs: S) { self.origin *= rhs.clone(); self.size *= rhs; } } impl Div for Bounds where Size: Div>, T: Div + Default + Clone + Debug, S: Clone, { type Output = Self; fn div(self, rhs: S) -> Self { Self { origin: self.origin / rhs.clone(), size: self.size / rhs, } } } impl Bounds where T: Add + Clone + Default + Debug, { pub fn upper_right(&self) -> Point { Point { x: self.origin.x.clone() + self.size.width.clone(), y: self.origin.y.clone(), } } pub fn lower_right(&self) -> Point { Point { x: self.origin.x.clone() + self.size.width.clone(), y: self.origin.y.clone() + self.size.height.clone(), } } pub fn lower_left(&self) -> Point { Point { x: self.origin.x.clone(), y: self.origin.y.clone() + self.size.height.clone(), } } } impl Bounds where T: Add + PartialOrd + Clone + Default + Debug, { pub fn contains_point(&self, point: &Point) -> bool { point.x >= self.origin.x && point.x <= self.origin.x.clone() + self.size.width.clone() && point.y >= self.origin.y && point.y <= self.origin.y.clone() + self.size.height.clone() } pub fn map(&self, f: impl Fn(T) -> U) -> Bounds where U: Clone + Default + Debug, { Bounds { origin: self.origin.map(&f), size: self.size.map(f), } } } impl Bounds { pub fn scale(&self, factor: f32) -> Bounds { Bounds { origin: self.origin.scale(factor), size: self.size.scale(factor), } } } impl Copy for Bounds {} #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)] #[refineable(debug)] #[repr(C)] pub struct Edges { pub top: T, pub right: T, pub bottom: T, pub left: T, } impl Mul for Edges where T: Mul + Clone + Default + Debug, { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { Self { top: self.top.clone() * rhs.top, right: self.right.clone() * rhs.right, bottom: self.bottom.clone() * rhs.bottom, left: self.left.clone() * rhs.left, } } } impl MulAssign for Edges where T: Mul + Clone + Default + Debug, S: Clone, { fn mul_assign(&mut self, rhs: S) { self.top = self.top.clone() * rhs.clone(); self.right = self.right.clone() * rhs.clone(); self.bottom = self.bottom.clone() * rhs.clone(); self.left = self.left.clone() * rhs; } } impl Copy for Edges {} impl Edges { pub fn map(&self, f: impl Fn(&T) -> U) -> Edges where U: Clone + Default + Debug, { Edges { top: f(&self.top), right: f(&self.right), bottom: f(&self.bottom), left: f(&self.left), } } pub fn any bool>(&self, predicate: F) -> bool { predicate(&self.top) || predicate(&self.right) || predicate(&self.bottom) || predicate(&self.left) } } impl Edges { pub fn auto() -> Self { Self { top: Length::Auto, right: Length::Auto, bottom: Length::Auto, left: Length::Auto, } } pub fn zero() -> Self { Self { top: px(0.).into(), right: px(0.).into(), bottom: px(0.).into(), left: px(0.).into(), } } } impl Edges { pub fn zero() -> Self { Self { top: px(0.).into(), right: px(0.).into(), bottom: px(0.).into(), left: px(0.).into(), } } } impl Edges { pub fn zero() -> Self { Self { top: px(0.).into(), right: px(0.).into(), bottom: px(0.).into(), left: px(0.).into(), } } pub fn to_pixels(&self, rem_size: Pixels) -> Edges { Edges { top: self.top.to_pixels(rem_size), right: self.right.to_pixels(rem_size), bottom: self.bottom.to_pixels(rem_size), left: self.left.to_pixels(rem_size), } } } impl Edges { pub fn scale(&self, factor: f32) -> Edges { Edges { top: self.top.scale(factor), right: self.right.scale(factor), bottom: self.bottom.scale(factor), left: self.left.scale(factor), } } } #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)] #[refineable(debug)] #[repr(C)] pub struct Corners { pub top_left: T, pub top_right: T, pub bottom_right: T, pub bottom_left: T, } impl Corners { pub fn to_pixels(&self, size: Size, rem_size: Pixels) -> Corners { let max = size.width.max(size.height) / 2.; Corners { top_left: self.top_left.to_pixels(rem_size).min(max), top_right: self.top_right.to_pixels(rem_size).min(max), bottom_right: self.bottom_right.to_pixels(rem_size).min(max), bottom_left: self.bottom_left.to_pixels(rem_size).min(max), } } } impl Corners { pub fn scale(&self, factor: f32) -> Corners { Corners { top_left: self.top_left.scale(factor), top_right: self.top_right.scale(factor), bottom_right: self.bottom_right.scale(factor), bottom_left: self.bottom_left.scale(factor), } } } impl Corners { pub fn map(&self, f: impl Fn(&T) -> U) -> Corners where U: Clone + Default + Debug, { Corners { top_left: f(&self.top_left), top_right: f(&self.top_right), bottom_right: f(&self.bottom_right), bottom_left: f(&self.bottom_left), } } } impl Mul for Corners where T: Mul + Clone + Default + Debug, { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { Self { top_left: self.top_left.clone() * rhs.top_left, top_right: self.top_right.clone() * rhs.top_right, bottom_right: self.bottom_right.clone() * rhs.bottom_right, bottom_left: self.bottom_left.clone() * rhs.bottom_left, } } } impl MulAssign for Corners where T: Mul + Clone + Default + Debug, S: Clone, { fn mul_assign(&mut self, rhs: S) { self.top_left = self.top_left.clone() * rhs.clone(); self.top_right = self.top_right.clone() * rhs.clone(); self.bottom_right = self.bottom_right.clone() * rhs.clone(); self.bottom_left = self.bottom_left.clone() * rhs; } } impl Copy for Corners where T: Copy + Clone + Default + Debug {} #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, Neg, PartialEq, PartialOrd)] #[repr(transparent)] pub struct Pixels(pub(crate) f32); impl Mul for Pixels { type Output = Pixels; fn mul(self, other: f32) -> Pixels { Pixels(self.0 * other) } } impl Mul for Pixels { type Output = Pixels; fn mul(self, other: usize) -> Pixels { Pixels(self.0 * other as f32) } } impl Mul for f32 { type Output = Pixels; fn mul(self, rhs: Pixels) -> Self::Output { Pixels(self * rhs.0) } } impl MulAssign for Pixels { fn mul_assign(&mut self, other: f32) { self.0 *= other; } } impl Pixels { pub const MAX: Pixels = Pixels(f32::MAX); pub fn round(&self) -> Self { Self(self.0.round()) } pub fn scale(&self, factor: f32) -> ScaledPixels { ScaledPixels(self.0 * factor) } } impl Mul for Pixels { type Output = Pixels; fn mul(self, rhs: Pixels) -> Self::Output { Pixels(self.0 * rhs.0) } } impl Eq for Pixels {} impl Ord for Pixels { fn cmp(&self, other: &Self) -> cmp::Ordering { self.0.partial_cmp(&other.0).unwrap() } } impl std::hash::Hash for Pixels { fn hash(&self, state: &mut H) { self.0.to_bits().hash(state); } } impl From for Pixels { fn from(pixels: f64) -> Self { Pixels(pixels as f32) } } impl From for Pixels { fn from(pixels: f32) -> Self { Pixels(pixels) } } impl Debug for Pixels { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} px", self.0) } } impl From for f32 { fn from(pixels: Pixels) -> Self { pixels.0 } } impl From<&Pixels> for f32 { fn from(pixels: &Pixels) -> Self { pixels.0 } } impl From for f64 { fn from(pixels: Pixels) -> Self { pixels.0 as f64 } } #[derive( Add, AddAssign, Clone, Copy, Default, Div, Eq, Hash, Ord, PartialEq, PartialOrd, Sub, SubAssign, )] #[repr(transparent)] pub struct DevicePixels(pub(crate) i32); impl DevicePixels { pub fn to_bytes(&self, bytes_per_pixel: u8) -> u32 { self.0 as u32 * bytes_per_pixel as u32 } } impl fmt::Debug for DevicePixels { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} px (device)", self.0) } } impl From for i32 { fn from(device_pixels: DevicePixels) -> Self { device_pixels.0 } } impl From for DevicePixels { fn from(device_pixels: i32) -> Self { DevicePixels(device_pixels) } } impl From for DevicePixels { fn from(device_pixels: u32) -> Self { DevicePixels(device_pixels as i32) } } impl From for u32 { fn from(device_pixels: DevicePixels) -> Self { device_pixels.0 as u32 } } impl From for u64 { fn from(device_pixels: DevicePixels) -> Self { device_pixels.0 as u64 } } impl From for DevicePixels { fn from(device_pixels: u64) -> Self { DevicePixels(device_pixels as i32) } } #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)] #[repr(transparent)] pub struct ScaledPixels(pub(crate) f32); impl ScaledPixels { pub fn floor(&self) -> Self { Self(self.0.floor()) } pub fn ceil(&self) -> Self { Self(self.0.ceil()) } } impl Eq for ScaledPixels {} impl Debug for ScaledPixels { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} px (scaled)", self.0) } } impl From for DevicePixels { fn from(scaled: ScaledPixels) -> Self { DevicePixels(scaled.0.ceil() as i32) } } impl From for ScaledPixels { fn from(device: DevicePixels) -> Self { ScaledPixels(device.0 as f32) } } impl From for f64 { fn from(scaled_pixels: ScaledPixels) -> Self { scaled_pixels.0 as f64 } } #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)] #[repr(transparent)] pub struct GlobalPixels(pub(crate) f32); impl Debug for GlobalPixels { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} px (global coordinate space)", self.0) } } impl From for f64 { fn from(global_pixels: GlobalPixels) -> Self { global_pixels.0 as f64 } } impl From for GlobalPixels { fn from(global_pixels: f64) -> Self { GlobalPixels(global_pixels as f32) } } #[derive(Clone, Copy, Default, Add, Sub, Mul, Div, Neg)] pub struct Rems(f32); impl Mul for Rems { type Output = Pixels; fn mul(self, other: Pixels) -> Pixels { Pixels(self.0 * other.0) } } impl Debug for Rems { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} rem", self.0) } } #[derive(Clone, Copy, Debug, Neg)] pub enum AbsoluteLength { Pixels(Pixels), Rems(Rems), } impl AbsoluteLength { pub fn is_zero(&self) -> bool { match self { AbsoluteLength::Pixels(px) => px.0 == 0., AbsoluteLength::Rems(rems) => rems.0 == 0., } } } impl From for AbsoluteLength { fn from(pixels: Pixels) -> Self { AbsoluteLength::Pixels(pixels) } } impl From for AbsoluteLength { fn from(rems: Rems) -> Self { AbsoluteLength::Rems(rems) } } impl AbsoluteLength { pub fn to_pixels(&self, rem_size: Pixels) -> Pixels { match self { AbsoluteLength::Pixels(pixels) => *pixels, AbsoluteLength::Rems(rems) => *rems * rem_size, } } } impl Default for AbsoluteLength { fn default() -> Self { px(0.).into() } } /// A non-auto length that can be defined in pixels, rems, or percent of parent. #[derive(Clone, Copy, Neg)] pub enum DefiniteLength { Absolute(AbsoluteLength), /// A fraction of the parent's size between 0 and 1. Fraction(f32), } impl DefiniteLength { pub fn to_pixels(&self, base_size: AbsoluteLength, rem_size: Pixels) -> Pixels { match self { DefiniteLength::Absolute(size) => size.to_pixels(rem_size), DefiniteLength::Fraction(fraction) => match base_size { AbsoluteLength::Pixels(px) => px * *fraction, AbsoluteLength::Rems(rems) => rems * rem_size * *fraction, }, } } } impl Debug for DefiniteLength { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { DefiniteLength::Absolute(length) => Debug::fmt(length, f), DefiniteLength::Fraction(fract) => write!(f, "{}%", (fract * 100.0) as i32), } } } impl From for DefiniteLength { fn from(pixels: Pixels) -> Self { Self::Absolute(pixels.into()) } } impl From for DefiniteLength { fn from(rems: Rems) -> Self { Self::Absolute(rems.into()) } } impl From for DefiniteLength { fn from(length: AbsoluteLength) -> Self { Self::Absolute(length) } } impl Default for DefiniteLength { fn default() -> Self { Self::Absolute(AbsoluteLength::default()) } } /// A length that can be defined in pixels, rems, percent of parent, or auto. #[derive(Clone, Copy)] pub enum Length { Definite(DefiniteLength), Auto, } impl Debug for Length { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Length::Definite(definite_length) => write!(f, "{:?}", definite_length), Length::Auto => write!(f, "auto"), } } } pub fn relative(fraction: f32) -> DefiniteLength { DefiniteLength::Fraction(fraction).into() } /// Returns the Golden Ratio, i.e. `~(1.0 + sqrt(5.0)) / 2.0`. pub fn phi() -> DefiniteLength { relative(1.61803398875) } pub fn rems(rems: f32) -> Rems { Rems(rems) } pub fn px(pixels: f32) -> Pixels { Pixels(pixels) } pub fn auto() -> Length { Length::Auto } impl From for Length { fn from(pixels: Pixels) -> Self { Self::Definite(pixels.into()) } } impl From for Length { fn from(rems: Rems) -> Self { Self::Definite(rems.into()) } } impl From for Length { fn from(length: DefiniteLength) -> Self { Self::Definite(length) } } impl From for Length { fn from(length: AbsoluteLength) -> Self { Self::Definite(length.into()) } } impl Default for Length { fn default() -> Self { Self::Definite(DefiniteLength::default()) } } impl From<()> for Length { fn from(_: ()) -> Self { Self::Definite(DefiniteLength::default()) } } pub trait IsZero { fn is_zero(&self) -> bool; } impl IsZero for DevicePixels { fn is_zero(&self) -> bool { self.0 == 0 } } impl IsZero for ScaledPixels { fn is_zero(&self) -> bool { self.0 == 0. } } impl IsZero for Pixels { fn is_zero(&self) -> bool { self.0 == 0. } } impl IsZero for Rems { fn is_zero(&self) -> bool { self.0 == 0. } } impl IsZero for AbsoluteLength { fn is_zero(&self) -> bool { match self { AbsoluteLength::Pixels(pixels) => pixels.is_zero(), AbsoluteLength::Rems(rems) => rems.is_zero(), } } } impl IsZero for DefiniteLength { fn is_zero(&self) -> bool { match self { DefiniteLength::Absolute(length) => length.is_zero(), DefiniteLength::Fraction(fraction) => *fraction == 0., } } } impl IsZero for Length { fn is_zero(&self) -> bool { match self { Length::Definite(length) => length.is_zero(), Length::Auto => false, } } } impl IsZero for Point { fn is_zero(&self) -> bool { self.x.is_zero() && self.y.is_zero() } } impl IsZero for Size where T: IsZero + Default + Debug + Clone, { fn is_zero(&self) -> bool { self.width.is_zero() || self.height.is_zero() } } impl IsZero for Bounds { fn is_zero(&self) -> bool { self.size.is_zero() } } impl IsZero for Corners where T: IsZero + Clone + Default + Debug, { fn is_zero(&self) -> bool { self.top_left.is_zero() && self.top_right.is_zero() && self.bottom_right.is_zero() && self.bottom_left.is_zero() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_bounds_intersects() { let bounds1 = Bounds { origin: Point { x: 0.0, y: 0.0 }, size: Size { width: 5.0, height: 5.0, }, }; let bounds2 = Bounds { origin: Point { x: 4.0, y: 4.0 }, size: Size { width: 5.0, height: 5.0, }, }; let bounds3 = Bounds { origin: Point { x: 10.0, y: 10.0 }, size: Size { width: 5.0, height: 5.0, }, }; // Test Case 1: Intersecting bounds assert_eq!(bounds1.intersects(&bounds2), true); // Test Case 2: Non-Intersecting bounds assert_eq!(bounds1.intersects(&bounds3), false); // Test Case 3: Bounds intersecting with themselves assert_eq!(bounds1.intersects(&bounds1), true); } }