1use super::{Plot, PlotError, safe_cstring};
4use crate::PieChartFlags;
5use crate::sys;
6
7pub struct PieChartPlot<'a> {
9 label_ids: Vec<&'a str>,
10 values: &'a [f64],
11 center_x: f64,
12 center_y: f64,
13 radius: f64,
14 label_fmt: Option<&'a str>,
15 angle0: f64,
16 flags: PieChartFlags,
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 }
45 }
46
47 pub fn with_label_format(mut self, fmt: Option<&'a str>) -> Self {
50 self.label_fmt = fmt;
51 self
52 }
53
54 pub fn with_start_angle(mut self, angle: f64) -> Self {
56 self.angle0 = angle;
57 self
58 }
59
60 pub fn with_flags(mut self, flags: PieChartFlags) -> Self {
62 self.flags = flags;
63 self
64 }
65
66 pub fn normalize(mut self) -> Self {
68 self.flags |= PieChartFlags::NORMALIZE;
69 self
70 }
71
72 pub fn ignore_hidden(mut self) -> Self {
74 self.flags |= PieChartFlags::IGNORE_HIDDEN;
75 self
76 }
77
78 pub fn exploding(mut self) -> Self {
80 self.flags |= PieChartFlags::EXPLODING;
81 self
82 }
83
84 pub fn validate(&self) -> Result<(), PlotError> {
86 if self.values.is_empty() {
87 return Err(PlotError::EmptyData);
88 }
89
90 if self.label_ids.len() != self.values.len() {
91 return Err(PlotError::DataLengthMismatch {
92 x_len: self.label_ids.len(),
93 y_len: self.values.len(),
94 });
95 }
96
97 if self.radius <= 0.0 {
98 return Err(PlotError::InvalidData(
99 "Radius must be positive".to_string(),
100 ));
101 }
102
103 if self.values.iter().any(|&v| v < 0.0) {
105 return Err(PlotError::InvalidData(
106 "Pie chart values cannot be negative".to_string(),
107 ));
108 }
109
110 Ok(())
111 }
112}
113
114impl<'a> Plot for PieChartPlot<'a> {
115 fn plot(&self) {
116 if self.validate().is_err() {
117 return;
118 }
119
120 let label_cstrs: Vec<_> = self
122 .label_ids
123 .iter()
124 .map(|&label| safe_cstring(label))
125 .collect();
126
127 let label_ptrs: Vec<*const std::os::raw::c_char> =
129 label_cstrs.iter().map(|cstr| cstr.as_ptr()).collect();
130
131 let label_fmt_cstr = self.label_fmt.map(safe_cstring);
132 let label_fmt_ptr = label_fmt_cstr
133 .as_ref()
134 .map(|cstr| cstr.as_ptr())
135 .unwrap_or(std::ptr::null());
136
137 unsafe {
138 sys::ImPlot_PlotPieChart_doublePtrStr(
139 label_ptrs.as_ptr(),
140 self.values.as_ptr(),
141 self.values.len() as i32,
142 self.center_x,
143 self.center_y,
144 self.radius,
145 label_fmt_ptr,
146 self.angle0,
147 self.flags.bits() as i32,
148 );
149 }
150 }
151
152 fn label(&self) -> &str {
153 "PieChart" }
155}
156
157pub struct PieChartPlotF32<'a> {
159 label_ids: Vec<&'a str>,
160 values: &'a [f32],
161 center_x: f64,
162 center_y: f64,
163 radius: f64,
164 label_fmt: Option<&'a str>,
165 angle0: f64,
166 flags: PieChartFlags,
167}
168
169impl<'a> PieChartPlotF32<'a> {
170 pub fn new(
172 label_ids: Vec<&'a str>,
173 values: &'a [f32],
174 center_x: f64,
175 center_y: f64,
176 radius: f64,
177 ) -> Self {
178 Self {
179 label_ids,
180 values,
181 center_x,
182 center_y,
183 radius,
184 label_fmt: Some("%.1f"),
185 angle0: 90.0,
186 flags: PieChartFlags::NONE,
187 }
188 }
189
190 pub fn with_label_format(mut self, fmt: Option<&'a str>) -> Self {
192 self.label_fmt = fmt;
193 self
194 }
195
196 pub fn with_start_angle(mut self, angle: f64) -> Self {
198 self.angle0 = angle;
199 self
200 }
201
202 pub fn with_flags(mut self, flags: PieChartFlags) -> Self {
204 self.flags = flags;
205 self
206 }
207
208 pub fn normalize(mut self) -> Self {
210 self.flags |= PieChartFlags::NORMALIZE;
211 self
212 }
213
214 pub fn ignore_hidden(mut self) -> Self {
216 self.flags |= PieChartFlags::IGNORE_HIDDEN;
217 self
218 }
219
220 pub fn exploding(mut self) -> Self {
222 self.flags |= PieChartFlags::EXPLODING;
223 self
224 }
225
226 pub fn validate(&self) -> Result<(), PlotError> {
228 if self.values.is_empty() {
229 return Err(PlotError::EmptyData);
230 }
231
232 if self.label_ids.len() != self.values.len() {
233 return Err(PlotError::DataLengthMismatch {
234 x_len: self.label_ids.len(),
235 y_len: self.values.len(),
236 });
237 }
238
239 if self.radius <= 0.0 {
240 return Err(PlotError::InvalidData(
241 "Radius must be positive".to_string(),
242 ));
243 }
244
245 if self.values.iter().any(|&v| v < 0.0) {
246 return Err(PlotError::InvalidData(
247 "Pie chart values cannot be negative".to_string(),
248 ));
249 }
250
251 Ok(())
252 }
253}
254
255impl<'a> Plot for PieChartPlotF32<'a> {
256 fn plot(&self) {
257 if self.validate().is_err() {
258 return;
259 }
260
261 let label_cstrs: Vec<_> = self
262 .label_ids
263 .iter()
264 .map(|&label| safe_cstring(label))
265 .collect();
266
267 let label_ptrs: Vec<*const std::os::raw::c_char> =
268 label_cstrs.iter().map(|cstr| cstr.as_ptr()).collect();
269
270 let label_fmt_cstr = self.label_fmt.map(safe_cstring);
271 let label_fmt_ptr = label_fmt_cstr
272 .as_ref()
273 .map(|cstr| cstr.as_ptr())
274 .unwrap_or(std::ptr::null());
275
276 unsafe {
277 sys::ImPlot_PlotPieChart_FloatPtrStr(
278 label_ptrs.as_ptr(),
279 self.values.as_ptr(),
280 self.values.len() as i32,
281 self.center_x,
282 self.center_y,
283 self.radius,
284 label_fmt_ptr,
285 self.angle0,
286 self.flags.bits() as i32,
287 );
288 }
289 }
290
291 fn label(&self) -> &str {
292 "PieChart"
293 }
294}
295
296impl<'ui> crate::PlotUi<'ui> {
298 pub fn pie_chart_plot(
300 &self,
301 label_ids: Vec<&str>,
302 values: &[f64],
303 center_x: f64,
304 center_y: f64,
305 radius: f64,
306 ) -> Result<(), PlotError> {
307 let plot = PieChartPlot::new(label_ids, values, center_x, center_y, radius);
308 plot.validate()?;
309 plot.plot();
310 Ok(())
311 }
312
313 pub fn pie_chart_plot_f32(
315 &self,
316 label_ids: Vec<&str>,
317 values: &[f32],
318 center_x: f64,
319 center_y: f64,
320 radius: f64,
321 ) -> Result<(), PlotError> {
322 let plot = PieChartPlotF32::new(label_ids, values, center_x, center_y, radius);
323 plot.validate()?;
324 plot.plot();
325 Ok(())
326 }
327
328 pub fn centered_pie_chart(
330 &self,
331 label_ids: Vec<&str>,
332 values: &[f64],
333 ) -> Result<(), PlotError> {
334 let plot = PieChartPlot::new(label_ids, values, 0.5, 0.5, 0.4);
335 plot.validate()?;
336 plot.plot();
337 Ok(())
338 }
339}