gpui: Support hitbox blocking mouse interaction except scrolling (#31712)

tl;dr: This adds `.block_mouse_except_scroll()` which should typically
be used instead of `.occlude()` for cases when the mouse shouldn't
interact with elements drawn below an element. The rationale for
treating scroll events differently:

* Mouse move / click / styles / tooltips are for elements the user is
interacting with directly.
* Mouse scroll events are about finding the current outer scroll
container.

Most use of `occlude` should probably be switched to this, but I figured
I'd derisk this change by minimizing behavior changes to just the 3 uses
of `block_mouse_except_scroll`.

GPUI changes:

* Added `InteractiveElement::block_mouse_except_scroll()`, and removes
`stop_mouse_events_except_scroll()`

* Added `Hitbox::should_handle_scroll()` to be used when handling scroll
wheel events.

* `Window::insert_hitbox` now takes `HitboxBehavior` instead of
`occlude: bool`.

    - `false` for that bool is now `HitboxBehavior::Normal`.

    - `true` for that bool is now `HitboxBehavior::BlockMouse`.
    
    - The new mode is `HitboxBehavior::BlockMouseExceptScroll`.

* Removes `Default` impl for `HitboxId` since applications should not
manually create `HitboxId(0)`.

Release Notes:

- N/A
This commit is contained in:
Michael Sloan 2025-05-29 15:41:15 -06:00 committed by GitHub
parent 2abc5893c1
commit 9086784038
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 231 additions and 99 deletions

View file

@ -9,8 +9,9 @@
use crate::{
AnyElement, App, AvailableSpace, Bounds, ContentMask, DispatchPhase, Edges, Element, EntityId,
FocusHandle, GlobalElementId, Hitbox, InspectorElementId, IntoElement, Overflow, Pixels, Point,
ScrollWheelEvent, Size, Style, StyleRefinement, Styled, Window, point, px, size,
FocusHandle, GlobalElementId, Hitbox, HitboxBehavior, InspectorElementId, IntoElement,
Overflow, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled, Window, point,
px, size,
};
use collections::VecDeque;
use refineable::Refineable as _;
@ -906,7 +907,7 @@ impl Element for List {
let mut style = Style::default();
style.refine(&self.style);
let hitbox = window.insert_hitbox(bounds, false);
let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);
// If the width of the list has changed, invalidate all cached item heights
if state.last_layout_bounds.map_or(true, |last_bounds| {
@ -962,7 +963,7 @@ impl Element for List {
let scroll_top = prepaint.layout.scroll_top;
let hitbox_id = prepaint.hitbox.id;
window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {
if phase == DispatchPhase::Bubble && hitbox_id.is_hovered(window) {
if phase == DispatchPhase::Bubble && hitbox_id.should_handle_scroll(window) {
list_state.0.borrow_mut().scroll(
&scroll_top,
height,