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