1use crate::sys;
19use crate::texture::TextureRef;
20use crate::ui::Ui;
21use crate::{StyleColor, StyleVar};
22use std::borrow::Cow;
23
24fn assert_non_negative_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
25 assert!(
26 value[0].is_finite() && value[1].is_finite(),
27 "{caller} {name} must contain finite values"
28 );
29 assert!(
30 value[0] >= 0.0 && value[1] >= 0.0,
31 "{caller} {name} must contain non-negative values"
32 );
33}
34
35fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
36 assert!(
37 value[0].is_finite() && value[1].is_finite(),
38 "{caller} {name} must contain finite values"
39 );
40}
41
42fn assert_finite_vec4(caller: &str, name: &str, value: [f32; 4]) {
43 assert!(
44 value.iter().all(|component| component.is_finite()),
45 "{caller} {name} must contain finite values"
46 );
47}
48
49fn is_default_tint_color(color: [f32; 4]) -> bool {
50 color == [1.0, 1.0, 1.0, 1.0]
51}
52
53fn is_transparent_color(color: [f32; 4]) -> bool {
54 color == [0.0, 0.0, 0.0, 0.0]
55}
56
57fn im_vec4(value: [f32; 4]) -> sys::ImVec4 {
58 sys::ImVec4 {
59 x: value[0],
60 y: value[1],
61 z: value[2],
62 w: value[3],
63 }
64}
65
66impl Ui {
87 #[doc(alias = "Image")]
89 pub fn image<'tex>(&self, texture: impl Into<TextureRef<'tex>>, size: [f32; 2]) {
90 self.image_config(texture, size).build()
91 }
92
93 #[doc(alias = "ImageButton")]
95 pub fn image_button<'tex>(
96 &self,
97 str_id: impl AsRef<str>,
98 texture: impl Into<TextureRef<'tex>>,
99 size: [f32; 2],
100 ) -> bool {
101 self.image_button_config(str_id.as_ref(), texture, size)
102 .build()
103 }
104
105 pub fn image_config<'ui, 'tex>(
107 &'ui self,
108 texture: impl Into<TextureRef<'tex>>,
109 size: [f32; 2],
110 ) -> Image<'ui, 'tex> {
111 Image::new(self, texture, size)
112 }
113
114 pub fn image_button_config<'ui, 'tex>(
116 &'ui self,
117 str_id: impl Into<Cow<'ui, str>>,
118 texture: impl Into<TextureRef<'tex>>,
119 size: [f32; 2],
120 ) -> ImageButton<'ui, 'tex> {
121 ImageButton::new(self, str_id, texture, size)
122 }
123}
124
125#[derive(Debug)]
127#[must_use]
128pub struct Image<'ui, 'tex> {
129 _ui: &'ui Ui,
130 texture: TextureRef<'tex>,
131 size: [f32; 2],
132 uv0: [f32; 2],
133 uv1: [f32; 2],
134 tint_color: [f32; 4],
135 border_color: [f32; 4],
136}
137
138impl<'ui, 'tex> Image<'ui, 'tex> {
139 pub fn new(ui: &'ui Ui, texture: impl Into<TextureRef<'tex>>, size: [f32; 2]) -> Self {
141 Self {
142 _ui: ui,
143 texture: texture.into(),
144 size,
145 uv0: [0.0, 0.0],
146 uv1: [1.0, 1.0],
147 tint_color: [1.0, 1.0, 1.0, 1.0],
148 border_color: [0.0, 0.0, 0.0, 0.0],
149 }
150 }
151
152 pub fn uv0(mut self, uv0: [f32; 2]) -> Self {
154 self.uv0 = uv0;
155 self
156 }
157
158 pub fn uv1(mut self, uv1: [f32; 2]) -> Self {
160 self.uv1 = uv1;
161 self
162 }
163
164 pub fn tint_color(mut self, tint_color: [f32; 4]) -> Self {
170 self.tint_color = tint_color;
171 self
172 }
173
174 pub fn border_color(mut self, border_color: [f32; 4]) -> Self {
180 self.border_color = border_color;
181 self
182 }
183
184 pub fn build(self) {
186 assert_non_negative_finite_vec2("Image::build()", "size", self.size);
187 assert_finite_vec2("Image::build()", "uv0", self.uv0);
188 assert_finite_vec2("Image::build()", "uv1", self.uv1);
189 assert_finite_vec4("Image::build()", "tint_color", self.tint_color);
190 assert_finite_vec4("Image::build()", "border_color", self.border_color);
191
192 let size_vec: sys::ImVec2 = self.size.into();
193 let uv0_vec: sys::ImVec2 = self.uv0.into();
194 let uv1_vec: sys::ImVec2 = self.uv1.into();
195
196 let _border_size_token = (self.border_color[3] > 0.0).then(|| {
197 let current_size = unsafe { self._ui.style().image_border_size() };
198 self._ui
199 .push_style_var(StyleVar::ImageBorderSize(current_size.max(1.0)))
200 });
201 let _border_color_token = (self.border_color[3] > 0.0).then(|| {
202 self._ui
203 .push_style_color(StyleColor::Border, self.border_color)
204 });
205
206 if is_default_tint_color(self.tint_color) && is_transparent_color(self.border_color) {
207 unsafe { sys::igImage(self.texture.raw(), size_vec, uv0_vec, uv1_vec) }
208 } else {
209 unsafe {
210 sys::igImageWithBg(
211 self.texture.raw(),
212 size_vec,
213 uv0_vec,
214 uv1_vec,
215 im_vec4([0.0, 0.0, 0.0, 0.0]),
216 im_vec4(self.tint_color),
217 )
218 }
219 }
220 }
221
222 pub fn build_with_bg(self, bg_color: [f32; 4], tint_color: [f32; 4]) {
224 assert_non_negative_finite_vec2("Image::build_with_bg()", "size", self.size);
225 assert_finite_vec2("Image::build_with_bg()", "uv0", self.uv0);
226 assert_finite_vec2("Image::build_with_bg()", "uv1", self.uv1);
227 assert_finite_vec4("Image::build_with_bg()", "bg_color", bg_color);
228 assert_finite_vec4("Image::build_with_bg()", "tint_color", tint_color);
229 assert_finite_vec4("Image::build_with_bg()", "border_color", self.border_color);
230
231 let size_vec: sys::ImVec2 = self.size.into();
232 let uv0_vec: sys::ImVec2 = self.uv0.into();
233 let uv1_vec: sys::ImVec2 = self.uv1.into();
234
235 let _border_size_token = (self.border_color[3] > 0.0).then(|| {
236 let current_size = unsafe { self._ui.style().image_border_size() };
237 self._ui
238 .push_style_var(StyleVar::ImageBorderSize(current_size.max(1.0)))
239 });
240 let _border_color_token = (self.border_color[3] > 0.0).then(|| {
241 self._ui
242 .push_style_color(StyleColor::Border, self.border_color)
243 });
244
245 unsafe {
246 sys::igImageWithBg(
247 self.texture.raw(),
248 size_vec,
249 uv0_vec,
250 uv1_vec,
251 im_vec4(bg_color),
252 im_vec4(tint_color),
253 )
254 }
255 }
256}
257
258#[derive(Debug)]
260#[must_use]
261pub struct ImageButton<'ui, 'tex> {
262 ui: &'ui Ui,
263 str_id: Cow<'ui, str>,
264 texture: TextureRef<'tex>,
265 size: [f32; 2],
266 uv0: [f32; 2],
267 uv1: [f32; 2],
268 bg_color: [f32; 4],
269 tint_color: [f32; 4],
270}
271
272impl<'ui, 'tex> ImageButton<'ui, 'tex> {
273 pub fn new(
275 ui: &'ui Ui,
276 str_id: impl Into<Cow<'ui, str>>,
277 texture: impl Into<TextureRef<'tex>>,
278 size: [f32; 2],
279 ) -> Self {
280 Self {
281 ui,
282 str_id: str_id.into(),
283 texture: texture.into(),
284 size,
285 uv0: [0.0, 0.0],
286 uv1: [1.0, 1.0],
287 bg_color: [0.0, 0.0, 0.0, 0.0],
288 tint_color: [1.0, 1.0, 1.0, 1.0],
289 }
290 }
291
292 pub fn uv0(mut self, uv0: [f32; 2]) -> Self {
294 self.uv0 = uv0;
295 self
296 }
297
298 pub fn uv1(mut self, uv1: [f32; 2]) -> Self {
300 self.uv1 = uv1;
301 self
302 }
303
304 pub fn bg_color(mut self, bg_color: [f32; 4]) -> Self {
306 self.bg_color = bg_color;
307 self
308 }
309
310 pub fn tint_color(mut self, tint_color: [f32; 4]) -> Self {
312 self.tint_color = tint_color;
313 self
314 }
315
316 pub fn build(self) -> bool {
318 assert_non_negative_finite_vec2("ImageButton::build()", "size", self.size);
319 assert_finite_vec2("ImageButton::build()", "uv0", self.uv0);
320 assert_finite_vec2("ImageButton::build()", "uv1", self.uv1);
321 assert_finite_vec4("ImageButton::build()", "bg_color", self.bg_color);
322 assert_finite_vec4("ImageButton::build()", "tint_color", self.tint_color);
323
324 let str_id_ptr = self.ui.scratch_txt(self.str_id.as_ref());
325 let size_vec: sys::ImVec2 = self.size.into();
326 let uv0_vec: sys::ImVec2 = self.uv0.into();
327 let uv1_vec: sys::ImVec2 = self.uv1.into();
328
329 unsafe {
330 sys::igImageButton(
331 str_id_ptr,
332 self.texture.raw(),
333 size_vec,
334 uv0_vec,
335 uv1_vec,
336 im_vec4(self.bg_color),
337 im_vec4(self.tint_color),
338 )
339 }
340 }
341}