1use super::{
4 PlotData, PlotDataLayout, PlotDataOffset, PlotDataStride, PlotError, PlotItemStyle,
5 plot_spec_with_style, validate_data_lengths, with_plot_str_or_empty,
6};
7use crate::{DigitalFlags, ItemFlags, sys};
8
9pub struct DigitalPlot<'a> {
14 label: &'a str,
15 x_data: &'a [f64],
16 y_data: &'a [f64],
17 style: PlotItemStyle,
18 flags: DigitalFlags,
19 item_flags: ItemFlags,
20 layout: PlotDataLayout,
21}
22
23impl<'a> super::PlotItemStyled for DigitalPlot<'a> {
24 fn style_mut(&mut self) -> &mut PlotItemStyle {
25 &mut self.style
26 }
27}
28
29impl<'a> DigitalPlot<'a> {
30 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
32 Self {
33 label,
34 x_data,
35 y_data,
36 style: PlotItemStyle::default(),
37 flags: DigitalFlags::NONE,
38 item_flags: ItemFlags::NONE,
39 layout: PlotDataLayout::DEFAULT,
40 }
41 }
42
43 pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
45 self.flags = flags;
46 self
47 }
48
49 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
51 self.style = style;
52 self
53 }
54
55 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
57 self.item_flags = flags;
58 self
59 }
60
61 pub fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
63 self.layout = layout;
64 self
65 }
66
67 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
69 self.layout = self.layout.with_offset(offset);
70 self
71 }
72
73 pub fn with_stride(mut self, stride: PlotDataStride) -> Self {
75 self.layout = self.layout.with_stride(stride);
76 self
77 }
78
79 pub fn validate(&self) -> Result<(), PlotError> {
81 validate_data_lengths(self.x_data, self.y_data)?;
82
83 Ok(())
86 }
87
88 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
90 let Ok(count) = i32::try_from(self.x_data.len()) else {
91 return;
92 };
93 let _guard = plot_ui.bind();
94 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
95 let spec = plot_spec_with_style(
96 self.style,
97 self.flags.bits() | self.item_flags.bits(),
98 self.layout,
99 );
100 sys::ImPlot_PlotDigital_doublePtr(
101 label_ptr,
102 self.x_data.as_ptr(),
103 self.y_data.as_ptr(),
104 count,
105 spec,
106 );
107 })
108 }
109}
110
111impl<'a> PlotData for DigitalPlot<'a> {
112 fn label(&self) -> &str {
113 self.label
114 }
115
116 fn data_len(&self) -> usize {
117 self.x_data.len().min(self.y_data.len())
118 }
119}
120
121pub struct DigitalPlotF32<'a> {
123 label: &'a str,
124 x_data: &'a [f32],
125 y_data: &'a [f32],
126 style: PlotItemStyle,
127 flags: DigitalFlags,
128 item_flags: ItemFlags,
129}
130
131impl<'a> super::PlotItemStyled for DigitalPlotF32<'a> {
132 fn style_mut(&mut self) -> &mut PlotItemStyle {
133 &mut self.style
134 }
135}
136
137impl<'a> DigitalPlotF32<'a> {
138 pub fn new(label: &'a str, x_data: &'a [f32], y_data: &'a [f32]) -> Self {
140 Self {
141 label,
142 x_data,
143 y_data,
144 style: PlotItemStyle::default(),
145 flags: DigitalFlags::NONE,
146 item_flags: ItemFlags::NONE,
147 }
148 }
149
150 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
152 self.style = style;
153 self
154 }
155
156 pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
158 self.flags = flags;
159 self
160 }
161
162 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
164 self.item_flags = flags;
165 self
166 }
167
168 pub fn validate(&self) -> Result<(), PlotError> {
170 if self.x_data.len() != self.y_data.len() {
171 return Err(PlotError::DataLengthMismatch {
172 x_len: self.x_data.len(),
173 y_len: self.y_data.len(),
174 });
175 }
176 if self.x_data.is_empty() {
177 return Err(PlotError::EmptyData);
178 }
179 Ok(())
180 }
181
182 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
184 let Ok(count) = i32::try_from(self.x_data.len()) else {
185 return;
186 };
187 let _guard = plot_ui.bind();
188 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
189 let spec = plot_spec_with_style(
190 self.style,
191 self.flags.bits() | self.item_flags.bits(),
192 PlotDataLayout::DEFAULT,
193 );
194 sys::ImPlot_PlotDigital_FloatPtr(
195 label_ptr,
196 self.x_data.as_ptr(),
197 self.y_data.as_ptr(),
198 count,
199 spec,
200 );
201 })
202 }
203}
204
205impl<'a> PlotData for DigitalPlotF32<'a> {
206 fn label(&self) -> &str {
207 self.label
208 }
209
210 fn data_len(&self) -> usize {
211 self.x_data.len().min(self.y_data.len())
212 }
213}
214
215pub struct SimpleDigitalPlot<'a> {
217 label: &'a str,
218 y_data: &'a [f64],
219 style: PlotItemStyle,
220 flags: DigitalFlags,
221 item_flags: ItemFlags,
222 x_scale: f64,
223 x_start: f64,
224}
225
226impl<'a> super::PlotItemStyled for SimpleDigitalPlot<'a> {
227 fn style_mut(&mut self) -> &mut PlotItemStyle {
228 &mut self.style
229 }
230}
231
232impl<'a> SimpleDigitalPlot<'a> {
233 pub fn new(label: &'a str, y_data: &'a [f64]) -> Self {
235 Self {
236 label,
237 y_data,
238 style: PlotItemStyle::default(),
239 flags: DigitalFlags::NONE,
240 item_flags: ItemFlags::NONE,
241 x_scale: 1.0,
242 x_start: 0.0,
243 }
244 }
245
246 pub fn with_x_scale(mut self, x_scale: f64) -> Self {
248 self.x_scale = x_scale;
249 self
250 }
251
252 pub fn with_x_start(mut self, x_start: f64) -> Self {
254 self.x_start = x_start;
255 self
256 }
257
258 pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
260 self.flags = flags;
261 self
262 }
263
264 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
266 self.style = style;
267 self
268 }
269
270 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
272 self.item_flags = flags;
273 self
274 }
275
276 pub fn validate(&self) -> Result<(), PlotError> {
278 if self.y_data.is_empty() {
279 return Err(PlotError::EmptyData);
280 }
281 Ok(())
282 }
283
284 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
286 let Ok(count) = i32::try_from(self.y_data.len()) else {
287 return;
288 };
289 let x_data: Vec<f64> = (0..self.y_data.len())
291 .map(|i| self.x_start + i as f64 * self.x_scale)
292 .collect();
293
294 let _guard = plot_ui.bind();
295 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
296 let spec = plot_spec_with_style(
297 self.style,
298 self.flags.bits() | self.item_flags.bits(),
299 PlotDataLayout::DEFAULT,
300 );
301 sys::ImPlot_PlotDigital_doublePtr(
302 label_ptr,
303 x_data.as_ptr(),
304 self.y_data.as_ptr(),
305 count,
306 spec,
307 );
308 })
309 }
310}
311
312impl<'a> PlotData for SimpleDigitalPlot<'a> {
313 fn label(&self) -> &str {
314 self.label
315 }
316
317 fn data_len(&self) -> usize {
318 self.y_data.len()
319 }
320}
321
322pub struct BooleanDigitalPlot<'a> {
324 label: &'a str,
325 x_data: &'a [f64],
326 y_data: &'a [bool],
327 style: PlotItemStyle,
328 flags: DigitalFlags,
329 item_flags: ItemFlags,
330}
331
332impl<'a> super::PlotItemStyled for BooleanDigitalPlot<'a> {
333 fn style_mut(&mut self) -> &mut PlotItemStyle {
334 &mut self.style
335 }
336}
337
338impl<'a> BooleanDigitalPlot<'a> {
339 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [bool]) -> Self {
341 Self {
342 label,
343 x_data,
344 y_data,
345 style: PlotItemStyle::default(),
346 flags: DigitalFlags::NONE,
347 item_flags: ItemFlags::NONE,
348 }
349 }
350
351 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
353 self.style = style;
354 self
355 }
356
357 pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
359 self.flags = flags;
360 self
361 }
362
363 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
365 self.item_flags = flags;
366 self
367 }
368
369 pub fn validate(&self) -> Result<(), PlotError> {
371 if self.x_data.len() != self.y_data.len() {
372 return Err(PlotError::DataLengthMismatch {
373 x_len: self.x_data.len(),
374 y_len: self.y_data.len(),
375 });
376 }
377 if self.x_data.is_empty() {
378 return Err(PlotError::EmptyData);
379 }
380 Ok(())
381 }
382
383 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
385 let Ok(count) = i32::try_from(self.x_data.len()) else {
386 return;
387 };
388 let y_data_f64: Vec<f64> = self
390 .y_data
391 .iter()
392 .map(|&b| if b { 1.0 } else { 0.0 })
393 .collect();
394
395 let _guard = plot_ui.bind();
396 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
397 let spec = plot_spec_with_style(
398 self.style,
399 self.flags.bits() | self.item_flags.bits(),
400 PlotDataLayout::DEFAULT,
401 );
402 sys::ImPlot_PlotDigital_doublePtr(
403 label_ptr,
404 self.x_data.as_ptr(),
405 y_data_f64.as_ptr(),
406 count,
407 spec,
408 );
409 })
410 }
411}
412
413impl<'a> PlotData for BooleanDigitalPlot<'a> {
414 fn label(&self) -> &str {
415 self.label
416 }
417
418 fn data_len(&self) -> usize {
419 self.x_data.len().min(self.y_data.len())
420 }
421}