Replaces the taking mechanism with `CursorSenses::consumes`, which
decides only whether a layer stops the input reaching the layer below.
Nothing is removed from the cursor, and senses on one layer no longer
block each other: every sensor the pointer is inside runs.
Where the cursor rests stops at the top layer under it. Something
happening to the cursor stops only at a widget that answers to it, so a
click-only child does not swallow a scroll -- which is what `main` gets
wrong, where any hovered sensor blocks the layer below.
A widget the cursor has left still hears its hover ending, but is handed
no press or scroll: that input landed somewhere else. This is a hit test
rather than a consumption rule, and without it a press beside a button
fires the button it just left.
`a_click_and_a_scroll_in_one_frame_go_to_different_widgets` goes with the
per-kind taking it tested. Of the five that remain, two fail on `main`.
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>
Reviewing this against the process we agreed: the title claimed per-kind
routing and the code decided it once for the whole frame. A scroll and a
click in the same frame both went to the button, because a widget that
matched any momentary sense consumed everything.
Consumption is now removing an input from the cursor the layers below see.
`CursorSense::take` states what each sense takes -- exhaustively, so a new
sense has to answer the question rather than inherit a default -- and
`is_momentary` is gone with the enumeration it was written on. `should_run`
and consumption share one matcher instead of two copies of the table.
Two tests, each checked to fail without the change: a click and a scroll in
one frame reach different widgets, and leaving a widget still ends its hover.
The second is a regression this review caught in its own first draft, where
the skip condition used `is_off`, which counts `End` -- the one frame a
hover-end handler has to run on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`run_sensors` decided that a widget had consumed the frame's input from
hover alone: if the cursor was inside its shape, no lower layer saw
anything. So a button sitting over a list swallowed the list's scroll,
having registered nothing but `click()`.
Being in shape still runs a widget -- a hover highlight has to fire on the
topmost thing under the cursor regardless -- but consuming is now judged
per input kind. With nothing momentary happening the behaviour is
unchanged and the topmost widget wins the hover; with a scroll or a press
happening, only a widget that registered a matching momentary sense
consumes it.
`TypeEventManager::registered` is what makes that askable: what a widget
would match is a different question from dispatching to it, and `run_fn`
can only answer the second.
tests/pointer_routing.rs drives `run_sensors` directly, with no GPU and no
window. It fails on the unfixed code with "a scroll over the button must
still reach the list underneath it".