1use super::{
4 Plot, PlotError, PlotItemStyle, plot_spec_with_style, validate_data_lengths,
5 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 offset: i32,
19 stride: i32,
20}
21
22impl<'a> super::PlotItemStyled for ShadedPlot<'a> {
23 fn style_mut(&mut self) -> &mut PlotItemStyle {
24 &mut self.style
25 }
26}
27
28impl<'a> ShadedPlot<'a> {
29 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
31 Self {
32 label,
33 x_data,
34 y_data,
35 style: PlotItemStyle::default(),
36 y_ref: 0.0, flags: ShadedFlags::NONE,
38 item_flags: ItemFlags::NONE,
39 offset: 0,
40 stride: std::mem::size_of::<f64>() as i32,
41 }
42 }
43
44 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
47 self.y_ref = y_ref;
48 self
49 }
50
51 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
53 self.flags = flags;
54 self
55 }
56
57 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
59 self.item_flags = flags;
60 self
61 }
62
63 pub fn with_offset(mut self, offset: i32) -> Self {
65 self.offset = offset;
66 self
67 }
68
69 pub fn with_stride(mut self, stride: i32) -> Self {
71 self.stride = stride;
72 self
73 }
74
75 pub fn validate(&self) -> Result<(), PlotError> {
77 validate_data_lengths(self.x_data, self.y_data)
78 }
79}
80
81impl<'a> Plot for ShadedPlot<'a> {
82 fn plot(&self) {
83 if self.validate().is_err() {
84 return;
85 }
86 let Ok(count) = i32::try_from(self.x_data.len()) else {
87 return;
88 };
89 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
90 let spec = plot_spec_with_style(
91 self.style,
92 self.flags.bits() | self.item_flags.bits(),
93 self.offset,
94 self.stride,
95 );
96 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
97 label_ptr,
98 self.x_data.as_ptr(),
99 self.y_data.as_ptr(),
100 count,
101 self.y_ref,
102 spec,
103 );
104 })
105 }
106
107 fn label(&self) -> &str {
108 self.label
109 }
110}
111
112pub struct ShadedBetweenPlot<'a> {
114 label: &'a str,
115 x_data: &'a [f64],
116 y1_data: &'a [f64],
117 y2_data: &'a [f64],
118 style: PlotItemStyle,
119 flags: ShadedFlags,
120 item_flags: ItemFlags,
121 offset: i32,
122 stride: i32,
123}
124
125impl<'a> super::PlotItemStyled for ShadedBetweenPlot<'a> {
126 fn style_mut(&mut self) -> &mut PlotItemStyle {
127 &mut self.style
128 }
129}
130
131impl<'a> ShadedBetweenPlot<'a> {
132 pub fn new(label: &'a str, x_data: &'a [f64], y1_data: &'a [f64], y2_data: &'a [f64]) -> Self {
134 Self {
135 label,
136 x_data,
137 y1_data,
138 y2_data,
139 style: PlotItemStyle::default(),
140 flags: ShadedFlags::NONE,
141 item_flags: ItemFlags::NONE,
142 offset: 0,
143 stride: crate::IMPLOT_AUTO,
144 }
145 }
146
147 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
149 self.flags = flags;
150 self
151 }
152
153 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
155 self.item_flags = flags;
156 self
157 }
158
159 pub fn with_offset(mut self, offset: i32) -> Self {
161 self.offset = offset;
162 self
163 }
164
165 pub fn with_stride(mut self, stride: i32) -> Self {
167 self.stride = stride;
168 self
169 }
170
171 pub fn validate(&self) -> Result<(), PlotError> {
173 validate_data_lengths(self.x_data, self.y1_data)?;
174 validate_data_lengths(self.x_data, self.y2_data)?;
175 Ok(())
176 }
177}
178
179impl<'a> Plot for ShadedBetweenPlot<'a> {
180 fn plot(&self) {
181 if self.validate().is_err() {
182 return;
183 }
184 let Ok(count) = i32::try_from(self.x_data.len()) else {
185 return;
186 };
187
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 self.offset,
193 self.stride,
194 );
195 sys::ImPlot_PlotShaded_doublePtrdoublePtrdoublePtr(
196 label_ptr,
197 self.x_data.as_ptr(),
198 self.y1_data.as_ptr(),
199 self.y2_data.as_ptr(),
200 count,
201 spec,
202 );
203 })
204 }
205
206 fn label(&self) -> &str {
207 self.label
208 }
209}
210
211pub struct SimpleShadedPlot<'a> {
213 label: &'a str,
214 values: &'a [f64],
215 style: PlotItemStyle,
216 y_ref: f64,
217 flags: ShadedFlags,
218 item_flags: ItemFlags,
219 x_scale: f64,
220 x_start: f64,
221}
222
223impl<'a> super::PlotItemStyled for SimpleShadedPlot<'a> {
224 fn style_mut(&mut self) -> &mut PlotItemStyle {
225 &mut self.style
226 }
227}
228
229impl<'a> SimpleShadedPlot<'a> {
230 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
232 Self {
233 label,
234 values,
235 style: PlotItemStyle::default(),
236 y_ref: 0.0,
237 flags: ShadedFlags::NONE,
238 item_flags: ItemFlags::NONE,
239 x_scale: 1.0,
240 x_start: 0.0,
241 }
242 }
243
244 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
246 self.y_ref = y_ref;
247 self
248 }
249
250 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
252 self.flags = flags;
253 self
254 }
255
256 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
258 self.item_flags = flags;
259 self
260 }
261
262 pub fn with_x_scale(mut self, scale: f64) -> Self {
264 self.x_scale = scale;
265 self
266 }
267
268 pub fn with_x_start(mut self, start: f64) -> Self {
270 self.x_start = start;
271 self
272 }
273}
274
275impl<'a> Plot for SimpleShadedPlot<'a> {
276 fn plot(&self) {
277 if self.values.is_empty() {
278 return;
279 }
280 let Ok(count) = i32::try_from(self.values.len()) else {
281 return;
282 };
283
284 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
285 let spec = plot_spec_with_style(
286 self.style,
287 self.flags.bits() | self.item_flags.bits(),
288 0,
289 std::mem::size_of::<f64>() as i32,
290 );
291 sys::ImPlot_PlotShaded_doublePtrInt(
292 label_ptr,
293 self.values.as_ptr(),
294 count,
295 self.y_ref,
296 self.x_scale,
297 self.x_start,
298 spec,
299 );
300 })
301 }
302
303 fn label(&self) -> &str {
304 self.label
305 }
306}
307
308impl<'ui> crate::PlotUi<'ui> {
310 pub fn shaded_plot(
312 &self,
313 label: &str,
314 x_data: &[f64],
315 y_data: &[f64],
316 ) -> Result<(), PlotError> {
317 let plot = ShadedPlot::new(label, x_data, y_data);
318 plot.validate()?;
319 plot.plot();
320 Ok(())
321 }
322
323 pub fn shaded_plot_with_ref(
325 &self,
326 label: &str,
327 x_data: &[f64],
328 y_data: &[f64],
329 y_ref: f64,
330 ) -> Result<(), PlotError> {
331 let plot = ShadedPlot::new(label, x_data, y_data).with_y_ref(y_ref);
332 plot.validate()?;
333 plot.plot();
334 Ok(())
335 }
336
337 pub fn shaded_between_plot(
339 &self,
340 label: &str,
341 x_data: &[f64],
342 y1_data: &[f64],
343 y2_data: &[f64],
344 ) -> Result<(), PlotError> {
345 let plot = ShadedBetweenPlot::new(label, x_data, y1_data, y2_data);
346 plot.validate()?;
347 plot.plot();
348 Ok(())
349 }
350
351 pub fn simple_shaded_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
353 if values.is_empty() {
354 return Err(PlotError::EmptyData);
355 }
356 let plot = SimpleShadedPlot::new(label, values);
357 plot.plot();
358 Ok(())
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365
366 #[test]
367 fn test_shaded_plot_creation() {
368 let x_data = [1.0, 2.0, 3.0, 4.0];
369 let y_data = [1.0, 4.0, 2.0, 3.0];
370
371 let plot = ShadedPlot::new("test", &x_data, &y_data);
372 assert_eq!(plot.label(), "test");
373 assert!(plot.validate().is_ok());
374 }
375
376 #[test]
377 fn test_shaded_plot_validation() {
378 let x_data = [1.0, 2.0, 3.0];
379 let y_data = [1.0, 4.0]; let plot = ShadedPlot::new("test", &x_data, &y_data);
382 assert!(plot.validate().is_err());
383 }
384
385 #[test]
386 fn test_shaded_between_plot() {
387 let x_data = [1.0, 2.0, 3.0, 4.0];
388 let y1_data = [1.0, 2.0, 3.0, 4.0];
389 let y2_data = [2.0, 3.0, 4.0, 5.0];
390
391 let plot = ShadedBetweenPlot::new("test", &x_data, &y1_data, &y2_data);
392 assert_eq!(plot.label(), "test");
393 assert!(plot.validate().is_ok());
394 }
395
396 #[test]
397 fn test_simple_shaded_plot_flags() {
398 let values = [1.0, 2.0, 3.0, 4.0];
399 let plot = SimpleShadedPlot::new("test", &values).with_item_flags(ItemFlags::NO_FIT);
400 assert_eq!(plot.label(), "test");
401 assert_eq!(plot.item_flags, ItemFlags::NO_FIT);
402 }
403}