use incular_core::finite_non_negative;
use std::ops::{Add, AddAssign, Sub, SubAssign};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct EdgeInsets {
pub left: f32,
pub top: f32,
pub right: f32,
pub bottom: f32,
}
impl EdgeInsets {
pub const ZERO: Self = Self {
left: 0.0,
top: 0.0,
right: 0.0,
bottom: 0.0,
};
#[must_use]
pub const fn zero() -> Self {
Self::ZERO
}
#[must_use]
pub const fn all(value: f32) -> Self {
Self {
left: value,
top: value,
right: value,
bottom: value,
}
}
#[must_use]
pub const fn symmetric(horizontal: f32, vertical: f32) -> Self {
Self {
left: horizontal,
top: vertical,
right: horizontal,
bottom: vertical,
}
}
#[must_use]
pub const fn horizontal_insets(horizontal: f32) -> Self {
Self::symmetric(horizontal, 0.0)
}
#[must_use]
pub const fn vertical_insets(vertical: f32) -> Self {
Self::symmetric(0.0, vertical)
}
#[must_use]
pub const fn from_xy(horizontal: f32, vertical: f32) -> Self {
Self::symmetric(horizontal, vertical)
}
#[must_use]
pub const fn only(left: f32, top: f32, right: f32, bottom: f32) -> Self {
Self {
left,
top,
right,
bottom,
}
}
#[must_use]
pub const fn from_ltrb(left: f32, top: f32, right: f32, bottom: f32) -> Self {
Self::only(left, top, right, bottom)
}
#[must_use]
pub const fn horizontal(self) -> f32 {
self.left + self.right
}
#[must_use]
pub const fn vertical(self) -> f32 {
self.top + self.bottom
}
#[must_use]
pub const fn dimensions(self) -> (f32, f32) {
(self.horizontal(), self.vertical())
}
#[must_use]
pub const fn is_zero(self) -> bool {
self.left == 0.0 && self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0
}
#[must_use]
pub fn is_valid(self) -> bool {
[self.left, self.top, self.right, self.bottom]
.into_iter()
.all(|value| value.is_finite() && value >= 0.0)
}
#[must_use]
pub fn normalized(self) -> Self {
Self::only(
finite_non_negative(self.left),
finite_non_negative(self.top),
finite_non_negative(self.right),
finite_non_negative(self.bottom),
)
}
#[must_use]
pub fn clamp(self, min: f32, max: f32) -> Self {
let (min, max) = if min.is_finite() && max.is_finite() && min <= max {
(min, max)
} else {
(0.0, f32::MAX)
};
Self::only(
self.left.clamp(min, max),
self.top.clamp(min, max),
self.right.clamp(min, max),
self.bottom.clamp(min, max),
)
}
#[must_use]
pub fn inset(self, amount: f32) -> Self {
Self::only(
(self.left - amount).max(0.0),
(self.top - amount).max(0.0),
(self.right - amount).max(0.0),
(self.bottom - amount).max(0.0),
)
}
#[must_use]
pub fn outset(self, amount: f32) -> Self {
Self::only(
(self.left + amount).max(0.0),
(self.top + amount).max(0.0),
(self.right + amount).max(0.0),
(self.bottom + amount).max(0.0),
)
}
}
impl Add for EdgeInsets {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::only(
self.left + rhs.left,
self.top + rhs.top,
self.right + rhs.right,
self.bottom + rhs.bottom,
)
}
}
impl AddAssign for EdgeInsets {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl Sub for EdgeInsets {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::only(
self.left - rhs.left,
self.top - rhs.top,
self.right - rhs.right,
self.bottom - rhs.bottom,
)
}
}
impl SubAssign for EdgeInsets {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl std::ops::Mul<f32> for EdgeInsets {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Self::only(
self.left * rhs,
self.top * rhs,
self.right * rhs,
self.bottom * rhs,
)
}
}
impl std::ops::Div<f32> for EdgeInsets {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
Self::only(
self.left / rhs,
self.top / rhs,
self.right / rhs,
self.bottom / rhs,
)
}
}
impl std::ops::Neg for EdgeInsets {
type Output = Self;
fn neg(self) -> Self::Output {
Self::only(-self.left, -self.top, -self.right, -self.bottom)
}
}
impl incular_core::Lerp for EdgeInsets {
fn lerp(&self, other: &Self, t: f32) -> Self {
let t = t.clamp(0.0, 1.0);
let mix = |a: f32, b: f32| a + (b - a) * t;
Self::only(
mix(self.left, other.left),
mix(self.top, other.top),
mix(self.right, other.right),
mix(self.bottom, other.bottom),
)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct EdgeInsetsDirectional {
pub start: f32,
pub top: f32,
pub end: f32,
pub bottom: f32,
}
impl EdgeInsetsDirectional {
pub const ZERO: Self = Self {
start: 0.0,
top: 0.0,
end: 0.0,
bottom: 0.0,
};
#[must_use]
pub const fn zero() -> Self {
Self::ZERO
}
#[must_use]
pub const fn all(value: f32) -> Self {
Self {
start: value,
top: value,
end: value,
bottom: value,
}
}
#[must_use]
pub const fn only(start: f32, top: f32, end: f32, bottom: f32) -> Self {
Self {
start,
top,
end,
bottom,
}
}
#[must_use]
pub const fn symmetric(horizontal: f32, vertical: f32) -> Self {
Self {
start: horizontal,
top: vertical,
end: horizontal,
bottom: vertical,
}
}
#[must_use]
pub const fn from_ste_b(start: f32, top: f32, end: f32, bottom: f32) -> Self {
Self::only(start, top, end, bottom)
}
#[must_use]
pub const fn resolve(self, direction: crate::TextDirection) -> EdgeInsets {
match direction {
crate::TextDirection::Ltr => {
EdgeInsets::only(self.start, self.top, self.end, self.bottom)
}
crate::TextDirection::Rtl => {
EdgeInsets::only(self.end, self.top, self.start, self.bottom)
}
}
}
#[must_use]
pub const fn horizontal(self) -> f32 {
self.start + self.end
}
#[must_use]
pub const fn vertical(self) -> f32 {
self.top + self.bottom
}
}
impl Add for EdgeInsetsDirectional {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::only(
self.start + rhs.start,
self.top + rhs.top,
self.end + rhs.end,
self.bottom + rhs.bottom,
)
}
}
impl Sub for EdgeInsetsDirectional {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::only(
self.start - rhs.start,
self.top - rhs.top,
self.end - rhs.end,
self.bottom - rhs.bottom,
)
}
}
impl std::ops::Mul<f32> for EdgeInsetsDirectional {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Self::only(
self.start * rhs,
self.top * rhs,
self.end * rhs,
self.bottom * rhs,
)
}
}
impl std::ops::Div<f32> for EdgeInsetsDirectional {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
Self::only(
self.start / rhs,
self.top / rhs,
self.end / rhs,
self.bottom / rhs,
)
}
}
impl incular_core::Lerp for EdgeInsetsDirectional {
fn lerp(&self, other: &Self, t: f32) -> Self {
let t = t.clamp(0.0, 1.0);
let mix = |a: f32, b: f32| a + (b - a) * t;
Self::only(
mix(self.start, other.start),
mix(self.top, other.top),
mix(self.end, other.end),
mix(self.bottom, other.bottom),
)
}
}