use crate::foundations::{cast, elem, Content};
use crate::layout::{Abs, Em, Fr, Length, Ratio, Rel};
use crate::utils::Numeric;
#[elem(title = "Spacing (H)")]
pub struct HElem {
#[required]
pub amount: Spacing,
#[default(false)]
pub weak: bool,
}
impl HElem {
pub fn hole() -> Self {
Self::new(Abs::zero().into()).with_weak(true)
}
}
#[elem(title = "Spacing (V)")]
pub struct VElem {
#[required]
pub amount: Spacing,
pub weak: bool,
#[internal]
#[parse(Some(false))]
pub attach: bool,
}
cast! {
VElem,
v: Content => v.unpack::<Self>().map_err(|_| "expected `v` element")?,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Spacing {
Rel(Rel<Length>),
Fr(Fr),
}
impl Spacing {
pub fn is_fractional(self) -> bool {
matches!(self, Self::Fr(_))
}
pub fn is_zero(&self) -> bool {
match self {
Self::Rel(rel) => rel.is_zero(),
Self::Fr(fr) => fr.is_zero(),
}
}
}
impl From<Abs> for Spacing {
fn from(abs: Abs) -> Self {
Self::Rel(abs.into())
}
}
impl From<Em> for Spacing {
fn from(em: Em) -> Self {
Self::Rel(Rel::new(Ratio::zero(), em.into()))
}
}
impl From<Length> for Spacing {
fn from(length: Length) -> Self {
Self::Rel(length.into())
}
}
impl From<Fr> for Spacing {
fn from(fr: Fr) -> Self {
Self::Fr(fr)
}
}
cast! {
Spacing,
self => match self {
Self::Rel(rel) => {
if rel.rel.is_zero() {
rel.abs.into_value()
} else if rel.abs.is_zero() {
rel.rel.into_value()
} else {
rel.into_value()
}
}
Self::Fr(fr) => fr.into_value(),
},
v: Rel<Length> => Self::Rel(v),
v: Fr => Self::Fr(v),
}