use crate::{saturating_add_signed::SaturatingAddSigned, utils::Utils};
use derive_more::{Add, IsVariant, Sub};
use mkutils_macros::{
SaturatingAdd as SaturatingAddImpl, SaturatingAddSigned as SaturatingAddSignedImpl,
SaturatingSub as SaturatingSubImpl,
};
use num::traits::{ConstZero, SaturatingSub};
use ratatui::layout::{Constraint, Layout, Size};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, IsVariant)]
pub enum Orientation {
Horizontal,
Vertical,
}
impl Orientation {
#[must_use]
pub const fn toggled(&self) -> Self {
match self {
Self::Horizontal => Self::Vertical,
Self::Vertical => Self::Horizontal,
}
}
pub const fn toggle(&mut self) {
*self = self.toggled();
}
pub fn layout<I: IntoIterator<Item: Into<Constraint>>>(&self, constraints: I) -> Layout {
self.is_horizontal()
.if_else::<fn(I) -> Layout>(Layout::horizontal, Layout::vertical)(constraints)
}
}
#[derive(
Add,
Clone,
Copy,
Debug,
Default,
Deserialize,
SaturatingAddImpl,
SaturatingSubImpl,
SaturatingAddSignedImpl,
Serialize,
Sub,
)]
#[saturating_add_signed(assoc(type Signed = Point<<T as SaturatingAddSigned>::Signed>))]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<T> Point<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn into_point<S: From<T>>(self) -> Point<S> {
self.x.pair(self.y).into()
}
pub fn into_pair(self) -> (T, T) {
self.into()
}
pub const fn get(&self, orientation: Orientation) -> &T {
match orientation {
Orientation::Horizontal => &self.x,
Orientation::Vertical => &self.y,
}
}
pub const fn get_mut(&mut self, orientation: Orientation) -> &mut T {
match orientation {
Orientation::Horizontal => &mut self.x,
Orientation::Vertical => &mut self.y,
}
}
}
impl<T: ConstZero> Point<T> {
pub const ZERO: Self = Self { x: T::ZERO, y: T::ZERO };
}
impl<T: SaturatingSub> Point<T> {
#[must_use]
pub fn saturating_sub_scalar(&self, rhs: &T) -> Self {
let x = self.x.saturating_sub(rhs);
let y = self.y.saturating_sub(rhs);
Self::new(x, y)
}
}
impl<T, X: Into<T>, Y: Into<T>> From<(X, Y)> for Point<T> {
fn from((x, y): (X, Y)) -> Self {
Self::new(x.into(), y.into())
}
}
impl<T: From<u16>> From<Size> for Point<T> {
fn from(size: Size) -> Self {
size.convert::<(u16, u16)>().into()
}
}
impl<T, X: From<T>, Y: From<T>> From<Point<T>> for (X, Y) {
fn from(point: Point<T>) -> Self {
point.x.convert::<X>().pair(point.y.into())
}
}
pub type PointU16 = Point<u16>;
pub type PointUsize = Point<usize>;
pub type PointIsize = Point<isize>;