use std::{cmp, fmt, ops};
use serde::{Deserialize, Serialize};
use crate::SideOffsets2D;
#[derive(Serialize, Deserialize)]
#[serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
pub struct CornerRadius2D<T, U> {
pub top_left: euclid::Size2D<T, U>,
pub top_right: euclid::Size2D<T, U>,
pub bottom_right: euclid::Size2D<T, U>,
pub bottom_left: euclid::Size2D<T, U>,
}
impl<T: Default, U> Default for CornerRadius2D<T, U> {
fn default() -> Self {
Self {
top_left: Default::default(),
top_right: Default::default(),
bottom_right: Default::default(),
bottom_left: Default::default(),
}
}
}
impl<T: Clone, U> Clone for CornerRadius2D<T, U> {
fn clone(&self) -> Self {
Self {
top_left: self.top_left.clone(),
top_right: self.top_right.clone(),
bottom_right: self.bottom_right.clone(),
bottom_left: self.bottom_left.clone(),
}
}
}
impl<T: Copy, U> Copy for CornerRadius2D<T, U> {}
impl<T: Copy + num_traits::Zero, U> CornerRadius2D<T, U> {
pub fn new(
top_left: euclid::Size2D<T, U>,
top_right: euclid::Size2D<T, U>,
bottom_right: euclid::Size2D<T, U>,
bottom_left: euclid::Size2D<T, U>,
) -> Self {
Self {
top_left,
top_right,
bottom_right,
bottom_left,
}
}
pub fn new_all(radius: euclid::Size2D<T, U>) -> Self {
Self::new(radius, radius, radius, radius)
}
pub fn zero() -> Self {
Self::new_all(euclid::Size2D::zero())
}
pub fn inflate(self, offsets: SideOffsets2D<T, U>) -> Self
where
T: ops::AddAssign,
{
let mut r = self;
r.top_left.width += offsets.left;
r.top_left.height += offsets.top;
r.top_right.width += offsets.right;
r.top_right.height += offsets.top;
r.bottom_right.width += offsets.right;
r.bottom_right.height += offsets.bottom;
r.bottom_left.width += offsets.left;
r.bottom_left.height += offsets.bottom;
r
}
pub fn deflate(self, offsets: SideOffsets2D<T, U>) -> Self
where
T: ops::SubAssign + cmp::PartialOrd,
{
let mut r = self;
if r.top_left.width >= offsets.left {
r.top_left.width -= offsets.left;
} else {
r.top_left.width = T::zero();
}
if r.top_left.height >= offsets.top {
r.top_left.height -= offsets.top;
} else {
r.top_left.height = T::zero();
}
if r.top_right.width >= offsets.right {
r.top_right.width -= offsets.right;
} else {
r.top_right.width = T::zero();
}
if r.top_right.height >= offsets.top {
r.top_right.height -= offsets.top;
} else {
r.top_right.height = T::zero();
}
if r.bottom_right.width >= offsets.right {
r.bottom_right.width -= offsets.right;
} else {
r.bottom_right.width = T::zero();
}
if r.bottom_right.height >= offsets.bottom {
r.bottom_right.height -= offsets.bottom;
} else {
r.bottom_right.height = T::zero();
}
if r.bottom_left.width >= offsets.left {
r.bottom_left.width -= offsets.left;
} else {
r.bottom_left.width = T::zero();
}
if r.bottom_left.height >= offsets.bottom {
r.bottom_left.height -= offsets.bottom;
} else {
r.bottom_left.height = T::zero();
}
r
}
}
impl<T: fmt::Debug, U> fmt::Debug for CornerRadius2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CornerRadius2D")
.field("top_left", &self.top_left)
.field("top_right", &self.top_right)
.field("bottom_right", &self.bottom_right)
.field("bottom_left", &self.bottom_left)
.finish()
}
}
impl<T: PartialEq, U> PartialEq for CornerRadius2D<T, U> {
fn eq(&self, other: &Self) -> bool {
self.top_left == other.top_left
&& self.top_right == other.top_right
&& self.bottom_right == other.bottom_right
&& self.bottom_left == other.bottom_left
}
}
impl<T: Eq, U> Eq for CornerRadius2D<T, U> {}