132 lines
3.9 KiB
Rust
132 lines
3.9 KiB
Rust
use crate::prelude::*;
|
|
|
|
pub struct Span {
|
|
pub children: Vec<(WidgetId, SpanLen)>,
|
|
pub dir: Dir,
|
|
}
|
|
|
|
impl Widget for Span {
|
|
fn draw(&mut self, painter: &mut Painter) {
|
|
let total = self.setup(&mut painter.size_ctx());
|
|
let mut start = UiScalar::rel_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.abs += offset;
|
|
}
|
|
SpanLen::Ratio(ratio) => {
|
|
let offset = UiScalar::new(total.rel, total.abs);
|
|
let rel_end = UiScalar::from_anchor(ratio / total.ratio);
|
|
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset);
|
|
}
|
|
SpanLen::Relative(rel) => {
|
|
start.rel += rel;
|
|
}
|
|
SpanLen::Sized(size) => {
|
|
let size_axis = size.axis(self.dir.axis);
|
|
start.abs += size_axis.abs;
|
|
start.rel += size_axis.rel;
|
|
}
|
|
}
|
|
axis.bot_right.set(start);
|
|
if self.dir.sign == Sign::Neg {
|
|
child_region.flip(self.dir.axis);
|
|
}
|
|
painter.widget_within(child, child_region);
|
|
}
|
|
}
|
|
|
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
|
let total = self.setup(ctx);
|
|
let axis = self.dir.axis;
|
|
let dir_len = if total.ratio != 0.0 {
|
|
UiScalar::rel_max()
|
|
} else {
|
|
UiScalar::new(total.rel, total.abs)
|
|
};
|
|
let mut max_ortho = UiScalar::ZERO;
|
|
for (child, _) in &self.children {
|
|
let size = ctx.size(child);
|
|
max_ortho = max_ortho.max(size.axis(!self.dir.axis));
|
|
}
|
|
UiVec2::from_axis(axis, dir_len, max_ortho)
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct SpanLenSums {
|
|
pub abs: f32,
|
|
pub ratio: f32,
|
|
pub rel: f32,
|
|
}
|
|
|
|
impl Span {
|
|
pub fn empty(dir: Dir) -> Self {
|
|
Self {
|
|
children: Vec::new(),
|
|
dir,
|
|
}
|
|
}
|
|
|
|
fn setup(&mut self, ctx: &mut SizeCtx) -> SpanLenSums {
|
|
self.children
|
|
.iter_mut()
|
|
.fold(SpanLenSums::default(), |mut s, (id, l)| {
|
|
match l {
|
|
SpanLen::Fixed(v) => s.abs += *v,
|
|
SpanLen::Ratio(v) => s.ratio += *v,
|
|
SpanLen::Relative(v) => s.rel += *v,
|
|
SpanLen::Sized(v) => {
|
|
let size = ctx.size(id);
|
|
let len = size.axis(self.dir.axis);
|
|
*v = size;
|
|
s.abs += len.abs;
|
|
s.rel += len.rel;
|
|
}
|
|
}
|
|
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),
|
|
/// size determined by the child widget itself
|
|
/// the value is not used externally, I just don't wanna make a duplicate enum
|
|
/// there are util functions instead so
|
|
Sized(UiVec2),
|
|
}
|
|
|
|
pub fn fixed<N: UiNum>(x: N) -> SpanLen {
|
|
SpanLen::Fixed(x.to_f32())
|
|
}
|
|
|
|
pub fn ratio<N: UiNum>(x: N) -> SpanLen {
|
|
SpanLen::Ratio(x.to_f32())
|
|
}
|
|
|
|
pub fn relative<N: UiNum>(x: N) -> SpanLen {
|
|
SpanLen::Relative(x.to_f32())
|
|
}
|
|
|
|
pub fn sized() -> SpanLen {
|
|
SpanLen::Sized(UiVec2::default())
|
|
}
|
|
|
|
impl<N: UiNum> From<N> for SpanLen {
|
|
fn from(value: N) -> Self {
|
|
Self::Ratio(value.to_f32())
|
|
}
|
|
}
|