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:
1 parent
0283c9d6c7
commit
8220a78d4a
21 files changed
+252
-214
No files matched your search
+17
-10
@@ -61,9 +61,9 @@ fn resize_one(h: &mut Harness, tree: &Tree, idx: usize, rng: &mut Rng) -> Lens {
|
||||
Some(Len::px(20.0 + rng.below(180) as f32)),
|
||||
Some(Len::px(20.0 + rng.below(180) as f32)),
|
||||
];
|
||||
let sized = &mut h.rsc[tree.sized[idx]];
|
||||
sized.x = lens[0];
|
||||
sized.y = lens[1];
|
||||
h.rsc
|
||||
.widgets_mut()
|
||||
.set_size_rules(tree.sized[idx], lens[0], lens[1]);
|
||||
lens
|
||||
}
|
||||
|
||||
@@ -174,18 +174,25 @@ fn reshuffle(
|
||||
/// written out by hand. A fuzz failure is a lead; the fast test that replaces
|
||||
/// it has to be buildable from what the failure printed.
|
||||
fn describe(id: WidgetId, h: &Harness) -> String {
|
||||
let rules = h.rsc.widgets().size_rules(id);
|
||||
let rule = |r: SizeRule| match r.known() {
|
||||
Some(len) => format!("{len}"),
|
||||
None => "-".into(),
|
||||
};
|
||||
// A size rule is a property of whatever carries it, so it prints with
|
||||
// that widget rather than as one of its own.
|
||||
match (rules.x, rules.y) {
|
||||
(SizeRule::Free, SizeRule::Free) => describe_widget(id, h),
|
||||
(x, y) => format!("{}[x:{},y:{}]", describe_widget(id, h), rule(x), rule(y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn describe_widget(id: WidgetId, h: &Harness) -> String {
|
||||
let label = h.rsc.widgets().label(id).to_string();
|
||||
let Some(widget) = h.rsc.widgets().get_dyn(id) else {
|
||||
return label;
|
||||
};
|
||||
let any: &dyn std::any::Any = widget;
|
||||
let len = |l: &Option<Len>| match l {
|
||||
Some(l) => format!("{l}"),
|
||||
None => "-".into(),
|
||||
};
|
||||
if let Some(w) = any.downcast_ref::<SetSize>() {
|
||||
return format!("SetSize{{x:{},y:{}}}", len(&w.x), len(&w.y));
|
||||
}
|
||||
if let Some(w) = any.downcast_ref::<Span>() {
|
||||
let sign = if w.dir.sign == Sign::Neg { "-" } else { "+" };
|
||||
return format!(
|
||||
|
||||
Reference in new issue
Block a user