1use super::{
4 Plot, PlotError, PlotItemStyle, plot_spec_with_style, validate_data_lengths,
5 with_plot_str_or_empty,
6};
7use crate::{ItemFlags, LineFlags, Marker, sys};
8
9pub struct LinePlot<'a> {
11 label: &'a str,
12 x_data: &'a [f64],
13 y_data: &'a [f64],
14 style: PlotItemStyle,
15 flags: LineFlags,
16 item_flags: ItemFlags,
17 offset: i32,
18 stride: i32,
19}
20
21impl<'a> super::PlotItemStyled for LinePlot<'a> {
22 fn style_mut(&mut self) -> &mut PlotItemStyle {
23 &mut self.style
24 }
25}
26
27impl<'a> LinePlot<'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 flags: LineFlags::NONE,
36 item_flags: ItemFlags::NONE,
37 offset: 0,
38 stride: std::mem::size_of::<f64>() as i32,
39 }
40 }
41
42 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
44 self.style = style;
45 self
46 }
47
48 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
50 self.style = self.style.with_line_color(color);
51 self
52 }
53
54 pub fn with_line_weight(mut self, weight: f32) -> Self {
56 self.style = self.style.with_line_weight(weight);
57 self
58 }
59
60 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
62 self.style = self.style.with_fill_color(color);
63 self
64 }
65
66 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
68 self.style = self.style.with_fill_alpha(alpha);
69 self
70 }
71
72 pub fn with_marker(mut self, marker: Marker) -> Self {
74 self.style = self.style.with_marker(marker);
75 self
76 }
77
78 pub fn with_marker_size(mut self, size: f32) -> Self {
80 self.style = self.style.with_marker_size(size);
81 self
82 }
83
84 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
86 self.style = self.style.with_marker_line_color(color);
87 self
88 }
89
90 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
92 self.style = self.style.with_marker_fill_color(color);
93 self
94 }
95
96 pub fn with_flags(mut self, flags: LineFlags) -> Self {
98 self.flags = flags;
99 self
100 }
101
102 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
104 self.item_flags = flags;
105 self
106 }
107
108 pub fn with_offset(mut self, offset: i32) -> Self {
110 self.offset = offset;
111 self
112 }
113
114 pub fn with_stride(mut self, stride: i32) -> Self {
116 self.stride = stride;
117 self
118 }
119
120 pub fn validate(&self) -> Result<(), PlotError> {
122 validate_data_lengths(self.x_data, self.y_data)
123 }
124}
125
126impl<'a> Plot for LinePlot<'a> {
127 fn plot(&self) {
128 if self.validate().is_err() {
129 return; }
131 let Ok(count) = i32::try_from(self.x_data.len()) else {
132 return;
133 };
134
135 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
136 let spec = plot_spec_with_style(
137 self.style,
138 self.flags.bits() | self.item_flags.bits(),
139 self.offset,
140 self.stride,
141 );
142 sys::ImPlot_PlotLine_doublePtrdoublePtr(
143 label_ptr,
144 self.x_data.as_ptr(),
145 self.y_data.as_ptr(),
146 count,
147 spec,
148 );
149 })
150 }
151
152 fn label(&self) -> &str {
153 self.label
154 }
155}
156
157pub struct SimpleLinePlot<'a> {
159 label: &'a str,
160 values: &'a [f64],
161 style: PlotItemStyle,
162 flags: LineFlags,
163 item_flags: ItemFlags,
164 x_scale: f64,
165 x_start: f64,
166}
167
168impl<'a> super::PlotItemStyled for SimpleLinePlot<'a> {
169 fn style_mut(&mut self) -> &mut PlotItemStyle {
170 &mut self.style
171 }
172}
173
174impl<'a> SimpleLinePlot<'a> {
175 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
177 Self {
178 label,
179 values,
180 style: PlotItemStyle::default(),
181 flags: LineFlags::NONE,
182 item_flags: ItemFlags::NONE,
183 x_scale: 1.0,
184 x_start: 0.0,
185 }
186 }
187
188 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
190 self.style = style;
191 self
192 }
193
194 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
196 self.style = self.style.with_line_color(color);
197 self
198 }
199
200 pub fn with_line_weight(mut self, weight: f32) -> Self {
202 self.style = self.style.with_line_weight(weight);
203 self
204 }
205
206 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
208 self.style = self.style.with_fill_color(color);
209 self
210 }
211
212 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
214 self.style = self.style.with_fill_alpha(alpha);
215 self
216 }
217
218 pub fn with_marker(mut self, marker: Marker) -> Self {
220 self.style = self.style.with_marker(marker);
221 self
222 }
223
224 pub fn with_marker_size(mut self, size: f32) -> Self {
226 self.style = self.style.with_marker_size(size);
227 self
228 }
229
230 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
232 self.style = self.style.with_marker_line_color(color);
233 self
234 }
235
236 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
238 self.style = self.style.with_marker_fill_color(color);
239 self
240 }
241
242 pub fn with_flags(mut self, flags: LineFlags) -> Self {
244 self.flags = flags;
245 self
246 }
247
248 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
250 self.item_flags = flags;
251 self
252 }
253
254 pub fn with_x_scale(mut self, scale: f64) -> Self {
256 self.x_scale = scale;
257 self
258 }
259
260 pub fn with_x_start(mut self, start: f64) -> Self {
262 self.x_start = start;
263 self
264 }
265}
266
267impl<'a> Plot for SimpleLinePlot<'a> {
268 fn plot(&self) {
269 if self.values.is_empty() {
270 return;
271 }
272 let Ok(count) = i32::try_from(self.values.len()) else {
273 return;
274 };
275
276 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
277 let spec = plot_spec_with_style(
278 self.style,
279 self.flags.bits() | self.item_flags.bits(),
280 0,
281 std::mem::size_of::<f64>() as i32,
282 );
283 sys::ImPlot_PlotLine_doublePtrInt(
284 label_ptr,
285 self.values.as_ptr(),
286 count,
287 self.x_scale,
288 self.x_start,
289 spec,
290 );
291 })
292 }
293
294 fn label(&self) -> &str {
295 self.label
296 }
297}
298
299impl<'ui> crate::PlotUi<'ui> {
301 pub fn line_plot(&self, label: &str, x_data: &[f64], y_data: &[f64]) -> Result<(), PlotError> {
303 let plot = LinePlot::new(label, x_data, y_data);
304 plot.validate()?;
305 self.bind();
306 plot.plot();
307 Ok(())
308 }
309
310 pub fn simple_line_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
312 if values.is_empty() {
313 return Err(PlotError::EmptyData);
314 }
315 let plot = SimpleLinePlot::new(label, values);
316 self.bind();
317 plot.plot();
318 Ok(())
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn test_line_plot_creation() {
328 let x_data = [1.0, 2.0, 3.0, 4.0];
329 let y_data = [1.0, 4.0, 2.0, 3.0];
330
331 let plot = LinePlot::new("test", &x_data, &y_data);
332 assert_eq!(plot.label(), "test");
333 assert!(plot.validate().is_ok());
334 }
335
336 #[test]
337 fn test_line_plot_validation() {
338 let x_data = [1.0, 2.0, 3.0];
339 let y_data = [1.0, 4.0]; let plot = LinePlot::new("test", &x_data, &y_data);
342 assert!(plot.validate().is_err());
343 }
344
345 #[test]
346 fn test_simple_line_plot() {
347 let values = [1.0, 2.0, 3.0, 4.0];
348 let plot = SimpleLinePlot::new("test", &values)
349 .with_flags(LineFlags::LOOP)
350 .with_item_flags(ItemFlags::NO_LEGEND);
351 assert_eq!(plot.label(), "test");
352 assert_eq!(plot.flags.bits(), LineFlags::LOOP.bits());
353 assert_eq!(plot.item_flags, ItemFlags::NO_LEGEND);
354 }
355
356 #[test]
357 fn test_line_plot_style_builders() {
358 let x_data = [1.0, 2.0, 3.0, 4.0];
359 let y_data = [1.0, 4.0, 2.0, 3.0];
360
361 let plot = LinePlot::new("styled", &x_data, &y_data)
362 .with_line_color([0.1, 0.2, 0.3, 0.4])
363 .with_line_weight(2.5)
364 .with_fill_color([0.4, 0.3, 0.2, 0.1])
365 .with_fill_alpha(0.6)
366 .with_marker(Marker::Circle)
367 .with_marker_size(7.0)
368 .with_marker_line_color([0.9, 0.8, 0.7, 0.6])
369 .with_marker_fill_color([0.6, 0.7, 0.8, 0.9]);
370
371 assert_eq!(
372 plot.style.line_color,
373 Some(sys::ImVec4_c {
374 x: 0.1,
375 y: 0.2,
376 z: 0.3,
377 w: 0.4,
378 })
379 );
380 assert_eq!(plot.style.line_weight, Some(2.5));
381 assert_eq!(
382 plot.style.fill_color,
383 Some(sys::ImVec4_c {
384 x: 0.4,
385 y: 0.3,
386 z: 0.2,
387 w: 0.1,
388 })
389 );
390 assert_eq!(plot.style.fill_alpha, Some(0.6));
391 assert_eq!(plot.style.marker, Some(Marker::Circle as sys::ImPlotMarker));
392 assert_eq!(plot.style.marker_size, Some(7.0));
393 assert_eq!(
394 plot.style.marker_line_color,
395 Some(sys::ImVec4_c {
396 x: 0.9,
397 y: 0.8,
398 z: 0.7,
399 w: 0.6,
400 })
401 );
402 assert_eq!(
403 plot.style.marker_fill_color,
404 Some(sys::ImVec4_c {
405 x: 0.6,
406 y: 0.7,
407 z: 0.8,
408 w: 0.9,
409 })
410 );
411 }
412}