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 unsafe fn setup_axis_links(
94 &self,
95 axis: Axis,
96 link_min: Option<&mut f64>,
97 link_max: Option<&mut f64>,
98 ) {
99 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
100 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
101 self.with_bound_context(|| unsafe { sys::ImPlot_SetupAxisLinks(axis.to_sys(), pmin, pmax) })
102 }
103
104 pub unsafe fn setup_axis_links_unchecked(
119 &self,
120 axis: sys::ImAxis,
121 link_min: Option<&mut f64>,
122 link_max: Option<&mut f64>,
123 ) {
124 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
125 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
126 self.with_bound_context(|| unsafe { sys::ImPlot_SetupAxisLinks(axis, pmin, pmax) })
127 }
128
129 pub fn setup_axes(
131 &self,
132 x_label: Option<&str>,
133 y_label: Option<&str>,
134 x_flags: AxisFlags,
135 y_flags: AxisFlags,
136 ) {
137 self.with_bound_context(|| {
138 let x_label = x_label.filter(|s| !s.contains('\0'));
139 let y_label = y_label.filter(|s| !s.contains('\0'));
140
141 match (x_label, y_label) {
142 (Some(x_label), Some(y_label)) => {
143 with_scratch_txt_two(x_label, y_label, |xp, yp| unsafe {
144 sys::ImPlot_SetupAxes(
145 xp,
146 yp,
147 x_flags.bits() as sys::ImPlotAxisFlags,
148 y_flags.bits() as sys::ImPlotAxisFlags,
149 )
150 })
151 }
152 (Some(x_label), None) => with_scratch_txt(x_label, |xp| unsafe {
153 sys::ImPlot_SetupAxes(
154 xp,
155 std::ptr::null(),
156 x_flags.bits() as sys::ImPlotAxisFlags,
157 y_flags.bits() as sys::ImPlotAxisFlags,
158 )
159 }),
160 (None, Some(y_label)) => with_scratch_txt(y_label, |yp| unsafe {
161 sys::ImPlot_SetupAxes(
162 std::ptr::null(),
163 yp,
164 x_flags.bits() as sys::ImPlotAxisFlags,
165 y_flags.bits() as sys::ImPlotAxisFlags,
166 )
167 }),
168 (None, None) => unsafe {
169 sys::ImPlot_SetupAxes(
170 std::ptr::null(),
171 std::ptr::null(),
172 x_flags.bits() as sys::ImPlotAxisFlags,
173 y_flags.bits() as sys::ImPlotAxisFlags,
174 )
175 },
176 }
177 })
178 }
179
180 pub fn setup_axes_limits(
182 &self,
183 x_min: f64,
184 x_max: f64,
185 y_min: f64,
186 y_max: f64,
187 cond: PlotCond,
188 ) {
189 assert_axis_limit_range("PlotUi::setup_axes_limits() x axis", x_min, x_max);
190 assert_axis_limit_range("PlotUi::setup_axes_limits() y axis", y_min, y_max);
191 self.with_bound_context(|| unsafe {
192 sys::ImPlot_SetupAxesLimits(x_min, x_max, y_min, y_max, cond as sys::ImPlotCond)
193 })
194 }
195
196 pub fn setup_finish(&self) {
198 self.with_bound_context(|| unsafe { sys::ImPlot_SetupFinish() })
199 }
200
201 pub fn set_next_x_axis_limits(&self, axis: XAxis, min: f64, max: f64, cond: PlotCond) {
203 assert_axis_limit_range("PlotUi::set_next_x_axis_limits()", min, max);
204 self.with_bound_context(|| unsafe {
205 sys::ImPlot_SetNextAxisLimits(axis as sys::ImAxis, min, max, cond as sys::ImPlotCond)
206 })
207 }
208
209 pub fn set_next_y_axis_limits(&self, axis: YAxis, min: f64, max: f64, cond: PlotCond) {
211 assert_axis_limit_range("PlotUi::set_next_y_axis_limits()", min, max);
212 self.with_bound_context(|| unsafe {
213 sys::ImPlot_SetNextAxisLimits(axis as sys::ImAxis, min, max, cond as sys::ImPlotCond)
214 })
215 }
216
217 pub unsafe fn set_next_axis_links(
237 &self,
238 axis: Axis,
239 link_min: Option<&mut f64>,
240 link_max: Option<&mut f64>,
241 ) {
242 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
243 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
244 self.with_bound_context(|| unsafe {
245 sys::ImPlot_SetNextAxisLinks(axis.to_sys(), pmin, pmax)
246 })
247 }
248
249 pub unsafe fn set_next_axis_links_unchecked(
264 &self,
265 axis: sys::ImAxis,
266 link_min: Option<&mut f64>,
267 link_max: Option<&mut f64>,
268 ) {
269 let pmin = link_min.map_or(std::ptr::null_mut(), |r| r as *mut f64);
270 let pmax = link_max.map_or(std::ptr::null_mut(), |r| r as *mut f64);
271 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisLinks(axis, pmin, pmax) })
272 }
273
274 pub fn set_next_axes_limits(
276 &self,
277 x_min: f64,
278 x_max: f64,
279 y_min: f64,
280 y_max: f64,
281 cond: PlotCond,
282 ) {
283 assert_axis_limit_range("PlotUi::set_next_axes_limits() x axis", x_min, x_max);
284 assert_axis_limit_range("PlotUi::set_next_axes_limits() y axis", y_min, y_max);
285 self.with_bound_context(|| unsafe {
286 sys::ImPlot_SetNextAxesLimits(x_min, x_max, y_min, y_max, cond as sys::ImPlotCond)
287 })
288 }
289
290 pub fn set_next_axes_to_fit(&self) {
292 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxesToFit() })
293 }
294
295 pub fn set_next_axis_to_fit(&self, axis: Axis) {
297 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis.to_sys()) })
298 }
299
300 pub unsafe fn set_next_axis_to_fit_unchecked(&self, axis: sys::ImAxis) {
307 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis) })
308 }
309
310 pub fn set_next_x_axis_to_fit(&self, axis: XAxis) {
312 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis as sys::ImAxis) })
313 }
314
315 pub fn set_next_y_axis_to_fit(&self, axis: YAxis) {
317 self.with_bound_context(|| unsafe { sys::ImPlot_SetNextAxisToFit(axis as sys::ImAxis) })
318 }
319
320 pub fn setup_x_axis_ticks_positions(
324 &self,
325 axis: XAxis,
326 values: &[f64],
327 labels: Option<&[&str]>,
328 keep_default: bool,
329 ) {
330 assert_finite_f64_slice("PlotUi::setup_x_axis_ticks_positions()", "values", values);
331 self.with_bound_context(|| {
332 let count = match i32::try_from(values.len()) {
333 Ok(v) => v,
334 Err(_) => return,
335 };
336 if let Some(labels) = labels {
337 if labels.len() != values.len() {
338 return;
339 }
340 let cleaned: Vec<&str> = labels
341 .iter()
342 .map(|&s| if s.contains('\0') { "" } else { s })
343 .collect();
344 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
345 sys::ImPlot_SetupAxisTicks_doublePtr(
346 axis as sys::ImAxis,
347 values.as_ptr(),
348 count,
349 ptrs.as_ptr() as *const *const c_char,
350 keep_default,
351 )
352 })
353 } else {
354 unsafe {
355 sys::ImPlot_SetupAxisTicks_doublePtr(
356 axis as sys::ImAxis,
357 values.as_ptr(),
358 count,
359 std::ptr::null(),
360 keep_default,
361 )
362 }
363 }
364 })
365 }
366
367 pub fn setup_y_axis_ticks_positions(
371 &self,
372 axis: YAxis,
373 values: &[f64],
374 labels: Option<&[&str]>,
375 keep_default: bool,
376 ) {
377 assert_finite_f64_slice("PlotUi::setup_y_axis_ticks_positions()", "values", values);
378 self.with_bound_context(|| {
379 let count = match i32::try_from(values.len()) {
380 Ok(v) => v,
381 Err(_) => return,
382 };
383 if let Some(labels) = labels {
384 if labels.len() != values.len() {
385 return;
386 }
387 let cleaned: Vec<&str> = labels
388 .iter()
389 .map(|&s| if s.contains('\0') { "" } else { s })
390 .collect();
391 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
392 sys::ImPlot_SetupAxisTicks_doublePtr(
393 axis as sys::ImAxis,
394 values.as_ptr(),
395 count,
396 ptrs.as_ptr() as *const *const c_char,
397 keep_default,
398 )
399 })
400 } else {
401 unsafe {
402 sys::ImPlot_SetupAxisTicks_doublePtr(
403 axis as sys::ImAxis,
404 values.as_ptr(),
405 count,
406 std::ptr::null(),
407 keep_default,
408 )
409 }
410 }
411 })
412 }
413
414 pub fn setup_x_axis_ticks_range(
418 &self,
419 axis: XAxis,
420 v_min: f64,
421 v_max: f64,
422 n_ticks: usize,
423 labels: Option<&[&str]>,
424 keep_default: bool,
425 ) {
426 assert_axis_limit_range("PlotUi::setup_x_axis_ticks_range()", v_min, v_max);
427 let n_ticks_i32 = axis_tick_count_to_i32("PlotUi::setup_x_axis_ticks_range()", n_ticks);
428 self.with_bound_context(|| {
429 if let Some(labels) = labels {
430 if labels.len() != n_ticks {
431 return;
432 }
433 let cleaned: Vec<&str> = labels
434 .iter()
435 .map(|&s| if s.contains('\0') { "" } else { s })
436 .collect();
437 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
438 sys::ImPlot_SetupAxisTicks_double(
439 axis as sys::ImAxis,
440 v_min,
441 v_max,
442 n_ticks_i32,
443 ptrs.as_ptr() as *const *const c_char,
444 keep_default,
445 )
446 })
447 } else {
448 unsafe {
449 sys::ImPlot_SetupAxisTicks_double(
450 axis as sys::ImAxis,
451 v_min,
452 v_max,
453 n_ticks_i32,
454 std::ptr::null(),
455 keep_default,
456 )
457 }
458 }
459 })
460 }
461
462 pub fn setup_y_axis_ticks_range(
466 &self,
467 axis: YAxis,
468 v_min: f64,
469 v_max: f64,
470 n_ticks: usize,
471 labels: Option<&[&str]>,
472 keep_default: bool,
473 ) {
474 assert_axis_limit_range("PlotUi::setup_y_axis_ticks_range()", v_min, v_max);
475 let n_ticks_i32 = axis_tick_count_to_i32("PlotUi::setup_y_axis_ticks_range()", n_ticks);
476 self.with_bound_context(|| {
477 if let Some(labels) = labels {
478 if labels.len() != n_ticks {
479 return;
480 }
481 let cleaned: Vec<&str> = labels
482 .iter()
483 .map(|&s| if s.contains('\0') { "" } else { s })
484 .collect();
485 with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
486 sys::ImPlot_SetupAxisTicks_double(
487 axis as sys::ImAxis,
488 v_min,
489 v_max,
490 n_ticks_i32,
491 ptrs.as_ptr() as *const *const c_char,
492 keep_default,
493 )
494 })
495 } else {
496 unsafe {
497 sys::ImPlot_SetupAxisTicks_double(
498 axis as sys::ImAxis,
499 v_min,
500 v_max,
501 n_ticks_i32,
502 std::ptr::null(),
503 keep_default,
504 )
505 }
506 }
507 })
508 }
509
510 pub fn setup_x_axis_format(&self, axis: XAxis, format: &AxisFormat<'_>) {
512 self.with_bound_context(|| {
513 with_scratch_txt(format.as_str(), |ptr| unsafe {
514 sys::ImPlot_SetupAxisFormat_Str(axis as sys::ImAxis, ptr)
515 })
516 })
517 }
518
519 pub fn setup_y_axis_format(&self, axis: YAxis, format: &AxisFormat<'_>) {
521 self.with_bound_context(|| {
522 with_scratch_txt(format.as_str(), |ptr| unsafe {
523 sys::ImPlot_SetupAxisFormat_Str(axis as sys::ImAxis, ptr)
524 })
525 })
526 }
527
528 pub fn setup_x_axis_scale(&self, axis: XAxis, scale: sys::ImPlotScale) {
530 self.with_bound_context(|| unsafe {
531 sys::ImPlot_SetupAxisScale_PlotScale(axis as sys::ImAxis, scale)
532 })
533 }
534
535 pub fn setup_y_axis_scale(&self, axis: YAxis, scale: sys::ImPlotScale) {
537 self.with_bound_context(|| unsafe {
538 sys::ImPlot_SetupAxisScale_PlotScale(axis as sys::ImAxis, scale)
539 })
540 }
541
542 pub fn setup_axis_limits_constraints(&self, axis: Axis, v_min: f64, v_max: f64) {
544 assert_axis_constraint_range("PlotUi::setup_axis_limits_constraints()", v_min, v_max);
545 self.with_bound_context(|| unsafe {
546 sys::ImPlot_SetupAxisLimitsConstraints(axis.to_sys(), v_min, v_max)
547 })
548 }
549
550 pub unsafe fn setup_axis_limits_constraints_unchecked(
557 &self,
558 axis: sys::ImAxis,
559 v_min: f64,
560 v_max: f64,
561 ) {
562 assert_axis_constraint_range(
563 "PlotUi::setup_axis_limits_constraints_unchecked()",
564 v_min,
565 v_max,
566 );
567 self.with_bound_context(|| unsafe {
568 sys::ImPlot_SetupAxisLimitsConstraints(axis, v_min, v_max)
569 })
570 }
571
572 pub fn setup_axis_zoom_constraints(&self, axis: Axis, z_min: f64, z_max: f64) {
574 assert_axis_zoom_range("PlotUi::setup_axis_zoom_constraints()", z_min, z_max);
575 self.with_bound_context(|| unsafe {
576 sys::ImPlot_SetupAxisZoomConstraints(axis.to_sys(), z_min, z_max)
577 })
578 }
579
580 pub unsafe fn setup_axis_zoom_constraints_unchecked(
587 &self,
588 axis: sys::ImAxis,
589 z_min: f64,
590 z_max: f64,
591 ) {
592 assert_axis_zoom_range(
593 "PlotUi::setup_axis_zoom_constraints_unchecked()",
594 z_min,
595 z_max,
596 );
597 self.with_bound_context(|| unsafe {
598 sys::ImPlot_SetupAxisZoomConstraints(axis, z_min, z_max)
599 })
600 }
601}