Skip to main content

dear_implot/
lib.rs

1//! # Dear ImPlot - Rust Bindings with Dear ImGui Compatibility
2//!
3//! High-level Rust bindings for ImPlot, the immediate mode plotting library.
4//! This crate provides safe, idiomatic Rust bindings designed to work seamlessly
5//! with dear-imgui (C++ bindgen) rather than imgui-rs (cimgui).
6//!
7//! ## Features
8//!
9//! - Safe, idiomatic Rust API
10//! - Full compatibility with dear-imgui
11//! - Builder pattern for plots and plot elements
12//! - Memory-safe string handling
13//! - Support for all major plot types
14//!
15//! ## Quick Start
16//!
17//! ```no_run
18//! use dear_imgui_rs::*;
19//! use dear_implot::*;
20//!
21//! let mut ctx = Context::create();
22//! let mut plot_ctx = PlotContext::create(&ctx);
23//!
24//! let ui = ctx.frame();
25//! let plot_ui = plot_ctx.get_plot_ui(&ui);
26//!
27//! if let Some(token) = plot_ui.begin_plot("My Plot") {
28//!     plot_ui.plot_line("Line", &[1.0, 2.0, 3.0, 4.0], &[1.0, 4.0, 2.0, 3.0]);
29//!     token.end();
30//! }
31//! ```
32//!
33//! ## Integration with Dear ImGui
34//!
35//! This crate is designed to work with the `dear-imgui-rs` ecosystem:
36//! - Uses the same context management patterns
37//! - Compatible with dear-imgui's UI tokens and lifetime management
38//! - Shares the same underlying Dear ImGui context
39
40use dear_implot_sys as sys;
41
42// Bindgen output for `dear-implot-sys` can fluctuate between historical
43// out-parameter signatures and the newer return-by-value signatures depending
44// on which generated `OUT_DIR` file rust-analyzer happens to index.
45//
46// Keep the wrapper crate stable by calling a local extern declaration for the
47// specific APIs we expose.
48#[allow(non_snake_case)]
49pub(crate) mod compat_ffi {
50    use super::sys;
51    use std::os::raw::c_char;
52
53    unsafe extern "C" {
54        pub fn ImPlot_GetPlotPos() -> sys::ImVec2;
55        pub fn ImPlot_GetPlotSize() -> sys::ImVec2;
56    }
57
58    // Some targets (notably import-style wasm) cannot call C variadic (`...`) functions.
59    // Declare the `*_Str0` convenience wrappers here to keep the safe layer independent
60    // of bindgen fluctuations / pregenerated bindings.
61    //
62    // On wasm32, these must be provided by the `imgui-sys-v0` provider module.
63    #[cfg(target_arch = "wasm32")]
64    #[link(wasm_import_module = "imgui-sys-v0")]
65    unsafe extern "C" {
66        pub fn ImPlot_Annotation_Str0(
67            x: f64,
68            y: f64,
69            col: sys::ImVec4_c,
70            pix_offset: sys::ImVec2_c,
71            clamp: bool,
72            fmt: *const c_char,
73        );
74        pub fn ImPlot_TagX_Str0(x: f64, col: sys::ImVec4_c, fmt: *const c_char);
75        pub fn ImPlot_TagY_Str0(y: f64, col: sys::ImVec4_c, fmt: *const c_char);
76    }
77
78    #[cfg(not(target_arch = "wasm32"))]
79    unsafe extern "C" {
80        pub fn ImPlot_Annotation_Str0(
81            x: f64,
82            y: f64,
83            col: sys::ImVec4_c,
84            pix_offset: sys::ImVec2_c,
85            clamp: bool,
86            fmt: *const c_char,
87        );
88        pub fn ImPlot_TagX_Str0(x: f64, col: sys::ImVec4_c, fmt: *const c_char);
89        pub fn ImPlot_TagY_Str0(y: f64, col: sys::ImVec4_c, fmt: *const c_char);
90    }
91}
92
93// Re-export essential types
94pub use dear_imgui_rs::{Context, Ui};
95pub use sys::{ImPlotPoint, ImPlotRange, ImPlotRect};
96pub use sys::{ImTextureID, ImVec2, ImVec4};
97
98mod advanced;
99mod context;
100mod style;
101mod utils;
102
103// New modular plot types
104pub mod plots;
105
106pub use context::*;
107pub use style::*;
108pub use utils::*;
109
110// Re-export new modular plot types for convenience
111pub use plots::{
112    Plot, PlotData, PlotError,
113    bar::{BarPlot, PositionalBarPlot},
114    error_bars::{AsymmetricErrorBarsPlot, ErrorBarsPlot, SimpleErrorBarsPlot},
115    heatmap::{HeatmapPlot, HeatmapPlotF32},
116    histogram::{Histogram2DPlot, HistogramPlot},
117    line::{LinePlot, SimpleLinePlot},
118    pie::{PieChartPlot, PieChartPlotF32},
119    polygon::PolygonPlot,
120    scatter::{ScatterPlot, SimpleScatterPlot},
121    shaded::{ShadedBetweenPlot, ShadedPlot, SimpleShadedPlot},
122    stems::{SimpleStemPlot, StemPlot},
123};
124
125// Constants
126const IMPLOT_AUTO: i32 = -1;
127
128/// Choice of Y axis for multi-axis plots
129#[derive(Clone, Copy, Debug, PartialEq, Eq)]
130#[repr(u32)]
131pub enum YAxisChoice {
132    First = 0,
133    Second = 1,
134    Third = 2,
135}
136
137/// Convert an Option<YAxisChoice> into an i32. Picks IMPLOT_AUTO for None.
138fn y_axis_choice_option_to_i32(y_axis_choice: Option<YAxisChoice>) -> i32 {
139    match y_axis_choice {
140        Some(choice) => choice as i32,
141        None => IMPLOT_AUTO,
142    }
143}
144
145/// X axis selector matching ImPlot's ImAxis values
146#[derive(Clone, Copy, Debug, PartialEq, Eq)]
147#[repr(i32)]
148pub enum XAxis {
149    X1 = 0,
150    X2 = 1,
151    X3 = 2,
152}
153
154/// Y axis selector matching ImPlot's ImAxis values
155#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156#[repr(i32)]
157pub enum YAxis {
158    Y1 = 3,
159    Y2 = 4,
160    Y3 = 5,
161}
162
163impl YAxis {
164    /// Convert a Y axis (Y1..Y3) to the 0-based index used by ImPlotPlot_YAxis_Nil
165    pub(crate) fn to_index(self) -> i32 {
166        (self as i32) - 3
167    }
168}
169
170/// Any ImPlot axis selector matching ImPlot's ImAxis values.
171#[derive(Clone, Copy, Debug, PartialEq, Eq)]
172#[repr(i32)]
173pub enum Axis {
174    X1 = 0,
175    X2 = 1,
176    X3 = 2,
177    Y1 = 3,
178    Y2 = 4,
179    Y3 = 5,
180}
181
182impl Axis {
183    pub(crate) fn to_sys(self) -> sys::ImAxis {
184        self as sys::ImAxis
185    }
186}
187
188impl From<XAxis> for Axis {
189    fn from(axis: XAxis) -> Self {
190        match axis {
191            XAxis::X1 => Self::X1,
192            XAxis::X2 => Self::X2,
193            XAxis::X3 => Self::X3,
194        }
195    }
196}
197
198impl From<YAxis> for Axis {
199    fn from(axis: YAxis) -> Self {
200        match axis {
201            YAxis::Y1 => Self::Y1,
202            YAxis::Y2 => Self::Y2,
203            YAxis::Y3 => Self::Y3,
204        }
205    }
206}
207
208/// Ui extension for obtaining a PlotUi from an ImPlot PlotContext
209pub trait ImPlotExt {
210    fn implot<'ui>(&'ui self, ctx: &'ui PlotContext) -> PlotUi<'ui>;
211}
212
213impl ImPlotExt for Ui {
214    fn implot<'ui>(&'ui self, ctx: &'ui PlotContext) -> PlotUi<'ui> {
215        ctx.get_plot_ui(self)
216    }
217}
218
219/// Markers for plot points
220#[repr(i32)]
221#[derive(Copy, Clone, Debug, PartialEq, Eq)]
222pub enum Marker {
223    Auto = sys::ImPlotMarker_Auto as i32,
224    None = sys::ImPlotMarker_None as i32,
225    Circle = sys::ImPlotMarker_Circle as i32,
226    Square = sys::ImPlotMarker_Square as i32,
227    Diamond = sys::ImPlotMarker_Diamond as i32,
228    Up = sys::ImPlotMarker_Up as i32,
229    Down = sys::ImPlotMarker_Down as i32,
230    Left = sys::ImPlotMarker_Left as i32,
231    Right = sys::ImPlotMarker_Right as i32,
232    Cross = sys::ImPlotMarker_Cross as i32,
233    Plus = sys::ImPlotMarker_Plus as i32,
234    Asterisk = sys::ImPlotMarker_Asterisk as i32,
235}
236
237/// Colorable plot elements
238#[repr(u32)]
239#[derive(Copy, Clone, Debug, PartialEq, Eq)]
240pub enum PlotColorElement {
241    FrameBg = sys::ImPlotCol_FrameBg as u32,
242    PlotBg = sys::ImPlotCol_PlotBg as u32,
243    PlotBorder = sys::ImPlotCol_PlotBorder as u32,
244    LegendBg = sys::ImPlotCol_LegendBg as u32,
245    LegendBorder = sys::ImPlotCol_LegendBorder as u32,
246    LegendText = sys::ImPlotCol_LegendText as u32,
247    TitleText = sys::ImPlotCol_TitleText as u32,
248    InlayText = sys::ImPlotCol_InlayText as u32,
249    AxisText = sys::ImPlotCol_AxisText as u32,
250    AxisGrid = sys::ImPlotCol_AxisGrid as u32,
251    AxisTick = sys::ImPlotCol_AxisTick as u32,
252    AxisBg = sys::ImPlotCol_AxisBg as u32,
253    AxisBgHovered = sys::ImPlotCol_AxisBgHovered as u32,
254    AxisBgActive = sys::ImPlotCol_AxisBgActive as u32,
255    Selection = sys::ImPlotCol_Selection as u32,
256    Crosshairs = sys::ImPlotCol_Crosshairs as u32,
257}
258
259/// Built-in colormaps
260#[repr(u32)]
261#[derive(Copy, Clone, Debug, PartialEq, Eq)]
262pub enum Colormap {
263    Deep = sys::ImPlotColormap_Deep as u32,
264    Dark = sys::ImPlotColormap_Dark as u32,
265    Pastel = sys::ImPlotColormap_Pastel as u32,
266    Paired = sys::ImPlotColormap_Paired as u32,
267    Viridis = sys::ImPlotColormap_Viridis as u32,
268    Plasma = sys::ImPlotColormap_Plasma as u32,
269    Hot = sys::ImPlotColormap_Hot as u32,
270    Cool = sys::ImPlotColormap_Cool as u32,
271    Pink = sys::ImPlotColormap_Pink as u32,
272    Jet = sys::ImPlotColormap_Jet as u32,
273}
274
275/// Plot location for legends, labels, etc.
276#[repr(u32)]
277#[derive(Copy, Clone, Debug, PartialEq, Eq)]
278pub enum PlotLocation {
279    Center = sys::ImPlotLocation_Center as u32,
280    North = sys::ImPlotLocation_North as u32,
281    South = sys::ImPlotLocation_South as u32,
282    West = sys::ImPlotLocation_West as u32,
283    East = sys::ImPlotLocation_East as u32,
284    NorthWest = sys::ImPlotLocation_NorthWest as u32,
285    NorthEast = sys::ImPlotLocation_NorthEast as u32,
286    SouthWest = sys::ImPlotLocation_SouthWest as u32,
287    SouthEast = sys::ImPlotLocation_SouthEast as u32,
288}
289
290/// Plot orientation
291#[repr(u32)]
292#[derive(Copy, Clone, Debug, PartialEq, Eq)]
293pub enum PlotOrientation {
294    Horizontal = 0,
295    Vertical = 1,
296}
297
298/// Binning methods for histograms
299#[repr(i32)]
300#[derive(Copy, Clone, Debug, PartialEq, Eq)]
301pub enum BinMethod {
302    Sqrt = -1,
303    Sturges = -2,
304    Rice = -3,
305    Scott = -4,
306}
307
308bitflags::bitflags! {
309    /// Flags for ANY `PlotX` function. Used by setting `ImPlotSpec::Flags`.
310    ///
311    /// These flags can be composed with the plot-type-specific flags (e.g. `LineFlags`).
312    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
313    pub struct ItemFlags: u32 {
314        const NONE = sys::ImPlotItemFlags_None as u32;
315        const NO_LEGEND = sys::ImPlotItemFlags_NoLegend as u32;
316        const NO_FIT = sys::ImPlotItemFlags_NoFit as u32;
317    }
318}
319
320// Plot flags for different plot types
321bitflags::bitflags! {
322    /// Flags for heatmap plots
323    pub struct HeatmapFlags: u32 {
324        const NONE = sys::ImPlotHeatmapFlags_None as u32;
325        const COL_MAJOR = sys::ImPlotHeatmapFlags_ColMajor as u32;
326    }
327}
328
329bitflags::bitflags! {
330    /// Flags for histogram plots
331    pub struct HistogramFlags: u32 {
332        const NONE = sys::ImPlotHistogramFlags_None as u32;
333        const HORIZONTAL = sys::ImPlotHistogramFlags_Horizontal as u32;
334        const CUMULATIVE = sys::ImPlotHistogramFlags_Cumulative as u32;
335        const DENSITY = sys::ImPlotHistogramFlags_Density as u32;
336        const NO_OUTLIERS = sys::ImPlotHistogramFlags_NoOutliers as u32;
337        const COL_MAJOR = sys::ImPlotHistogramFlags_ColMajor as u32;
338    }
339}
340
341bitflags::bitflags! {
342    /// Flags for pie chart plots
343    pub struct PieChartFlags: u32 {
344        const NONE = sys::ImPlotPieChartFlags_None as u32;
345        const NORMALIZE = sys::ImPlotPieChartFlags_Normalize as u32;
346        const IGNORE_HIDDEN = sys::ImPlotPieChartFlags_IgnoreHidden as u32;
347        const EXPLODING = sys::ImPlotPieChartFlags_Exploding as u32;
348        const NO_SLICE_BORDER = sys::ImPlotPieChartFlags_NoSliceBorder as u32;
349    }
350}
351
352bitflags::bitflags! {
353    /// Flags for line plots
354    pub struct LineFlags: u32 {
355        const NONE = sys::ImPlotLineFlags_None as u32;
356        const SEGMENTS = sys::ImPlotLineFlags_Segments as u32;
357        const LOOP = sys::ImPlotLineFlags_Loop as u32;
358        const SKIP_NAN = sys::ImPlotLineFlags_SkipNaN as u32;
359        const NO_CLIP = sys::ImPlotLineFlags_NoClip as u32;
360        const SHADED = sys::ImPlotLineFlags_Shaded as u32;
361    }
362}
363
364bitflags::bitflags! {
365    /// Flags for polygon plots
366    pub struct PolygonFlags: u32 {
367        const NONE = sys::ImPlotPolygonFlags_None as u32;
368        const CONCAVE = sys::ImPlotPolygonFlags_Concave as u32;
369    }
370}
371
372bitflags::bitflags! {
373    /// Flags for scatter plots
374    pub struct ScatterFlags: u32 {
375        const NONE = sys::ImPlotScatterFlags_None as u32;
376        const NO_CLIP = sys::ImPlotScatterFlags_NoClip as u32;
377    }
378}
379
380bitflags::bitflags! {
381    /// Flags for bar plots
382    pub struct BarsFlags: u32 {
383        const NONE = sys::ImPlotBarsFlags_None as u32;
384        const HORIZONTAL = sys::ImPlotBarsFlags_Horizontal as u32;
385    }
386}
387
388bitflags::bitflags! {
389    /// Flags for shaded plots
390    pub struct ShadedFlags: u32 {
391        const NONE = sys::ImPlotShadedFlags_None as u32;
392    }
393}
394
395bitflags::bitflags! {
396    /// Flags for stem plots
397    pub struct StemsFlags: u32 {
398        const NONE = sys::ImPlotStemsFlags_None as u32;
399        const HORIZONTAL = sys::ImPlotStemsFlags_Horizontal as u32;
400    }
401}
402
403bitflags::bitflags! {
404    /// Flags for error bar plots
405    pub struct ErrorBarsFlags: u32 {
406        const NONE = sys::ImPlotErrorBarsFlags_None as u32;
407        const HORIZONTAL = sys::ImPlotErrorBarsFlags_Horizontal as u32;
408    }
409}
410
411bitflags::bitflags! {
412    /// Flags for stairs plots
413    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
414    pub struct StairsFlags: u32 {
415        const NONE = sys::ImPlotStairsFlags_None as u32;
416        const PRE_STEP = sys::ImPlotStairsFlags_PreStep as u32;
417        const SHADED = sys::ImPlotStairsFlags_Shaded as u32;
418    }
419}
420
421bitflags::bitflags! {
422    /// Flags for bar groups plots
423    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
424    pub struct BarGroupsFlags: u32 {
425        const NONE = sys::ImPlotBarGroupsFlags_None as u32;
426        const HORIZONTAL = sys::ImPlotBarGroupsFlags_Horizontal as u32;
427        const STACKED = sys::ImPlotBarGroupsFlags_Stacked as u32;
428    }
429}
430
431bitflags::bitflags! {
432    /// Flags for digital plots
433    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
434    pub struct DigitalFlags: u32 {
435        const NONE = sys::ImPlotDigitalFlags_None as u32;
436    }
437}
438
439bitflags::bitflags! {
440    /// Flags for text plots
441    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
442    pub struct TextFlags: u32 {
443        const NONE = sys::ImPlotTextFlags_None as u32;
444        const VERTICAL = sys::ImPlotTextFlags_Vertical as u32;
445    }
446}
447
448bitflags::bitflags! {
449    /// Flags for dummy plots
450    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
451    pub struct DummyFlags: u32 {
452        const NONE = sys::ImPlotDummyFlags_None as u32;
453    }
454}
455
456bitflags::bitflags! {
457    /// Flags for drag tools (points/lines)
458    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
459    pub struct DragToolFlags: u32 {
460        const NONE = sys::ImPlotDragToolFlags_None as u32;
461        const NO_CURSORS = sys::ImPlotDragToolFlags_NoCursors as u32;
462        const NO_FIT = sys::ImPlotDragToolFlags_NoFit as u32;
463        const NO_INPUTS = sys::ImPlotDragToolFlags_NoInputs as u32;
464        const DELAYED = sys::ImPlotDragToolFlags_Delayed as u32;
465    }
466}
467
468bitflags::bitflags! {
469    /// Flags for infinite lines plots
470    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
471    pub struct InfLinesFlags: u32 {
472        const NONE = sys::ImPlotInfLinesFlags_None as u32;
473        const HORIZONTAL = sys::ImPlotInfLinesFlags_Horizontal as u32;
474    }
475}
476
477bitflags::bitflags! {
478    /// Flags for image plots
479    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
480    pub struct ImageFlags: u32 {
481        const NONE = sys::ImPlotImageFlags_None as u32;
482    }
483}
484
485bitflags::bitflags! {
486    /// Axis flags matching ImPlotAxisFlags_ (see cimplot.h)
487    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
488    pub struct AxisFlags: u32 {
489        const NONE           = sys::ImPlotAxisFlags_None as u32;
490        const NO_LABEL       = sys::ImPlotAxisFlags_NoLabel as u32;
491        const NO_GRID_LINES  = sys::ImPlotAxisFlags_NoGridLines as u32;
492        const NO_TICK_MARKS  = sys::ImPlotAxisFlags_NoTickMarks as u32;
493        const NO_TICK_LABELS = sys::ImPlotAxisFlags_NoTickLabels as u32;
494        const NO_INITIAL_FIT = sys::ImPlotAxisFlags_NoInitialFit as u32;
495        const NO_MENUS       = sys::ImPlotAxisFlags_NoMenus as u32;
496        const NO_SIDE_SWITCH = sys::ImPlotAxisFlags_NoSideSwitch as u32;
497        const NO_HIGHLIGHT   = sys::ImPlotAxisFlags_NoHighlight as u32;
498        const OPPOSITE       = sys::ImPlotAxisFlags_Opposite as u32;
499        const FOREGROUND     = sys::ImPlotAxisFlags_Foreground as u32;
500        const INVERT         = sys::ImPlotAxisFlags_Invert as u32;
501        const AUTO_FIT       = sys::ImPlotAxisFlags_AutoFit as u32;
502        const RANGE_FIT      = sys::ImPlotAxisFlags_RangeFit as u32;
503        const PAN_STRETCH    = sys::ImPlotAxisFlags_PanStretch as u32;
504        const LOCK_MIN       = sys::ImPlotAxisFlags_LockMin as u32;
505        const LOCK_MAX       = sys::ImPlotAxisFlags_LockMax as u32;
506    }
507}
508
509/// Plot condition (setup/next) matching ImPlotCond (ImGuiCond)
510#[derive(Clone, Copy, Debug, PartialEq, Eq)]
511#[repr(i32)]
512pub enum PlotCond {
513    None = 0,
514    Always = 1,
515    Once = 2,
516}
517
518// Re-export all plot types for convenience
519pub use plots::*;
520
521// Re-export advanced features (explicit to avoid AxisFlags name clash)
522pub use advanced::{
523    LegendFlags, LegendLocation, LegendManager, LegendToken, MultiAxisPlot, MultiAxisToken,
524    SubplotFlags, SubplotGrid, SubplotToken, YAxisConfig,
525};