117 lines
3.3 KiB
Rust
117 lines
3.3 KiB
Rust
use std::marker::PhantomData;
|
|
|
|
use crate::prelude::*;
|
|
|
|
pub struct Span {
|
|
pub children: Vec<WidgetId>,
|
|
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<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> {
|
|
pub children: Wa,
|
|
pub dir: Dir,
|
|
pub gap: f32,
|
|
_pd: PhantomData<Tag>,
|
|
}
|
|
|
|
impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> FnOnce<(&mut Ui,)>
|
|
for SpanBuilder<LEN, Wa, Tag>
|
|
{
|
|
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<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> SpanBuilder<LEN, Wa, Tag> {
|
|
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
|
|
}
|
|
}
|