1use super::ui::PlotUi;
2use super::validation::{
3 assert_axis_constraint_range, assert_axis_limit_range, assert_axis_zoom_range,
4 assert_finite_f64_slice, axis_tick_count_to_i32,
5};
6use crate::{Axis, AxisFlags, AxisFormat, PlotCond, XAxis, YAxis, sys};
7use dear_imgui_rs::{with_scratch_txt, with_scratch_txt_slice, with_scratch_txt_two};
8use std::os::raw::c_char;
9
10impl<'ui> PlotUi<'ui> {
11 pub fn setup_x_axis(&self, axis: XAxis, label: Option<&str>, flags: AxisFlags) {
13 self.with_bound_context(|| {
14 let label = label.filter(|s| !s.contains('\0'));
15 match label {
16 Some(label) => with_scratch_txt(label, |ptr| unsafe {
17 sys::ImPlot_SetupAxis(
18 axis as sys::ImAxis,
19 ptr,
20 flags.bits() as sys::ImPlotAxisFlags,
21 )
22 }),
23 None => unsafe {
24 sys::ImPlot_SetupAxis(
25 axis as sys::ImAxis,
26 std::ptr::null(),
27 flags.bits() as sys::ImPlotAxisFlags,
28 )
29 },
30 }
31 })
32 }
33
34 pub fn setup_y_axis(&self, axis: YAxis, label: Option<&str>, flags: AxisFlags) {
36 self.with_bound_context(|| {
37 let label = label.filter(|s| !s.contains('\0'));
38 match label {
39 Some(label) => with_scratch_txt(label, |ptr| unsafe {
40 sys::ImPlot_SetupAxis(
41 axis as sys::ImAxis,
42 ptr,
43 flags.bits() as sys::ImPlotAxisFlags,
44 )
45 }),
46 None => unsafe {
47 sys::ImPlot_SetupAxis(
48 axis as sys::ImAxis,
49 std::ptr::null(),
50 flags.bits() as sys::ImPlotAxisFlags,
51 )
52 },
53 }
54 })
55 }
56
57 pub fn setup_x_axis_limits(&self, axis: XAxis, min: f64, max: f64, cond: PlotCond) {
59 assert_axis_limit_range("PlotUi::setup_x_axis_limits()", min, max);
60 self.with_bound_context(|| unsafe {
61 sys::ImPlot_SetupAxisLimits(axis as sys::ImAxis, min, max, cond as sys::ImPlotCond)
62 })
63 }
64
65 pub fn setup_y_axis_limits(&self, axis: YAxis, min: f64, max: f64, cond: PlotCond) {
67 assert_axis_limit_range("PlotUi::setup_y_axis_limits()", min, max);
68 self.with_bound_context(|| unsafe {
69 sys::ImPlot_SetupAxisLimits(axis as sys::ImAxis, min, max, cond as sys::ImPlotCond)
70 })
71 }
72
73 pub fn setup_axis_links(
75 &self,
76 axis: Axis,
77 link_min: Option<&mut f64>,
78 link_max: Option<&mut f64>,
79 ) {
80 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
81 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
82 self.with_bound_context(|| unsafe { sys::ImPlot_SetupAxisLinks(axis.to_sys(), pmin, pmax) })
83 }
84
85 pub unsafe fn setup_axis_links_unchecked(
92 &self,
93 axis: sys::ImAxis,
94 link_min: Option<&mut f64>,
95 link_max: Option<&mut f64>,
96 ) {
97 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
98 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
99 self.with_bound_context(|| unsafe { sys::ImPlot_SetupAxisLinks(axis, pmin, pmax) })
100 }
101
102 pub fn setup_axes(
104 &self,
105 x_label: Option<&str>,
106 y_label: Option<&str>,
107 x_flags: AxisFlags,
108 y_flags: AxisFlags,
109 ) {
110 self.with_bound_context(|| {
111 let x_label = x_label.filter(|s| !s.contains('\0'));
112 let y_label = y_label.filter(|s| !s.contains('\0'));
113
114 match (x_label, y_label) {
115 (Some(x_label), Some(y_label)) => {
116 with_scratch_txt_two(x_label, y_label, |xp, yp| unsafe {
117 sys::ImPlot_SetupAxes(
118 xp,
119 yp,
120 x_flags.bits() as sys::ImPlotAxisFlags,
121 y_flags.bits() as sys::ImPlotAxisFlags,
122 )
123 })
124 }
125 (Some(x_label), None) => with_scratch_txt(x_label, |xp| unsafe {
126 sys::ImPlot_SetupAxes(
127 xp,
128 std::ptr::null(),
129 x_flags.bits() as sys::ImPlotAxisFlags,
130 y_flags.bits() as sys::ImPlotAxisFlags,
131 )
132 }),
133 (None, Some(y_label)) => with_scratch_txt(y_label, |yp| unsafe {
134 sys::ImPlot_SetupAxes(
135 std::ptr::null(),
136 yp,
137 x_flags.bits() as sys::ImPlotAxisFlags,
138 y_flags.bits() as sys::ImPlotAxisFlags,
139 )
140 }),
141 (None, None) => unsafe {
142 sys::ImPlot_SetupAxes(
143 std::ptr::null(),
144 std::ptr::null(),
145 x_flags.bits() as sys::ImPlotAxisFlags,
146 y_flags.bits() as sys::ImPlotAxisFlags,
147 )
148 },
149 }
150 })
151 }
152
153 pub fn setup_axes_limits(
155 &self,
156 x_min: f64,
157 x_max: f64,
158 y_min: f64,
159 y_max: f64,
160 cond: PlotCond,
161 ) {
162 assert_axis_limit_range("PlotUi::setup_axes_limits() x axis", x_min, x_max);
163 assert_axis_limit_range("PlotUi::setup_axes_limits() y axis", y_min, y_max);
164 self.with_bound_context(|| unsafe {
165 sys::ImPlot_SetupAxesLimits(x_min, x_max, y_min, y_max, cond as sys::ImPlotCond)
166 })
167 }
168
169 pub fn setup_finish(&self) {
171 self.with_bound_context(|| unsafe { sys::ImPlot_SetupFinish() })
172 }
173
174 pub fn set_next_x_axis_limits(&self, axis: XAxis, min: f64, max: f64, cond: PlotCond) {
176 assert_axis_limit_range("PlotUi::set_next_x_axis_limits()", min, max);
177 self.with_bound_context(|| unsafe {
178 sys::ImPlot_SetNextAxisLimits(axis as sys::ImAxis, min, max, cond as sys::ImPlotCond)
179 })
180 }
181
182 pub fn set_next_y_axis_limits(&self, axis: YAxis, min: f64, max: f64, cond: PlotCond) {
184 assert_axis_limit_range("PlotUi::set_next_y_axis_limits()", min, max);
185 self.with_bound_context(|| unsafe {
186 sys::ImPlot_SetNextAxisLimits(axis as sys::ImAxis, min, max, cond as sys::ImPlotCond)
187 })
188 }
189
190 pub fn set_next_axis_links(
192 &self,
193 axis: Axis,
194 link_min: Option<&mut f64>,
195 link_max: Option<&mut f64>,
196 ) {
197 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
198 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
199 self.with_bound_context(|| unsafe {
200 sys::ImPlot_SetNextAxisLinks(axis.to_sys(), pmin, pmax)
201 })
202 }
203
204 pub unsafe fn set_next_axis_links_unchecked(
211 &self,
212 axis: sys::ImAxis,
213 link_min: Option<&mut f64>,
214 link_max: Option<&mut f64>,
215 ) {
216 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
217 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
218 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisLinks(axis, pmin, pmax) })
219 }
220
221 pub fn set_next_axes_limits(
223 &self,
224 x_min: f64,
225 x_max: f64,
226 y_min: f64,
227 y_max: f64,
228 cond: PlotCond,
229 ) {
230 assert_axis_limit_range("PlotUi::set_next_axes_limits() x axis", x_min, x_max);
231 assert_axis_limit_range("PlotUi::set_next_axes_limits() y axis", y_min, y_max);
232 self.with_bound_context(|| unsafe {
233 sys::ImPlot_SetNextAxesLimits(x_min, x_max, y_min, y_max, cond as sys::ImPlotCond)
234 })
235 }
236
237 pub fn set_next_axes_to_fit(&self) {
239 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxesToFit() })
240 }
241
242 pub fn set_next_axis_to_fit(&self, axis: Axis) {
244 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis.to_sys()) })
245 }
246
247 pub unsafe fn set_next_axis_to_fit_unchecked(&self, axis: sys::ImAxis) {
254 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis) })
255 }
256
257 pub fn set_next_x_axis_to_fit(&self, axis: XAxis) {
259 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis as sys::ImAxis) })
260 }
261
262 pub fn set_next_y_axis_to_fit(&self, axis: YAxis) {
264 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis as sys::ImAxis) })
265 }
266
267 pub fn setup_x_axis_ticks_positions(
271 &self,
272 axis: XAxis,
273 values: &[f64],
274 labels: Option<&[&str]>,
275 keep_default: bool,
276 ) {
277 assert_finite_f64_slice("PlotUi::setup_x_axis_ticks_positions()", "values", values);
278 self.with_bound_context(|| {
279 let count = match i32::try_from(values.len()) {
280 Ok(v) => v,
281 Err(_) => return,
282 };
283 if let Some(labels) = labels {
284 if labels.len() != values.len() {
285 return;
286 }
287 let cleaned: Vec<&str> = labels
288 .iter()
289 .map(|&s| if s.contains('\0') { "" } else { s })
290 .collect();
291 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
292 sys::ImPlot_SetupAxisTicks_doublePtr(
293 axis as sys::ImAxis,
294 values.as_ptr(),
295 count,
296 ptrs.as_ptr() as *const *const c_char,
297 keep_default,
298 )
299 })
300 } else {
301 unsafe {
302 sys::ImPlot_SetupAxisTicks_doublePtr(
303 axis as sys::ImAxis,
304 values.as_ptr(),
305 count,
306 std::ptr::null(),
307 keep_default,
308 )
309 }
310 }
311 })
312 }
313
314 pub fn setup_y_axis_ticks_positions(
318 &self,
319 axis: YAxis,
320 values: &[f64],
321 labels: Option<&[&str]>,
322 keep_default: bool,
323 ) {
324 assert_finite_f64_slice("PlotUi::setup_y_axis_ticks_positions()", "values", values);
325 self.with_bound_context(|| {
326 let count = match i32::try_from(values.len()) {
327 Ok(v) => v,
328 Err(_) => return,
329 };
330 if let Some(labels) = labels {
331 if labels.len() != values.len() {
332 return;
333 }
334 let cleaned: Vec<&str> = labels
335 .iter()
336 .map(|&s| if s.contains('\0') { "" } else { s })
337 .collect();
338 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
339 sys::ImPlot_SetupAxisTicks_doublePtr(
340 axis as sys::ImAxis,
341 values.as_ptr(),
342 count,
343 ptrs.as_ptr() as *const *const c_char,
344 keep_default,
345 )
346 })
347 } else {
348 unsafe {
349 sys::ImPlot_SetupAxisTicks_doublePtr(
350 axis as sys::ImAxis,
351 values.as_ptr(),
352 count,
353 std::ptr::null(),
354 keep_default,
355 )
356 }
357 }
358 })
359 }
360
361 pub fn setup_x_axis_ticks_range(
365 &self,
366 axis: XAxis,
367 v_min: f64,
368 v_max: f64,
369 n_ticks: usize,
370 labels: Option<&[&str]>,
371 keep_default: bool,
372 ) {
373 assert_axis_limit_range("PlotUi::setup_x_axis_ticks_range()", v_min, v_max);
374 let n_ticks_i32 = axis_tick_count_to_i32("PlotUi::setup_x_axis_ticks_range()", n_ticks);
375 self.with_bound_context(|| {
376 if let Some(labels) = labels {
377 if labels.len() != n_ticks {
378 return;
379 }
380 let cleaned: Vec<&str> = labels
381 .iter()
382 .map(|&s| if s.contains('\0') { "" } else { s })
383 .collect();
384 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
385 sys::ImPlot_SetupAxisTicks_double(
386 axis as sys::ImAxis,
387 v_min,
388 v_max,
389 n_ticks_i32,
390 ptrs.as_ptr() as *const *const c_char,
391 keep_default,
392 )
393 })
394 } else {
395 unsafe {
396 sys::ImPlot_SetupAxisTicks_double(
397 axis as sys::ImAxis,
398 v_min,
399 v_max,
400 n_ticks_i32,
401 std::ptr::null(),
402 keep_default,
403 )
404 }
405 }
406 })
407 }
408
409 pub fn setup_y_axis_ticks_range(
413 &self,
414 axis: YAxis,
415 v_min: f64,
416 v_max: f64,
417 n_ticks: usize,
418 labels: Option<&[&str]>,
419 keep_default: bool,
420 ) {
421 assert_axis_limit_range("PlotUi::setup_y_axis_ticks_range()", v_min, v_max);
422 let n_ticks_i32 = axis_tick_count_to_i32("PlotUi::setup_y_axis_ticks_range()", n_ticks);
423 self.with_bound_context(|| {
424 if let Some(labels) = labels {
425 if labels.len() != n_ticks {
426 return;
427 }
428 let cleaned: Vec<&str> = labels
429 .iter()
430 .map(|&s| if s.contains('\0') { "" } else { s })
431 .collect();
432 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
433 sys::ImPlot_SetupAxisTicks_double(
434 axis as sys::ImAxis,
435 v_min,
436 v_max,
437 n_ticks_i32,
438 ptrs.as_ptr() as *const *const c_char,
439 keep_default,
440 )
441 })
442 } else {
443 unsafe {
444 sys::ImPlot_SetupAxisTicks_double(
445 axis as sys::ImAxis,
446 v_min,
447 v_max,
448 n_ticks_i32,
449 std::ptr::null(),
450 keep_default,
451 )
452 }
453 }
454 })
455 }
456
457 pub fn setup_x_axis_format(&self, axis: XAxis, format: &AxisFormat<'_>) {
459 self.with_bound_context(|| {
460 with_scratch_txt(format.as_str(), |ptr| unsafe {
461 sys::ImPlot_SetupAxisFormat_Str(axis as sys::ImAxis, ptr)
462 })
463 })
464 }
465
466 pub fn setup_y_axis_format(&self, axis: YAxis, format: &AxisFormat<'_>) {
468 self.with_bound_context(|| {
469 with_scratch_txt(format.as_str(), |ptr| unsafe {
470 sys::ImPlot_SetupAxisFormat_Str(axis as sys::ImAxis, ptr)
471 })
472 })
473 }
474
475 pub fn setup_x_axis_scale(&self, axis: XAxis, scale: sys::ImPlotScale) {
477 self.with_bound_context(|| unsafe {
478 sys::ImPlot_SetupAxisScale_PlotScale(axis as sys::ImAxis, scale)
479 })
480 }
481
482 pub fn setup_y_axis_scale(&self, axis: YAxis, scale: sys::ImPlotScale) {
484 self.with_bound_context(|| unsafe {
485 sys::ImPlot_SetupAxisScale_PlotScale(axis as sys::ImAxis, scale)
486 })
487 }
488
489 pub fn setup_axis_limits_constraints(&self, axis: Axis, v_min: f64, v_max: f64) {
491 assert_axis_constraint_range("PlotUi::setup_axis_limits_constraints()", v_min, v_max);
492 self.with_bound_context(|| unsafe {
493 sys::ImPlot_SetupAxisLimitsConstraints(axis.to_sys(), v_min, v_max)
494 })
495 }
496
497 pub unsafe fn setup_axis_limits_constraints_unchecked(
504 &self,
505 axis: sys::ImAxis,
506 v_min: f64,
507 v_max: f64,
508 ) {
509 assert_axis_constraint_range(
510 "PlotUi::setup_axis_limits_constraints_unchecked()",
511 v_min,
512 v_max,
513 );
514 self.with_bound_context(|| unsafe {
515 sys::ImPlot_SetupAxisLimitsConstraints(axis, v_min, v_max)
516 })
517 }
518
519 pub fn setup_axis_zoom_constraints(&self, axis: Axis, z_min: f64, z_max: f64) {
521 assert_axis_zoom_range("PlotUi::setup_axis_zoom_constraints()", z_min, z_max);
522 self.with_bound_context(|| unsafe {
523 sys::ImPlot_SetupAxisZoomConstraints(axis.to_sys(), z_min, z_max)
524 })
525 }
526
527 pub unsafe fn setup_axis_zoom_constraints_unchecked(
534 &self,
535 axis: sys::ImAxis,
536 z_min: f64,
537 z_max: f64,
538 ) {
539 assert_axis_zoom_range(
540 "PlotUi::setup_axis_zoom_constraints_unchecked()",
541 z_min,
542 z_max,
543 );
544 self.with_bound_context(|| unsafe {
545 sys::ImPlot_SetupAxisZoomConstraints(axis, z_min, z_max)
546 })
547 }
548}