95 lines
3.0 KiB
Rust
95 lines
3.0 KiB
Rust
|
use std::{hash::{Hash, Hasher}, collections::{HashMap, hash_map::DefaultHasher}};
|
||
|
|
||
|
use winit::event::ElementState;
|
||
|
|
||
|
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||
|
pub enum ButtonEvent<T: Clone + Hash + Eq + PartialEq + 'static> {
|
||
|
Pressed(T),
|
||
|
Released(T),
|
||
|
JustPressed(T),
|
||
|
}
|
||
|
|
||
|
impl<T: Clone + Hash + Eq + PartialEq + 'static> ButtonEvent<T> {
|
||
|
fn take_val(self) -> T {
|
||
|
match self {
|
||
|
ButtonEvent::Pressed(t) => t,
|
||
|
ButtonEvent::JustPressed(t) => t,
|
||
|
ButtonEvent::Released(t) => t,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn clone_val(&self) -> T {
|
||
|
self.clone().take_val()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Clone)]
|
||
|
pub struct InputButtons<T: Clone + Hash + Eq + PartialEq + 'static> {
|
||
|
// the u64 as the key is the hashed value of T. this makes it easier to
|
||
|
// search for a button and see its state
|
||
|
button_events: HashMap<u64, ButtonEvent<T>>,
|
||
|
}
|
||
|
|
||
|
impl<T: Clone + Hash + Eq + PartialEq + 'static> Default for InputButtons<T> {
|
||
|
fn default() -> Self {
|
||
|
Self::new()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Clone + Hash + Eq + PartialEq + 'static> InputButtons<T> {
|
||
|
pub fn new() -> Self {
|
||
|
Self {
|
||
|
button_events: HashMap::new(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn get_button_hash(button: &T) -> u64 {
|
||
|
let mut hasher = DefaultHasher::new();
|
||
|
button.hash(&mut hasher);
|
||
|
hasher.finish()
|
||
|
}
|
||
|
|
||
|
/// Add a button event to this input type
|
||
|
pub fn add_input(&mut self, button: ButtonEvent<T>) {
|
||
|
let hash = Self::get_button_hash(&button.clone_val());
|
||
|
|
||
|
self.button_events.insert(hash, button);
|
||
|
}
|
||
|
|
||
|
pub(crate) fn add_input_from_winit(&mut self, button: T, state: ElementState) {
|
||
|
let event = match state {
|
||
|
ElementState::Pressed if self.is_pressed(button.clone()) => ButtonEvent::Pressed(button),
|
||
|
ElementState::Pressed => ButtonEvent::JustPressed(button),
|
||
|
ElementState::Released => ButtonEvent::Released(button),
|
||
|
};
|
||
|
|
||
|
self.add_input(event);
|
||
|
}
|
||
|
|
||
|
/// Returns true if the button is pressed (or was just pressed)
|
||
|
pub fn is_pressed(&self, button: T) -> bool
|
||
|
{
|
||
|
let hash = Self::get_button_hash(&button);
|
||
|
match self.button_events.get(&hash) {
|
||
|
Some(button_event) => match button_event {
|
||
|
// this if statement should always be true, but just in case ;)
|
||
|
ButtonEvent::Pressed(b) | ButtonEvent::JustPressed(b) if button == *b => true,
|
||
|
_ => false,
|
||
|
},
|
||
|
None => false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Returns true if the button was just pressed this tick
|
||
|
pub fn was_just_pressed(&self, button: T) -> bool {
|
||
|
let hash = Self::get_button_hash(&button);
|
||
|
match self.button_events.get(&hash) {
|
||
|
Some(button_event) => match button_event {
|
||
|
// this if statement should always be true, but just in case ;)
|
||
|
ButtonEvent::JustPressed(b) if button == *b => true,
|
||
|
_ => false,
|
||
|
},
|
||
|
None => false
|
||
|
}
|
||
|
}
|
||
|
}
|