diff --git a/CHANGELOG.md b/CHANGELOG.md index 717eefcd..a5b04bc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Changed default font to [Ubuntu-Light](https://fonts.google.com/specimen/Ubuntu). * Remove minimum button width * Refactored `egui::Layout` substantially, changing its interface. +* Calling ``on_hover_text`/`on_hover_ui` multiple times will stack tooltips underneath the previous ones. ### Removed 🔥 diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs index de3efbb4..0ea79756 100644 --- a/egui/src/containers/popup.rs +++ b/egui/src/containers/popup.rs @@ -4,12 +4,22 @@ use crate::*; /// Show a tooltip at the current mouse position (if any). pub fn show_tooltip(ctx: &Arc, add_contents: impl FnOnce(&mut Ui)) { - if let Some(mouse_pos) = ctx.input().mouse.pos { - // TODO: default size - let id = Id::tooltip(); - let window_pos = mouse_pos + vec2(16.0, 16.0); - show_popup(ctx, id, window_pos, add_contents); - } + let tooltip_rect = ctx.memory().tooltip_rect; + + let window_pos = if let Some(tooltip_rect) = tooltip_rect { + tooltip_rect.left_bottom() + } else if let Some(mouse_pos) = ctx.input().mouse.pos { + mouse_pos + vec2(16.0, 16.0) + } else { + return; // No good place for a tooltip :( + }; + + // TODO: default size + let id = Id::tooltip(); + let response = show_popup(ctx, id, window_pos, add_contents); + + let tooltip_rect = tooltip_rect.unwrap_or_else(Rect::nothing); + ctx.memory().tooltip_rect = Some(tooltip_rect.union(response.rect)); } /// Show a tooltip at the current mouse position (if any). diff --git a/egui/src/memory.rs b/egui/src/memory.rs index 993848d5..39cb6c2e 100644 --- a/egui/src/memory.rs +++ b/egui/src/memory.rs @@ -54,6 +54,12 @@ pub struct Memory { #[cfg_attr(feature = "serde", serde(skip))] popup: Option, + /// If a tooltip has been shown this frame, where was it? + /// This is used to prevent multiple tooltips to cover each other. + /// Initialized to `None` at the start of each frame. + #[cfg_attr(feature = "serde", serde(skip))] + pub(crate) tooltip_rect: Option, + /// Useful for debugging, benchmarking etc. pub all_collpasing_are_open: bool, /// Useful for debugging, benchmarking etc. @@ -162,6 +168,7 @@ impl Memory { ) { self.used_ids.clear(); self.interaction.begin_frame(prev_input, new_input); + self.tooltip_rect = None; if !prev_input.mouse.down { self.window_interaction = None; diff --git a/egui/src/types.rs b/egui/src/types.rs index 46fd3f9e..06d224cf 100644 --- a/egui/src/types.rs +++ b/egui/src/types.rs @@ -116,7 +116,8 @@ impl std::fmt::Debug for Response { } impl Response { - /// Show this UI if the item was hovered (i.e. a tooltip) + /// Show this UI if the item was hovered (i.e. a tooltip). + /// If you call this multiple times the tooltips will stack underneath the previous ones. pub fn on_hover_ui(self, add_contents: impl FnOnce(&mut Ui)) -> Self { if self.hovered { crate::containers::show_tooltip(&self.ctx, add_contents); @@ -124,7 +125,8 @@ impl Response { self } - /// Show this text if the item was hovered (i.e. a tooltip) + /// Show this text if the item was hovered (i.e. a tooltip). + /// If you call this multiple times the tooltips will stack underneath the previous ones. pub fn on_hover_text(self, text: impl Into) -> Self { self.on_hover_ui(|ui| { ui.add(crate::widgets::Label::new(text)); diff --git a/egui/src/widgets/drag_value.rs b/egui/src/widgets/drag_value.rs index 13ea464e..8fa9d6db 100644 --- a/egui/src/widgets/drag_value.rs +++ b/egui/src/widgets/drag_value.rs @@ -146,7 +146,7 @@ impl<'a> Widget for DragValue<'a> { .sense(Sense::click_and_drag()) .text_style(TextStyle::Monospace); let response = ui.add(button); - // response.on_hover_text("Drag to edit, click to enter a value"); // TODO: may clash with users own tooltips + let response = response.on_hover_text("Drag to edit, click to enter a value"); if response.clicked { ui.memory().request_kb_focus(kb_edit_id); ui.memory().temp_edit_string = None; // Filled in next frame