Skip to main content

egui_components/
tooltip.rs

1//! `Tooltip` — themed hover help attached to any widget [`Response`].
2//!
3//! egui already renders tooltips in a framed popover; this wrapper styles the
4//! content with the component theme (foreground / muted colors, optional bold
5//! title) so it matches the rest of the library. Attach it to whatever a
6//! widget returns:
7//!
8//! ```ignore
9//! let r = sc::Tooltip::new("Delete this item")
10//!     .attach(ui.add(sc::Button::danger("Delete")));
11//! ```
12
13use egui::{Response, Ui};
14
15use crate::common::Size;
16use crate::label::Label;
17
18pub struct Tooltip {
19    title: Option<String>,
20    text: String,
21    at_pointer: bool,
22}
23
24impl Tooltip {
25    pub fn new(text: impl Into<String>) -> Self {
26        Self {
27            title: None,
28            text: text.into(),
29            at_pointer: false,
30        }
31    }
32
33    /// Add a bold title line above the body text.
34    pub fn title(mut self, t: impl Into<String>) -> Self {
35        self.title = Some(t.into());
36        self
37    }
38
39    /// Anchor the tooltip to the pointer instead of the widget.
40    pub fn at_pointer(mut self) -> Self {
41        self.at_pointer = true;
42        self
43    }
44
45    /// Attach the tooltip to `response`, shown while the widget is hovered.
46    /// Returns the (possibly updated) [`Response`].
47    pub fn attach(self, response: Response) -> Response {
48        let Tooltip {
49            title,
50            text,
51            at_pointer,
52        } = self;
53        let add = move |ui: &mut Ui| {
54            ui.set_max_width(280.0);
55            if let Some(title) = &title {
56                ui.add(Label::new(title.clone()).strong().size(Size::Small));
57            }
58            ui.add(Label::new(text.clone()).size(Size::Small));
59        };
60        if at_pointer {
61            response.on_hover_ui_at_pointer(add)
62        } else {
63            response.on_hover_ui(add)
64        }
65    }
66}