use std::ops::{Add, Div, Mul, Neg, Sub};
use super::{Axis, CellId};
#[derive(Clone, Debug, PartialEq)]
pub enum Extent {
Sum {
px: f64,
inches: f64,
percent: f64,
},
Min(Box<Extent>, Box<Extent>),
Max(Box<Extent>, Box<Extent>),
TrackOf {
grid: CellId,
axis: Axis,
track: u16,
span: u16,
},
}
impl Extent {
pub const ZERO: Extent = Extent::Sum {
px: 0.0,
inches: 0.0,
percent: 0.0,
};
pub const fn px(v: f64) -> Self {
Extent::Sum {
px: v,
inches: 0.0,
percent: 0.0,
}
}
pub const fn mm(v: f64) -> Self {
Extent::Sum {
px: 0.0,
inches: v / 25.4,
percent: 0.0,
}
}
pub const fn cm(v: f64) -> Self {
Extent::Sum {
px: 0.0,
inches: v / 2.54,
percent: 0.0,
}
}
pub const fn inch(v: f64) -> Self {
Extent::Sum {
px: 0.0,
inches: v,
percent: 0.0,
}
}
pub const fn pt(v: f64) -> Self {
Extent::Sum {
px: 0.0,
inches: v / 72.0,
percent: 0.0,
}
}
pub const fn percent(v: f64) -> Self {
Extent::Sum {
px: 0.0,
inches: 0.0,
percent: v,
}
}
pub fn min(a: Extent, b: Extent) -> Self {
Extent::Min(Box::new(a), Box::new(b))
}
pub fn max(a: Extent, b: Extent) -> Self {
Extent::Max(Box::new(a), Box::new(b))
}
pub const fn track_of(grid: CellId, axis: Axis, track: u16) -> Self {
Extent::TrackOf {
grid,
axis,
track,
span: 1,
}
}
pub const fn tracks_of(grid: CellId, axis: Axis, start: u16, span: u16) -> Self {
Extent::TrackOf {
grid,
axis,
track: start,
span: if span == 0 { 1 } else { span },
}
}
pub fn is_absolute(&self) -> bool {
match self {
Extent::Sum { percent, .. } => *percent == 0.0,
Extent::Min(a, b) | Extent::Max(a, b) => a.is_absolute() && b.is_absolute(),
Extent::TrackOf { .. } => false,
}
}
}
impl Default for Extent {
fn default() -> Self {
Extent::ZERO
}
}
impl Add for Extent {
type Output = Extent;
fn add(self, rhs: Extent) -> Extent {
match (self, rhs) {
(
Extent::Sum {
px: a,
inches: b,
percent: c,
},
Extent::Sum {
px: x,
inches: y,
percent: z,
},
) => Extent::Sum {
px: a + x,
inches: b + y,
percent: c + z,
},
(Extent::Min(a, b), other) => {
let other_clone = other.clone();
Extent::Min(Box::new(*a + other), Box::new(*b + other_clone))
}
(other, Extent::Min(a, b)) => {
let other_clone = other.clone();
Extent::Min(Box::new(other + *a), Box::new(other_clone + *b))
}
(Extent::Max(a, b), other) => {
let other_clone = other.clone();
Extent::Max(Box::new(*a + other), Box::new(*b + other_clone))
}
(other, Extent::Max(a, b)) => {
let other_clone = other.clone();
Extent::Max(Box::new(other + *a), Box::new(other_clone + *b))
}
(Extent::TrackOf { .. }, _) | (_, Extent::TrackOf { .. }) => panic!(
"Extent::TrackOf cannot participate in +/-/*; \
use Extent::tracks_of(.., span = N) for consecutive tracks, \
or compose via Extent::min / Extent::max"
),
}
}
}
impl Neg for Extent {
type Output = Extent;
fn neg(self) -> Extent {
match self {
Extent::Sum {
px,
inches,
percent,
} => Extent::Sum {
px: -px,
inches: -inches,
percent: -percent,
},
Extent::Min(a, b) => Extent::Max(Box::new(-*a), Box::new(-*b)),
Extent::Max(a, b) => Extent::Min(Box::new(-*a), Box::new(-*b)),
Extent::TrackOf { .. } => panic!(
"Extent::TrackOf cannot be negated; use Extent::min / Extent::max for composition"
),
}
}
}
impl Sub for Extent {
type Output = Extent;
fn sub(self, rhs: Extent) -> Extent {
self + (-rhs)
}
}
impl Mul<f64> for Extent {
type Output = Extent;
fn mul(self, k: f64) -> Extent {
match self {
Extent::Sum {
px,
inches,
percent,
} => Extent::Sum {
px: px * k,
inches: inches * k,
percent: percent * k,
},
Extent::Min(a, b) if k >= 0.0 => Extent::Min(Box::new(*a * k), Box::new(*b * k)),
Extent::Min(a, b) => Extent::Max(Box::new(*a * k), Box::new(*b * k)),
Extent::Max(a, b) if k >= 0.0 => Extent::Max(Box::new(*a * k), Box::new(*b * k)),
Extent::Max(a, b) => Extent::Min(Box::new(*a * k), Box::new(*b * k)),
Extent::TrackOf { .. } => panic!(
"Extent::TrackOf cannot be scaled by f64; use Extent::min / Extent::max for composition"
),
}
}
}
impl Mul<Extent> for f64 {
type Output = Extent;
fn mul(self, l: Extent) -> Extent {
l * self
}
}
impl Div<f64> for Extent {
type Output = Extent;
fn div(self, k: f64) -> Extent {
self * (1.0 / k)
}
}