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.
169 lines
4.6 KiB
169 lines
4.6 KiB
use ggez::{
|
|
event::{EventHandler, KeyCode, KeyMods, MouseButton},
|
|
graphics, Context, GameResult,
|
|
};
|
|
use std::collections::BTreeMap;
|
|
use std::sync::{
|
|
atomic::{AtomicUsize, Ordering},
|
|
mpsc::{channel, Receiver, Sender},
|
|
};
|
|
|
|
static ID_CTR: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
static mut tx: Option<Sender<HandlerDiff>> = None;
|
|
static mut rx: Option<Receiver<HandlerDiff>> = None;
|
|
|
|
#[inline(always)]
|
|
pub fn get_tx() -> Sender<HandlerDiff> {
|
|
unsafe { tx.as_ref() }.expect("Call event::setup() first!").clone()
|
|
}
|
|
|
|
/// Must absolutely call this function before using the event system!
|
|
pub fn setup() {
|
|
let (tx_, rx_) = channel();
|
|
unsafe { tx = Some(tx_) };
|
|
unsafe { rx = Some(rx_) };
|
|
}
|
|
|
|
pub type EventId = usize;
|
|
|
|
pub fn new_id() -> EventId {
|
|
ID_CTR.fetch_add(1, Ordering::Relaxed)
|
|
}
|
|
|
|
pub type BoxedHandler = Box<dyn EventHandler + 'static>;
|
|
|
|
pub enum HandlerDiff {
|
|
Add { id: usize, inner: BoxedHandler },
|
|
Remove(usize),
|
|
}
|
|
|
|
impl HandlerDiff {
|
|
pub fn add(inner: impl EventHandler + 'static) -> (usize, Self) {
|
|
let id = new_id();
|
|
(
|
|
id,
|
|
Self::Add {
|
|
id,
|
|
inner: Box::new(inner),
|
|
},
|
|
)
|
|
}
|
|
|
|
pub fn remove(id: usize) -> Self {
|
|
Self::Remove(id)
|
|
}
|
|
}
|
|
|
|
pub struct EventLayer<L> {
|
|
layers: BTreeMap<usize, BoxedHandler>,
|
|
layer_rx: Receiver<HandlerDiff>,
|
|
render: L,
|
|
}
|
|
|
|
impl<L: EventHandler> EventLayer<L> {
|
|
pub fn new(render: L) -> Self {
|
|
let layer_rx = unsafe { rx.take().expect("Call event::setup() first!") };
|
|
|
|
Self {
|
|
layers: BTreeMap::new(),
|
|
layer_rx,
|
|
render,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<L: EventHandler> EventHandler for EventLayer<L> {
|
|
fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
|
|
// Add all new layers to the update stack
|
|
while let Ok(l) = self.layer_rx.try_recv() {
|
|
match l {
|
|
HandlerDiff::Add { id, inner } => {
|
|
self.layers.insert(id, inner);
|
|
}
|
|
HandlerDiff::Remove(ref id) => {
|
|
self.layers.remove(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Then update all the layers
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.update(ctx))
|
|
.collect::<GameResult<Vec<()>>>()?;
|
|
|
|
// Update the renderer last
|
|
self.render.update(ctx)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
|
|
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15));
|
|
self.render.draw(ctx)?;
|
|
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.draw(ctx))
|
|
.collect::<Vec<_>>();
|
|
|
|
graphics::present(ctx)
|
|
}
|
|
|
|
fn mouse_button_down_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) {
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.mouse_button_down_event(ctx, button, x, y))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
|
|
fn mouse_button_up_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) {
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.mouse_button_up_event(ctx, button, x, y))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
|
|
fn mouse_motion_event(&mut self, ctx: &mut Context, x: f32, y: f32, dx: f32, dy: f32) {
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.mouse_motion_event(ctx, x, y, dx, dy))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
|
|
/// A keyboard button was pressed.
|
|
///
|
|
/// The default implementation of this will call `ggez::event::quit()`
|
|
/// when the escape key is pressed. If you override this with
|
|
/// your own event handler you have to re-implment that
|
|
/// functionality yourself.
|
|
fn key_down_event(
|
|
&mut self,
|
|
ctx: &mut Context,
|
|
keycode: KeyCode,
|
|
keymods: KeyMods,
|
|
repeat: bool,
|
|
) {
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.key_down_event(ctx, keycode, keymods, repeat))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
|
|
/// A keyboard button was released.
|
|
fn key_up_event(&mut self, ctx: &mut Context, keycode: KeyCode, keymods: KeyMods) {
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.key_up_event(ctx, keycode, keymods))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
|
|
/// A unicode character was received, usually from keyboard input.
|
|
/// This is the intended way of facilitating text input.
|
|
fn text_input_event(&mut self, ctx: &mut Context, character: char) {
|
|
self.layers
|
|
.iter_mut()
|
|
.map(|(_, l)| l.text_input_event(ctx, character))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
}
|
|
|