1use crate::{Axis, XAxis, YAxis, compat_ffi, sys};
4use dear_imgui_rs::with_scratch_txt;
5
6fn assert_finite_f32(caller: &str, name: &str, value: f32) {
7 assert!(value.is_finite(), "{caller} {name} must be finite");
8}
9
10fn assert_finite_f64(caller: &str, name: &str, value: f64) {
11 assert!(value.is_finite(), "{caller} {name} must be finite");
12}
13
14fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
15 assert!(
16 value[0].is_finite() && value[1].is_finite(),
17 "{caller} {name} must be finite"
18 );
19}
20
21fn assert_finite_color(caller: &str, name: &str, value: [f32; 4]) {
22 assert!(
23 value.iter().all(|component| component.is_finite()),
24 "{caller} {name} must be finite"
25 );
26}
27
28fn assert_finite_point(caller: &str, name: &str, value: sys::ImPlotPoint) {
29 assert!(
30 value.x.is_finite() && value.y.is_finite(),
31 "{caller} {name} must be finite"
32 );
33}
34
35pub fn is_plot_hovered() -> bool {
37 unsafe { sys::ImPlot_IsPlotHovered() }
38}
39
40pub fn is_subplots_hovered() -> bool {
42 unsafe { sys::ImPlot_IsSubplotsHovered() }
43}
44
45pub fn is_legend_entry_hovered(label: &str) -> bool {
47 let label = if label.contains('\0') { "" } else { label };
48 with_scratch_txt(label, |ptr| unsafe {
49 sys::ImPlot_IsLegendEntryHovered(ptr)
50 })
51}
52
53pub fn get_plot_mouse_position(y_axis_choice: Option<crate::YAxisChoice>) -> sys::ImPlotPoint {
55 let x_axis = 0; let y_axis = match y_axis_choice {
57 Some(crate::YAxisChoice::First) => 3, Some(crate::YAxisChoice::Second) => 4, Some(crate::YAxisChoice::Third) => 5, None => 3, };
62 unsafe { sys::ImPlot_GetPlotMousePos(x_axis as sys::ImAxis, y_axis as sys::ImAxis) }
63}
64
65pub fn get_plot_mouse_position_axes(x_axis: XAxis, y_axis: YAxis) -> sys::ImPlotPoint {
67 unsafe { sys::ImPlot_GetPlotMousePos(x_axis as sys::ImAxis, y_axis as sys::ImAxis) }
68}
69
70pub fn pixels_to_plot(
72 pixel_position: [f32; 2],
73 y_axis_choice: Option<crate::YAxisChoice>,
74) -> sys::ImPlotPoint {
75 assert_finite_vec2("pixels_to_plot()", "pixel_position", pixel_position);
76 let y_index = match y_axis_choice {
78 Some(crate::YAxisChoice::First) => 0,
79 Some(crate::YAxisChoice::Second) => 1,
80 Some(crate::YAxisChoice::Third) => 2,
81 None => 0,
82 };
83 unsafe {
84 let plot = sys::ImPlot_GetCurrentPlot();
85 if plot.is_null() {
86 return sys::ImPlotPoint { x: 0.0, y: 0.0 };
87 }
88 let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, 0);
89 let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_index);
90 let x = sys::ImPlotAxis_PixelsToPlot(x_axis_ptr, pixel_position[0]);
91 let y = sys::ImPlotAxis_PixelsToPlot(y_axis_ptr, pixel_position[1]);
92 sys::ImPlotPoint { x, y }
93 }
94}
95
96pub fn pixels_to_plot_axes(
98 pixel_position: [f32; 2],
99 x_axis: XAxis,
100 y_axis: YAxis,
101) -> sys::ImPlotPoint {
102 assert_finite_vec2("pixels_to_plot_axes()", "pixel_position", pixel_position);
103 unsafe {
104 let plot = sys::ImPlot_GetCurrentPlot();
105 if plot.is_null() {
106 return sys::ImPlotPoint { x: 0.0, y: 0.0 };
107 }
108 let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, x_axis as i32);
109 let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_axis.to_index());
110 let x = sys::ImPlotAxis_PixelsToPlot(x_axis_ptr, pixel_position[0]);
111 let y = sys::ImPlotAxis_PixelsToPlot(y_axis_ptr, pixel_position[1]);
112 sys::ImPlotPoint { x, y }
113 }
114}
115
116pub fn plot_to_pixels(
118 plot_position: sys::ImPlotPoint,
119 y_axis_choice: Option<crate::YAxisChoice>,
120) -> [f32; 2] {
121 assert_finite_point("plot_to_pixels()", "plot_position", plot_position);
122 let y_index = match y_axis_choice {
123 Some(crate::YAxisChoice::First) => 0,
124 Some(crate::YAxisChoice::Second) => 1,
125 Some(crate::YAxisChoice::Third) => 2,
126 None => 0,
127 };
128 unsafe {
129 let plot = sys::ImPlot_GetCurrentPlot();
130 if plot.is_null() {
131 return [0.0, 0.0];
132 }
133 let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, 0);
134 let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_index);
135 let px = sys::ImPlotAxis_PlotToPixels(x_axis_ptr, plot_position.x);
136 let py = sys::ImPlotAxis_PlotToPixels(y_axis_ptr, plot_position.y);
137 [px, py]
138 }
139}
140
141pub fn plot_to_pixels_axes(
143 plot_position: sys::ImPlotPoint,
144 x_axis: XAxis,
145 y_axis: YAxis,
146) -> [f32; 2] {
147 assert_finite_point("plot_to_pixels_axes()", "plot_position", plot_position);
148 unsafe {
149 let plot = sys::ImPlot_GetCurrentPlot();
150 if plot.is_null() {
151 return [0.0, 0.0];
152 }
153 let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, x_axis as i32);
154 let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_axis.to_index());
155 let px = sys::ImPlotAxis_PlotToPixels(x_axis_ptr, plot_position.x);
156 let py = sys::ImPlotAxis_PlotToPixels(y_axis_ptr, plot_position.y);
157 [px, py]
158 }
159}
160
161pub fn get_plot_limits(
163 _x_axis_choice: Option<crate::YAxisChoice>,
164 y_axis_choice: Option<crate::YAxisChoice>,
165) -> sys::ImPlotRect {
166 let x_axis = 0; let y_axis = match y_axis_choice {
168 Some(crate::YAxisChoice::First) => 3, Some(crate::YAxisChoice::Second) => 4, Some(crate::YAxisChoice::Third) => 5, None => 3, };
173 unsafe { sys::ImPlot_GetPlotLimits(x_axis, y_axis) }
174}
175
176pub fn is_plot_selected() -> bool {
178 unsafe { sys::ImPlot_IsPlotSelected() }
179}
180
181pub fn get_plot_selection_axes(x_axis: XAxis, y_axis: YAxis) -> Option<sys::ImPlotRect> {
183 if !is_plot_selected() {
184 return None;
185 }
186 let rect = unsafe { sys::ImPlot_GetPlotSelection(x_axis as i32, y_axis as i32) };
187 Some(rect)
188}
189
190pub fn annotation_point(
192 x: f64,
193 y: f64,
194 color: [f32; 4],
195 pixel_offset: [f32; 2],
196 clamp: bool,
197 round: bool,
198) {
199 assert_finite_f64("annotation_point()", "x", x);
200 assert_finite_f64("annotation_point()", "y", y);
201 assert_finite_color("annotation_point()", "color", color);
202 assert_finite_vec2("annotation_point()", "pixel_offset", pixel_offset);
203 let col = sys::ImVec4_c {
204 x: color[0],
205 y: color[1],
206 z: color[2],
207 w: color[3],
208 };
209 let off = sys::ImVec2_c {
210 x: pixel_offset[0],
211 y: pixel_offset[1],
212 };
213 unsafe { sys::ImPlot_Annotation_Bool(x, y, col, off, clamp, round) }
214}
215
216pub fn annotation_text(
221 x: f64,
222 y: f64,
223 color: [f32; 4],
224 pixel_offset: [f32; 2],
225 clamp: bool,
226 text: &str,
227) {
228 assert_finite_f64("annotation_text()", "x", x);
229 assert_finite_f64("annotation_text()", "y", y);
230 assert_finite_color("annotation_text()", "color", color);
231 assert_finite_vec2("annotation_text()", "pixel_offset", pixel_offset);
232 let col = sys::ImVec4_c {
233 x: color[0],
234 y: color[1],
235 z: color[2],
236 w: color[3],
237 };
238 let off = sys::ImVec2_c {
239 x: pixel_offset[0],
240 y: pixel_offset[1],
241 };
242 assert!(!text.contains('\0'), "text contained NUL");
243 with_scratch_txt(text, |ptr| unsafe {
244 compat_ffi::ImPlot_Annotation_Str0(x, y, col, off, clamp, ptr)
245 })
246}
247
248pub fn tag_x(x: f64, color: [f32; 4], round: bool) {
250 assert_finite_f64("tag_x()", "x", x);
251 assert_finite_color("tag_x()", "color", color);
252 let col = sys::ImVec4_c {
253 x: color[0],
254 y: color[1],
255 z: color[2],
256 w: color[3],
257 };
258 unsafe { sys::ImPlot_TagX_Bool(x, col, round) }
259}
260
261pub fn tag_x_text(x: f64, color: [f32; 4], text: &str) {
263 assert_finite_f64("tag_x_text()", "x", x);
264 assert_finite_color("tag_x_text()", "color", color);
265 let col = sys::ImVec4_c {
266 x: color[0],
267 y: color[1],
268 z: color[2],
269 w: color[3],
270 };
271 assert!(!text.contains('\0'), "text contained NUL");
272 with_scratch_txt(text, |ptr| unsafe {
273 compat_ffi::ImPlot_TagX_Str0(x, col, ptr)
274 })
275}
276
277pub fn tag_y(y: f64, color: [f32; 4], round: bool) {
279 assert_finite_f64("tag_y()", "y", y);
280 assert_finite_color("tag_y()", "color", color);
281 let col = sys::ImVec4_c {
282 x: color[0],
283 y: color[1],
284 z: color[2],
285 w: color[3],
286 };
287 unsafe { sys::ImPlot_TagY_Bool(y, col, round) }
288}
289
290pub fn tag_y_text(y: f64, color: [f32; 4], text: &str) {
292 assert_finite_f64("tag_y_text()", "y", y);
293 assert_finite_color("tag_y_text()", "color", color);
294 let col = sys::ImVec4_c {
295 x: color[0],
296 y: color[1],
297 z: color[2],
298 w: color[3],
299 };
300 assert!(!text.contains('\0'), "text contained NUL");
301 with_scratch_txt(text, |ptr| unsafe {
302 compat_ffi::ImPlot_TagY_Str0(y, col, ptr)
303 })
304}
305
306pub fn get_plot_limits_axes(x_axis: XAxis, y_axis: YAxis) -> sys::ImPlotRect {
308 unsafe { sys::ImPlot_GetPlotLimits(x_axis as i32, y_axis as i32) }
309}
310
311pub fn is_axis_hovered(axis: Axis) -> bool {
313 unsafe { sys::ImPlot_IsAxisHovered(axis.to_sys()) }
314}
315
316pub unsafe fn is_axis_hovered_unchecked(axis: sys::ImAxis) -> bool {
323 unsafe { sys::ImPlot_IsAxisHovered(axis) }
324}
325
326pub fn is_plot_x_axis_hovered() -> bool {
328 is_axis_hovered(Axis::X1)
329}
330
331pub fn is_plot_x_axis_hovered_axis(x_axis: XAxis) -> bool {
333 is_axis_hovered(x_axis.into())
334}
335
336pub fn is_plot_y_axis_hovered(y_axis_choice: Option<crate::YAxisChoice>) -> bool {
338 let y_axis = match y_axis_choice {
339 Some(crate::YAxisChoice::First) => 3, Some(crate::YAxisChoice::Second) => 4, Some(crate::YAxisChoice::Third) => 5, None => 3, };
344 is_axis_hovered(match y_axis {
345 3 => Axis::Y1,
346 4 => Axis::Y2,
347 5 => Axis::Y3,
348 _ => Axis::Y1,
349 })
350}
351
352pub fn is_plot_y_axis_hovered_axis(y_axis: YAxis) -> bool {
354 is_axis_hovered(y_axis.into())
355}
356
357#[cfg(feature = "demo")]
359pub fn show_demo_window(show: &mut bool) {
360 unsafe { sys::ImPlot_ShowDemoWindow(show) }
361}
362
363#[cfg(not(feature = "demo"))]
365pub fn show_demo_window(_show: &mut bool) {}
366
367pub fn show_user_guide() {
369 unsafe { sys::ImPlot_ShowUserGuide() }
370}
371
372pub fn show_metrics_window(open: &mut bool) {
374 unsafe { sys::ImPlot_ShowMetricsWindow(open as *mut bool) }
375}
376
377pub fn get_plot_pos() -> [f32; 2] {
379 let out = unsafe { crate::compat_ffi::ImPlot_GetPlotPos() };
380 [out.x, out.y]
381}
382
383pub fn get_plot_size() -> [f32; 2] {
385 let out = unsafe { crate::compat_ffi::ImPlot_GetPlotSize() };
386 [out.x, out.y]
387}
388
389pub fn get_plot_draw_list() -> *mut sys::ImDrawList {
391 unsafe { sys::ImPlot_GetPlotDrawList() }
392}
393
394pub fn push_plot_clip_rect(expand: f32) {
396 assert_finite_f32("push_plot_clip_rect()", "expand", expand);
397 unsafe { sys::ImPlot_PushPlotClipRect(expand) }
398}
399
400pub fn pop_plot_clip_rect() {
402 unsafe { sys::ImPlot_PopPlotClipRect() }
403}
404
405#[derive(Debug, Clone, Copy, Default)]
407pub struct DragResult {
408 pub changed: bool,
410 pub clicked: bool,
412 pub hovered: bool,
414 pub held: bool,
416}
417
418fn color4(rgba: [f32; 4]) -> sys::ImVec4_c {
419 sys::ImVec4_c {
420 x: rgba[0],
421 y: rgba[1],
422 z: rgba[2],
423 w: rgba[3],
424 }
425}
426
427pub fn drag_point(
429 id: i32,
430 x: &mut f64,
431 y: &mut f64,
432 color: [f32; 4],
433 size: f32,
434 flags: crate::DragToolFlags,
435) -> DragResult {
436 let mut clicked = false;
437 let mut hovered = false;
438 let mut held = false;
439 let changed = unsafe {
440 sys::ImPlot_DragPoint(
441 id,
442 x as *mut f64,
443 y as *mut f64,
444 color4(color),
445 size,
446 flags.bits() as i32,
447 &mut clicked as *mut bool,
448 &mut hovered as *mut bool,
449 &mut held as *mut bool,
450 )
451 };
452 DragResult {
453 changed,
454 clicked,
455 hovered,
456 held,
457 }
458}
459
460pub fn drag_line_x(
462 id: i32,
463 x: &mut f64,
464 color: [f32; 4],
465 thickness: f32,
466 flags: crate::DragToolFlags,
467) -> DragResult {
468 let mut clicked = false;
469 let mut hovered = false;
470 let mut held = false;
471 let changed = unsafe {
472 sys::ImPlot_DragLineX(
473 id,
474 x as *mut f64,
475 color4(color),
476 thickness,
477 flags.bits() as i32,
478 &mut clicked as *mut bool,
479 &mut hovered as *mut bool,
480 &mut held as *mut bool,
481 )
482 };
483 DragResult {
484 changed,
485 clicked,
486 hovered,
487 held,
488 }
489}
490
491pub fn drag_line_y(
493 id: i32,
494 y: &mut f64,
495 color: [f32; 4],
496 thickness: f32,
497 flags: crate::DragToolFlags,
498) -> DragResult {
499 let mut clicked = false;
500 let mut hovered = false;
501 let mut held = false;
502 let changed = unsafe {
503 sys::ImPlot_DragLineY(
504 id,
505 y as *mut f64,
506 color4(color),
507 thickness,
508 flags.bits() as i32,
509 &mut clicked as *mut bool,
510 &mut hovered as *mut bool,
511 &mut held as *mut bool,
512 )
513 };
514 DragResult {
515 changed,
516 clicked,
517 hovered,
518 held,
519 }
520}