Skip to main content

dear_implot3d/style/
colormap.rs

1use crate::sys;
2use crate::{Plot3DContext, Plot3DUi};
3
4use super::tokens::ColormapToken;
5use super::types::{ColormapColorIndex, ColormapIndex};
6use std::marker::PhantomData;
7
8impl<'ui> Plot3DUi<'ui> {
9    #[inline]
10    pub fn push_colormap(&self, cmap: impl Into<ColormapIndex>) -> ColormapToken<'_> {
11        let _guard = self.bind();
12        unsafe { sys::ImPlot3D_PushColormap_Plot3DColormap(cmap.into().raw()) }
13        ColormapToken {
14            binding: self.binding,
15            imgui_alive: self.imgui_alive.clone(),
16            was_popped: false,
17            _lifetime: PhantomData,
18            _not_send_or_sync: PhantomData,
19        }
20    }
21
22    #[inline]
23    pub fn push_colormap_name(&self, name: &str) -> ColormapToken<'_> {
24        assert!(!name.contains('\0'), "colormap name contained NUL");
25        let _guard = self.bind();
26        dear_imgui_rs::with_scratch_txt(name, |ptr| unsafe { sys::ImPlot3D_PushColormap_Str(ptr) });
27        ColormapToken {
28            binding: self.binding,
29            imgui_alive: self.imgui_alive.clone(),
30            was_popped: false,
31            _lifetime: PhantomData,
32            _not_send_or_sync: PhantomData,
33        }
34    }
35}
36
37pub(super) fn colormap_count_from_i32(raw: i32, caller: &str) -> usize {
38    assert!(raw >= 0, "{caller} returned a negative colormap count");
39    usize::try_from(raw).expect("non-negative colormap count must fit usize")
40}
41
42impl Plot3DContext {
43    #[inline]
44    fn with_bound_colormap<R>(&self, caller: &str, f: impl FnOnce() -> R) -> R {
45        self.assert_imgui_alive(caller);
46        let _guard = self.binding().bind();
47        f()
48    }
49
50    /// Return the number of available ImPlot3D colormaps.
51    #[inline]
52    pub fn colormap_count(&self) -> usize {
53        self.with_bound_colormap("dear-implot3d: Plot3DContext::colormap_count()", || {
54            colormap_count_from_i32(
55                unsafe { sys::ImPlot3D_GetColormapCount() },
56                "Plot3DContext::colormap_count()",
57            )
58        })
59    }
60
61    /// Return a colormap name, or an empty string if the index is invalid for this context.
62    #[inline]
63    pub fn colormap_name(&self, index: impl Into<ColormapIndex>) -> String {
64        self.with_bound_colormap("dear-implot3d: Plot3DContext::colormap_name()", || unsafe {
65            let p = sys::ImPlot3D_GetColormapName(index.into().raw());
66            if p.is_null() {
67                return String::new();
68            }
69            std::ffi::CStr::from_ptr(p).to_string_lossy().into_owned()
70        })
71    }
72
73    /// Return the number of color entries in a colormap.
74    #[inline]
75    pub fn colormap_size(&self, index: impl Into<ColormapIndex>) -> usize {
76        self.with_bound_colormap("dear-implot3d: Plot3DContext::colormap_size()", || {
77            colormap_count_from_i32(
78                unsafe { sys::ImPlot3D_GetColormapSize(index.into().raw()) },
79                "Plot3DContext::colormap_size()",
80            )
81        })
82    }
83
84    /// Return the default colormap stored in this ImPlot3D context's style.
85    #[inline]
86    pub fn style_colormap_index(&self) -> Option<ColormapIndex> {
87        self.with_bound_colormap(
88            "dear-implot3d: Plot3DContext::style_colormap_index()",
89            || unsafe {
90                let style = sys::ImPlot3D_GetStyle();
91                if style.is_null() {
92                    return None;
93                }
94                ColormapIndex::from_raw((*style).Colormap)
95            },
96        )
97    }
98
99    /// Return this context's default colormap name.
100    #[inline]
101    pub fn style_colormap_name(&self) -> Option<String> {
102        let idx = self.style_colormap_index()?;
103        let count = self.colormap_count();
104        if idx.get() >= count {
105            return None;
106        }
107        Some(self.colormap_name(idx))
108    }
109
110    /// Permanently set the default colormap used by this ImPlot3D context.
111    #[inline]
112    pub fn set_style_colormap(&self, index: impl Into<ColormapIndex>) {
113        self.with_bound_colormap(
114            "dear-implot3d: Plot3DContext::set_style_colormap()",
115            || unsafe {
116                let style = sys::ImPlot3D_GetStyle();
117                if !style.is_null() {
118                    let count = colormap_count_from_i32(
119                        sys::ImPlot3D_GetColormapCount(),
120                        "Plot3DContext::set_style_colormap()",
121                    );
122                    if count > 0 {
123                        let index = index.into().get();
124                        let idx = index.min(count - 1);
125                        (*style).Colormap = ColormapIndex::from(idx).raw();
126                    }
127                }
128            },
129        )
130    }
131
132    /// Look up a colormap index by its name.
133    #[inline]
134    pub fn colormap_index_by_name(&self, name: &str) -> Option<ColormapIndex> {
135        if name.contains('\0') {
136            return None;
137        }
138        let index = self.with_bound_colormap(
139            "dear-implot3d: Plot3DContext::colormap_index_by_name()",
140            || {
141                dear_imgui_rs::with_scratch_txt(name, |ptr| unsafe {
142                    sys::ImPlot3D_GetColormapIndex(ptr)
143                })
144            },
145        );
146        ColormapIndex::from_raw(index)
147    }
148
149    /// Permanently set the default colormap by name. Invalid names are ignored.
150    #[inline]
151    pub fn set_style_colormap_by_name(&self, name: &str) {
152        if let Some(idx) = self.colormap_index_by_name(name) {
153            self.set_style_colormap(idx);
154        }
155    }
156
157    /// Return a color from this context's active colormap.
158    pub fn colormap_color(&self, index: ColormapColorIndex) -> [f32; 4] {
159        self.with_bound_colormap(
160            "dear-implot3d: Plot3DContext::colormap_color()",
161            || unsafe {
162                let out = crate::compat_ffi::ImPlot3D_GetColormapColor(
163                    index.raw(),
164                    (-1) as sys::ImPlot3DColormap,
165                );
166                [out.x, out.y, out.z, out.w]
167            },
168        )
169    }
170
171    /// Return the next color from this context's current colormap and advance its color cursor.
172    pub fn next_colormap_color(&self) -> [f32; 4] {
173        self.with_bound_colormap(
174            "dear-implot3d: Plot3DContext::next_colormap_color()",
175            || unsafe {
176                let out = crate::compat_ffi::ImPlot3D_NextColormapColor();
177                [out.x, out.y, out.z, out.w]
178            },
179        )
180    }
181}
182
183impl Plot3DUi<'_> {
184    /// Return a color from this UI's active ImPlot3D colormap.
185    pub fn colormap_color(&self, index: ColormapColorIndex) -> [f32; 4] {
186        let _guard = self.bind();
187        unsafe {
188            let out = crate::compat_ffi::ImPlot3D_GetColormapColor(
189                index.raw(),
190                (-1) as sys::ImPlot3DColormap,
191            );
192            [out.x, out.y, out.z, out.w]
193        }
194    }
195
196    /// Return the next color from this UI's current colormap and advance its color cursor.
197    pub fn next_colormap_color(&self) -> [f32; 4] {
198        let _guard = self.bind();
199        unsafe {
200            let out = crate::compat_ffi::ImPlot3D_NextColormapColor();
201            [out.x, out.y, out.z, out.w]
202        }
203    }
204}