use serde::{Serialize, Deserialize};
use wgpu::{Device, Queue, RenderPass};
use winit::event::MouseEvent;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ButtonState {
Normal,
Hovered,
Pressed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Button {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
pub text: String,
pub state: ButtonState,
pub on_click: Option<Box<dyn Fn() + Send + Sync>>,
}
impl Button {
pub fn new(x: f32, y: f32, width: f32, height: f32, text: &str) -> Self {
Self {
x,
y,
width,
height,
text: text.to_string(),
state: ButtonState::Normal,
on_click: None,
}
}
pub fn set_on_click<F: Fn() + Send + Sync + 'static>(&mut self, callback: F) {
self.on_click = Some(Box::new(callback));
}
pub fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
match event {
MouseEvent::CursorMoved { position, .. } => {
let (x, y) = (position.x as f32, position.y as f32);
let is_inside = x >= self.x && x <= self.x + self.width &&
y >= self.y && y <= self.y + self.height;
if is_inside {
if self.state != ButtonState::Pressed {
self.state = ButtonState::Hovered;
}
} else {
self.state = ButtonState::Normal;
}
is_inside
},
MouseEvent::ButtonPressed { .. } => {
if self.state == ButtonState::Hovered {
self.state = ButtonState::Pressed;
true
} else {
false
}
},
MouseEvent::ButtonReleased { .. } => {
let was_pressed = self.state == ButtonState::Pressed;
if was_pressed {
self.state = ButtonState::Hovered;
if let Some(callback) = self.on_click.as_ref() {
callback();
}
}
was_pressed
},
_ => false,
}
}
pub fn render(&self, device: &Device, queue: &Queue, render_pass: &mut RenderPass) {
let bg_color = match self.state {
ButtonState::Normal => [0.2, 0.4, 0.6, 1.0],
ButtonState::Hovered => [0.3, 0.5, 0.7, 1.0],
ButtonState::Pressed => [0.1, 0.3, 0.5, 1.0],
};
}
}