Give a length with no share in it its own type again

`UiScalar` was `Len` without the `leftover` weight, which is the separation
canonical `main` already had as `Len` beside `LayoutLen` and this branch
collapsed. It is needed back for the queued clamp: a cap may not contain a
share, because a cap has to read the report a rule otherwise makes moot, and
a share puts the container's division into the same equation -- two
self-consistent assignments, which is the multiple-fixed-point failure
generated seed 13 punished for orthogonal sizing. `min(report, cap)` is not
a `LayoutLen` either: it is a sum of parts, and the smaller of two of them
is not one.

So `UiScalar` is `Len`, what was `Len` is `LayoutLen`, and the two say in
their docs which is which: a `Len` is pixels plus a fraction of a box -- a
position being the length from the box's start, which is why a span is two
of them -- and a `LayoutLen` is a `Len` plus a claim only a container
dividing its room can answer. `From<Len> for LayoutLen` is the one-way step
between them.

Names only; the shader's `UiScalar` is renamed with them. Checked: fmt,
clippy, 105 tests, and `tabs`, `minimal`, `view`, `text` and `random`
byte-identical at 1920x1200.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-16 13:40:15 -04:00
1 parent 4f5e27cba9
commit a8898aaa54
27 files changed
+218 -202

No files matched your search

+1 -1
View File
@@ -165,7 +165,7 @@ impl Harness {
}
/// Changes a length rule after the fact, the way `.width()` sets one.
pub fn set_len(&mut self, id: impl IdLike, axis: Axis, len: impl Into<Len>) {
pub fn set_len(&mut self, id: impl IdLike, axis: Axis, len: impl Into<LayoutLen>) {
self.rsc
.widgets_mut()
.set_size_rule(id, axis, SizeRule::Exact(len.into()));
+5 -5
View File
@@ -9,7 +9,7 @@ use crate::prelude::*;
use std::collections::HashMap;
/// The declared lengths of one widget carrying a size rule, by axis.
pub type Lens = [Option<Len>; 2];
pub type Lens = [Option<LayoutLen>; 2];
/// Where one widget carrying an alignment sits, by axis. `None` uses the
/// centered default.
@@ -181,10 +181,10 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
id
}
fn len(&mut self) -> Option<Len> {
fn len(&mut self) -> Option<LayoutLen> {
match self.rng.below(4) {
0 => Some(Len::px(20.0 + self.rng.below(180) as f32)),
1 => Some(Len::LEFTOVER),
0 => Some(LayoutLen::px(20.0 + self.rng.below(180) as f32)),
1 => Some(LayoutLen::LEFTOVER),
_ => None,
}
}
@@ -367,7 +367,7 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
if dir.axis == Axis::X {
self.rsc
.widgets_mut()
.set_size_rules(id, None, Some(Len::rel(1.0)));
.set_size_rules(id, None, Some(LayoutLen::rel(1.0)));
}
self.tree.ids.push(id.id());
self.tree.spans.push(Spanned { id, spares, grown });
+2 -2
View File
@@ -11,8 +11,8 @@ impl Widget for Image {
Size::px(self.handle.size())
}
fn size_hint(&self, axis: Axis) -> Option<Len> {
Some(Len::px(self.handle.size().axis(axis)))
fn size_hint(&self, axis: Axis) -> Option<LayoutLen> {
Some(LayoutLen::px(self.handle.size().axis(axis)))
}
}
+2 -2
View File
@@ -11,11 +11,11 @@ impl Widget for Pad {
.widget_aligned(&self.inner, self.padding.region(), RegionAlign::NEAR)
.size();
Size {
x: Len {
x: LayoutLen {
px: inner.x.px + self.padding.left + self.padding.right,
..inner.x
},
y: Len {
y: LayoutLen {
px: inner.y.px + self.padding.top + self.padding.bottom,
..inner.y
},
+2 -2
View File
@@ -57,8 +57,8 @@ impl Widget for Scroll {
if moved || self.content_len != self.container_len {
let offset = UiVec2::from_axis(
self.axis,
UiScalar::from_parts(Rel::ZERO, anchor - self.amt),
UiScalar::ZERO,
Len::from_parts(Rel::ZERO, anchor - self.amt),
Len::ZERO,
);
region = region.offset(offset);
region.axis_mut(self.axis).end = region.axis(self.axis).start.offset(self.content_len);
+11 -11
View File
@@ -12,10 +12,10 @@ impl Widget for Span {
let axis = self.dir.axis;
// A length for every child before their final boxes are chosen: from
// a hint where one exists, and from drawing otherwise.
let mut cursor = UiScalar::rel_min();
let mut cursor = Len::rel_min();
let mut lens = Vec::with_capacity(self.children.len());
for child in &self.children {
let mut span = UiSpan::new(cursor, UiScalar::rel_max());
let mut span = UiSpan::new(cursor, Len::rel_max());
if self.dir.sign == Sign::Neg {
span.flip();
}
@@ -33,9 +33,9 @@ impl Widget for Span {
.gap
.mul_int(self.children.len().saturating_sub(1) as i32);
let total = lens.iter().fold(
Len {
LayoutLen {
px: gaps,
..Len::ZERO
..LayoutLen::ZERO
},
|sum, len| sum + *len,
);
@@ -89,11 +89,11 @@ impl Widget for Span {
// from the last child: the share of the room is rounded, and taking
// each from the one before it would carry every rounding along the
// row.
let mut fixed = UiScalar::rel_min();
let mut fixed = Len::rel_min();
let mut taken = Weight::ZERO;
let room = UiScalar::rel_max() - UiScalar::from_parts(total.rel, total.px);
let mut start = UiScalar::rel_min();
let mut ortho = Len::ZERO;
let room = Len::rel_max() - Len::from_parts(total.rel, total.px);
let mut start = Len::rel_min();
let mut ortho = LayoutLen::ZERO;
for (child, len) in self.children.iter().zip(&lens) {
// A child asking for nothing but a part of what is left over,
// when nothing is, is not drawn at all. One that also asked for
@@ -125,7 +125,7 @@ impl Widget for Span {
// A scalable child therefore makes Children scalable too;
// only fixed children are compared with one another.
if used.rel != Rel::ZERO || used.leftover != Weight::ZERO {
ortho = Len::LEFTOVER;
ortho = LayoutLen::LEFTOVER;
} else if ortho.leftover == Weight::ZERO {
ortho.px = ortho.px.max(used.px);
}
@@ -144,7 +144,7 @@ impl Widget for Span {
let along = total;
let ortho = match shrinks {
true => ortho,
false => Len::rel(1.0),
false => LayoutLen::rel(1.0),
};
Size::from_axis(axis, along, ortho)
}
@@ -153,7 +153,7 @@ impl Widget for Span {
/// Where a row has reached: everything fixed before this point, which is a
/// sum and exact, plus the share of the room the weights so far are worth,
/// which is one rounding wherever it is asked for.
fn shared(fixed: UiScalar, taken: Weight, weight: Weight, room: UiScalar) -> UiScalar {
fn shared(fixed: Len, taken: Weight, weight: Weight, room: Len) -> Len {
if taken == Weight::ZERO {
return fixed;
}
+2 -2
View File
@@ -38,8 +38,8 @@ impl Widget for Rect {
Size::LEFTOVER
}
fn size_hint(&self, _: Axis) -> Option<Len> {
Some(Len::LEFTOVER)
fn size_hint(&self, _: Axis) -> Option<LayoutLen> {
Some(LayoutLen::LEFTOVER)
}
}
+2 -2
View File
@@ -59,7 +59,7 @@ widget_trait! {
}
}
fn width(self, len: impl Into<Len>) -> impl WidgetIdFn<Rsc, WL::Widget> {
fn width(self, len: impl Into<LayoutLen>) -> impl WidgetIdFn<Rsc, WL::Widget> {
let len = len.into();
move |state| {
let id = self.add(state);
@@ -71,7 +71,7 @@ widget_trait! {
}
}
fn height(self, len: impl Into<Len>) -> impl WidgetIdFn<Rsc, WL::Widget> {
fn height(self, len: impl Into<LayoutLen>) -> impl WidgetIdFn<Rsc, WL::Widget> {
let len = len.into();
move |state| {
let id = self.add(state);