use super::*;
#[inline]
pub fn flex1d<const N: usize>(min: f32, max: f32, gap: Option<Unit>, justify: Justify, template: &[Unit; N]) -> [[f32; 2]; N] {
let mut spans = [[0.0; 2]; N];
flex1d_slice(min, max, gap, justify, template, &mut spans);
spans
}
pub fn flex1d_slice(
min: f32,
max: f32,
gap: Option<Unit>,
justify: Justify,
template: &[Unit],
spans: &mut [[f32; 2]],
) {
debug_assert_eq!(template.len(), spans.len());
if template.len() == 0 || template.len() != spans.len() {
return;
}
debug_assert!(min <= max);
if min > max {
return;
}
let size = max - min;
let mut total_used = 0.0;
let mut total_fr = match gap {
None => 0.0,
Some(Unit::Abs(_)) => 0.0,
Some(Unit::Pct(_)) => 0.0,
Some(Unit::Fr(v)) => v * (template.len() - 1) as f32,
};
for i in 0..template.len() {
match template[i] {
Unit::Abs(v) => total_used += v,
Unit::Pct(v) => total_used += v * (0.01 * size),
Unit::Fr(v) => total_fr += v,
}
}
let mut fr_space = size - total_used;
let gap_size = if template.len() == 1 { 0.0 }
else {
match gap {
None => 0.0,
Some(Unit::Abs(v)) => v,
Some(Unit::Pct(v)) => v * (0.01 * size),
Some(Unit::Fr(v)) => v * (fr_space / total_fr),
}
};
if !matches!(gap, Some(Unit::Fr(_))) {
fr_space -= gap_size * (template.len() - 1) as f32;
}
let justify_space = if total_fr == 0.0 { fr_space } else { 0.0 };
let (mut base, shift) = match justify {
Justify::Start => (0.0, 0.0),
Justify::Center => (justify_space * 0.5, 0.0),
Justify::End => (justify_space, 0.0),
Justify::SpaceBetween => {
let value = if spans.len() > 1 { justify_space / (spans.len() - 1) as f32 } else { 0.0 };
(0.0, value)
}
Justify::SpaceAround => {
let value = justify_space / spans.len() as f32;
(value * 0.5, value)
}
Justify::SpaceEvenly => {
let value = justify_space / (spans.len() + 1) as f32;
(value, value)
}
};
let mut pos = min;
for i in 0..template.len() {
let size = match template[i] {
Unit::Abs(v) => v,
Unit::Pct(v) => v * (0.01 * size),
Unit::Fr(v) => v * (fr_space / total_fr),
};
spans[i] = [base + pos, base + pos + size];
pos += size + gap_size;
base += shift;
}
}
use cvmath::Bounds2;
#[inline]
pub fn flex2d<const N: usize>(rect: Bounds2<f32>, orientation: Orientation, gap: Option<Unit>, justify: Justify, template: &[Unit; N]) -> [Bounds2<f32>; N] {
let values = match orientation {
Orientation::Vertical => flex1d(rect.mins.y, rect.maxs.y, gap, justify, template),
Orientation::Horizontal => flex1d(rect.mins.x, rect.maxs.x, gap, justify, template),
};
let mut rects = [Bounds2::ZERO; N];
for (i, &[begin, end]) in values.iter().enumerate() {
match orientation {
Orientation::Vertical => rects[i] = Bounds2::c(rect.mins.x, begin, rect.maxs.x, end),
Orientation::Horizontal => rects[i] = Bounds2::c(begin, rect.mins.y, end, rect.maxs.y),
}
}
rects
}