use crate::{Dir, Painter, Sign, UiNum, UiRegion, UIScalar, Widget, WidgetId}; pub struct Span { pub children: Vec<(WidgetId, SpanLen)>, pub dir: Dir, } impl Widget for Span { fn draw(&self, painter: &mut Painter) { let total = self.sums(); let mut start = UIScalar::min(); for (child, length) in &self.children { let mut child_region = UiRegion::full(); let mut axis = child_region.axis_mut(self.dir.axis); axis.top_left.set(start); match *length { SpanLen::Fixed(offset) => { start.offset += offset; *axis.bot_right.offset = start.offset; *axis.bot_right.anchor = *axis.top_left.anchor; } SpanLen::Ratio(ratio) => { let offset = UIScalar::new(total.relative, total.fixed); let rel_end = UIScalar::from_anchor(ratio / total.ratio); start = rel_end.within(start, (UIScalar::max() + start) - offset); axis.bot_right.set(start); } SpanLen::Relative(rel) => { start.anchor += rel; axis.bot_right.set(start); } } if self.dir.sign == Sign::Neg { child_region.flip(); } painter.draw_within(child, child_region); } } } #[derive(Default)] pub struct SpanLenSums { pub fixed: f32, pub ratio: f32, pub relative: f32, } impl Span { pub fn empty(dir: Dir) -> Self { Self { children: Vec::new(), dir, } } pub fn sums(&self) -> SpanLenSums { self.lengths().fold(SpanLenSums::default(), |mut s, l| { match l { SpanLen::Fixed(v) => s.fixed += v, SpanLen::Ratio(v) => s.ratio += v, SpanLen::Relative(v) => s.relative += v, } s }) } pub fn lengths(&self) -> impl ExactSizeIterator { self.children.iter().map(|(_, s)| s) } } #[derive(Clone, Copy)] pub enum SpanLen { /// exact (non dynamic) size Fixed(f32), /// relative to remaining free space and other ratios /// eg. 1 and 2 would take up 1/3 and 2/3 of the remaining space (after others) Ratio(f32), /// relative to the total space (of the entire span) /// eg. 0.5 means 1/2 of the total space Relative(f32), } pub fn fixed(x: N) -> SpanLen { SpanLen::Fixed(x.to_f32()) } pub fn ratio(x: N) -> SpanLen { SpanLen::Ratio(x.to_f32()) } pub fn rel(x: N) -> SpanLen { SpanLen::Relative(x.to_f32()) } impl From for SpanLen { fn from(value: N) -> Self { Self::Ratio(value.to_f32()) } }