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 plot.plot();
225 Ok(())
226 }
227
228 pub fn bar_plot_with_width(
230 &self,
231 label: &str,
232 values: &[f64],
233 width: f64,
234 ) -> Result<(), PlotError> {
235 let plot = BarPlot::new(label, values).with_bar_size(width);
236 plot.validate()?;
237 plot.plot();
238 Ok(())
239 }
240
241 pub fn positional_bar_plot(
243 &self,
244 label: &str,
245 x_data: &[f64],
246 y_data: &[f64],
247 ) -> Result<(), PlotError> {
248 let plot = PositionalBarPlot::new(label, x_data, y_data);
249 plot.validate()?;
250 plot.plot();
251 Ok(())
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258 use crate::plots::PlotItemStyled;
259
260 #[test]
261 fn test_bar_plot_creation() {
262 let values = [1.0, 2.0, 3.0, 4.0];
263 let plot = BarPlot::new("test", &values);
264 assert_eq!(plot.label(), "test");
265 assert!(plot.validate().is_ok());
266 }
267
268 #[test]
269 fn test_bar_plot_empty_data() {
270 let values: &[f64] = &[];
271 let plot = BarPlot::new("test", values);
272 assert!(plot.validate().is_err());
273 }
274
275 #[test]
276 fn test_positional_bar_plot() {
277 let x_data = [1.0, 2.0, 3.0, 4.0];
278 let y_data = [1.0, 4.0, 2.0, 3.0];
279
280 let plot = PositionalBarPlot::new("test", &x_data, &y_data);
281 assert_eq!(plot.label(), "test");
282 assert!(plot.validate().is_ok());
283 }
284
285 #[test]
286 fn test_positional_bar_plot_validation() {
287 let x_data = [1.0, 2.0, 3.0];
288 let y_data = [1.0, 4.0]; let plot = PositionalBarPlot::new("test", &x_data, &y_data);
291 assert!(plot.validate().is_err());
292 }
293
294 #[test]
295 fn test_bar_plot_style_trait_builders() {
296 let values = [1.0, 2.0, 3.0, 4.0];
297 let plot = BarPlot::new("styled", &values)
298 .with_line_color([0.1, 0.2, 0.3, 0.4])
299 .with_fill_color([0.4, 0.3, 0.2, 0.1])
300 .with_fill_alpha(0.6)
301 .with_line_weight(2.5);
302
303 assert_eq!(
304 plot.style.line_color,
305 Some(sys::ImVec4_c {
306 x: 0.1,
307 y: 0.2,
308 z: 0.3,
309 w: 0.4,
310 })
311 );
312 assert_eq!(
313 plot.style.fill_color,
314 Some(sys::ImVec4_c {
315 x: 0.4,
316 y: 0.3,
317 z: 0.2,
318 w: 0.1,
319 })
320 );
321 assert_eq!(plot.style.fill_alpha, Some(0.6));
322 assert_eq!(plot.style.line_weight, Some(2.5));
323 }
324}