yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
keyboard_shortcuts.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Implementation of keyboard shortcut overlay system for yaze
3
5#include "util/i18n/tr.h"
6
7#include <algorithm>
8#include <cstring>
9
10#include "app/gui/core/color.h"
14#include "imgui/imgui.h"
15
16namespace yaze {
17namespace gui {
18
19namespace {
20
21// Key name lookup table (local to this file for Shortcut::GetDisplayString)
22// Note: gui::GetKeyName from platform_keys.h is the canonical version
23constexpr struct {
24 ImGuiKey key;
25 const char* name;
26} kLocalKeyNames[] = {
27 {ImGuiKey_Tab, "Tab"},
28 {ImGuiKey_LeftArrow, "Left"},
29 {ImGuiKey_RightArrow, "Right"},
30 {ImGuiKey_UpArrow, "Up"},
31 {ImGuiKey_DownArrow, "Down"},
32 {ImGuiKey_PageUp, "PageUp"},
33 {ImGuiKey_PageDown, "PageDown"},
34 {ImGuiKey_Home, "Home"},
35 {ImGuiKey_End, "End"},
36 {ImGuiKey_Insert, "Insert"},
37 {ImGuiKey_Delete, "Delete"},
38 {ImGuiKey_Backspace, "Backspace"},
39 {ImGuiKey_Space, "Space"},
40 {ImGuiKey_Enter, "Enter"},
41 {ImGuiKey_Escape, "Escape"},
42 {ImGuiKey_A, "A"},
43 {ImGuiKey_B, "B"},
44 {ImGuiKey_C, "C"},
45 {ImGuiKey_D, "D"},
46 {ImGuiKey_E, "E"},
47 {ImGuiKey_F, "F"},
48 {ImGuiKey_G, "G"},
49 {ImGuiKey_H, "H"},
50 {ImGuiKey_I, "I"},
51 {ImGuiKey_J, "J"},
52 {ImGuiKey_K, "K"},
53 {ImGuiKey_L, "L"},
54 {ImGuiKey_M, "M"},
55 {ImGuiKey_N, "N"},
56 {ImGuiKey_O, "O"},
57 {ImGuiKey_P, "P"},
58 {ImGuiKey_Q, "Q"},
59 {ImGuiKey_R, "R"},
60 {ImGuiKey_S, "S"},
61 {ImGuiKey_T, "T"},
62 {ImGuiKey_U, "U"},
63 {ImGuiKey_V, "V"},
64 {ImGuiKey_W, "W"},
65 {ImGuiKey_X, "X"},
66 {ImGuiKey_Y, "Y"},
67 {ImGuiKey_Z, "Z"},
68 {ImGuiKey_0, "0"},
69 {ImGuiKey_1, "1"},
70 {ImGuiKey_2, "2"},
71 {ImGuiKey_3, "3"},
72 {ImGuiKey_4, "4"},
73 {ImGuiKey_5, "5"},
74 {ImGuiKey_6, "6"},
75 {ImGuiKey_7, "7"},
76 {ImGuiKey_8, "8"},
77 {ImGuiKey_9, "9"},
78 {ImGuiKey_F1, "F1"},
79 {ImGuiKey_F2, "F2"},
80 {ImGuiKey_F3, "F3"},
81 {ImGuiKey_F4, "F4"},
82 {ImGuiKey_F5, "F5"},
83 {ImGuiKey_F6, "F6"},
84 {ImGuiKey_F7, "F7"},
85 {ImGuiKey_F8, "F8"},
86 {ImGuiKey_F9, "F9"},
87 {ImGuiKey_F10, "F10"},
88 {ImGuiKey_F11, "F11"},
89 {ImGuiKey_F12, "F12"},
90 {ImGuiKey_Minus, "-"},
91 {ImGuiKey_Equal, "="},
92 {ImGuiKey_LeftBracket, "["},
93 {ImGuiKey_RightBracket, "]"},
94 {ImGuiKey_Backslash, "\\"},
95 {ImGuiKey_Semicolon, ";"},
96 {ImGuiKey_Apostrophe, "'"},
97 {ImGuiKey_Comma, ","},
98 {ImGuiKey_Period, "."},
99 {ImGuiKey_Slash, "/"},
100 {ImGuiKey_GraveAccent, "`"},
102
103const char* GetLocalKeyName(ImGuiKey key) {
104 for (const auto& entry : kLocalKeyNames) {
105 if (entry.key == key) {
106 return entry.name;
107 }
108 }
109 return "?";
110}
111
112} // namespace
113
114std::string Shortcut::GetDisplayString() const {
115 std::string result;
116
117 // Use runtime platform detection for correct modifier names
118 // This handles native macOS, WASM on Mac browsers, and Windows/Linux
119 if (requires_ctrl) {
120 result += GetCtrlDisplayName();
121 result += "+";
122 }
123 if (requires_alt) {
124 result += GetAltDisplayName();
125 result += "+";
126 }
127 if (requires_shift) {
128 result += "Shift+";
129 }
130
131 // Use platform_keys.h GetKeyName for consistent key name formatting
132 result += gui::GetKeyName(key);
133 return result;
134}
135
136bool Shortcut::Matches(ImGuiKey pressed_key, bool ctrl, bool shift,
137 bool alt) const {
138 if (!enabled)
139 return false;
140 if (pressed_key != key)
141 return false;
142 if (ctrl != requires_ctrl)
143 return false;
144 if (shift != requires_shift)
145 return false;
146 if (alt != requires_alt)
147 return false;
148 return true;
149}
150
152 static KeyboardShortcuts instance;
153 return instance;
154}
155
157 shortcuts_[shortcut.id] = shortcut;
158}
159
160void KeyboardShortcuts::RegisterShortcut(const std::string& id,
161 const std::string& description,
162 ImGuiKey key, bool ctrl, bool shift,
163 bool alt, const std::string& category,
164 ShortcutContext context,
165 std::function<void()> action) {
166 Shortcut shortcut;
167 shortcut.id = id;
168 shortcut.description = description;
169 shortcut.key = key;
170 shortcut.requires_ctrl = ctrl;
171 shortcut.requires_shift = shift;
172 shortcut.requires_alt = alt;
173 shortcut.category = category;
174 shortcut.context = context;
175 shortcut.action = action;
176 shortcut.enabled = true;
177 RegisterShortcut(shortcut);
178}
179
180void KeyboardShortcuts::UnregisterShortcut(const std::string& id) {
181 shortcuts_.erase(id);
182}
183
184void KeyboardShortcuts::SetShortcutEnabled(const std::string& id,
185 bool enabled) {
186 auto it = shortcuts_.find(id);
187 if (it != shortcuts_.end()) {
188 it->second.enabled = enabled;
189 }
190}
191
193 // Check if any ImGui input widget is active (text fields, etc.)
194 // This prevents shortcuts from triggering while the user is typing
195 return ImGui::GetIO().WantTextInput;
196}
197
199 // Don't process shortcuts when text input is active
200 if (IsTextInputActive()) {
202 return;
203 }
204
205 const auto& io = ImGui::GetIO();
206 bool ctrl = io.KeyCtrl;
207 bool shift = io.KeyShift;
208 bool alt = io.KeyAlt;
209
210 // Handle '?' key to toggle overlay (Shift + /)
211 // Note: '?' is typically Shift+Slash on US keyboards
212 if (ImGui::IsKeyPressed(ImGuiKey_Slash) && shift && !ctrl && !alt) {
216 }
217 } else if (!ImGui::IsKeyPressed(ImGuiKey_Slash)) {
219 }
220
221 // Close overlay with Escape
222 if (show_overlay_ && ImGui::IsKeyPressed(ImGuiKey_Escape)) {
223 HideOverlay();
224 return;
225 }
226
227 // Don't process other shortcuts while overlay is shown
228 if (show_overlay_) {
229 return;
230 }
231
232 // Check all registered shortcuts
233 for (const auto& [id, shortcut] : shortcuts_) {
234 if (!shortcut.enabled)
235 continue;
236 if (!IsShortcutActiveInContext(shortcut))
237 continue;
238
239 // Check if this shortcut's key is pressed
240 if (ImGui::IsKeyPressed(shortcut.key, false)) {
241 if (shortcut.Matches(shortcut.key, ctrl, shift, alt)) {
242 if (shortcut.action) {
243 shortcut.action();
244 }
245 }
246 }
247 }
248}
249
252 if (show_overlay_) {
253 // Clear search filter when opening
254 search_filter_[0] = '\0';
255 }
256}
257
259 if (!show_overlay_)
260 return;
261
262 // Semi-transparent fullscreen background
263 ImGuiIO& io = ImGui::GetIO();
264 ImGui::SetNextWindowPos(ImVec2(0, 0));
265 ImGui::SetNextWindowSize(io.DisplaySize);
266 ImGuiWindowFlags overlay_flags =
267 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
268 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
269 ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoBringToFrontOnFocus;
270
271 {
272 StyledWindow overlay_bg("##ShortcutOverlayBg",
273 {.bg = ImVec4(0.0f, 0.0f, 0.0f, 0.7f),
274 .padding = ImVec2(0, 0),
275 .border_size = 0.0f},
276 nullptr, overlay_flags);
277 if (overlay_bg) {
278 // Close on click outside modal
279 if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(0)) {
280 ImVec2 mouse = ImGui::GetMousePos();
281 ImVec2 modal_pos = ImVec2((io.DisplaySize.x - 600) * 0.5f,
282 (io.DisplaySize.y - 500) * 0.5f);
283 ImVec2 modal_size = ImVec2(600, 500);
284
285 if (mouse.x < modal_pos.x || mouse.x > modal_pos.x + modal_size.x ||
286 mouse.y < modal_pos.y || mouse.y > modal_pos.y + modal_size.y) {
287 HideOverlay();
288 }
289 }
290 }
291 }
292
293 // Draw the centered modal window
295}
296
298 const auto& theme = ThemeManager::Get().GetCurrentTheme();
299 ImGuiIO& io = ImGui::GetIO();
300
301 // Calculate centered position
302 float modal_width = 600.0f;
303 float modal_height = 500.0f;
304 ImVec2 modal_pos((io.DisplaySize.x - modal_width) * 0.5f,
305 (io.DisplaySize.y - modal_height) * 0.5f);
306
307 ImGui::SetNextWindowPos(modal_pos);
308 ImGui::SetNextWindowSize(ImVec2(modal_width, modal_height));
309
310 // Style the modal window
311 ImGuiWindowFlags modal_flags =
312 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
313 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
314 ImGuiWindowFlags_NoSavedSettings;
315
316 StyledWindow modal("##ShortcutOverlay",
317 {.bg = ConvertColorToImVec4(theme.popup_bg),
318 .border = ConvertColorToImVec4(theme.border),
319 .padding = ImVec2(20, 16),
320 .border_size = 1.0f,
321 .rounding = 8.0f},
322 nullptr, modal_flags);
323
324 if (modal) {
325 // Header
326 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); // Use default font
327 ImGui::TextColored(ConvertColorToImVec4(theme.accent),
328 tr("Keyboard Shortcuts"));
329 ImGui::PopFont();
330
331 ImGui::SameLine(modal_width - 60);
332 if (ImGui::SmallButton(tr("X##CloseOverlay"))) {
333 HideOverlay();
334 }
335 if (ImGui::IsItemHovered()) {
336 ImGui::SetTooltip(tr("Close (Escape)"));
337 }
338
339 ImGui::Separator();
340 ImGui::Spacing();
341
342 // Search filter
343 ImGui::SetNextItemWidth(modal_width - 40);
344 {
345 StyleVarGuard frame_rounding(ImGuiStyleVar_FrameRounding, 4.0f);
346 ImGui::InputTextWithHint("##ShortcutSearch", "Search shortcuts...",
348 }
349
350 // Context indicator
351 ImGui::SameLine();
352 ImGui::TextDisabled("(%s)", ShortcutContextToString(current_context_));
353
354 ImGui::Spacing();
355 ImGui::Separator();
356 ImGui::Spacing();
357
358 // Scrollable content area
359 ImGui::BeginChild("##ShortcutList", ImVec2(0, -30), false,
360 ImGuiWindowFlags_AlwaysVerticalScrollbar);
361
362 // Collect shortcuts by category
363 std::map<std::string, std::vector<const Shortcut*>> shortcuts_by_category;
364 std::string filter_lower;
365 for (char c : std::string(search_filter_)) {
366 filter_lower += static_cast<char>(std::tolower(c));
367 }
368
369 for (const auto& [id, shortcut] : shortcuts_) {
370 // Apply search filter
371 if (!filter_lower.empty()) {
372 std::string desc_lower;
373 for (char c : shortcut.description) {
374 desc_lower += static_cast<char>(std::tolower(c));
375 }
376 std::string cat_lower;
377 for (char c : shortcut.category) {
378 cat_lower += static_cast<char>(std::tolower(c));
379 }
380 std::string key_lower;
381 for (char c : shortcut.GetDisplayString()) {
382 key_lower += static_cast<char>(std::tolower(c));
383 }
384
385 if (desc_lower.find(filter_lower) == std::string::npos &&
386 cat_lower.find(filter_lower) == std::string::npos &&
387 key_lower.find(filter_lower) == std::string::npos) {
388 continue;
389 }
390 }
391
392 shortcuts_by_category[shortcut.category].push_back(&shortcut);
393 }
394
395 // Display shortcuts by category in order
396 for (const auto& category : category_order_) {
397 auto it = shortcuts_by_category.find(category);
398 if (it != shortcuts_by_category.end() && !it->second.empty()) {
399 DrawCategorySection(category, it->second);
400 }
401 }
402
403 // Display any categories not in the order list
404 for (const auto& [category, shortcuts] : shortcuts_by_category) {
405 bool in_order = false;
406 for (const auto& ordered : category_order_) {
407 if (ordered == category) {
408 in_order = true;
409 break;
410 }
411 }
412 if (!in_order && !shortcuts.empty()) {
413 DrawCategorySection(category, shortcuts);
414 }
415 }
416
417 ImGui::EndChild();
418
419 // Footer
420 ImGui::Separator();
421 ImGui::TextDisabled(tr("Press ? to toggle | Escape to close"));
422 }
423}
424
426 const std::string& category,
427 const std::vector<const Shortcut*>& shortcuts) {
428 const auto& theme = ThemeManager::Get().GetCurrentTheme();
429 auto header_bg = ConvertColorToImVec4(theme.header);
430
431 // Category header with collapsible behavior
432 StyleColorGuard header_colors({
433 {ImGuiCol_Header, header_bg},
434 {ImGuiCol_HeaderHovered, ImVec4(header_bg.x + 0.05f, header_bg.y + 0.05f,
435 header_bg.z + 0.05f, 1.0f)},
436 });
437
438 bool is_open =
439 ImGui::CollapsingHeader(category.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
440
441 if (is_open) {
442 ImGui::Indent(10.0f);
443
444 // Table for shortcuts
445 if (ImGui::BeginTable(
446 "##ShortcutTable", 3,
447 ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_RowBg)) {
448 ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthFixed,
449 120.0f);
450 ImGui::TableSetupColumn("Description",
451 ImGuiTableColumnFlags_WidthStretch);
452 ImGui::TableSetupColumn("Context", ImGuiTableColumnFlags_WidthFixed,
453 80.0f);
454
455 for (const auto* shortcut : shortcuts) {
456 DrawShortcutRow(*shortcut);
457 }
458
459 ImGui::EndTable();
460 }
461
462 ImGui::Unindent(10.0f);
463 ImGui::Spacing();
464 }
465}
466
468 const auto& theme = ThemeManager::Get().GetCurrentTheme();
469
470 ImGui::TableNextRow();
471
472 // Shortcut key combination
473 ImGui::TableNextColumn();
474 bool is_active = IsShortcutActiveInContext(shortcut);
475
476 // Draw keyboard shortcut badge
477 StyleColorGuard badge_colors({
478 {ImGuiCol_Button, is_active ? ImVec4(0.2f, 0.3f, 0.4f, 0.8f)
479 : ImVec4(0.15f, 0.15f, 0.15f, 0.6f)},
480 {ImGuiCol_ButtonHovered, is_active ? ImVec4(0.25f, 0.35f, 0.45f, 0.9f)
481 : ImVec4(0.2f, 0.2f, 0.2f, 0.7f)},
482 });
483 StyleVarGuard badge_vars({
484 {ImGuiStyleVar_FrameRounding, 4.0f},
485 {ImGuiStyleVar_FramePadding, ImVec2(6, 2)},
486 });
487
488 std::string display = shortcut.GetDisplayString();
489 ImGui::SmallButton(display.c_str());
490
491 // Description
492 ImGui::TableNextColumn();
493 ImVec4 text_color = is_active ? ConvertColorToImVec4(theme.text_primary)
494 : ConvertColorToImVec4(theme.text_secondary);
495 ImGui::TextColored(text_color, "%s", shortcut.description.c_str());
496
497 // Context indicator
498 ImGui::TableNextColumn();
499 if (shortcut.context != ShortcutContext::kGlobal) {
500 ImGui::TextDisabled("%s", ShortcutContextToString(shortcut.context));
501 }
502}
503
505 const Shortcut& shortcut) const {
506 if (shortcut.context == ShortcutContext::kGlobal) {
507 return true;
508 }
509 return shortcut.context == current_context_;
510}
511
512std::vector<const Shortcut*> KeyboardShortcuts::GetShortcutsInCategory(
513 const std::string& category) const {
514 std::vector<const Shortcut*> result;
515 for (const auto& [id, shortcut] : shortcuts_) {
516 if (shortcut.category == category) {
517 result.push_back(&shortcut);
518 }
519 }
520 return result;
521}
522
523std::vector<const Shortcut*> KeyboardShortcuts::GetContextShortcuts() const {
524 std::vector<const Shortcut*> result;
525 for (const auto& [id, shortcut] : shortcuts_) {
526 if (IsShortcutActiveInContext(shortcut)) {
527 result.push_back(&shortcut);
528 }
529 }
530 return result;
531}
532
533std::vector<std::string> KeyboardShortcuts::GetCategories() const {
534 std::vector<std::string> result;
535 for (const auto& [id, shortcut] : shortcuts_) {
536 bool found = false;
537 for (const auto& cat : result) {
538 if (cat == shortcut.category) {
539 found = true;
540 break;
541 }
542 }
543 if (!found) {
544 result.push_back(shortcut.category);
545 }
546 }
547 return result;
548}
549
551 std::function<void()> open_callback, std::function<void()> save_callback,
552 std::function<void()> save_as_callback,
553 std::function<void()> close_callback, std::function<void()> undo_callback,
554 std::function<void()> redo_callback, std::function<void()> copy_callback,
555 std::function<void()> paste_callback, std::function<void()> cut_callback,
556 std::function<void()> find_callback) {
557
558 // === File Shortcuts ===
559 if (open_callback) {
560 RegisterShortcut("file.open", "Open ROM/Project", ImGuiKey_O, true, false,
561 false, "File", ShortcutContext::kGlobal, open_callback);
562 }
563
564 if (save_callback) {
565 RegisterShortcut("file.save", "Save", ImGuiKey_S, true, false, false,
566 "File", ShortcutContext::kGlobal, save_callback);
567 }
568
569 if (save_as_callback) {
570 RegisterShortcut("file.save_as", "Save As...", ImGuiKey_S, true, true,
571 false, "File", ShortcutContext::kGlobal, save_as_callback);
572 }
573
574 if (close_callback) {
575 RegisterShortcut("file.close", "Close", ImGuiKey_W, true, false, false,
576 "File", ShortcutContext::kGlobal, close_callback);
577 }
578
579 // === Edit Shortcuts ===
580 if (undo_callback) {
581 RegisterShortcut("edit.undo", "Undo", ImGuiKey_Z, true, false, false,
582 "Edit", ShortcutContext::kGlobal, undo_callback);
583 }
584
585 if (redo_callback) {
586 RegisterShortcut("edit.redo", "Redo", ImGuiKey_Y, true, false, false,
587 "Edit", ShortcutContext::kGlobal, redo_callback);
588
589 // Also register Ctrl+Shift+Z for redo (common alternative)
590 RegisterShortcut("edit.redo_alt", "Redo", ImGuiKey_Z, true, true, false,
591 "Edit", ShortcutContext::kGlobal, redo_callback);
592 }
593
594 if (copy_callback) {
595 RegisterShortcut("edit.copy", "Copy", ImGuiKey_C, true, false, false,
596 "Edit", ShortcutContext::kGlobal, copy_callback);
597 }
598
599 if (paste_callback) {
600 RegisterShortcut("edit.paste", "Paste", ImGuiKey_V, true, false, false,
601 "Edit", ShortcutContext::kGlobal, paste_callback);
602 }
603
604 if (cut_callback) {
605 RegisterShortcut("edit.cut", "Cut", ImGuiKey_X, true, false, false, "Edit",
606 ShortcutContext::kGlobal, cut_callback);
607 }
608
609 if (find_callback) {
610 RegisterShortcut("edit.find", "Find", ImGuiKey_F, true, false, false,
611 "Edit", ShortcutContext::kGlobal, find_callback);
612 }
613
614 // === View Shortcuts ===
615 RegisterShortcut("view.fullscreen", "Toggle Fullscreen", ImGuiKey_F11, false,
616 false, false, "View", ShortcutContext::kGlobal,
617 nullptr); // Placeholder - implement in EditorManager
618
619 RegisterShortcut("view.grid", "Toggle Grid", ImGuiKey_G, true, false, false,
621 nullptr); // Placeholder
622
623 RegisterShortcut("view.zoom_in", "Zoom In", ImGuiKey_Equal, true, false,
624 false, "View", ShortcutContext::kGlobal,
625 nullptr); // Placeholder
626
627 RegisterShortcut("view.zoom_out", "Zoom Out", ImGuiKey_Minus, true, false,
628 false, "View", ShortcutContext::kGlobal,
629 nullptr); // Placeholder
630
631 RegisterShortcut("view.zoom_reset", "Reset Zoom", ImGuiKey_0, true, false,
632 false, "View", ShortcutContext::kGlobal,
633 nullptr); // Placeholder
634
635 // === Navigation Shortcuts ===
636 RegisterShortcut("nav.first", "Go to First", ImGuiKey_Home, false, false,
637 false, "Navigation", ShortcutContext::kGlobal,
638 nullptr); // Placeholder
639
640 RegisterShortcut("nav.last", "Go to Last", ImGuiKey_End, false, false, false,
641 "Navigation", ShortcutContext::kGlobal,
642 nullptr); // Placeholder
643
644 RegisterShortcut("nav.prev", "Previous", ImGuiKey_PageUp, false, false, false,
645 "Navigation", ShortcutContext::kGlobal,
646 nullptr); // Placeholder
647
648 RegisterShortcut("nav.next", "Next", ImGuiKey_PageDown, false, false, false,
649 "Navigation", ShortcutContext::kGlobal,
650 nullptr); // Placeholder
651
652 // === Emulator Shortcuts ===
653 RegisterShortcut("emu.play_pause", "Play/Pause Emulator", ImGuiKey_Space,
654 false, false, false, "Editor", ShortcutContext::kEmulator,
655 nullptr); // Placeholder
656
657 RegisterShortcut("emu.reset", "Reset Emulator", ImGuiKey_R, true, false,
658 false, "Editor", ShortcutContext::kEmulator,
659 nullptr); // Placeholder
660
661 RegisterShortcut("emu.step", "Step Frame", ImGuiKey_F, false, false, false,
663 nullptr); // Placeholder
664
665 // === Overworld Editor Shortcuts ===
666 RegisterShortcut("ow.select_all", "Select All Tiles", ImGuiKey_A, true, false,
667 false, "Editor", ShortcutContext::kOverworld,
668 nullptr); // Placeholder
669
670 RegisterShortcut("ow.deselect", "Deselect", ImGuiKey_D, true, false, false,
672 nullptr); // Placeholder
673
674 // === Dungeon Editor Shortcuts ===
675 RegisterShortcut("dg.select_all", "Select All Objects", ImGuiKey_A, true,
676 false, false, "Editor", ShortcutContext::kDungeon,
677 nullptr); // Placeholder
678
679 RegisterShortcut("dg.delete", "Delete Selected", ImGuiKey_Delete, false,
680 false, false, "Editor", ShortcutContext::kDungeon,
681 nullptr); // Placeholder
682
683 RegisterShortcut("dg.duplicate", "Duplicate Selected", ImGuiKey_D, true,
684 false, false, "Editor", ShortcutContext::kDungeon,
685 nullptr); // Placeholder
686}
687
689 switch (context) {
691 return "Global";
693 return "Overworld";
695 return "Dungeon";
697 return "Graphics";
699 return "Palette";
701 return "Sprite";
703 return "Music";
705 return "Message";
707 return "Emulator";
709 return "Code";
710 default:
711 return "Unknown";
712 }
713}
714
715ShortcutContext EditorNameToContext(const std::string& editor_name) {
716 if (editor_name == "Overworld")
718 if (editor_name == "Dungeon")
720 if (editor_name == "Graphics")
722 if (editor_name == "Palette")
724 if (editor_name == "Sprite")
726 if (editor_name == "Music")
728 if (editor_name == "Message")
730 if (editor_name == "Emulator")
732 if (editor_name == "Assembly" || editor_name == "Code")
735}
736
737} // namespace gui
738} // namespace yaze
Manages keyboard shortcuts and provides an overlay UI.
void SetShortcutEnabled(const std::string &id, bool enabled)
void UnregisterShortcut(const std::string &id)
std::vector< std::string > category_order_
std::vector< std::string > GetCategories() const
std::map< std::string, Shortcut > shortcuts_
void DrawShortcutRow(const Shortcut &shortcut)
std::vector< const Shortcut * > GetContextShortcuts() const
std::vector< const Shortcut * > GetShortcutsInCategory(const std::string &category) const
static KeyboardShortcuts & Get()
void DrawCategorySection(const std::string &category, const std::vector< const Shortcut * > &shortcuts)
void RegisterShortcut(const Shortcut &shortcut)
void RegisterDefaultShortcuts(std::function< void()> open_callback, std::function< void()> save_callback, std::function< void()> save_as_callback, std::function< void()> close_callback, std::function< void()> undo_callback, std::function< void()> redo_callback, std::function< void()> copy_callback, std::function< void()> paste_callback, std::function< void()> cut_callback, std::function< void()> find_callback)
bool IsShortcutActiveInContext(const Shortcut &shortcut) const
RAII guard for ImGui style colors.
Definition style_guard.h:27
RAII guard for ImGui style vars.
Definition style_guard.h:68
RAII compound guard for window-level style setup.
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
constexpr struct yaze::gui::anonymous_namespace{keyboard_shortcuts.cc}::@1 kLocalKeyNames[]
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:134
const char * ShortcutContextToString(ShortcutContext context)
Convert ShortcutContext to display string.
ShortcutContext EditorNameToContext(const std::string &editor_name)
Convert editor type name to ShortcutContext.
const char * GetKeyName(ImGuiKey key)
Get the ImGui key name as a string.
ShortcutContext
Defines the context in which a shortcut is active.
const char * GetAltDisplayName()
Get the display name for the secondary modifier key.
Represents a keyboard shortcut with its associated action.
ShortcutContext context
std::string GetDisplayString() const
std::function< void()> action
bool Matches(ImGuiKey pressed_key, bool ctrl, bool shift, bool alt) const