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
+13
-26
@@ -81,7 +81,7 @@ fn a_child_drawn_twice_moves_once() {
|
||||
h.set_root((left, centered).span(Dir::RIGHT));
|
||||
assert_corners!(h, inner, (100, 0), (300, 200));
|
||||
|
||||
h.rsc[left].x = Some(Len::px(150));
|
||||
h.set_len(left, Axis::X, 150);
|
||||
h.frame();
|
||||
|
||||
assert_corners!(h, inner, (150, 0), (350, 200));
|
||||
@@ -131,7 +131,7 @@ fn a_fixed_box_is_drawn_again_rather_than_stretched() {
|
||||
h.set_root(stack.align(Align::TOP));
|
||||
assert_corners!(h, panel, (0, 0), (400, 100));
|
||||
|
||||
h.rsc[leaf].y = Some(Len::px(250));
|
||||
h.set_len(leaf, Axis::Y, 250);
|
||||
h.frame();
|
||||
|
||||
assert_corners!(h, panel, (0, 0), (400, 250));
|
||||
@@ -146,7 +146,7 @@ fn a_moved_subtree_takes_its_children_with_it() {
|
||||
h.set_root((first, row).span(Dir::DOWN));
|
||||
assert_corners!(h, inner, (10, 50), (390, 70));
|
||||
|
||||
h.rsc[first].y = Some(Len::px(80));
|
||||
h.set_len(first, Axis::Y, 80);
|
||||
h.frame();
|
||||
|
||||
// The row opted into one movable region, so its descendants follow one
|
||||
@@ -167,7 +167,7 @@ fn a_fixed_length_child_keeps_it_when_the_box_around_it_grows() {
|
||||
assert_corners!(h, fixed, (100, 0), (150, 200));
|
||||
assert_corners!(h, leftover, (150, 0), (400, 200));
|
||||
|
||||
h.rsc[bar].x = Some(Len::px(200));
|
||||
h.set_len(bar, Axis::X, 200);
|
||||
h.frame();
|
||||
|
||||
// The panel's box is 100 shorter, so the fixed child is the same 50 wide
|
||||
@@ -195,7 +195,7 @@ fn a_box_with_a_fixed_length_can_be_stretched_on_its_other_axis() {
|
||||
h.set_root((bar, column).span(Dir::RIGHT));
|
||||
assert_corners!(h, inner, (110, 10), (390, 30));
|
||||
|
||||
h.rsc[bar].x = Some(Len::px(200));
|
||||
h.set_len(bar, Axis::X, 200);
|
||||
h.frame();
|
||||
|
||||
assert_corners!(h, inner, (210, 10), (390, 30));
|
||||
@@ -282,24 +282,14 @@ fn drawn_edges(h: &Harness, id: WidgetId, axis: Axis) -> (f32, f32) {
|
||||
}
|
||||
|
||||
fn hairline(h: &mut Harness, marks: &mut Vec<WidgetId>) -> StrongWidget {
|
||||
let inner = rect(Color::RED).add_strong(&mut h.rsc);
|
||||
let mark = SetSize {
|
||||
inner,
|
||||
x: Some(Len::px(1.0)),
|
||||
y: None,
|
||||
}
|
||||
.add_strong(&mut h.rsc);
|
||||
let mark = rect(Color::RED).width(1).add_strong(&mut h.rsc);
|
||||
marks.push(mark.id());
|
||||
mark
|
||||
}
|
||||
|
||||
fn share(h: &mut Harness, inner: StrongWidget, ratio: f32) -> StrongWidget {
|
||||
SetSize {
|
||||
inner,
|
||||
x: Some(Len::leftover(ratio)),
|
||||
y: None,
|
||||
}
|
||||
.add_strong(&mut h.rsc)
|
||||
h.set_len(&inner, Axis::X, Len::leftover(ratio));
|
||||
inner
|
||||
}
|
||||
|
||||
/// Shares in weights no binary fraction lands on, a padding on one branch
|
||||
@@ -402,18 +392,15 @@ fn only_a_pure_leftover_child_disappears_when_nothing_is_left() {
|
||||
|
||||
// An undrawn child remains a dependency of the span, so making room for
|
||||
// it draws it without rebuilding the tree.
|
||||
h.rsc[fixed].x = Some(Len::px(60));
|
||||
h.set_len(fixed, Axis::X, 60);
|
||||
h.frame();
|
||||
assert_corners!(h, leftover, (60, 0), (100, 20));
|
||||
|
||||
let mut h = Harness::new((100, 20));
|
||||
let fixed = rect(Color::RED).width(100).add(&mut h.rsc);
|
||||
let mixed = SetSize {
|
||||
inner: rect(Color::BLUE).add_strong(&mut h.rsc),
|
||||
x: Some(Len::px(20) + Len::LEFTOVER),
|
||||
y: None,
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
let mixed = rect(Color::BLUE)
|
||||
.width(Len::px(20) + Len::LEFTOVER)
|
||||
.add(&mut h.rsc);
|
||||
h.set_root((fixed, mixed).span(Dir::RIGHT));
|
||||
|
||||
// Pixels and fractions still overflow; only a child whose entire length
|
||||
@@ -432,7 +419,7 @@ fn leftover_children_disappear_at_the_exact_fixed_content_boundary() {
|
||||
assert!(h.region(&a).is_some());
|
||||
assert!(h.region(&b).is_some());
|
||||
|
||||
h.rsc[first].y = Some(Len::px(96.0));
|
||||
h.set_len(first, Axis::Y, 96.0);
|
||||
h.frame();
|
||||
|
||||
assert!(h.region(&a).is_none());
|
||||
|
||||
Reference in new issue
Block a user