Skip to content

Commit

Permalink
Remove stuck tooltips (cherry-pick #22548) (#22549)
Browse files Browse the repository at this point in the history
Cherry-picked Remove stuck tooltips (#22548)

Closes #21657

Follow-up of #22488
Previous PR broke git blame tooltips, which are expected to be open when
hovered, even if the mouse cursor is moved away from the actual blame
entry that caused the tooltip to appear.

Current version moves the invalidation logic into `prepaint_tooltip`,
where the new data about the tooltip origin is used to ensure we
invalidate only tooltips that have no mouse cursor in either origin
bounds or tooltip bounds (if it's hoverable).


Release Notes:

- Fixed tooltips getting stuck

Co-authored-by: Kirill Bulatov <[email protected]>
  • Loading branch information
1 parent a2264c3 commit 342b41a
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
12 changes: 9 additions & 3 deletions crates/gpui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ use util::ResultExt;

use crate::{
current_platform, hash, init_app_menus, Action, ActionRegistry, Any, AnyView, AnyWindowHandle,
Asset, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
Entity, EventEmitter, FocusHandle, FocusId, ForegroundExecutor, Global, KeyBinding, Keymap,
Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, Context, DispatchPhase,
DisplayId, Entity, EventEmitter, FocusHandle, FocusId, ForegroundExecutor, Global, KeyBinding,
Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
PlatformDisplay, Point, PromptBuilder, PromptHandle, PromptLevel, Render,
RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, SubscriberSet,
Subscription, SvgRenderer, Task, TextSystem, View, ViewContext, Window, WindowAppearance,
Expand Down Expand Up @@ -1612,6 +1612,12 @@ pub struct AnyTooltip {

/// The absolute position of the mouse when the tooltip was deployed.
pub mouse_position: Point<Pixels>,

/// Whether the tooltitp can be hovered or not.
pub hoverable: bool,

/// Bounds of the element that triggered the tooltip appearance.
pub origin_bounds: Bounds<Pixels>,
}

/// A keystroke event, and potentially the associated action
Expand Down
3 changes: 3 additions & 0 deletions crates/gpui/src/elements/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,7 @@ impl Interactivity {
cx.on_mouse_event({
let active_tooltip = active_tooltip.clone();
let hitbox = hitbox.clone();
let source_bounds = hitbox.bounds;
let tooltip_id = self.tooltip_id;
move |_: &MouseMoveEvent, phase, cx| {
let is_hovered =
Expand Down Expand Up @@ -1952,6 +1953,8 @@ impl Interactivity {
tooltip: Some(AnyTooltip {
view: build_tooltip(cx),
mouse_position: cx.mouse_position(),
hoverable: tooltip_is_hoverable,
origin_bounds: source_bounds,
}),
_task: None,
});
Expand Down
3 changes: 3 additions & 0 deletions crates/gpui/src/elements/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ impl Element for InteractiveText {

if let Some(tooltip_builder) = self.tooltip_builder.clone() {
let hitbox = hitbox.clone();
let source_bounds = hitbox.bounds;
let active_tooltip = interactive_state.active_tooltip.clone();
let pending_mouse_down = interactive_state.mouse_down_index.clone();
let text_layout = text_layout.clone();
Expand Down Expand Up @@ -708,6 +709,8 @@ impl Element for InteractiveText {
tooltip: Some(AnyTooltip {
view: tooltip,
mouse_position: cx.mouse_position(),
hoverable: true,
origin_bounds: source_bounds,
}),
_task: None,
}
Expand Down
13 changes: 13 additions & 0 deletions crates/gpui/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,19 @@ impl<'a> WindowContext<'a> {
let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self);

let mut tooltip_bounds = Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
// Element's parent can get hidden (e.g. via the `visible_on_hover` method),
// and element's `paint` won't be called (ergo, mouse listeners also won't be active) to detect that the tooltip has to be removed.
// Ensure it's not stuck around in such cases.
let invalidate_tooltip = !tooltip_request
.tooltip
.origin_bounds
.contains(&self.mouse_position())
&& (!tooltip_request.tooltip.hoverable
|| !tooltip_bounds.contains(&self.mouse_position()));
if invalidate_tooltip {
return None;
}

let window_bounds = Bounds {
origin: Point::default(),
size: self.viewport_size(),
Expand Down

0 comments on commit 342b41a

Please sign in to comment.