Skip to main content

dear_implot/plots/
image.rs

1//! Image plot implementation
2
3use super::{
4    Plot, PlotDataLayout, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_or_empty,
5};
6use crate::{ImageFlags, ItemFlags, sys};
7use dear_imgui_rs::texture::TextureRef;
8
9fn to_sys_texture_ref(ui: &dear_imgui_rs::Ui, texture: TextureRef<'_>) -> sys::ImTextureRef_c {
10    let texture = unsafe { ui.resolve_texture_ref_raw(texture) }
11        .unwrap_or_else(|error| panic!("ImagePlot rejected texture: {error}"));
12    sys::ImTextureRef_c {
13        _TexData: texture._TexData as *mut sys::ImTextureData,
14        _TexID: texture._TexID as sys::ImTextureID,
15    }
16}
17
18/// Plot an image in plot coordinates using an ImGui texture reference.
19pub struct ImagePlot<'a, 'tex> {
20    label: &'a str,
21    texture: TextureRef<'tex>,
22    bounds_min: sys::ImPlotPoint,
23    bounds_max: sys::ImPlotPoint,
24    uv0: [f32; 2],
25    uv1: [f32; 2],
26    tint: [f32; 4],
27    style: PlotItemStyle,
28    flags: ImageFlags,
29    item_flags: ItemFlags,
30}
31
32impl<'a, 'tex> super::PlotItemStyled for ImagePlot<'a, 'tex> {
33    fn style_mut(&mut self) -> &mut PlotItemStyle {
34        &mut self.style
35    }
36}
37
38impl<'a, 'tex> ImagePlot<'a, 'tex> {
39    pub fn new(
40        label: &'a str,
41        texture: impl Into<TextureRef<'tex>>,
42        bounds_min: sys::ImPlotPoint,
43        bounds_max: sys::ImPlotPoint,
44    ) -> Self {
45        Self {
46            label,
47            texture: texture.into(),
48            bounds_min,
49            bounds_max,
50            uv0: [0.0, 0.0],
51            uv1: [1.0, 1.0],
52            tint: [1.0, 1.0, 1.0, 1.0],
53            style: PlotItemStyle::default(),
54            flags: ImageFlags::NONE,
55            item_flags: ItemFlags::NONE,
56        }
57    }
58
59    pub fn with_uv(mut self, uv0: [f32; 2], uv1: [f32; 2]) -> Self {
60        self.uv0 = uv0;
61        self.uv1 = uv1;
62        self
63    }
64    pub fn with_tint(mut self, tint: [f32; 4]) -> Self {
65        self.tint = tint;
66        self
67    }
68    pub fn with_flags(mut self, flags: ImageFlags) -> Self {
69        self.flags = flags;
70        self
71    }
72
73    /// Set common item flags for this plot item (applies to all plot types)
74    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
75        self.item_flags = flags;
76        self
77    }
78
79    pub fn validate(&self) -> Result<(), PlotError> {
80        Ok(())
81    }
82}
83
84impl<'a, 'tex> Plot for ImagePlot<'a, 'tex> {
85    fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
86        if self.validate().is_err() {
87            return;
88        }
89        let uv0 = sys::ImVec2_c {
90            x: self.uv0[0],
91            y: self.uv0[1],
92        };
93        let uv1 = sys::ImVec2_c {
94            x: self.uv1[0],
95            y: self.uv1[1],
96        };
97        let tint = sys::ImVec4_c {
98            x: self.tint[0],
99            y: self.tint[1],
100            z: self.tint[2],
101            w: self.tint[3],
102        };
103        plot_ui.with_bound_context(|| {
104            let tex_ref = to_sys_texture_ref(plot_ui.ui, self.texture);
105            with_plot_str_or_empty(self.label, |label_ptr| unsafe {
106                let spec = plot_spec_with_style(
107                    self.style,
108                    self.flags.bits() | self.item_flags.bits(),
109                    PlotDataLayout::DEFAULT,
110                );
111                sys::ImPlot_PlotImage(
112                    label_ptr,
113                    tex_ref,
114                    self.bounds_min,
115                    self.bounds_max,
116                    uv0,
117                    uv1,
118                    tint,
119                    spec,
120                )
121            })
122        })
123    }
124
125    fn label(&self) -> &str {
126        self.label
127    }
128}
129
130/// Convenience methods on PlotUi
131impl<'ui> crate::PlotUi<'ui> {
132    pub fn plot_image<'tex>(
133        &self,
134        label: &str,
135        texture: impl Into<TextureRef<'tex>>,
136        bounds_min: sys::ImPlotPoint,
137        bounds_max: sys::ImPlotPoint,
138    ) -> Result<(), PlotError> {
139        let plot = ImagePlot::new(label, texture, bounds_min, bounds_max);
140        plot.validate()?;
141        plot.plot(self);
142        Ok(())
143    }
144
145    /// Plot an image using ImGui's TextureId wrapper (if available)
146    #[allow(unused_variables)]
147    pub fn plot_image_with_imgui_texture(
148        &self,
149        label: &str,
150        texture: dear_imgui_rs::TextureId,
151        bounds_min: sys::ImPlotPoint,
152        bounds_max: sys::ImPlotPoint,
153    ) -> Result<(), PlotError> {
154        self.plot_image(label, texture, bounds_min, bounds_max)
155    }
156}