1use crate::input::{Key, MouseButton};
2use crate::{StyleColor, sys};
3use bitflags::bitflags;
4
5bitflags! {
6 #[repr(transparent)]
8 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9 pub struct HoveredFlags: i32 {
10 const NONE = sys::ImGuiHoveredFlags_None as i32;
12 const CHILD_WINDOWS = sys::ImGuiHoveredFlags_ChildWindows as i32;
14 const ROOT_WINDOW = sys::ImGuiHoveredFlags_RootWindow as i32;
16 const ANY_WINDOW = sys::ImGuiHoveredFlags_AnyWindow as i32;
18 const NO_POPUP_HIERARCHY = sys::ImGuiHoveredFlags_NoPopupHierarchy as i32;
20 const DOCK_HIERARCHY = sys::ImGuiHoveredFlags_DockHierarchy as i32;
22 const ALLOW_WHEN_BLOCKED_BY_POPUP = sys::ImGuiHoveredFlags_AllowWhenBlockedByPopup as i32;
24 const ALLOW_WHEN_BLOCKED_BY_ACTIVE_ITEM = sys::ImGuiHoveredFlags_AllowWhenBlockedByActiveItem as i32;
26 const ALLOW_WHEN_OVERLAPPED = sys::ImGuiHoveredFlags_AllowWhenOverlapped as i32;
28 const ALLOW_WHEN_DISABLED = sys::ImGuiHoveredFlags_AllowWhenDisabled as i32;
30 const NO_NAV_OVERRIDE = sys::ImGuiHoveredFlags_NoNavOverride as i32;
32 const FOR_TOOLTIP = sys::ImGuiHoveredFlags_ForTooltip as i32;
34 const STATIONARY = sys::ImGuiHoveredFlags_Stationary as i32;
36 const DELAY_NONE = sys::ImGuiHoveredFlags_DelayNone as i32;
38 const DELAY_SHORT = sys::ImGuiHoveredFlags_DelayShort as i32;
40 const DELAY_NORMAL = sys::ImGuiHoveredFlags_DelayNormal as i32;
42 const NO_SHARED_DELAY = sys::ImGuiHoveredFlags_NoSharedDelay as i32;
44 }
45}
46
47impl Default for HoveredFlags {
48 fn default() -> Self {
49 HoveredFlags::NONE
50 }
51}
52
53impl crate::ui::Ui {
55 #[doc(alias = "IsItemToggledOpen")]
61 pub fn is_item_toggled_open(&self) -> bool {
62 unsafe { sys::igIsItemToggledOpen() }
63 }
64
65 #[doc(alias = "GetItemRectMin")]
67 pub fn item_rect_min(&self) -> [f32; 2] {
68 unsafe {
69 let mut rect = sys::ImVec2 { x: 0.0, y: 0.0 };
70 sys::igGetItemRectMin(&mut rect);
71 [rect.x, rect.y]
72 }
73 }
74
75 #[doc(alias = "GetItemRectMax")]
77 pub fn item_rect_max(&self) -> [f32; 2] {
78 unsafe {
79 let mut rect = sys::ImVec2 { x: 0.0, y: 0.0 };
80 sys::igGetItemRectMax(&mut rect);
81 [rect.x, rect.y]
82 }
83 }
84
85 #[doc(alias = "IsWindowHovered")]
91 pub fn is_window_hovered(&self) -> bool {
92 unsafe { sys::igIsWindowHovered(HoveredFlags::NONE.bits()) }
93 }
94
95 #[doc(alias = "IsWindowHovered")]
97 pub fn is_window_hovered_with_flags(&self, flags: HoveredFlags) -> bool {
98 unsafe { sys::igIsWindowHovered(flags.bits()) }
99 }
100
101 #[doc(alias = "IsWindowFocused")]
103 pub fn is_window_focused(&self) -> bool {
104 unsafe { sys::igIsWindowFocused(0) }
105 }
106
107 #[doc(alias = "IsWindowAppearing")]
109 pub fn is_window_appearing(&self) -> bool {
110 unsafe { sys::igIsWindowAppearing() }
111 }
112
113 #[doc(alias = "IsWindowCollapsed")]
115 pub fn is_window_collapsed(&self) -> bool {
116 unsafe { sys::igIsWindowCollapsed() }
117 }
118
119 #[doc(alias = "GetKeyPressedAmount")]
125 pub fn get_key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> i32 {
126 unsafe { sys::igGetKeyPressedAmount(key.into(), repeat_delay, rate) }
127 }
128
129 #[doc(alias = "GetKeyName")]
131 pub fn get_key_name(&self, key: Key) -> &str {
132 unsafe {
133 let name_ptr = sys::igGetKeyName(key.into());
134 let c_str = std::ffi::CStr::from_ptr(name_ptr);
135 c_str.to_str().unwrap_or("Unknown")
136 }
137 }
138
139 #[doc(alias = "GetMouseClickedCount")]
141 pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
142 unsafe { sys::igGetMouseClickedCount(button.into()) }
143 }
144
145 #[doc(alias = "GetMousePos")]
147 pub fn get_mouse_pos(&self) -> [f32; 2] {
148 unsafe {
149 let mut pos = sys::ImVec2 { x: 0.0, y: 0.0 };
150 sys::igGetMousePos(&mut pos);
151 [pos.x, pos.y]
152 }
153 }
154
155 #[doc(alias = "GetMousePosOnOpeningCurrentPopup")]
157 pub fn get_mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
158 unsafe {
159 let mut pos = sys::ImVec2 { x: 0.0, y: 0.0 };
160 sys::igGetMousePosOnOpeningCurrentPopup(&mut pos);
161 [pos.x, pos.y]
162 }
163 }
164
165 #[doc(alias = "GetMouseDragDelta")]
167 pub fn get_mouse_drag_delta(&self, button: MouseButton, lock_threshold: f32) -> [f32; 2] {
168 unsafe {
169 let mut delta = sys::ImVec2 { x: 0.0, y: 0.0 };
170 sys::igGetMouseDragDelta(&mut delta, button.into(), lock_threshold);
171 [delta.x, delta.y]
172 }
173 }
174
175 #[doc(alias = "GetIO")]
177 pub fn get_mouse_wheel(&self) -> f32 {
178 unsafe { (*sys::igGetIO_Nil()).MouseWheel }
179 }
180
181 #[doc(alias = "GetIO")]
183 pub fn get_mouse_wheel_h(&self) -> f32 {
184 unsafe { (*sys::igGetIO_Nil()).MouseWheelH }
185 }
186
187 #[doc(alias = "IsAnyMouseDown")]
189 pub fn is_any_mouse_down(&self) -> bool {
190 unsafe { sys::igIsAnyMouseDown() }
191 }
192
193 #[doc(alias = "GetTime")]
199 pub fn time(&self) -> f64 {
200 unsafe { sys::igGetTime() }
201 }
202
203 #[doc(alias = "GetFrameCount")]
205 pub fn frame_count(&self) -> i32 {
206 unsafe { sys::igGetFrameCount() }
207 }
208
209 #[doc(alias = "GetStyle")]
214 pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] {
215 unsafe {
216 let style_ptr = sys::igGetStyle();
217 let colors = (*style_ptr).Colors.as_ptr();
218 let color = *colors.add(style_color as usize);
219 [color.x, color.y, color.z, color.w]
220 }
221 }
222
223 #[doc(alias = "GetStyleColorName")]
229 pub fn style_color_name(&self, style_color: StyleColor) -> &'static str {
230 unsafe {
231 let name_ptr = sys::igGetStyleColorName(style_color as sys::ImGuiCol);
232 let c_str = std::ffi::CStr::from_ptr(name_ptr);
233 c_str.to_str().unwrap_or("Unknown")
234 }
235 }
236
237 #[doc(alias = "IsRectVisible")]
239 pub fn is_rect_visible(&self, size: [f32; 2]) -> bool {
240 unsafe {
241 let size = sys::ImVec2 {
242 x: size[0],
243 y: size[1],
244 };
245 sys::igIsRectVisible_Nil(size)
246 }
247 }
248
249 #[doc(alias = "IsRectVisible")]
251 pub fn is_rect_visible_ex(&self, rect_min: [f32; 2], rect_max: [f32; 2]) -> bool {
252 unsafe {
253 let rect_min = sys::ImVec2 {
254 x: rect_min[0],
255 y: rect_min[1],
256 };
257 let rect_max = sys::ImVec2 {
258 x: rect_max[0],
259 y: rect_max[1],
260 };
261 sys::igIsRectVisible_Vec2(rect_min, rect_max)
262 }
263 }
264
265 #[doc(alias = "GetCursorScreenPos")]
269 pub fn get_cursor_screen_pos(&self) -> [f32; 2] {
270 unsafe {
271 let mut pos = sys::ImVec2 { x: 0.0, y: 0.0 };
272 sys::igGetCursorScreenPos(&mut pos);
273 [pos.x, pos.y]
274 }
275 }
276
277 #[doc(alias = "GetContentRegionAvail")]
279 pub fn get_content_region_avail(&self) -> [f32; 2] {
280 unsafe {
281 let mut size = sys::ImVec2 { x: 0.0, y: 0.0 };
282 sys::igGetContentRegionAvail(&mut size);
283 [size.x, size.y]
284 }
285 }
286
287 pub fn is_point_in_rect(
289 &self,
290 point: [f32; 2],
291 rect_min: [f32; 2],
292 rect_max: [f32; 2],
293 ) -> bool {
294 point[0] >= rect_min[0]
295 && point[0] <= rect_max[0]
296 && point[1] >= rect_min[1]
297 && point[1] <= rect_max[1]
298 }
299
300 pub fn distance(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
302 let dx = p2[0] - p1[0];
303 let dy = p2[1] - p1[1];
304 (dx * dx + dy * dy).sqrt()
305 }
306
307 pub fn distance_squared(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
309 let dx = p2[0] - p1[0];
310 let dy = p2[1] - p1[1];
311 dx * dx + dy * dy
312 }
313
314 pub fn line_segments_intersect(
316 &self,
317 p1: [f32; 2],
318 p2: [f32; 2],
319 p3: [f32; 2],
320 p4: [f32; 2],
321 ) -> bool {
322 let d1 = self.cross_product(
323 [p4[0] - p3[0], p4[1] - p3[1]],
324 [p1[0] - p3[0], p1[1] - p3[1]],
325 );
326 let d2 = self.cross_product(
327 [p4[0] - p3[0], p4[1] - p3[1]],
328 [p2[0] - p3[0], p2[1] - p3[1]],
329 );
330 let d3 = self.cross_product(
331 [p2[0] - p1[0], p2[1] - p1[1]],
332 [p3[0] - p1[0], p3[1] - p1[1]],
333 );
334 let d4 = self.cross_product(
335 [p2[0] - p1[0], p2[1] - p1[1]],
336 [p4[0] - p1[0], p4[1] - p1[1]],
337 );
338
339 (d1 > 0.0) != (d2 > 0.0) && (d3 > 0.0) != (d4 > 0.0)
340 }
341
342 fn cross_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
344 v1[0] * v2[1] - v1[1] * v2[0]
345 }
346
347 pub fn normalize(&self, v: [f32; 2]) -> [f32; 2] {
349 let len = (v[0] * v[0] + v[1] * v[1]).sqrt();
350 if len > f32::EPSILON {
351 [v[0] / len, v[1] / len]
352 } else {
353 [0.0, 0.0]
354 }
355 }
356
357 pub fn dot_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
359 v1[0] * v2[0] + v1[1] * v2[1]
360 }
361
362 pub fn angle_between_vectors(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
364 let dot = self.dot_product(v1, v2);
365 let len1 = (v1[0] * v1[0] + v1[1] * v1[1]).sqrt();
366 let len2 = (v2[0] * v2[0] + v2[1] * v2[1]).sqrt();
367
368 if len1 > f32::EPSILON && len2 > f32::EPSILON {
369 (dot / (len1 * len2)).acos()
370 } else {
371 0.0
372 }
373 }
374
375 pub fn is_point_in_circle(&self, point: [f32; 2], center: [f32; 2], radius: f32) -> bool {
377 self.distance_squared(point, center) <= radius * radius
378 }
379
380 pub fn triangle_area(&self, p1: [f32; 2], p2: [f32; 2], p3: [f32; 2]) -> f32 {
382 let cross = self.cross_product(
383 [p2[0] - p1[0], p2[1] - p1[1]],
384 [p3[0] - p1[0], p3[1] - p1[1]],
385 );
386 cross.abs() * 0.5
387 }
388
389 #[doc(alias = "SetNextItemAllowOverlap")]
393 pub fn set_next_item_allow_overlap(&self) {
394 unsafe { sys::igSetNextItemAllowOverlap() };
395 }
396}