Mostly fix hover tooltips not respecting occlusion (#24319)
Regression in #22644 Unfortunately not a full fix, In the case where a tooltip gets displayed and then gets occluded after display, it will stick around until the mouse exits the hover bounds. Release Notes: - N/A Co-authored-by: Ben <ben@zed.dev>
This commit is contained in:
parent
e1919b4121
commit
1dbca5d9a0
2 changed files with 51 additions and 13 deletions
|
@ -2008,18 +2008,27 @@ impl Interactivity {
|
||||||
let build_tooltip = Rc::new(move |window: &mut Window, cx: &mut App| {
|
let build_tooltip = Rc::new(move |window: &mut Window, cx: &mut App| {
|
||||||
Some(((tooltip_builder.build)(window, cx), tooltip_is_hoverable))
|
Some(((tooltip_builder.build)(window, cx), tooltip_is_hoverable))
|
||||||
});
|
});
|
||||||
// Use bounds instead of testing hitbox since check_is_hovered is also called
|
// Use bounds instead of testing hitbox since this is called during prepaint.
|
||||||
// during prepaint.
|
let check_is_hovered_during_prepaint = Rc::new({
|
||||||
let source_bounds = hitbox.bounds;
|
let pending_mouse_down = pending_mouse_down.clone();
|
||||||
let check_is_hovered = Rc::new(move |window: &Window| {
|
let source_bounds = hitbox.bounds;
|
||||||
pending_mouse_down.borrow().is_none()
|
move |window: &Window| {
|
||||||
&& source_bounds.contains(&window.mouse_position())
|
pending_mouse_down.borrow().is_none()
|
||||||
|
&& source_bounds.contains(&window.mouse_position())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let check_is_hovered = Rc::new({
|
||||||
|
let hitbox = hitbox.clone();
|
||||||
|
move |window: &Window| {
|
||||||
|
pending_mouse_down.borrow().is_none() && hitbox.is_hovered(window)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
register_tooltip_mouse_handlers(
|
register_tooltip_mouse_handlers(
|
||||||
&active_tooltip,
|
&active_tooltip,
|
||||||
self.tooltip_id,
|
self.tooltip_id,
|
||||||
build_tooltip,
|
build_tooltip,
|
||||||
check_is_hovered,
|
check_is_hovered,
|
||||||
|
check_is_hovered_during_prepaint,
|
||||||
window,
|
window,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2361,6 +2370,7 @@ pub(crate) fn register_tooltip_mouse_handlers(
|
||||||
tooltip_id: Option<TooltipId>,
|
tooltip_id: Option<TooltipId>,
|
||||||
build_tooltip: Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
|
build_tooltip: Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
|
||||||
check_is_hovered: Rc<dyn Fn(&Window) -> bool>,
|
check_is_hovered: Rc<dyn Fn(&Window) -> bool>,
|
||||||
|
check_is_hovered_during_prepaint: Rc<dyn Fn(&Window) -> bool>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
) {
|
) {
|
||||||
window.on_mouse_event({
|
window.on_mouse_event({
|
||||||
|
@ -2372,6 +2382,7 @@ pub(crate) fn register_tooltip_mouse_handlers(
|
||||||
&active_tooltip,
|
&active_tooltip,
|
||||||
&build_tooltip,
|
&build_tooltip,
|
||||||
&check_is_hovered,
|
&check_is_hovered,
|
||||||
|
&check_is_hovered_during_prepaint,
|
||||||
phase,
|
phase,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
|
@ -2398,10 +2409,22 @@ pub(crate) fn register_tooltip_mouse_handlers(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles displaying tooltips when an element is hovered.
|
||||||
|
///
|
||||||
|
/// The mouse hovering logic also relies on being called from window prepaint in order to handle the
|
||||||
|
/// case where the element the tooltip is on is not rendered - in that case its mouse listeners are
|
||||||
|
/// also not registered. During window prepaint, the hitbox information is not available, so
|
||||||
|
/// `check_is_hovered_during_prepaint` is used which bases the check off of the absolute bounds of
|
||||||
|
/// the element.
|
||||||
|
///
|
||||||
|
/// TODO: There's a minor bug due to the use of absolute bounds while checking during prepaint - it
|
||||||
|
/// does not know if the hitbox is occluded. In the case where a tooltip gets displayed and then
|
||||||
|
/// gets occluded after display, it will stick around until the mouse exits the hover bounds.
|
||||||
fn handle_tooltip_mouse_move(
|
fn handle_tooltip_mouse_move(
|
||||||
active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
|
active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
|
||||||
build_tooltip: &Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
|
build_tooltip: &Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
|
||||||
check_is_hovered: &Rc<dyn Fn(&Window) -> bool>,
|
check_is_hovered: &Rc<dyn Fn(&Window) -> bool>,
|
||||||
|
check_is_hovered_during_prepaint: &Rc<dyn Fn(&Window) -> bool>,
|
||||||
phase: DispatchPhase,
|
phase: DispatchPhase,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
|
@ -2447,7 +2470,7 @@ fn handle_tooltip_mouse_move(
|
||||||
let delayed_show_task = window.spawn(cx, {
|
let delayed_show_task = window.spawn(cx, {
|
||||||
let active_tooltip = active_tooltip.clone();
|
let active_tooltip = active_tooltip.clone();
|
||||||
let build_tooltip = build_tooltip.clone();
|
let build_tooltip = build_tooltip.clone();
|
||||||
let check_is_hovered = check_is_hovered.clone();
|
let check_is_hovered_during_prepaint = check_is_hovered_during_prepaint.clone();
|
||||||
move |mut cx| async move {
|
move |mut cx| async move {
|
||||||
cx.background_executor().timer(TOOLTIP_SHOW_DELAY).await;
|
cx.background_executor().timer(TOOLTIP_SHOW_DELAY).await;
|
||||||
cx.update(|window, cx| {
|
cx.update(|window, cx| {
|
||||||
|
@ -2463,7 +2486,7 @@ fn handle_tooltip_mouse_move(
|
||||||
handle_tooltip_check_visible_and_update(
|
handle_tooltip_check_visible_and_update(
|
||||||
&active_tooltip,
|
&active_tooltip,
|
||||||
tooltip_is_hoverable,
|
tooltip_is_hoverable,
|
||||||
&check_is_hovered,
|
&check_is_hovered_during_prepaint,
|
||||||
tooltip_bounds,
|
tooltip_bounds,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -734,7 +734,6 @@ impl Element for InteractiveText {
|
||||||
|
|
||||||
if let Some(tooltip_builder) = self.tooltip_builder.clone() {
|
if let Some(tooltip_builder) = self.tooltip_builder.clone() {
|
||||||
let active_tooltip = interactive_state.active_tooltip.clone();
|
let active_tooltip = interactive_state.active_tooltip.clone();
|
||||||
let pending_mouse_down = interactive_state.mouse_down_index.clone();
|
|
||||||
let build_tooltip = Rc::new({
|
let build_tooltip = Rc::new({
|
||||||
let tooltip_is_hoverable = false;
|
let tooltip_is_hoverable = false;
|
||||||
let text_layout = text_layout.clone();
|
let text_layout = text_layout.clone();
|
||||||
|
@ -746,11 +745,12 @@ impl Element for InteractiveText {
|
||||||
.map(|view| (view, tooltip_is_hoverable))
|
.map(|view| (view, tooltip_is_hoverable))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Use bounds instead of testing hitbox since check_is_hovered is also
|
|
||||||
// called during prepaint.
|
// Use bounds instead of testing hitbox since this is called during prepaint.
|
||||||
let source_bounds = hitbox.bounds;
|
let check_is_hovered_during_prepaint = Rc::new({
|
||||||
let check_is_hovered = Rc::new({
|
let source_bounds = hitbox.bounds;
|
||||||
let text_layout = text_layout.clone();
|
let text_layout = text_layout.clone();
|
||||||
|
let pending_mouse_down = interactive_state.mouse_down_index.clone();
|
||||||
move |window: &Window| {
|
move |window: &Window| {
|
||||||
text_layout
|
text_layout
|
||||||
.index_for_position(window.mouse_position())
|
.index_for_position(window.mouse_position())
|
||||||
|
@ -759,11 +759,26 @@ impl Element for InteractiveText {
|
||||||
&& pending_mouse_down.get().is_none()
|
&& pending_mouse_down.get().is_none()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let check_is_hovered = Rc::new({
|
||||||
|
let hitbox = hitbox.clone();
|
||||||
|
let text_layout = text_layout.clone();
|
||||||
|
let pending_mouse_down = interactive_state.mouse_down_index.clone();
|
||||||
|
move |window: &Window| {
|
||||||
|
text_layout
|
||||||
|
.index_for_position(window.mouse_position())
|
||||||
|
.is_ok()
|
||||||
|
&& hitbox.is_hovered(window)
|
||||||
|
&& pending_mouse_down.get().is_none()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
register_tooltip_mouse_handlers(
|
register_tooltip_mouse_handlers(
|
||||||
&active_tooltip,
|
&active_tooltip,
|
||||||
self.tooltip_id,
|
self.tooltip_id,
|
||||||
build_tooltip,
|
build_tooltip,
|
||||||
check_is_hovered,
|
check_is_hovered,
|
||||||
|
check_is_hovered_during_prepaint,
|
||||||
window,
|
window,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue