use super::CellId;
pub trait Measure {
fn width_hint(&self, dpi: f64) -> WidthHint;
fn height_at(&self, width: f64, dpi: f64) -> f64;
fn width_at(&self, _height: f64, _dpi: f64) -> f64 {
0.0
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum WidthHint {
Min(f64),
NeedsHeight { seed: f64 },
}
pub struct Cell {
pub(crate) measure: Box<dyn Measure>,
pub(crate) id: Option<CellId>,
}
impl Cell {
pub fn empty() -> Self {
Self {
measure: Box::new(EmptyMeasure),
id: None,
}
}
pub fn measured(m: impl Measure + 'static) -> Self {
Self {
measure: Box::new(m),
id: None,
}
}
pub fn measured_boxed(m: Box<dyn Measure>) -> Self {
Self {
measure: m,
id: None,
}
}
pub fn id(mut self, id: CellId) -> Self {
self.id = Some(id);
self
}
pub fn into_measure(self) -> Box<dyn Measure> {
self.measure
}
pub fn cell_id(&self) -> Option<CellId> {
self.id
}
}
struct EmptyMeasure;
pub struct MaxMergeMeasure {
children: Vec<Box<dyn Measure>>,
}
impl MaxMergeMeasure {
pub fn new(children: Vec<Box<dyn Measure>>) -> Self {
Self { children }
}
}
impl Measure for MaxMergeMeasure {
fn width_hint(&self, dpi: f64) -> WidthHint {
let mut max_min: f64 = 0.0;
let mut any_needs_height = false;
for c in &self.children {
match c.width_hint(dpi) {
WidthHint::Min(w) => max_min = max_min.max(w),
WidthHint::NeedsHeight { seed } => {
any_needs_height = true;
max_min = max_min.max(seed);
}
}
}
if any_needs_height {
WidthHint::NeedsHeight { seed: max_min }
} else {
WidthHint::Min(max_min)
}
}
fn height_at(&self, width: f64, dpi: f64) -> f64 {
self.children
.iter()
.map(|c| c.height_at(width, dpi))
.fold(0.0_f64, f64::max)
}
fn width_at(&self, height: f64, dpi: f64) -> f64 {
self.children
.iter()
.map(|c| c.width_at(height, dpi))
.fold(0.0_f64, f64::max)
}
}
impl Measure for EmptyMeasure {
fn width_hint(&self, _dpi: f64) -> WidthHint {
WidthHint::Min(0.0)
}
fn height_at(&self, _width: f64, _dpi: f64) -> f64 {
0.0
}
}