egui_bind/
target.rs

1use egui::{Context, Key, Modifiers, PointerButton};
2use std::mem::zeroed;
3
4/// Type that can be used as a bind target
5pub trait BindTarget: Clone {
6    /// Can accept key bind?
7    const IS_KEY: bool;
8    /// Can accept pointer bind?
9    const IS_POINTER: bool;
10
11    /// Can be cleared?
12    const CLEARABLE: bool;
13
14    /// Sets new key bind
15    fn set_key(&mut self, key: Key, modifiers: Modifiers);
16
17    /// Sets new pointer bind
18    fn set_pointer(&mut self, button: PointerButton, modifiers: Modifiers);
19
20    /// Clears the bind
21    fn clear(&mut self);
22
23    /// Formats a bind to a string
24    fn format(&self) -> String;
25
26    /// Is bind down?
27    fn down(&self, ctx: &Context) -> bool;
28
29    /// Was bind pressed this frame?
30    fn pressed(&self, ctx: &Context) -> bool;
31
32    /// Was bind released this frame?
33    fn released(&self, ctx: &Context) -> bool;
34}
35
36impl BindTarget for Key {
37    const IS_KEY: bool = true;
38    const IS_POINTER: bool = false;
39    const CLEARABLE: bool = false;
40
41    fn set_key(&mut self, key: Key, _: Modifiers) {
42        *self = key;
43    }
44
45    fn set_pointer(&mut self, _: PointerButton, _: Modifiers) {
46        unimplemented!()
47    }
48
49    fn format(&self) -> String {
50        match self {
51            Self::Backspace => "BKSP".into(),
52            Self::Escape => "ESC".into(),
53            Self::Enter => "RET".into(),
54            Self::Insert => "INS".into(),
55            Self::Delete => "DEL".into(),
56            Self::PageUp => "PGU".into(),
57            Self::PageDown => "PGD".into(),
58            Self::Equals => "=".into(),
59            Self::Period => ".".into(),
60            Self::Comma => ",".into(),
61            Self::Plus => "+".into(),
62            Self::Backtick => "`".into(),
63            Self::Minus => "-".into(),
64            Self::Backslash => "\\".into(),
65            Self::Colon => ":".into(),
66            Self::Semicolon => ";".into(),
67            Self::OpenBracket => "[".into(),
68            Self::CloseBracket => "]".into(),
69            Self::Num0 => "0".into(),
70            Self::Num1 => "1".into(),
71            Self::Num2 => "2".into(),
72            Self::Num3 => "3".into(),
73            Self::Num4 => "4".into(),
74            Self::Num5 => "5".into(),
75            Self::Num6 => "6".into(),
76            Self::Num7 => "7".into(),
77            Self::Num8 => "8".into(),
78            Self::Num9 => "9".into(),
79            _ => format!("{self:?}"),
80        }
81    }
82
83    fn clear(&mut self) {
84        unimplemented!()
85    }
86
87    fn down(&self, ctx: &Context) -> bool {
88        ctx.input(|i| i.key_down(*self))
89    }
90
91    fn pressed(&self, ctx: &Context) -> bool {
92        ctx.input(|i| i.key_pressed(*self))
93    }
94
95    fn released(&self, ctx: &Context) -> bool {
96        ctx.input(|i| i.key_released(*self))
97    }
98}
99
100macro_rules! option_through {
101    ($check:expr, $ctx:expr, $($path:tt)*) => {
102        if let Some(v) = $check {
103            v.$($path)*($ctx)
104        } else {
105            false
106        }
107    };
108}
109
110impl BindTarget for Option<Key> {
111    const IS_KEY: bool = true;
112    const IS_POINTER: bool = false;
113    const CLEARABLE: bool = true;
114
115    fn set_key(&mut self, key: Key, _: Modifiers) {
116        *self = Some(key);
117    }
118
119    fn set_pointer(&mut self, _: PointerButton, _: Modifiers) {
120        unimplemented!()
121    }
122
123    fn format(&self) -> String {
124        self.as_ref()
125            .map(BindTarget::format)
126            .unwrap_or_else(|| "None".into())
127    }
128
129    fn clear(&mut self) {
130        *self = None;
131    }
132
133    fn down(&self, ctx: &Context) -> bool {
134        option_through!(self, ctx, down)
135    }
136
137    fn pressed(&self, ctx: &Context) -> bool {
138        option_through!(self, ctx, pressed)
139    }
140
141    fn released(&self, ctx: &Context) -> bool {
142        option_through!(self, ctx, released)
143    }
144}
145
146impl BindTarget for PointerButton {
147    const IS_KEY: bool = false;
148    const IS_POINTER: bool = true;
149    const CLEARABLE: bool = false;
150
151    fn set_key(&mut self, _: Key, _: Modifiers) {
152        unimplemented!()
153    }
154
155    fn set_pointer(&mut self, button: PointerButton, _: Modifiers) {
156        *self = button;
157    }
158
159    fn clear(&mut self) {
160        unimplemented!()
161    }
162
163    fn format(&self) -> String {
164        match self {
165            PointerButton::Extra2 => "M5",
166            PointerButton::Extra1 => "M4",
167            PointerButton::Middle => "M3",
168            PointerButton::Secondary => "M2",
169            PointerButton::Primary => "M1",
170        }
171        .into()
172    }
173
174    fn down(&self, ctx: &Context) -> bool {
175        ctx.input(|i| i.pointer.button_down(*self))
176    }
177
178    fn pressed(&self, ctx: &Context) -> bool {
179        ctx.input(|i| i.pointer.button_pressed(*self))
180    }
181
182    fn released(&self, ctx: &Context) -> bool {
183        ctx.input(|i| i.pointer.button_released(*self))
184    }
185}
186
187impl BindTarget for Option<PointerButton> {
188    const IS_KEY: bool = false;
189    const IS_POINTER: bool = true;
190    const CLEARABLE: bool = false;
191
192    fn set_key(&mut self, _: Key, _: Modifiers) {
193        unimplemented!()
194    }
195
196    fn set_pointer(&mut self, button: PointerButton, _: Modifiers) {
197        *self = Some(button);
198    }
199
200    fn format(&self) -> String {
201        self.as_ref()
202            .map(BindTarget::format)
203            .unwrap_or_else(|| "None".into())
204    }
205
206    fn clear(&mut self) {
207        *self = None;
208    }
209
210    fn down(&self, ctx: &Context) -> bool {
211        option_through!(self, ctx, down)
212    }
213
214    fn pressed(&self, ctx: &Context) -> bool {
215        option_through!(self, ctx, pressed)
216    }
217
218    fn released(&self, ctx: &Context) -> bool {
219        option_through!(self, ctx, released)
220    }
221}
222
223impl<B: BindTarget> BindTarget for (B, Modifiers) {
224    const IS_KEY: bool = B::IS_KEY;
225    const IS_POINTER: bool = B::IS_POINTER;
226    const CLEARABLE: bool = false;
227
228    fn set_key(&mut self, key: Key, modifiers: Modifiers) {
229        self.0.set_key(key, modifiers);
230        self.1 = modifiers;
231    }
232
233    fn set_pointer(&mut self, button: PointerButton, modifiers: Modifiers) {
234        self.0.set_pointer(button, modifiers);
235        self.1 = modifiers;
236    }
237
238    fn clear(&mut self) {
239        unimplemented!();
240    }
241
242    fn format(&self) -> String {
243        let mut prefix = String::with_capacity(4);
244        if self.1.ctrl || self.1.command {
245            prefix.push('^');
246        }
247
248        if self.1.shift {
249            prefix.push('_');
250        }
251
252        if self.1.alt {
253            prefix.push('*');
254        }
255
256        prefix + &self.0.format()
257    }
258
259    fn down(&self, ctx: &Context) -> bool {
260        ctx.input(|i| i.modifiers.matches_logically(self.1)) && self.0.down(ctx)
261    }
262
263    fn pressed(&self, ctx: &Context) -> bool {
264        ctx.input(|i| i.modifiers.matches_logically(self.1)) && self.0.pressed(ctx)
265    }
266
267    fn released(&self, ctx: &Context) -> bool {
268        ctx.input(|i| i.modifiers.matches_logically(self.1)) && self.0.released(ctx)
269    }
270}
271
272impl<B: BindTarget> BindTarget for Option<(B, Modifiers)> {
273    const IS_KEY: bool = B::IS_KEY;
274    const IS_POINTER: bool = B::IS_POINTER;
275    const CLEARABLE: bool = true;
276
277    fn set_key(&mut self, key: Key, modifiers: Modifiers) {
278        unsafe {
279            (self as *mut Self).write(Some(zeroed()));
280        }
281
282        if let Some((b, m)) = self {
283            b.set_key(key, modifiers);
284            *m = modifiers;
285        }
286    }
287
288    fn set_pointer(&mut self, button: PointerButton, modifiers: Modifiers) {
289        unsafe {
290            (self as *mut Self).write(Some(zeroed()));
291        }
292
293        if let Some((b, m)) = self {
294            b.set_pointer(button, modifiers);
295            *m = modifiers;
296        }
297    }
298
299    fn clear(&mut self) {
300        *self = None;
301    }
302
303    fn format(&self) -> String {
304        self.as_ref()
305            .map(BindTarget::format)
306            .unwrap_or_else(|| "None".into())
307    }
308
309    fn down(&self, ctx: &Context) -> bool {
310        if let Some(v) = self {
311            v.down(ctx)
312        } else {
313            false
314        }
315    }
316
317    fn pressed(&self, ctx: &Context) -> bool {
318        if let Some(v) = self {
319            v.pressed(ctx)
320        } else {
321            false
322        }
323    }
324
325    fn released(&self, ctx: &Context) -> bool {
326        if let Some(v) = self {
327            v.released(ctx)
328        } else {
329            false
330        }
331    }
332}
333
334#[test]
335fn test_set_opt() {
336    let mut b: Option<(Key, Modifiers)> = None;
337    let mods = Modifiers {
338        alt: true,
339        shift: true,
340        ctrl: false,
341        command: false,
342        mac_cmd: false,
343    };
344    b.set_key(Key::Tab, mods);
345
346    assert_eq!(b, Some((Key::Tab, mods)));
347}