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