use std::{fmt, ops};
use zng_var::{animation::Transitionable, impl_from_and_into_var};
use super::{impl_length_comp_conversions, DipRect, Factor2d, LayoutMask, Length, Point, PxRect, Size, Vector};
#[derive(Clone, Default, PartialEq, serde::Serialize, serde::Deserialize, Transitionable)]
pub struct Rect {
pub origin: Point,
pub size: Size,
}
impl fmt::Debug for Rect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.debug_struct("Rect")
.field("origin", &self.origin)
.field("size", &self.size)
.finish()
} else {
write!(f, "{:?}.at{:?}", self.origin, self.size)
}
}
}
impl fmt::Display for Rect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(p) = f.precision() {
write!(f, "{:.p$} {:.p$}", self.origin, self.size, p = p)
} else {
write!(f, "{} {}", self.origin, self.size)
}
}
}
impl Rect {
pub fn new<O: Into<Point>, S: Into<Size>>(origin: O, size: S) -> Self {
Rect {
origin: origin.into(),
size: size.into(),
}
}
pub fn from_size<S: Into<Size>>(size: S) -> Self {
Self::new(Point::zero(), size)
}
pub fn zero() -> Self {
Self::new(Point::zero(), Size::zero())
}
pub fn fill() -> Self {
Self::from_size(Size::fill())
}
pub fn min(&self) -> Point {
self.origin.clone()
}
pub fn max(&self) -> Point {
self.origin.clone() + self.size.clone()
}
pub fn min_x(&self) -> Length {
self.origin.x.clone()
}
pub fn min_y(&self) -> Length {
self.origin.y.clone()
}
pub fn max_x(&self) -> Length {
self.origin.x.clone() + self.size.width.clone()
}
pub fn max_y(&self) -> Length {
self.origin.y.clone() + self.size.height.clone()
}
pub fn translate(&self, by: impl Into<Vector>) -> Self {
let mut r = self.clone();
r.origin += by.into();
r
}
pub fn is_default(&self) -> bool {
self.origin.is_default() && self.size.is_default()
}
pub fn replace_default(&mut self, overwrite: &Rect) {
self.origin.replace_default(&overwrite.origin);
self.size.replace_default(&overwrite.size);
}
}
impl super::Layout2d for Rect {
type Px = PxRect;
fn layout_dft(&self, default: Self::Px) -> Self::Px {
PxRect {
origin: self.origin.layout_dft(default.origin),
size: self.size.layout_dft(default.size),
}
}
fn affect_mask(&self) -> LayoutMask {
self.origin.affect_mask() | self.size.affect_mask()
}
}
impl_length_comp_conversions! {
fn from(x: X, y: Y, width: W, height: H) -> Rect {
Rect::new((x, y), (width, height))
}
}
impl_from_and_into_var! {
fn from(rect: PxRect) -> Rect {
Rect::new(rect.origin, rect.size)
}
fn from(rect: DipRect) -> Rect {
Rect::new(rect.origin, rect.size)
}
fn from(size: Size) -> Rect {
Rect::from_size(size)
}
fn from<O: Into<Point>, S: Into<Size>>((origin, size): (O, S)) -> Rect {
Rect::new(origin, size)
}
}
impl<S: Into<Factor2d>> ops::Mul<S> for Rect {
type Output = Self;
fn mul(mut self, rhs: S) -> Self {
self *= rhs;
self
}
}
impl<S: Into<Factor2d>> ops::Mul<S> for &Rect {
type Output = Rect;
fn mul(self, rhs: S) -> Self::Output {
self.clone() * rhs
}
}
impl<S: Into<Factor2d>> ops::MulAssign<S> for Rect {
fn mul_assign(&mut self, rhs: S) {
let rhs = rhs.into();
self.origin *= rhs;
self.size *= rhs;
}
}
impl<S: Into<Factor2d>> ops::Div<S> for Rect {
type Output = Self;
fn div(mut self, rhs: S) -> Self {
self /= rhs;
self
}
}
impl<S: Into<Factor2d>> ops::Div<S> for &Rect {
type Output = Rect;
fn div(self, rhs: S) -> Self::Output {
self.clone() / rhs
}
}
impl<S: Into<Factor2d>> ops::DivAssign<S> for Rect {
fn div_assign(&mut self, rhs: S) {
let rhs = rhs.into();
self.origin /= rhs;
self.size /= rhs;
}
}
impl ops::Add for Rect {
type Output = Self;
fn add(mut self, rhs: Self) -> Self {
self += rhs;
self
}
}
impl ops::AddAssign for Rect {
fn add_assign(&mut self, rhs: Self) {
self.origin += rhs.origin;
self.size += rhs.size;
}
}
impl ops::Sub for Rect {
type Output = Self;
fn sub(mut self, rhs: Self) -> Self {
self -= rhs;
self
}
}
impl ops::SubAssign for Rect {
fn sub_assign(&mut self, rhs: Self) {
self.origin -= rhs.origin;
self.size -= rhs.size;
}
}
pub trait RectFromTuplesBuilder {
fn at<X: Into<Length>, Y: Into<Length>>(self, x: X, y: Y) -> Rect;
}
impl<W: Into<Length>, H: Into<Length>> RectFromTuplesBuilder for (W, H) {
fn at<X: Into<Length>, Y: Into<Length>>(self, x: X, y: Y) -> Rect {
Rect::new((x, y), self)
}
}