use crate::{color::ColorUtils, get_tx, EventId, HandlerDiff}; use ggez::graphics::{self, Align, Color, DrawMode, DrawParam, Drawable, MeshBuilder, Rect, Text}; use ggez::{ event::{EventHandler, MouseButton}, Context, GameResult, }; use rst_core::data::Pos; use std::collections::HashMap; /// A button with next that can be clicked to run some code pub struct Button { pos: Pos, size: Pos, text: Option, color_base: Color, color_trim: Color, cbs: HashMap ()>>, } impl Button { /// Create a new button pub fn new( pos: Pos, size: Pos, text: impl Into>, color: impl Into, ) -> Self { let color = color.into(); Self { pos, size, text: text.into(), color_base: color.clone(), color_trim: color.brighten(2), cbs: HashMap::new(), } } /// Register an on-click listening closure pub fn on_click () + 'static>(mut self, btn: MouseButton, cb: C) -> Self { self.cbs.insert(btn, Box::new(cb)); self } /// Register the button with the event handler pub fn register(self) -> EventId { let (btn_id, diff) = HandlerDiff::add(self); get_tx().send(diff).unwrap(); btn_id } fn boundry_check(&self, x: f32, y: f32) -> bool { self.pos.x < x && (self.pos.x + self.size.x) > x && self.pos.y < y && (self.pos.y + self.size.y) > y } } impl EventHandler for Button { fn update(&mut self, ctx: &mut Context) -> GameResult<()> { Ok(()) } fn mouse_button_down_event(&mut self, _ctx: &mut Context, btn: MouseButton, x: f32, y: f32) { if self.boundry_check(x, y) { trace!("Triggering button state"); std::mem::swap(&mut self.color_base, &mut self.color_trim); if let Some(ref mut callback) = self.cbs.get_mut(&btn) { callback(); } } } fn mouse_button_up_event(&mut self, _ctx: &mut Context, btn: MouseButton, x: f32, y: f32) { if self.boundry_check(x, y) { trace!("Releasing button state"); std::mem::swap(&mut self.color_base, &mut self.color_trim); } } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { let mut mb = MeshBuilder::new(); let bounds = Rect { x: self.pos.x, y: self.pos.y, w: self.size.x, h: self.size.y, }; // Create the basic building blocks let rect = mb .rectangle(DrawMode::fill(), bounds, self.color_base.clone())? .build(ctx)?; let frame = mb .rectangle(DrawMode::stroke(2.0), bounds, self.color_trim.clone())? .build(ctx)?; rect.draw(ctx, DrawParam::new())?; frame.draw(ctx, DrawParam::new())?; if let Some(ref text) = self.text { let Pos { x, y } = self.pos; let Pos { x: w, y: h } = self.size; let mut text = Text::new(text.clone()); text.draw( ctx, DrawParam::new().dest([ x + (w / 2.0 - text.width(ctx) / 2.0), y + (h / 2.0 - text.height(ctx) / 2.0), ]), )?; } Ok(()) } }