From 4c5d2f6ebb8e9d3b16dd09dd549ec8c3a76f7b9d Mon Sep 17 00:00:00 2001 From: WerWolv Date: Tue, 8 Nov 2022 21:43:22 +0100 Subject: [PATCH] feat: Finish up work on new pl section system --- lib/external/pattern_language | 2 +- lib/libimhex/include/hex/api/event.hpp | 4 +- lib/libimhex/include/hex/api/imhex_api.hpp | 16 +++- lib/libimhex/source/api/imhex_api.cpp | 22 +++-- plugins/builtin/CMakeLists.txt | 5 +- .../providers/memory_file_provider.hpp | 9 +- .../content/views/view_data_inspector.hpp | 1 + .../include/content/views/view_hex_editor.hpp | 4 +- .../content/views/view_pattern_data.hpp | 4 +- .../content/views/view_pattern_editor.hpp | 8 +- .../{content/helpers => ui}/hex_editor.hpp | 22 +++-- .../helpers => ui}/pattern_drawer.hpp | 7 +- plugins/builtin/include/ui/widgets.hpp | 3 + .../source/content/data_processor_nodes.cpp | 2 +- .../content/views/view_data_inspector.cpp | 31 +++--- .../source/content/views/view_find.cpp | 2 +- .../source/content/views/view_hashes.cpp | 2 +- .../source/content/views/view_hex_editor.cpp | 21 ++-- .../content/views/view_pattern_data.cpp | 96 +------------------ .../content/views/view_pattern_editor.cpp | 33 ++++--- .../{content/helpers => ui}/hex_editor.cpp | 80 ++++++++-------- .../helpers => ui}/pattern_drawer.cpp | 91 +++++++++++++++++- 22 files changed, 250 insertions(+), 215 deletions(-) rename plugins/builtin/include/{content/helpers => ui}/hex_editor.hpp (89%) rename plugins/builtin/include/{content/helpers => ui}/pattern_drawer.hpp (88%) rename plugins/builtin/source/{content/helpers => ui}/hex_editor.cpp (90%) rename plugins/builtin/source/{content/helpers => ui}/pattern_drawer.cpp (77%) diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 2fc96aedc..a74070f38 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 2fc96aedca0f665957eec878d75403eff7de5a91 +Subproject commit a74070f38e7deae8c82e827f3a84a0e2619d5981 diff --git a/lib/libimhex/include/hex/api/event.hpp b/lib/libimhex/include/hex/api/event.hpp index 04ec37f1f..91afe8f38 100644 --- a/lib/libimhex/include/hex/api/event.hpp +++ b/lib/libimhex/include/hex/api/event.hpp @@ -106,7 +106,7 @@ namespace hex { EVENT_DEF(EventDataChanged); EVENT_DEF(EventHighlightingChanged); EVENT_DEF(EventWindowClosing, GLFWwindow *); - EVENT_DEF(EventRegionSelected, Region); + EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion); EVENT_DEF(EventSettingsChanged); EVENT_DEF(EventAbnormalTermination, int); EVENT_DEF(EventOSThemeChanged); @@ -138,6 +138,4 @@ namespace hex { EVENT_DEF(RequestShowYesNoQuestionPopup, std::string, std::function, std::function); EVENT_DEF(RequestShowFileChooserPopup, std::vector, std::vector, std::function); - EVENT_DEF(QuerySelection, std::optional &); - } \ No newline at end of file diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index fd4f5fe5b..ea48188af 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -64,6 +64,14 @@ namespace hex { color_t m_color = 0x00; }; + struct ProviderRegion : public Region { + prv::Provider *provider; + + [[nodiscard]] prv::Provider *getProvider() const { return this->provider; } + + [[nodiscard]] Region getRegion() const { return { this->address, this->size }; } + }; + namespace impl { using HighlightingFunction = std::function(u64, const u8*, size_t, bool)>; @@ -75,6 +83,7 @@ namespace hex { std::map &getTooltips(); std::map &getTooltipFunctions(); + void setCurrentSelection(ProviderRegion region); } u32 addBackgroundHighlight(const Region ®ion, color_t color); @@ -96,9 +105,10 @@ namespace hex { void removeForegroundHighlightingProvider(u32 id); bool isSelectionValid(); - std::optional getSelection(); - void setSelection(const Region ®ion); - void setSelection(u64 address, size_t size); + std::optional getSelection(); + void setSelection(const Region ®ion, prv::Provider *provider = nullptr); + void setSelection(const ProviderRegion ®ion); + void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr); } diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 40346a153..a8e0ccfea 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -75,6 +75,11 @@ namespace hex { return s_tooltipFunctions; } + static std::optional s_currentSelection; + void setCurrentSelection(std::optional region) { + s_currentSelection = region; + } + } u32 addBackgroundHighlight(const Region ®ion, color_t color) { @@ -181,19 +186,20 @@ namespace hex { return getSelection().has_value(); } - std::optional getSelection() { - std::optional selection; - EventManager::post(selection); - - return selection; + std::optional getSelection() { + return impl::s_currentSelection; } - void setSelection(const Region ®ion) { + void setSelection(const Region ®ion, prv::Provider *provider) { + setSelection(ProviderRegion { region, provider == nullptr ? Provider::get() : provider }); + } + + void setSelection(const ProviderRegion ®ion) { EventManager::post(region); } - void setSelection(u64 address, size_t size) { - setSelection({ address, size }); + void setSelection(u64 address, size_t size, prv::Provider *provider) { + setSelection({ { address, size }, provider == nullptr ? Provider::get() : provider }); } } diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 6faecbf67..98bcafcd2 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -54,8 +54,9 @@ add_library(${PROJECT_NAME} SHARED source/content/views/view_find.cpp source/content/helpers/math_evaluator.cpp - source/content/helpers/pattern_drawer.cpp - source/content/helpers/hex_editor.cpp + + source/ui/hex_editor.cpp + source/ui/pattern_drawer.cpp source/lang/de_DE.cpp source/lang/en_US.cpp diff --git a/plugins/builtin/include/content/providers/memory_file_provider.hpp b/plugins/builtin/include/content/providers/memory_file_provider.hpp index b26267eb3..fa7337fe5 100644 --- a/plugins/builtin/include/content/providers/memory_file_provider.hpp +++ b/plugins/builtin/include/content/providers/memory_file_provider.hpp @@ -12,9 +12,9 @@ namespace hex::plugin::builtin { [[nodiscard]] bool isAvailable() const override { return true; } [[nodiscard]] bool isReadable() const override { return true; } - [[nodiscard]] bool isWritable() const override { return true; } - [[nodiscard]] bool isResizable() const override { return true; } - [[nodiscard]] bool isSavable() const override { return true; } + [[nodiscard]] bool isWritable() const override { return !this->m_readOnly; } + [[nodiscard]] bool isResizable() const override { return !this->m_readOnly; } + [[nodiscard]] bool isSavable() const override { return !this->m_readOnly; } [[nodiscard]] bool open() override; void close() override { } @@ -42,8 +42,11 @@ namespace hex::plugin::builtin { void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); } [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; } + void setReadOnly(bool readOnly) { this->m_readOnly = readOnly; } + private: std::vector m_data; + bool m_readOnly = false; }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_data_inspector.hpp b/plugins/builtin/include/content/views/view_data_inspector.hpp index 44495be76..4766a2b5d 100644 --- a/plugins/builtin/include/content/views/view_data_inspector.hpp +++ b/plugins/builtin/include/content/views/view_data_inspector.hpp @@ -33,6 +33,7 @@ namespace hex::plugin::builtin { u64 m_startAddress = 0; size_t m_validBytes = 0; + prv::Provider *m_selectedProvider = nullptr; std::atomic m_dataValid = false; std::vector m_cachedData, m_workData; TaskHolder m_updateTask; diff --git a/plugins/builtin/include/content/views/view_hex_editor.hpp b/plugins/builtin/include/content/views/view_hex_editor.hpp index c7d34e4b4..a43e537eb 100644 --- a/plugins/builtin/include/content/views/view_hex_editor.hpp +++ b/plugins/builtin/include/content/views/view_hex_editor.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace hex::plugin::builtin { @@ -70,7 +70,7 @@ namespace hex::plugin::builtin { void registerEvents(); void registerMenuItems(); - HexEditor m_hexEditor; + ui::HexEditor m_hexEditor; bool m_shouldOpenPopup = false; std::unique_ptr m_currPopup; diff --git a/plugins/builtin/include/content/views/view_pattern_data.hpp b/plugins/builtin/include/content/views/view_pattern_data.hpp index 2f4491715..f6fa07986 100644 --- a/plugins/builtin/include/content/views/view_pattern_data.hpp +++ b/plugins/builtin/include/content/views/view_pattern_data.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -20,7 +20,7 @@ namespace hex::plugin::builtin { private: std::map> m_sortedPatterns; - hex::PatternDrawer m_patternDrawer; + ui::PatternDrawer m_patternDrawer; }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 5add04995..ad187128c 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include @@ -63,9 +65,7 @@ namespace hex::plugin::builtin { bool m_syncPatternSourceCode = false; bool m_autoLoadPatterns = true; - std::unique_ptr m_sectionProvider = nullptr; - HexEditor m_hexEditor; - + std::map> m_sectionWindowDrawer; private: void drawConsole(ImVec2 size, const std::vector> &console); void drawEnvVars(ImVec2 size, std::list &envVars); diff --git a/plugins/builtin/include/content/helpers/hex_editor.hpp b/plugins/builtin/include/ui/hex_editor.hpp similarity index 89% rename from plugins/builtin/include/content/helpers/hex_editor.hpp rename to plugins/builtin/include/ui/hex_editor.hpp index 0fba7d0f5..9b2e2130a 100644 --- a/plugins/builtin/include/content/helpers/hex_editor.hpp +++ b/plugins/builtin/include/ui/hex_editor.hpp @@ -17,21 +17,22 @@ #include #include -namespace hex { +namespace hex::plugin::builtin::ui { class HexEditor { public: - HexEditor(); + explicit HexEditor(prv::Provider *provider = nullptr); ~HexEditor(); - void draw(prv::Provider *provider, float height = ImGui::GetContentRegionAvail().y); + void draw(float height = ImGui::GetContentRegionAvail().y); + void setProvider(prv::Provider *provider) { this->m_provider = provider; } private: enum class CellType { None, Hex, ASCII }; - void drawCell(prv::Provider *provider, u64 address, u8 *data, size_t size, bool hovered, CellType cellType); + void drawCell(u64 address, u8 *data, size_t size, bool hovered, CellType cellType); void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize) const; - void drawEditor(prv::Provider *provider, const ImVec2 &size); - void drawFooter(prv::Provider *provider, const ImVec2 &size); + void drawEditor(const ImVec2 &size); + void drawFooter(const ImVec2 &size); void drawTooltip(u64 address, const u8 *data, size_t size); void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered); @@ -47,9 +48,7 @@ namespace hex { if (!ImHexApi::Provider::isValid()) return; - auto provider = ImHexApi::Provider::get(); - - const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1; + const size_t maxAddress = this->m_provider->getActualSize() + this->m_provider->getBaseAddress() - 1; this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end; @@ -57,7 +56,8 @@ namespace hex { this->m_selectionEnd = std::clamp(end, 0, maxAddress); if (this->m_selectionChanged) { - EventManager::post(this->getSelection()); + auto selection = this->getSelection(); + EventManager::post(ImHexApi::HexEditor::ProviderRegion{ { selection.address, selection.size }, this->m_provider }); this->m_shouldModifyValue = true; } } @@ -161,6 +161,8 @@ namespace hex { } private: + prv::Provider *m_provider; + std::optional m_selectionStart; std::optional m_selectionEnd; float m_scrollPosition = 0; diff --git a/plugins/builtin/include/content/helpers/pattern_drawer.hpp b/plugins/builtin/include/ui/pattern_drawer.hpp similarity index 88% rename from plugins/builtin/include/content/helpers/pattern_drawer.hpp rename to plugins/builtin/include/ui/pattern_drawer.hpp index a3ae5a1a5..c428d4f82 100644 --- a/plugins/builtin/include/content/helpers/pattern_drawer.hpp +++ b/plugins/builtin/include/ui/pattern_drawer.hpp @@ -4,14 +4,18 @@ #include #include -namespace hex { +namespace hex::plugin::builtin::ui { class PatternDrawer : public pl::PatternVisitor { public: PatternDrawer() = default; + void draw(const std::vector> &patterns, float height = 0.0F); + + private: void draw(pl::ptrn::Pattern& pattern); + public: void visit(pl::ptrn::PatternArrayDynamic& pattern) override; void visit(pl::ptrn::PatternArrayStatic& pattern) override; void visit(pl::ptrn::PatternBitfieldField& pattern) override; @@ -39,5 +43,6 @@ namespace hex { private: std::map m_displayEnd; + std::vector m_sortedPatterns; }; } \ No newline at end of file diff --git a/plugins/builtin/include/ui/widgets.hpp b/plugins/builtin/include/ui/widgets.hpp index dedf00c42..7fdf77c96 100644 --- a/plugins/builtin/include/ui/widgets.hpp +++ b/plugins/builtin/include/ui/widgets.hpp @@ -3,6 +3,9 @@ #include #include +namespace pl::ptrn { class Pattern; } +namespace hex::prv { class Provider; } + namespace hex::plugin::builtin::ui { diff --git a/plugins/builtin/source/content/data_processor_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes.cpp index 5b3e95779..277ecd087 100644 --- a/plugins/builtin/source/content/data_processor_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes.cpp @@ -466,7 +466,7 @@ namespace hex::plugin::builtin { class NodeDataSelection : public dp::Node { public: NodeDataSelection() : Node("hex.builtin.nodes.data_access.selection.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.size") }) { - EventManager::subscribe(this, [this](const Region ®ion) { + EventManager::subscribe(this, [this](const auto ®ion) { this->m_address = region.address; this->m_size = region.size; }); diff --git a/plugins/builtin/source/content/views/view_data_inspector.cpp b/plugins/builtin/source/content/views/view_data_inspector.cpp index 3c25ed6bb..608227125 100644 --- a/plugins/builtin/source/content/views/view_data_inspector.cpp +++ b/plugins/builtin/source/content/views/view_data_inspector.cpp @@ -18,22 +18,26 @@ namespace hex::plugin::builtin { using NumberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle; ViewDataInspector::ViewDataInspector() : View("hex.builtin.view.data_inspector.name") { - EventManager::subscribe(this, [this](Region region) { + EventManager::subscribe(this, [this](const auto ®ion) { if (!ImHexApi::Provider::isValid() || region == Region::Invalid()) { this->m_validBytes = 0; } else { - auto provider = ImHexApi::Provider::get(); - - this->m_validBytes = u64(provider->getActualSize() - region.address); + this->m_validBytes = u64(region.getProvider()->getActualSize() - region.address); this->m_startAddress = region.address; + this->m_selectedProvider = region.getProvider(); } this->m_shouldInvalidate = true; }); + + EventManager::subscribe(this, [this](const auto*) { + this->m_selectedProvider = nullptr; + }); } ViewDataInspector::~ViewDataInspector() { EventManager::unsubscribe(this); + EventManager::unsubscribe(this); } void ViewDataInspector::drawContent() { @@ -47,17 +51,18 @@ namespace hex::plugin::builtin { this->m_updateTask = TaskManager::createBackgroundTask("Update Inspector", [this, validBytes = this->m_validBytes, startAddress = this->m_startAddress, endian = this->m_endian, invert = this->m_invert, numberDisplayStyle = this->m_numberDisplayStyle](auto &) { - auto provider = ImHexApi::Provider::get(); - this->m_workData.clear(); + if (this->m_selectedProvider == nullptr) + return; + // Decode bytes using registered inspectors for (auto &entry : ContentRegistry::DataInspector::getEntries()) { if (validBytes < entry.requiredSize) continue; std::vector buffer(validBytes > entry.maxSize ? entry.maxSize : validBytes); - provider->read(startAddress, buffer.data(), buffer.size()); + this->m_selectedProvider->read(startAddress, buffer.data(), buffer.size()); if (invert) { for (auto &byte : buffer) @@ -81,14 +86,14 @@ namespace hex::plugin::builtin { pl::PatternLanguage runtime; ContentRegistry::PatternLanguage::configureRuntime(runtime, nullptr); - runtime.setDataSource([invert, provider](u64 offset, u8 *buffer, size_t size) { - provider->read(offset, buffer, size); + runtime.setDataSource([this, invert](u64 offset, u8 *buffer, size_t size) { + this->m_selectedProvider->read(offset, buffer, size); if (invert) { for (size_t i = 0; i < size; i++) buffer[i] ^= 0xFF; } - }, provider->getBaseAddress(), provider->getActualSize()); + }, this->m_selectedProvider->getBaseAddress(), this->m_selectedProvider->getActualSize()); runtime.setDangerousFunctionCallHandler([]{ return false; }); runtime.setDefaultEndian(endian); @@ -139,9 +144,7 @@ namespace hex::plugin::builtin { } if (ImGui::Begin(View::toWindowName("hex.builtin.view.data_inspector.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { - auto provider = ImHexApi::Provider::get(); - - if (ImHexApi::Provider::isValid() && provider->isReadable() && this->m_validBytes > 0) { + if (this->m_selectedProvider != nullptr && this->m_selectedProvider->isReadable() && this->m_validBytes > 0) { if (ImGui::BeginTable("##datainspector", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg, ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * (this->m_cachedData.size() + 1)))) { ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupColumn("hex.builtin.view.data_inspector.table.name"_lang); @@ -177,7 +180,7 @@ namespace hex::plugin::builtin { if (ImGui::InputText("##InspectorLineEditing", this->m_editingValue, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) { auto bytes = (*editingFunction)(this->m_editingValue, this->m_endian); - provider->write(this->m_startAddress, bytes.data(), bytes.size()); + this->m_selectedProvider->write(this->m_startAddress, bytes.data(), bytes.size()); this->m_editingValue.clear(); editing = false; this->m_shouldInvalidate = true; diff --git a/plugins/builtin/source/content/views/view_find.cpp b/plugins/builtin/source/content/views/view_find.cpp index f899a09ff..da283e580 100644 --- a/plugins/builtin/source/content/views/view_find.cpp +++ b/plugins/builtin/source/content/views/view_find.cpp @@ -443,7 +443,7 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); return Region { provider->getBaseAddress(), provider->getActualSize() }; } else { - return ImHexApi::HexEditor::getSelection().value(); + return ImHexApi::HexEditor::getSelection()->getRegion(); } }(); diff --git a/plugins/builtin/source/content/views/view_hashes.cpp b/plugins/builtin/source/content/views/view_hashes.cpp index 890a11ee6..2bb7435ee 100644 --- a/plugins/builtin/source/content/views/view_hashes.cpp +++ b/plugins/builtin/source/content/views/view_hashes.cpp @@ -7,7 +7,7 @@ namespace hex::plugin::builtin { ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") { - EventManager::subscribe(this, [this](const Region &) { + EventManager::subscribe(this, [this](const auto &) { for (auto &function : this->m_hashFunctions) function.reset(); }); diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index bcb07102c..0f9855fc3 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -584,7 +584,10 @@ namespace hex::plugin::builtin { void ViewHexEditor::drawContent() { if (ImGui::Begin(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { - this->m_hexEditor.draw(ImHexApi::Provider::get()); + this->m_hexEditor.setProvider(ImHexApi::Provider::get()); + + this->m_hexEditor.draw(); + this->drawPopup(); } ImGui::End(); @@ -686,11 +689,13 @@ namespace hex::plugin::builtin { // Remove selection ShortcutManager::addShortcut(this, Keys::Escape, [this] { - auto &data = ProviderExtraData::getCurrent().editor; + auto provider = ImHexApi::Provider::get(); + auto &data = ProviderExtraData::get(provider).editor; data.selectionStart.reset(); data.selectionEnd.reset(); - EventManager::post(this->getSelection()); + + EventManager::post(ImHexApi::HexEditor::ProviderRegion{ this->getSelection(), provider }); }); // Move cursor around @@ -873,11 +878,6 @@ namespace hex::plugin::builtin { } }); - EventManager::subscribe(this, [this](auto ®ion) { - if (isSelectionValid()) - region = getSelection(); - }); - EventManager::subscribe(this, [this](auto *oldProvider, auto *newProvider) { if (oldProvider != nullptr) { auto &oldData = ProviderExtraData::get(oldProvider).editor; @@ -897,8 +897,9 @@ namespace hex::plugin::builtin { } this->m_hexEditor.forceUpdateScrollPosition(); - if (isSelectionValid()) - EventManager::post(getSelection()); + if (isSelectionValid()) { + EventManager::post(ImHexApi::HexEditor::ProviderRegion{ this->getSelection(), newProvider }); + } }); } diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index 251269c61..01bd27836 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -25,89 +25,6 @@ namespace hex::plugin::builtin { EventManager::unsubscribe(this); } - static bool sortPatterns(prv::Provider *provider, const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) { - if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getDisplayName() > right->getDisplayName(); - else - return left->getDisplayName() < right->getDisplayName(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getOffset() > right->getOffset(); - else - return left->getOffset() < right->getOffset(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getSize() > right->getSize(); - else - return left->getSize() < right->getSize(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) { - size_t biggerSize = std::max(left->getSize(), right->getSize()); - std::vector leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00); - - provider->read(left->getOffset(), leftBuffer.data(), left->getSize()); - provider->read(right->getOffset(), rightBuffer.data(), right->getSize()); - - if (left->getEndian() != std::endian::native) - std::reverse(leftBuffer.begin(), leftBuffer.end()); - if (right->getEndian() != std::endian::native) - std::reverse(rightBuffer.begin(), rightBuffer.end()); - - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return leftBuffer > rightBuffer; - else - return leftBuffer < rightBuffer; - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getTypeName() > right->getTypeName(); - else - return left->getTypeName() < right->getTypeName(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getColor() > right->getColor(); - else - return left->getColor() < right->getColor(); - } - - return false; - } - - static bool beginPatternTable(prv::Provider *&provider, const std::vector> &patterns, std::vector &sortedPatterns) { - if (ImGui::BeginTable("##Patterntable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) { - ImGui::TableSetupScrollFreeze(0, 1); - ImGui::TableSetupColumn("hex.builtin.view.pattern_data.var_name"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("name")); - ImGui::TableSetupColumn("hex.builtin.view.pattern_data.color"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("color")); - ImGui::TableSetupColumn("hex.builtin.view.pattern_data.offset"_lang, ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort, 0, ImGui::GetID("offset")); - ImGui::TableSetupColumn("hex.builtin.view.pattern_data.size"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("size")); - ImGui::TableSetupColumn("hex.builtin.view.pattern_data.type"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("type")); - ImGui::TableSetupColumn("hex.builtin.view.pattern_data.value"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("value")); - - auto sortSpecs = ImGui::TableGetSortSpecs(); - - if (!patterns.empty() && (sortSpecs->SpecsDirty || sortedPatterns.empty())) { - sortedPatterns.clear(); - std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr &pattern) { - return pattern.get(); - }); - - std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs, &provider](pl::ptrn::Pattern *left, pl::ptrn::Pattern *right) -> bool { - return sortPatterns(provider, sortSpecs, left, right); - }); - - for (auto &pattern : sortedPatterns) - pattern->sort([&sortSpecs, &provider](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){ - return sortPatterns(provider, sortSpecs, left, right); - }); - - sortSpecs->SpecsDirty = false; - } - - return true; - } - - return false; - } - void ViewPatternData::drawContent() { if (ImGui::Begin(View::toWindowName("hex.builtin.view.pattern_data.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { if (ImHexApi::Provider::isValid()) { @@ -123,18 +40,7 @@ namespace hex::plugin::builtin { } }(); - auto &sortedPatterns = this->m_sortedPatterns[ImHexApi::Provider::get()]; - if (beginPatternTable(provider, patterns, sortedPatterns)) { - ImGui::TableHeadersRow(); - - if (!sortedPatterns.empty()) { - for (auto &pattern : sortedPatterns) { - this->m_patternDrawer.draw(*pattern); - } - } - - ImGui::EndTable(); - } + this->m_patternDrawer.draw(patterns); } } ImGui::End(); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index aeb457666..30e6e9d2e 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -114,7 +114,7 @@ namespace hex::plugin::builtin { this->m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, true); auto settingsSize = ImGui::GetContentRegionAvail(); - settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5; + settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5F; if (ImGui::BeginTabBar("##settings")) { if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) { @@ -438,8 +438,8 @@ namespace hex::plugin::builtin { void ViewPatternEditor::drawSectionSelector(ImVec2 size, std::map §ions) { if (ImGui::BeginTable("##sections_table", 3, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, size)) { ImGui::TableSetupScrollFreeze(0, 1); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.5F); - ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthStretch, 0.5F); + ImGui::TableSetupColumn("hex.builtin.common.name"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F); + ImGui::TableSetupColumn("hex.builtin.common.size"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F); ImGui::TableSetupColumn("##button", ImGuiTableColumnFlags_WidthFixed, 20_scaled); ImGui::TableHeadersRow(); @@ -455,11 +455,13 @@ namespace hex::plugin::builtin { ImGui::TextFormatted("{} | 0x{:02X}", hex::toByteString(section.data.size()), section.data.size()); ImGui::TableNextColumn(); if (ImGui::IconButton(ICON_VS_OPEN_PREVIEW, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { - this->m_sectionProvider = std::make_unique(); - this->m_sectionProvider->resize(section.data.size()); - this->m_sectionProvider->writeRaw(0, section.data.data(), section.data.size()); + auto dataProvider = std::make_unique(); + dataProvider->resize(section.data.size()); + dataProvider->writeRaw(0x00, section.data.data(), section.data.size()); + dataProvider->setReadOnly(true); - this->m_hexEditor.setBackgroundHighlightCallback([this, id](u64 address, const u8 *, size_t) -> std::optional { + auto hexEditor = ui::HexEditor(); + hexEditor.setBackgroundHighlightCallback([this, id](u64 address, const u8 *, size_t) -> std::optional { if (this->m_runningEvaluators != 0) return std::nullopt; if (!ImHexApi::Provider::isValid()) @@ -478,6 +480,15 @@ namespace hex::plugin::builtin { return color; }); + + auto patternProvider = ImHexApi::Provider::get(); + + this->m_sectionWindowDrawer[patternProvider] = [id, patternProvider, dataProvider = std::move(dataProvider), hexEditor, patternDrawer = ui::PatternDrawer()] mutable { + hexEditor.setProvider(dataProvider.get()); + hexEditor.draw(480_scaled); + + patternDrawer.draw(ProviderExtraData::get(patternProvider).patternLanguage.runtime->getAllPatterns(id), 150_scaled); + }; } ImGui::PopID(); @@ -527,17 +538,17 @@ namespace hex::plugin::builtin { ImGui::EndPopup(); } - auto open = this->m_sectionProvider != nullptr && this->m_sectionProvider->isReadable(); + auto open = this->m_sectionWindowDrawer.contains(provider); if (open) { ImGui::SetNextWindowSize(scaled(ImVec2(500, 650)), ImGuiCond_Appearing); - if (ImGui::Begin("hex.builtin.view.pattern_editor.section_popup"_lang, &open)) { - this->m_hexEditor.draw(this->m_sectionProvider.get()); + if (ImGui::Begin("hex.builtin.view.pattern_editor.section_popup"_lang, &open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { + this->m_sectionWindowDrawer[provider](); } ImGui::End(); } if (!open) - this->m_sectionProvider = nullptr; + this->m_sectionWindowDrawer.erase(provider); } diff --git a/plugins/builtin/source/content/helpers/hex_editor.cpp b/plugins/builtin/source/ui/hex_editor.cpp similarity index 90% rename from plugins/builtin/source/content/helpers/hex_editor.cpp rename to plugins/builtin/source/ui/hex_editor.cpp index 7461fdf96..00229de7f 100644 --- a/plugins/builtin/source/content/helpers/hex_editor.cpp +++ b/plugins/builtin/source/ui/hex_editor.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -7,7 +7,7 @@ #include #include -namespace hex { +namespace hex::plugin::builtin::ui { /* Data Visualizer */ @@ -70,7 +70,7 @@ namespace hex { /* Hex Editor */ - HexEditor::HexEditor() { + HexEditor::HexEditor(prv::Provider *provider) : m_provider(provider) { this->m_currDataVisualizer = ContentRegistry::HexEditor::impl::getVisualizers()["hex.builtin.visualizer.hexadecimal.8bit"]; this->m_grayZeroHighlighter = ImHexApi::HexEditor::addForegroundHighlightingProvider([this](u64 address, const u8 *data, size_t size, bool hasColor) -> std::optional { @@ -237,7 +237,7 @@ namespace hex { ImGui::PopStyleVar(); } - void HexEditor::drawCell(prv::Provider *provider, u64 address, u8 *data, size_t size, bool hovered, CellType cellType) { + void HexEditor::drawCell(u64 address, u8 *data, size_t size, bool hovered, CellType cellType) { static DataVisualizerAscii asciiVisualizer; if (this->m_shouldUpdateEditingValue) { @@ -253,7 +253,7 @@ namespace hex { else asciiVisualizer.draw(address, data, size, this->m_upperCaseHex); - if (hovered && provider->isWritable()) { + if (hovered && this->m_provider->isWritable()) { // Enter editing mode when double-clicking a cell if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { this->m_editingAddress = address; @@ -278,13 +278,13 @@ namespace hex { if (shouldExitEditingMode || this->m_shouldModifyValue) { - provider->write(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size()); + this->m_provider->write(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size()); if (!this->m_selectionChanged && !ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { auto nextEditingAddress = *this->m_editingAddress + this->m_currDataVisualizer->getBytesPerCell(); this->setSelection(nextEditingAddress, nextEditingAddress); - if (nextEditingAddress >= provider->getSize()) + if (nextEditingAddress >= this->m_provider->getSize()) this->m_editingAddress = std::nullopt; else this->m_editingAddress = nextEditingAddress; @@ -334,7 +334,7 @@ namespace hex { drawList->AddLine(cellPos + ImVec2(0, cellSize.y), cellPos + cellSize + ImVec2(1, 0), ImColor(SelectionFrameColor), 1.0F); } - void HexEditor::drawEditor(prv::Provider *provider, const ImVec2 &size) { + void HexEditor::drawEditor(const ImVec2 &size) { const float SeparatorColumWidth = 6_scaled; const auto CharacterSize = ImGui::CalcTextSize("0"); @@ -377,13 +377,13 @@ namespace hex { ImGui::TableNextRow(); ImGui::TableNextColumn(); - if (provider != nullptr && provider->isReadable()) { + if (this->m_provider != nullptr && this->m_provider->isReadable()) { std::pair validRegion = { Region::Invalid(), false }; - const auto isCurrRegionValid = [&validRegion, &provider](u64 address){ + const auto isCurrRegionValid = [this, &validRegion](u64 address){ auto &[currRegion, currRegionValid] = validRegion; if (!Region{ address, 1 }.isWithin(currRegion)) { - validRegion = provider->getRegionValidity(address); + validRegion = this->m_provider->getRegionValidity(address); } return currRegionValid; @@ -391,7 +391,7 @@ namespace hex { ImGuiListClipper clipper; - clipper.Begin(std::ceil(provider->getSize() / (long double)(this->m_bytesPerRow)), CharacterSize.y); + clipper.Begin(std::ceil(this->m_provider->getSize() / (long double)(this->m_bytesPerRow)), CharacterSize.y); while (clipper.Step()) { this->m_visibleRowCount = clipper.DisplayEnd - clipper.DisplayStart; @@ -401,18 +401,18 @@ namespace hex { // Draw address column ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::TextFormatted(this->m_upperCaseHex ? "{:08X}: " : "{:08x}: ", y * this->m_bytesPerRow + provider->getBaseAddress() + provider->getCurrentPageAddress()); + ImGui::TextFormatted(this->m_upperCaseHex ? "{:08X}: " : "{:08x}: ", y * this->m_bytesPerRow + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress()); ImGui::TableNextColumn(); - const u8 validBytes = std::min(this->m_bytesPerRow, provider->getSize() - y * this->m_bytesPerRow); + const u8 validBytes = std::min(this->m_bytesPerRow, this->m_provider->getSize() - y * this->m_bytesPerRow); std::vector bytes(this->m_bytesPerRow, 0x00); - provider->read(y * this->m_bytesPerRow + provider->getBaseAddress() + provider->getCurrentPageAddress(), bytes.data(), validBytes); + this->m_provider->read(y * this->m_bytesPerRow + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress(), bytes.data(), validBytes); std::vector, std::optional>> cellColors; { for (u64 x = 0; x < std::ceil(float(validBytes) / bytesPerCell); x++) { - const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + provider->getBaseAddress() + provider->getCurrentPageAddress(); + const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress(); const auto cellBytes = std::min(validBytes, bytesPerCell); @@ -438,7 +438,7 @@ namespace hex { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(3, 0)); for (u64 x = 0; x < columnCount; x++) { - const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + provider->getBaseAddress() + provider->getCurrentPageAddress(); + const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress(); ImGui::TableNextColumn(); if (isColumnSeparatorColumn(x, columnCount)) @@ -486,7 +486,7 @@ namespace hex { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::PushItemWidth((CharacterSize * maxCharsPerCell).x); if (isCurrRegionValid(byteAddress)) - this->drawCell(provider, byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex); + this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex); else ImGui::TextFormatted("{}", std::string(maxCharsPerCell, '?')); ImGui::PopItemWidth(); @@ -513,7 +513,7 @@ namespace hex { for (u64 x = 0; x < this->m_bytesPerRow; x++) { ImGui::TableNextColumn(); - const u64 byteAddress = y * this->m_bytesPerRow + x + provider->getBaseAddress() + provider->getCurrentPageAddress(); + const u64 byteAddress = y * this->m_bytesPerRow + x + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress(); const auto cellStartPos = getCellPosition(); const auto cellSize = CharacterSize + ImVec2(this->m_characterCellPadding, 0); @@ -543,7 +543,7 @@ namespace hex { if (!isCurrRegionValid(byteAddress)) ImGui::TextFormatted("?"); else - this->drawCell(provider, byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII); + this->drawCell(byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII); ImGui::PopItemWidth(); ImGui::PopStyleVar(); } @@ -562,9 +562,9 @@ namespace hex { std::vector> encodingData; u32 offset = 0; do { - const u64 address = y * this->m_bytesPerRow + offset + provider->getBaseAddress() + provider->getCurrentPageAddress(); + const u64 address = y * this->m_bytesPerRow + offset + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress(); - auto result = queryCustomEncodingData(provider, *this->m_currCustomEncoding, address); + auto result = queryCustomEncodingData(this->m_provider, *this->m_currCustomEncoding, address); offset += std::max(1, result.advance); encodingData.emplace_back(address, result); @@ -621,13 +621,13 @@ namespace hex { auto fractionPerLine = 1.0 / (this->m_visibleRowCount + 1); if (y == (u64(clipper.DisplayStart) + 3)) { - if (i128(this->m_selectionEnd.value() - provider->getBaseAddress() - provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 3) * this->m_bytesPerRow)) { + if (i128(this->m_selectionEnd.value() - this->m_provider->getBaseAddress() - this->m_provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 3) * this->m_bytesPerRow)) { this->m_shouldScrollToSelection = false; ImGui::SetScrollHereY(fractionPerLine * 5); } } else if (y == (u64(clipper.DisplayEnd) - 1)) { - if (i128(this->m_selectionEnd.value() - provider->getBaseAddress() - provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) { + if (i128(this->m_selectionEnd.value() - this->m_provider->getBaseAddress() - this->m_provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) { this->m_shouldScrollToSelection = false; ImGui::SetScrollHereY(fractionPerLine * (this->m_visibleRowCount)); } @@ -638,7 +638,7 @@ namespace hex { if (this->m_shouldJumpWhenOffScreen) { this->m_shouldJumpWhenOffScreen = false; - const auto pageAddress = provider->getCurrentPageAddress() + provider->getBaseAddress(); + const auto pageAddress = this->m_provider->getCurrentPageAddress() + this->m_provider->getBaseAddress(); auto newSelection = getSelection(); newSelection.address -= pageAddress; @@ -657,9 +657,9 @@ namespace hex { this->m_shouldJumpToSelection = false; auto newSelection = getSelection(); - provider->setCurrentPage(provider->getPageOfAddress(newSelection.address).value_or(0)); + this->m_provider->setCurrentPage(this->m_provider->getPageOfAddress(newSelection.address).value_or(0)); - const auto pageAddress = provider->getCurrentPageAddress() + provider->getBaseAddress(); + const auto pageAddress = this->m_provider->getCurrentPageAddress() + this->m_provider->getBaseAddress(); auto scrollPos = (static_cast(newSelection.getStartAddress() - pageAddress) / this->m_bytesPerRow) * CharacterSize.y; bool scrollUpwards = scrollPos < ImGui::GetScrollY(); auto scrollFraction = scrollUpwards ? 0.0F : (1.0F - ((1.0F / this->m_visibleRowCount) * 2)); @@ -693,12 +693,12 @@ namespace hex { this->m_enteredEditingMode = false; } - void HexEditor::drawFooter(prv::Provider *provider, const ImVec2 &size) { - if (provider != nullptr && provider->isReadable()) { - const auto pageCount = provider->getPageCount(); + void HexEditor::drawFooter(const ImVec2 &size) { + if (this->m_provider != nullptr && this->m_provider->isReadable()) { + const auto pageCount = this->m_provider->getPageCount(); constexpr static u32 MinPage = 1; - const auto windowEndPos = ImGui::GetWindowPos() + ImGui::GetWindowSize() - ImGui::GetStyle().WindowPadding; + const auto windowEndPos = ImGui::GetWindowPos() + size - ImGui::GetStyle().WindowPadding; ImGui::GetWindowDrawList()->AddLine(windowEndPos - ImVec2(0, size.y - 1_scaled), windowEndPos - size + ImVec2(0, 1_scaled), ImGui::GetColorU32(ImGuiCol_Separator), 2.0_scaled); if (ImGui::BeginChild("##footer", size, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { @@ -708,7 +708,7 @@ namespace hex { // Page slider ImGui::TableNextColumn(); { - u32 page = provider->getCurrentPage() + 1; + u32 page = this->m_provider->getCurrentPage() + 1; ImGui::TextFormatted("{}: ", "hex.builtin.view.hex_editor.page"_lang); ImGui::SameLine(); @@ -716,7 +716,7 @@ namespace hex { ImGui::BeginDisabled(pageCount <= 1); { if (ImGui::SliderScalar("##page_selection", ImGuiDataType_U32, &page, &MinPage, &pageCount, hex::format("%d / {}", pageCount).c_str())) - provider->setCurrentPage(page - 1); + this->m_provider->setCurrentPage(page - 1); } ImGui::EndDisabled(); } @@ -724,7 +724,7 @@ namespace hex { // Page Address ImGui::TableNextColumn(); { - ImGui::TextFormatted("{0}: 0x{1:08X} - 0x{2:08X} ({1} - {2})", "hex.builtin.view.hex_editor.region"_lang, provider->getCurrentPageAddress(), provider->getSize()); + ImGui::TextFormatted("{0}: 0x{1:08X} - 0x{2:08X} ({1} - {2})", "hex.builtin.view.hex_editor.region"_lang, this->m_provider->getCurrentPageAddress(), this->m_provider->getSize()); } ImGui::TableNextRow(); @@ -752,9 +752,9 @@ namespace hex { ImGui::TableNextColumn(); { ImGui::TextFormatted("{0}: 0x{1:08X} (0x{2:X} | {3})", "hex.builtin.view.hex_editor.data_size"_lang, - provider->getActualSize(), - provider->getActualSize(), - hex::toByteString(provider->getActualSize()) + this->m_provider->getActualSize(), + this->m_provider->getActualSize(), + hex::toByteString(this->m_provider->getActualSize()) ); } @@ -788,14 +788,14 @@ namespace hex { } } - void HexEditor::draw(prv::Provider *provider, float height) { + void HexEditor::draw(float height) { const auto width = ImGui::GetContentRegionAvail().x; const auto FooterSize = ImVec2(width, ImGui::GetTextLineHeightWithSpacing() * 2.3F); const auto TableSize = ImVec2(width, height - FooterSize.y); - this->drawEditor(provider, TableSize); - this->drawFooter(provider, FooterSize); + this->drawEditor(TableSize); + this->drawFooter(FooterSize); this->m_selectionChanged = false; } diff --git a/plugins/builtin/source/content/helpers/pattern_drawer.cpp b/plugins/builtin/source/ui/pattern_drawer.cpp similarity index 77% rename from plugins/builtin/source/content/helpers/pattern_drawer.cpp rename to plugins/builtin/source/ui/pattern_drawer.cpp index 107307fc3..71ede8422 100644 --- a/plugins/builtin/source/content/helpers/pattern_drawer.cpp +++ b/plugins/builtin/source/ui/pattern_drawer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -21,11 +21,12 @@ #include #include +#include #include #include -namespace hex { +namespace hex::plugin::builtin::ui { namespace { @@ -414,7 +415,7 @@ namespace hex { auto &displayEnd = this->getDisplayEnd(pattern); if (chunkCount > displayEnd) { - ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns); + ImGui::Selectable(hex::format("... ({})", "hex.builtin.pattern_drawer.double_click"_lang).c_str(), false, ImGuiSelectableFlags_SpanAllColumns); if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) displayEnd += DisplayEndStep; break; @@ -470,4 +471,88 @@ namespace hex { auto [value, success] = this->m_displayEnd.emplace(&pattern, DisplayEndDefault); return value->second; } + + static bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) { + if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getDisplayName() > right->getDisplayName(); + else + return left->getDisplayName() < right->getDisplayName(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getOffset() > right->getOffset(); + else + return left->getOffset() < right->getOffset(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getSize() > right->getSize(); + else + return left->getSize() < right->getSize(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getValue() > right->getValue(); + else + return left->getValue() < right->getValue(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getTypeName() > right->getTypeName(); + else + return left->getTypeName() < right->getTypeName(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getColor() > right->getColor(); + else + return left->getColor() < right->getColor(); + } + + return false; + } + + static bool beginPatternTable(const std::vector> &patterns, std::vector &sortedPatterns, float height) { + if (ImGui::BeginTable("##Patterntable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, height))) { + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableSetupColumn("hex.builtin.pattern_drawer.var_name"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("name")); + ImGui::TableSetupColumn("hex.builtin.pattern_drawer.color"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("color")); + ImGui::TableSetupColumn("hex.builtin.pattern_drawer.offset"_lang, ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort, 0, ImGui::GetID("offset")); + ImGui::TableSetupColumn("hex.builtin.pattern_drawer.size"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("size")); + ImGui::TableSetupColumn("hex.builtin.pattern_drawer.type"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("type")); + ImGui::TableSetupColumn("hex.builtin.pattern_drawer.value"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("value")); + + auto sortSpecs = ImGui::TableGetSortSpecs(); + + if (!patterns.empty() && (sortSpecs->SpecsDirty || sortedPatterns.empty())) { + sortedPatterns.clear(); + std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr &pattern) { + return pattern.get(); + }); + + std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs](pl::ptrn::Pattern *left, pl::ptrn::Pattern *right) -> bool { + return sortPatterns(sortSpecs, left, right); + }); + + for (auto &pattern : sortedPatterns) + pattern->sort([&sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){ + return sortPatterns(sortSpecs, left, right); + }); + + sortSpecs->SpecsDirty = false; + } + + return true; + } + + return false; + } + + void PatternDrawer::draw(const std::vector> &patterns, float height) { + if (beginPatternTable(patterns, this->m_sortedPatterns, height)) { + ImGui::TableHeadersRow(); + + for (auto &pattern : this->m_sortedPatterns) { + this->draw(*pattern); + } + + ImGui::EndTable(); + } + } }