use crate::style::color::Color;
use crate::widget::Widget;
use crate::graphics::Renderer;
use crate::animation::animation::{ Animation, Vec2Animation, FadeAnimation };
use image::{ DynamicImage, GenericImageView };
use std::cell::RefCell;
use std::path::Path;
use std::sync::Arc;
use log::debug;
pub struct ImageView {
x: f32,
y: f32,
width: f32,
height: f32,
texture_id: Option<u32>,
position_animation: Option<Vec2Animation>,
fade_animation: Option<FadeAnimation>,
on_hover: Option<Arc<RefCell<dyn FnMut(bool) + 'static>>>,
is_pressed: bool,
is_hovered: bool,
on_click: Option<Arc<RefCell<dyn FnMut() + 'static>>>,
opacity: f32,
}
impl ImageView {
pub fn new() -> Self {
Self {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
texture_id: None,
position_animation: None,
fade_animation: None,
opacity: 1.0,
is_pressed: false,
is_hovered: false,
on_click: None,
on_hover: None,
}
}
pub fn load_from_path<P: AsRef<Path>>(&mut self, path: P) -> Result<(), String> {
let img: DynamicImage = image::open(path).map_err(|e| e.to_string())?;
self.load_image(img)
}
pub fn load_from_url(&mut self, url: &str) -> Result<(), String> {
let response = reqwest::blocking::get(url).map_err(|e| e.to_string())?;
let bytes = response.bytes().map_err(|e| e.to_string())?;
let img = image::load_from_memory(&bytes).map_err(|e| e.to_string())?;
self.load_image(img)
}
fn load_image(&mut self, img: DynamicImage) -> Result<(), String> {
let dimensions = img.dimensions();
self.width = dimensions.0 as f32;
self.height = dimensions.1 as f32;
let rgba = img.to_rgba8();
let raw = rgba.into_raw();
let mut texture_id = 0;
unsafe {
gl::GenTextures(1, &mut texture_id);
gl::BindTexture(gl::TEXTURE_2D, texture_id);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGBA as i32,
dimensions.0 as i32,
dimensions.1 as i32,
0,
gl::RGBA,
gl::UNSIGNED_BYTE,
raw.as_ptr() as *const _
);
}
debug!("Loaded image from path: {:?}", img.dimensions());
self.texture_id = Some(texture_id);
Ok(())
}
pub fn update_hover(&mut self, x: f32, y: f32) {
let was_hovered = self.is_hovered;
self.is_hovered = self.contains_point(x, y);
if was_hovered != self.is_hovered {
if let Some(callback) = &self.on_hover {
callback.borrow_mut()(self.is_hovered);
}
}
}
pub fn has_fade_animation(&self) -> bool {
self.fade_animation.is_some()
}
pub fn has_position_animation(&self) -> bool {
self.position_animation.is_some()
}
}
impl Widget for ImageView {
fn get_position(&self) -> (f32, f32) {
(self.x, self.y)
}
fn get_size(&self) -> (f32, f32) {
(self.width, self.height)
}
fn get_background_color(&self) -> Color {
Color::new(0.0, 0.0, 0.0, 0.0)
}
fn get_text_color(&self) -> Color {
Color::new(0.0, 0.0, 0.0, 0.0)
}
fn get_hover_background_color(&self) -> Color {
Color::new(0.0, 0.0, 0.0, 0.0)
}
fn get_hover_text_color(&self) -> Color {
Color::new(0.0, 0.0, 0.0, 0.0)
}
fn get_opacity(&self) -> f32 {
self.opacity
}
fn get_is_hovered(&self) -> bool {
self.is_hovered
}
fn get_is_pressed(&self) -> bool {
self.is_pressed
}
fn draw(&self, renderer: &mut Renderer, _screen_width: f32, _screen_height: f32) {
if let Some(texture_id) = self.texture_id {
renderer.draw_textured_rect(
self.x,
self.y,
self.width,
self.height,
texture_id,
self.opacity
);
}
}
fn set_size(&mut self, width: f32, height: f32) {
self.width = width;
self.height = height;
}
fn position(&self) -> (f32, f32) {
(self.x, self.y)
}
fn size(&self) -> (f32, f32) {
(self.width, self.height)
}
fn set_position(&mut self, x: f32, y: f32) {
self.x = x;
self.y = y;
}
fn on_mouse_press(&mut self, x: f32, y: f32) -> bool {
if self.contains_point(x, y) {
self.is_pressed = true;
true
} else {
false
}
}
fn on_mouse_release(&mut self, x: f32, y: f32) -> bool {
if self.is_pressed {
self.is_pressed = false;
if self.contains_point(x, y) {
if let Some(callback) = &self.on_click {
callback.borrow_mut()();
}
return true;
}
}
false
}
fn set_on_click<F>(&mut self, callback: F) where F: FnMut() + 'static {
self.on_click = Some(Arc::new(RefCell::new(callback)));
}
fn set_on_hover<F>(&mut self, callback: F) where F: FnMut(bool) + 'static {
self.on_hover = Some(Arc::new(RefCell::new(callback)));
}
fn set_position_animation(&mut self, animation: Vec2Animation) {
self.position_animation = Some(animation);
}
fn set_fade_animation(&mut self, animation: FadeAnimation) {
self.fade_animation = Some(animation);
}
fn update_animations(&mut self, delta_time: f32) {
if let Some(ref mut anim) = self.position_animation {
anim.update(delta_time);
let pos = anim.value();
self.x = pos.x;
self.y = pos.y;
if anim.is_finished() {
self.position_animation = None;
}
}
if let Some(ref mut anim) = self.fade_animation {
anim.update(delta_time);
self.opacity = anim.value();
if anim.is_finished() {
self.fade_animation = None;
}
}
}
}