use super::*; use Split::*; pub trait Xy { fn x (&self) -> N; fn y (&self) -> N; } pub trait Wh: Wide + Tall { fn wh (&self) -> [N;2]; } pub trait Xywh: Xy + Wh { fn xywh (&self) -> XYWH { XYWH(self.x(), self.y(), self.w(), self.h()) } } pub trait Wide: Xy { fn w (&self) -> N { N::zero() } fn w_min (&self) -> N { self.w() } fn w_max (&self) -> N { self.w() } } pub trait Tall { fn h (&self) -> N { N::zero() } fn h_min (&self) -> N { self.h() } fn h_max (&self) -> N { self.h() } } /// Point with size. /// /// ``` /// # use tengri::*; /// let xywh = XYWH(0u16, 0, 0, 0); /// assert_eq!(XYWH(10u16, 10, 20, 20).center(), (20, 20)); /// ``` /// /// * [ ] TODO: origin field (determines at which corner/side is X0 Y0) /// #[cfg_attr(test, derive(Arbitrary))] #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct XYWH(pub N, pub N, pub N, pub N); impl Xy for XYWH { fn x (&self) -> N { self.0 } fn y (&self) -> N { self.1 } } impl Wide for XYWH { fn w (&self) -> N { self.2 } } impl Tall for XYWH { fn h (&self) -> N { self.3 } } impl XYWH { pub fn zero () -> Self { Self(0.into(), 0.into(), 0.into(), 0.into()) } pub fn center (&self) -> (N, N) { let Self(x, y, w, h) = *self; (x.plus(w/2.into()), y.plus(h/2.into())) } pub fn centered (&self) -> (N, N) { let Self(x, y, w, h) = *self; (x.minus(w/2.into()), y.minus(h/2.into())) } pub fn centered_x (&self, n: N) -> Self { let Self(x, y, w, h) = *self; let x_center = (x.plus(w / 2.into())).minus(n / 2.into()); let y_center = y.plus(h / 2.into()); XYWH(x_center, y_center, n, 1.into()) } pub fn centered_y (&self, n: N) -> Self { let Self(x, y, w, h) = *self; let x_center = x.plus(w / 2.into()); let y_corner = (y.plus(h / 2.into())).minus(n / 2.into()); XYWH(x_center, y_corner, 1.into(), n) } pub fn centered_xy (&self, [n, m]: [N;2]) -> Self { let Self(x, y, w, h) = *self; let x_center = (x.plus(w / 2.into())).minus(n / 2.into()); let y_corner = (y.plus(h / 2.into())).minus(m / 2.into()); XYWH(x_center, y_corner, n, m) } pub fn split_half (&self, direction: &Split) -> (Self, Self) { let XYWH(x, y, w, h) = self.xywh(); match direction { South => (XYWH(x, y, w, h - h / 2.into()), XYWH(x, y + h / 2.into(), w, h / 2.into())), East => (XYWH(x, y, w - w / 2.into(), h), XYWH(x + w / 2.into(), y, w / 2.into(), h)), North => (XYWH(x, y + h / 2.into(), w, h - h / 2.into()), XYWH(x, y, w, h / 2.into())), West => (XYWH(x + w / 2.into(), y, w - w / 2.into(), h), XYWH(x, y, w / 2.into(), h)), Above | Below => (XYWH(x, y, w, h), XYWH(x, y, w, h)) } } } impl From<&ratatui::prelude::Rect> for XYWH { fn from (rect: &ratatui::prelude::Rect) -> Self { Self(rect.x, rect.y, rect.width, rect.height) } } impl + Tall> Wh for T { fn wh (&self) -> [N;2] { [self.w(), self.h()] } } impl + Wh> Xywh for T {}