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) {
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 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
140 let spec = plot_spec_with_style(
141 self.style,
142 self.flags.bits() | self.item_flags.bits(),
143 self.layout,
144 );
145 sys::ImPlot_PlotLine_doublePtrdoublePtr(
146 label_ptr,
147 self.x_data.as_ptr(),
148 self.y_data.as_ptr(),
149 count,
150 spec,
151 );
152 })
153 }
154
155 fn label(&self) -> &str {
156 self.label
157 }
158}
159
160pub struct SimpleLinePlot<'a> {
162 label: &'a str,
163 values: &'a [f64],
164 style: PlotItemStyle,
165 flags: LineFlags,
166 item_flags: ItemFlags,
167 x_scale: f64,
168 x_start: f64,
169}
170
171impl<'a> super::PlotItemStyled for SimpleLinePlot<'a> {
172 fn style_mut(&mut self) -> &mut PlotItemStyle {
173 &mut self.style
174 }
175}
176
177impl<'a> SimpleLinePlot<'a> {
178 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
180 Self {
181 label,
182 values,
183 style: PlotItemStyle::default(),
184 flags: LineFlags::NONE,
185 item_flags: ItemFlags::NONE,
186 x_scale: 1.0,
187 x_start: 0.0,
188 }
189 }
190
191 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
193 self.style = style;
194 self
195 }
196
197 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
199 self.style = self.style.with_line_color(color);
200 self
201 }
202
203 pub fn with_line_weight(mut self, weight: f32) -> Self {
205 self.style = self.style.with_line_weight(weight);
206 self
207 }
208
209 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
211 self.style = self.style.with_fill_color(color);
212 self
213 }
214
215 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
217 self.style = self.style.with_fill_alpha(alpha);
218 self
219 }
220
221 pub fn with_marker(mut self, marker: Marker) -> Self {
223 self.style = self.style.with_marker(marker);
224 self
225 }
226
227 pub fn with_marker_size(mut self, size: f32) -> Self {
229 self.style = self.style.with_marker_size(size);
230 self
231 }
232
233 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
235 self.style = self.style.with_marker_line_color(color);
236 self
237 }
238
239 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
241 self.style = self.style.with_marker_fill_color(color);
242 self
243 }
244
245 pub fn with_flags(mut self, flags: LineFlags) -> Self {
247 self.flags = flags;
248 self
249 }
250
251 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
253 self.item_flags = flags;
254 self
255 }
256
257 pub fn with_x_scale(mut self, scale: f64) -> Self {
259 self.x_scale = scale;
260 self
261 }
262
263 pub fn with_x_start(mut self, start: f64) -> Self {
265 self.x_start = start;
266 self
267 }
268}
269
270impl<'a> Plot for SimpleLinePlot<'a> {
271 fn plot(&self) {
272 if self.values.is_empty() {
273 return;
274 }
275 let Ok(count) = i32::try_from(self.values.len()) else {
276 return;
277 };
278
279 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
280 let spec = plot_spec_with_style(
281 self.style,
282 self.flags.bits() | self.item_flags.bits(),
283 PlotDataLayout::DEFAULT,
284 );
285 sys::ImPlot_PlotLine_doublePtrInt(
286 label_ptr,
287 self.values.as_ptr(),
288 count,
289 self.x_scale,
290 self.x_start,
291 spec,
292 );
293 })
294 }
295
296 fn label(&self) -> &str {
297 self.label
298 }
299}
300
301impl<'ui> crate::PlotUi<'ui> {
303 pub fn line_plot(&self, label: &str, x_data: &[f64], y_data: &[f64]) -> Result<(), PlotError> {
305 let plot = LinePlot::new(label, x_data, y_data);
306 plot.validate()?;
307 self.bind();
308 plot.plot();
309 Ok(())
310 }
311
312 pub fn simple_line_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
314 if values.is_empty() {
315 return Err(PlotError::EmptyData);
316 }
317 let plot = SimpleLinePlot::new(label, values);
318 self.bind();
319 plot.plot();
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}