switch to element defined span lens + better size fn

This commit is contained in:
2025-11-13 14:27:31 -05:00
parent 8755c04feb
commit 73afea8c35
17 changed files with 767 additions and 646 deletions

View File

@@ -1,36 +1,26 @@
use crate::prelude::*;
pub struct Span {
pub children: Vec<(WidgetId, SpanLen)>,
pub children: Vec<WidgetId>,
pub dir: Dir,
pub spacing: f32,
}
impl Widget for Span {
fn draw(&mut self, painter: &mut Painter) {
let total = self.setup(&mut painter.size_ctx());
let total = self.len_sum(&mut painter.size_ctx());
let mut start = UiScalar::rel_min();
for (child, length) in &self.children {
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);
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;
}
let len = painter.size(child).axis(self.dir.axis);
start.abs += len.abs;
start.rel += len.rel;
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);
}
axis.bot_right.set(start);
if self.dir.sign == Sign::Neg {
@@ -41,33 +31,29 @@ impl Widget for Span {
}
}
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()
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.spacing * self.children.len().saturating_sub(1) as f32;
sums
} else {
UiScalar::new(
total.rel,
total.abs + self.spacing * self.children.len().saturating_sub(1) as f32,
)
Len::default()
};
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));
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);
}
UiVec2::from_axis(axis, dir_len, max_ortho)
Size::from_axis(self.dir.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 {
@@ -82,61 +68,10 @@ impl Span {
self
}
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())
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
})
}
}