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> = None; static mut rx: Option> = None; #[inline(always)] pub fn get_tx() -> Sender { 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; 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 { layers: BTreeMap, layer_rx: Receiver, render: L, } impl EventLayer { 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 EventHandler for EventLayer { 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::>>()?; // 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::>(); 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::>(); } 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::>(); } 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::>(); } /// 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::>(); } /// 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::>(); } /// 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::>(); } }