1use super::{Plot, PlotError, plot_spec_from, with_plot_str_or_empty};
4use crate::{BarsFlags, ItemFlags, sys};
5
6pub struct BarPlot<'a> {
8 label: &'a str,
9 values: &'a [f64],
10 bar_size: f64,
11 shift: f64,
12 flags: BarsFlags,
13 item_flags: ItemFlags,
14 offset: i32,
15 stride: i32,
16}
17
18impl<'a> BarPlot<'a> {
19 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
21 Self {
22 label,
23 values,
24 bar_size: 0.67, shift: 0.0,
26 flags: BarsFlags::NONE,
27 item_flags: ItemFlags::NONE,
28 offset: 0,
29 stride: std::mem::size_of::<f64>() as i32,
30 }
31 }
32
33 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
35 self.bar_size = bar_size;
36 self
37 }
38
39 pub fn with_shift(mut self, shift: f64) -> Self {
41 self.shift = shift;
42 self
43 }
44
45 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
47 self.flags = flags;
48 self
49 }
50
51 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
53 self.item_flags = flags;
54 self
55 }
56
57 pub fn with_offset(mut self, offset: i32) -> Self {
59 self.offset = offset;
60 self
61 }
62
63 pub fn with_stride(mut self, stride: i32) -> Self {
65 self.stride = stride;
66 self
67 }
68
69 pub fn validate(&self) -> Result<(), PlotError> {
71 if self.values.is_empty() {
72 Err(PlotError::EmptyData)
73 } else {
74 Ok(())
75 }
76 }
77}
78
79impl<'a> Plot for BarPlot<'a> {
80 fn plot(&self) {
81 if self.validate().is_err() {
82 return; }
84 let Ok(count) = i32::try_from(self.values.len()) else {
85 return;
86 };
87
88 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
89 let spec = plot_spec_from(
90 self.flags.bits() | self.item_flags.bits(),
91 self.offset,
92 self.stride,
93 );
94 sys::ImPlot_PlotBars_doublePtrInt(
95 label_ptr,
96 self.values.as_ptr(),
97 count,
98 self.bar_size,
99 self.shift,
100 spec,
101 );
102 })
103 }
104
105 fn label(&self) -> &str {
106 self.label
107 }
108}
109
110pub struct PositionalBarPlot<'a> {
112 label: &'a str,
113 x_data: &'a [f64],
114 y_data: &'a [f64],
115 bar_size: f64,
116 flags: BarsFlags,
117 item_flags: ItemFlags,
118}
119
120impl<'a> PositionalBarPlot<'a> {
121 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
123 Self {
124 label,
125 x_data,
126 y_data,
127 bar_size: 0.67,
128 flags: BarsFlags::NONE,
129 item_flags: ItemFlags::NONE,
130 }
131 }
132
133 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
135 self.bar_size = bar_size;
136 self
137 }
138
139 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
141 self.flags = flags;
142 self
143 }
144
145 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
147 self.item_flags = flags;
148 self
149 }
150
151 pub fn validate(&self) -> Result<(), PlotError> {
153 super::validate_data_lengths(self.x_data, self.y_data)
154 }
155}
156
157impl<'a> Plot for PositionalBarPlot<'a> {
158 fn plot(&self) {
159 if self.validate().is_err() {
160 return; }
162 let Ok(count) = i32::try_from(self.y_data.len()) else {
163 return;
164 };
165
166 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
167 let spec = plot_spec_from(
168 self.flags.bits() | self.item_flags.bits(),
169 0,
170 std::mem::size_of::<f64>() as i32,
171 );
172 sys::ImPlot_PlotBars_doublePtrdoublePtr(
173 label_ptr,
174 self.x_data.as_ptr(),
175 self.y_data.as_ptr(),
176 count,
177 self.bar_size,
178 spec,
179 );
180 })
181 }
182
183 fn label(&self) -> &str {
184 self.label
185 }
186}
187
188impl<'ui> crate::PlotUi<'ui> {
190 pub fn bar_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
192 let plot = BarPlot::new(label, values);
193 plot.validate()?;
194 plot.plot();
195 Ok(())
196 }
197
198 pub fn bar_plot_with_width(
200 &self,
201 label: &str,
202 values: &[f64],
203 width: f64,
204 ) -> Result<(), PlotError> {
205 let plot = BarPlot::new(label, values).with_bar_size(width);
206 plot.validate()?;
207 plot.plot();
208 Ok(())
209 }
210
211 pub fn positional_bar_plot(
213 &self,
214 label: &str,
215 x_data: &[f64],
216 y_data: &[f64],
217 ) -> Result<(), PlotError> {
218 let plot = PositionalBarPlot::new(label, x_data, y_data);
219 plot.validate()?;
220 plot.plot();
221 Ok(())
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_bar_plot_creation() {
231 let values = [1.0, 2.0, 3.0, 4.0];
232 let plot = BarPlot::new("test", &values);
233 assert_eq!(plot.label(), "test");
234 assert!(plot.validate().is_ok());
235 }
236
237 #[test]
238 fn test_bar_plot_empty_data() {
239 let values: &[f64] = &[];
240 let plot = BarPlot::new("test", values);
241 assert!(plot.validate().is_err());
242 }
243
244 #[test]
245 fn test_positional_bar_plot() {
246 let x_data = [1.0, 2.0, 3.0, 4.0];
247 let y_data = [1.0, 4.0, 2.0, 3.0];
248
249 let plot = PositionalBarPlot::new("test", &x_data, &y_data);
250 assert_eq!(plot.label(), "test");
251 assert!(plot.validate().is_ok());
252 }
253
254 #[test]
255 fn test_positional_bar_plot_validation() {
256 let x_data = [1.0, 2.0, 3.0];
257 let y_data = [1.0, 4.0]; let plot = PositionalBarPlot::new("test", &x_data, &y_data);
260 assert!(plot.validate().is_err());
261 }
262}