Carry a length as a rule beside a widget, not a widget around it

`.width()` built a `SetSize` whose whole job was to answer `size_hint`, so
every declared length cost a widget, an `ActiveData` and a link of chain to
say one number. It is now a `SizeRule` per axis on `WidgetData`, beside
`region_node`, resolved by `Painter` where the widget is drawn. `SetSize`
and `MaxSize` are gone; `MaxSize` had no caller but its own builders.

That settles which of two answers is the size. A rule wins on the axis it
names and the `Size` returned by `draw` answers the rest, applied once in
`draw_inner` rather than by each widget that could carry one -- so the
widget under a rule never learns of it. `Painter::size_hint` reads the rule
first for the same reason: a rule that beats what a widget would draw has
to beat what it says about itself.

`declared_lens` still falls back to a non-leftover `size_hint`, which is
how an image or a gap gets its own pixel size rather than the whole offer.
That is the offer's business rather than a declaration's, and it falls away
when a widget occupies its reported size inside the box it was offered.

`known` and `declared` are separate because a share is a length to whoever
divides one and not to whoever composes a box: `.width(leftover(3))` is
known without drawing but cannot narrow anything.

Checked: fmt, clippy, 85 tests, and 100 generated seeds agreeing warm
against cold in 67.6 s. `minimal`, `text` and `view` render byte-identical
at 1920x1200; `tabs` differs only in the widget count it prints about
itself, which is two wrapper types smaller.
This commit is contained in:
iris-ai committed 2026-09-15 19:44:21 -04:00
1 parent 0283c9d6c7
commit 8220a78d4a
21 files changed
+252 -214

No files matched your search

+2 -2
View File
@@ -10,7 +10,7 @@ use iris::prelude::*;
/// A row of a fixed height under a bar, so changing the bar's height moves the
/// row without changing the box it is given: the move path, repeatedly.
fn plant(h: &mut Harness, bar_height: f32) -> (WeakWidget<SetSize>, WeakWidget<Rect>) {
fn plant(h: &mut Harness, bar_height: f32) -> (WeakWidget<Rect>, WeakWidget<Rect>) {
let bar = rect(Color::RED).height(bar_height).add(&mut h.rsc);
let inner = rect(Color::BLUE).add(&mut h.rsc);
let row = (inner, rect(Color::GREEN)).span(Dir::RIGHT).height(100);
@@ -33,7 +33,7 @@ fn a_subtree_moved_many_times_stays_where_a_cold_layout_puts_it() {
let mut height = 40.0;
for step in 0..MOVES {
height = 40.0 + (step % 300) as f32 * 0.37;
warm.rsc[bar].y = Some(Len::px(height));
warm.set_len(bar, Axis::Y, height);
warm.frame();
}