1use fret_core::{Modifiers, MouseButton};
2
3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
4pub struct ModifiersMask {
5 pub shift: bool,
6 pub ctrl: bool,
7 pub alt: bool,
8 pub alt_gr: bool,
9 pub meta: bool,
10}
11
12impl ModifiersMask {
13 pub const NONE: Self = Self {
14 shift: false,
15 ctrl: false,
16 alt: false,
17 alt_gr: false,
18 meta: false,
19 };
20
21 pub fn matches(self, modifiers: Modifiers, allow_extra: bool) -> bool {
22 let required = self;
23 if required.shift && !modifiers.shift {
24 return false;
25 }
26 if required.ctrl && !modifiers.ctrl {
27 return false;
28 }
29 if required.alt && !modifiers.alt {
30 return false;
31 }
32 if required.alt_gr && !modifiers.alt_gr {
33 return false;
34 }
35 if required.meta && !modifiers.meta {
36 return false;
37 }
38
39 if allow_extra {
40 return true;
41 }
42
43 if modifiers.shift != required.shift {
44 return false;
45 }
46 if modifiers.ctrl != required.ctrl {
47 return false;
48 }
49 if modifiers.alt != required.alt {
50 return false;
51 }
52 if modifiers.alt_gr != required.alt_gr {
53 return false;
54 }
55 if modifiers.meta != required.meta {
56 return false;
57 }
58
59 true
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum ModifierKey {
65 Shift,
66 Ctrl,
67 Alt,
68 AltGr,
69 Meta,
70}
71
72impl ModifierKey {
73 pub fn is_pressed(self, modifiers: Modifiers) -> bool {
74 match self {
75 Self::Shift => modifiers.shift,
76 Self::Ctrl => modifiers.ctrl,
77 Self::Alt => modifiers.alt,
78 Self::AltGr => modifiers.alt_gr,
79 Self::Meta => modifiers.meta,
80 }
81 }
82
83 pub fn is_required_by(self, required: ModifiersMask) -> bool {
84 match self {
85 Self::Shift => required.shift,
86 Self::Ctrl => required.ctrl,
87 Self::Alt => required.alt,
88 Self::AltGr => required.alt_gr,
89 Self::Meta => required.meta,
90 }
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub struct PointerChord {
96 pub button: MouseButton,
97 pub modifiers: ModifiersMask,
98 pub allow_extra_modifiers: bool,
99}
100
101impl PointerChord {
102 pub const fn new(button: MouseButton, modifiers: ModifiersMask) -> Self {
103 Self {
104 button,
105 modifiers,
106 allow_extra_modifiers: false,
107 }
108 }
109
110 pub fn matches(self, button: MouseButton, modifiers: Modifiers) -> bool {
111 if self.button != button {
112 return false;
113 }
114 self.modifiers
115 .matches(modifiers, self.allow_extra_modifiers)
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub struct ChartInputMap {
121 pub pan: PointerChord,
122 pub box_zoom: PointerChord,
123 pub box_zoom_alt: Option<PointerChord>,
124 pub box_zoom_cancel: Option<PointerChord>,
125 pub brush_select: PointerChord,
126 pub box_zoom_expand_x: Option<ModifierKey>,
127 pub box_zoom_expand_y: Option<ModifierKey>,
128 pub wheel_zoom_mod: Option<ModifierKey>,
129 pub axis_lock_toggle: PointerChord,
130}
131
132impl Default for ChartInputMap {
133 fn default() -> Self {
134 Self {
142 pan: PointerChord::new(MouseButton::Left, ModifiersMask::NONE),
143 box_zoom: PointerChord::new(MouseButton::Right, ModifiersMask::NONE),
144 box_zoom_alt: Some(PointerChord::new(
145 MouseButton::Left,
146 ModifiersMask {
147 shift: true,
148 ..ModifiersMask::NONE
149 },
150 )),
151 box_zoom_cancel: Some(PointerChord::new(MouseButton::Left, ModifiersMask::NONE)),
152 brush_select: PointerChord::new(
153 MouseButton::Right,
154 ModifiersMask {
155 alt: true,
156 ..ModifiersMask::NONE
157 },
158 ),
159 box_zoom_expand_x: Some(ModifierKey::Alt),
160 box_zoom_expand_y: Some(ModifierKey::Shift),
161 wheel_zoom_mod: None,
162 axis_lock_toggle: PointerChord::new(
163 MouseButton::Left,
164 ModifiersMask {
165 ctrl: true,
166 ..ModifiersMask::NONE
167 },
168 ),
169 }
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn modifiers_mask_exact_vs_allow_extra() {
179 let required = ModifiersMask {
180 shift: true,
181 ..ModifiersMask::NONE
182 };
183 let mods = Modifiers {
184 shift: true,
185 ctrl: true,
186 ..Modifiers::default()
187 };
188 assert!(!required.matches(mods, false));
189 assert!(required.matches(mods, true));
190 }
191}