use blit::BlitOptions;
use taffy::prelude::{Layout, Node};
use vek::{Extent2, Rect, Vec2};
use crate::input::Input;
#[derive(Debug)]
pub struct Button {
pub offset: Vec2<f64>,
pub size: Extent2<f64>,
pub click_region: Option<Rect<f64, f64>>,
pub label: Option<String>,
pub state: State,
pub node: Node,
}
impl Button {
pub fn update(&mut self, input: &Input) -> bool {
let mut rect = Rect::new(self.offset.x, self.offset.y, self.size.w, self.size.h);
if let Some(mut click_region) = self.click_region {
click_region.x += self.offset.x;
click_region.y += self.offset.y;
rect = rect.union(click_region);
}
match self.state {
State::Normal => {
if !input.left_mouse.is_down() && rect.contains_point(input.mouse_pos.as_()) {
self.state = State::Hover;
}
false
}
State::Hover => {
if !rect.contains_point(input.mouse_pos.as_()) {
self.state = State::Normal;
} else if input.left_mouse.is_down() {
self.state = State::Down;
}
false
}
State::Down => {
if input.left_mouse.is_released() {
self.state = State::Normal;
true
} else {
false
}
}
}
}
pub fn render(&self, canvas: &mut [u32]) {
let button = crate::sprite(match self.state {
State::Normal => "button-normal",
State::Hover => "button-hover",
State::Down => "button-down",
});
button.render_options(
canvas,
&BlitOptions::new_position(self.offset.x, self.offset.y)
.with_slice9((2, 2, 1, 2))
.with_area((self.size.w, self.size.h)),
);
if let Some(label) = &self.label {
crate::font().render_centered(
label,
self.offset + (self.size.w / 2.0, self.size.h / 2.0),
canvas,
);
}
}
pub fn update_layout(&mut self, location: Vec2<f64>, layout: &Layout) {
self.offset.x = location.x;
self.offset.y = location.y;
self.size.w = layout.size.width as f64;
self.size.h = layout.size.height as f64;
}
}
impl Default for Button {
fn default() -> Self {
Self {
offset: Vec2::zero(),
size: Extent2::zero(),
label: None,
state: State::default(),
click_region: None,
node: Node::default(),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum State {
#[default]
Normal,
Hover,
Down,
}