yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
shortcut_configurator.cc
Go to the documentation of this file.
2
3#include "absl/functional/bind_front.h"
4#include "absl/strings/str_format.h"
5#include "absl/strings/str_split.h"
17#include "core/project.h"
18
19namespace yaze::editor {
20
21namespace {
22
23void RegisterIfValid(ShortcutManager* shortcut_manager, const std::string& name,
24 const std::vector<ImGuiKey>& keys,
25 std::function<void()> callback,
27 if (!shortcut_manager || !callback) {
28 return;
29 }
30 shortcut_manager->RegisterShortcut(name, keys, std::move(callback), scope);
31}
32
33void RegisterIfValid(ShortcutManager* shortcut_manager, const std::string& name,
34 ImGuiKey key, std::function<void()> callback,
36 if (!shortcut_manager || !callback) {
37 return;
38 }
39 shortcut_manager->RegisterShortcut(name, key, std::move(callback), scope);
40}
41
43 std::string id;
44 std::vector<ImGuiKey> keys;
45 std::string description;
46};
47
48const std::vector<EditorShortcutDef> kMusicEditorShortcuts = {
49 {"music.play_pause", {ImGuiKey_Space}, "Play/Pause current song"},
50 {"music.stop", {ImGuiKey_Escape}, "Stop playback"},
51 {"music.speed_up", {ImGuiKey_Equal}, "Increase playback speed"},
52 {"music.speed_up_keypad", {ImGuiKey_KeypadAdd}, "Increase playback speed (keypad)"},
53 {"music.speed_down", {ImGuiKey_Minus}, "Decrease playback speed"},
54 {"music.speed_down_keypad", {ImGuiKey_KeypadSubtract}, "Decrease playback speed (keypad)"},
55};
56
57const std::vector<EditorShortcutDef> kDungeonEditorShortcuts = {
58 {"dungeon.object.select_tool", {ImGuiKey_S}, "Select tool"},
59 {"dungeon.object.place_tool", {ImGuiKey_P}, "Place tool"},
60 {"dungeon.object.delete_tool", {ImGuiKey_D}, "Delete tool"},
61 {"dungeon.object.next_object", {ImGuiKey_RightBracket}, "Next object"},
62 {"dungeon.object.prev_object", {ImGuiKey_LeftBracket}, "Previous object"},
63 {"dungeon.object.copy", {ImGuiMod_Ctrl, ImGuiKey_C}, "Copy selection"},
64 {"dungeon.object.paste", {ImGuiMod_Ctrl, ImGuiKey_V}, "Paste selection"},
65 {"dungeon.object.delete", {ImGuiKey_Delete}, "Delete selection"},
66};
67
68const std::vector<EditorShortcutDef> kOverworldShortcuts = {
69 {"overworld.brush_toggle", {ImGuiKey_B}, "Toggle brush"},
70 {"overworld.fill", {ImGuiKey_F}, "Fill tool"},
71 {"overworld.next_tile", {ImGuiKey_RightBracket}, "Next tile"},
72 {"overworld.prev_tile", {ImGuiKey_LeftBracket}, "Previous tile"},
73};
74
75const std::vector<EditorShortcutDef> kGraphicsShortcuts = {
76 // Sheet navigation
77 {"graphics.next_sheet", {ImGuiKey_PageDown}, "Next sheet"},
78 {"graphics.prev_sheet", {ImGuiKey_PageUp}, "Previous sheet"},
79
80 // Tool selection shortcuts
81 {"graphics.tool.select", {ImGuiKey_V}, "Select tool"},
82 {"graphics.tool.pencil", {ImGuiKey_B}, "Pencil tool"},
83 {"graphics.tool.brush", {ImGuiKey_P}, "Brush tool"},
84 {"graphics.tool.eraser", {ImGuiKey_E}, "Eraser tool"},
85 {"graphics.tool.fill", {ImGuiKey_G}, "Fill tool"},
86 {"graphics.tool.line", {ImGuiKey_L}, "Line tool"},
87 {"graphics.tool.rectangle", {ImGuiKey_R}, "Rectangle tool"},
88 {"graphics.tool.eyedropper", {ImGuiKey_I}, "Eyedropper tool"},
89
90 // Zoom controls
91 {"graphics.zoom_in", {ImGuiKey_Equal}, "Zoom in"},
92 {"graphics.zoom_in_keypad", {ImGuiKey_KeypadAdd}, "Zoom in (keypad)"},
93 {"graphics.zoom_out", {ImGuiKey_Minus}, "Zoom out"},
94 {"graphics.zoom_out_keypad", {ImGuiKey_KeypadSubtract}, "Zoom out (keypad)"},
95
96 // View toggles
97 {"graphics.toggle_grid", {ImGuiMod_Ctrl, ImGuiKey_G}, "Toggle grid"},
98};
99
100} // namespace
101
103 ShortcutManager* shortcut_manager) {
104 if (!shortcut_manager) {
105 return;
106 }
107
108 auto* editor_manager = deps.editor_manager;
109 auto* ui_coordinator = deps.ui_coordinator;
110 auto* popup_manager = deps.popup_manager;
111 auto* panel_manager = deps.panel_manager;
112
113 // Toggle activity bar (48px icon strip) visibility
114 RegisterIfValid(shortcut_manager, "view.toggle_activity_bar",
115 {ImGuiMod_Ctrl, ImGuiKey_B},
116 [panel_manager]() {
117 if (panel_manager) {
118 panel_manager->ToggleSidebarVisibility();
119 }
120 },
122
123 // Toggle side panel (250px expanded panel) expansion
124 RegisterIfValid(shortcut_manager, "view.toggle_side_panel",
125 {ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_E},
126 [panel_manager]() {
127 if (panel_manager) {
128 panel_manager->TogglePanelExpanded();
129 }
130 },
132
133 RegisterIfValid(shortcut_manager, "Open", {ImGuiMod_Ctrl, ImGuiKey_O},
134 [editor_manager]() {
135 if (editor_manager) {
136 editor_manager->LoadRom();
137 }
139
140 RegisterIfValid(shortcut_manager, "Save", {ImGuiMod_Ctrl, ImGuiKey_S},
141 [editor_manager]() {
142 if (editor_manager) {
143 editor_manager->SaveRom();
144 }
145 });
146
147 RegisterIfValid(shortcut_manager, "Save As",
148 {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_S},
149 [editor_manager]() {
150 if (editor_manager) {
151 // Use project-aware default filename when possible
152 std::string filename =
153 editor_manager->GetCurrentRom()
154 ? editor_manager->GetCurrentRom()->filename()
155 : "";
156 editor_manager->SaveRomAs(filename);
157 }
158 },
160
161 RegisterIfValid(shortcut_manager, "Close ROM", {ImGuiMod_Ctrl, ImGuiKey_W},
162 [editor_manager]() {
163 if (editor_manager && editor_manager->GetCurrentRom()) {
164 editor_manager->GetCurrentRom()->Close();
165 }
166 },
168
169 RegisterIfValid(shortcut_manager, "Quit", {ImGuiMod_Ctrl, ImGuiKey_Q},
170 [editor_manager]() {
171 if (editor_manager) {
172 editor_manager->Quit();
173 }
174 },
176
177 RegisterIfValid(shortcut_manager, "Undo", {ImGuiMod_Ctrl, ImGuiKey_Z},
178 [editor_manager]() {
179 if (editor_manager && editor_manager->GetCurrentEditor()) {
180 editor_manager->GetCurrentEditor()->Undo();
181 }
183
184 RegisterIfValid(shortcut_manager, "Redo", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_Z},
185 [editor_manager]() {
186 if (editor_manager && editor_manager->GetCurrentEditor()) {
187 editor_manager->GetCurrentEditor()->Redo();
188 }
190
191 RegisterIfValid(shortcut_manager, "Cut", {ImGuiMod_Ctrl, ImGuiKey_X},
192 [editor_manager]() {
193 if (editor_manager && editor_manager->GetCurrentEditor()) {
194 editor_manager->GetCurrentEditor()->Cut();
195 }
197
198 RegisterIfValid(shortcut_manager, "Copy", {ImGuiMod_Ctrl, ImGuiKey_C},
199 [editor_manager]() {
200 if (editor_manager && editor_manager->GetCurrentEditor()) {
201 editor_manager->GetCurrentEditor()->Copy();
202 }
204
205 RegisterIfValid(shortcut_manager, "Paste", {ImGuiMod_Ctrl, ImGuiKey_V},
206 [editor_manager]() {
207 if (editor_manager && editor_manager->GetCurrentEditor()) {
208 editor_manager->GetCurrentEditor()->Paste();
209 }
211
212 RegisterIfValid(shortcut_manager, "Find", {ImGuiMod_Ctrl, ImGuiKey_F},
213 [editor_manager]() {
214 if (editor_manager && editor_manager->GetCurrentEditor()) {
215 editor_manager->GetCurrentEditor()->Find();
216 }
218
219 RegisterIfValid(shortcut_manager, "Command Palette", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_P},
220 [ui_coordinator]() {
221 if (ui_coordinator) {
222 ui_coordinator->ShowCommandPalette();
223 }
224 },
226
227 RegisterIfValid(shortcut_manager, "Global Search", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_K},
228 [ui_coordinator]() {
229 if (ui_coordinator) {
230 ui_coordinator->ShowGlobalSearch();
231 }
232 },
234
235 RegisterIfValid(
236 shortcut_manager, "Load Last ROM", {ImGuiMod_Ctrl, ImGuiKey_R},
237 [editor_manager]() {
239 if (!recent.GetRecentFiles().empty() && editor_manager) {
240 editor_manager->OpenRomOrProject(recent.GetRecentFiles().front());
241 }
243
244 RegisterIfValid(shortcut_manager, "Show About", ImGuiKey_F1,
245 [popup_manager]() {
246 if (popup_manager) {
247 popup_manager->Show("About");
248 }
250
251 auto register_editor_shortcut = [&](EditorType type, ImGuiKey key) {
252 RegisterIfValid(shortcut_manager,
253 absl::StrFormat("switch.%d", static_cast<int>(type)),
254 {ImGuiMod_Ctrl, key}, [editor_manager, type]() {
255 if (editor_manager) {
256 editor_manager->SwitchToEditor(type);
257 }
258 });
259 };
260
261 register_editor_shortcut(EditorType::kOverworld, ImGuiKey_1);
262 register_editor_shortcut(EditorType::kDungeon, ImGuiKey_2);
263 register_editor_shortcut(EditorType::kGraphics, ImGuiKey_3);
264 register_editor_shortcut(EditorType::kSprite, ImGuiKey_4);
265 register_editor_shortcut(EditorType::kMessage, ImGuiKey_5);
266 register_editor_shortcut(EditorType::kMusic, ImGuiKey_6);
267 register_editor_shortcut(EditorType::kPalette, ImGuiKey_7);
268 register_editor_shortcut(EditorType::kScreen, ImGuiKey_8);
269 register_editor_shortcut(EditorType::kAssembly, ImGuiKey_9);
270 register_editor_shortcut(EditorType::kSettings, ImGuiKey_0);
271
272 // Editor-scoped Music shortcuts (toggle playback, speed controls)
273 if (editor_manager) {
274 auto* editor_set = editor_manager->GetCurrentEditorSet();
275 if (editor_set && editor_set->GetMusicEditor()) {
276 auto* music_editor = editor_set->GetMusicEditor();
277 for (const auto& def : kMusicEditorShortcuts) {
278 RegisterIfValid(shortcut_manager, def.id, def.keys,
279 [music_editor, id = def.id]() {
280 if (!music_editor) return;
281 if (id == "music.play_pause") {
282 music_editor->TogglePlayPause();
283 } else if (id == "music.stop") {
284 music_editor->StopPlayback();
285 } else if (id == "music.speed_up" ||
286 id == "music.speed_up_keypad") {
287 music_editor->SpeedUp();
288 } else if (id == "music.speed_down" ||
289 id == "music.speed_down_keypad") {
290 music_editor->SlowDown();
291 }
292 },
294 }
295 }
296 }
297
298 // Editor-scoped Dungeon shortcuts (object tools)
299 if (editor_manager) {
300 auto* editor_set = editor_manager->GetCurrentEditorSet();
301 if (editor_set && editor_set->GetDungeonEditor()) {
302 auto* dungeon_editor = editor_set->GetDungeonEditor();
303 for (const auto& def : kDungeonEditorShortcuts) {
304 RegisterIfValid(shortcut_manager, def.id, def.keys,
305 [dungeon_editor, id = def.id]() {
306 if (!dungeon_editor) return;
307 auto* obj_panel = dungeon_editor->object_editor_panel();
308 if (!obj_panel) return;
309 if (id == "dungeon.object.select_tool") {
310 // Unified mode: cancel placement to switch to selection
311 obj_panel->CancelPlacement();
312 } else if (id == "dungeon.object.place_tool") {
313 // Unified mode: handled by object selector click
314 // No-op (mode is controlled by selecting an object)
315 } else if (id == "dungeon.object.delete_tool") {
316 // Unified mode: delete selected objects
317 obj_panel->DeleteSelectedObjects();
318 } else if (id == "dungeon.object.next_object") {
319 obj_panel->CycleObjectSelection(1);
320 } else if (id == "dungeon.object.prev_object") {
321 obj_panel->CycleObjectSelection(-1);
322 } else if (id == "dungeon.object.copy") {
323 obj_panel->CopySelectedObjects();
324 } else if (id == "dungeon.object.paste") {
325 obj_panel->PasteObjects();
326 } else if (id == "dungeon.object.delete") {
327 obj_panel->DeleteSelectedObjects();
328 }
329 },
331 }
332 }
333 }
334
335 // Editor-scoped Overworld shortcuts (basic tools)
336 if (editor_manager) {
337 auto* editor_set = editor_manager->GetCurrentEditorSet();
338 if (editor_set && editor_set->GetOverworldEditor()) {
339 auto* overworld_editor = editor_set->GetOverworldEditor();
340 for (const auto& def : kOverworldShortcuts) {
341 RegisterIfValid(shortcut_manager, def.id, def.keys,
342 [overworld_editor, id = def.id]() {
343 if (!overworld_editor) return;
344 if (id == "overworld.brush_toggle") {
345 overworld_editor->ToggleBrushTool();
346 } else if (id == "overworld.fill") {
347 overworld_editor->ActivateFillTool();
348 } else if (id == "overworld.next_tile") {
349 overworld_editor->CycleTileSelection(1);
350 } else if (id == "overworld.prev_tile") {
351 overworld_editor->CycleTileSelection(-1);
352 }
353 },
354 Shortcut::Scope::kEditor);
355 }
356 }
357 }
358
359 // Editor-scoped Graphics shortcuts (sheet navigation)
360 if (editor_manager) {
361 auto* editor_set = editor_manager->GetCurrentEditorSet();
362 if (editor_set && editor_set->GetGraphicsEditor()) {
363 auto* graphics_editor = editor_set->GetGraphicsEditor();
364 for (const auto& def : kGraphicsShortcuts) {
365 RegisterIfValid(shortcut_manager, def.id, def.keys,
366 [graphics_editor, id = def.id]() {
367 if (!graphics_editor) return;
368 if (id == "graphics.next_sheet") {
369 graphics_editor->NextSheet();
370 } else if (id == "graphics.prev_sheet") {
371 graphics_editor->PrevSheet();
372 }
373 },
374 Shortcut::Scope::kEditor);
375 }
376 }
377 }
378
379
380 RegisterIfValid(shortcut_manager, "Editor Selection", {ImGuiMod_Ctrl, ImGuiKey_E},
381 [ui_coordinator]() {
382 if (ui_coordinator) {
383 ui_coordinator->ShowEditorSelection();
384 }
385 }, Shortcut::Scope::kGlobal);
386
387 RegisterIfValid(shortcut_manager, "Panel Browser", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_B},
388 [ui_coordinator]() {
389 if (ui_coordinator) {
390 ui_coordinator->ShowPanelBrowser();
391 }
392 }, Shortcut::Scope::kGlobal);
393 RegisterIfValid(shortcut_manager, "Panel Browser (Alt)", {ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_P},
394 [ui_coordinator]() {
395 if (ui_coordinator) {
396 ui_coordinator->ShowPanelBrowser();
397 }
398 }, Shortcut::Scope::kGlobal);
399
400 if (panel_manager) {
401 // Note: Using Ctrl+Alt for panel shortcuts to avoid conflicts with Save As
402 // (Ctrl+Shift+S)
403 RegisterIfValid(shortcut_manager, "Show Dungeon Panels", {ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_D},
404 [panel_manager]() {
405 panel_manager->ShowAllPanelsInCategory(0, "Dungeon");
406 }, Shortcut::Scope::kEditor);
407 RegisterIfValid(shortcut_manager, "Show Graphics Panels", {ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_G},
408 [panel_manager]() {
409 panel_manager->ShowAllPanelsInCategory(0, "Graphics");
410 }, Shortcut::Scope::kEditor);
411 RegisterIfValid(shortcut_manager, "Show Screen Panels", {ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_S},
412 [panel_manager]() {
413 panel_manager->ShowAllPanelsInCategory(0, "Screen");
414 }, Shortcut::Scope::kEditor);
415 }
416
417#ifdef YAZE_BUILD_AGENT_UI
418 RegisterIfValid(shortcut_manager, "Agent Editor", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_A}, [editor_manager]() {
419 if (editor_manager) {
420 editor_manager->ShowAIAgent();
421 }
422 });
423
424 RegisterIfValid(shortcut_manager, "Agent Sidebar", {ImGuiMod_Ctrl, ImGuiKey_H}, [editor_manager]() {
425 if (editor_manager) {
426 editor_manager->ShowChatHistory();
427 }
428 });
429
430 RegisterIfValid(shortcut_manager, "Proposal Drawer",
431 {ImGuiMod_Ctrl, ImGuiMod_Shift,
432 ImGuiKey_R}, // Changed from Ctrl+P to Ctrl+Shift+R
433 [editor_manager]() {
434 if (editor_manager) {
435 editor_manager->ShowProposalDrawer();
436 }
437 });
438#endif
439
440 // ============================================================================
441 // Layout Presets (command palette only - no keyboard shortcuts)
442 // ============================================================================
443 shortcut_manager->RegisterCommand("Layout: Apply Minimal Preset",
444 [editor_manager]() {
445 if (editor_manager) {
446 editor_manager->ApplyLayoutPreset("Minimal");
447 }
448 });
449 shortcut_manager->RegisterCommand("Layout: Apply Developer Preset",
450 [editor_manager]() {
451 if (editor_manager) {
452 editor_manager->ApplyLayoutPreset("Developer");
453 }
454 });
455 shortcut_manager->RegisterCommand("Layout: Apply Designer Preset",
456 [editor_manager]() {
457 if (editor_manager) {
458 editor_manager->ApplyLayoutPreset("Designer");
459 }
460 });
461 shortcut_manager->RegisterCommand("Layout: Apply Modder Preset",
462 [editor_manager]() {
463 if (editor_manager) {
464 editor_manager->ApplyLayoutPreset("Modder");
465 }
466 });
467 shortcut_manager->RegisterCommand("Layout: Apply Overworld Expert Preset",
468 [editor_manager]() {
469 if (editor_manager) {
470 editor_manager->ApplyLayoutPreset("Overworld Expert");
471 }
472 });
473 shortcut_manager->RegisterCommand("Layout: Apply Dungeon Expert Preset",
474 [editor_manager]() {
475 if (editor_manager) {
476 editor_manager->ApplyLayoutPreset("Dungeon Expert");
477 }
478 });
479 shortcut_manager->RegisterCommand("Layout: Apply Testing Preset",
480 [editor_manager]() {
481 if (editor_manager) {
482 editor_manager->ApplyLayoutPreset("Testing");
483 }
484 });
485 shortcut_manager->RegisterCommand("Layout: Apply Audio Preset",
486 [editor_manager]() {
487 if (editor_manager) {
488 editor_manager->ApplyLayoutPreset("Audio");
489 }
490 });
491 shortcut_manager->RegisterCommand("Layout: Reset Current Editor",
492 [editor_manager]() {
493 if (editor_manager) {
494 editor_manager->ResetCurrentEditorLayout();
495 }
496 });
497}
498
500 ShortcutManager* shortcut_manager) {
501 if (!shortcut_manager) {
502 return;
503 }
504
505 auto* menu_orchestrator = deps.menu_orchestrator;
506 auto* session_coordinator = deps.session_coordinator;
507 auto* workspace_manager = deps.workspace_manager;
508
509 RegisterIfValid(shortcut_manager, "New Session", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_N}, [session_coordinator]() {
510 if (session_coordinator) {
511 session_coordinator->CreateNewSession();
512 }
513 });
514
515 RegisterIfValid(shortcut_manager, "Duplicate Session", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_D}, [session_coordinator]() {
516 if (session_coordinator) {
517 session_coordinator->DuplicateCurrentSession();
518 }
519 });
520
521 RegisterIfValid(shortcut_manager, "Close Session", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_W}, [session_coordinator]() {
522 if (session_coordinator) {
523 session_coordinator->CloseCurrentSession();
524 }
525 });
526
527 RegisterIfValid(shortcut_manager, "Session Switcher", {ImGuiMod_Ctrl, ImGuiKey_Tab}, [session_coordinator]() {
528 if (session_coordinator) {
529 session_coordinator->ShowSessionSwitcher();
530 }
531 });
532
533 RegisterIfValid(shortcut_manager, "Save Layout", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_L}, [workspace_manager]() {
534 if (workspace_manager) {
535 workspace_manager->SaveWorkspaceLayout();
536 }
537 });
538
539 RegisterIfValid(shortcut_manager, "Load Layout", {ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_O}, [workspace_manager]() {
540 if (workspace_manager) {
541 workspace_manager->LoadWorkspaceLayout();
542 }
543 });
544
545 // Note: Changed from Ctrl+Shift+R to Ctrl+Alt+R to avoid conflict with
546 // Proposal Drawer
547 RegisterIfValid(shortcut_manager, "Reset Layout", {ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_R}, [workspace_manager]() {
548 if (workspace_manager) {
549 workspace_manager->ResetWorkspaceLayout();
550 }
551 });
552
553 RegisterIfValid(shortcut_manager, "Maximize Window", ImGuiKey_F11,
554 [workspace_manager]() {
555 if (workspace_manager) {
556 workspace_manager->MaximizeCurrentWindow();
557 }
558 });
559
560#ifdef YAZE_ENABLE_TESTING
561 RegisterIfValid(shortcut_manager, "Test Dashboard",
562 {ImGuiMod_Ctrl, ImGuiKey_T},
563 [menu_orchestrator]() {
564 if (menu_orchestrator) {
565 menu_orchestrator->OnShowTestDashboard();
566 }
567 });
568#endif
569}
570
571namespace {
572
573// Helper to parse shortcut strings like "Ctrl+Shift+R" into ImGuiKey combinations
574std::vector<ImGuiKey> ParseShortcutString(const std::string& shortcut) {
575 std::vector<ImGuiKey> keys;
576 if (shortcut.empty()) {
577 return keys;
578 }
579
580 std::vector<std::string> parts = absl::StrSplit(shortcut, '+');
581
582 for (const auto& part : parts) {
583 std::string trimmed = part;
584 // Trim whitespace
585 while (!trimmed.empty() && (trimmed.front() == ' ' || trimmed.front() == '\t')) {
586 trimmed = trimmed.substr(1);
587 }
588 while (!trimmed.empty() && (trimmed.back() == ' ' || trimmed.back() == '\t')) {
589 trimmed.pop_back();
590 }
591
592 if (trimmed.empty()) continue;
593
594 // Modifiers
595 if (trimmed == "Ctrl" || trimmed == "Control") {
596 keys.push_back(ImGuiMod_Ctrl);
597 } else if (trimmed == "Shift") {
598 keys.push_back(ImGuiMod_Shift);
599 } else if (trimmed == "Alt") {
600 keys.push_back(ImGuiMod_Alt);
601 } else if (trimmed == "Super" || trimmed == "Win" || trimmed == "Cmd") {
602 keys.push_back(ImGuiMod_Super);
603 }
604 // Letter keys
605 else if (trimmed.length() == 1 && trimmed[0] >= 'A' && trimmed[0] <= 'Z') {
606 keys.push_back(static_cast<ImGuiKey>(ImGuiKey_A + (trimmed[0] - 'A')));
607 }
608 else if (trimmed.length() == 1 && trimmed[0] >= 'a' && trimmed[0] <= 'z') {
609 keys.push_back(static_cast<ImGuiKey>(ImGuiKey_A + (trimmed[0] - 'a')));
610 }
611 // Number keys
612 else if (trimmed.length() == 1 && trimmed[0] >= '0' && trimmed[0] <= '9') {
613 keys.push_back(static_cast<ImGuiKey>(ImGuiKey_0 + (trimmed[0] - '0')));
614 }
615 // Function keys
616 else if (trimmed[0] == 'F' && trimmed.length() >= 2) {
617 try {
618 int fnum = std::stoi(trimmed.substr(1));
619 if (fnum >= 1 && fnum <= 12) {
620 keys.push_back(static_cast<ImGuiKey>(ImGuiKey_F1 + (fnum - 1)));
621 }
622 } catch (const std::exception&) {
623 // Invalid function key format (e.g., "Fabc") - skip this key
624 }
625 }
626 }
627
628 return keys;
629}
630
631} // namespace
632
634 ShortcutManager* shortcut_manager) {
635 if (!shortcut_manager || !deps.panel_manager) {
636 return;
637 }
638
639 auto* panel_manager = deps.panel_manager;
640 auto* user_settings = deps.user_settings;
641 int session_id = deps.session_coordinator ? deps.session_coordinator->GetActiveSessionIndex() : 0;
642
643 // Get all categories and panels
644 auto categories = panel_manager->GetAllCategories();
645
646 for (const auto& category : categories) {
647 auto panels = panel_manager->GetPanelsInCategory(session_id, category);
648
649 for (const auto& panel : panels) {
650 std::string shortcut_string;
651
652 // Check for user-defined shortcut first
653 if (user_settings) {
654 auto it = user_settings->prefs().panel_shortcuts.find(panel.card_id);
655 if (it != user_settings->prefs().panel_shortcuts.end()) {
656 shortcut_string = it->second;
657 }
658 }
659
660 // Fall back to default shortcut_hint
661 if (shortcut_string.empty() && !panel.shortcut_hint.empty()) {
662 shortcut_string = panel.shortcut_hint;
663 }
664
665 // If we have a shortcut, parse and register it
666 if (!shortcut_string.empty()) {
667 auto keys = ParseShortcutString(shortcut_string);
668 if (!keys.empty()) {
669 std::string panel_id_copy = panel.card_id;
670 // Toggle panel visibility shortcut
671 if (panel.shortcut_scope == PanelDescriptor::ShortcutScope::kPanel) {
672 std::string toggle_id = "view.toggle." + panel.card_id;
673 RegisterIfValid(
674 shortcut_manager,
675 toggle_id,
676 keys,
677 [panel_manager, panel_id_copy, session_id]() {
678 panel_manager->TogglePanel(session_id, panel_id_copy);
679 });
680 }
681 }
682 }
683 }
684 }
685}
686
687} // namespace yaze::editor
void RegisterCommand(const std::string &name, std::function< void()> callback, Shortcut::Scope scope=Shortcut::Scope::kGlobal)
Register a command without keyboard shortcut (command palette only)
void RegisterShortcut(const std::string &name, const std::vector< ImGuiKey > &keys, Shortcut::Scope scope=Shortcut::Scope::kGlobal)
static RecentFilesManager & GetInstance()
Definition project.h:310
void RegisterIfValid(ShortcutManager *shortcut_manager, const std::string &name, const std::vector< ImGuiKey > &keys, std::function< void()> callback, Shortcut::Scope scope=Shortcut::Scope::kGlobal)
std::vector< ImGuiKey > ParseShortcutString(const std::string &shortcut)
Editors are the view controllers for the application.
Definition agent_chat.cc:23
void ConfigureMenuShortcuts(const ShortcutDependencies &deps, ShortcutManager *shortcut_manager)
void ConfigurePanelShortcuts(const ShortcutDependencies &deps, ShortcutManager *shortcut_manager)
Register configurable panel shortcuts from user settings.
void ConfigureEditorShortcuts(const ShortcutDependencies &deps, ShortcutManager *shortcut_manager)