use crate::util::sys::f32_max;
use crate::CompactLength;
use crate::{style::Dimension, util::sys::f32_min};
use core::ops::{Add, Sub};
#[cfg(feature = "flexbox")]
use crate::style::FlexDirection;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AbsoluteAxis {
Horizontal,
Vertical,
}
impl AbsoluteAxis {
#[inline]
pub const fn other_axis(&self) -> Self {
match *self {
AbsoluteAxis::Horizontal => AbsoluteAxis::Vertical,
AbsoluteAxis::Vertical => AbsoluteAxis::Horizontal,
}
}
}
impl<T> Size<T> {
#[inline(always)]
pub fn get_abs(self, axis: AbsoluteAxis) -> T {
match axis {
AbsoluteAxis::Horizontal => self.width,
AbsoluteAxis::Vertical => self.height,
}
}
}
impl<T: Add> Rect<T> {
#[inline(always)]
pub fn grid_axis_sum(self, axis: AbsoluteAxis) -> <T as Add>::Output {
match axis {
AbsoluteAxis::Horizontal => self.left + self.right,
AbsoluteAxis::Vertical => self.top + self.bottom,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AbstractAxis {
Inline,
Block,
}
impl AbstractAxis {
#[inline]
pub const fn other(&self) -> AbstractAxis {
match *self {
AbstractAxis::Inline => AbstractAxis::Block,
AbstractAxis::Block => AbstractAxis::Inline,
}
}
#[inline]
pub const fn as_abs_naive(&self) -> AbsoluteAxis {
match self {
AbstractAxis::Inline => AbsoluteAxis::Horizontal,
AbstractAxis::Block => AbsoluteAxis::Vertical,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct InBothAbsAxis<T> {
pub horizontal: T,
pub vertical: T,
}
impl<T: Copy> InBothAbsAxis<T> {
#[cfg(feature = "grid")]
pub const fn get(&self, axis: AbsoluteAxis) -> T {
match axis {
AbsoluteAxis::Horizontal => self.horizontal,
AbsoluteAxis::Vertical => self.vertical,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Rect<T> {
pub left: T,
pub right: T,
pub top: T,
pub bottom: T,
}
impl<U, T: Add<U>> Add<Rect<U>> for Rect<T> {
type Output = Rect<T::Output>;
fn add(self, rhs: Rect<U>) -> Self::Output {
Rect {
left: self.left + rhs.left,
right: self.right + rhs.right,
top: self.top + rhs.top,
bottom: self.bottom + rhs.bottom,
}
}
}
impl<T> Rect<T> {
#[cfg(any(feature = "flexbox", feature = "block_layout"))]
pub(crate) fn zip_size<R, F, U>(self, size: Size<U>, f: F) -> Rect<R>
where
F: Fn(T, U) -> R,
U: Copy,
{
Rect {
left: f(self.left, size.width),
right: f(self.right, size.width),
top: f(self.top, size.height),
bottom: f(self.bottom, size.height),
}
}
pub fn map<R, F>(self, f: F) -> Rect<R>
where
F: Fn(T) -> R,
{
Rect { left: f(self.left), right: f(self.right), top: f(self.top), bottom: f(self.bottom) }
}
pub fn horizontal_components(self) -> Line<T> {
Line { start: self.left, end: self.right }
}
pub fn vertical_components(self) -> Line<T> {
Line { start: self.top, end: self.bottom }
}
}
impl<T, U> Rect<T>
where
T: Add<Output = U> + Copy + Clone,
{
#[inline(always)]
pub fn horizontal_axis_sum(&self) -> U {
self.left + self.right
}
#[inline(always)]
pub fn vertical_axis_sum(&self) -> U {
self.top + self.bottom
}
#[inline(always)]
#[allow(dead_code)] pub fn sum_axes(&self) -> Size<U> {
Size { width: self.horizontal_axis_sum(), height: self.vertical_axis_sum() }
}
#[cfg(feature = "flexbox")]
pub(crate) fn main_axis_sum(&self, direction: FlexDirection) -> U {
if direction.is_row() {
self.horizontal_axis_sum()
} else {
self.vertical_axis_sum()
}
}
#[cfg(feature = "flexbox")]
pub(crate) fn cross_axis_sum(&self, direction: FlexDirection) -> U {
if direction.is_row() {
self.vertical_axis_sum()
} else {
self.horizontal_axis_sum()
}
}
}
impl<T> Rect<T>
where
T: Copy + Clone,
{
#[cfg(feature = "flexbox")]
pub(crate) const fn main_start(&self, direction: FlexDirection) -> T {
if direction.is_row() {
self.left
} else {
self.top
}
}
#[cfg(feature = "flexbox")]
pub(crate) const fn main_end(&self, direction: FlexDirection) -> T {
if direction.is_row() {
self.right
} else {
self.bottom
}
}
#[cfg(feature = "flexbox")]
pub(crate) const fn cross_start(&self, direction: FlexDirection) -> T {
if direction.is_row() {
self.top
} else {
self.left
}
}
#[cfg(feature = "flexbox")]
pub(crate) const fn cross_end(&self, direction: FlexDirection) -> T {
if direction.is_row() {
self.bottom
} else {
self.right
}
}
}
impl Rect<f32> {
pub const ZERO: Rect<f32> = Self { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 };
#[must_use]
pub const fn new(start: f32, end: f32, top: f32, bottom: f32) -> Self {
Self { left: start, right: end, top, bottom }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct Line<T> {
pub start: T,
pub end: T,
}
impl<T> Line<T> {
pub fn map<R, F>(self, f: F) -> Line<R>
where
F: Fn(T) -> R,
{
Line { start: f(self.start), end: f(self.end) }
}
}
impl Line<bool> {
pub const TRUE: Self = Line { start: true, end: true };
pub const FALSE: Self = Line { start: false, end: false };
}
impl<T: Add + Copy> Line<T> {
pub fn sum(&self) -> <T as Add>::Output {
self.start + self.end
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Size<T> {
pub width: T,
pub height: T,
}
impl<U, T: Add<U>> Add<Size<U>> for Size<T> {
type Output = Size<<T as Add<U>>::Output>;
fn add(self, rhs: Size<U>) -> Self::Output {
Size { width: self.width + rhs.width, height: self.height + rhs.height }
}
}
impl<U, T: Sub<U>> Sub<Size<U>> for Size<T> {
type Output = Size<<T as Sub<U>>::Output>;
fn sub(self, rhs: Size<U>) -> Self::Output {
Size { width: self.width - rhs.width, height: self.height - rhs.height }
}
}
#[allow(dead_code)]
impl<T> Size<T> {
pub fn map<R, F>(self, f: F) -> Size<R>
where
F: Fn(T) -> R,
{
Size { width: f(self.width), height: f(self.height) }
}
pub fn map_width<F>(self, f: F) -> Size<T>
where
F: Fn(T) -> T,
{
Size { width: f(self.width), height: self.height }
}
pub fn map_height<F>(self, f: F) -> Size<T>
where
F: Fn(T) -> T,
{
Size { width: self.width, height: f(self.height) }
}
pub fn zip_map<Other, Ret, Func>(self, other: Size<Other>, f: Func) -> Size<Ret>
where
Func: Fn(T, Other) -> Ret,
{
Size { width: f(self.width, other.width), height: f(self.height, other.height) }
}
#[cfg(feature = "flexbox")]
pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
if direction.is_row() {
self.width = value
} else {
self.height = value
}
}
#[cfg(feature = "flexbox")]
pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
if direction.is_row() {
self.height = value
} else {
self.width = value
}
}
#[cfg(feature = "flexbox")]
pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
let mut new = self;
if direction.is_row() {
new.width = value
} else {
new.height = value
}
new
}
#[cfg(feature = "flexbox")]
pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
let mut new = self;
if direction.is_row() {
new.height = value
} else {
new.width = value
}
new
}
#[cfg(feature = "flexbox")]
pub(crate) fn map_main(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
let mut new = self;
if direction.is_row() {
new.width = mapper(new.width);
} else {
new.height = mapper(new.height);
}
new
}
#[cfg(feature = "flexbox")]
pub(crate) fn map_cross(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
let mut new = self;
if direction.is_row() {
new.height = mapper(new.height);
} else {
new.width = mapper(new.width);
}
new
}
#[cfg(feature = "flexbox")]
pub(crate) fn main(self, direction: FlexDirection) -> T {
if direction.is_row() {
self.width
} else {
self.height
}
}
#[cfg(feature = "flexbox")]
pub(crate) fn cross(self, direction: FlexDirection) -> T {
if direction.is_row() {
self.height
} else {
self.width
}
}
#[cfg(feature = "grid")]
pub(crate) fn get(self, axis: AbstractAxis) -> T {
match axis {
AbstractAxis::Inline => self.width,
AbstractAxis::Block => self.height,
}
}
#[cfg(feature = "grid")]
pub(crate) fn set(&mut self, axis: AbstractAxis, value: T) {
match axis {
AbstractAxis::Inline => self.width = value,
AbstractAxis::Block => self.height = value,
}
}
}
impl Size<f32> {
pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
#[inline(always)]
pub fn f32_max(self, rhs: Size<f32>) -> Size<f32> {
Size { width: f32_max(self.width, rhs.width), height: f32_max(self.height, rhs.height) }
}
#[inline(always)]
pub fn f32_min(self, rhs: Size<f32>) -> Size<f32> {
Size { width: f32_min(self.width, rhs.width), height: f32_min(self.height, rhs.height) }
}
#[inline(always)]
pub fn has_non_zero_area(self) -> bool {
self.width > 0.0 && self.height > 0.0
}
}
impl Size<Option<f32>> {
pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
#[must_use]
pub const fn new(width: f32, height: f32) -> Self {
Size { width: Some(width), height: Some(height) }
}
#[cfg(feature = "flexbox")]
pub const fn from_cross(direction: FlexDirection, value: Option<f32>) -> Self {
let mut new = Self::NONE;
if direction.is_row() {
new.height = value
} else {
new.width = value
}
new
}
pub fn maybe_apply_aspect_ratio(self, aspect_ratio: Option<f32>) -> Size<Option<f32>> {
match aspect_ratio {
Some(ratio) => match (self.width, self.height) {
(Some(width), None) => Size { width: Some(width), height: Some(width / ratio) },
(None, Some(height)) => Size { width: Some(height * ratio), height: Some(height) },
_ => self,
},
None => self,
}
}
}
impl<T> Size<Option<T>> {
pub fn unwrap_or(self, alt: Size<T>) -> Size<T> {
Size { width: self.width.unwrap_or(alt.width), height: self.height.unwrap_or(alt.height) }
}
pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
}
#[inline(always)]
pub fn both_axis_defined(&self) -> bool {
self.width.is_some() && self.height.is_some()
}
}
impl Size<Dimension> {
#[must_use]
pub const fn from_lengths(width: f32, height: f32) -> Self {
Size { width: Dimension(CompactLength::length(width)), height: Dimension(CompactLength::length(height)) }
}
#[must_use]
pub const fn from_percent(width: f32, height: f32) -> Self {
Size { width: Dimension(CompactLength::percent(width)), height: Dimension(CompactLength::percent(height)) }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl Point<f32> {
pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
}
impl Point<Option<f32>> {
pub const NONE: Self = Self { x: None, y: None };
}
impl<U, T: Add<U>> Add<Point<U>> for Point<T> {
type Output = Point<<T as Add<U>>::Output>;
fn add(self, rhs: Point<U>) -> Self::Output {
Point { x: self.x + rhs.x, y: self.y + rhs.y }
}
}
impl<T> Point<T> {
pub fn map<R, F>(self, f: F) -> Point<R>
where
F: Fn(T) -> R,
{
Point { x: f(self.x), y: f(self.y) }
}
#[cfg(feature = "grid")]
pub fn get(self, axis: AbstractAxis) -> T {
match axis {
AbstractAxis::Inline => self.x,
AbstractAxis::Block => self.y,
}
}
pub fn transpose(self) -> Point<T> {
Point { x: self.y, y: self.x }
}
#[cfg(feature = "grid")]
pub fn set(&mut self, axis: AbstractAxis, value: T) {
match axis {
AbstractAxis::Inline => self.x = value,
AbstractAxis::Block => self.y = value,
}
}
#[cfg(feature = "flexbox")]
pub(crate) fn main(self, direction: FlexDirection) -> T {
if direction.is_row() {
self.x
} else {
self.y
}
}
#[cfg(feature = "flexbox")]
pub(crate) fn cross(self, direction: FlexDirection) -> T {
if direction.is_row() {
self.y
} else {
self.x
}
}
}
impl<T> From<Point<T>> for Size<T> {
fn from(value: Point<T>) -> Self {
Size { width: value.x, height: value.y }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MinMax<Min, Max> {
pub min: Min,
pub max: Max,
}