Settle growing layout branches in one frame

This commit is contained in:
iris committed 2026-09-09 16:54:39 -04:00
1 parent f95835593f
commit 46e6edfd0b
3 files changed
+90 -4

No files matched your search

+64
View File
@@ -1172,3 +1172,67 @@ fn a_span_of_padded_children_inside_a_span_draws_each_where_its_box_is() {
);
}
}
/// Growing an already-drawn row first measures its new child against the
/// row's old height. That provisional box can end before it starts when the
/// old trailing edge is above the new child's cursor. The size must bubble to
/// `LazySpan` and the corrected allocation must travel back down before this
/// update is presented; a later stream event is not a layout pass.
#[test]
fn a_new_child_in_a_growing_lazy_row_uses_its_final_box_immediately() {
const FIRST: f32 = 30.0;
const SECOND: f32 = 70.0;
const GAP: f32 = 8.0;
let mut rsc = TestRsc {
ui: UiData::default(),
};
let first = rsc.ui.widgets.add_strong(Rect::new(UiColor::WHITE));
let first_id = first.id();
let first = rsc.ui.widgets.add_strong(Sized {
inner: first.any(),
x: None,
y: Some(Len::abs(FIRST)),
});
let mut contents = Span::empty(Dir::DOWN).gap(Len::abs(GAP));
contents.push(first.any());
let contents = rsc.ui.widgets.add_strong(contents);
let contents_w = contents.weak();
let row = rsc.ui.widgets.add_strong(Sized {
inner: contents.any(),
x: Some(Len::rest(1.0)),
y: None,
});
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
list.push_back(LazyItem::new(0, row.any()));
let root = rsc.ui.widgets.add_strong(list).any();
let mut render = UiRenderState::new();
render.resize((200.0, 200.0));
render.update(&root, &mut rsc);
let second = rsc.ui.widgets.add_strong(Rect::new(UiColor::WHITE));
let second_id = second.id();
let second = rsc.ui.widgets.add_strong(Sized {
inner: second.any(),
x: None,
y: Some(Len::abs(SECOND)),
});
rsc.ui
.widgets
.get_mut(&contents_w)
.unwrap()
.push(second.any());
render.update(&root, &mut rsc);
let first = render.primitive_corners(render.first_primitive(first_id).unwrap(), &rsc);
let second = render.primitive_corners(render.first_primitive(second_id).unwrap(), &rsc);
assert!(
(second.top_left.y - (first.bot_right.y + GAP)).abs() < 0.01,
"the new child should start after the old child and its gap: first={first:?} second={second:?}"
);
assert!(
(second.bot_right.y - second.top_left.y - SECOND).abs() < 0.01,
"the new child retained its provisional box: {second:?}"
);
}
+8
View File
@@ -31,4 +31,12 @@ impl Widget for Sized {
Axis::Y => self.y,
}
}
fn requires_exact_region(&self) -> bool {
// `Sized` may be measured in a provisional box and then placed in
// the content-sized box it reported. Its own region can be corrected
// by a move, but its child consumed the original box and must see the
// final one too.
true
}
}