1use crate::input::{Key, MouseButton};
8use crate::{StyleColor, sys};
9use bitflags::bitflags;
10
11bitflags! {
12 #[repr(transparent)]
14 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15 pub struct HoveredFlags: i32 {
16 const NONE = sys::ImGuiHoveredFlags_None as i32;
18 const CHILD_WINDOWS = sys::ImGuiHoveredFlags_ChildWindows as i32;
20 const ROOT_WINDOW = sys::ImGuiHoveredFlags_RootWindow as i32;
22 const ANY_WINDOW = sys::ImGuiHoveredFlags_AnyWindow as i32;
24 const NO_POPUP_HIERARCHY = sys::ImGuiHoveredFlags_NoPopupHierarchy as i32;
26 const DOCK_HIERARCHY = sys::ImGuiHoveredFlags_DockHierarchy as i32;
28 const ALLOW_WHEN_BLOCKED_BY_POPUP = sys::ImGuiHoveredFlags_AllowWhenBlockedByPopup as i32;
30 const ALLOW_WHEN_BLOCKED_BY_ACTIVE_ITEM = sys::ImGuiHoveredFlags_AllowWhenBlockedByActiveItem as i32;
32 const ALLOW_WHEN_OVERLAPPED = sys::ImGuiHoveredFlags_AllowWhenOverlapped as i32;
34 const ALLOW_WHEN_DISABLED = sys::ImGuiHoveredFlags_AllowWhenDisabled as i32;
36 const NO_NAV_OVERRIDE = sys::ImGuiHoveredFlags_NoNavOverride as i32;
38 const FOR_TOOLTIP = sys::ImGuiHoveredFlags_ForTooltip as i32;
40 const STATIONARY = sys::ImGuiHoveredFlags_Stationary as i32;
42 const DELAY_NONE = sys::ImGuiHoveredFlags_DelayNone as i32;
44 const DELAY_SHORT = sys::ImGuiHoveredFlags_DelayShort as i32;
46 const DELAY_NORMAL = sys::ImGuiHoveredFlags_DelayNormal as i32;
48 const NO_SHARED_DELAY = sys::ImGuiHoveredFlags_NoSharedDelay as i32;
50 }
51}
52
53impl Default for HoveredFlags {
54 fn default() -> Self {
55 HoveredFlags::NONE
56 }
57}
58
59bitflags! {
60 #[repr(transparent)]
62 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63 pub struct FocusedFlags: i32 {
64 const NONE = sys::ImGuiFocusedFlags_None as i32;
66 const CHILD_WINDOWS = sys::ImGuiFocusedFlags_ChildWindows as i32;
68 const ROOT_WINDOW = sys::ImGuiFocusedFlags_RootWindow as i32;
70 const ANY_WINDOW = sys::ImGuiFocusedFlags_AnyWindow as i32;
72 const NO_POPUP_HIERARCHY = sys::ImGuiFocusedFlags_NoPopupHierarchy as i32;
74 const DOCK_HIERARCHY = sys::ImGuiFocusedFlags_DockHierarchy as i32;
76 }
77}
78
79impl Default for FocusedFlags {
80 fn default() -> Self {
81 FocusedFlags::NONE
82 }
83}
84
85impl crate::ui::Ui {
87 #[doc(alias = "IsItemToggledOpen")]
93 pub fn is_item_toggled_open(&self) -> bool {
94 unsafe { sys::igIsItemToggledOpen() }
95 }
96
97 #[doc(alias = "GetItemRectMin")]
99 pub fn item_rect_min(&self) -> [f32; 2] {
100 let rect = unsafe { sys::igGetItemRectMin() };
101 [rect.x, rect.y]
102 }
103
104 #[doc(alias = "GetItemRectMax")]
106 pub fn item_rect_max(&self) -> [f32; 2] {
107 let rect = unsafe { sys::igGetItemRectMax() };
108 [rect.x, rect.y]
109 }
110
111 #[doc(alias = "IsWindowHovered")]
117 pub fn is_window_hovered(&self) -> bool {
118 unsafe { sys::igIsWindowHovered(HoveredFlags::NONE.bits()) }
119 }
120
121 #[doc(alias = "IsWindowHovered")]
123 pub fn is_window_hovered_with_flags(&self, flags: HoveredFlags) -> bool {
124 unsafe { sys::igIsWindowHovered(flags.bits()) }
125 }
126
127 #[doc(alias = "IsWindowFocused")]
129 pub fn is_window_focused(&self) -> bool {
130 self.is_window_focused_with_flags(FocusedFlags::NONE)
131 }
132
133 #[doc(alias = "IsWindowFocused")]
135 pub fn is_window_focused_with_flags(&self, flags: FocusedFlags) -> bool {
136 unsafe { sys::igIsWindowFocused(flags.bits()) }
137 }
138
139 #[doc(alias = "IsWindowAppearing")]
141 pub fn is_window_appearing(&self) -> bool {
142 unsafe { sys::igIsWindowAppearing() }
143 }
144
145 #[doc(alias = "IsWindowCollapsed")]
147 pub fn is_window_collapsed(&self) -> bool {
148 unsafe { sys::igIsWindowCollapsed() }
149 }
150
151 #[doc(alias = "GetKeyPressedAmount")]
157 pub fn get_key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> i32 {
158 unsafe { sys::igGetKeyPressedAmount(key.into(), repeat_delay, rate) }
159 }
160
161 #[doc(alias = "GetKeyName")]
163 pub fn get_key_name(&self, key: Key) -> &str {
164 unsafe {
165 let name_ptr = sys::igGetKeyName(key.into());
166 if name_ptr.is_null() {
167 return "Unknown";
168 }
169 let c_str = std::ffi::CStr::from_ptr(name_ptr);
170 c_str.to_str().unwrap_or("Unknown")
171 }
172 }
173
174 #[doc(alias = "GetMouseClickedCount")]
176 pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
177 unsafe { sys::igGetMouseClickedCount(button.into()) }
178 }
179
180 #[doc(alias = "GetMousePos")]
182 pub fn get_mouse_pos(&self) -> [f32; 2] {
183 let pos = unsafe { sys::igGetMousePos() };
184 [pos.x, pos.y]
185 }
186
187 #[doc(alias = "GetMousePosOnOpeningCurrentPopup")]
189 pub fn get_mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
190 let pos = unsafe { sys::igGetMousePosOnOpeningCurrentPopup() };
191 [pos.x, pos.y]
192 }
193
194 #[doc(alias = "GetMouseDragDelta")]
196 pub fn get_mouse_drag_delta(&self, button: MouseButton, lock_threshold: f32) -> [f32; 2] {
197 let delta = unsafe { sys::igGetMouseDragDelta(button.into(), lock_threshold) };
198 [delta.x, delta.y]
199 }
200
201 #[doc(alias = "GetIO")]
203 pub fn get_mouse_wheel(&self) -> f32 {
204 self.io().mouse_wheel()
205 }
206
207 #[doc(alias = "GetIO")]
209 pub fn get_mouse_wheel_h(&self) -> f32 {
210 self.io().mouse_wheel_h()
211 }
212
213 #[doc(alias = "IsAnyMouseDown")]
215 pub fn is_any_mouse_down(&self) -> bool {
216 unsafe { sys::igIsAnyMouseDown() }
217 }
218
219 #[doc(alias = "GetTime")]
225 pub fn time(&self) -> f64 {
226 unsafe { sys::igGetTime() }
227 }
228
229 #[doc(alias = "GetFrameCount")]
231 pub fn frame_count(&self) -> i32 {
232 unsafe { sys::igGetFrameCount() }
233 }
234
235 #[doc(alias = "CalcItemWidth")]
237 pub fn calc_item_width(&self) -> f32 {
238 unsafe { sys::igCalcItemWidth() }
239 }
240
241 #[doc(alias = "LogToTTY")]
243 pub fn log_to_tty(&self, auto_open_depth: i32) {
244 unsafe { sys::igLogToTTY(auto_open_depth) }
245 }
246
247 #[doc(alias = "LogToFile")]
249 pub fn log_to_file_default(&self, auto_open_depth: i32) {
250 unsafe { sys::igLogToFile(auto_open_depth, std::ptr::null()) }
251 }
252
253 #[doc(alias = "LogToFile")]
259 pub fn log_to_file(
260 &self,
261 auto_open_depth: i32,
262 filename: &std::path::Path,
263 ) -> crate::error::ImGuiResult<()> {
264 use crate::error::SafeStringConversion;
265 let cstr = filename.to_string_lossy().into_owned().to_cstring_safe()?;
266 unsafe { sys::igLogToFile(auto_open_depth, cstr.as_ptr()) }
267 Ok(())
268 }
269
270 #[doc(alias = "LogToClipboard")]
272 pub fn log_to_clipboard(&self, auto_open_depth: i32) {
273 unsafe { sys::igLogToClipboard(auto_open_depth) }
274 }
275
276 #[doc(alias = "LogButtons")]
278 pub fn log_buttons(&self) {
279 unsafe { sys::igLogButtons() }
280 }
281
282 #[doc(alias = "LogFinish")]
284 pub fn log_finish(&self) {
285 unsafe { sys::igLogFinish() }
286 }
287
288 #[doc(alias = "GetStyle", alias = "GetStyleColorVec4")]
293 pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] {
294 unsafe {
295 let color = sys::igGetStyleColorVec4(style_color as sys::ImGuiCol);
296 let color = &*color;
297 [color.x, color.y, color.z, color.w]
298 }
299 }
300
301 #[doc(alias = "GetColorU32")]
305 pub fn get_color_u32(&self, style_color: StyleColor) -> u32 {
306 self.get_color_u32_with_alpha(style_color, 1.0)
307 }
308
309 #[doc(alias = "GetColorU32")]
311 pub fn get_color_u32_with_alpha(&self, style_color: StyleColor, alpha_mul: f32) -> u32 {
312 unsafe { sys::igGetColorU32_Col(style_color as sys::ImGuiCol, alpha_mul) }
313 }
314
315 #[doc(alias = "GetColorU32")]
319 pub fn get_color_u32_from_rgba(&self, rgba: [f32; 4]) -> u32 {
320 unsafe {
321 sys::igGetColorU32_Vec4(sys::ImVec4_c {
322 x: rgba[0],
323 y: rgba[1],
324 z: rgba[2],
325 w: rgba[3],
326 })
327 }
328 }
329
330 #[doc(alias = "GetColorU32")]
332 pub fn get_color_u32_from_packed(&self, abgr: u32, alpha_mul: f32) -> u32 {
333 unsafe { sys::igGetColorU32_U32(abgr, alpha_mul) }
334 }
335
336 #[doc(alias = "GetStyleColorName")]
342 pub fn style_color_name(&self, style_color: StyleColor) -> &'static str {
343 unsafe {
344 let name_ptr = sys::igGetStyleColorName(style_color as sys::ImGuiCol);
345 if name_ptr.is_null() {
346 return "Unknown";
347 }
348 let c_str = std::ffi::CStr::from_ptr(name_ptr);
349 c_str.to_str().unwrap_or("Unknown")
350 }
351 }
352
353 #[doc(alias = "IsRectVisible")]
355 pub fn is_rect_visible(&self, size: [f32; 2]) -> bool {
356 unsafe {
357 let size = sys::ImVec2 {
358 x: size[0],
359 y: size[1],
360 };
361 sys::igIsRectVisible_Nil(size)
362 }
363 }
364
365 #[doc(alias = "IsRectVisible")]
367 pub fn is_rect_visible_ex(&self, rect_min: [f32; 2], rect_max: [f32; 2]) -> bool {
368 unsafe {
369 let rect_min = sys::ImVec2 {
370 x: rect_min[0],
371 y: rect_min[1],
372 };
373 let rect_max = sys::ImVec2 {
374 x: rect_max[0],
375 y: rect_max[1],
376 };
377 sys::igIsRectVisible_Vec2(rect_min, rect_max)
378 }
379 }
380
381 #[doc(alias = "GetCursorScreenPos")]
385 pub fn get_cursor_screen_pos(&self) -> [f32; 2] {
386 let pos = unsafe { sys::igGetCursorScreenPos() };
387 [pos.x, pos.y]
388 }
389
390 #[doc(alias = "GetContentRegionAvail")]
392 pub fn get_content_region_avail(&self) -> [f32; 2] {
393 let size = unsafe { sys::igGetContentRegionAvail() };
394 [size.x, size.y]
395 }
396
397 pub fn is_point_in_rect(
399 &self,
400 point: [f32; 2],
401 rect_min: [f32; 2],
402 rect_max: [f32; 2],
403 ) -> bool {
404 point[0] >= rect_min[0]
405 && point[0] <= rect_max[0]
406 && point[1] >= rect_min[1]
407 && point[1] <= rect_max[1]
408 }
409
410 pub fn distance(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
412 let dx = p2[0] - p1[0];
413 let dy = p2[1] - p1[1];
414 (dx * dx + dy * dy).sqrt()
415 }
416
417 pub fn distance_squared(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
419 let dx = p2[0] - p1[0];
420 let dy = p2[1] - p1[1];
421 dx * dx + dy * dy
422 }
423
424 pub fn line_segments_intersect(
426 &self,
427 p1: [f32; 2],
428 p2: [f32; 2],
429 p3: [f32; 2],
430 p4: [f32; 2],
431 ) -> bool {
432 let d1 = self.cross_product(
433 [p4[0] - p3[0], p4[1] - p3[1]],
434 [p1[0] - p3[0], p1[1] - p3[1]],
435 );
436 let d2 = self.cross_product(
437 [p4[0] - p3[0], p4[1] - p3[1]],
438 [p2[0] - p3[0], p2[1] - p3[1]],
439 );
440 let d3 = self.cross_product(
441 [p2[0] - p1[0], p2[1] - p1[1]],
442 [p3[0] - p1[0], p3[1] - p1[1]],
443 );
444 let d4 = self.cross_product(
445 [p2[0] - p1[0], p2[1] - p1[1]],
446 [p4[0] - p1[0], p4[1] - p1[1]],
447 );
448
449 (d1 > 0.0) != (d2 > 0.0) && (d3 > 0.0) != (d4 > 0.0)
450 }
451
452 fn cross_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
454 v1[0] * v2[1] - v1[1] * v2[0]
455 }
456
457 pub fn normalize(&self, v: [f32; 2]) -> [f32; 2] {
459 let len = (v[0] * v[0] + v[1] * v[1]).sqrt();
460 if len > f32::EPSILON {
461 [v[0] / len, v[1] / len]
462 } else {
463 [0.0, 0.0]
464 }
465 }
466
467 pub fn dot_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
469 v1[0] * v2[0] + v1[1] * v2[1]
470 }
471
472 pub fn angle_between_vectors(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
474 let dot = self.dot_product(v1, v2);
475 let len1 = (v1[0] * v1[0] + v1[1] * v1[1]).sqrt();
476 let len2 = (v2[0] * v2[0] + v2[1] * v2[1]).sqrt();
477
478 if len1 > f32::EPSILON && len2 > f32::EPSILON {
479 (dot / (len1 * len2)).acos()
480 } else {
481 0.0
482 }
483 }
484
485 pub fn is_point_in_circle(&self, point: [f32; 2], center: [f32; 2], radius: f32) -> bool {
487 self.distance_squared(point, center) <= radius * radius
488 }
489
490 pub fn triangle_area(&self, p1: [f32; 2], p2: [f32; 2], p3: [f32; 2]) -> f32 {
492 let cross = self.cross_product(
493 [p2[0] - p1[0], p2[1] - p1[1]],
494 [p3[0] - p1[0], p3[1] - p1[1]],
495 );
496 cross.abs() * 0.5
497 }
498
499 #[doc(alias = "SetNextItemAllowOverlap")]
503 pub fn set_next_item_allow_overlap(&self) {
504 unsafe { sys::igSetNextItemAllowOverlap() };
505 }
506}