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