use log::debug;
use crate::animation::animation::{ FadeAnimation, Vec2Animation };
use crate::graphics::Renderer;
use crate::style::color::Color;
use crate::widget::Widget;
use crate::Animation;
use std::cell::RefCell;
use std::sync::Arc;
#[derive(Debug)]
pub enum ShapeType {
Rectangle,
Circle,
Triangle,
}
pub struct Shape {
x: f32,
y: f32,
width: f32,
height: f32,
shape_type: ShapeType,
fill_color: Color,
border_color: Color,
border_width: f32,
opacity: f32,
is_hovered: bool,
is_pressed: bool,
position_animation: Option<Vec2Animation>,
fade_animation: Option<FadeAnimation>,
on_hover: Option<Arc<RefCell<dyn FnMut(bool) + 'static>>>,
on_click: Option<Arc<RefCell<dyn FnMut() + 'static>>>,
}
impl Shape {
pub fn new(shape_type: ShapeType) -> Self {
debug!("Creating new shape: {:?}", shape_type);
Self {
x: 0.0,
y: 0.0,
width: 100.0,
height: 100.0,
shape_type,
fill_color: Color::new(1.0, 1.0, 1.0, 1.0),
border_color: Color::new(0.0, 0.0, 0.0, 1.0),
border_width: 0.0,
opacity: 1.0,
is_hovered: false,
is_pressed: false,
position_animation: None,
fade_animation: None,
on_hover: None,
on_click: None,
}
}
pub fn set_fill_color(&mut self, color: Color) {
debug!("Setting fill color: {:?}", color);
self.fill_color = color;
}
pub fn set_border_color(&mut self, color: Color) {
debug!("Setting border color: {:?}", color);
self.border_color = color;
}
pub fn set_border_width(&mut self, width: f32) {
debug!("Setting border width: {}", width);
self.border_width = width;
}
pub fn update_hover(&mut self, x: f32, y: f32) {
let was_hovered = self.is_hovered;
let is_now_hovered = self.contains_point(x, y);
if was_hovered == is_now_hovered {
return;
}
self.is_hovered = is_now_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 Shape {
fn draw(&self, renderer: &mut Renderer, _screen_width: f32, _screen_height: f32) {
let fill_color = self.fill_color.with_opacity(self.opacity);
let border_color = self.border_color.with_opacity(self.opacity);
match self.shape_type {
ShapeType::Rectangle => {
if self.border_width > 0.0 {
renderer.draw_rect(
self.x - self.border_width,
self.y - self.border_width,
self.width + self.border_width * 2.0,
self.height + self.border_width * 2.0,
border_color.to_array()
);
}
renderer.draw_rect(self.x, self.y, self.width, self.height, fill_color.to_array());
}
ShapeType::Circle => {
self.draw_circle_with_opacity(renderer, fill_color, border_color)
}
ShapeType::Triangle => {
self.draw_triangle_with_opacity(renderer, fill_color, border_color)
}
}
}
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.fill_color
}
fn get_text_color(&self) -> Color {
Color::new(0.0, 0.0, 0.0, 0.0)
}
fn get_hover_background_color(&self) -> Color {
self.fill_color
}
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 set_position(&mut self, x: f32, y: f32) {
self.x = x;
self.y = y;
}
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_animation(&mut self, animation: Vec2Animation) {
self.position_animation = Some(animation);
}
fn set_fade_animation(&mut self, animation: FadeAnimation) {
self.fade_animation = Some(animation);
}
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 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.contains_point(x, y) {
if let Some(callback) = &self.on_click {
callback.borrow_mut()();
}
true
} else {
false
}
}
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;
}
}
}
}
impl Shape {
fn draw_circle_with_opacity(
&self,
renderer: &mut Renderer,
fill_color: Color,
border_color: Color
) {
let center_x = self.x + self.width / 2.0;
let center_y = self.y + self.height / 2.0;
let radius = self.width.min(self.height) / 2.0;
if self.border_width > 0.0 {
renderer.draw_circle(
center_x,
center_y,
radius + self.border_width,
border_color.to_array()
);
}
renderer.draw_circle(center_x, center_y, radius, fill_color.to_array());
}
fn draw_triangle_with_opacity(
&self,
renderer: &mut Renderer,
fill_color: Color,
border_color: Color
) {
let vertices = [
(self.x, self.y + self.height),
(self.x + self.width, self.y + self.height),
(self.x + self.width / 2.0, self.y),
];
if self.border_width > 0.0 {
let border_vertices = [
(vertices[0].0 - self.border_width, vertices[0].1 + self.border_width),
(vertices[1].0 + self.border_width, vertices[1].1 + self.border_width),
(vertices[2].0, vertices[2].1 - self.border_width),
];
renderer.draw_triangle(border_vertices, border_color.to_array());
}
renderer.draw_triangle(vertices, fill_color.to_array());
}
}