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        let min = unsafe { sys::igGetItemRectMin() };
181        let max = unsafe { sys::igGetItemRectMax() };
182        ([min.x, min.y], [max.x, max.y])
183    }
184
185    /// Gets the size of the last item.
186    #[doc(alias = "GetItemRectSize")]
187    pub fn item_rect_size(&self) -> [f32; 2] {
188        let size = unsafe { sys::igGetItemRectSize() };
189        [size.x, size.y]
190    }
191}
192
193/// Tracks a tooltip that can be ended by calling `.end()` or by dropping
194#[must_use]
195pub struct TooltipToken<'ui> {
196    ui: &'ui Ui,
197}
198
199impl<'ui> TooltipToken<'ui> {
200    /// Creates a new tooltip token
201    fn new(ui: &'ui Ui) -> Self {
202        TooltipToken { ui }
203    }
204
205    /// Ends the tooltip
206    pub fn end(self) {
207        // The drop implementation will handle the actual ending
208    }
209}
210
211impl<'ui> Drop for TooltipToken<'ui> {
212    fn drop(&mut self) {
213        unsafe {
214            sys::igEndTooltip();
215        }
216    }
217}