1use super::{Plot, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_or_empty};
4use crate::{BarsFlags, ItemFlags, sys};
5
6pub struct BarPlot<'a> {
8 label: &'a str,
9 values: &'a [f64],
10 style: PlotItemStyle,
11 bar_size: f64,
12 shift: f64,
13 flags: BarsFlags,
14 item_flags: ItemFlags,
15 offset: i32,
16 stride: i32,
17}
18
19impl<'a> super::PlotItemStyled for BarPlot<'a> {
20 fn style_mut(&mut self) -> &mut PlotItemStyle {
21 &mut self.style
22 }
23}
24
25impl<'a> BarPlot<'a> {
26 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
28 Self {
29 label,
30 values,
31 style: PlotItemStyle::default(),
32 bar_size: 0.67, shift: 0.0,
34 flags: BarsFlags::NONE,
35 item_flags: ItemFlags::NONE,
36 offset: 0,
37 stride: std::mem::size_of::<f64>() as i32,
38 }
39 }
40
41 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
43 self.bar_size = bar_size;
44 self
45 }
46
47 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
49 self.style = style;
50 self
51 }
52
53 pub fn with_shift(mut self, shift: f64) -> Self {
55 self.shift = shift;
56 self
57 }
58
59 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
61 self.flags = flags;
62 self
63 }
64
65 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
67 self.item_flags = flags;
68 self
69 }
70
71 pub fn with_offset(mut self, offset: i32) -> Self {
73 self.offset = offset;
74 self
75 }
76
77 pub fn with_stride(mut self, stride: i32) -> Self {
79 self.stride = stride;
80 self
81 }
82
83 pub fn validate(&self) -> Result<(), PlotError> {
85 if self.values.is_empty() {
86 Err(PlotError::EmptyData)
87 } else {
88 Ok(())
89 }
90 }
91}
92
93impl<'a> Plot for BarPlot<'a> {
94 fn plot(&self) {
95 if self.validate().is_err() {
96 return; }
98 let Ok(count) = i32::try_from(self.values.len()) else {
99 return;
100 };
101
102 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
103 let spec = plot_spec_with_style(
104 self.style,
105 self.flags.bits() | self.item_flags.bits(),
106 self.offset,
107 self.stride,
108 );
109 sys::ImPlot_PlotBars_doublePtrInt(
110 label_ptr,
111 self.values.as_ptr(),
112 count,
113 self.bar_size,
114 self.shift,
115 spec,
116 );
117 })
118 }
119
120 fn label(&self) -> &str {
121 self.label
122 }
123}
124
125pub struct PositionalBarPlot<'a> {
127 label: &'a str,
128 x_data: &'a [f64],
129 y_data: &'a [f64],
130 style: PlotItemStyle,
131 bar_size: f64,
132 flags: BarsFlags,
133 item_flags: ItemFlags,
134}
135
136impl<'a> super::PlotItemStyled for PositionalBarPlot<'a> {
137 fn style_mut(&mut self) -> &mut PlotItemStyle {
138 &mut self.style
139 }
140}
141
142impl<'a> PositionalBarPlot<'a> {
143 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
145 Self {
146 label,
147 x_data,
148 y_data,
149 style: PlotItemStyle::default(),
150 bar_size: 0.67,
151 flags: BarsFlags::NONE,
152 item_flags: ItemFlags::NONE,
153 }
154 }
155
156 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
158 self.bar_size = bar_size;
159 self
160 }
161
162 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
164 self.style = style;
165 self
166 }
167
168 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
170 self.flags = flags;
171 self
172 }
173
174 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
176 self.item_flags = flags;
177 self
178 }
179
180 pub fn validate(&self) -> Result<(), PlotError> {
182 super::validate_data_lengths(self.x_data, self.y_data)
183 }
184}
185
186impl<'a> Plot for PositionalBarPlot<'a> {
187 fn plot(&self) {
188 if self.validate().is_err() {
189 return; }
191 let Ok(count) = i32::try_from(self.y_data.len()) else {
192 return;
193 };
194
195 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
196 let spec = plot_spec_with_style(
197 self.style,
198 self.flags.bits() | self.item_flags.bits(),
199 0,
200 std::mem::size_of::<f64>() as i32,
201 );
202 sys::ImPlot_PlotBars_doublePtrdoublePtr(
203 label_ptr,
204 self.x_data.as_ptr(),
205 self.y_data.as_ptr(),
206 count,
207 self.bar_size,
208 spec,
209 );
210 })
211 }
212
213 fn label(&self) -> &str {
214 self.label
215 }
216}
217
218impl<'ui> crate::PlotUi<'ui> {
220 pub fn bar_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
222 let plot = BarPlot::new(label, values);
223 plot.validate()?;
224 self.bind();
225 plot.plot();
226 Ok(())
227 }
228
229 pub fn bar_plot_with_width(
231 &self,
232 label: &str,
233 values: &[f64],
234 width: f64,
235 ) -> Result<(), PlotError> {
236 let plot = BarPlot::new(label, values).with_bar_size(width);
237 plot.validate()?;
238 self.bind();
239 plot.plot();
240 Ok(())
241 }
242
243 pub fn positional_bar_plot(
245 &self,
246 label: &str,
247 x_data: &[f64],
248 y_data: &[f64],
249 ) -> Result<(), PlotError> {
250 let plot = PositionalBarPlot::new(label, x_data, y_data);
251 plot.validate()?;
252 self.bind();
253 plot.plot();
254 Ok(())
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261 use crate::plots::PlotItemStyled;
262
263 #[test]
264 fn test_bar_plot_creation() {
265 let values = [1.0, 2.0, 3.0, 4.0];
266 let plot = BarPlot::new("test", &values);
267 assert_eq!(plot.label(), "test");
268 assert!(plot.validate().is_ok());
269 }
270
271 #[test]
272 fn test_bar_plot_empty_data() {
273 let values: &[f64] = &[];
274 let plot = BarPlot::new("test", values);
275 assert!(plot.validate().is_err());
276 }
277
278 #[test]
279 fn test_positional_bar_plot() {
280 let x_data = [1.0, 2.0, 3.0, 4.0];
281 let y_data = [1.0, 4.0, 2.0, 3.0];
282
283 let plot = PositionalBarPlot::new("test", &x_data, &y_data);
284 assert_eq!(plot.label(), "test");
285 assert!(plot.validate().is_ok());
286 }
287
288 #[test]
289 fn test_positional_bar_plot_validation() {
290 let x_data = [1.0, 2.0, 3.0];
291 let y_data = [1.0, 4.0]; let plot = PositionalBarPlot::new("test", &x_data, &y_data);
294 assert!(plot.validate().is_err());
295 }
296
297 #[test]
298 fn test_bar_plot_style_trait_builders() {
299 let values = [1.0, 2.0, 3.0, 4.0];
300 let plot = BarPlot::new("styled", &values)
301 .with_line_color([0.1, 0.2, 0.3, 0.4])
302 .with_fill_color([0.4, 0.3, 0.2, 0.1])
303 .with_fill_alpha(0.6)
304 .with_line_weight(2.5);
305
306 assert_eq!(
307 plot.style.line_color,
308 Some(sys::ImVec4_c {
309 x: 0.1,
310 y: 0.2,
311 z: 0.3,
312 w: 0.4,
313 })
314 );
315 assert_eq!(
316 plot.style.fill_color,
317 Some(sys::ImVec4_c {
318 x: 0.4,
319 y: 0.3,
320 z: 0.2,
321 w: 0.1,
322 })
323 );
324 assert_eq!(plot.style.fill_alpha, Some(0.6));
325 assert_eq!(plot.style.line_weight, Some(2.5));
326 }
327}