use crate::prelude::*;
use indexmap::IndexMap;
#[derive(Default)]
pub struct Keymap<T>
where
T: 'static + Clone + PartialEq + Send + Sync,
{
entries: IndexMap<KeyChord, Vec<KeymapEntry<T>>>,
}
impl<T> Keymap<T>
where
T: 'static + Clone + PartialEq + Send + Sync,
{
pub fn new() -> Self {
Self { entries: IndexMap::new() }
}
fn insert(&mut self, chord: KeyChord, keymap_entry: KeymapEntry<T>) {
if let Some(actions) = self.entries.get_mut(&chord) {
if !actions.contains(&keymap_entry) {
actions.push(keymap_entry);
}
} else {
self.entries.insert(chord, vec![keymap_entry]);
}
}
fn remove(&mut self, chord: &KeyChord, action: &T) {
if let Some(actions) = self.entries.get_mut(chord) {
if let Some(index) = actions.iter().position(|x| x == action) {
if actions.len() == 1 {
self.entries.swap_remove(chord);
} else {
actions.swap_remove(index);
}
}
}
}
pub fn pressed_actions(
&self,
cx: &Context,
code: Code,
) -> impl Iterator<Item = &KeymapEntry<T>> {
if let Some(actions) = self.entries.get(&KeyChord::new(cx.modifiers, code)) {
actions.iter()
} else {
[].iter()
}
}
pub fn export(&self) -> Vec<(&KeyChord, &KeymapEntry<T>)> {
let mut vec = Vec::new();
for (chord, entries) in self.entries.iter() {
for entry in entries {
vec.push((chord, entry));
}
}
vec
}
}
impl<T> Model for Keymap<T>
where
T: 'static + Clone + PartialEq + Send + Sync,
{
fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
event.map(|keymap_event, _| match keymap_event {
KeymapEvent::InsertAction(chord, entry) => self.insert(*chord, entry.clone()),
KeymapEvent::RemoveAction(chord, action) => self.remove(chord, action),
});
event.map(|window_event, _| match window_event {
WindowEvent::KeyDown(code, _) => {
if let Some(entries) = self.entries.get(&KeyChord::new(*cx.modifiers, *code)) {
for entry in entries {
(entry.on_action())(cx)
}
}
}
_ => {}
})
}
}
impl<T> From<Vec<(KeyChord, KeymapEntry<T>)>> for Keymap<T>
where
T: 'static + Clone + PartialEq + Send + Sync,
{
fn from(vec: Vec<(KeyChord, KeymapEntry<T>)>) -> Self {
let mut keymap = Self::new();
for (chord, entry) in vec {
keymap.insert(chord, entry);
}
keymap
}
}
pub enum KeymapEvent<T>
where
T: 'static + Clone + PartialEq + Send + Sync,
{
InsertAction(KeyChord, KeymapEntry<T>),
RemoveAction(KeyChord, T),
}