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