Skip to main content

dear_implot3d/
builder.rs

1use std::marker::PhantomData;
2
3use crate::ui::{Plot3DContextBinding, Plot3DToken};
4use crate::{Plot3DFlags, debug_begin_plot, imvec2, sys};
5use dear_imgui_rs::Ui;
6
7/// Plot builder for configuring the 3D plot
8pub struct Plot3DBuilder<'ui> {
9    pub(crate) binding: Plot3DContextBinding,
10    pub(crate) imgui_alive: Option<dear_imgui_rs::ContextAliveToken>,
11    pub(crate) title: String,
12    pub(crate) size: Option<[f32; 2]>,
13    pub(crate) flags: Plot3DFlags,
14    pub(crate) _lifetime: PhantomData<&'ui Ui>,
15}
16
17impl<'ui> Plot3DBuilder<'ui> {
18    pub fn size(mut self, size: [f32; 2]) -> Self {
19        self.size = Some(size);
20        self
21    }
22    pub fn flags(mut self, flags: Plot3DFlags) -> Self {
23        self.flags = flags;
24        self
25    }
26    pub fn build(self) -> Option<Plot3DToken<'ui>> {
27        if let Some(alive) = &self.imgui_alive {
28            assert!(
29                alive.is_alive(),
30                "dear-implot3d: ImGui context has been dropped"
31            );
32        }
33        self.binding.bind();
34        if self.title.contains('\0') {
35            return None;
36        }
37        let title = self.title;
38        let size = self.size.unwrap_or([0.0, 0.0]);
39        let ok = dear_imgui_rs::with_scratch_txt(&title, |title_ptr| unsafe {
40            // Defensive: ensure style.Colormap is in range before plotting
41            let style = sys::ImPlot3D_GetStyle();
42            if !style.is_null() {
43                let count = sys::ImPlot3D_GetColormapCount();
44                if count > 0 && ((*style).Colormap < 0 || (*style).Colormap >= count) {
45                    (*style).Colormap = 0;
46                }
47            }
48            sys::ImPlot3D_BeginPlot(
49                title_ptr,
50                imvec2(size[0], size[1]),
51                self.flags.bits() as i32,
52            )
53        });
54        if ok {
55            debug_begin_plot();
56            Some(Plot3DToken {
57                binding: self.binding,
58                imgui_alive: self.imgui_alive.clone(),
59                _lifetime: PhantomData,
60            })
61        } else {
62            None
63        }
64    }
65}