use {Key, KeyState, KeyboardEvent, Modifiers};
pub struct ShortcutMatcher<T> {
state: KeyState,
key: Key,
modifiers: Modifiers,
matched: bool,
value: Option<T>,
}
impl<T> ShortcutMatcher<T> {
pub fn new(state: KeyState, key: Key, mut modifiers: Modifiers) -> ShortcutMatcher<T> {
modifiers &= Modifiers::SHIFT | Modifiers::CONTROL | Modifiers::ALT | Modifiers::META;
ShortcutMatcher {
state,
key,
modifiers,
matched: false,
value: None,
}
}
pub fn from_event(key_event: KeyboardEvent) -> ShortcutMatcher<T> {
ShortcutMatcher::new(key_event.state, key_event.key, key_event.modifiers)
}
pub fn shortcut<K, F>(mut self, modifiers: Modifiers, key: K, f: F) -> ShortcutMatcher<T>
where
K: MatchKey,
F: (FnOnce() -> T),
{
if self.matched {
return self;
}
if modifiers == self.modifiers && key.match_key(&self.key) {
if self.state == KeyState::Down {
self.value = Some(f());
}
self.matched = true;
}
self
}
pub fn optional_shortcut<K, F>(
self,
enabled: bool,
modifiers: Modifiers,
key: K,
f: F,
) -> ShortcutMatcher<T>
where
K: MatchKey,
F: (FnOnce() -> T),
{
if !enabled {
return self;
}
self.shortcut(modifiers, key, f)
}
pub fn otherwise<F>(self, f: F) -> Option<T>
where
F: (FnOnce() -> T),
{
if !self.matched {
Some(f())
} else {
self.value
}
}
}
pub trait MatchKey {
fn match_key(&self, key: &Key) -> bool;
}
impl MatchKey for Key {
fn match_key(&self, key: &Key) -> bool {
self == key
}
}
impl MatchKey for char {
fn match_key(&self, key: &Key) -> bool {
match key {
Key::Character(text) => {
let mut buf = [0; 4];
text.eq_ignore_ascii_case(self.encode_utf8(&mut buf))
}
_ => false,
}
}
}