diff --git a/lib/libimhex/include/hex/api/content_registry/command_palette.hpp b/lib/libimhex/include/hex/api/content_registry/command_palette.hpp index bada8ec76..39ec8fc67 100644 --- a/lib/libimhex/include/hex/api/content_registry/command_palette.hpp +++ b/lib/libimhex/include/hex/api/content_registry/command_palette.hpp @@ -21,12 +21,14 @@ EXPORT_MODULE namespace hex { namespace impl { + using QueryResultCallback = std::function; + struct QueryResult { std::string name; - std::function callback; + QueryResultCallback callback; }; - using ContentDisplayCallback = std::function; + using ContentDisplayCallback = std::function; using DisplayCallback = std::function; using ExecuteCallback = std::function(std::string)>; using QueryCallback = std::function(std::string)>; @@ -46,10 +48,15 @@ EXPORT_MODULE namespace hex { DisplayCallback displayCallback; }; + struct ContentDisplay { + bool showSearchBox; + ContentDisplayCallback callback; + }; + const std::vector& getEntries(); const std::vector& getHandlers(); - std::optional& getDisplayedContent(); + std::optional& getDisplayedContent(); } @@ -86,6 +93,12 @@ EXPORT_MODULE namespace hex { * @param displayCallback Display callback that will be called to display the content */ void setDisplayedContent(const impl::ContentDisplayCallback &displayCallback); + + /** + * @brief Opens the command palette window, displaying a user defined interface + * @param displayCallback Display callback that will be called to display the content + */ + void openWithContent(const impl::ContentDisplayCallback &displayCallback); } } \ No newline at end of file diff --git a/lib/libimhex/include/hex/api/events/requests_interaction.hpp b/lib/libimhex/include/hex/api/events/requests_interaction.hpp index 87f20a8ab..26ca515c8 100644 --- a/lib/libimhex/include/hex/api/events/requests_interaction.hpp +++ b/lib/libimhex/include/hex/api/events/requests_interaction.hpp @@ -71,34 +71,8 @@ namespace hex { /** * @brief Requests the Pattern editor to run the current code * - * This is only ever used in the introduction tutorial. - * - * FIXME: the name is misleading, as for now this activates the pattern's auto-evaluation rather than a - * one-off execution */ - EVENT_DEF(RequestRunPatternCode); - - /** - * @brief Request to load a pattern language file - * - * FIXME: this request is unused, as now another component is responsible for pattern file loading. - * This request should be scrapped. - * - * @param path the pattern file's path - * @param bool track changes to the file on disk - * - */ - EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path, bool); - - /** - * @brief Request to save a pattern language file - * - * FIXME: this request is unused, as now another component is responsible for pattern file saving. - * This request should be scrapped. - * - * @param path the pattern file's path - */ - EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path); + EVENT_DEF(RequestTriggerPatternEvaluation); /** * @brief Requests ImHex to open and process a file @@ -116,4 +90,9 @@ namespace hex { */ EVENT_DEF(RequestAddVirtualFile, std::fs::path, std::vector, Region); + /** + * @brief Requests the command palette to be opened + */ + EVENT_DEF(RequestOpenCommandPalette); + } diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 75c454b67..c0dd1ea1c 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #if defined(OS_WEB) #include @@ -613,8 +614,8 @@ namespace hex { return *s_handlers; } - static AutoReset> s_displayedContent; - std::optional& getDisplayedContent() { + static AutoReset> s_displayedContent; + std::optional& getDisplayedContent() { return *s_displayedContent; } @@ -633,7 +634,12 @@ namespace hex { } void setDisplayedContent(const impl::ContentDisplayCallback &displayCallback) { - impl::s_displayedContent = displayCallback; + impl::s_displayedContent = impl::ContentDisplay { true, displayCallback }; + } + + void openWithContent(const impl::ContentDisplayCallback &displayCallback) { + RequestOpenCommandPalette::post(); + impl::s_displayedContent = impl::ContentDisplay { false, displayCallback }; } } diff --git a/plugins/builtin/source/content/command_line_interface.cpp b/plugins/builtin/source/content/command_line_interface.cpp index 44351c014..73b6ea377 100644 --- a/plugins/builtin/source/content/command_line_interface.cpp +++ b/plugins/builtin/source/content/command_line_interface.cpp @@ -566,7 +566,7 @@ namespace hex::plugin::builtin { } RequestSetPatternLanguageCode::post(patternSourceCode); - RequestRunPatternCode::post(); + RequestTriggerPatternEvaluation::post(); }); } diff --git a/plugins/builtin/source/content/command_palette_commands.cpp b/plugins/builtin/source/content/command_palette_commands.cpp index 39a6b75f1..672a8ca1f 100644 --- a/plugins/builtin/source/content/command_palette_commands.cpp +++ b/plugins/builtin/source/content/command_palette_commands.cpp @@ -454,7 +454,7 @@ namespace hex::plugin::builtin { continue; result.emplace_back(name, [&toolEntry](const auto &) { - ContentRegistry::CommandPalette::setDisplayedContent([&toolEntry](const auto) { + ContentRegistry::CommandPalette::setDisplayedContent([&toolEntry]() { toolEntry.function(); }); }); diff --git a/plugins/builtin/source/content/tutorials/introduction.cpp b/plugins/builtin/source/content/tutorials/introduction.cpp index e49234f01..b89d15bfe 100644 --- a/plugins/builtin/source/content/tutorials/introduction.cpp +++ b/plugins/builtin/source/content/tutorials/introduction.cpp @@ -75,7 +75,7 @@ namespace hex::plugin::builtin { }) .onAppear([] { RequestSetPatternLanguageCode::post("\n\n\n\n\n\nstruct Test {\n u8 value;\n};\n\nTest test @ 0x00;"); - RequestRunPatternCode::post(); + RequestTriggerPatternEvaluation::post(); }) .allowSkip(); } diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index e78cd003c..e2c26c2b0 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -3,9 +3,12 @@ #include #include #include + #include #include #include +#include +#include #include #include @@ -24,7 +27,6 @@ #include #include -#include namespace hex::plugin::builtin { @@ -423,8 +425,10 @@ namespace hex::plugin::builtin { EventProviderChanged::subscribe([](auto, auto) { providerJustChanged = true; }); static prv::Provider *rightClickedProvider = nullptr; - EventSearchBoxClicked::subscribe([](ImGuiMouseButton button){ - if (button == ImGuiMouseButton_Right) { + EventSearchBoxClicked::subscribe([](ImGuiMouseButton button) { + if (button == ImGuiMouseButton_Left) { + RequestOpenCommandPalette::post(); + } else if (button == ImGuiMouseButton_Right) { rightClickedProvider = ImHexApi::Provider::get(); RequestOpenPopup::post("ProviderMenu"); } diff --git a/plugins/builtin/source/content/views/view_command_palette.cpp b/plugins/builtin/source/content/views/view_command_palette.cpp index 7cd138772..abc797f66 100644 --- a/plugins/builtin/source/content/views/view_command_palette.cpp +++ b/plugins/builtin/source/content/views/view_command_palette.cpp @@ -2,51 +2,51 @@ #include #include + #include -#include +#include #include "imstb_textedit.h" #include +#include namespace hex::plugin::builtin { ViewCommandPalette::ViewCommandPalette() : View::Special("hex.builtin.view.command_palette.name") { // Add global shortcut to open the command palette ShortcutManager::addGlobalShortcut(CTRLCMD + SHIFT + Keys::P, "hex.builtin.view.command_palette.name", [this] { - RequestOpenPopup::post("hex.builtin.view.command_palette.name"_lang); - m_commandPaletteOpen = true; - m_justOpened = true; + RequestOpenCommandPalette::post(); }); - EventSearchBoxClicked::subscribe([this](ImGuiMouseButton button) { - if (button == ImGuiMouseButton_Left) { - m_commandPaletteOpen = true; - m_justOpened = true; - } + RequestOpenCommandPalette::subscribe([this]() { + m_commandPaletteOpen = true; + m_justOpened = true; + ContentRegistry::CommandPalette::impl::getDisplayedContent().reset(); }); } void ViewCommandPalette::drawAlwaysVisibleContent() { + auto &displayedContent = ContentRegistry::CommandPalette::impl::getDisplayedContent(); + if (m_justOpened) { ImGui::OpenPopup("hex.builtin.view.command_palette.name"_lang); - ContentRegistry::CommandPalette::impl::getDisplayedContent().reset(); } // If the command palette is hidden, don't draw it if (!m_commandPaletteOpen) return; - auto windowPos = ImHexApi::System::getMainWindowPosition(); - auto windowSize = ImHexApi::System::getMainWindowSize(); - - const auto &displayedContent = ContentRegistry::CommandPalette::impl::getDisplayedContent(); + const auto windowPos = ImHexApi::System::getMainWindowPosition(); + const auto windowSize = ImHexApi::System::getMainWindowSize(); ImGui::SetNextWindowPos(ImVec2(windowPos.x + windowSize.x * 0.5F, windowPos.y), ImGuiCond_Always, ImVec2(0.5F, 0.0F)); if (!displayedContent.has_value()) ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize()); else - ImGui::SetNextWindowSizeConstraints(this->getMinSize(), ImVec2(FLT_MAX, FLT_MAX)); + ImGui::SetNextWindowSizeConstraints(ImVec2(this->getMinSize().x, 20_scaled), ImVec2(FLT_MAX, FLT_MAX)); - if (ImGui::BeginPopup("hex.builtin.view.command_palette.name"_lang)) { + const bool hasSearchBox = !displayedContent.has_value() || displayedContent->showSearchBox; + + if (ImGui::BeginPopup("hex.builtin.view.command_palette.name"_lang, !hasSearchBox ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None)) { ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindowRead()); ImGui::BringWindowToFocusFront(ImGui::GetCurrentWindowRead()); @@ -54,82 +54,92 @@ namespace hex::plugin::builtin { if (ImGui::IsKeyDown(ImGuiKey_Escape)) ImGui::CloseCurrentPopup(); + if (hasSearchBox) { + const auto buttonColor = [](float alpha) { + return ImU32(ImColor(ImGui::GetStyleColorVec4(ImGuiCol_ModalWindowDimBg) * ImVec4(1, 1, 1, alpha))); + }; - const auto buttonColor = [](float alpha) { - return ImU32(ImColor(ImGui::GetStyleColorVec4(ImGuiCol_ModalWindowDimBg) * ImVec4(1, 1, 1, alpha))); - }; + // Draw the main input text box + ImGui::PushItemWidth(-1); + ImGui::PushStyleColor(ImGuiCol_FrameBg, buttonColor(0.5F)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, buttonColor(0.7F)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, buttonColor(0.9F)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0_scaled); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4_scaled); - // Draw the main input text box - ImGui::PushItemWidth(-1); - ImGui::PushStyleColor(ImGuiCol_FrameBg, buttonColor(0.5F)); - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, buttonColor(0.7F)); - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, buttonColor(0.9F)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0_scaled); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4_scaled); - - if (ImGui::InputText("##command_input", m_commandBuffer)) { - m_lastResults = this->getCommandResults(m_commandBuffer); - } - ImGui::SetItemKeyOwner(ImGuiKey_LeftAlt, ImGuiInputFlags_CondActive); - - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(3); - ImGui::PopItemWidth(); - ImGui::SetItemDefaultFocus(); - - if (m_moveCursorToEnd) { - auto textState = ImGui::GetInputTextState(ImGui::GetID("##command_input")); - if (textState != nullptr) { - auto stb = reinterpret_cast(textState->Stb); - stb->cursor = - stb->select_start = - stb->select_end = m_commandBuffer.size(); + if (ImGui::InputText("##command_input", m_commandBuffer)) { + m_lastResults = this->getCommandResults(m_commandBuffer); } - m_moveCursorToEnd = false; - } + ImGui::SetItemKeyOwner(ImGuiKey_LeftAlt, ImGuiInputFlags_CondActive); - // Handle giving back focus to the input text box - if (m_focusInputTextBox) { - ImGui::SetKeyboardFocusHere(-1); - ImGui::ActivateItemByID(ImGui::GetID("##command_input")); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(3); + ImGui::PopItemWidth(); + ImGui::SetItemDefaultFocus(); - m_focusInputTextBox = false; - m_moveCursorToEnd = true; - } + if (m_moveCursorToEnd) { + auto textState = ImGui::GetInputTextState(ImGui::GetID("##command_input")); + if (textState != nullptr) { + auto stb = reinterpret_cast(textState->Stb); + stb->cursor = + stb->select_start = + stb->select_end = m_commandBuffer.size(); + } + m_moveCursorToEnd = false; + } - // Execute the currently selected command when pressing enter - if (ImGui::IsItemFocused() && (ImGui::IsKeyPressed(ImGuiKey_Enter, false) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter, false))) { - bool closePalette = true; - if (!m_lastResults.empty()) { - auto &[displayResult, matchedCommand, callback] = m_lastResults.front(); + // Handle giving back focus to the input text box + if (m_focusInputTextBox) { + ImGui::SetKeyboardFocusHere(-1); + ImGui::ActivateItemByID(ImGui::GetID("##command_input")); - if (auto result = callback(matchedCommand); result.has_value()) { - m_commandBuffer = result.value(); - closePalette = false; - m_focusInputTextBox = true; + m_focusInputTextBox = false; + m_moveCursorToEnd = true; + } + + // Execute the currently selected command when pressing enter + if (ImGui::IsItemFocused() && (ImGui::IsKeyPressed(ImGuiKey_Enter, false) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter, false))) { + bool closePalette = true; + if (!m_lastResults.empty()) { + auto &[displayResult, matchedCommand, callback] = m_lastResults.front(); + + if (auto result = callback(matchedCommand); result.has_value()) { + m_commandBuffer = result.value(); + closePalette = false; + m_focusInputTextBox = true; + } + } + + if (closePalette) { + ImGui::CloseCurrentPopup(); } } - if (closePalette) { - ImGui::CloseCurrentPopup(); + // Focus the input text box when the popup is opened + if (m_justOpened) { + focusInputTextBox(); + m_lastResults = this->getCommandResults(""); + m_commandBuffer.clear(); } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y); + + ImGui::Separator(); } - // Focus the input text box when the popup is opened - if (m_justOpened) { - focusInputTextBox(); - m_lastResults = this->getCommandResults(""); - m_commandBuffer.clear(); - m_justOpened = false; - } - - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y); - - ImGui::Separator(); + m_justOpened = false; // Draw the results if (displayedContent.has_value()) { - (*displayedContent)(m_commandBuffer); + if (!displayedContent->showSearchBox){ + if (ImGui::BeginMenuBar()) { + ImGui::TextUnformatted(ICON_VS_TARGET); + ImGui::EndMenuBar(); + } + + displayedContent->callback(); + } + } else { if (ImGui::BeginChild("##results", ImGui::GetContentRegionAvail(), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { u32 id = 1; @@ -252,4 +262,4 @@ namespace hex::plugin::builtin { return results; } -} \ No newline at end of file +} diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 96eb71789..8b5d21d2a 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -238,7 +238,7 @@ namespace hex::plugin::builtin { ViewPatternEditor::~ViewPatternEditor() { RequestPatternEditorSelectionChange::unsubscribe(this); RequestSetPatternLanguageCode::unsubscribe(this); - RequestRunPatternCode::unsubscribe(this); + RequestTriggerPatternEvaluation::unsubscribe(this); EventFileLoaded::unsubscribe(this); EventProviderChanged::unsubscribe(this); EventProviderClosed::unsubscribe(this); @@ -1854,20 +1854,10 @@ namespace hex::plugin::builtin { m_textEditor.get(provider).setCursorPosition(coords); }); - RequestLoadPatternLanguageFile::subscribe(this, [this](const std::fs::path &path, bool trackFile) { - this->loadPatternFile(path, ImHexApi::Provider::get(), trackFile); - }); - - RequestRunPatternCode::subscribe(this, [this] { + RequestTriggerPatternEvaluation::subscribe(this, [this] { m_triggerAutoEvaluate = true; }); - RequestSavePatternLanguageFile::subscribe(this, [this](const std::fs::path &path) { - auto provider = ImHexApi::Provider::get(); - wolv::io::File file(path, wolv::io::File::Mode::Create); - file.writeString(wolv::util::trim(m_textEditor.get(provider).getText())); - }); - RequestSetPatternLanguageCode::subscribe(this, [this](const std::string &code) { auto provider = ImHexApi::Provider::get(); m_textEditor.get(provider).setText(wolv::util::preprocessText(code));