diff --git a/src/app/editor/system/command_manager.cc b/src/app/editor/system/command_manager.cc index b613d728..5587752c 100644 --- a/src/app/editor/system/command_manager.cc +++ b/src/app/editor/system/command_manager.cc @@ -76,5 +76,145 @@ void CommandManager::LoadKeybindings(const std::string &filepath) { } } +// Enhanced hierarchical WhichKey with Spacemacs-style navigation +void CommandManager::ShowWhichKeyHierarchical() { + // Activate on Space key + if (ImGui::IsKeyPressed(ImGuiKey_Space) && current_prefix_.empty()) { + whichkey_active_ = true; + whichkey_timer_ = 0.0f; + ImGui::OpenPopup("WhichKeyHierarchical"); + } + + // ESC to close or go back + if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { + if (!current_prefix_.empty()) { + current_prefix_.clear(); // Go back to root + } else { + whichkey_active_ = false; + ImGui::CloseCurrentPopup(); + } + } + + // Position at bottom of screen + ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - 150), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, 150), + ImGuiCond_Always); + + if (ImGui::BeginPopup("WhichKeyHierarchical")) { + whichkey_active_ = true; + + // Update timer for auto-close + whichkey_timer_ += ImGui::GetIO().DeltaTime; + if (whichkey_timer_ > 5.0f) { // Auto-close after 5 seconds + whichkey_active_ = false; + current_prefix_.clear(); + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + return; + } + + // Show breadcrumb navigation + if (!current_prefix_.empty()) { + ImGui::TextColored(ImVec4(0.5f, 0.8f, 1.0f, 1.0f), + "Space > %s", current_prefix_.c_str()); + ImGui::Separator(); + } else { + ImGui::TextColored(ImVec4(0.5f, 0.8f, 1.0f, 1.0f), "Space > ..."); + ImGui::Separator(); + } + + // Color palette for visual grouping + const ImVec4 colors[] = { + ImVec4(0.8f, 0.2f, 0.2f, 1.0f), // Red - Window + ImVec4(0.2f, 0.8f, 0.2f, 1.0f), // Green - Buffer + ImVec4(0.2f, 0.2f, 0.8f, 1.0f), // Blue - File + ImVec4(0.8f, 0.8f, 0.2f, 1.0f), // Yellow - Session + ImVec4(0.8f, 0.2f, 0.8f, 1.0f), // Magenta - Layout + ImVec4(0.2f, 0.8f, 0.8f, 1.0f) // Cyan - Theme + }; + + // Show commands based on current navigation level + if (current_prefix_.empty()) { + // Root level - show main groups + if (ImGui::BeginTable("RootCommands", 6, ImGuiTableFlags_SizingStretchProp)) { + int colorIndex = 0; + for (const auto &[shortcut, group] : commands_) { + ImGui::TableNextColumn(); + ImGui::TextColored(colors[colorIndex % 6], + "%c: %s", + group.main_command.mnemonic, + group.main_command.name.c_str()); + colorIndex++; + } + ImGui::EndTable(); + } + } else { + // Submenu level - show subcommands + auto it = commands_.find(current_prefix_); + if (it != commands_.end()) { + const auto& group = it->second; + if (!group.subcommands.empty()) { + if (ImGui::BeginTable("Subcommands", + std::min(6, (int)group.subcommands.size()), + ImGuiTableFlags_SizingStretchProp)) { + int colorIndex = 0; + for (const auto& [key, cmd] : group.subcommands) { + ImGui::TableNextColumn(); + ImGui::TextColored(colors[colorIndex % 6], + "%c: %s", + cmd.mnemonic, + cmd.name.c_str()); + colorIndex++; + } + ImGui::EndTable(); + } + } else { + ImGui::TextDisabled("No subcommands available"); + } + } + } + + ImGui::EndPopup(); + } else { + whichkey_active_ = false; + current_prefix_.clear(); + } +} + +// Handle keyboard input for WhichKey navigation +void CommandManager::HandleWhichKeyInput() { + if (!whichkey_active_) return; + + // Check for prefix keys (w, l, f, b, s, t, etc.) + for (const auto& [shortcut, group] : commands_) { + ImGuiKey key = gui::MapKeyToImGuiKey(group.main_command.mnemonic); + if (key != ImGuiKey_COUNT && ImGui::IsKeyPressed(key)) { + if (current_prefix_.empty()) { + // Enter submenu + current_prefix_ = shortcut; + whichkey_timer_ = 0.0f; + return; + } else { + // Execute subcommand + auto it = commands_.find(current_prefix_); + if (it != commands_.end()) { + for (const auto& [subkey, cmd] : it->second.subcommands) { + if (cmd.mnemonic == group.main_command.mnemonic) { + if (cmd.command) { + cmd.command(); + } + whichkey_active_ = false; + current_prefix_.clear(); + ImGui::CloseCurrentPopup(); + return; + } + } + } + } + } + } +} + } // namespace editor } // namespace yaze diff --git a/src/app/editor/system/command_manager.h b/src/app/editor/system/command_manager.h index 773c6e74..a87af3cd 100644 --- a/src/app/editor/system/command_manager.h +++ b/src/app/editor/system/command_manager.h @@ -72,11 +72,24 @@ class CommandManager { void ShowWhichKey(); + // Enhanced hierarchical WhichKey with submenu support + void ShowWhichKeyHierarchical(); + void HandleWhichKeyInput(); + void SaveKeybindings(const std::string &filepath); void LoadKeybindings(const std::string &filepath); + // Navigation state + bool IsWhichKeyActive() const { return whichkey_active_; } + std::string GetCurrentPrefix() const { return current_prefix_; } + private: std::unordered_map commands_; + + // WhichKey state + bool whichkey_active_ = false; + std::string current_prefix_; // Current navigation prefix (e.g., "w", "l", "f") + float whichkey_timer_ = 0.0f; // Auto-close timer }; } // namespace editor diff --git a/src/app/editor/system/shortcut_manager.cc b/src/app/editor/system/shortcut_manager.cc index 02e87c21..daf18bc4 100644 --- a/src/app/editor/system/shortcut_manager.cc +++ b/src/app/editor/system/shortcut_manager.cc @@ -164,5 +164,90 @@ void ExecuteShortcuts(const ShortcutManager& shortcut_manager) { } } +} // namespace editor +} // namespace yaze + +// Implementation in header file (inline methods) +namespace yaze { +namespace editor { + +void ShortcutManager::RegisterStandardShortcuts( + std::function save_callback, + std::function open_callback, + std::function close_callback, + std::function find_callback, + std::function settings_callback) { + + // Ctrl+S - Save + if (save_callback) { + RegisterShortcut("save", {ImGuiMod_Ctrl, ImGuiKey_S}, save_callback); + } + + // Ctrl+O - Open + if (open_callback) { + RegisterShortcut("open", {ImGuiMod_Ctrl, ImGuiKey_O}, open_callback); + } + + // Ctrl+W - Close + if (close_callback) { + RegisterShortcut("close", {ImGuiMod_Ctrl, ImGuiKey_W}, close_callback); + } + + // Ctrl+F - Find + if (find_callback) { + RegisterShortcut("find", {ImGuiMod_Ctrl, ImGuiKey_F}, find_callback); + } + + // Ctrl+, - Settings + if (settings_callback) { + RegisterShortcut("settings", {ImGuiMod_Ctrl, ImGuiKey_Comma}, settings_callback); + } + + // Ctrl+Tab - Next tab (placeholder for now) + // Ctrl+Shift+Tab - Previous tab (placeholder for now) +} + +void ShortcutManager::RegisterWindowNavigationShortcuts( + std::function focus_left, + std::function focus_right, + std::function focus_up, + std::function focus_down, + std::function close_window, + std::function split_horizontal, + std::function split_vertical) { + + // Ctrl+Arrow keys for window navigation + if (focus_left) { + RegisterShortcut("focus_left", {ImGuiMod_Ctrl, ImGuiKey_LeftArrow}, focus_left); + } + + if (focus_right) { + RegisterShortcut("focus_right", {ImGuiMod_Ctrl, ImGuiKey_RightArrow}, focus_right); + } + + if (focus_up) { + RegisterShortcut("focus_up", {ImGuiMod_Ctrl, ImGuiKey_UpArrow}, focus_up); + } + + if (focus_down) { + RegisterShortcut("focus_down", {ImGuiMod_Ctrl, ImGuiKey_DownArrow}, focus_down); + } + + // Ctrl+W, C - Close current window + if (close_window) { + RegisterShortcut("close_window", {ImGuiMod_Ctrl, ImGuiKey_W, ImGuiKey_C}, close_window); + } + + // Ctrl+W, S - Split horizontal + if (split_horizontal) { + RegisterShortcut("split_horizontal", {ImGuiMod_Ctrl, ImGuiKey_W, ImGuiKey_S}, split_horizontal); + } + + // Ctrl+W, V - Split vertical + if (split_vertical) { + RegisterShortcut("split_vertical", {ImGuiMod_Ctrl, ImGuiKey_W, ImGuiKey_V}, split_vertical); + } +} + } // 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 index 4b0a7442..86637e24 100644 --- a/src/app/editor/system/shortcut_manager.h +++ b/src/app/editor/system/shortcut_manager.h @@ -62,6 +62,23 @@ class ShortcutManager { auto GetShortcuts() const { return shortcuts_; } + // Convenience methods for registering common shortcuts + void RegisterStandardShortcuts( + std::function save_callback, + std::function open_callback, + std::function close_callback, + std::function find_callback, + std::function settings_callback); + + void RegisterWindowNavigationShortcuts( + std::function focus_left, + std::function focus_right, + std::function focus_up, + std::function focus_down, + std::function close_window, + std::function split_horizontal, + std::function split_vertical); + private: std::unordered_map shortcuts_; };