1use super::{Plot, PlotError, plot_spec_from, with_plot_str_slice_with_opt};
4use crate::{ItemFlags, PieChartFlags, sys};
5
6pub struct PieChartPlot<'a> {
8 label_ids: Vec<&'a str>,
9 values: &'a [f64],
10 center_x: f64,
11 center_y: f64,
12 radius: f64,
13 label_fmt: Option<&'a str>,
14 angle0: f64,
15 flags: PieChartFlags,
16 item_flags: ItemFlags,
17}
18
19impl<'a> PieChartPlot<'a> {
20 pub fn new(
29 label_ids: Vec<&'a str>,
30 values: &'a [f64],
31 center_x: f64,
32 center_y: f64,
33 radius: f64,
34 ) -> Self {
35 Self {
36 label_ids,
37 values,
38 center_x,
39 center_y,
40 radius,
41 label_fmt: Some("%.1f"),
42 angle0: 90.0, flags: PieChartFlags::NONE,
44 item_flags: ItemFlags::NONE,
45 }
46 }
47
48 pub fn with_label_format(mut self, fmt: Option<&'a str>) -> Self {
51 self.label_fmt = fmt;
52 self
53 }
54
55 pub fn with_start_angle(mut self, angle: f64) -> Self {
57 self.angle0 = angle;
58 self
59 }
60
61 pub fn with_flags(mut self, flags: PieChartFlags) -> Self {
63 self.flags = flags;
64 self
65 }
66
67 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
69 self.item_flags = flags;
70 self
71 }
72
73 pub fn normalize(mut self) -> Self {
75 self.flags |= PieChartFlags::NORMALIZE;
76 self
77 }
78
79 pub fn ignore_hidden(mut self) -> Self {
81 self.flags |= PieChartFlags::IGNORE_HIDDEN;
82 self
83 }
84
85 pub fn exploding(mut self) -> Self {
87 self.flags |= PieChartFlags::EXPLODING;
88 self
89 }
90
91 pub fn validate(&self) -> Result<(), PlotError> {
93 if self.values.is_empty() {
94 return Err(PlotError::EmptyData);
95 }
96
97 if self.label_ids.len() != self.values.len() {
98 return Err(PlotError::DataLengthMismatch {
99 x_len: self.label_ids.len(),
100 y_len: self.values.len(),
101 });
102 }
103
104 if self.radius <= 0.0 {
105 return Err(PlotError::InvalidData(
106 "Radius must be positive".to_string(),
107 ));
108 }
109
110 if self.values.iter().any(|&v| v < 0.0) {
112 return Err(PlotError::InvalidData(
113 "Pie chart values cannot be negative".to_string(),
114 ));
115 }
116
117 Ok(())
118 }
119}
120
121impl<'a> Plot for PieChartPlot<'a> {
122 fn plot(&self) {
123 if self.validate().is_err() {
124 return;
125 }
126 let Ok(count) = i32::try_from(self.values.len()) else {
127 return;
128 };
129 with_plot_str_slice_with_opt(
130 &self.label_ids,
131 self.label_fmt,
132 |label_ptrs, label_fmt_ptr| unsafe {
133 let spec = plot_spec_from(
134 self.flags.bits() | self.item_flags.bits(),
135 0,
136 crate::IMPLOT_AUTO,
137 );
138 sys::ImPlot_PlotPieChart_doublePtrStr(
139 label_ptrs.as_ptr(),
140 self.values.as_ptr(),
141 count,
142 self.center_x,
143 self.center_y,
144 self.radius,
145 label_fmt_ptr,
146 self.angle0,
147 spec,
148 );
149 },
150 )
151 }
152
153 fn label(&self) -> &str {
154 "PieChart" }
156}
157
158pub struct PieChartPlotF32<'a> {
160 label_ids: Vec<&'a str>,
161 values: &'a [f32],
162 center_x: f64,
163 center_y: f64,
164 radius: f64,
165 label_fmt: Option<&'a str>,
166 angle0: f64,
167 flags: PieChartFlags,
168 item_flags: ItemFlags,
169}
170
171impl<'a> PieChartPlotF32<'a> {
172 pub fn new(
174 label_ids: Vec<&'a str>,
175 values: &'a [f32],
176 center_x: f64,
177 center_y: f64,
178 radius: f64,
179 ) -> Self {
180 Self {
181 label_ids,
182 values,
183 center_x,
184 center_y,
185 radius,
186 label_fmt: Some("%.1f"),
187 angle0: 90.0,
188 flags: PieChartFlags::NONE,
189 item_flags: ItemFlags::NONE,
190 }
191 }
192
193 pub fn with_label_format(mut self, fmt: Option<&'a str>) -> Self {
195 self.label_fmt = fmt;
196 self
197 }
198
199 pub fn with_start_angle(mut self, angle: f64) -> Self {
201 self.angle0 = angle;
202 self
203 }
204
205 pub fn with_flags(mut self, flags: PieChartFlags) -> Self {
207 self.flags = flags;
208 self
209 }
210
211 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
213 self.item_flags = flags;
214 self
215 }
216
217 pub fn normalize(mut self) -> Self {
219 self.flags |= PieChartFlags::NORMALIZE;
220 self
221 }
222
223 pub fn ignore_hidden(mut self) -> Self {
225 self.flags |= PieChartFlags::IGNORE_HIDDEN;
226 self
227 }
228
229 pub fn exploding(mut self) -> Self {
231 self.flags |= PieChartFlags::EXPLODING;
232 self
233 }
234
235 pub fn validate(&self) -> Result<(), PlotError> {
237 if self.values.is_empty() {
238 return Err(PlotError::EmptyData);
239 }
240
241 if self.label_ids.len() != self.values.len() {
242 return Err(PlotError::DataLengthMismatch {
243 x_len: self.label_ids.len(),
244 y_len: self.values.len(),
245 });
246 }
247
248 if self.radius <= 0.0 {
249 return Err(PlotError::InvalidData(
250 "Radius must be positive".to_string(),
251 ));
252 }
253
254 if self.values.iter().any(|&v| v < 0.0) {
255 return Err(PlotError::InvalidData(
256 "Pie chart values cannot be negative".to_string(),
257 ));
258 }
259
260 Ok(())
261 }
262}
263
264impl<'a> Plot for PieChartPlotF32<'a> {
265 fn plot(&self) {
266 if self.validate().is_err() {
267 return;
268 }
269 let Ok(count) = i32::try_from(self.values.len()) else {
270 return;
271 };
272 with_plot_str_slice_with_opt(
273 &self.label_ids,
274 self.label_fmt,
275 |label_ptrs, label_fmt_ptr| unsafe {
276 let spec = plot_spec_from(
277 self.flags.bits() | self.item_flags.bits(),
278 0,
279 crate::IMPLOT_AUTO,
280 );
281 sys::ImPlot_PlotPieChart_FloatPtrStr(
282 label_ptrs.as_ptr(),
283 self.values.as_ptr(),
284 count,
285 self.center_x,
286 self.center_y,
287 self.radius,
288 label_fmt_ptr,
289 self.angle0,
290 spec,
291 );
292 },
293 )
294 }
295
296 fn label(&self) -> &str {
297 "PieChart"
298 }
299}
300
301impl<'ui> crate::PlotUi<'ui> {
303 pub fn pie_chart_plot(
305 &self,
306 label_ids: Vec<&str>,
307 values: &[f64],
308 center_x: f64,
309 center_y: f64,
310 radius: f64,
311 ) -> Result<(), PlotError> {
312 let plot = PieChartPlot::new(label_ids, values, center_x, center_y, radius);
313 plot.validate()?;
314 plot.plot();
315 Ok(())
316 }
317
318 pub fn pie_chart_plot_f32(
320 &self,
321 label_ids: Vec<&str>,
322 values: &[f32],
323 center_x: f64,
324 center_y: f64,
325 radius: f64,
326 ) -> Result<(), PlotError> {
327 let plot = PieChartPlotF32::new(label_ids, values, center_x, center_y, radius);
328 plot.validate()?;
329 plot.plot();
330 Ok(())
331 }
332
333 pub fn centered_pie_chart(
335 &self,
336 label_ids: Vec<&str>,
337 values: &[f64],
338 ) -> Result<(), PlotError> {
339 let plot = PieChartPlot::new(label_ids, values, 0.5, 0.5, 0.4);
340 plot.validate()?;
341 plot.plot();
342 Ok(())
343 }
344}