use crate::prelude::*; use std::marker::PhantomData; pub struct Span { pub children: Vec, pub dir: Dir, pub gap: f32, } impl Widget for Span { fn draw(&mut self, painter: &mut Painter) -> Size { let axis = self.dir.axis; // A length for every child before any is placed: from its own hint // where it has one, and from drawing it where it does not. let lens: Vec = self .children .iter() .map(|child| match painter.size_hint(child, axis) { Some(len) => len, None => painter.widget(child).len(axis), }) .collect(); let gap = self.gap * self.children.len().saturating_sub(1) as f32; let total = lens.iter().fold(Len::abs(gap), |sum, len| sum + *len); let mut start = UiScalar::rel_min(); let mut ortho = Len::ZERO; for (child, len) in self.children.iter().zip(&lens) { let mut span = UiSpan::FULL; span.start = start; if len.rest > 0.0 { let offset = UiScalar::new(total.rel, total.abs); let rel_end = UiScalar::rel(len.rest / total.rest); let end = (UiScalar::rel_max() + start) - offset; start = rel_end.within(&start.to(end)); } start.abs += len.abs; start.rel += len.rel; span.end = start; let mut region = UiRegion::from_axis(axis, span, UiSpan::FULL); if self.dir.sign == Sign::Neg { region.flip(axis); } let used = painter.widget_within(child, region).size().axis(!axis); // TODO: rel shouldn't do this, but no easy way before actually calculating pixels if used.rel > 0.0 || used.rest > 0.0 { ortho = Len::REST; } else if ortho.rest == 0.0 { ortho.abs = ortho.abs.max(used.abs); } start.abs += self.gap; } let along = match total.rest == 0.0 && total.rel == 0.0 { true => total, false => Len::default(), }; Size::from_axis(axis, along, ortho) } } impl Span { pub fn empty(dir: Dir) -> Self { Self { children: Vec::new(), dir, gap: 0.0, } } pub fn gap(mut self, gap: impl UiNum) -> Self { self.gap = gap.to_f32(); self } pub fn push(&mut self, w: StrongWidget) { self.children.push(w); } pub fn pop(&mut self) -> Option { self.children.pop() } } pub struct SpanBuilder, Tag> { pub children: Wa, pub dir: Dir, pub gap: f32, _pd: PhantomData<(State, Tag)>, } impl, Tag> WidgetFnTrait for SpanBuilder { type Widget = Span; #[track_caller] fn run(self, rsc: &mut Rsc) -> Self::Widget { Span { children: self.children.add(rsc).arr.into_iter().collect(), dir: self.dir, gap: self.gap, } } } impl, Tag> SpanBuilder { pub fn new(children: Wa, dir: Dir) -> Self { Self { children, dir, gap: 0.0, _pd: PhantomData, } } pub fn gap(mut self, gap: impl UiNum) -> Self { self.gap = gap.to_f32(); self } } impl std::ops::Deref for Span { type Target = Vec; fn deref(&self) -> &Self::Target { &self.children } } impl std::ops::DerefMut for Span { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.children } }