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