End the hover of a widget that gets covered

Breaking out of the layer loop left every sensor below the consuming
layer untouched, so one that was hovered stayed hovered: moving onto a
widget in a layer above never ended the hover of what it covered, and
nothing ever would.

Consumption now carries into the hit test rather than stopping the walk.
A covered widget is simply not in shape, so its hover ends and its
`HoverEnd` runs; `should_run` already refuses non-position senses once
the hover is not on, so nothing else reaches it. It is applied after a
layer rather than during one, so senses on the same layer still do not
block each other.
This commit is contained in:
iris committed 2026-09-13 21:27:35 -04:00
1 parent 8cac927438
commit 5494642dec
2 files changed
+40 -6

No files matched your search

+30
View File
@@ -288,3 +288,33 @@ fn hovering_a_button_above_does_not_stop_a_later_scroll() {
);
assert_eq!(clicked.take(), []);
}
#[test]
fn covering_a_widget_ends_its_hover() {
let ui = &mut Ui::new();
let below = full(ui);
// Only the left half of the layer above is a widget, so the cursor can
// start beside it and then move onto it.
let (above, gap) = (full(ui), full(ui));
let below_hover = ui.listen(&below, CursorSense::HoverStart | CursorSense::HoverEnd);
let above_hover = ui.listen(&above, CursorSense::HoverStart);
let row = ui.rsc.ui.widgets.add_strong(Span {
children: vec![above.any(), gap.any()],
dir: Dir::RIGHT,
gap: 0.0,
});
ui.stack(vec![below.any(), row.any()]);
let beside_it = ui.cursor((80.0, 50.0));
ui.run(beside_it);
assert_eq!(below_hover.take(), [CursorSense::HoverStart]);
let onto_above = ui.cursor((20.0, 50.0));
ui.run(onto_above);
assert_eq!(above_hover.take(), [CursorSense::HoverStart]);
assert_eq!(
below_hover.take(),
[CursorSense::HoverEnd],
"a widget covered by one that took the input is no longer hovered"
);
}