dear_imgui_rs/widget/
tooltip.rs

1//! Tooltips
2//!
3//! Tooltip helpers with automatic lifetime management via tokens and
4//! convenient `with_tooltip` patterns.
5//!
6#![allow(
7    clippy::cast_possible_truncation,
8    clippy::cast_sign_loss,
9    clippy::as_conversions
10)]
11use crate::input::MouseButton;
12use crate::sys;
13use crate::ui::Ui;
14
15/// # Tooltip Widgets
16impl Ui {
17    /// Construct a tooltip window that can have any kind of content.
18    ///
19    /// Typically used with `Ui::is_item_hovered()` or some other conditional check.
20    ///
21    /// # Examples
22    ///
23    /// ```no_run
24    /// # use dear_imgui_rs::*;
25    /// # let mut ctx = Context::create();
26    /// # let ui = ctx.frame();
27    /// ui.text("Hover over me");
28    /// if ui.is_item_hovered() {
29    ///     ui.tooltip(|| {
30    ///         ui.text_colored([1.0, 0.0, 0.0, 1.0], "I'm red!");
31    ///     });
32    /// }
33    /// ```
34    #[doc(alias = "BeginTooltip", alias = "EndTooltip")]
35    pub fn tooltip<F: FnOnce()>(&self, f: F) {
36        if let Some(_token) = self.begin_tooltip() {
37            f();
38        }
39    }
40
41    /// Construct a tooltip window that can have any kind of content.
42    ///
43    /// Returns a `TooltipToken` that must be ended by calling `.end()` or by dropping.
44    #[doc(alias = "BeginTooltip")]
45    pub fn begin_tooltip(&self) -> Option<TooltipToken<'_>> {
46        if unsafe { sys::igBeginTooltip() } {
47            Some(TooltipToken::new(self))
48        } else {
49            None
50        }
51    }
52
53    /// Shortcut to call [`Self::tooltip`] with simple text content.
54    ///
55    /// # Examples
56    ///
57    /// ```no_run
58    /// # use dear_imgui_rs::*;
59    /// # let mut ctx = Context::create();
60    /// # let ui = ctx.frame();
61    /// ui.text("Hover over me");
62    /// if ui.is_item_hovered() {
63    ///     ui.tooltip_text("I'm a tooltip!");
64    /// }
65    /// ```
66    #[doc(alias = "BeginTooltip", alias = "EndTooltip", alias = "SetTooltip")]
67    pub fn tooltip_text(&self, text: impl AsRef<str>) {
68        self.tooltip(|| self.text(text));
69    }
70
71    /// Sets a tooltip with simple text content.
72    /// This is more efficient than begin_tooltip/end_tooltip for simple text.
73    #[doc(alias = "SetTooltip")]
74    pub fn set_tooltip(&self, text: impl AsRef<str>) {
75        let text_ptr = self.scratch_txt(text);
76        unsafe {
77            sys::igSetTooltip(text_ptr);
78        }
79    }
80
81    /// Sets a tooltip with formatted text content.
82    #[doc(alias = "SetTooltip")]
83    pub fn set_tooltip_formatted(&self, text: impl AsRef<str>) {
84        self.set_tooltip(text);
85    }
86
87    /// Sets a tooltip for the last item with simple text content.
88    /// More efficient than building a tooltip window for simple cases.
89    #[doc(alias = "SetItemTooltip")]
90    pub fn set_item_tooltip(&self, text: impl AsRef<str>) {
91        let text_ptr = self.scratch_txt(text);
92        unsafe { sys::igSetItemTooltip(text_ptr) }
93    }
94}
95
96/// # Item/Widget Utilities and Query Functions
97impl Ui {
98    /// Returns true if the last item is being hovered by mouse (and usable).
99    /// This is typically used to show tooltips.
100    #[doc(alias = "IsItemHovered")]
101    pub fn is_item_hovered(&self) -> bool {
102        unsafe { sys::igIsItemHovered(crate::HoveredFlags::NONE.bits()) }
103    }
104
105    /// Returns true if the last item is being hovered by mouse with specific flags.
106    #[doc(alias = "IsItemHovered")]
107    pub fn is_item_hovered_with_flags(&self, flags: crate::HoveredFlags) -> bool {
108        unsafe { sys::igIsItemHovered(flags.bits()) }
109    }
110
111    /// Returns true if the last item is active (e.g. button being held, text field being edited).
112    #[doc(alias = "IsItemActive")]
113    pub fn is_item_active(&self) -> bool {
114        unsafe { sys::igIsItemActive() }
115    }
116
117    /// Returns true if the last item is focused (e.g. text input field).
118    #[doc(alias = "IsItemFocused")]
119    pub fn is_item_focused(&self) -> bool {
120        unsafe { sys::igIsItemFocused() }
121    }
122
123    /// Returns true if the last item was just clicked.
124    #[doc(alias = "IsItemClicked")]
125    pub fn is_item_clicked(&self) -> bool {
126        unsafe { sys::igIsItemClicked(crate::input::MouseButton::Left as i32) }
127    }
128
129    /// Returns true if the last item was clicked with specific mouse button.
130    #[doc(alias = "IsItemClicked")]
131    pub fn is_item_clicked_with_button(&self, mouse_button: MouseButton) -> bool {
132        unsafe { sys::igIsItemClicked(mouse_button as i32) }
133    }
134
135    /// Returns true if the last item is visible (not clipped).
136    #[doc(alias = "IsItemVisible")]
137    pub fn is_item_visible(&self) -> bool {
138        unsafe { sys::igIsItemVisible() }
139    }
140
141    /// Returns true if the last item was just made active (e.g. button was pressed).
142    #[doc(alias = "IsItemActivated")]
143    pub fn is_item_activated(&self) -> bool {
144        unsafe { sys::igIsItemActivated() }
145    }
146
147    /// Returns true if the last item was just made inactive (e.g. button was released).
148    #[doc(alias = "IsItemDeactivated")]
149    pub fn is_item_deactivated(&self) -> bool {
150        unsafe { sys::igIsItemDeactivated() }
151    }
152
153    /// Returns true if the last item was just made inactive and was edited.
154    #[doc(alias = "IsItemDeactivatedAfterEdit")]
155    pub fn is_item_deactivated_after_edit(&self) -> bool {
156        unsafe { sys::igIsItemDeactivatedAfterEdit() }
157    }
158
159    /// Returns true if any item is active.
160    #[doc(alias = "IsAnyItemActive")]
161    pub fn is_any_item_active(&self) -> bool {
162        unsafe { sys::igIsAnyItemActive() }
163    }
164
165    /// Returns true if any item is focused.
166    #[doc(alias = "IsAnyItemFocused")]
167    pub fn is_any_item_focused(&self) -> bool {
168        unsafe { sys::igIsAnyItemFocused() }
169    }
170
171    /// Returns true if any item is hovered.
172    #[doc(alias = "IsAnyItemHovered")]
173    pub fn is_any_item_hovered(&self) -> bool {
174        unsafe { sys::igIsAnyItemHovered() }
175    }
176
177    /// Gets the bounding rectangle of the last item in screen space.
178    #[doc(alias = "GetItemRectMin", alias = "GetItemRectMax")]
179    pub fn item_rect(&self) -> ([f32; 2], [f32; 2]) {
180        unsafe {
181            let mut min = sys::ImVec2 { x: 0.0, y: 0.0 };
182            let mut max = sys::ImVec2 { x: 0.0, y: 0.0 };
183            sys::igGetItemRectMin(&mut min);
184            sys::igGetItemRectMax(&mut max);
185            ([min.x, min.y], [max.x, max.y])
186        }
187    }
188
189    /// Gets the size of the last item.
190    #[doc(alias = "GetItemRectSize")]
191    pub fn item_rect_size(&self) -> [f32; 2] {
192        unsafe {
193            let mut size = sys::ImVec2 { x: 0.0, y: 0.0 };
194            sys::igGetItemRectSize(&mut size);
195            [size.x, size.y]
196        }
197    }
198}
199
200/// Tracks a tooltip that can be ended by calling `.end()` or by dropping
201#[must_use]
202pub struct TooltipToken<'ui> {
203    ui: &'ui Ui,
204}
205
206impl<'ui> TooltipToken<'ui> {
207    /// Creates a new tooltip token
208    fn new(ui: &'ui Ui) -> Self {
209        TooltipToken { ui }
210    }
211
212    /// Ends the tooltip
213    pub fn end(self) {
214        // The drop implementation will handle the actual ending
215    }
216}
217
218impl<'ui> Drop for TooltipToken<'ui> {
219    fn drop(&mut self) {
220        unsafe {
221            sys::igEndTooltip();
222        }
223    }
224}