1use super::{Plot, PlotError, with_plot_str_or_empty};
4use crate::{BarsFlags, 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 offset: i32,
14 stride: i32,
15}
16
17impl<'a> BarPlot<'a> {
18 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
20 Self {
21 label,
22 values,
23 bar_size: 0.67, shift: 0.0,
25 flags: BarsFlags::NONE,
26 offset: 0,
27 stride: std::mem::size_of::<f64>() as i32,
28 }
29 }
30
31 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
33 self.bar_size = bar_size;
34 self
35 }
36
37 pub fn with_shift(mut self, shift: f64) -> Self {
39 self.shift = shift;
40 self
41 }
42
43 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
45 self.flags = flags;
46 self
47 }
48
49 pub fn with_offset(mut self, offset: i32) -> Self {
51 self.offset = offset;
52 self
53 }
54
55 pub fn with_stride(mut self, stride: i32) -> Self {
57 self.stride = stride;
58 self
59 }
60
61 pub fn validate(&self) -> Result<(), PlotError> {
63 if self.values.is_empty() {
64 Err(PlotError::EmptyData)
65 } else {
66 Ok(())
67 }
68 }
69}
70
71impl<'a> Plot for BarPlot<'a> {
72 fn plot(&self) {
73 if self.validate().is_err() {
74 return; }
76 let Ok(count) = i32::try_from(self.values.len()) else {
77 return;
78 };
79
80 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
81 sys::ImPlot_PlotBars_doublePtrInt(
82 label_ptr,
83 self.values.as_ptr(),
84 count,
85 self.bar_size,
86 self.shift,
87 self.flags.bits() as i32,
88 self.offset,
89 self.stride,
90 );
91 })
92 }
93
94 fn label(&self) -> &str {
95 self.label
96 }
97}
98
99pub struct PositionalBarPlot<'a> {
101 label: &'a str,
102 x_data: &'a [f64],
103 y_data: &'a [f64],
104 bar_size: f64,
105 flags: BarsFlags,
106}
107
108impl<'a> PositionalBarPlot<'a> {
109 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
111 Self {
112 label,
113 x_data,
114 y_data,
115 bar_size: 0.67,
116 flags: BarsFlags::NONE,
117 }
118 }
119
120 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
122 self.bar_size = bar_size;
123 self
124 }
125
126 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
128 self.flags = flags;
129 self
130 }
131
132 pub fn validate(&self) -> Result<(), PlotError> {
134 super::validate_data_lengths(self.x_data, self.y_data)
135 }
136}
137
138impl<'a> Plot for PositionalBarPlot<'a> {
139 fn plot(&self) {
140 if self.validate().is_err() {
141 return; }
143 let Ok(count) = i32::try_from(self.y_data.len()) else {
144 return;
145 };
146
147 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
148 sys::ImPlot_PlotBars_doublePtrdoublePtr(
149 label_ptr,
150 self.x_data.as_ptr(),
151 self.y_data.as_ptr(),
152 count,
153 self.bar_size,
154 self.flags.bits() as i32,
155 0,
156 std::mem::size_of::<f64>() as i32,
157 );
158 })
159 }
160
161 fn label(&self) -> &str {
162 self.label
163 }
164}
165
166impl<'ui> crate::PlotUi<'ui> {
168 pub fn bar_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
170 let plot = BarPlot::new(label, values);
171 plot.validate()?;
172 plot.plot();
173 Ok(())
174 }
175
176 pub fn bar_plot_with_width(
178 &self,
179 label: &str,
180 values: &[f64],
181 width: f64,
182 ) -> Result<(), PlotError> {
183 let plot = BarPlot::new(label, values).with_bar_size(width);
184 plot.validate()?;
185 plot.plot();
186 Ok(())
187 }
188
189 pub fn positional_bar_plot(
191 &self,
192 label: &str,
193 x_data: &[f64],
194 y_data: &[f64],
195 ) -> Result<(), PlotError> {
196 let plot = PositionalBarPlot::new(label, x_data, y_data);
197 plot.validate()?;
198 plot.plot();
199 Ok(())
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_bar_plot_creation() {
209 let values = [1.0, 2.0, 3.0, 4.0];
210 let plot = BarPlot::new("test", &values);
211 assert_eq!(plot.label(), "test");
212 assert!(plot.validate().is_ok());
213 }
214
215 #[test]
216 fn test_bar_plot_empty_data() {
217 let values: &[f64] = &[];
218 let plot = BarPlot::new("test", values);
219 assert!(plot.validate().is_err());
220 }
221
222 #[test]
223 fn test_positional_bar_plot() {
224 let x_data = [1.0, 2.0, 3.0, 4.0];
225 let y_data = [1.0, 4.0, 2.0, 3.0];
226
227 let plot = PositionalBarPlot::new("test", &x_data, &y_data);
228 assert_eq!(plot.label(), "test");
229 assert!(plot.validate().is_ok());
230 }
231
232 #[test]
233 fn test_positional_bar_plot_validation() {
234 let x_data = [1.0, 2.0, 3.0];
235 let y_data = [1.0, 4.0]; let plot = PositionalBarPlot::new("test", &x_data, &y_data);
238 assert!(plot.validate().is_err());
239 }
240}