Detailed changes
@@ -2162,7 +2162,7 @@ impl ActiveThread {
.inset_0()
.bg(panel_bg)
.opacity(0.8)
- .stop_mouse_events_except_scroll()
+ .block_mouse_except_scroll()
.on_click(cx.listener(Self::handle_cancel_click));
v_flex()
@@ -699,7 +699,7 @@ fn render_diff_hunk_controls(
.rounded_b_md()
.bg(cx.theme().colors().editor_background)
.gap_1()
- .stop_mouse_events_except_scroll()
+ .block_mouse_except_scroll()
.shadow_md()
.children(vec![
Button::new(("reject", row as u64), "Reject")
@@ -21907,7 +21907,7 @@ fn render_diff_hunk_controls(
.rounded_b_lg()
.bg(cx.theme().colors().editor_background)
.gap_1()
- .stop_mouse_events_except_scroll()
+ .block_mouse_except_scroll()
.shadow_md()
.child(if status.has_secondary_hunk() {
Button::new(("stage", row as u64), "Stage")
@@ -42,13 +42,13 @@ use git::{
use gpui::{
Action, Along, AnyElement, App, AppContext, AvailableSpace, Axis as ScrollbarAxis, BorderStyle,
Bounds, ClickEvent, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase, Edges,
- Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox, Hsla,
- InteractiveElement, IntoElement, IsZero, Keystroke, Length, ModifiersChangedEvent, MouseButton,
- MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta,
- ScrollHandle, ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement,
- Style, Styled, TextRun, TextStyleRefinement, WeakEntity, Window, anchored, deferred, div, fill,
- linear_color_stop, linear_gradient, outline, point, px, quad, relative, size, solid_background,
- transparent_black,
+ Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox,
+ HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, Keystroke, Length,
+ ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
+ ParentElement, Pixels, ScrollDelta, ScrollHandle, ScrollWheelEvent, ShapedLine, SharedString,
+ Size, StatefulInteractiveElement, Style, Styled, TextRun, TextStyleRefinement, WeakEntity,
+ Window, anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, point, px,
+ quad, relative, size, solid_background, transparent_black,
};
use itertools::Itertools;
use language::language_settings::{
@@ -1620,7 +1620,7 @@ impl EditorElement {
);
let layout = ScrollbarLayout::for_minimap(
- window.insert_hitbox(minimap_bounds, false),
+ window.insert_hitbox(minimap_bounds, HitboxBehavior::Normal),
visible_editor_lines,
total_editor_lines,
minimap_line_height,
@@ -1791,7 +1791,7 @@ impl EditorElement {
if matches!(hunk, DisplayDiffHunk::Unfolded { .. }) {
let hunk_bounds =
Self::diff_hunk_bounds(snapshot, line_height, gutter_hitbox.bounds, hunk);
- *hitbox = Some(window.insert_hitbox(hunk_bounds, true));
+ *hitbox = Some(window.insert_hitbox(hunk_bounds, HitboxBehavior::BlockMouse));
}
}
}
@@ -2883,7 +2883,7 @@ impl EditorElement {
let hitbox = line_origin.map(|line_origin| {
window.insert_hitbox(
Bounds::new(line_origin, size(shaped_line.width, line_height)),
- false,
+ HitboxBehavior::Normal,
)
});
#[cfg(test)]
@@ -6371,7 +6371,7 @@ impl EditorElement {
}
};
- if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
+ if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
delta = delta.coalesce(event.delta);
editor.update(cx, |editor, cx| {
let position_map: &PositionMap = &position_map;
@@ -7651,15 +7651,17 @@ impl Element for EditorElement {
.map(|(guide, active)| (self.column_pixels(*guide, window, cx), *active))
.collect::<SmallVec<[_; 2]>>();
- let hitbox = window.insert_hitbox(bounds, false);
- let gutter_hitbox =
- window.insert_hitbox(gutter_bounds(bounds, gutter_dimensions), false);
+ let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);
+ let gutter_hitbox = window.insert_hitbox(
+ gutter_bounds(bounds, gutter_dimensions),
+ HitboxBehavior::Normal,
+ );
let text_hitbox = window.insert_hitbox(
Bounds {
origin: gutter_hitbox.top_right(),
size: size(text_width, bounds.size.height),
},
- false,
+ HitboxBehavior::Normal,
);
let content_origin = text_hitbox.origin + content_offset;
@@ -8880,7 +8882,7 @@ impl EditorScrollbars {
})
.map(|(viewport_size, scroll_range)| {
ScrollbarLayout::new(
- window.insert_hitbox(scrollbar_bounds_for(axis), false),
+ window.insert_hitbox(scrollbar_bounds_for(axis), HitboxBehavior::Normal),
viewport_size,
scroll_range,
glyph_grid_cell.along(axis),
@@ -1,8 +1,8 @@
use gpui::{
- App, Application, Bounds, Context, CursorStyle, Decorations, Hsla, MouseButton, Pixels, Point,
- ResizeEdge, Size, Window, WindowBackgroundAppearance, WindowBounds, WindowDecorations,
- WindowOptions, black, canvas, div, green, point, prelude::*, px, rgb, size, transparent_black,
- white,
+ App, Application, Bounds, Context, CursorStyle, Decorations, HitboxBehavior, Hsla, MouseButton,
+ Pixels, Point, ResizeEdge, Size, Window, WindowBackgroundAppearance, WindowBounds,
+ WindowDecorations, WindowOptions, black, canvas, div, green, point, prelude::*, px, rgb, size,
+ transparent_black, white,
};
struct WindowShadow {}
@@ -37,7 +37,7 @@ impl Render for WindowShadow {
point(px(0.0), px(0.0)),
window.window_bounds().get_bounds().size,
),
- false,
+ HitboxBehavior::Normal,
)
},
move |_bounds, hitbox, window, _cx| {
@@ -17,10 +17,10 @@
use crate::{
Action, AnyDrag, AnyElement, AnyTooltip, AnyView, App, Bounds, ClickEvent, DispatchPhase,
- Element, ElementId, Entity, FocusHandle, Global, GlobalElementId, Hitbox, HitboxId,
- InspectorElementId, IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
- ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow,
- ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
+ Element, ElementId, Entity, FocusHandle, Global, GlobalElementId, Hitbox, HitboxBehavior,
+ HitboxId, InspectorElementId, IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent,
+ LayoutId, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
+ Overflow, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
StyleRefinement, Styled, Task, TooltipId, Visibility, Window, point, px, size,
};
use collections::HashMap;
@@ -313,7 +313,7 @@ impl Interactivity {
) {
self.scroll_wheel_listeners
.push(Box::new(move |event, phase, hitbox, window, cx| {
- if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
+ if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
(listener)(event, window, cx);
}
}));
@@ -567,19 +567,20 @@ impl Interactivity {
});
}
- /// Block the mouse from interacting with this element or any of its children
+ /// Block the mouse from all interactions with elements behind this element's hitbox. Typically
+ /// `block_mouse_except_scroll` should be preferred.
+ ///
/// The imperative API equivalent to [`InteractiveElement::occlude`]
pub fn occlude_mouse(&mut self) {
- self.occlude_mouse = true;
+ self.hitbox_behavior = HitboxBehavior::BlockMouse;
}
- /// Registers event handles that stop propagation of mouse events for non-scroll events.
+ /// Block non-scroll mouse interactions with elements behind this element's hitbox. See
+ /// [`Hitbox::is_hovered`] for details.
+ ///
/// The imperative API equivalent to [`InteractiveElement::block_mouse_except_scroll`]
- pub fn stop_mouse_events_except_scroll(&mut self) {
- self.on_any_mouse_down(|_, _, cx| cx.stop_propagation());
- self.on_any_mouse_up(|_, _, cx| cx.stop_propagation());
- self.on_click(|_, _, cx| cx.stop_propagation());
- self.on_hover(|_, _, cx| cx.stop_propagation());
+ pub fn block_mouse_except_scroll(&mut self) {
+ self.hitbox_behavior = HitboxBehavior::BlockMouseExceptScroll;
}
}
@@ -949,7 +950,8 @@ pub trait InteractiveElement: Sized {
self
}
- /// Block the mouse from interacting with this element or any of its children
+ /// Block the mouse from all interactions with elements behind this element's hitbox. Typically
+ /// `block_mouse_except_scroll` should be preferred.
/// The fluent API equivalent to [`Interactivity::occlude_mouse`]
fn occlude(mut self) -> Self {
self.interactivity().occlude_mouse();
@@ -961,10 +963,12 @@ pub trait InteractiveElement: Sized {
self.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
}
- /// Registers event handles that stop propagation of mouse events for non-scroll events.
+ /// Block non-scroll mouse interactions with elements behind this element's hitbox. See
+ /// [`Hitbox::is_hovered`] for details.
+ ///
/// The fluent API equivalent to [`Interactivity::block_mouse_except_scroll`]
- fn stop_mouse_events_except_scroll(mut self) -> Self {
- self.interactivity().stop_mouse_events_except_scroll();
+ fn block_mouse_except_scroll(mut self) -> Self {
+ self.interactivity().block_mouse_except_scroll();
self
}
}
@@ -1448,7 +1452,7 @@ pub struct Interactivity {
pub(crate) drag_listener: Option<(Arc<dyn Any>, DragListener)>,
pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut Window, &mut App)>>,
pub(crate) tooltip_builder: Option<TooltipBuilder>,
- pub(crate) occlude_mouse: bool,
+ pub(crate) hitbox_behavior: HitboxBehavior,
#[cfg(any(feature = "inspector", debug_assertions))]
pub(crate) source_location: Option<&'static core::panic::Location<'static>>,
@@ -1594,7 +1598,7 @@ impl Interactivity {
style.overflow_mask(bounds, window.rem_size()),
|window| {
let hitbox = if self.should_insert_hitbox(&style, window, cx) {
- Some(window.insert_hitbox(bounds, self.occlude_mouse))
+ Some(window.insert_hitbox(bounds, self.hitbox_behavior))
} else {
None
};
@@ -1611,7 +1615,7 @@ impl Interactivity {
}
fn should_insert_hitbox(&self, style: &Style, window: &Window, cx: &App) -> bool {
- self.occlude_mouse
+ self.hitbox_behavior != HitboxBehavior::Normal
|| style.mouse_cursor.is_some()
|| self.group.is_some()
|| self.scroll_offset.is_some()
@@ -2270,7 +2274,7 @@ impl Interactivity {
let hitbox = hitbox.clone();
let current_view = window.current_view();
window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {
- if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
+ if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
let mut scroll_offset = scroll_offset.borrow_mut();
let old_scroll_offset = *scroll_offset;
let delta = event.delta.pixel_delta(line_height);
@@ -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,
@@ -1,8 +1,8 @@
use crate::{
ActiveTooltip, AnyView, App, Bounds, DispatchPhase, Element, ElementId, GlobalElementId,
- HighlightStyle, Hitbox, InspectorElementId, IntoElement, LayoutId, MouseDownEvent,
- MouseMoveEvent, MouseUpEvent, Pixels, Point, SharedString, Size, TextOverflow, TextRun,
- TextStyle, TooltipId, WhiteSpace, Window, WrappedLine, WrappedLineLayout,
+ HighlightStyle, Hitbox, HitboxBehavior, InspectorElementId, IntoElement, LayoutId,
+ MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, SharedString, Size, TextOverflow,
+ TextRun, TextStyle, TooltipId, WhiteSpace, Window, WrappedLine, WrappedLineLayout,
register_tooltip_mouse_handlers, set_tooltip_on_window,
};
use anyhow::Context as _;
@@ -739,7 +739,7 @@ impl Element for InteractiveText {
self.text
.prepaint(None, inspector_id, bounds, state, window, cx);
- let hitbox = window.insert_hitbox(bounds, false);
+ let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);
(hitbox, interactive_state)
},
)
@@ -413,14 +413,42 @@ pub(crate) struct CursorStyleRequest {
pub(crate) style: CursorStyle,
}
-/// An identifier for a [Hitbox].
-#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
-pub struct HitboxId(usize);
+#[derive(Default, Eq, PartialEq)]
+pub(crate) struct HitTest {
+ pub(crate) ids: SmallVec<[HitboxId; 8]>,
+ pub(crate) hover_hitbox_count: usize,
+}
+
+/// An identifier for a [Hitbox] which also includes [HitboxBehavior].
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct HitboxId(u64);
impl HitboxId {
- /// Checks if the hitbox with this id is currently hovered.
- pub fn is_hovered(&self, window: &Window) -> bool {
- window.mouse_hit_test.0.contains(self)
+ /// Checks if the hitbox with this ID is currently hovered. Except when handling
+ /// `ScrollWheelEvent`, this is typically what you want when determining whether to handle mouse
+ /// events or paint hover styles.
+ ///
+ /// See [`Hitbox::is_hovered`] for details.
+ pub fn is_hovered(self, window: &Window) -> bool {
+ let hit_test = &window.mouse_hit_test;
+ for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
+ if self == *id {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// Checks if the hitbox with this ID contains the mouse and should handle scroll events.
+ /// Typically this should only be used when handling `ScrollWheelEvent`, and otherwise
+ /// `is_hovered` should be used. See the documentation of `Hitbox::is_hovered` for details about
+ /// this distinction.
+ pub fn should_handle_scroll(self, window: &Window) -> bool {
+ window.mouse_hit_test.ids.contains(&self)
+ }
+
+ fn next(mut self) -> HitboxId {
+ HitboxId(self.0.wrapping_add(1))
}
}
@@ -435,19 +463,98 @@ pub struct Hitbox {
pub bounds: Bounds<Pixels>,
/// The content mask when the hitbox was inserted.
pub content_mask: ContentMask<Pixels>,
- /// Whether the hitbox occludes other hitboxes inserted prior.
- pub opaque: bool,
+ /// Flags that specify hitbox behavior.
+ pub behavior: HitboxBehavior,
}
impl Hitbox {
- /// Checks if the hitbox is currently hovered.
+ /// Checks if the hitbox is currently hovered. Except when handling `ScrollWheelEvent`, this is
+ /// typically what you want when determining whether to handle mouse events or paint hover
+ /// styles.
+ ///
+ /// This can return `false` even when the hitbox contains the mouse, if a hitbox in front of
+ /// this sets `HitboxBehavior::BlockMouse` (`InteractiveElement::occlude`) or
+ /// `HitboxBehavior::BlockMouseExceptScroll` (`InteractiveElement::block_mouse_except_scroll`).
+ ///
+ /// Handling of `ScrollWheelEvent` should typically use `should_handle_scroll` instead.
+ /// Concretely, this is due to use-cases like overlays that cause the elements under to be
+ /// non-interactive while still allowing scrolling. More abstractly, this is because
+ /// `is_hovered` is about element interactions directly under the mouse - mouse moves, clicks,
+ /// hover styling, etc. In contrast, scrolling is about finding the current outer scrollable
+ /// container.
pub fn is_hovered(&self, window: &Window) -> bool {
self.id.is_hovered(window)
}
+
+ /// Checks if the hitbox contains the mouse and should handle scroll events. Typically this
+ /// should only be used when handling `ScrollWheelEvent`, and otherwise `is_hovered` should be
+ /// used. See the documentation of `Hitbox::is_hovered` for details about this distinction.
+ ///
+ /// This can return `false` even when the hitbox contains the mouse, if a hitbox in front of
+ /// this sets `HitboxBehavior::BlockMouse` (`InteractiveElement::occlude`).
+ pub fn should_handle_scroll(&self, window: &Window) -> bool {
+ self.id.should_handle_scroll(window)
+ }
}
-#[derive(Default, Eq, PartialEq)]
-pub(crate) struct HitTest(SmallVec<[HitboxId; 8]>);
+/// How the hitbox affects mouse behavior.
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub enum HitboxBehavior {
+ /// Normal hitbox mouse behavior, doesn't affect mouse handling for other hitboxes.
+ #[default]
+ Normal,
+
+ /// All hitboxes behind this hitbox will be ignored and so will have `hitbox.is_hovered() ==
+ /// false` and `hitbox.should_handle_scroll() == false`. Typically for elements this causes
+ /// skipping of all mouse events, hover styles, and tooltips. This flag is set by
+ /// [`InteractiveElement::occlude`].
+ ///
+ /// For mouse handlers that check those hitboxes, this behaves the same as registering a
+ /// bubble-phase handler for every mouse event type:
+ ///
+ /// ```
+ /// window.on_mouse_event(move |_: &EveryMouseEventTypeHere, phase, window, cx| {
+ /// if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
+ /// cx.stop_propagation();
+ /// }
+ /// }
+ /// ```
+ ///
+ /// This has effects beyond event handling - any use of hitbox checking, such as hover
+ /// styles and tooltops. These other behaviors are the main point of this mechanism. An
+ /// alternative might be to not affect mouse event handling - but this would allow
+ /// inconsistent UI where clicks and moves interact with elements that are not considered to
+ /// be hovered.
+ BlockMouse,
+
+ /// All hitboxes behind this hitbox will have `hitbox.is_hovered() == false`, even when
+ /// `hitbox.should_handle_scroll() == true`. Typically for elements this causes all mouse
+ /// interaction except scroll events to be ignored - see the documentation of
+ /// [`Hitbox::is_hovered`] for details. This flag is set by
+ /// [`InteractiveElement::block_mouse_except_scroll`].
+ ///
+ /// For mouse handlers that check those hitboxes, this behaves the same as registering a
+ /// bubble-phase handler for every mouse event type **except** `ScrollWheelEvent`:
+ ///
+ /// ```
+ /// window.on_mouse_event(move |_: &EveryMouseEventTypeExceptScroll, phase, window, _cx| {
+ /// if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
+ /// cx.stop_propagation();
+ /// }
+ /// }
+ /// ```
+ ///
+ /// See the documentation of [`Hitbox::is_hovered`] for details of why `ScrollWheelEvent` is
+ /// handled differently than other mouse events. If also blocking these scroll events is
+ /// desired, then a `cx.stop_propagation()` handler like the one above can be used.
+ ///
+ /// This has effects beyond event handling - this affects any use of `is_hovered`, such as
+ /// hover styles and tooltops. These other behaviors are the main point of this mechanism.
+ /// An alternative might be to not affect mouse event handling - but this would allow
+ /// inconsistent UI where clicks and moves interact with elements that are not considered to
+ /// be hovered.
+ BlockMouseExceptScroll,
+}
/// An identifier for a tooltip.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
@@ -578,16 +685,26 @@ impl Frame {
}
pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
+ let mut set_hover_hitbox_count = false;
let mut hit_test = HitTest::default();
for hitbox in self.hitboxes.iter().rev() {
let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
if bounds.contains(&position) {
- hit_test.0.push(hitbox.id);
- if hitbox.opaque {
+ hit_test.ids.push(hitbox.id);
+ if !set_hover_hitbox_count
+ && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
+ {
+ hit_test.hover_hitbox_count = hit_test.ids.len();
+ set_hover_hitbox_count = true;
+ }
+ if hitbox.behavior == HitboxBehavior::BlockMouse {
break;
}
}
}
+ if !set_hover_hitbox_count {
+ hit_test.hover_hitbox_count = hit_test.ids.len();
+ }
hit_test
}
@@ -638,7 +755,7 @@ pub struct Window {
pub(crate) image_cache_stack: Vec<AnyImageCache>,
pub(crate) rendered_frame: Frame,
pub(crate) next_frame: Frame,
- pub(crate) next_hitbox_id: HitboxId,
+ next_hitbox_id: HitboxId,
pub(crate) next_tooltip_id: TooltipId,
pub(crate) tooltip_bounds: Option<TooltipBounds>,
next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
@@ -927,7 +1044,7 @@ impl Window {
rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
next_frame_callbacks,
- next_hitbox_id: HitboxId::default(),
+ next_hitbox_id: HitboxId(0),
next_tooltip_id: TooltipId::default(),
tooltip_bounds: None,
dirty_views: FxHashSet::default(),
@@ -2870,17 +2987,17 @@ impl Window {
/// to determine whether the inserted hitbox was the topmost.
///
/// This method should only be called as part of the prepaint phase of element drawing.
- pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, opaque: bool) -> Hitbox {
+ pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
self.invalidator.debug_assert_prepaint();
let content_mask = self.content_mask();
- let id = self.next_hitbox_id;
- self.next_hitbox_id.0 += 1;
+ let mut id = self.next_hitbox_id;
+ self.next_hitbox_id = self.next_hitbox_id.next();
let hitbox = Hitbox {
id,
bounds,
content_mask,
- opaque,
+ behavior,
};
self.next_frame.hitboxes.push(hitbox.clone());
hitbox
@@ -4042,7 +4159,7 @@ impl Window {
inspector.update(cx, |inspector, _cx| {
if let Some(depth) = inspector.pick_depth.as_mut() {
*depth += delta_y.0 / SCROLL_PIXELS_PER_LAYER;
- let max_depth = self.mouse_hit_test.0.len() as f32 - 0.5;
+ let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
if *depth < 0.0 {
*depth = 0.0;
} else if *depth > max_depth {
@@ -4067,9 +4184,9 @@ impl Window {
) -> Option<(HitboxId, crate::InspectorElementId)> {
if let Some(pick_depth) = inspector.pick_depth {
let depth = (pick_depth as i64).try_into().unwrap_or(0);
- let max_skipped = self.mouse_hit_test.0.len().saturating_sub(1);
+ let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
let skip_count = (depth as usize).min(max_skipped);
- for hitbox_id in self.mouse_hit_test.0.iter().skip(skip_count) {
+ for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
return Some((*hitbox_id, inspector_id.clone()));
}
@@ -3,6 +3,7 @@ mod path_range;
use base64::Engine as _;
use futures::FutureExt as _;
+use gpui::HitboxBehavior;
use language::LanguageName;
use log::Level;
pub use path_range::{LineCol, PathWithRange};
@@ -1211,7 +1212,7 @@ impl Element for MarkdownElement {
window.set_focus_handle(&focus_handle, cx);
window.set_view_id(self.markdown.entity_id());
- let hitbox = window.insert_hitbox(bounds, false);
+ let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);
rendered_markdown.element.prepaint(window, cx);
self.autoscroll(&rendered_markdown.text, window, cx);
hitbox
@@ -136,7 +136,9 @@ pub struct IndentGuideLayout {
/// Implements the necessary functionality for rendering indent guides inside a uniform list.
mod uniform_list {
- use gpui::{DispatchPhase, Hitbox, MouseButton, MouseDownEvent, MouseMoveEvent};
+ use gpui::{
+ DispatchPhase, Hitbox, HitboxBehavior, MouseButton, MouseDownEvent, MouseMoveEvent,
+ };
use super::*;
@@ -256,7 +258,12 @@ mod uniform_list {
.indent_guides
.as_ref()
.iter()
- .map(|guide| window.insert_hitbox(guide.hitbox.unwrap_or(guide.bounds), false))
+ .map(|guide| {
+ window.insert_hitbox(
+ guide.hitbox.unwrap_or(guide.bounds),
+ HitboxBehavior::Normal,
+ )
+ })
.collect();
Self::PrepaintState::Interactive {
hitboxes: Rc::new(hitboxes),
@@ -2,9 +2,9 @@ use std::{cell::RefCell, rc::Rc};
use gpui::{
AnyElement, AnyView, App, Bounds, Corner, DismissEvent, DispatchPhase, Element, ElementId,
- Entity, Focusable as _, GlobalElementId, HitboxId, InteractiveElement, IntoElement, LayoutId,
- Length, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, Style, Window, anchored,
- deferred, div, point, prelude::FluentBuilder, px, size,
+ Entity, Focusable as _, GlobalElementId, HitboxBehavior, HitboxId, InteractiveElement,
+ IntoElement, LayoutId, Length, ManagedView, MouseDownEvent, ParentElement, Pixels, Point,
+ Style, Window, anchored, deferred, div, point, prelude::FluentBuilder, px, size,
};
use crate::prelude::*;
@@ -421,7 +421,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
((), element_state)
});
- window.insert_hitbox(bounds, false).id
+ window.insert_hitbox(bounds, HitboxBehavior::Normal).id
})
}
@@ -2,9 +2,9 @@ use std::{cell::RefCell, rc::Rc};
use gpui::{
AnyElement, App, Bounds, Corner, DismissEvent, DispatchPhase, Element, ElementId, Entity,
- Focusable as _, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId,
- ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Window, anchored,
- deferred, div, px,
+ Focusable as _, GlobalElementId, Hitbox, HitboxBehavior, InteractiveElement, IntoElement,
+ LayoutId, ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Window,
+ anchored, deferred, div, px,
};
pub struct RightClickMenu<M: ManagedView> {
@@ -185,7 +185,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
window: &mut Window,
cx: &mut App,
) -> PrepaintState {
- let hitbox = window.insert_hitbox(bounds, false);
+ let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);
if let Some(child) = request_layout.child_element.as_mut() {
child.prepaint(window, cx);
@@ -3,9 +3,9 @@ use std::{any::Any, cell::Cell, fmt::Debug, ops::Range, rc::Rc, sync::Arc};
use crate::{IntoElement, prelude::*, px, relative};
use gpui::{
Along, App, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Corners, Edges, Element,
- ElementId, Entity, EntityId, GlobalElementId, Hitbox, Hsla, IsZero, LayoutId, ListState,
- MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, ScrollHandle, ScrollWheelEvent,
- Size, Style, UniformListScrollHandle, Window, quad,
+ ElementId, Entity, EntityId, GlobalElementId, Hitbox, HitboxBehavior, Hsla, IsZero, LayoutId,
+ ListState, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, ScrollHandle,
+ ScrollWheelEvent, Size, Style, UniformListScrollHandle, Window, quad,
};
pub struct Scrollbar {
@@ -226,7 +226,7 @@ impl Element for Scrollbar {
_: &mut App,
) -> Self::PrepaintState {
window.with_content_mask(Some(ContentMask { bounds }), |window| {
- window.insert_hitbox(bounds, false)
+ window.insert_hitbox(bounds, HitboxBehavior::Normal)
})
}
@@ -902,9 +902,9 @@ mod element {
use std::{cell::RefCell, iter, rc::Rc, sync::Arc};
use gpui::{
- Along, AnyElement, App, Axis, BorderStyle, Bounds, Element, GlobalElementId, IntoElement,
- MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Size, Style,
- WeakEntity, Window, px, relative, size,
+ Along, AnyElement, App, Axis, BorderStyle, Bounds, Element, GlobalElementId,
+ HitboxBehavior, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement,
+ Pixels, Point, Size, Style, WeakEntity, Window, px, relative, size,
};
use gpui::{CursorStyle, Hitbox};
use parking_lot::Mutex;
@@ -1091,7 +1091,7 @@ mod element {
};
PaneAxisHandleLayout {
- hitbox: window.insert_hitbox(handle_bounds, true),
+ hitbox: window.insert_hitbox(handle_bounds, HitboxBehavior::Normal),
divider_bounds,
}
}
@@ -37,10 +37,10 @@ use futures::{
use gpui::{
Action, AnyEntity, AnyView, AnyWeakView, App, AsyncApp, AsyncWindowContext, Bounds, Context,
CursorStyle, Decorations, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle,
- Focusable, Global, Hsla, KeyContext, Keystroke, ManagedView, MouseButton, PathPromptOptions,
- Point, PromptLevel, Render, ResizeEdge, Size, Stateful, Subscription, Task, Tiling, WeakEntity,
- WindowBounds, WindowHandle, WindowId, WindowOptions, action_as, actions, canvas,
- impl_action_as, impl_actions, point, relative, size, transparent_black,
+ Focusable, Global, HitboxBehavior, Hsla, KeyContext, Keystroke, ManagedView, MouseButton,
+ PathPromptOptions, Point, PromptLevel, Render, ResizeEdge, Size, Stateful, Subscription, Task,
+ Tiling, WeakEntity, WindowBounds, WindowHandle, WindowId, WindowOptions, action_as, actions,
+ canvas, impl_action_as, impl_actions, point, relative, size, transparent_black,
};
pub use history_manager::*;
pub use item::{
@@ -7344,7 +7344,7 @@ pub fn client_side_decorations(
point(px(0.0), px(0.0)),
window.window_bounds().get_bounds().size,
),
- false,
+ HitboxBehavior::Normal,
)
},
move |_bounds, hitbox, window, cx| {