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

+6 -4
View File
@@ -14,7 +14,7 @@ impl Widget for Scroll {
let container_len = painter.px_len(self.axis);
// Asked in the whole viewport, then put at the scrolled offset.
let answer_len = painter
.widget_at(&self.inner, [None; 2], [Place::Fill(Part::All); 2])
.widget_at(&self.inner, [None; 2], [Place::Fill(Part::WHOLE); 2])
.len(self.axis);
let fixed = painter.to_px(Len::from_parts(answer_len.rel, answer_len.px), self.axis);
self.container_len = container_len;
@@ -56,15 +56,17 @@ impl Widget for Scroll {
let start = Len::from_parts(Rel::ZERO, anchor - self.amt);
Part::From(UiSpan::new(start, start.offset(self.content_len)))
}
false => Part::All,
false => Part::WHOLE,
};
// The viewport is the inner's frame, so a fraction it declares or
// The viewport is the inner's rel base, so a fraction it declares or
// reports is a fraction of what is on screen rather than of the
// content box its own answer decided. Where it goes is the content
// box, scrolled: its drawing moved there, not made again there.
painter.place_at(
&self.inner,
self.axis.pair(Place::Fill(content), Place::Fill(Part::All)),
[None; 2],
self.axis
.pair(Place::Fill(content), Place::Fill(Part::WHOLE)),
);
// What it occupies is its box, on both axes: it clips its content to
// that box, so it can neither take less of one nor honestly ask for