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, plot_ui: &crate::PlotUi<'_>) {
102 if self.validate().is_err() {
103 return; }
105 let Ok(count) = i32::try_from(self.values.len()) else {
106 return;
107 };
108
109 let _guard = plot_ui.bind();
110 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
111 let spec = plot_spec_with_style(
112 self.style,
113 self.flags.bits() | self.item_flags.bits(),
114 self.layout,
115 );
116 sys::ImPlot_PlotBars_doublePtrInt(
117 label_ptr,
118 self.values.as_ptr(),
119 count,
120 self.bar_size,
121 self.shift,
122 spec,
123 );
124 })
125 }
126
127 fn label(&self) -> &str {
128 self.label
129 }
130}
131
132pub struct PositionalBarPlot<'a> {
134 label: &'a str,
135 x_data: &'a [f64],
136 y_data: &'a [f64],
137 style: PlotItemStyle,
138 bar_size: f64,
139 flags: BarsFlags,
140 item_flags: ItemFlags,
141}
142
143impl<'a> super::PlotItemStyled for PositionalBarPlot<'a> {
144 fn style_mut(&mut self) -> &mut PlotItemStyle {
145 &mut self.style
146 }
147}
148
149impl<'a> PositionalBarPlot<'a> {
150 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
152 Self {
153 label,
154 x_data,
155 y_data,
156 style: PlotItemStyle::default(),
157 bar_size: 0.67,
158 flags: BarsFlags::NONE,
159 item_flags: ItemFlags::NONE,
160 }
161 }
162
163 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
165 self.bar_size = bar_size;
166 self
167 }
168
169 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
171 self.style = style;
172 self
173 }
174
175 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
177 self.flags = flags;
178 self
179 }
180
181 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
183 self.item_flags = flags;
184 self
185 }
186
187 pub fn validate(&self) -> Result<(), PlotError> {
189 super::validate_data_lengths(self.x_data, self.y_data)
190 }
191}
192
193impl<'a> Plot for PositionalBarPlot<'a> {
194 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
195 if self.validate().is_err() {
196 return; }
198 let Ok(count) = i32::try_from(self.y_data.len()) else {
199 return;
200 };
201
202 let _guard = plot_ui.bind();
203 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
204 let spec = plot_spec_with_style(
205 self.style,
206 self.flags.bits() | self.item_flags.bits(),
207 PlotDataLayout::DEFAULT,
208 );
209 sys::ImPlot_PlotBars_doublePtrdoublePtr(
210 label_ptr,
211 self.x_data.as_ptr(),
212 self.y_data.as_ptr(),
213 count,
214 self.bar_size,
215 spec,
216 );
217 })
218 }
219
220 fn label(&self) -> &str {
221 self.label
222 }
223}
224
225impl<'ui> crate::PlotUi<'ui> {
227 pub fn bar_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
229 let plot = BarPlot::new(label, values);
230 plot.validate()?;
231 plot.plot(self);
232 Ok(())
233 }
234
235 pub fn bar_plot_with_width(
237 &self,
238 label: &str,
239 values: &[f64],
240 width: f64,
241 ) -> Result<(), PlotError> {
242 let plot = BarPlot::new(label, values).with_bar_size(width);
243 plot.validate()?;
244 plot.plot(self);
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 plot.plot(self);
258 Ok(())
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use crate::plots::PlotItemStyled;
266
267 #[test]
268 fn test_bar_plot_creation() {
269 let values = [1.0, 2.0, 3.0, 4.0];
270 let plot = BarPlot::new("test", &values);
271 assert_eq!(plot.label(), "test");
272 assert!(plot.validate().is_ok());
273 }
274
275 #[test]
276 fn test_bar_plot_empty_data() {
277 let values: &[f64] = &[];
278 let plot = BarPlot::new("test", values);
279 assert!(plot.validate().is_err());
280 }
281
282 #[test]
283 fn test_positional_bar_plot() {
284 let x_data = [1.0, 2.0, 3.0, 4.0];
285 let y_data = [1.0, 4.0, 2.0, 3.0];
286
287 let plot = PositionalBarPlot::new("test", &x_data, &y_data);
288 assert_eq!(plot.label(), "test");
289 assert!(plot.validate().is_ok());
290 }
291
292 #[test]
293 fn test_positional_bar_plot_validation() {
294 let x_data = [1.0, 2.0, 3.0];
295 let y_data = [1.0, 4.0]; let plot = PositionalBarPlot::new("test", &x_data, &y_data);
298 assert!(plot.validate().is_err());
299 }
300
301 #[test]
302 fn test_bar_plot_style_trait_builders() {
303 let values = [1.0, 2.0, 3.0, 4.0];
304 let plot = BarPlot::new("styled", &values)
305 .with_line_color([0.1, 0.2, 0.3, 0.4])
306 .with_fill_color([0.4, 0.3, 0.2, 0.1])
307 .with_fill_alpha(0.6)
308 .with_line_weight(2.5);
309
310 assert_eq!(
311 plot.style.line_color,
312 Some(sys::ImVec4_c {
313 x: 0.1,
314 y: 0.2,
315 z: 0.3,
316 w: 0.4,
317 })
318 );
319 assert_eq!(
320 plot.style.fill_color,
321 Some(sys::ImVec4_c {
322 x: 0.4,
323 y: 0.3,
324 z: 0.2,
325 w: 0.1,
326 })
327 );
328 assert_eq!(plot.style.fill_alpha, Some(0.6));
329 assert_eq!(plot.style.line_weight, Some(2.5));
330 }
331}