Say layout's operations by name, and index a pair by its axis

Four rounds over the same idea: an expression that needed a comment to say
what it computed wanted to be a named operation.

The placement description is built by chaining off the value that says it.
`UiSpan::within_desc`/`shifted_desc` and `Len::as_desc` replace the
`PlaceDescAxis::` constructors, `PlaceDescAxis::axis` lifts one axis into a
pair with the whole box across it, and `PlaceDesc::per_axis` covers the case
where the two axes differ. `beside` is dropped: `from_axis` already said it.

Seven module-level functions become methods on the value each took first --
`Widgets::declared_lens`, `LayoutLen::fills`, `PlaceDesc::placement` and
`::rel_base_and_region`, `Size::within_box`, `UiRegion::at_origin` and
`::as_translation`.

`UiSpan::place` is the aligned-placement rule, which was written out three
times; `LayoutLen::without_leftover` is the sibling `apply_leftover` never
had, at six sites; `is_px` and `is_only_leftover` name field comparisons the
surrounding comments had to translate; `Holds::covers` was interval
containment spelled out by hand. A span's `shared` loses the two arguments
that did not vary across its loop.

`LayoutHolds` was four two-element arrays where every other pair here is a
struct of two per-axis values, so nothing it did could be written once.
It becomes `AxisHolds` on `x` and `y`, and `and`, `covers` and `contains`
lose their loops.

Every pair gets `Index<Axis>`/`IndexMut<Axis>` through one macro, and the
eighteen `axis`/`axis_mut` methods go. `const_index` keeps the accessors
usable in const context.

Cold layout is unchanged: `layout_dump` over 400 depth-5 trees is identical
to 58ce74d byte for byte, across all 34,492 boxes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-19 20:56:59 -04:00
1 parent 58ce74dd7d
commit 55df32a33c
21 files changed
+465 -490

No files matched your search

+4 -4
View File
@@ -22,14 +22,14 @@ struct BranchesOnMeasurement {
impl Widget for BranchesOnMeasurement {
fn draw(&mut self, painter: &mut Painter) -> Size {
let cut = Len::from_parts(Rel::ZERO, Px::from_int(40));
let top = PlaceDescAxis::shifted(UiSpan::new(Len::ZERO, cut));
let top = UiSpan::new(Len::ZERO, cut).shifted_desc();
let measured = painter
.widget_at(&self.probe, PlaceDesc::new(PlaceDescAxis::WHOLE, top))
.widget_at(&self.probe, top.axis(Axis::Y))
.len(Axis::X);
let px = painter.to_px(measured.apply_leftover(), Axis::X);
let below = PlaceDescAxis::shifted(UiSpan::new(cut, painter.region_len(Axis::Y)));
let place = PlaceDesc::new(PlaceDescAxis::WHOLE, below);
let below = UiSpan::new(cut, painter.region_len(Axis::Y)).shifted_desc();
let place = below.axis(Axis::Y);
match px > Px::from_f32(self.threshold) {
true => painter.widget_at(&self.wide, place),
false => painter.widget_at(&self.narrow, place),
+4 -4
View File
@@ -501,10 +501,10 @@ fn a_row_of_equal_shares_fills_it_exactly() {
fn drawn_edges(h: &Harness, id: WidgetId, axis: Axis) -> (f32, f32) {
let active = &h.render.active[&id];
let region = h.render.moves.resolve(active.move_idx, active.placement);
let dim = h.size().axis(axis);
let dim = h.size()[axis];
let snap = |v: f32| (v + Px::STEP.to_f32() * 0.5).floor();
let edge = |s: Len| snap(s.rel.to_f32() * dim + s.px.to_f32());
let span = region.axis(axis);
let span = region[axis];
(edge(span.start), edge(span.end))
}
@@ -853,8 +853,8 @@ fn a_collapsed_share_keeps_the_gaps_before_the_next_slot() {
Sign::Pos => (400 - tail_len, 400),
Sign::Neg => (0, tail_len),
};
assert_eq!(region.top_left.axis(dir.axis), Px::from_int(from));
assert_eq!(region.bot_right.axis(dir.axis), Px::from_int(to));
assert_eq!(region.top_left[dir.axis], Px::from_int(from));
assert_eq!(region.bot_right[dir.axis], Px::from_int(to));
}
}
}
+13 -24
View File
@@ -214,10 +214,7 @@ impl Widget for FromHint {
fn draw(&mut self, painter: &mut Painter) -> Size {
let len = painter.size_hint(&self.inner, Axis::Y).unwrap();
let top = UiSpan::new(Len::ZERO, Len::from_parts(Rel::ZERO, len.px));
painter.widget_at(
&self.inner,
PlaceDesc::new(PlaceDescAxis::WHOLE, PlaceDescAxis::shifted(top)),
);
painter.widget_at(&self.inner, top.shifted_desc().axis(Axis::Y));
Size::LEFTOVER
}
}
@@ -876,10 +873,7 @@ fn resizing_a_fixed_frame_recomposes_its_contents_without_drawing_them() {
fn draw(&mut self, painter: &mut Painter) -> Size {
painter.widget_at(
&self.child,
PlaceDesc::new(
PlaceDescAxis::shifted(self.region.x),
PlaceDescAxis::shifted(self.region.y),
),
PlaceDesc::new(self.region.x.shifted_desc(), self.region.y.shifted_desc()),
);
Size::LEFTOVER
}
@@ -965,8 +959,8 @@ fn glyph_origins_compose_identically_when_drawn_and_when_retained() {
painter.widget_at(
&self.child,
PlaceDesc::new(
PlaceDescAxis::shifted(self.region.x).fills(),
PlaceDescAxis::shifted(self.region.y).fills(),
self.region.x.shifted_desc().fills(),
self.region.y.shifted_desc().fills(),
)
.rel_base(Axis::X, self.frame.x.len()),
);
@@ -1135,8 +1129,8 @@ fn padding_and_stack_boxes_follow_the_region_without_drawing_again() {
painter.widget_at(
&self.child,
PlaceDesc::new(
PlaceDescAxis::shifted(self.region.x).fills(),
PlaceDescAxis::shifted(self.region.y).fills(),
self.region.x.shifted_desc().fills(),
self.region.y.shifted_desc().fills(),
),
);
Size::LEFTOVER
@@ -1222,12 +1216,10 @@ fn moving_a_childs_region_preserves_the_slot_chosen_from_its_measurement() {
painter.widget_at(
&self.child,
PlaceDesc::new(
PlaceDescAxis::shifted(UiSpan::new(
Len::px(self.start),
Len::px(self.start + 200.0),
))
.fills(),
PlaceDescAxis::shifted(UiSpan::FULL).fills(),
UiSpan::new(Len::px(self.start), Len::px(self.start + 200.0))
.shifted_desc()
.fills(),
UiSpan::FULL.shifted_desc().fills(),
),
);
Size::LEFTOVER
@@ -1263,10 +1255,7 @@ fn changing_regions_keep_fractional_reports_and_numeric_dependencies_valid() {
painter
.widget_at(
&self.child,
PlaceDesc::new(
PlaceDescAxis::shifted(self.region.x),
PlaceDescAxis::shifted(self.region.y),
),
PlaceDesc::new(self.region.x.shifted_desc(), self.region.y.shifted_desc()),
)
.size()
}
@@ -1283,8 +1272,8 @@ fn changing_regions_keep_fractional_reports_and_numeric_dependencies_valid() {
.widget_at(
&self.child,
PlaceDesc::new(
PlaceDescAxis::shifted(self.region.x).fills(),
PlaceDescAxis::shifted(self.region.y).fills(),
self.region.x.shifted_desc().fills(),
self.region.y.shifted_desc().fills(),
),
)
.size(),