use std::ops::ControlFlow;
use anathema_geometry::Size;
use anathema_widgets::LayoutForEach;
use anathema_widgets::error::Result;
use anathema_widgets::layout::{Constraints, LayoutCtx};
use super::Axis;
const DEFAULT_FACTOR: u16 = 1;
fn distribute_size(weights: &[u16], mut total: u16) -> Vec<u16> {
let mut indexed = weights
.iter()
.copied()
.enumerate()
.map(|(i, w)| (i, w, 0u16))
.collect::<Vec<_>>();
fn pop(n: &mut u16) -> bool {
if let Some(nn) = n.checked_sub(1) {
*n = nn;
true
} else {
false
}
}
while pop(&mut total) {
indexed.sort_by_cached_key(|&(_, w, r)| (((w as f64) / ((r * (r + 1)) as f64).sqrt()) * -10000.) as isize);
indexed[0].2 += 1;
}
indexed.sort_by_key(|&(i, ..)| i);
indexed.into_iter().map(|(_, _, r)| r).collect()
}
pub fn layout_all_expansions<'bp>(
nodes: &mut LayoutForEach<'_, 'bp>,
constraints: Constraints,
axis: Axis,
ctx: &mut LayoutCtx<'_, 'bp>,
) -> Result<Size> {
let mut factors = vec![];
_ = nodes.each(ctx, |ctx, node, _children| {
if node.ident == "expand" {
let attributes = ctx.attribute_storage.get(node.id());
let factor = attributes.get_as::<u16>("factor").unwrap_or(DEFAULT_FACTOR);
factors.push(factor);
}
Ok(ControlFlow::Continue(()))
})?;
let mut size = Size::ZERO;
if factors.is_empty() {
return Ok(size);
}
let sizes = match axis {
Axis::Horizontal => distribute_size(&factors, constraints.max_width()),
Axis::Vertical => distribute_size(&factors, constraints.max_height()),
};
let mut index = 0;
_ = nodes.each(ctx, |ctx, node, children| {
if node.ident != "expand" {
return Ok(ControlFlow::Continue(()));
}
let sub_size = sizes[index];
index += 1;
let constraints = match axis {
Axis::Horizontal => {
let mut constraints = Constraints::new(sub_size, constraints.max_height());
constraints.min_width = constraints.max_width();
constraints
}
Axis::Vertical => {
let mut constraints = Constraints::new(constraints.max_width(), sub_size);
constraints.min_height = constraints.max_height();
constraints
}
};
let widget_size = Size::from(node.layout(children, constraints, ctx)?);
match axis {
Axis::Horizontal => {
size.width += widget_size.width;
size.height = size.height.max(widget_size.height);
}
Axis::Vertical => {
size.width = size.width.max(widget_size.width);
size.height += widget_size.height;
}
}
Ok(ControlFlow::Continue(()))
})?;
Ok(size)
}