diff --git a/src/app/editor/editor.cmake b/src/app/editor/editor.cmake index 78367f94..97ea730a 100644 --- a/src/app/editor/editor.cmake +++ b/src/app/editor/editor.cmake @@ -17,4 +17,5 @@ set( app/editor/system/settings_editor.cc app/editor/system/command_manager.cc app/editor/system/extension_manager.cc + app/editor/system/shortcut_manager.cc ) diff --git a/src/app/editor/editor.h b/src/app/editor/editor.h index 94577f61..ad6247eb 100644 --- a/src/app/editor/editor.h +++ b/src/app/editor/editor.h @@ -8,6 +8,7 @@ #include "app/editor/system/extension_manager.h" #include "app/editor/system/history_manager.h" #include "app/editor/system/popup_manager.h" +#include "app/editor/system/shortcut_manager.h" namespace yaze { @@ -22,6 +23,7 @@ struct EditorContext { ExtensionManager extension_manager; HistoryManager history_manager; PopupManager popup_manager; + ShortcutManager shortcut_manager; }; enum class EditorType { diff --git a/src/app/editor/editor_manager.cc b/src/app/editor/editor_manager.cc index b21e1f3d..b71a2d84 100644 --- a/src/app/editor/editor_manager.cc +++ b/src/app/editor/editor_manager.cc @@ -53,14 +53,6 @@ void EditorManager::Initialize(const std::string &filename) { if (!filename.empty()) { PRINT_IF_ERROR(rom()->LoadFromFile(filename)); } - gui::kMainMenu[gui::MenuType::kFile].name = "File"; - gui::kMainMenu[gui::MenuType::kEdit].name = "Edit"; - gui::kMainMenu[gui::MenuType::kView].name = "View"; - gui::kMainMenu[gui::MenuType::kTools].name = "Tools"; - gui::kMainMenu[gui::MenuType::kHelp].name = "Help"; - - gui::AddToFileMenu(absl::StrCat(ICON_MD_FILE_OPEN, " Open"), "Ctrl+O", - [&]() { LoadRom(); }); std::vector recent_files; static RecentFilesManager manager("recent_files.txt"); @@ -73,63 +65,117 @@ void EditorManager::Initialize(const std::string &filename) { [&]() { OpenRomOrProject(filePath); }); } } - gui::AddToFileMenu( - "Open Recent", "", nullptr, []() { return true; }, recent_files); - gui::AddToFileMenu(absl::StrCat(ICON_MD_FILE_DOWNLOAD, " Save"), "Ctrl+S", - [&]() { SaveRom(); }); - gui::AddToFileMenu(absl::StrCat(ICON_MD_SAVE_AS, " Save As.."), "", - [&]() { save_as_menu_ = true; }); - gui::AddToFileMenu(absl::StrCat(ICON_MD_CLOSE, " Close"), "", - [&]() { rom()->Close(); }); - gui::AddToMenu("-", nullptr, gui::MenuType::kFile); std::vector options_subitems; options_subitems.emplace_back( "Backup ROM", "", [&]() { backup_rom_ |= backup_rom_; }, [&]() { return backup_rom_; }); - gui::AddToFileMenu( - absl::StrCat(ICON_MD_SETTINGS, "Options"), "", [&]() {}, - []() { return true; }, options_subitems); - gui::AddToFileMenu("Quit", "Ctrl+Q", [&]() { quit_ = true; }); + context_.shortcut_manager.RegisterShortcut( + "Open", {ImGuiKey_O, ImGuiMod_Ctrl}, [&]() { LoadRom(); }); + context_.shortcut_manager.RegisterShortcut( + "Save", {ImGuiKey_S, ImGuiMod_Ctrl}, [&]() { SaveRom(); }); + context_.shortcut_manager.RegisterShortcut( + "Close", {ImGuiKey_W, ImGuiMod_Ctrl}, [&]() { rom()->Close(); }); + context_.shortcut_manager.RegisterShortcut( + "Quit", {ImGuiKey_Q, ImGuiMod_Ctrl}, [&]() { quit_ = true; }); - gui::AddToEditMenu(absl::StrCat(ICON_MD_CONTENT_CUT, " Cut"), "Cmd+X", - [&]() { status_ = current_editor_->Cut(); }); - gui::AddToEditMenu(absl::StrCat(ICON_MD_CONTENT_COPY, " Copy"), "Cmd+C", - [&]() { status_ = current_editor_->Copy(); }); - gui::AddToEditMenu(absl::StrCat(ICON_MD_CONTENT_PASTE, " Paste"), "Cmd+V", - [&]() { status_ = current_editor_->Paste(); }); - gui::AddToEditMenu(absl::StrCat(ICON_MD_UNDO, " Undo"), "Cmd+Z", - [&]() { status_ = current_editor_->Undo(); }); - gui::AddToEditMenu(absl::StrCat(ICON_MD_REDO, " Redo"), "Cmd+Y", - [&]() { status_ = current_editor_->Redo(); }); - gui::AddToEditMenu(absl::StrCat(ICON_MD_SEARCH, " Find"), "Cmd+F", - [&]() { status_ = current_editor_->Find(); }); + context_.shortcut_manager.RegisterShortcut( + "Undo", {ImGuiKey_Z, ImGuiMod_Ctrl}, + [&]() { status_ = current_editor_->Undo(); }); + context_.shortcut_manager.RegisterShortcut( + "Redo", {ImGuiKey_Y, ImGuiMod_Ctrl}, + [&]() { status_ = current_editor_->Redo(); }); + context_.shortcut_manager.RegisterShortcut( + "Cut", {ImGuiKey_X, ImGuiMod_Ctrl}, + [&]() { status_ = current_editor_->Cut(); }); + context_.shortcut_manager.RegisterShortcut( + "Copy", {ImGuiKey_C, ImGuiMod_Ctrl}, + [&]() { status_ = current_editor_->Copy(); }); + context_.shortcut_manager.RegisterShortcut( + "Paste", {ImGuiKey_V, ImGuiMod_Ctrl}, + [&]() { status_ = current_editor_->Paste(); }); + context_.shortcut_manager.RegisterShortcut( + "Find", {ImGuiKey_F, ImGuiMod_Ctrl}, + [&]() { status_ = current_editor_->Find(); }); - gui::AddToViewMenu(absl::StrCat(ICON_MD_GAMEPAD, " Emulator"), "", - [&]() { show_emulator_ = true; }); - gui::AddToViewMenu(absl::StrCat(ICON_MD_MEMORY, " Memory Editor"), "", - [&]() { show_memory_editor_ = true; }); - gui::AddToViewMenu(absl::StrCat(ICON_MD_CODE, " Assembly Editor"), "", - [&]() { show_asm_editor_ = true; }); - gui::AddToViewMenu(absl::StrCat(ICON_MD_PALETTE, " Palette Editor"), "", - [&]() { show_palette_editor_ = true; }); - gui::AddToViewMenu(absl::StrCat(ICON_MD_SIM_CARD, " ROM Metadata"), "", - [&]() { rom_info_ = true; }); - gui::AddToMenu("-", nullptr, gui::MenuType::kView); - gui::AddToViewMenu(absl::StrCat(ICON_MD_HELP, " ImGui Demo"), "", - [&]() { show_imgui_demo_ = true; }); - gui::AddToViewMenu(absl::StrCat(ICON_MD_HELP, " ImGui Metrics"), "", - [&]() { show_imgui_metrics_ = true; }); - - gui::AddToHelpMenu(absl::StrCat(ICON_MD_HELP, " How to open a ROM"), "", - [&]() { open_rom_help = true; }); - gui::AddToHelpMenu(absl::StrCat(ICON_MD_HELP, " Supported Features"), "", - [&]() { open_supported_features = true; }); - gui::AddToHelpMenu(absl::StrCat(ICON_MD_HELP, " How to manage a project"), "", - [&]() { open_manage_project = true; }); - gui::AddToHelpMenu(absl::StrCat(ICON_MD_HELP, " About"), "F1", - [&]() { about_ = true; }); + gui::kMainMenu = { + {"File", + {}, + {}, + {}, + { + {absl::StrCat(ICON_MD_FILE_OPEN, " Open"), + context_.shortcut_manager.GetKeys("Open"), + context_.shortcut_manager.GetCallback("Open")}, + {"Open Recent", "", [&]() {}, + []() { return !manager.GetRecentFiles().empty(); }, recent_files}, + {absl::StrCat(ICON_MD_FILE_DOWNLOAD, " Save"), + context_.shortcut_manager.GetKeys("Save"), + context_.shortcut_manager.GetCallback("Save")}, + {absl::StrCat(ICON_MD_SAVE_AS, " Save As.."), "", + [&]() { save_as_menu_ = true; }}, + {absl::StrCat(ICON_MD_CLOSE, " Close"), "", + [&]() { rom()->Close(); }}, + {"-", "", nullptr, []() { return true; }}, + {absl::StrCat(ICON_MD_SETTINGS, "Options"), "", [&]() {}, + []() { return true; }, options_subitems}, + {"Quit", "Ctrl+Q", [&]() { quit_ = true; }}, + }}, + {"Edit", + {}, + {}, + {}, + { + {absl::StrCat(ICON_MD_CONTENT_CUT, " Cut"), "Cmd+X", + [&]() { status_ = current_editor_->Cut(); }}, + {absl::StrCat(ICON_MD_CONTENT_COPY, " Copy"), "Cmd+C", + [&]() { status_ = current_editor_->Copy(); }}, + {absl::StrCat(ICON_MD_CONTENT_PASTE, " Paste"), "Cmd+V", + [&]() { status_ = current_editor_->Paste(); }}, + {absl::StrCat(ICON_MD_UNDO, " Undo"), "Cmd+Z", + [&]() { status_ = current_editor_->Undo(); }}, + {absl::StrCat(ICON_MD_REDO, " Redo"), "Cmd+Y", + [&]() { status_ = current_editor_->Redo(); }}, + {absl::StrCat(ICON_MD_SEARCH, " Find"), "Cmd+F", + [&]() { status_ = current_editor_->Find(); }}, + }}, + {"View", + {}, + {}, + {}, + { + {absl::StrCat(ICON_MD_GAMEPAD, " Emulator"), "", + [&]() { show_emulator_ = true; }}, + {absl::StrCat(ICON_MD_MEMORY, " Memory Editor"), "", + [&]() { show_memory_editor_ = true; }}, + {absl::StrCat(ICON_MD_CODE, " Assembly Editor"), "", + [&]() { show_asm_editor_ = true; }}, + {absl::StrCat(ICON_MD_PALETTE, " Palette Editor"), "", + [&]() { show_palette_editor_ = true; }}, + {absl::StrCat(ICON_MD_SIM_CARD, " ROM Metadata"), "", + [&]() { rom_info_ = true; }}, + {"-", "", nullptr, []() { return true; }}, + {absl::StrCat(ICON_MD_HELP, " ImGui Demo"), "", + [&]() { show_imgui_demo_ = true; }}, + {absl::StrCat(ICON_MD_HELP, " ImGui Metrics"), "", + [&]() { show_imgui_metrics_ = true; }}, + }}, + {"Tools", {}, {}, {}, {}}, + {"Help", + {}, + {}, + {}, + { + {absl::StrCat(ICON_MD_HELP, " How to open a ROM"), "", + [&]() { open_rom_help = true; }}, + {absl::StrCat(ICON_MD_HELP, " Supported Features"), "", + [&]() { open_supported_features = true; }}, + {absl::StrCat(ICON_MD_HELP, " How to manage a project"), "", + [&]() { open_manage_project = true; }}, + {absl::StrCat(ICON_MD_HELP, " About"), "F1", + [&]() { about_ = true; }}, + }}}; overworld_editor_.Initialize(); } @@ -322,7 +368,7 @@ void EditorManager::ManageActiveEditors() { void EditorManager::ManageKeyboardShortcuts() { bool ctrl_or_super = (GetIO().KeyCtrl || GetIO().KeySuper); - editor_context_.command_manager.ShowWhichKey(); + context_.command_manager.ShowWhichKey(); // If CMD + R is pressed, reload the top result of recent files if (IsKeyDown(ImGuiKey_R) && ctrl_or_super) { diff --git a/src/app/editor/editor_manager.h b/src/app/editor/editor_manager.h index 5ee4a238..0f9d67ec 100644 --- a/src/app/editor/editor_manager.h +++ b/src/app/editor/editor_manager.h @@ -97,7 +97,7 @@ class EditorManager : public SharedRom { Rom *current_rom_ = nullptr; Project current_project_; - EditorContext editor_context_; + EditorContext context_; Editor *current_editor_ = nullptr; AssemblyEditor assembly_editor_; diff --git a/src/app/editor/system/shortcut_manager.cc b/src/app/editor/system/shortcut_manager.cc new file mode 100644 index 00000000..a3d8d908 --- /dev/null +++ b/src/app/editor/system/shortcut_manager.cc @@ -0,0 +1,141 @@ +#include "shortcut_manager.h" + +#include +#include + +#include "app/gui/input.h" +#include "imgui/imgui.h" + +namespace yaze { +namespace editor { + +namespace { +constexpr std::pair kKeyNames[] = { + {ImGuiKey_Tab, "Tab"}, + {ImGuiKey_LeftArrow, "Left"}, + {ImGuiKey_RightArrow, "Right"}, + {ImGuiKey_UpArrow, "Up"}, + {ImGuiKey_DownArrow, "Down"}, + {ImGuiKey_PageUp, "PageUp"}, + {ImGuiKey_PageDown, "PageDown"}, + {ImGuiKey_Home, "Home"}, + {ImGuiKey_End, "End"}, + {ImGuiKey_Insert, "Insert"}, + {ImGuiKey_Delete, "Delete"}, + {ImGuiKey_Backspace, "Backspace"}, + {ImGuiKey_Space, "Space"}, + {ImGuiKey_Enter, "Enter"}, + {ImGuiKey_Escape, "Escape"}, + {ImGuiMod_Ctrl, "Ctrl"}, + {ImGuiMod_Shift, "Shift"}, + {ImGuiMod_Alt, "Alt"}, + {ImGuiMod_Super, "Super"}, + {ImGuiKey_A, "A"}, + {ImGuiKey_B, "B"}, + {ImGuiKey_C, "C"}, + {ImGuiKey_D, "D"}, + {ImGuiKey_E, "E"}, + {ImGuiKey_F, "F"}, + {ImGuiKey_G, "G"}, + {ImGuiKey_H, "H"}, + {ImGuiKey_I, "I"}, + {ImGuiKey_J, "J"}, + {ImGuiKey_K, "K"}, + {ImGuiKey_L, "L"}, + {ImGuiKey_M, "M"}, + {ImGuiKey_N, "N"}, + {ImGuiKey_O, "O"}, + {ImGuiKey_P, "P"}, + {ImGuiKey_Q, "Q"}, + {ImGuiKey_R, "R"}, + {ImGuiKey_S, "S"}, + {ImGuiKey_T, "T"}, + {ImGuiKey_U, "U"}, + {ImGuiKey_V, "V"}, + {ImGuiKey_W, "W"}, + {ImGuiKey_X, "X"}, + {ImGuiKey_Y, "Y"}, + {ImGuiKey_Z, "Z"}, + {ImGuiKey_F1, "F1"}, + {ImGuiKey_F2, "F2"}, + {ImGuiKey_F3, "F3"}, + {ImGuiKey_F4, "F4"}, + {ImGuiKey_F5, "F5"}, + {ImGuiKey_F6, "F6"}, + {ImGuiKey_F7, "F7"}, + {ImGuiKey_F8, "F8"}, + {ImGuiKey_F9, "F9"}, + {ImGuiKey_F10, "F10"}, + {ImGuiKey_F11, "F11"}, + {ImGuiKey_F12, "F12"}, + {ImGuiKey_F13, "F13"}, + {ImGuiKey_F14, "F14"}, + {ImGuiKey_F15, "F15"}, +}; + +constexpr const char* GetKeyName(ImGuiKey key) { + for (const auto& pair : kKeyNames) { + if (pair.first == key) { + return pair.second; + } + } + return ""; +} +} // namespace + +std::string PrintShortcut(const std::vector& keys) { + std::string shortcut; + for (size_t i = keys.size(); i > 0; --i) { + shortcut += GetKeyName(keys[i - 1]); + if (i > 1) { + shortcut += "+"; + } + } + return shortcut; +} + +constexpr std::string kCtrlKey = "Ctrl"; +constexpr std::string kAltKey = "Alt"; +constexpr std::string kShiftKey = "Shift"; +constexpr std::string kSuperKey = "Super"; + +std::vector ParseShortcut(const std::string& shortcut) { + std::vector shortcuts; + // Search for special keys and the + symbol to combine with the + // MapKeyToImGuiKey function + size_t start = 0; + size_t end = shortcut.find(kCtrlKey); + if (end != std::string::npos) { + shortcuts.push_back(ImGuiMod_Ctrl); + start = end + kCtrlKey.size(); + } + + end = shortcut.find(kAltKey, start); + if (end != std::string::npos) { + shortcuts.push_back(ImGuiMod_Alt); + start = end + kAltKey.size(); + } + + end = shortcut.find(kShiftKey, start); + if (end != std::string::npos) { + shortcuts.push_back(ImGuiMod_Shift); + start = end + kShiftKey.size(); + } + + end = shortcut.find(kSuperKey, start); + if (end != std::string::npos) { + shortcuts.push_back(ImGuiMod_Super); + start = end + kSuperKey.size(); + } + + // Parse the rest of the keys + while (start < shortcut.size()) { + shortcuts.push_back(gui::MapKeyToImGuiKey(shortcut[start])); + start++; + } + + return shortcuts; +} + +} // namespace editor +} // namespace yaze \ No newline at end of file diff --git a/src/app/editor/system/shortcut_manager.h b/src/app/editor/system/shortcut_manager.h new file mode 100644 index 00000000..d6184420 --- /dev/null +++ b/src/app/editor/system/shortcut_manager.h @@ -0,0 +1,65 @@ +#ifndef YAZE_APP_EDITOR_SYSTEM_SHORTCUT_MANAGER_H +#define YAZE_APP_EDITOR_SYSTEM_SHORTCUT_MANAGER_H + +#include +#include +#include + +#include "imgui/imgui.h" + +namespace yaze { +namespace editor { + +struct Shortcut { + std::string name; + std::vector keys; + std::function callback; +}; + +std::vector ParseShortcut(const std::string &shortcut); + +std::string PrintShortcut(const std::vector &keys); + +class ShortcutManager { + public: + void RegisterShortcut(const std::string &name, + const std::vector &keys) { + shortcuts_[name] = {name, keys}; + } + void RegisterShortcut(const std::string &name, + const std::vector &keys, + std::function callback) { + shortcuts_[name] = {name, keys, callback}; + } + + void RegisterShortcut(const std::string &name, ImGuiKey key, + std::function callback) { + shortcuts_[name] = {name, {key}, callback}; + } + + void ExecuteShortcut(const std::string &name) const { + shortcuts_.at(name).callback(); + } + + // Access the shortcut and print the readable name of the shortcut for menus + const Shortcut &GetShortcut(const std::string &name) const { + return shortcuts_.at(name); + } + + // Get shortcut callback function + std::function GetCallback(const std::string &name) const { + return shortcuts_.at(name).callback; + } + + const std::string GetKeys(const std::string &name) const { + return PrintShortcut(shortcuts_.at(name).keys); + } + + private: + std::unordered_map shortcuts_; +}; + +} // namespace editor +} // namespace yaze + +#endif // YAZE_APP_EDITOR_SYSTEM_SHORTCUT_MANAGER_H \ No newline at end of file