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

+10 -6
View File
@@ -183,12 +183,16 @@ impl SensorUi for UiRenderState {
// update it there?
let mut active = std::mem::take(&mut rsc.events_mut().get_type::<CursorSense>().active);
let position_only = cursor.position_only();
let mut consumed = false;
for layer in self.layers.indices().rev() {
let mut consumed = false;
let mut consumed_here = false;
for (id, sensor) in active.get_mut(&layer).into_flat_iter() {
let shape = self.active.get(id).unwrap().region;
let region = shape.to_px(window_size);
let in_shape = cursor.exists && region.contains(cursor.pos);
// Once a layer above has taken the input, everything under it
// is covered rather than skipped: it is not hovered, so a
// widget that was gets to end its hover.
let in_shape = !consumed && cursor.exists && region.contains(cursor.pos);
sensor.hover.update(in_shape);
if sensor.hover == ActivationState::Off {
continue;
@@ -212,11 +216,11 @@ impl SensorUi for UiRenderState {
// hovering does not reach through one -- but not at a widget
// it has just left, which is here only to end its hover.
let answered = rsc.run_event::<CursorSense>(*id, data, state);
consumed |= answered || (position_only && in_shape);
}
if consumed {
break;
consumed_here |= answered || (position_only && in_shape);
}
// Applied after the layer, never during it: senses on one layer
// do not block each other.
consumed |= consumed_here;
}
rsc.events_mut().get_type::<CursorSense>().active = active;
}