From 9123b21e18e0823d07701f6f837cca443c95534f Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 16 Dec 2020 22:43:07 +0100 Subject: [PATCH] Added basic command palette (similar to the one in vscode) --- CMakeLists.txt | 1 + include/views/view.hpp | 21 ++++ include/views/view_command_palette.hpp | 40 ++++++++ source/main.cpp | 2 + source/views/view_command_palette.cpp | 131 +++++++++++++++++++++++++ source/window.cpp | 22 ++++- 6 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 include/views/view_command_palette.hpp create mode 100644 source/views/view_command_palette.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 40fd4580b..c19de3b74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ add_executable(ImHex source/views/view_disassembler.cpp source/views/view_bookmarks.cpp source/views/view_patches.cpp + source/views/view_command_palette.cpp libs/glad/source/glad.c diff --git a/include/views/view.hpp b/include/views/view.hpp index 90d844c70..96171dca2 100644 --- a/include/views/view.hpp +++ b/include/views/view.hpp @@ -52,7 +52,25 @@ namespace hex { ImGui::OpenPopup("Error"); } + static void setWindowPosition(s32 x, s32 y) { + View::s_windowPos = ImVec2(x, y); + } + + static const ImVec2& getWindowPosition() { + return View::s_windowPos; + } + + static void setWindowSize(s32 width, s32 height) { + View::s_windowSize = ImVec2(width, height); + } + + static const ImVec2& getWindowSize() { + return View::s_windowSize; + } + virtual bool hasViewMenuItemEntry() { return true; } + virtual ImVec2 getMinSize() { return ImVec2(480, 720); } + virtual ImVec2 getMaxSize() { return ImVec2(FLT_MAX, FLT_MAX); } bool& getWindowOpenState() { return this->m_windowOpen; @@ -85,6 +103,9 @@ namespace hex { static inline std::vector> s_deferedCalls; static inline std::string s_errorMessage; + + static inline ImVec2 s_windowPos; + static inline ImVec2 s_windowSize; }; void confirmButtons(const char *textLeft, const char *textRight, auto leftButtonFn, auto rightButtonFn) { diff --git a/include/views/view_command_palette.hpp b/include/views/view_command_palette.hpp new file mode 100644 index 000000000..761a750a8 --- /dev/null +++ b/include/views/view_command_palette.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "imgui.h" +#include "views/view.hpp" +#include "lang/pattern_data.hpp" + +#include +#include +#include + +namespace hex { + + namespace prv { class Provider; } + + class ViewCommandPalette : public View { + public: + ViewCommandPalette(); + ~ViewCommandPalette() override; + + void createView() override; + void createMenu() override; + + bool handleShortcut(int key, int mods) override; + + bool hasViewMenuItemEntry() override { return false; } + ImVec2 getMinSize() override { return ImVec2(400, 100); } + ImVec2 getMaxSize() override { return ImVec2(400, 100); } + + private: + bool m_justOpened = false; + std::vector m_commandBuffer; + std::vector m_lastResults; + std::string m_exactResult; + + std::vector getCommandResults(std::string_view command); + }; + +} \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 6019f242b..cc67e0b39 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -13,6 +13,7 @@ #include "views/view_disassembler.hpp" #include "views/view_bookmarks.hpp" #include "views/view_patches.hpp" +#include "views/view_command_palette.hpp" #include "providers/provider.hpp" @@ -43,6 +44,7 @@ int main(int argc, char **argv) { window.addView(dataProvider); window.addView(dataProvider); window.addView(dataProvider); + window.addView(); window.addView(); if (argc > 1) diff --git a/source/views/view_command_palette.cpp b/source/views/view_command_palette.cpp new file mode 100644 index 000000000..e4d056767 --- /dev/null +++ b/source/views/view_command_palette.cpp @@ -0,0 +1,131 @@ +#include "views/view_command_palette.hpp" + +#include + +#include "helpers/math_evaluator.hpp" + +namespace hex { + + ViewCommandPalette::ViewCommandPalette() : View("Command Palette") { + this->getWindowOpenState() = true; + + this->m_commandBuffer.resize(1024, 0x00); + this->m_lastResults = this->getCommandResults(""); + } + + ViewCommandPalette::~ViewCommandPalette() { + + } + + void ViewCommandPalette::createView() { + + auto windowPos = View::getWindowPosition(); + auto windowSize = View::getWindowSize(); + auto paletteSize = this->getMinSize(); + ImGui::SetNextWindowPos(ImVec2(windowPos.x + (windowSize.x - paletteSize.x) / 2.0F, windowPos.y), ImGuiCond_Always); + if (ImGui::BeginPopup("Command Palette")) { + if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) + ImGui::CloseCurrentPopup(); + + ImGui::PushItemWidth(paletteSize.x - ImGui::GetStyle().WindowPadding.x * 2); + if (ImGui::InputText("##nolabel", this->m_commandBuffer.data(), this->m_commandBuffer.size(), ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_EnterReturnsTrue, + [](ImGuiInputTextCallbackData *callbackData) -> int { + auto _this = static_cast(callbackData->UserData); + _this->m_lastResults = _this->getCommandResults(callbackData->Buf); + + return 0; + }, this)) { + ImGui::CloseCurrentPopup(); + } + ImGui::PopItemWidth(); + + if (this->m_justOpened) { + ImGui::SetKeyboardFocusHere(0); + this->m_justOpened = false; + } + + ImGui::Separator(); + + for (const auto &result : this->m_lastResults) { + ImGui::TextUnformatted(result.c_str()); + } + + ImGui::EndPopup(); + } + } + + void ViewCommandPalette::createMenu() { + + } + + bool ViewCommandPalette::handleShortcut(int key, int mods) { + if (key == GLFW_KEY_P && mods == (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL)) { + View::doLater([this] { + this->m_justOpened = true; + ImGui::OpenPopup("Command Palette"); + }); + return true; + } + + return false; + } + + enum class MatchType { + NoMatch, + InfoMatch, + PartialMatch, + PerfectMatch + }; + + std::vector ViewCommandPalette::getCommandResults(std::string_view command) { + constexpr auto matchCommand = [](std::string_view currCommand, std::string_view commandToMatch) -> std::pair { + if (currCommand.empty()) { + return { MatchType::InfoMatch, "" }; + } + else if (currCommand.size() <= commandToMatch.size()) { + if (commandToMatch.starts_with(currCommand)) + return { MatchType::PartialMatch, currCommand }; + else + return { MatchType::NoMatch, { } }; + } + else { + if (currCommand.starts_with(commandToMatch)) + return { MatchType::PerfectMatch, currCommand.substr(commandToMatch.length()) }; + else + return { MatchType::NoMatch, { } }; + } + }; + + std::vector results; + + if (auto [match, value] = matchCommand(command, "#"); match != MatchType::NoMatch) { + if (match != MatchType::PerfectMatch) + results.emplace_back("# (Calculator)"); + else { + MathEvaluator evaluator; + evaluator.registerStandardVariables(); + evaluator.registerStandardFunctions(); + + auto result = evaluator.evaluate(std::string(value)); + + if (result.has_value()) + results.emplace_back(hex::format("#%s = %Lf", value.data(), result.value())); + else + results.emplace_back(hex::format("#%s = ???", value.data())); + } + } + if (auto [match, value] = matchCommand(command, "/find "); match != MatchType::NoMatch) { + if (match != MatchType::PerfectMatch) + results.emplace_back("/find (Find Command)"); + else { + results.emplace_back(hex::format("Command: Find \"%s\"", value.data())); + } + } + if (auto [match, value] = matchCommand(command, ">"); match != MatchType::NoMatch) { + results.emplace_back("> (Command)"); + } + + return results; + } + +} \ No newline at end of file diff --git a/source/window.cpp b/source/window.cpp index f30f1ee46..34a2d4dfd 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -69,7 +69,7 @@ namespace hex { if (!view->getWindowOpenState()) continue; - ImGui::SetNextWindowSizeConstraints(ImVec2(480, 720), ImVec2(FLT_MAX, FLT_MAX)); + ImGui::SetNextWindowSizeConstraints(view->getMinSize(), view->getMaxSize()); view->createView(); } @@ -240,6 +240,26 @@ namespace hex { glfwMakeContextCurrent(this->m_window); glfwSwapInterval(1); + { + int x = 0, y = 0; + glfwGetWindowPos(this->m_window, &x, &y); + View::setWindowPosition(x, y); + } + + { + int width = 0, height = 0; + glfwGetWindowSize(this->m_window, &width, &height); + View::setWindowSize(width, height); + } + + glfwSetWindowPosCallback(this->m_window, [](GLFWwindow *window, int x, int y) { + View::setWindowPosition(x, y); + }); + + glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) { + View::setWindowSize(width, height); + }); + glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS) Window::s_currShortcut = { key, mods };