Resolve a declared length where the widget is drawn, not inside it
SetSize took its declared length out of UiRegion::FULL, which is the box it was already given, so a span that had sized that box from the same hint had the fraction taken twice: .width(rel(0.5)) in a 400-wide span drew its child 100 wide. It held under a Pad or the root, which do not honour a hint, and hid under px, where 200 of a 200-wide box is all of it. The text example was 111,923 pixels from upstream/main because of it. Whoever draws a widget now takes its declared length, in its own box, which is what a fraction of one means, and is the identity for a caller that already reserved the space. rest is not taken: a share of what is left over is only a length to the widget dividing one, so it passes up in the size as it does out of a span. SetSize keeps only what it declares. A declared length is then part of the box its parent decided, so changing one has to redraw the parent; the lengths resolved into a box are kept beside it and compared. Assuming instead that any dirty widget which declares a length needs its parent costs 17% of a frame that dirties 130 of 260 widgets, and buys nothing. All five reference renders, the resize render and the image replay are byte-identical to upstream/main, the 100-seed sweep passes, and the resize fixture is 1.286 ms against 1.289 before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
169db7f16f
commit
de9ddc0ad4
4 files changed
+83
-22
No files matched your search
@@ -8,20 +8,11 @@ pub struct SetSize {
|
||||
|
||||
impl Widget for SetSize {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
// A declared length is what the child gets, whatever box this widget
|
||||
// was offered before its parent knew that. Measuring it anywhere else
|
||||
// asks about a box it will not have, and the answer on the other axis
|
||||
// is taken under that: a wrapping text measured in the whole width
|
||||
// reports one line, and nothing revisits it once the real width
|
||||
// arrives.
|
||||
let mut region = UiRegion::FULL;
|
||||
for (axis, len) in [(Axis::X, self.x), (Axis::Y, self.y)] {
|
||||
if let Some(len) = len {
|
||||
let span = region.axis_mut(axis);
|
||||
span.end = span.start + len.apply_rest();
|
||||
}
|
||||
}
|
||||
let child = painter.widget_within(&self.inner, region).size();
|
||||
// Nothing to apply: a declared length is taken where this widget is
|
||||
// drawn, so the box it has already is that length, and `rest` is a
|
||||
// share only whoever divides a length can work out. Both reach them
|
||||
// through `size_hint`.
|
||||
let child = painter.widget(&self.inner).size();
|
||||
Size {
|
||||
x: self.x.unwrap_or(child.x),
|
||||
y: self.y.unwrap_or(child.y),
|
||||
|
||||
Reference in new issue
Block a user