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