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