use crate::animation::animation::{ Animation, Vec2Animation, FadeAnimation };
use crate::style::color::Color;
use crate::widget::Widget;
use crate::graphics::Renderer;
use log::{ debug, info };
use std::sync::Arc;
use std::cell::RefCell;
pub struct TextView {
x: f32,
y: f32,
width: f32,
height: f32,
text: String,
font_size: f32,
background_color: Color,
text_color: Color,
is_hovered: bool,
hover_background_color: Color,
hover_text_color: Color,
on_hover: Option<Arc<RefCell<dyn FnMut(bool) + 'static>>>,
is_pressed: bool,
on_click: Option<Arc<RefCell<dyn FnMut() + 'static>>>,
position_animation: Option<Vec2Animation>,
fade_animation: Option<FadeAnimation>,
opacity: f32,
}
impl TextView {
pub fn new(text: &str, renderer: &Renderer) -> Self {
debug!("Creating new TextView with text: '{}'", text);
let background_color = Color::new(1.0, 1.0, 1.0, 0.5);
let text_color = Color::new(0.0, 0.0, 0.0, 1.0);
let mut tv = Self {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
text: text.to_string(),
font_size: 32.0,
background_color,
text_color,
is_hovered: false,
hover_background_color: Color::new(0.9, 0.9, 0.9, 0.7),
hover_text_color: Color::new(0.0, 0.0, 0.0, 1.0),
on_hover: None,
is_pressed: false,
on_click: None,
position_animation: None,
fade_animation: None,
opacity: 1.0,
};
tv.update_size(renderer);
info!("TextView created with size: {}x{}", tv.width, tv.height);
tv
}
pub fn with_style(
text: String,
font_size: f32,
background_color: Color,
text_color: Color,
hover_background_color: Color,
hover_text_color: Color,
renderer: &Renderer
) -> Self {
let mut tv = Self {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
text,
font_size,
background_color,
text_color,
hover_background_color,
hover_text_color,
is_hovered: false,
opacity: 1.0,
on_hover: None,
is_pressed: false,
on_click: None,
position_animation: None,
fade_animation: None,
};
tv.update_size(renderer);
tv
}
fn update_size(&mut self, renderer: &Renderer) {
let (width, height) = renderer
.text_renderer()
.font_renderer()
.calculate_text_size(&self.text, self.font_size);
self.width = width + 20.0; self.height = height + 10.0;
debug!("TextView size updated: {}x{}", self.width, self.height);
}
pub fn set_text(&mut self, text: &str, renderer: &Renderer) {
debug!("TextView text changing from '{}' to '{}'", self.text, text);
self.text = text.to_string();
self.update_size(renderer);
}
pub fn set_font_size(&mut self, size: f32, renderer: &Renderer) {
debug!("TextView font size changing from {} to {}", self.font_size, size);
self.font_size = size;
self.update_size(renderer);
}
pub fn set_background_color(&mut self, color: Color) {
self.background_color = color;
}
pub fn set_text_color(&mut self, color: Color) {
self.text_color = color;
}
pub fn set_position(&mut self, x: f32, y: f32) {
self.x = x;
self.y = y;
}
pub fn set_hover_background_color(&mut self, color: Color) {
self.hover_background_color = color;
}
pub fn set_hover_text_color(&mut self, color: Color) {
self.hover_text_color = color;
}
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 TextView {
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 {
self.background_color
}
fn get_text_color(&self) -> Color {
self.text_color
}
fn get_hover_background_color(&self) -> Color {
self.hover_background_color
}
fn get_hover_text_color(&self) -> Color {
self.hover_text_color
}
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) {
let current_background =
(if self.is_hovered { self.hover_background_color } else { self.background_color }) *
self.opacity;
let current_text =
(if self.is_hovered { self.hover_text_color } else { self.text_color }) * self.opacity;
renderer.draw_rect(self.x, self.y, self.width, self.height, current_background.to_array());
renderer
.text_renderer_mut()
.render_text(
&self.text,
self.x + 10.0,
self.y + 5.0,
self.font_size,
screen_width,
screen_height,
current_text.to_array()
);
}
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 animate_fade(&mut self, start: f32, end: f32, duration: f32) {
self.set_fade_animation(FadeAnimation::new(start, end, duration));
}
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;
}
}
}
}