#![doc=include_str!("../README.md")]
#![deny(clippy::missing_const_for_fn)]
use std::ops::{Add, Not};
use layout::Vec2;
pub mod align;
pub mod flexbox;
pub mod grid;
pub mod layout;
pub use align::Alignment;
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Orientation {
Vertical,
Horizontal,
}
impl Not for Orientation {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Orientation::Vertical => Orientation::Horizontal,
Orientation::Horizontal => Orientation::Vertical,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MinimumNatural<T> {
pub minimum: T,
pub natural: T,
}
impl<T: Clone> MinimumNatural<T> {
pub fn same(t: T) -> Self {
Self {
minimum: t.clone(),
natural: t,
}
}
}
impl<T: Add<U, Output = P>, U, P> Add<MinimumNatural<U>> for MinimumNatural<T> {
type Output = MinimumNatural<P>;
fn add(self, other: MinimumNatural<U>) -> MinimumNatural<P> {
MinimumNatural {
minimum: self.minimum + other.minimum,
natural: self.natural + other.natural,
}
}
}
pub trait Layout {
fn width_for_height(&self, height: usize) -> MinimumNatural<usize>;
fn height_for_width(&self, width: usize) -> MinimumNatural<usize>;
fn prefered_size(&self) -> MinimumNatural<Vec2>;
fn prefered_size_of_container(
&self,
container: Vec2,
) -> MinimumNatural<Vec2>;
}
pub trait LayoutExt: Layout {
fn sub_for_prim(
&self,
prim: usize,
orientation: Orientation,
) -> MinimumNatural<usize> {
match orientation {
Orientation::Vertical => self.width_for_height(prim),
Orientation::Horizontal => self.height_for_width(prim),
}
}
}
impl<T> LayoutExt for T where T: Layout {}
pub fn squash<L: Layout>(l: &L, container: Vec2) -> MinimumNatural<Vec2> {
let mut size = l.prefered_size();
if size.natural.x > container.x {
size.natural.x = container.x;
size.natural.y = l.height_for_width(size.natural.x).natural;
}
if size.natural.y > container.y {
size.natural.y = container.y;
size.natural.x = l.width_for_height(size.natural.y).natural;
}
let mut size = l.prefered_size();
if size.minimum.x > container.x {
size.minimum.x = container.x;
size.minimum.y = l.height_for_width(size.minimum.x).minimum;
}
if size.minimum.y > container.y {
size.minimum.y = container.y;
size.minimum.x = l.width_for_height(size.minimum.y).minimum;
}
size
}
impl<T: Layout> Layout for &T {
fn width_for_height(&self, height: usize) -> MinimumNatural<usize> {
(*self).width_for_height(height)
}
fn height_for_width(&self, width: usize) -> MinimumNatural<usize> {
(*self).height_for_width(width)
}
fn prefered_size(&self) -> MinimumNatural<Vec2> {
(*self).prefered_size()
}
fn prefered_size_of_container(
&self,
container: Vec2,
) -> MinimumNatural<Vec2> {
(*self).prefered_size_of_container(container)
}
}