diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 661de610712b..76f1c6dd27cb 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -135,7 +135,7 @@ fn show_tooltip_at_avoid_dyn<'c, R>( .pivot(pivot) .fixed_pos(anchor) .default_width(ctx.style().spacing.tooltip_width) - .interactable(false) + // .interactable(false) .show(ctx, |ui| { Frame::popup(&ctx.style()).show_dyn(ui, add_contents).inner }); @@ -234,6 +234,11 @@ pub fn was_tooltip_open_last_frame(ctx: &Context, widget_id: Id) -> bool { }) } +pub fn tooltip_area_state(ctx: &Context, widget_id: Id) -> Option { + let primary_tooltip_area_id = tooltip_id(widget_id, 0); + AreaState::load(ctx, primary_tooltip_area_id) +} + /// Helper for [`popup_above_or_below_widget`]. pub fn popup_below_widget( ui: &Ui, diff --git a/crates/egui/src/layers.rs b/crates/egui/src/layers.rs index b9b1fb5a5c38..5e5ad0838db8 100644 --- a/crates/egui/src/layers.rs +++ b/crates/egui/src/layers.rs @@ -49,7 +49,7 @@ impl Order { | Self::Middle | Self::Foreground | Self::Debug => true, - Self::Tooltip => false, + Self::Tooltip => true, } } diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 8697a9743a50..7cceb4092ac8 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -2,8 +2,8 @@ use std::{any::Any, sync::Arc}; use crate::{ emath::{Align, Pos2, Rect, Vec2}, - menu, ComboBox, Context, CursorIcon, Id, LayerId, PointerButton, Sense, Ui, WidgetRect, - WidgetText, + menu, tooltip_area_state, ComboBox, Context, CursorIcon, Id, LayerId, PointerButton, Sense, Ui, + WidgetRect, WidgetText, }; // ---------------------------------------------------------------------------- @@ -570,6 +570,31 @@ impl Response { return true; } + let is_tooltip_open = self.is_tooltip_open(); + + if is_tooltip_open { + if let Some(area) = tooltip_area_state(&self.ctx, self.id) { + // We keep the tooltip open if hovered, + // or if the pointer is on its way to it, + // so that the user can interact with the tooltip + // (i.e. click links that are in it). + + let rect = area.rect(); + let pointer_in_area_or_on_the_way_there = self.ctx.input(|i| { + if let Some(pos) = i.pointer.hover_pos() { + rect.contains(pos) + || rect.intersects_ray(pos, i.pointer.velocity().normalized()) + } else { + false + } + }); + + if pointer_in_area_or_on_the_way_there { + return true; + } + } + } + // Fast early-outs: if self.enabled { if !self.hovered || !self.ctx.input(|i| i.pointer.has_pointer()) { @@ -605,7 +630,7 @@ impl Response { let tooltip_was_recently_shown = when_was_a_toolip_last_shown .map_or(false, |time| ((now - time) as f32) < tooltip_grace_time); - if !tooltip_was_recently_shown && !self.is_tooltip_open() { + if !tooltip_was_recently_shown && !is_tooltip_open { if self.ctx.style().interaction.show_tooltips_only_when_still { // We only show the tooltip when the mouse pointer is still. if !self.ctx.input(|i| i.pointer.is_still()) {