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

+42 -38
View File
@@ -6,41 +6,41 @@ use crate::{Px, PxVec2, Rel, UiNum, util::impl_op};
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, bytemuck::Pod, bytemuck::Zeroable, Default)]
pub struct UiVec2 {
pub x: UiScalar,
pub y: UiScalar,
pub x: Len,
pub y: Len,
}
impl UiVec2 {
pub const ZERO: Self = Self {
x: UiScalar::ZERO,
y: UiScalar::ZERO,
x: Len::ZERO,
y: Len::ZERO,
};
pub const fn new(x: UiScalar, y: UiScalar) -> Self {
pub const fn new(x: Len, y: Len) -> Self {
Self { x, y }
}
pub const fn px(px: impl const Into<Vec2>) -> Self {
let px = px.into();
Self {
x: UiScalar::px(px.x),
y: UiScalar::px(px.y),
x: Len::px(px.x),
y: Len::px(px.y),
}
}
/// From lengths already on the grid, with no fraction of a box.
pub const fn from_px(px: PxVec2) -> Self {
Self {
x: UiScalar::from_parts(Rel::ZERO, px.x),
y: UiScalar::from_parts(Rel::ZERO, px.y),
x: Len::from_parts(Rel::ZERO, px.x),
y: Len::from_parts(Rel::ZERO, px.y),
}
}
pub const fn rel(rel: impl const Into<Vec2>) -> Self {
let rel = rel.into();
Self {
x: UiScalar::rel(rel.x),
y: UiScalar::rel(rel.y),
x: Len::rel(rel.x),
y: Len::rel(rel.y),
}
}
@@ -61,14 +61,14 @@ impl UiVec2 {
}
}
pub fn axis_mut(&mut self, axis: Axis) -> &mut UiScalar {
pub fn axis_mut(&mut self, axis: Axis) -> &mut Len {
match axis {
Axis::X => &mut self.x,
Axis::Y => &mut self.y,
}
}
pub fn axis(&self, axis: Axis) -> UiScalar {
pub fn axis(&self, axis: Axis) -> Len {
match axis {
Axis::X => self.x,
Axis::Y => self.y,
@@ -83,7 +83,7 @@ impl UiVec2 {
pub const FULL_SIZE: Self = Self::rel(Vec2::ONE);
pub const fn from_axis(axis: Axis, aligned: UiScalar, ortho: UiScalar) -> Self {
pub const fn from_axis(axis: Axis, aligned: Len, ortho: Len) -> Self {
match axis {
Axis::X => Self {
x: aligned,
@@ -129,21 +129,27 @@ where
}
}
/// A position along one axis, as a fraction of the box it sits in plus an
/// offset: `rel * len + px`. Both parts are fixed point, so composing one
/// through a chain of boxes rounds only where it multiplies and lands on the
/// same number as any other route to the same place.
/// A length along one axis: a fraction of the box it is measured in plus an
/// offset, `rel * box + px`. A position is the same number -- the length from
/// the start of the box to the point -- which is why a [`UiSpan`] is two of
/// these. Both parts are fixed point, so composing one through a chain of
/// boxes rounds only where it multiplies, and lands on the same number as any
/// other route to the same place.
///
/// It carries no claim on what a container has left over. That is
/// [`crate::LayoutLen`], which is this plus a weight, and which means nothing
/// to anyone but whoever divides the room.
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, bytemuck::Pod, Default, bytemuck::Zeroable)]
pub struct UiScalar {
pub struct Len {
pub rel: Rel,
pub px: Px,
}
impl_op!(same UiScalar Add add; rel px);
impl_op!(same UiScalar Sub sub; rel px);
impl_op!(same Len Add add; rel px);
impl_op!(same Len Sub sub; rel px);
impl UiScalar {
impl Len {
pub const ZERO: Self = Self {
rel: Rel::ZERO,
px: Px::ZERO,
@@ -192,10 +198,8 @@ impl UiScalar {
}
}
/// Both channels by the same factor, which is what a fraction of a
/// length means when the length is part pixels and part a share.
/// Both channels by the same fraction, which is what a part of a length
/// means when the length is part pixels and part a share.
/// Both parts by the same fraction, which is what a part of a length
/// means when the length is part pixels and part a fraction of a box.
pub const fn scale(&self, by: Rel) -> Self {
Self {
rel: self.rel.mul(by),
@@ -215,14 +219,14 @@ impl UiScalar {
}
}
pub fn within_len(&self, len: UiScalar) -> Self {
pub fn within_len(&self, len: Len) -> Self {
self.within(&UiSpan {
start: UiScalar::ZERO,
start: Len::ZERO,
end: len,
})
}
pub fn select_len(&self, len: UiScalar) -> Self {
pub fn select_len(&self, len: Len) -> Self {
len.within_len(*self)
}
@@ -245,24 +249,24 @@ impl UiScalar {
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct UiSpan {
pub start: UiScalar,
pub end: UiScalar,
pub start: Len,
pub end: Len,
}
impl UiSpan {
pub const FULL: Self = Self {
start: UiScalar::ZERO,
end: UiScalar::FULL,
start: Len::ZERO,
end: Len::FULL,
};
pub const fn rel(rel: f32) -> Self {
Self {
start: UiScalar::rel(rel),
end: UiScalar::rel(rel),
start: Len::rel(rel),
end: Len::rel(rel),
}
}
pub const fn new(start: UiScalar, end: UiScalar) -> Self {
pub const fn new(start: Len, end: Len) -> Self {
Self { start, end }
}
@@ -273,7 +277,7 @@ impl UiSpan {
std::mem::swap(&mut self.start.px, &mut self.end.px);
}
pub const fn shift(&mut self, offset: UiScalar) {
pub const fn shift(&mut self, offset: Len) {
self.start += offset;
self.end += offset;
}
@@ -285,7 +289,7 @@ impl UiSpan {
}
}
pub const fn len(&self) -> UiScalar {
pub const fn len(&self) -> Len {
self.end - self.start
}
}