1use 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
18pub 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 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
130impl<'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 #[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}