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}