diff options
Diffstat (limited to 'src/input/binding.rs')
| -rw-r--r-- | src/input/binding.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/input/binding.rs b/src/input/binding.rs new file mode 100644 index 0000000..386fb66 --- /dev/null +++ b/src/input/binding.rs @@ -0,0 +1,123 @@ +//! Bindings module, which is a key combination that does something when pressed. + +use super::Button; +use raylib::RaylibHandle; +use serde::{Deserialize, Serialize}; + +/// Binding struct, which holds any number of buttons (keyboard and mouse may be mixed, if desired) +#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Binding { + buttons: Vec<Button>, +} + +impl Binding { + /// Create a new binding from a range of buttons. The button order does not matter, but at least + /// one button must be supplied. + pub fn new(buttons: Vec<Button>) -> Self { + if buttons.is_empty() { + panic!("Tried to create a binding without any keys."); + } + + Self { buttons } + } + + /// Returns `true` if only mouse buttons are present in this binding, otherwise false. + pub fn mouse_only(&self) -> bool { + for button in &self.buttons { + match button { + Button::Mouse(_) => continue, + _ => return false, + } + } + + true + } + + /// Returns `true` if only keyboard buttons are present in this binding, otherwise false. + pub fn keyboard_only(&self) -> bool { + for button in &self.buttons { + match button { + Button::Scancode(_) | Button::Text(_) => continue, + _ => return false, + } + } + + true + } + + /// Returns `true` if at least one mouse button is required for this binding to work. + pub fn has_mouse_component(&self) -> bool { + self.buttons.iter().any(|b| { + if let Button::Mouse(_) = b { + true + } else { + false + } + }) + } + + /// Returns `true` if at least one keyboard button is required for this binding to work. + pub fn has_keyboard_component(&self) -> bool { + self.buttons.iter().any(|b| match b { + Button::Scancode(_) | Button::Text(_) => true, + _ => false, + }) + } + + /// Checks if this binding was pressed this frame. Heavily dependent on input struct working + /// correctly. + pub(super) fn is_pressed( + &self, + allow_mouse: bool, + allow_keyboard: bool, + text: &str, + rl: &RaylibHandle, + ) -> bool { + let mut distinct_press = false; + for button in &self.buttons { + match *button { + Button::Mouse(mouse_button) => { + if !allow_mouse || !rl.is_mouse_button_down(mouse_button.into()) { + return false; + } + + /* Check if the button has been pressed in this frame exactly. + * This prevents activating the same keybinding every frame + * while the buttons are being held down. + */ + if rl.is_mouse_button_pressed(mouse_button.into()) { + distinct_press = true; + } + } + Button::Scancode(code) => { + if !allow_keyboard || !rl.is_key_down(code.into()) { + return false; + } + + // Check the same as with the mouse button. + if rl.is_key_pressed(code.into()) { + distinct_press = true; + } + } + Button::Text(c) => { + if !allow_keyboard || !text.contains(c) { + return false; + } + + // Always distinct, since on triggering, the text is cleared. + distinct_press = true; + } + } + } + + distinct_press + } +} + +impl From<Button> for Binding { + fn from(button: Button) -> Self { + Self { + buttons: vec![button], + } + } +} |
