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 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 let pos = unsafe { sys::igGetMousePos() };
149 [pos.x, pos.y]
150 }
151
152 #[doc(alias = "GetMousePosOnOpeningCurrentPopup")]
154 pub fn get_mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
155 let pos = unsafe { sys::igGetMousePosOnOpeningCurrentPopup() };
156 [pos.x, pos.y]
157 }
158
159 #[doc(alias = "GetMouseDragDelta")]
161 pub fn get_mouse_drag_delta(&self, button: MouseButton, lock_threshold: f32) -> [f32; 2] {
162 let delta = unsafe { sys::igGetMouseDragDelta(button.into(), lock_threshold) };
163 [delta.x, delta.y]
164 }
165
166 #[doc(alias = "GetIO")]
168 pub fn get_mouse_wheel(&self) -> f32 {
169 unsafe { (*sys::igGetIO_Nil()).MouseWheel }
170 }
171
172 #[doc(alias = "GetIO")]
174 pub fn get_mouse_wheel_h(&self) -> f32 {
175 unsafe { (*sys::igGetIO_Nil()).MouseWheelH }
176 }
177
178 #[doc(alias = "IsAnyMouseDown")]
180 pub fn is_any_mouse_down(&self) -> bool {
181 unsafe { sys::igIsAnyMouseDown() }
182 }
183
184 #[doc(alias = "GetTime")]
190 pub fn time(&self) -> f64 {
191 unsafe { sys::igGetTime() }
192 }
193
194 #[doc(alias = "GetFrameCount")]
196 pub fn frame_count(&self) -> i32 {
197 unsafe { sys::igGetFrameCount() }
198 }
199
200 #[doc(alias = "GetStyle")]
205 pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] {
206 unsafe {
207 let style_ptr = sys::igGetStyle();
208 let colors = (*style_ptr).Colors.as_ptr();
209 let color = *colors.add(style_color as usize);
210 [color.x, color.y, color.z, color.w]
211 }
212 }
213
214 #[doc(alias = "GetStyleColorName")]
220 pub fn style_color_name(&self, style_color: StyleColor) -> &'static str {
221 unsafe {
222 let name_ptr = sys::igGetStyleColorName(style_color as sys::ImGuiCol);
223 let c_str = std::ffi::CStr::from_ptr(name_ptr);
224 c_str.to_str().unwrap_or("Unknown")
225 }
226 }
227
228 #[doc(alias = "IsRectVisible")]
230 pub fn is_rect_visible(&self, size: [f32; 2]) -> bool {
231 unsafe {
232 let size = sys::ImVec2 {
233 x: size[0],
234 y: size[1],
235 };
236 sys::igIsRectVisible_Nil(size)
237 }
238 }
239
240 #[doc(alias = "IsRectVisible")]
242 pub fn is_rect_visible_ex(&self, rect_min: [f32; 2], rect_max: [f32; 2]) -> bool {
243 unsafe {
244 let rect_min = sys::ImVec2 {
245 x: rect_min[0],
246 y: rect_min[1],
247 };
248 let rect_max = sys::ImVec2 {
249 x: rect_max[0],
250 y: rect_max[1],
251 };
252 sys::igIsRectVisible_Vec2(rect_min, rect_max)
253 }
254 }
255
256 #[doc(alias = "GetCursorScreenPos")]
260 pub fn get_cursor_screen_pos(&self) -> [f32; 2] {
261 let pos = unsafe { sys::igGetCursorScreenPos() };
262 [pos.x, pos.y]
263 }
264
265 #[doc(alias = "GetContentRegionAvail")]
267 pub fn get_content_region_avail(&self) -> [f32; 2] {
268 let size = unsafe { sys::igGetContentRegionAvail() };
269 [size.x, size.y]
270 }
271
272 pub fn is_point_in_rect(
274 &self,
275 point: [f32; 2],
276 rect_min: [f32; 2],
277 rect_max: [f32; 2],
278 ) -> bool {
279 point[0] >= rect_min[0]
280 && point[0] <= rect_max[0]
281 && point[1] >= rect_min[1]
282 && point[1] <= rect_max[1]
283 }
284
285 pub fn distance(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
287 let dx = p2[0] - p1[0];
288 let dy = p2[1] - p1[1];
289 (dx * dx + dy * dy).sqrt()
290 }
291
292 pub fn distance_squared(&self, p1: [f32; 2], p2: [f32; 2]) -> f32 {
294 let dx = p2[0] - p1[0];
295 let dy = p2[1] - p1[1];
296 dx * dx + dy * dy
297 }
298
299 pub fn line_segments_intersect(
301 &self,
302 p1: [f32; 2],
303 p2: [f32; 2],
304 p3: [f32; 2],
305 p4: [f32; 2],
306 ) -> bool {
307 let d1 = self.cross_product(
308 [p4[0] - p3[0], p4[1] - p3[1]],
309 [p1[0] - p3[0], p1[1] - p3[1]],
310 );
311 let d2 = self.cross_product(
312 [p4[0] - p3[0], p4[1] - p3[1]],
313 [p2[0] - p3[0], p2[1] - p3[1]],
314 );
315 let d3 = self.cross_product(
316 [p2[0] - p1[0], p2[1] - p1[1]],
317 [p3[0] - p1[0], p3[1] - p1[1]],
318 );
319 let d4 = self.cross_product(
320 [p2[0] - p1[0], p2[1] - p1[1]],
321 [p4[0] - p1[0], p4[1] - p1[1]],
322 );
323
324 (d1 > 0.0) != (d2 > 0.0) && (d3 > 0.0) != (d4 > 0.0)
325 }
326
327 fn cross_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
329 v1[0] * v2[1] - v1[1] * v2[0]
330 }
331
332 pub fn normalize(&self, v: [f32; 2]) -> [f32; 2] {
334 let len = (v[0] * v[0] + v[1] * v[1]).sqrt();
335 if len > f32::EPSILON {
336 [v[0] / len, v[1] / len]
337 } else {
338 [0.0, 0.0]
339 }
340 }
341
342 pub fn dot_product(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
344 v1[0] * v2[0] + v1[1] * v2[1]
345 }
346
347 pub fn angle_between_vectors(&self, v1: [f32; 2], v2: [f32; 2]) -> f32 {
349 let dot = self.dot_product(v1, v2);
350 let len1 = (v1[0] * v1[0] + v1[1] * v1[1]).sqrt();
351 let len2 = (v2[0] * v2[0] + v2[1] * v2[1]).sqrt();
352
353 if len1 > f32::EPSILON && len2 > f32::EPSILON {
354 (dot / (len1 * len2)).acos()
355 } else {
356 0.0
357 }
358 }
359
360 pub fn is_point_in_circle(&self, point: [f32; 2], center: [f32; 2], radius: f32) -> bool {
362 self.distance_squared(point, center) <= radius * radius
363 }
364
365 pub fn triangle_area(&self, p1: [f32; 2], p2: [f32; 2], p3: [f32; 2]) -> f32 {
367 let cross = self.cross_product(
368 [p2[0] - p1[0], p2[1] - p1[1]],
369 [p3[0] - p1[0], p3[1] - p1[1]],
370 );
371 cross.abs() * 0.5
372 }
373
374 #[doc(alias = "SetNextItemAllowOverlap")]
378 pub fn set_next_item_allow_overlap(&self) {
379 unsafe { sys::igSetNextItemAllowOverlap() };
380 }
381}