1use super::{Plot, PlotError, safe_cstring};
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
77 let label_cstr = safe_cstring(self.label);
78
79 unsafe {
80 sys::ImPlot_PlotBars_doublePtrInt(
81 label_cstr.as_ptr(),
82 self.values.as_ptr(),
83 self.values.len() as i32,
84 self.bar_size,
85 self.shift,
86 self.flags.bits() as i32,
87 self.offset,
88 self.stride,
89 );
90 }
91 }
92
93 fn label(&self) -> &str {
94 self.label
95 }
96}
97
98pub struct PositionalBarPlot<'a> {
100 label: &'a str,
101 x_data: &'a [f64],
102 y_data: &'a [f64],
103 bar_size: f64,
104 flags: BarsFlags,
105}
106
107impl<'a> PositionalBarPlot<'a> {
108 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
110 Self {
111 label,
112 x_data,
113 y_data,
114 bar_size: 0.67,
115 flags: BarsFlags::NONE,
116 }
117 }
118
119 pub fn with_bar_size(mut self, bar_size: f64) -> Self {
121 self.bar_size = bar_size;
122 self
123 }
124
125 pub fn with_flags(mut self, flags: BarsFlags) -> Self {
127 self.flags = flags;
128 self
129 }
130
131 pub fn validate(&self) -> Result<(), PlotError> {
133 super::validate_data_lengths(self.x_data, self.y_data)
134 }
135}
136
137impl<'a> Plot for PositionalBarPlot<'a> {
138 fn plot(&self) {
139 if self.validate().is_err() {
140 return; }
142
143 let label_cstr = safe_cstring(self.label);
144
145 unsafe {
146 sys::ImPlot_PlotBars_doublePtrdoublePtr(
147 label_cstr.as_ptr(),
148 self.x_data.as_ptr(),
149 self.y_data.as_ptr(),
150 self.y_data.len() as i32,
151 self.bar_size,
152 self.flags.bits() as i32,
153 0,
154 std::mem::size_of::<f64>() as i32,
155 );
156 }
157 }
158
159 fn label(&self) -> &str {
160 self.label
161 }
162}
163
164impl<'ui> crate::PlotUi<'ui> {
166 pub fn bar_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
168 let plot = BarPlot::new(label, values);
169 plot.validate()?;
170 plot.plot();
171 Ok(())
172 }
173
174 pub fn bar_plot_with_width(
176 &self,
177 label: &str,
178 values: &[f64],
179 width: f64,
180 ) -> Result<(), PlotError> {
181 let plot = BarPlot::new(label, values).with_bar_size(width);
182 plot.validate()?;
183 plot.plot();
184 Ok(())
185 }
186
187 pub fn positional_bar_plot(
189 &self,
190 label: &str,
191 x_data: &[f64],
192 y_data: &[f64],
193 ) -> Result<(), PlotError> {
194 let plot = PositionalBarPlot::new(label, x_data, y_data);
195 plot.validate()?;
196 plot.plot();
197 Ok(())
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_bar_plot_creation() {
207 let values = [1.0, 2.0, 3.0, 4.0];
208 let plot = BarPlot::new("test", &values);
209 assert_eq!(plot.label(), "test");
210 assert!(plot.validate().is_ok());
211 }
212
213 #[test]
214 fn test_bar_plot_empty_data() {
215 let values: &[f64] = &[];
216 let plot = BarPlot::new("test", values);
217 assert!(plot.validate().is_err());
218 }
219
220 #[test]
221 fn test_positional_bar_plot() {
222 let x_data = [1.0, 2.0, 3.0, 4.0];
223 let y_data = [1.0, 4.0, 2.0, 3.0];
224
225 let plot = PositionalBarPlot::new("test", &x_data, &y_data);
226 assert_eq!(plot.label(), "test");
227 assert!(plot.validate().is_ok());
228 }
229
230 #[test]
231 fn test_positional_bar_plot_validation() {
232 let x_data = [1.0, 2.0, 3.0];
233 let y_data = [1.0, 4.0]; let plot = PositionalBarPlot::new("test", &x_data, &y_data);
236 assert!(plot.validate().is_err());
237 }
238}