Put lengths, padding, gaps and alignment on the grid too

`Len` is `Px` beside `Rel` beside `Weight`, so the seam `4e28f10` left in
`Span` -- a float length added to a fixed-point cursor -- is gone, and the
sum a span compares against its box is exact.

`Weight` is its own scale, `Fixed<16>`, because a share of what is left over
is not a fraction of anything: a list divides its room by the total of them,
so the range has to hold a whole list's worth while the precision only has to
tell two weights apart. `Rel::ratio` turns two weights into a share on the
finer grid, which is what a span needs and what dividing them on their own
grid would round away.

`AxisAlign` holds a `Rel` rather than a float, which is what the layout was
reading out of it anyway. `Padding` and `Span::gap` hold `Px`, converted
where they are built instead of on every frame. `RegionAlign::rel` is gone;
its one caller wanted a position, and now builds one.

`Fixed` gains `from_num` for a number as it is written in source, `mul_int`
for a length repeated a whole number of times, and `ratio`.

Checked: fmt, clippy, 101 tests, 100 generated seeds in 86 s, all five
shrinker cases at 300 seeds, and all five examples byte-identical at
1920x1200 against `4e28f10`.

With the fuzzer comparing for equality rather than within 0.05 px, four of
the five cases now pass 100 seeds -- `resize-repaint` joins the other three.
`reorder` still fails one seed by one step, so the last of it is in what a
box is measured *in*: `px_len` and the window are still floats.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-16 01:40:42 -04:00
1 parent 4e28f1047e
commit bd6de71a55
15 files changed
+199 -158

No files matched your search

+26 -28
View File
@@ -24,22 +24,22 @@ impl Widget for Pad {
}
pub struct Padding {
pub left: f32,
pub right: f32,
pub top: f32,
pub bottom: f32,
pub left: Px,
pub right: Px,
pub top: Px,
pub bottom: Px,
}
impl Padding {
pub const ZERO: Self = Self {
left: 0.0,
right: 0.0,
top: 0.0,
bottom: 0.0,
left: Px::ZERO,
right: Px::ZERO,
top: Px::ZERO,
bottom: Px::ZERO,
};
pub fn uniform(amt: impl UiNum) -> Self {
let amt = amt.to_f32();
let amt = Px::from_num(amt);
Self {
left: amt,
right: amt,
@@ -49,78 +49,76 @@ impl Padding {
}
pub fn region(&self) -> UiRegion {
let mut region = UiRegion::FULL;
region.x.start.px += Px::from_f32(self.left);
region.y.start.px += Px::from_f32(self.top);
region.x.end.px -= Px::from_f32(self.right);
region.y.end.px -= Px::from_f32(self.bottom);
region.x.start.px += self.left;
region.y.start.px += self.top;
region.x.end.px -= self.right;
region.y.end.px -= self.bottom;
region
}
pub fn x(amt: impl UiNum) -> Self {
let amt = amt.to_f32();
let amt = Px::from_num(amt);
Self {
left: amt,
right: amt,
top: 0.0,
bottom: 0.0,
..Self::ZERO
}
}
pub fn y(amt: impl UiNum) -> Self {
let amt = amt.to_f32();
let amt = Px::from_num(amt);
Self {
left: 0.0,
right: 0.0,
top: amt,
bottom: amt,
..Self::ZERO
}
}
pub fn top(amt: impl UiNum) -> Self {
let mut s = Self::ZERO;
s.top = amt.to_f32();
s.top = Px::from_num(amt);
s
}
pub fn bottom(amt: impl UiNum) -> Self {
let mut s = Self::ZERO;
s.bottom = amt.to_f32();
s.bottom = Px::from_num(amt);
s
}
pub fn left(amt: impl UiNum) -> Self {
let mut s = Self::ZERO;
s.left = amt.to_f32();
s.left = Px::from_num(amt);
s
}
pub fn right(amt: impl UiNum) -> Self {
let mut s = Self::ZERO;
s.right = amt.to_f32();
s.right = Px::from_num(amt);
s
}
pub fn with_top(mut self, amt: impl UiNum) -> Self {
self.top = amt.to_f32();
self.top = Px::from_num(amt);
self
}
pub fn with_bottom(mut self, amt: impl UiNum) -> Self {
self.bottom = amt.to_f32();
self.bottom = Px::from_num(amt);
self
}
pub fn with_left(mut self, amt: impl UiNum) -> Self {
self.left = amt.to_f32();
self.left = Px::from_num(amt);
self
}
pub fn with_right(mut self, amt: impl UiNum) -> Self {
self.right = amt.to_f32();
self.right = Px::from_num(amt);
self
}
}
impl<T: UiNum> From<T> for Padding {
fn from(amt: T) -> Self {
Self::uniform(amt.to_f32())
Self::uniform(amt)
}
}