keybinding.rs

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