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
59impl crate::ui::Ui {
61 #[doc(alias = "IsItemToggledOpen")]
67 pub fn is_item_toggled_open(&self) -> bool {
68 unsafe { sys::igIsItemToggledOpen() }
69 }
70
71 #[doc(alias = "GetItemRectMin")]
73 pub fn item_rect_min(&self) -> [f32; 2] {
74 let rect = unsafe { sys::igGetItemRectMin() };
75 [rect.x, rect.y]
76 }
77
78 #[doc(alias = "GetItemRectMax")]
80 pub fn item_rect_max(&self) -> [f32; 2] {
81 let rect = unsafe { sys::igGetItemRectMax() };
82 [rect.x, rect.y]
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 if name_ptr.is_null() {
135 return "Unknown";
136 }
137 let c_str = std::ffi::CStr::from_ptr(name_ptr);
138 c_str.to_str().unwrap_or("Unknown")
139 }
140 }
141
142 #[doc(alias = "GetMouseClickedCount")]
144 pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
145 unsafe { sys::igGetMouseClickedCount(button.into()) }
146 }
147
148 #[doc(alias = "GetMousePos")]
150 pub fn get_mouse_pos(&self) -> [f32; 2] {
151 let pos = unsafe { sys::igGetMousePos() };
152 [pos.x, pos.y]
153 }
154
155 #[doc(alias = "GetMousePosOnOpeningCurrentPopup")]
157 pub fn get_mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
158 let pos = unsafe { sys::igGetMousePosOnOpeningCurrentPopup() };
159 [pos.x, pos.y]
160 }
161
162 #[doc(alias = "GetMouseDragDelta")]
164 pub fn get_mouse_drag_delta(&self, button: MouseButton, lock_threshold: f32) -> [f32; 2] {
165 let delta = unsafe { sys::igGetMouseDragDelta(button.into(), lock_threshold) };
166 [delta.x, delta.y]
167 }
168
169 #[doc(alias = "GetIO")]
171 pub fn get_mouse_wheel(&self) -> f32 {
172 self.io().mouse_wheel()
173 }
174
175 #[doc(alias = "GetIO")]
177 pub fn get_mouse_wheel_h(&self) -> f32 {
178 self.io().mouse_wheel_h()
179 }
180
181 #[doc(alias = "IsAnyMouseDown")]
183 pub fn is_any_mouse_down(&self) -> bool {
184 unsafe { sys::igIsAnyMouseDown() }
185 }
186
187 #[doc(alias = "GetTime")]
193 pub fn time(&self) -> f64 {
194 unsafe { sys::igGetTime() }
195 }
196
197 #[doc(alias = "GetFrameCount")]
199 pub fn frame_count(&self) -> i32 {
200 unsafe { sys::igGetFrameCount() }
201 }
202
203 #[doc(alias = "GetStyle")]
208 pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] {
209 unsafe {
210 let style_ptr = sys::igGetStyle();
211 let colors = (*style_ptr).Colors.as_ptr();
212 let color = *colors.add(style_color as usize);
213 [color.x, color.y, color.z, color.w]
214 }
215 }
216
217 #[doc(alias = "GetStyleColorName")]
223 pub fn style_color_name(&self, style_color: StyleColor) -> &'static str {
224 unsafe {
225 let name_ptr = sys::igGetStyleColorName(style_color as sys::ImGuiCol);
226 if name_ptr.is_null() {
227 return "Unknown";
228 }
229 let c_str = std::ffi::CStr::from_ptr(name_ptr);
230 c_str.to_str().unwrap_or("Unknown")
231 }
232 }
233
234 #[doc(alias = "IsRectVisible")]
236 pub fn is_rect_visible(&self, size: [f32; 2]) -> bool {
237 unsafe {
238 let size = sys::ImVec2 {
239 x: size[0],
240 y: size[1],
241 };
242 sys::igIsRectVisible_Nil(size)
243 }
244 }
245
246 #[doc(alias = "IsRectVisible")]
248 pub fn is_rect_visible_ex(&self, rect_min: [f32; 2], rect_max: [f32; 2]) -> bool {
249 unsafe {
250 let rect_min = sys::ImVec2 {
251 x: rect_min[0],
252 y: rect_min[1],
253 };
254 let rect_max = sys::ImVec2 {
255 x: rect_max[0],
256 y: rect_max[1],
257 };
258 sys::igIsRectVisible_Vec2(rect_min, rect_max)
259 }
260 }
261
262 #[doc(alias = "GetCursorScreenPos")]
266 pub fn get_cursor_screen_pos(&self) -> [f32; 2] {
267 let pos = unsafe { sys::igGetCursorScreenPos() };
268 [pos.x, pos.y]
269 }
270
271 #[doc(alias = "GetContentRegionAvail")]
273 pub fn get_content_region_avail(&self) -> [f32; 2] {
274 let size = unsafe { sys::igGetContentRegionAvail() };
275 [size.x, size.y]
276 }
277
278 pub fn is_point_in_rect(
280 &self,
281 point: [f32; 2],
282 rect_min: [f32; 2],
283 rect_max: [f32; 2],
284 ) -> bool {
285 point[0] >= rect_min[0]
286 && point[0] <= rect_max[0]
287 && point[1] >= rect_min[1]
288 && point[1] <= rect_max[1]
289 }
290
291 pub fn distance(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
293 let dx = p2[0] - p1[0];
294 let dy = p2[1] - p1[1];
295 (dx * dx + dy * dy).sqrt()
296 }
297
298 pub fn distance_squared(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
300 let dx = p2[0] - p1[0];
301 let dy = p2[1] - p1[1];
302 dx * dx + dy * dy
303 }
304
305 pub fn line_segments_intersect(
307 &self,
308 p1: [f32; 2],
309 p2: [f32; 2],
310 p3: [f32; 2],
311 p4: [f32; 2],
312 ) -> bool {
313 let d1 = self.cross_product(
314 [p4[0] - p3[0], p4[1] - p3[1]],
315 [p1[0] - p3[0], p1[1] - p3[1]],
316 );
317 let d2 = self.cross_product(
318 [p4[0] - p3[0], p4[1] - p3[1]],
319 [p2[0] - p3[0], p2[1] - p3[1]],
320 );
321 let d3 = self.cross_product(
322 [p2[0] - p1[0], p2[1] - p1[1]],
323 [p3[0] - p1[0], p3[1] - p1[1]],
324 );
325 let d4 = self.cross_product(
326 [p2[0] - p1[0], p2[1] - p1[1]],
327 [p4[0] - p1[0], p4[1] - p1[1]],
328 );
329
330 (d1 > 0.0) != (d2 > 0.0) && (d3 > 0.0) != (d4 > 0.0)
331 }
332
333 fn cross_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
335 v1[0] * v2[1] - v1[1] * v2[0]
336 }
337
338 pub fn normalize(&self, v: [f32; 2]) -> [f32; 2] {
340 let len = (v[0] * v[0] + v[1] * v[1]).sqrt();
341 if len > f32::EPSILON {
342 [v[0] / len, v[1] / len]
343 } else {
344 [0.0, 0.0]
345 }
346 }
347
348 pub fn dot_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
350 v1[0] * v2[0] + v1[1] * v2[1]
351 }
352
353 pub fn angle_between_vectors(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
355 let dot = self.dot_product(v1, v2);
356 let len1 = (v1[0] * v1[0] + v1[1] * v1[1]).sqrt();
357 let len2 = (v2[0] * v2[0] + v2[1] * v2[1]).sqrt();
358
359 if len1 > f32::EPSILON && len2 > f32::EPSILON {
360 (dot / (len1 * len2)).acos()
361 } else {
362 0.0
363 }
364 }
365
366 pub fn is_point_in_circle(&self, point: [f32; 2], center: [f32; 2], radius: f32) -> bool {
368 self.distance_squared(point, center) <= radius * radius
369 }
370
371 pub fn triangle_area(&self, p1: [f32; 2], p2: [f32; 2], p3: [f32; 2]) -> f32 {
373 let cross = self.cross_product(
374 [p2[0] - p1[0], p2[1] - p1[1]],
375 [p3[0] - p1[0], p3[1] - p1[1]],
376 );
377 cross.abs() * 0.5
378 }
379
380 #[doc(alias = "SetNextItemAllowOverlap")]
384 pub fn set_next_item_allow_overlap(&self) {
385 unsafe { sys::igSetNextItemAllowOverlap() };
386 }
387}