use crate::sys;
use crate::texture::TextureRef;
use crate::ui::Ui;
use crate::{StyleColor, StyleVar};
use std::borrow::Cow;
fn assert_non_negative_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
assert!(
value[0].is_finite() && value[1].is_finite(),
"{caller} {name} must contain finite values"
);
assert!(
value[0] >= 0.0 && value[1] >= 0.0,
"{caller} {name} must contain non-negative values"
);
}
fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
assert!(
value[0].is_finite() && value[1].is_finite(),
"{caller} {name} must contain finite values"
);
}
fn assert_finite_vec4(caller: &str, name: &str, value: [f32; 4]) {
assert!(
value.iter().all(|component| component.is_finite()),
"{caller} {name} must contain finite values"
);
}
fn is_default_tint_color(color: [f32; 4]) -> bool {
color == [1.0, 1.0, 1.0, 1.0]
}
fn is_transparent_color(color: [f32; 4]) -> bool {
color == [0.0, 0.0, 0.0, 0.0]
}
fn im_vec4(value: [f32; 4]) -> sys::ImVec4 {
sys::ImVec4 {
x: value[0],
y: value[1],
z: value[2],
w: value[3],
}
}
impl Ui {
#[doc(alias = "Image")]
pub fn image(&self, texture: impl Into<TextureRef>, size: [f32; 2]) {
self.image_config(texture, size).build()
}
#[doc(alias = "ImageButton")]
pub fn image_button(
&self,
str_id: impl AsRef<str>,
texture: impl Into<TextureRef>,
size: [f32; 2],
) -> bool {
self.image_button_config(str_id.as_ref(), texture, size)
.build()
}
pub fn image_config(&self, texture: impl Into<TextureRef>, size: [f32; 2]) -> Image<'_> {
Image::new(self, texture, size)
}
pub fn image_button_config<'ui>(
&'ui self,
str_id: impl Into<Cow<'ui, str>>,
texture: impl Into<TextureRef>,
size: [f32; 2],
) -> ImageButton<'ui> {
ImageButton::new(self, str_id, texture, size)
}
}
#[derive(Debug)]
#[must_use]
pub struct Image<'ui> {
_ui: &'ui Ui,
texture: TextureRef,
size: [f32; 2],
uv0: [f32; 2],
uv1: [f32; 2],
tint_color: [f32; 4],
border_color: [f32; 4],
}
impl<'ui> Image<'ui> {
pub fn new(ui: &'ui Ui, texture: impl Into<TextureRef>, size: [f32; 2]) -> Self {
Self {
_ui: ui,
texture: texture.into(),
size,
uv0: [0.0, 0.0],
uv1: [1.0, 1.0],
tint_color: [1.0, 1.0, 1.0, 1.0],
border_color: [0.0, 0.0, 0.0, 0.0],
}
}
pub fn uv0(mut self, uv0: [f32; 2]) -> Self {
self.uv0 = uv0;
self
}
pub fn uv1(mut self, uv1: [f32; 2]) -> Self {
self.uv1 = uv1;
self
}
pub fn tint_color(mut self, tint_color: [f32; 4]) -> Self {
self.tint_color = tint_color;
self
}
pub fn border_color(mut self, border_color: [f32; 4]) -> Self {
self.border_color = border_color;
self
}
pub fn build(self) {
assert_non_negative_finite_vec2("Image::build()", "size", self.size);
assert_finite_vec2("Image::build()", "uv0", self.uv0);
assert_finite_vec2("Image::build()", "uv1", self.uv1);
assert_finite_vec4("Image::build()", "tint_color", self.tint_color);
assert_finite_vec4("Image::build()", "border_color", self.border_color);
let size_vec: sys::ImVec2 = self.size.into();
let uv0_vec: sys::ImVec2 = self.uv0.into();
let uv1_vec: sys::ImVec2 = self.uv1.into();
let _border_size_token = (self.border_color[3] > 0.0).then(|| {
let current_size = unsafe { self._ui.style().image_border_size() };
self._ui
.push_style_var(StyleVar::ImageBorderSize(current_size.max(1.0)))
});
let _border_color_token = (self.border_color[3] > 0.0).then(|| {
self._ui
.push_style_color(StyleColor::Border, self.border_color)
});
if is_default_tint_color(self.tint_color) && is_transparent_color(self.border_color) {
unsafe { sys::igImage(self.texture.raw(), size_vec, uv0_vec, uv1_vec) }
} else {
unsafe {
sys::igImageWithBg(
self.texture.raw(),
size_vec,
uv0_vec,
uv1_vec,
im_vec4([0.0, 0.0, 0.0, 0.0]),
im_vec4(self.tint_color),
)
}
}
}
pub fn build_with_bg(self, bg_color: [f32; 4], tint_color: [f32; 4]) {
assert_non_negative_finite_vec2("Image::build_with_bg()", "size", self.size);
assert_finite_vec2("Image::build_with_bg()", "uv0", self.uv0);
assert_finite_vec2("Image::build_with_bg()", "uv1", self.uv1);
assert_finite_vec4("Image::build_with_bg()", "bg_color", bg_color);
assert_finite_vec4("Image::build_with_bg()", "tint_color", tint_color);
assert_finite_vec4("Image::build_with_bg()", "border_color", self.border_color);
let size_vec: sys::ImVec2 = self.size.into();
let uv0_vec: sys::ImVec2 = self.uv0.into();
let uv1_vec: sys::ImVec2 = self.uv1.into();
let _border_size_token = (self.border_color[3] > 0.0).then(|| {
let current_size = unsafe { self._ui.style().image_border_size() };
self._ui
.push_style_var(StyleVar::ImageBorderSize(current_size.max(1.0)))
});
let _border_color_token = (self.border_color[3] > 0.0).then(|| {
self._ui
.push_style_color(StyleColor::Border, self.border_color)
});
unsafe {
sys::igImageWithBg(
self.texture.raw(),
size_vec,
uv0_vec,
uv1_vec,
im_vec4(bg_color),
im_vec4(tint_color),
)
}
}
}
#[derive(Debug)]
#[must_use]
pub struct ImageButton<'ui> {
ui: &'ui Ui,
str_id: Cow<'ui, str>,
texture: TextureRef,
size: [f32; 2],
uv0: [f32; 2],
uv1: [f32; 2],
bg_color: [f32; 4],
tint_color: [f32; 4],
}
impl<'ui> ImageButton<'ui> {
pub fn new(
ui: &'ui Ui,
str_id: impl Into<Cow<'ui, str>>,
texture: impl Into<TextureRef>,
size: [f32; 2],
) -> Self {
Self {
ui,
str_id: str_id.into(),
texture: texture.into(),
size,
uv0: [0.0, 0.0],
uv1: [1.0, 1.0],
bg_color: [0.0, 0.0, 0.0, 0.0],
tint_color: [1.0, 1.0, 1.0, 1.0],
}
}
pub fn uv0(mut self, uv0: [f32; 2]) -> Self {
self.uv0 = uv0;
self
}
pub fn uv1(mut self, uv1: [f32; 2]) -> Self {
self.uv1 = uv1;
self
}
pub fn bg_color(mut self, bg_color: [f32; 4]) -> Self {
self.bg_color = bg_color;
self
}
pub fn tint_color(mut self, tint_color: [f32; 4]) -> Self {
self.tint_color = tint_color;
self
}
pub fn build(self) -> bool {
assert_non_negative_finite_vec2("ImageButton::build()", "size", self.size);
assert_finite_vec2("ImageButton::build()", "uv0", self.uv0);
assert_finite_vec2("ImageButton::build()", "uv1", self.uv1);
assert_finite_vec4("ImageButton::build()", "bg_color", self.bg_color);
assert_finite_vec4("ImageButton::build()", "tint_color", self.tint_color);
let str_id_ptr = self.ui.scratch_txt(self.str_id.as_ref());
let size_vec: sys::ImVec2 = self.size.into();
let uv0_vec: sys::ImVec2 = self.uv0.into();
let uv1_vec: sys::ImVec2 = self.uv1.into();
unsafe {
sys::igImageButton(
str_id_ptr,
self.texture.raw(),
size_vec,
uv0_vec,
uv1_vec,
im_vec4(self.bg_color),
im_vec4(self.tint_color),
)
}
}
}