1use egui::{Context, Key, Modifiers, PointerButton};
2use std::mem::zeroed;
3
4pub trait BindTarget: Clone {
6 const IS_KEY: bool;
8 const IS_POINTER: bool;
10
11 const CLEARABLE: bool;
13
14 fn set_key(&mut self, key: Key, modifiers: Modifiers);
16
17 fn set_pointer(&mut self, button: PointerButton, modifiers: Modifiers);
19
20 fn clear(&mut self);
22
23 fn format(&self) -> String;
25
26 fn down(&self, ctx: &Context) -> bool;
28
29 fn pressed(&self, ctx: &Context) -> bool;
31
32 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}