Say rel base, and give containers back a box to hand over

`frame` named a length, not a rectangle, which was the one word in the
layout vocabulary that lied about its own shape. It is `rel_base`: what a
fraction a widget declares or reports is a fraction of.

Three API changes with it, all for containers that do one simple thing:

- `widget_within(id, region)` returns, taking a box in the widget's own
  coordinates and deriving the child's rel base from it. `Offset` and `Pad`
  are one call each again. `Offset` also stops reading `region_len`, which
  pinned its drawing to a box length it does not care about.
- `place_at` takes the rel base, returns the answer, and asks the child
  where there is no answer to re-express. Which of the two happens is the
  painter's to work out, so `Span`'s second pass is one call and its
  `drawn_across` bookkeeping is gone.
- `Part::All` is a `Part::WHOLE` constant rather than a variant, since it
  was exactly `Of(UiSpan::FULL)` and bought a separate arm in two matches.
  Measured at 0.07% of instructions retired against 0.04% run-to-run noise.

Cold layout is byte-identical to `84dad21` over 400 depth-5 trees.
This commit is contained in:
iris-ai committed 2026-09-19 16:33:49 -04:00
1 parent a904cf4f36
commit aeb60e50f5
16 files changed
+246 -238

No files matched your search

+2 -2
View File
@@ -24,12 +24,12 @@ impl Widget for BranchesOnMeasurement {
let cut = Len::from_parts(Rel::ZERO, Px::from_int(40));
let top = Place::Within(Part::From(UiSpan::new(Len::ZERO, cut)));
let measured = painter
.widget_at(&self.probe, [None; 2], [Place::Within(Part::All), top])
.widget_at(&self.probe, [None; 2], [Place::Within(Part::WHOLE), top])
.len(Axis::X);
let px = painter.to_px(measured.apply_leftover(), Axis::X);
let below = Place::Within(Part::From(UiSpan::new(cut, painter.region_len(Axis::Y))));
let place = [Place::Within(Part::All), below];
let place = [Place::Within(Part::WHOLE), below];
match px > Px::from_f32(self.threshold) {
true => painter.widget_at(&self.wide, [None; 2], place),
false => painter.widget_at(&self.narrow, [None; 2], place),
+4 -4
View File
@@ -108,7 +108,7 @@ const PARAGRAPH: &str = "Wrapping shapes one source into as many lines as the bo
/// the icon's width, while a wrapping text beside it is asked in the room
/// left, 900 - 24 - 32, and wraps there.
#[test]
fn padding_keeps_the_frame_distinct_from_the_room_left_in_a_row() {
fn padding_keeps_the_rel_base_distinct_from_the_room_left_in_a_row() {
let mut h = Harness::new((900, 200));
let icon = rect(Color::RED).width(24).add(&mut h.rsc);
let fill = rect(Color::GREEN).width(rel(1.0)).add(&mut h.rsc);
@@ -125,7 +125,7 @@ fn padding_keeps_the_frame_distinct_from_the_room_left_in_a_row() {
let active = &h.render.active[&text.id()];
let window = h.render.output_size().x;
let asked = active.region.x.len().to_px(window);
assert_eq!(active.frame.x.to_px(window), Px::from_int(868));
assert_eq!(active.rel_base.x.to_px(window), Px::from_int(868));
assert_eq!(asked, Px::from_int(844));
}
@@ -155,7 +155,7 @@ fn a_share_inside_padding_fills_the_slot_it_was_given() {
/// The same padding in a share instead: the slot is 450, so both the
/// fraction and the wrap are the slot less the padding, and the two agree.
#[test]
fn padding_narrows_both_frame_and_box_inside_a_share() {
fn padding_narrows_both_rel_base_and_box_inside_a_share() {
let mut h = Harness::new((900, 200));
let fill = rect(Color::GREEN).width(rel(1.0)).add(&mut h.rsc);
let padded = fill.pad(16).width(leftover(1)).add(&mut h.rsc);
@@ -170,7 +170,7 @@ fn padding_narrows_both_frame_and_box_inside_a_share() {
h.set_root((padded, other).span(Dir::RIGHT).width(rel(1.0)));
let active = &h.render.active[&text.id()];
let window = h.render.output_size().x;
assert_eq!(active.frame.x.to_px(window), Px::from_int(418));
assert_eq!(active.rel_base.x.to_px(window), Px::from_int(418));
assert_eq!(active.region.x.len().to_px(window), Px::from_int(418));
}
+1 -1
View File
@@ -217,7 +217,7 @@ impl Widget for FromHint {
painter.widget_at(
&self.inner,
[None; 2],
[Place::Within(Part::All), Place::Within(Part::From(top))],
[Place::Within(Part::WHOLE), Place::Within(Part::From(top))],
);
Size::LEFTOVER
}
+2 -2
View File
@@ -406,8 +406,8 @@ fn describe_widget(id: WidgetId, h: &Harness) -> String {
fn record(id: WidgetId, h: &Harness) -> String {
let active = &h.render.active[&id];
format!(
"frame {} region {} placement {} size {}",
active.frame, active.region, active.placement, active.size,
"rel_base {} region {} placement {} size {}",
active.rel_base, active.region, active.placement, active.size,
)
}