1use egui::{Context, Event, Key, Modifiers};
3use emath::Vec2;
4
5use crate::config::ArrowKeyBindings;
6use crate::message::MessageTarget;
7use crate::{
8 message::Message,
9 wave_data::{PER_SCROLL_EVENT, SCROLL_EVENTS_PER_PAGE},
10 MoveDir, SystemState,
11};
12
13impl SystemState {
14 pub fn handle_pressed_keys(&self, ctx: &Context, msgs: &mut Vec<Message>) {
15 ctx.input(|i| {
16 i.events.iter().for_each(|event| match event {
17 Event::Key {
18 key,
19 repeat: _,
20 pressed,
21 modifiers,
22 physical_key: _,
23 } => match (
24 key,
25 pressed,
26 self.command_prompt.visible,
27 self.user.variable_name_filter_focused,
28 ) {
29 (Key::Num0, true, false, false) => {
30 handle_digit(0, modifiers, msgs);
31 }
32 (Key::Num1, true, false, false) => {
33 handle_digit(1, modifiers, msgs);
34 }
35 (Key::Num2, true, false, false) => {
36 handle_digit(2, modifiers, msgs);
37 }
38 (Key::Num3, true, false, false) => {
39 handle_digit(3, modifiers, msgs);
40 }
41 (Key::Num4, true, false, false) => {
42 handle_digit(4, modifiers, msgs);
43 }
44 (Key::Num5, true, false, false) => {
45 handle_digit(5, modifiers, msgs);
46 }
47 (Key::Num6, true, false, false) => {
48 handle_digit(6, modifiers, msgs);
49 }
50 (Key::Num7, true, false, false) => {
51 handle_digit(7, modifiers, msgs);
52 }
53 (Key::Num8, true, false, false) => {
54 handle_digit(8, modifiers, msgs);
55 }
56 (Key::Num9, true, false, false) => {
57 handle_digit(9, modifiers, msgs);
58 }
59 (Key::Home, true, false, false) => msgs.push(Message::ScrollToItem(0)),
60 (Key::End, true, false, false) => {
61 if let Some(waves) = &self.user.waves {
62 if waves.displayed_items.len() > 1 {
63 msgs.push(Message::ScrollToItem(waves.displayed_items.len() - 1));
64 }
65 }
66 }
67 (Key::Space, true, false, false) => {
68 msgs.push(Message::ShowCommandPrompt(Some("".to_string())))
69 }
70 (Key::Escape, true, true, false) => msgs.push(Message::ShowCommandPrompt(None)),
71 (Key::G, true, true, false) => {
72 if modifiers.command {
73 msgs.push(Message::ShowCommandPrompt(None))
74 }
75 }
76 (Key::G, true, false, false) => msgs.push(Message::GroupNew {
77 name: None,
78 before: None,
79 items: None,
80 }),
81 (Key::Escape, true, false, false) => {
82 msgs.push(Message::InvalidateCount);
83 msgs.push(Message::ItemSelectionClear);
84 }
85 (Key::Escape, true, _, true) => msgs.push(Message::SetFilterFocused(false)),
86 (Key::B, true, false, false) => msgs.push(Message::ToggleSidePanel),
87 (Key::M, true, false, false) => {
88 if modifiers.alt {
89 msgs.push(Message::ToggleMenu)
90 } else if let Some(waves) = self.user.waves.as_ref() {
91 if let Some(cursor) = waves.cursor.as_ref() {
92 let marker_exists = waves
94 .markers
95 .values()
96 .any(|marker_time| marker_time == cursor);
97 if !marker_exists {
98 msgs.push(Message::AddMarker {
99 time: cursor.clone(),
100 name: None,
101 move_focus: self
102 .user
103 .config
104 .layout
105 .move_focus_on_inserted_marker(),
106 });
107 }
108 }
109 }
110 }
111 (Key::T, true, false, false) => msgs.push(Message::ToggleToolbar),
112 (Key::F11, true, false, _) => msgs.push(Message::ToggleFullscreen),
113 (Key::U, true, false, false) => {
114 if modifiers.shift {
115 msgs.push(Message::Redo(self.get_count()));
116 } else {
117 msgs.push(Message::Undo(self.get_count()));
118 }
119 }
120 (Key::Z, true, false, false) => {
121 if modifiers.ctrl {
122 msgs.push(Message::Undo(self.get_count()));
123 }
124 }
125 (Key::Y, true, false, false) => {
126 if modifiers.ctrl {
127 msgs.push(Message::Redo(self.get_count()));
128 }
129 }
130 (Key::F, true, false, false) => {
131 msgs.push(Message::ShowCommandPrompt(Some("item_focus ".to_string())))
132 }
133 (Key::S, true, false, false) => {
134 if modifiers.command {
135 msgs.push(Message::SaveStateFile(self.user.state_file.clone()));
136 } else {
137 msgs.push(Message::GoToStart { viewport_idx: 0 });
138 }
139 }
140 (Key::A, true, false, false) => {
141 if modifiers.command {
142 msgs.push(Message::ItemSelectAll);
143 } else {
144 msgs.push(Message::ToggleItemSelected(None));
145 }
146 }
147 (Key::E, true, false, false) => msgs.push(Message::GoToEnd { viewport_idx: 0 }),
148 (Key::R, true, false, false) => msgs.push(Message::ReloadWaveform(
149 self.user.config.behavior.keep_during_reload,
150 )),
151 (Key::H, true, false, false) => msgs.push(Message::MoveCursorToTransition {
152 next: false,
153 variable: None,
154 skip_zero: modifiers.shift,
155 }),
156 (Key::L, true, false, false) => msgs.push(Message::MoveCursorToTransition {
157 next: true,
158 variable: None,
159 skip_zero: modifiers.shift,
160 }),
161 (Key::Minus, true, false, false) => msgs.push(Message::CanvasZoom {
162 mouse_ptr: None,
163 delta: 2.0,
164 viewport_idx: 0,
165 }),
166 (Key::Plus | Key::Equals, true, false, false) => {
167 msgs.push(Message::CanvasZoom {
168 mouse_ptr: None,
169 delta: 0.5,
170 viewport_idx: 0,
171 });
172 }
173 (Key::PageUp, true, false, false) => msgs.push(Message::CanvasScroll {
174 delta: Vec2 {
175 x: 0.,
176 y: -PER_SCROLL_EVENT * SCROLL_EVENTS_PER_PAGE,
177 },
178 viewport_idx: 0,
179 }),
180 (Key::PageDown, true, false, false) => msgs.push(Message::CanvasScroll {
181 delta: Vec2 {
182 x: 0.,
183 y: PER_SCROLL_EVENT * SCROLL_EVENTS_PER_PAGE,
184 },
185 viewport_idx: 0,
186 }),
187 (Key::ArrowRight, true, false, false) => {
188 msgs.push(match self.user.config.behavior.arrow_key_bindings {
189 ArrowKeyBindings::Edge => Message::MoveCursorToTransition {
190 next: true,
191 variable: None,
192 skip_zero: modifiers.shift,
193 },
194 ArrowKeyBindings::Scroll => Message::CanvasScroll {
195 delta: Vec2 {
196 x: 0.,
197 y: -PER_SCROLL_EVENT,
198 },
199 viewport_idx: 0,
200 },
201 });
202 }
203 (Key::ArrowLeft, true, false, false) => {
204 msgs.push(match self.user.config.behavior.arrow_key_bindings {
205 ArrowKeyBindings::Edge => Message::MoveCursorToTransition {
206 next: false,
207 variable: None,
208 skip_zero: modifiers.shift,
209 },
210 ArrowKeyBindings::Scroll => Message::CanvasScroll {
211 delta: Vec2 {
212 x: 0.,
213 y: PER_SCROLL_EVENT,
214 },
215 viewport_idx: 0,
216 },
217 });
218 }
219 (Key::J, true, false, false) => {
220 if modifiers.alt {
221 msgs.push(Message::MoveFocus(
222 MoveDir::Down,
223 self.get_count(),
224 modifiers.shift,
225 ));
226 } else if modifiers.command {
227 msgs.push(Message::MoveFocusedItem(MoveDir::Down, self.get_count()));
228 } else {
229 msgs.push(Message::VerticalScroll(MoveDir::Down, self.get_count()));
230 }
231 msgs.push(Message::InvalidateCount);
232 }
233 (Key::K, true, false, false) => {
234 if modifiers.alt {
235 msgs.push(Message::MoveFocus(
236 MoveDir::Up,
237 self.get_count(),
238 modifiers.shift,
239 ));
240 } else if modifiers.command {
241 msgs.push(Message::MoveFocusedItem(MoveDir::Up, self.get_count()));
242 } else {
243 msgs.push(Message::VerticalScroll(MoveDir::Up, self.get_count()));
244 }
245 msgs.push(Message::InvalidateCount);
246 }
247 (Key::ArrowDown, true, false, false) => {
248 if modifiers.alt {
249 msgs.push(Message::MoveFocus(
250 MoveDir::Down,
251 self.get_count(),
252 modifiers.shift,
253 ));
254 } else if modifiers.command {
255 msgs.push(Message::MoveFocusedItem(MoveDir::Down, self.get_count()));
256 } else {
257 msgs.push(Message::VerticalScroll(MoveDir::Down, self.get_count()));
258 }
259 msgs.push(Message::InvalidateCount);
260 }
261 (Key::ArrowUp, true, false, false) => {
262 if modifiers.alt {
263 msgs.push(Message::MoveFocus(
264 MoveDir::Up,
265 self.get_count(),
266 modifiers.shift,
267 ));
268 } else if modifiers.command {
269 msgs.push(Message::MoveFocusedItem(MoveDir::Up, self.get_count()));
270 } else {
271 msgs.push(Message::VerticalScroll(MoveDir::Up, self.get_count()));
272 }
273 msgs.push(Message::InvalidateCount);
274 }
275 (Key::Delete | Key::X, true, false, false) => {
276 if let Some(waves) = &self.user.waves {
277 let mut remove_ids = waves
278 .items_tree
279 .iter_visible_selected()
280 .map(|i| i.item_ref)
281 .collect::<Vec<_>>();
282 if let Some(node) = waves
283 .focused_item
284 .and_then(|focus| waves.items_tree.get_visible(focus))
285 {
286 remove_ids.push(node.item_ref)
287 }
288
289 msgs.push(Message::RemoveItems(remove_ids));
290 }
291 }
292 (Key::ArrowUp, true, true, false) => msgs.push(Message::SelectPrevCommand),
293 (Key::P, true, true, false) => {
294 if modifiers.command {
295 msgs.push(Message::SelectPrevCommand);
296 }
297 }
298 (Key::ArrowDown, true, true, false) => msgs.push(Message::SelectNextCommand),
299 (Key::N, true, true, false) => {
300 if modifiers.command {
301 msgs.push(Message::SelectNextCommand);
302 }
303 }
304 _ => {}
305 },
306 Event::Copy => msgs.push(Message::VariableValueToClipbord(
307 MessageTarget::CurrentSelection,
308 )),
309 _ => {}
310 });
311 });
312 }
313
314 pub fn get_count(&self) -> usize {
315 if let Some(count) = &self.user.count {
316 count.parse::<usize>().unwrap_or(1)
317 } else {
318 1
319 }
320 }
321}
322
323fn handle_digit(digit: u8, modifiers: &Modifiers, msgs: &mut Vec<Message>) {
324 if modifiers.alt {
325 msgs.push(Message::AddCount((digit + 48) as char));
326 } else if modifiers.command {
327 msgs.push(Message::MoveMarkerToCursor(digit));
328 } else {
329 msgs.push(Message::GoToMarkerPosition(digit, 0));
330 }
331}