dear_implot/
utils.rs

1// Utility functions for ImPlot
2
3use crate::{XAxis, YAxis, sys};
4
5/// Check if the plot area is hovered
6pub fn is_plot_hovered() -> bool {
7    unsafe { sys::ImPlot_IsPlotHovered() }
8}
9
10/// Check if any subplots area is hovered
11pub fn is_subplots_hovered() -> bool {
12    unsafe { sys::ImPlot_IsSubplotsHovered() }
13}
14
15/// Check if a legend entry is hovered
16pub fn is_legend_entry_hovered(label: &str) -> bool {
17    let c = std::ffi::CString::new(label).unwrap_or_default();
18    unsafe { sys::ImPlot_IsLegendEntryHovered(c.as_ptr()) }
19}
20
21/// Get the mouse position in plot coordinates
22pub fn get_plot_mouse_position(y_axis_choice: Option<crate::YAxisChoice>) -> sys::ImPlotPoint {
23    let x_axis = 0; // ImAxis_X1
24    let y_axis = match y_axis_choice {
25        Some(crate::YAxisChoice::First) => 3,  // ImAxis_Y1
26        Some(crate::YAxisChoice::Second) => 4, // ImAxis_Y2
27        Some(crate::YAxisChoice::Third) => 5,  // ImAxis_Y3
28        None => 3,                             // Default to Y1
29    };
30    let mut out = sys::ImPlotPoint { x: 0.0, y: 0.0 };
31    unsafe {
32        sys::ImPlot_GetPlotMousePos(
33            &mut out as *mut sys::ImPlotPoint,
34            x_axis as sys::ImAxis,
35            y_axis as sys::ImAxis,
36        )
37    }
38    out
39}
40
41/// Get the mouse position in plot coordinates for specific axes
42pub fn get_plot_mouse_position_axes(x_axis: XAxis, y_axis: YAxis) -> sys::ImPlotPoint {
43    let mut out = sys::ImPlotPoint { x: 0.0, y: 0.0 };
44    unsafe {
45        sys::ImPlot_GetPlotMousePos(
46            &mut out as *mut sys::ImPlotPoint,
47            x_axis as sys::ImAxis,
48            y_axis as sys::ImAxis,
49        )
50    };
51    out
52}
53
54/// Convert pixels to plot coordinates
55pub fn pixels_to_plot(
56    pixel_position: [f32; 2],
57    y_axis_choice: Option<crate::YAxisChoice>,
58) -> sys::ImPlotPoint {
59    // Map absolute pixel coordinates to plot coordinates using current plot's axes
60    let y_index = match y_axis_choice {
61        Some(crate::YAxisChoice::First) => 0,
62        Some(crate::YAxisChoice::Second) => 1,
63        Some(crate::YAxisChoice::Third) => 2,
64        None => 0,
65    };
66    unsafe {
67        let plot = sys::ImPlot_GetCurrentPlot();
68        if plot.is_null() {
69            return sys::ImPlotPoint { x: 0.0, y: 0.0 };
70        }
71        let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, 0);
72        let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_index);
73        let x = sys::ImPlotAxis_PixelsToPlot(x_axis_ptr, pixel_position[0]);
74        let y = sys::ImPlotAxis_PixelsToPlot(y_axis_ptr, pixel_position[1]);
75        sys::ImPlotPoint { x, y }
76    }
77}
78
79/// Convert pixels to plot coordinates for specific axes
80pub fn pixels_to_plot_axes(
81    pixel_position: [f32; 2],
82    x_axis: XAxis,
83    y_axis: YAxis,
84) -> sys::ImPlotPoint {
85    unsafe {
86        let plot = sys::ImPlot_GetCurrentPlot();
87        if plot.is_null() {
88            return sys::ImPlotPoint { x: 0.0, y: 0.0 };
89        }
90        let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, x_axis as i32);
91        let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_axis.to_index());
92        let x = sys::ImPlotAxis_PixelsToPlot(x_axis_ptr, pixel_position[0]);
93        let y = sys::ImPlotAxis_PixelsToPlot(y_axis_ptr, pixel_position[1]);
94        sys::ImPlotPoint { x, y }
95    }
96}
97
98/// Convert plot coordinates to pixels
99pub fn plot_to_pixels(
100    plot_position: sys::ImPlotPoint,
101    y_axis_choice: Option<crate::YAxisChoice>,
102) -> [f32; 2] {
103    let y_index = match y_axis_choice {
104        Some(crate::YAxisChoice::First) => 0,
105        Some(crate::YAxisChoice::Second) => 1,
106        Some(crate::YAxisChoice::Third) => 2,
107        None => 0,
108    };
109    unsafe {
110        let plot = sys::ImPlot_GetCurrentPlot();
111        if plot.is_null() {
112            return [0.0, 0.0];
113        }
114        let x_axis_ptr = sys::ImPlotPlot_XAxis_Nil(plot, 0);
115        let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_index);
116        let px = sys::ImPlotAxis_PlotToPixels(x_axis_ptr, plot_position.x);
117        let py = sys::ImPlotAxis_PlotToPixels(y_axis_ptr, plot_position.y);
118        [px, py]
119    }
120}
121
122/// Convert plot coordinates to pixels for specific axes
123pub fn plot_to_pixels_axes(
124    plot_position: sys::ImPlotPoint,
125    x_axis: XAxis,
126    y_axis: YAxis,
127) -> [f32; 2] {
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, x_axis as i32);
134        let y_axis_ptr = sys::ImPlotPlot_YAxis_Nil(plot, y_axis.to_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
141/// Get the current plot limits
142pub fn get_plot_limits(
143    _x_axis_choice: Option<crate::YAxisChoice>,
144    y_axis_choice: Option<crate::YAxisChoice>,
145) -> sys::ImPlotRect {
146    let x_axis = 0; // ImAxis_X1
147    let y_axis = match y_axis_choice {
148        Some(crate::YAxisChoice::First) => 3,  // ImAxis_Y1
149        Some(crate::YAxisChoice::Second) => 4, // ImAxis_Y2
150        Some(crate::YAxisChoice::Third) => 5,  // ImAxis_Y3
151        None => 3,                             // Default to Y1
152    };
153    let mut rect: sys::ImPlotRect = unsafe { std::mem::zeroed() };
154    unsafe { sys::ImPlot_GetPlotLimits(&mut rect as *mut sys::ImPlotRect, x_axis, y_axis) };
155    rect
156}
157
158/// Whether a plot has an active selection region
159pub fn is_plot_selected() -> bool {
160    unsafe { sys::ImPlot_IsPlotSelected() }
161}
162
163/// Get the current plot selection rectangle for specific axes
164pub fn get_plot_selection_axes(x_axis: XAxis, y_axis: YAxis) -> Option<sys::ImPlotRect> {
165    if !is_plot_selected() {
166        return None;
167    }
168    let mut rect: sys::ImPlotRect = unsafe { std::mem::zeroed() };
169    unsafe {
170        sys::ImPlot_GetPlotSelection(
171            &mut rect as *mut sys::ImPlotRect,
172            x_axis as i32,
173            y_axis as i32,
174        )
175    };
176    Some(rect)
177}
178
179/// Draw a simple round annotation marker at (x,y)
180pub fn annotation_point(
181    x: f64,
182    y: f64,
183    color: [f32; 4],
184    pixel_offset: [f32; 2],
185    clamp: bool,
186    round: bool,
187) {
188    let col = sys::ImVec4 {
189        x: color[0],
190        y: color[1],
191        z: color[2],
192        w: color[3],
193    };
194    let off = sys::ImVec2 {
195        x: pixel_offset[0],
196        y: pixel_offset[1],
197    };
198    unsafe { sys::ImPlot_Annotation_Bool(x, y, col, off, clamp, round) }
199}
200
201/// Tag the X axis at position x with a tick-like mark
202pub fn tag_x(x: f64, color: [f32; 4], round: bool) {
203    let col = sys::ImVec4 {
204        x: color[0],
205        y: color[1],
206        z: color[2],
207        w: color[3],
208    };
209    unsafe { sys::ImPlot_TagX_Bool(x, col, round) }
210}
211
212/// Tag the Y axis at position y with a tick-like mark
213pub fn tag_y(y: f64, color: [f32; 4], round: bool) {
214    let col = sys::ImVec4 {
215        x: color[0],
216        y: color[1],
217        z: color[2],
218        w: color[3],
219    };
220    unsafe { sys::ImPlot_TagY_Bool(y, col, round) }
221}
222
223/// Get the current plot limits for specific axes
224pub fn get_plot_limits_axes(x_axis: XAxis, y_axis: YAxis) -> sys::ImPlotRect {
225    let mut rect: sys::ImPlotRect = unsafe { std::mem::zeroed() };
226    unsafe {
227        sys::ImPlot_GetPlotLimits(
228            &mut rect as *mut sys::ImPlotRect,
229            x_axis as i32,
230            y_axis as i32,
231        )
232    };
233    rect
234}
235
236/// Check if an axis is hovered
237pub fn is_axis_hovered(axis: i32) -> bool {
238    unsafe { sys::ImPlot_IsAxisHovered(axis) }
239}
240
241/// Check if the X axis is hovered
242pub fn is_plot_x_axis_hovered() -> bool {
243    is_axis_hovered(XAxis::X1 as i32)
244}
245
246/// Check if a specific X axis is hovered
247pub fn is_plot_x_axis_hovered_axis(x_axis: XAxis) -> bool {
248    is_axis_hovered(x_axis as i32)
249}
250
251/// Check if a Y axis is hovered
252pub fn is_plot_y_axis_hovered(y_axis_choice: Option<crate::YAxisChoice>) -> bool {
253    let y_axis = match y_axis_choice {
254        Some(crate::YAxisChoice::First) => 3,  // ImAxis_Y1
255        Some(crate::YAxisChoice::Second) => 4, // ImAxis_Y2
256        Some(crate::YAxisChoice::Third) => 5,  // ImAxis_Y3
257        None => 3,                             // Default to Y1
258    };
259    is_axis_hovered(y_axis)
260}
261
262/// Check if a specific Y axis is hovered
263pub fn is_plot_y_axis_hovered_axis(y_axis: YAxis) -> bool {
264    is_axis_hovered(y_axis as i32)
265}
266
267/// Show the ImPlot demo window (requires sys demo symbols to be linked)
268#[cfg(feature = "demo")]
269pub fn show_demo_window(show: &mut bool) {
270    unsafe { sys::ImPlot_ShowDemoWindow(show) }
271}
272
273/// Stub when demo feature is disabled
274#[cfg(not(feature = "demo"))]
275pub fn show_demo_window(_show: &mut bool) {}
276
277/// Show the built-in user guide for ImPlot
278pub fn show_user_guide() {
279    unsafe { sys::ImPlot_ShowUserGuide() }
280}
281
282/// Show the metrics window (pass &mut bool for open state)
283pub fn show_metrics_window(open: &mut bool) {
284    unsafe { sys::ImPlot_ShowMetricsWindow(open as *mut bool) }
285}
286
287/// Get current plot position (top-left) in pixels
288pub fn get_plot_pos() -> [f32; 2] {
289    let mut out = sys::ImVec2 { x: 0.0, y: 0.0 };
290    unsafe { sys::ImPlot_GetPlotPos(&mut out as *mut _) };
291    [out.x, out.y]
292}
293
294/// Get current plot size in pixels
295pub fn get_plot_size() -> [f32; 2] {
296    let mut out = sys::ImVec2 { x: 0.0, y: 0.0 };
297    unsafe { sys::ImPlot_GetPlotSize(&mut out as *mut _) };
298    [out.x, out.y]
299}
300
301/// Get the underlying ImDrawList for the current plot (unsafe pointer)
302pub fn get_plot_draw_list() -> *mut sys::ImDrawList {
303    unsafe { sys::ImPlot_GetPlotDrawList() }
304}
305
306/// Push plot clip rect
307pub fn push_plot_clip_rect(expand: f32) {
308    unsafe { sys::ImPlot_PushPlotClipRect(expand) }
309}
310
311/// Pop plot clip rect
312pub fn pop_plot_clip_rect() {
313    unsafe { sys::ImPlot_PopPlotClipRect() }
314}
315
316/// Result of a drag interaction
317#[derive(Debug, Clone, Copy, Default)]
318pub struct DragResult {
319    /// True if the underlying value changed this frame
320    pub changed: bool,
321    /// True if it was clicked this frame
322    pub clicked: bool,
323    /// True if hovered this frame
324    pub hovered: bool,
325    /// True if held/active this frame
326    pub held: bool,
327}
328
329fn color4(rgba: [f32; 4]) -> sys::ImVec4 {
330    sys::ImVec4 {
331        x: rgba[0],
332        y: rgba[1],
333        z: rgba[2],
334        w: rgba[3],
335    }
336}
337
338/// Draggable point with result flags
339pub fn drag_point(
340    id: i32,
341    x: &mut f64,
342    y: &mut f64,
343    color: [f32; 4],
344    size: f32,
345    flags: crate::DragToolFlags,
346) -> DragResult {
347    let mut clicked = false;
348    let mut hovered = false;
349    let mut held = false;
350    let changed = unsafe {
351        sys::ImPlot_DragPoint(
352            id,
353            x as *mut f64,
354            y as *mut f64,
355            color4(color),
356            size,
357            flags.bits() as i32,
358            &mut clicked as *mut bool,
359            &mut hovered as *mut bool,
360            &mut held as *mut bool,
361        )
362    };
363    DragResult {
364        changed,
365        clicked,
366        hovered,
367        held,
368    }
369}
370
371/// Draggable vertical line at x
372pub fn drag_line_x(
373    id: i32,
374    x: &mut f64,
375    color: [f32; 4],
376    thickness: f32,
377    flags: crate::DragToolFlags,
378) -> DragResult {
379    let mut clicked = false;
380    let mut hovered = false;
381    let mut held = false;
382    let changed = unsafe {
383        sys::ImPlot_DragLineX(
384            id,
385            x as *mut f64,
386            color4(color),
387            thickness,
388            flags.bits() as i32,
389            &mut clicked as *mut bool,
390            &mut hovered as *mut bool,
391            &mut held as *mut bool,
392        )
393    };
394    DragResult {
395        changed,
396        clicked,
397        hovered,
398        held,
399    }
400}
401
402/// Draggable horizontal line at y
403pub fn drag_line_y(
404    id: i32,
405    y: &mut f64,
406    color: [f32; 4],
407    thickness: f32,
408    flags: crate::DragToolFlags,
409) -> DragResult {
410    let mut clicked = false;
411    let mut hovered = false;
412    let mut held = false;
413    let changed = unsafe {
414        sys::ImPlot_DragLineY(
415            id,
416            y as *mut f64,
417            color4(color),
418            thickness,
419            flags.bits() as i32,
420            &mut clicked as *mut bool,
421            &mut hovered as *mut bool,
422            &mut held as *mut bool,
423        )
424    };
425    DragResult {
426        changed,
427        clicked,
428        hovered,
429        held,
430    }
431}