keybinding.rs

  1use std::collections::HashSet;
  2use std::marker::PhantomData;
  3
  4use strum::{EnumIter, IntoEnumIterator};
  5
  6use crate::prelude::*;
  7use crate::theme;
  8
  9#[derive(Element, Clone)]
 10pub struct Keybinding<S: 'static + Send + Sync + Clone> {
 11    state_type: PhantomData<S>,
 12
 13    /// A keybinding consists of a key and a set of modifier keys.
 14    /// More then one keybinding produces a chord.
 15    ///
 16    /// This should always contain at least one element.
 17    keybinding: Vec<(String, ModifierKeys)>,
 18}
 19
 20impl<S: 'static + Send + Sync + Clone> Keybinding<S> {
 21    pub fn new(key: String, modifiers: ModifierKeys) -> Self {
 22        Self {
 23            state_type: PhantomData,
 24            keybinding: vec![(key, modifiers)],
 25        }
 26    }
 27
 28    pub fn new_chord(
 29        first_note: (String, ModifierKeys),
 30        second_note: (String, ModifierKeys),
 31    ) -> Self {
 32        Self {
 33            state_type: PhantomData,
 34            keybinding: vec![first_note, second_note],
 35        }
 36    }
 37
 38    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
 39        div()
 40            .flex()
 41            .gap_2()
 42            .children(self.keybinding.iter().map(|(key, modifiers)| {
 43                div()
 44                    .flex()
 45                    .gap_1()
 46                    .children(ModifierKey::iter().filter_map(|modifier| {
 47                        if modifiers.0.contains(&modifier) {
 48                            Some(Key::new(modifier.glyph()))
 49                        } else {
 50                            None
 51                        }
 52                    }))
 53                    .child(Key::new(key.clone()))
 54            }))
 55    }
 56}
 57
 58#[derive(Element)]
 59pub struct Key<S: 'static + Send + Sync> {
 60    state_type: PhantomData<S>,
 61    key: String,
 62}
 63
 64impl<S: 'static + Send + Sync> Key<S> {
 65    pub fn new<K>(key: K) -> Self
 66    where
 67        K: Into<String>,
 68    {
 69        Self {
 70            state_type: PhantomData,
 71            key: key.into(),
 72        }
 73    }
 74
 75    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
 76        let theme = theme(cx);
 77
 78        div()
 79            .px_2()
 80            .py_0()
 81            .rounded_md()
 82            .text_sm()
 83            .text_color(theme.lowest.on.default.foreground)
 84            .fill(theme.lowest.on.default.background)
 85            .child(self.key.clone())
 86    }
 87}
 88
 89// NOTE: The order the modifier keys appear in this enum impacts the order in
 90// which they are rendered in the UI.
 91#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
 92pub enum ModifierKey {
 93    Control,
 94    Alt,
 95    Command,
 96    Shift,
 97}
 98
 99impl ModifierKey {
100    /// Returns the glyph for the [`ModifierKey`].
101    pub fn glyph(&self) -> char {
102        match self {
103            Self::Control => '^',
104            Self::Alt => '⌥',
105            Self::Command => '⌘',
106            Self::Shift => '⇧',
107        }
108    }
109}
110
111#[derive(Clone)]
112pub struct ModifierKeys(HashSet<ModifierKey>);
113
114impl ModifierKeys {
115    pub fn new() -> Self {
116        Self(HashSet::new())
117    }
118
119    pub fn all() -> Self {
120        Self(HashSet::from_iter(ModifierKey::iter()))
121    }
122
123    pub fn add(mut self, modifier: ModifierKey) -> Self {
124        self.0.insert(modifier);
125        self
126    }
127
128    pub fn control(mut self, control: bool) -> Self {
129        if control {
130            self.0.insert(ModifierKey::Control);
131        } else {
132            self.0.remove(&ModifierKey::Control);
133        }
134
135        self
136    }
137
138    pub fn alt(mut self, alt: bool) -> Self {
139        if alt {
140            self.0.insert(ModifierKey::Alt);
141        } else {
142            self.0.remove(&ModifierKey::Alt);
143        }
144
145        self
146    }
147
148    pub fn command(mut self, command: bool) -> Self {
149        if command {
150            self.0.insert(ModifierKey::Command);
151        } else {
152            self.0.remove(&ModifierKey::Command);
153        }
154
155        self
156    }
157
158    pub fn shift(mut self, shift: bool) -> Self {
159        if shift {
160            self.0.insert(ModifierKey::Shift);
161        } else {
162            self.0.remove(&ModifierKey::Shift);
163        }
164
165        self
166    }
167}