use std::marker::PhantomData; use crate::prelude::*; pub struct Span { pub children: Vec, pub dir: Dir, pub gap: f32, } impl Widget for Span { fn draw(&mut self, painter: &mut Painter) { let total = self.len_sum(&mut painter.size_ctx()); let mut start = UiScalar::rel_min(); for child in &self.children { let mut child_region = UiRegion::full(); let mut axis = child_region.axis_mut(self.dir.axis); axis.top_left.set(start); let len = painter.size(child).axis(self.dir.axis); if len.rest > 0.0 { let offset = UiScalar::new(total.rel, total.abs); let rel_end = UiScalar::from_anchor(len.rest / total.rest); start = rel_end.within(start, (UiScalar::rel_max() + start) - offset); } start.abs += len.abs; start.rel += len.rel; axis.bot_right.set(start); if self.dir.sign == Sign::Neg { child_region.flip(self.dir.axis); } painter.widget_within(child, child_region); start.abs += self.gap; } } fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size { let mut sums = self.len_sum(ctx); let dir_len = if sums.rest == 0.0 && sums.rel == 0.0 { sums.abs += self.gap * self.children.len().saturating_sub(1) as f32; sums } else { Len::default() }; let mut max_ortho = Len::ZERO; for child in &self.children { let len = ctx.size(child).axis(!self.dir.axis); // TODO: rel shouldn't do this, but no easy way before actually calculating pixels if len.rel > 0.0 || len.rest > 0.0 { max_ortho.rest = 1.0; max_ortho.abs = 0.0; break; } max_ortho.abs = max_ortho.abs.max(len.abs); } Size::from_axis(self.dir.axis, dir_len, max_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 } fn len_sum(&mut self, ctx: &mut SizeCtx) -> Len { self.children.iter_mut().fold(Len::ZERO, |mut s, id| { s += ctx.size(id).axis(self.dir.axis); s }) } } pub struct SpanBuilder, Tag> { pub children: Wa, pub dir: Dir, pub gap: f32, _pd: PhantomData, } impl, Tag> FnOnce<(&mut Ui,)> for SpanBuilder { type Output = Span; extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output { Span { children: self.children.ui(args.0).arr.to_vec(), 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 } }