Keep momentary input on the widget the cursor is on

Tests across layers, as asked, and the fifth one found a defect older than
this branch: a press fired on a widget the cursor had just left, because the
frame its hover ends is a frame it still gets dispatched on, and `should_run`
only ever looked at the cursor. A button in the corner of a list therefore
clicked when the press landed anywhere else in the row.

A widget that is not under the cursor now sees a cursor with nothing
momentary in it, which settles both halves of the question at once: it is not
its press to receive, and not its press to take from the layers below.

`CursorSense` and `CursorButton` derive `Debug`, so a failure says which
sense fired rather than `left != right`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-09-13 19:22:56 -04:00
1 parent 0a14df2cc3
commit 71ba3723ff
2 files changed
+197 -111

No files matched your search

+15 -4
View File
@@ -4,14 +4,14 @@ use std::{
rc::Rc,
};
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CursorButton {
Left,
Right,
Middle,
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CursorSense {
PressStart(CursorButton),
Pressing(CursorButton),
@@ -205,6 +205,19 @@ impl SensorUi for UiRenderState {
}
hovered_here |= over;
// Momentary input belongs to whatever the cursor is on. A
// widget it has just left still hears its hover ending, but
// a press landing elsewhere is neither its press to receive
// nor its press to take.
let cursor = match over {
true => cursor.clone(),
false => CursorState {
pos: cursor.pos,
exists: cursor.exists,
..Default::default()
},
};
for senses in rsc.events_mut().get_type::<CursorSense>().registered(*id) {
for sense in senses.iter() {
if matches(sense, &cursor, sensor.hover) {
@@ -213,8 +226,6 @@ impl SensorUi for UiRenderState {
}
}
let cursor = cursor.clone();
let data = CursorData {
pos: cursor.pos - region.top_left,
size: region.bot_right - region.top_left,