You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.4 KiB
119 lines
3.4 KiB
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<String>,
|
|
color_base: Color,
|
|
color_trim: Color,
|
|
cbs: HashMap<MouseButton, Box<dyn FnMut() -> ()>>,
|
|
}
|
|
|
|
impl Button {
|
|
/// Create a new button
|
|
pub fn new(
|
|
pos: Pos,
|
|
size: Pos,
|
|
text: impl Into<Option<String>>,
|
|
color: impl Into<Color>,
|
|
) -> 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<C: FnMut() -> () + '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(())
|
|
}
|
|
}
|
|
|