1use super::{
4 Plot, PlotDataLayout, PlotDataOffset, PlotDataStride, PlotError, PlotItemStyle,
5 plot_spec_with_style, validate_data_lengths, with_plot_str_or_empty,
6};
7use crate::{ItemFlags, ShadedFlags, sys};
8
9pub struct ShadedPlot<'a> {
11 label: &'a str,
12 x_data: &'a [f64],
13 y_data: &'a [f64],
14 style: PlotItemStyle,
15 y_ref: f64,
16 flags: ShadedFlags,
17 item_flags: ItemFlags,
18 layout: PlotDataLayout,
19}
20
21impl<'a> super::PlotItemStyled for ShadedPlot<'a> {
22 fn style_mut(&mut self) -> &mut PlotItemStyle {
23 &mut self.style
24 }
25}
26
27impl<'a> ShadedPlot<'a> {
28 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
30 Self {
31 label,
32 x_data,
33 y_data,
34 style: PlotItemStyle::default(),
35 y_ref: 0.0, flags: ShadedFlags::NONE,
37 item_flags: ItemFlags::NONE,
38 layout: PlotDataLayout::DEFAULT,
39 }
40 }
41
42 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
45 self.y_ref = y_ref;
46 self
47 }
48
49 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
51 self.flags = flags;
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 unsafe fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
68 self.layout = layout;
69 self
70 }
71
72 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
74 self.layout = self.layout.with_offset(offset);
75 self
76 }
77
78 pub unsafe fn with_stride(mut self, stride: PlotDataStride) -> Self {
85 self.layout = self.layout.with_stride(stride);
86 self
87 }
88
89 pub fn validate(&self) -> Result<(), PlotError> {
91 validate_data_lengths(self.x_data, self.y_data)
92 }
93}
94
95impl<'a> Plot for ShadedPlot<'a> {
96 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
97 if self.validate().is_err() {
98 return;
99 }
100 let Ok(count) = i32::try_from(self.x_data.len()) else {
101 return;
102 };
103 plot_ui.with_bound_context(|| {
104 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
105 let spec = plot_spec_with_style(
106 self.style,
107 self.flags.bits() | self.item_flags.bits(),
108 self.layout,
109 );
110 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
111 label_ptr,
112 self.x_data.as_ptr(),
113 self.y_data.as_ptr(),
114 count,
115 self.y_ref,
116 spec,
117 );
118 })
119 })
120 }
121
122 fn label(&self) -> &str {
123 self.label
124 }
125}
126
127pub struct ShadedBetweenPlot<'a> {
129 label: &'a str,
130 x_data: &'a [f64],
131 y1_data: &'a [f64],
132 y2_data: &'a [f64],
133 style: PlotItemStyle,
134 flags: ShadedFlags,
135 item_flags: ItemFlags,
136 layout: PlotDataLayout,
137}
138
139impl<'a> super::PlotItemStyled for ShadedBetweenPlot<'a> {
140 fn style_mut(&mut self) -> &mut PlotItemStyle {
141 &mut self.style
142 }
143}
144
145impl<'a> ShadedBetweenPlot<'a> {
146 pub fn new(label: &'a str, x_data: &'a [f64], y1_data: &'a [f64], y2_data: &'a [f64]) -> Self {
148 Self {
149 label,
150 x_data,
151 y1_data,
152 y2_data,
153 style: PlotItemStyle::default(),
154 flags: ShadedFlags::NONE,
155 item_flags: ItemFlags::NONE,
156 layout: PlotDataLayout::DEFAULT,
157 }
158 }
159
160 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
162 self.flags = flags;
163 self
164 }
165
166 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
168 self.item_flags = flags;
169 self
170 }
171
172 pub unsafe fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
179 self.layout = layout;
180 self
181 }
182
183 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
185 self.layout = self.layout.with_offset(offset);
186 self
187 }
188
189 pub unsafe fn with_stride(mut self, stride: PlotDataStride) -> Self {
196 self.layout = self.layout.with_stride(stride);
197 self
198 }
199
200 pub fn validate(&self) -> Result<(), PlotError> {
202 validate_data_lengths(self.x_data, self.y1_data)?;
203 validate_data_lengths(self.x_data, self.y2_data)?;
204 Ok(())
205 }
206}
207
208impl<'a> Plot for ShadedBetweenPlot<'a> {
209 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
210 if self.validate().is_err() {
211 return;
212 }
213 let Ok(count) = i32::try_from(self.x_data.len()) else {
214 return;
215 };
216
217 plot_ui.with_bound_context(|| {
218 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
219 let spec = plot_spec_with_style(
220 self.style,
221 self.flags.bits() | self.item_flags.bits(),
222 self.layout,
223 );
224 sys::ImPlot_PlotShaded_doublePtrdoublePtrdoublePtr(
225 label_ptr,
226 self.x_data.as_ptr(),
227 self.y1_data.as_ptr(),
228 self.y2_data.as_ptr(),
229 count,
230 spec,
231 );
232 })
233 })
234 }
235
236 fn label(&self) -> &str {
237 self.label
238 }
239}
240
241pub struct SimpleShadedPlot<'a> {
243 label: &'a str,
244 values: &'a [f64],
245 style: PlotItemStyle,
246 y_ref: f64,
247 flags: ShadedFlags,
248 item_flags: ItemFlags,
249 x_scale: f64,
250 x_start: f64,
251}
252
253impl<'a> super::PlotItemStyled for SimpleShadedPlot<'a> {
254 fn style_mut(&mut self) -> &mut PlotItemStyle {
255 &mut self.style
256 }
257}
258
259impl<'a> SimpleShadedPlot<'a> {
260 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
262 Self {
263 label,
264 values,
265 style: PlotItemStyle::default(),
266 y_ref: 0.0,
267 flags: ShadedFlags::NONE,
268 item_flags: ItemFlags::NONE,
269 x_scale: 1.0,
270 x_start: 0.0,
271 }
272 }
273
274 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
276 self.y_ref = y_ref;
277 self
278 }
279
280 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
282 self.flags = flags;
283 self
284 }
285
286 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
288 self.item_flags = flags;
289 self
290 }
291
292 pub fn with_x_scale(mut self, scale: f64) -> Self {
294 self.x_scale = scale;
295 self
296 }
297
298 pub fn with_x_start(mut self, start: f64) -> Self {
300 self.x_start = start;
301 self
302 }
303}
304
305impl<'a> Plot for SimpleShadedPlot<'a> {
306 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
307 if self.values.is_empty() {
308 return;
309 }
310 let Ok(count) = i32::try_from(self.values.len()) else {
311 return;
312 };
313
314 plot_ui.with_bound_context(|| {
315 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
316 let spec = plot_spec_with_style(
317 self.style,
318 self.flags.bits() | self.item_flags.bits(),
319 PlotDataLayout::DEFAULT,
320 );
321 sys::ImPlot_PlotShaded_doublePtrInt(
322 label_ptr,
323 self.values.as_ptr(),
324 count,
325 self.y_ref,
326 self.x_scale,
327 self.x_start,
328 spec,
329 );
330 })
331 })
332 }
333
334 fn label(&self) -> &str {
335 self.label
336 }
337}
338
339impl<'ui> crate::PlotUi<'ui> {
341 pub fn shaded_plot(
343 &self,
344 label: &str,
345 x_data: &[f64],
346 y_data: &[f64],
347 ) -> Result<(), PlotError> {
348 let plot = ShadedPlot::new(label, x_data, y_data);
349 plot.validate()?;
350 plot.plot(self);
351 Ok(())
352 }
353
354 pub fn shaded_plot_with_ref(
356 &self,
357 label: &str,
358 x_data: &[f64],
359 y_data: &[f64],
360 y_ref: f64,
361 ) -> Result<(), PlotError> {
362 let plot = ShadedPlot::new(label, x_data, y_data).with_y_ref(y_ref);
363 plot.validate()?;
364 plot.plot(self);
365 Ok(())
366 }
367
368 pub fn shaded_between_plot(
370 &self,
371 label: &str,
372 x_data: &[f64],
373 y1_data: &[f64],
374 y2_data: &[f64],
375 ) -> Result<(), PlotError> {
376 let plot = ShadedBetweenPlot::new(label, x_data, y1_data, y2_data);
377 plot.validate()?;
378 plot.plot(self);
379 Ok(())
380 }
381
382 pub fn simple_shaded_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
384 if values.is_empty() {
385 return Err(PlotError::EmptyData);
386 }
387 let plot = SimpleShadedPlot::new(label, values);
388 plot.plot(self);
389 Ok(())
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn test_shaded_plot_creation() {
399 let x_data = [1.0, 2.0, 3.0, 4.0];
400 let y_data = [1.0, 4.0, 2.0, 3.0];
401
402 let plot = ShadedPlot::new("test", &x_data, &y_data);
403 assert_eq!(plot.label(), "test");
404 assert!(plot.validate().is_ok());
405 }
406
407 #[test]
408 fn test_shaded_plot_validation() {
409 let x_data = [1.0, 2.0, 3.0];
410 let y_data = [1.0, 4.0]; let plot = ShadedPlot::new("test", &x_data, &y_data);
413 assert!(plot.validate().is_err());
414 }
415
416 #[test]
417 fn test_shaded_between_plot() {
418 let x_data = [1.0, 2.0, 3.0, 4.0];
419 let y1_data = [1.0, 2.0, 3.0, 4.0];
420 let y2_data = [2.0, 3.0, 4.0, 5.0];
421
422 let plot = ShadedBetweenPlot::new("test", &x_data, &y1_data, &y2_data);
423 assert_eq!(plot.label(), "test");
424 assert!(plot.validate().is_ok());
425 }
426
427 #[test]
428 fn test_simple_shaded_plot_flags() {
429 let values = [1.0, 2.0, 3.0, 4.0];
430 let plot = SimpleShadedPlot::new("test", &values).with_item_flags(ItemFlags::NO_FIT);
431 assert_eq!(plot.label(), "test");
432 assert_eq!(plot.item_flags, ItemFlags::NO_FIT);
433 }
434}