Skip to main content

dear_imgui_rs/widget/
plot.rs

1//! Basic plots
2//!
3//! Simple line/histogram plot helpers built on top of Dear ImGui. For more
4//! advanced charts, consider using the optional implot bindings.
5//!
6#![allow(
7    clippy::cast_possible_truncation,
8    clippy::cast_sign_loss,
9    clippy::as_conversions
10)]
11use crate::internal::plot_value_count_i32;
12use crate::sys;
13use crate::ui::Ui;
14use std::borrow::Cow;
15
16/// # Plot Widgets
17impl Ui {
18    /// Creates a plot lines widget
19    #[doc(alias = "PlotLines")]
20    pub fn plot_lines(&self, label: impl AsRef<str>, values: &[f32]) {
21        self.plot_lines_config(label.as_ref(), values).build()
22    }
23
24    /// Creates a plot histogram widget
25    #[doc(alias = "PlotHistogram")]
26    pub fn plot_histogram(&self, label: impl AsRef<str>, values: &[f32]) {
27        self.plot_histogram_config(label.as_ref(), values).build()
28    }
29
30    /// Creates a plot lines builder
31    pub fn plot_lines_config<'ui, 'p>(
32        &'ui self,
33        label: impl Into<Cow<'ui, str>>,
34        values: &'p [f32],
35    ) -> PlotLines<'ui, 'p> {
36        PlotLines::new(self, label, values)
37    }
38
39    /// Creates a plot histogram builder
40    pub fn plot_histogram_config<'ui, 'p>(
41        &'ui self,
42        label: impl Into<Cow<'ui, str>>,
43        values: &'p [f32],
44    ) -> PlotHistogram<'ui, 'p> {
45        PlotHistogram::new(self, label, values)
46    }
47}
48
49/// Builder for a plot lines widget
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
51pub struct PlotValueOffset(usize);
52
53impl PlotValueOffset {
54    /// First value in the slice.
55    pub const ZERO: Self = Self(0);
56
57    /// Create a value offset from a Rust slice index.
58    #[inline]
59    pub const fn new(offset: usize) -> Self {
60        Self(offset)
61    }
62
63    #[inline]
64    pub(crate) fn into_i32(self, caller: &str, value_count: i32) -> i32 {
65        let offset = i32::try_from(self.0).unwrap_or_else(|_| {
66            panic!("{caller} values_offset supports at most i32::MAX");
67        });
68        assert!(
69            value_count == 0 || offset < value_count,
70            "{caller} values_offset must be less than values.len()"
71        );
72        offset
73    }
74}
75
76impl From<usize> for PlotValueOffset {
77    fn from(offset: usize) -> Self {
78        Self::new(offset)
79    }
80}
81
82/// Builder for a plot lines widget
83#[derive(Debug)]
84#[must_use]
85pub struct PlotLines<'ui, 'p> {
86    ui: &'ui Ui,
87    label: Cow<'ui, str>,
88    values: &'p [f32],
89    values_offset: PlotValueOffset,
90    overlay_text: Option<Cow<'ui, str>>,
91    scale_min: f32,
92    scale_max: f32,
93    graph_size: [f32; 2],
94}
95
96impl<'ui, 'p> PlotLines<'ui, 'p> {
97    /// Creates a new plot lines builder
98    pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>, values: &'p [f32]) -> Self {
99        Self {
100            ui,
101            label: label.into(),
102            values,
103            values_offset: PlotValueOffset::ZERO,
104            overlay_text: None,
105            scale_min: f32::MAX,
106            scale_max: f32::MAX,
107            graph_size: [0.0, 0.0],
108        }
109    }
110
111    /// Sets the offset for the values array
112    pub fn values_offset(mut self, offset: impl Into<PlotValueOffset>) -> Self {
113        self.values_offset = offset.into();
114        self
115    }
116
117    /// Sets the overlay text
118    pub fn overlay_text(mut self, text: impl Into<Cow<'ui, str>>) -> Self {
119        self.overlay_text = Some(text.into());
120        self
121    }
122
123    /// Sets the scale minimum value
124    pub fn scale_min(mut self, scale_min: f32) -> Self {
125        self.scale_min = scale_min;
126        self
127    }
128
129    /// Sets the scale maximum value
130    pub fn scale_max(mut self, scale_max: f32) -> Self {
131        self.scale_max = scale_max;
132        self
133    }
134
135    /// Sets the graph size
136    pub fn graph_size(mut self, size: [f32; 2]) -> Self {
137        self.graph_size = size;
138        self
139    }
140
141    /// Builds the plot lines widget
142    pub fn build(self) {
143        let count = plot_value_count_i32("PlotLines::build()", self.values.len());
144        let values_offset = self.values_offset.into_i32("PlotLines::build()", count);
145        let (label_ptr, overlay_ptr) = self
146            .ui
147            .scratch_txt_with_opt(self.label.as_ref(), self.overlay_text.as_deref());
148        let graph_size_vec: sys::ImVec2 = self.graph_size.into();
149
150        unsafe {
151            sys::igPlotLines_FloatPtr(
152                label_ptr,
153                self.values.as_ptr(),
154                count,
155                values_offset,
156                overlay_ptr,
157                self.scale_min,
158                self.scale_max,
159                graph_size_vec,
160                std::mem::size_of::<f32>() as i32,
161            );
162        }
163    }
164}
165
166/// Builder for a plot histogram widget
167#[derive(Debug)]
168#[must_use]
169pub struct PlotHistogram<'ui, 'p> {
170    ui: &'ui Ui,
171    label: Cow<'ui, str>,
172    values: &'p [f32],
173    values_offset: PlotValueOffset,
174    overlay_text: Option<Cow<'ui, str>>,
175    scale_min: f32,
176    scale_max: f32,
177    graph_size: [f32; 2],
178}
179
180impl<'ui, 'p> PlotHistogram<'ui, 'p> {
181    /// Creates a new plot histogram builder
182    pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>, values: &'p [f32]) -> Self {
183        Self {
184            ui,
185            label: label.into(),
186            values,
187            values_offset: PlotValueOffset::ZERO,
188            overlay_text: None,
189            scale_min: f32::MAX,
190            scale_max: f32::MAX,
191            graph_size: [0.0, 0.0],
192        }
193    }
194
195    /// Sets the offset for the values array
196    pub fn values_offset(mut self, offset: impl Into<PlotValueOffset>) -> Self {
197        self.values_offset = offset.into();
198        self
199    }
200
201    /// Sets the overlay text
202    pub fn overlay_text(mut self, text: impl Into<Cow<'ui, str>>) -> Self {
203        self.overlay_text = Some(text.into());
204        self
205    }
206
207    /// Sets the scale minimum value
208    pub fn scale_min(mut self, scale_min: f32) -> Self {
209        self.scale_min = scale_min;
210        self
211    }
212
213    /// Sets the scale maximum value
214    pub fn scale_max(mut self, scale_max: f32) -> Self {
215        self.scale_max = scale_max;
216        self
217    }
218
219    /// Sets the graph size
220    pub fn graph_size(mut self, size: [f32; 2]) -> Self {
221        self.graph_size = size;
222        self
223    }
224
225    /// Builds the plot histogram widget
226    pub fn build(self) {
227        let count = plot_value_count_i32("PlotHistogram::build()", self.values.len());
228        let values_offset = self.values_offset.into_i32("PlotHistogram::build()", count);
229        let (label_ptr, overlay_ptr) = self
230            .ui
231            .scratch_txt_with_opt(self.label.as_ref(), self.overlay_text.as_deref());
232        let graph_size_vec: sys::ImVec2 = self.graph_size.into();
233
234        unsafe {
235            sys::igPlotHistogram_FloatPtr(
236                label_ptr,
237                self.values.as_ptr(),
238                count,
239                values_offset,
240                overlay_ptr,
241                self.scale_min,
242                self.scale_max,
243                graph_size_vec,
244                std::mem::size_of::<f32>() as i32,
245            );
246        }
247    }
248}