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

+54 -37
View File
@@ -3,23 +3,28 @@ use crate::{Px, PxVec2, Rel, UiNum, Weight, util::impl_op};
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct Size {
pub x: Len,
pub y: Len,
pub x: LayoutLen,
pub y: LayoutLen,
}
/// What a widget asks for along one axis: pixels, a fraction of the box it
/// is given, and a share of whatever is left over once everything fixed has
/// been taken. The three add up rather than choosing between one another.
/// What a widget asks for along one axis: a [`Len`] -- pixels and a fraction
/// of the box it is given -- plus a share of whatever is left over once
/// everything fixed has been taken. The parts add up rather than choosing
/// between one another.
///
/// Only a container dividing its room can answer a share, so a length nobody
/// divides is a `Len`: a position, a padding, a cap, anything already
/// resolved.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Len {
pub struct LayoutLen {
pub px: Px,
pub rel: Rel,
pub leftover: Weight,
}
impl<N: UiNum> From<N> for Len {
impl<N: UiNum> From<N> for LayoutLen {
fn from(value: N) -> Self {
Len::px(value.to_f32())
LayoutLen::px(value.to_f32())
}
}
@@ -32,21 +37,33 @@ impl<Nx: UiNum, Ny: UiNum> From<(Nx, Ny)> for Size {
}
}
impl From<Len> for Size {
fn from(value: Len) -> Self {
/// A length with no share in it is a length a container does not have to
/// divide, which is one it can always give.
impl From<Len> for LayoutLen {
fn from(len: Len) -> Self {
Self {
px: len.px,
rel: len.rel,
leftover: Weight::ZERO,
}
}
}
impl From<LayoutLen> for Size {
fn from(value: LayoutLen) -> Self {
Self { x: value, y: value }
}
}
impl Size {
pub const ZERO: Self = Self {
x: Len::ZERO,
y: Len::ZERO,
x: LayoutLen::ZERO,
y: LayoutLen::ZERO,
};
pub const LEFTOVER: Self = Self {
x: Len::LEFTOVER,
y: Len::LEFTOVER,
x: LayoutLen::LEFTOVER,
y: LayoutLen::LEFTOVER,
};
/// From something measured outside layout -- a texture, a shaped line --
@@ -57,28 +74,28 @@ impl Size {
pub const fn from_px(v: PxVec2) -> Self {
Self {
x: Len {
x: LayoutLen {
px: v.x,
..Len::ZERO
..LayoutLen::ZERO
},
y: Len {
y: LayoutLen {
px: v.y,
..Len::ZERO
..LayoutLen::ZERO
},
}
}
pub fn rel(v: Vec2) -> Self {
Self {
x: Len::rel(v.x),
y: Len::rel(v.y),
x: LayoutLen::rel(v.x),
y: LayoutLen::rel(v.y),
}
}
pub fn leftover(v: Vec2) -> Self {
Self {
x: Len::leftover(v.x),
y: Len::leftover(v.y),
x: LayoutLen::leftover(v.x),
y: LayoutLen::leftover(v.y),
}
}
@@ -89,7 +106,7 @@ impl Size {
}
}
pub fn from_axis(axis: Axis, aligned: Len, ortho: Len) -> Self {
pub fn from_axis(axis: Axis, aligned: LayoutLen, ortho: LayoutLen) -> Self {
match axis {
Axis::X => Self {
x: aligned,
@@ -102,7 +119,7 @@ impl Size {
}
}
pub fn axis(&self, axis: Axis) -> Len {
pub fn axis(&self, axis: Axis) -> LayoutLen {
match axis {
Axis::X => self.x,
Axis::Y => self.y,
@@ -110,7 +127,7 @@ impl Size {
}
}
impl Len {
impl LayoutLen {
pub const ZERO: Self = Self {
px: Px::ZERO,
rel: Rel::ZERO,
@@ -126,12 +143,12 @@ impl Len {
/// The whole of what is left over counts as the whole box, which is what
/// a length means to something that is not dividing a box between
/// siblings -- a scroll asking how long its content is.
pub fn apply_leftover(&self) -> UiScalar {
pub fn apply_leftover(&self) -> Len {
let share = match self.leftover > Weight::ZERO {
true => Rel::ONE,
false => Rel::ZERO,
};
UiScalar::from_parts(self.rel.add(share), self.px)
Len::from_parts(self.rel.add(share), self.px)
}
pub fn px(px: impl UiNum) -> Self {
@@ -157,24 +174,24 @@ impl Len {
pub mod len_fns {
use super::*;
pub fn px(px: impl UiNum) -> Len {
Len::px(px)
pub fn px(px: impl UiNum) -> LayoutLen {
LayoutLen::px(px)
}
pub fn rel(rel: impl UiNum) -> Len {
Len::rel(rel)
pub fn rel(rel: impl UiNum) -> LayoutLen {
LayoutLen::rel(rel)
}
pub fn leftover(ratio: impl UiNum) -> Len {
Len::leftover(ratio)
pub fn leftover(ratio: impl UiNum) -> LayoutLen {
LayoutLen::leftover(ratio)
}
}
impl_op!(same Len Add add; px rel leftover);
impl_op!(same Len Sub sub; px rel leftover);
impl_op!(same LayoutLen Add add; px rel leftover);
impl_op!(same LayoutLen Sub sub; px rel leftover);
impl_op!(same Size Add add; x y);
impl_op!(same Size Sub sub; x y);
impl Default for Len {
impl Default for LayoutLen {
fn default() -> Self {
Self::leftover(1.0)
}
@@ -186,7 +203,7 @@ impl std::fmt::Display for Size {
}
}
impl std::fmt::Display for Len {
impl std::fmt::Display for LayoutLen {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.px != Px::ZERO {
write!(f, "{} px;", self.px)?;