diff --git a/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h b/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h index 7a7b05090..bddd7e9df 100644 --- a/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h +++ b/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h @@ -48,7 +48,7 @@ namespace ImGui { return this->m_textureId != nullptr; } - [[nodiscard]] constexpr operator ImTextureID() { + [[nodiscard]] constexpr operator ImTextureID() const noexcept { return this->m_textureId; } diff --git a/lib/libimhex/include/hex/ui/widgets.hpp b/lib/libimhex/include/hex/ui/widgets.hpp new file mode 100644 index 000000000..43f326316 --- /dev/null +++ b/lib/libimhex/include/hex/ui/widgets.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace hex::ui { + + template + class SearchableWidget { + public: + SearchableWidget(const std::function &comparator) : m_comparator(comparator) { + + } + + const std::vector &draw(const auto &entries) { + if (this->m_filteredEntries.empty() && this->m_searchBuffer.empty()) { + for (auto &entry : entries) + this->m_filteredEntries.push_back(&entry); + } + + if (ImGui::InputText("##search", this->m_searchBuffer)) { + this->m_pendingUpdate = true; + } + + if (this->m_pendingUpdate && !this->m_updateTask.isRunning()) { + this->m_pendingUpdate = false; + this->m_filteredEntries.clear(); + this->m_filteredEntries.reserve(entries.size()); + + this->m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = this->m_searchBuffer](Task&) { + for (auto &entry : entries) { + if (searchBuffer.empty() || this->m_comparator(searchBuffer, entry)) + this->m_filteredEntries.push_back(&entry); + } + }); + + } + + return this->m_filteredEntries; + } + + void reset() { + this->m_filteredEntries.clear(); + } + private: + std::atomic m_pendingUpdate = false; + TaskHolder m_updateTask; + + std::string m_searchBuffer; + std::vector m_filteredEntries; + std::function m_comparator; + }; + +} \ No newline at end of file diff --git a/plugins/windows/include/content/providers/process_memory_provider.hpp b/plugins/windows/include/content/providers/process_memory_provider.hpp index bb09a035c..1b9cc90ce 100644 --- a/plugins/windows/include/content/providers/process_memory_provider.hpp +++ b/plugins/windows/include/content/providers/process_memory_provider.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -81,9 +82,15 @@ namespace hex::plugin::windows { }; std::vector m_processes; - Process *m_selectedProcess = nullptr; + const Process *m_selectedProcess = nullptr; std::set m_memoryRegions; + ui::SearchableWidget m_processSearchWidget = ui::SearchableWidget([](const std::string &search, const Process &process) { + return process.name.contains(search); + }); + ui::SearchableWidget m_regionSearchWidget = ui::SearchableWidget([](const std::string &search, const MemoryRegion &memoryRegion) { + return memoryRegion.name.contains(search); + }); HANDLE m_processHandle = nullptr; diff --git a/plugins/windows/source/content/providers/process_memory_provider.cpp b/plugins/windows/source/content/providers/process_memory_provider.cpp index 865e93782..0ea04ab10 100644 --- a/plugins/windows/source/content/providers/process_memory_provider.cpp +++ b/plugins/windows/source/content/providers/process_memory_provider.cpp @@ -127,7 +127,10 @@ namespace hex::plugin::windows { if (this->m_enumerationFailed) { ImGui::TextUnformatted("hex.windows.provider.process_memory.enumeration_failed"_lang); } else { - if (ImGui::BeginTable("##process_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(0, 500_scaled))) { + ImGui::PushItemWidth(350_scaled); + const auto &filtered = this->m_processSearchWidget.draw(this->m_processes); + ImGui::PopItemWidth(); + if (ImGui::BeginTable("##process_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(350_scaled, 500_scaled))) { ImGui::TableSetupColumn("##icon"); ImGui::TableSetupColumn("hex.windows.provider.process_memory.process_id"_lang); ImGui::TableSetupColumn("hex.windows.provider.process_memory.process_name"_lang); @@ -135,19 +138,19 @@ namespace hex::plugin::windows { ImGui::TableHeadersRow(); - for (auto &process : this->m_processes) { - ImGui::PushID(process.id); + for (auto &process : filtered) { + ImGui::PushID(process); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Image(process.icon, process.icon.getSize()); + ImGui::Image(process->icon, process->icon.getSize()); ImGui::TableNextColumn(); - ImGui::Text("%d", process.id); + ImGui::Text("%d", process->id); ImGui::TableNextColumn(); - if (ImGui::Selectable(process.name.c_str(), this->m_selectedProcess != nullptr && process.id == this->m_selectedProcess->id, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, process.icon.getSize().y))) - this->m_selectedProcess = &process; + if (ImGui::Selectable(process->name.c_str(), this->m_selectedProcess != nullptr && process->id == this->m_selectedProcess->id, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, process->icon.getSize().y))) + this->m_selectedProcess = process; ImGui::PopID(); } @@ -160,7 +163,12 @@ namespace hex::plugin::windows { void ProcessMemoryProvider::drawInterface() { ImGui::Header("hex.windows.provider.process_memory.memory_regions"_lang, true); - if (ImGui::BeginTable("##module_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(0, 400_scaled))) { + + auto availableX = ImGui::GetContentRegionAvail().x; + ImGui::PushItemWidth(availableX); + const auto &filtered = this->m_regionSearchWidget.draw(this->m_memoryRegions); + ImGui::PopItemWidth(); + if (ImGui::BeginTable("##module_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(availableX, 400_scaled))) { ImGui::TableSetupColumn("hex.builtin.common.region"_lang); ImGui::TableSetupColumn("hex.builtin.common.size"_lang); ImGui::TableSetupColumn("hex.builtin.common.name"_lang); @@ -168,20 +176,20 @@ namespace hex::plugin::windows { ImGui::TableHeadersRow(); - for (auto &memoryRegion : this->m_memoryRegions) { - ImGui::PushID(memoryRegion.region.getStartAddress()); + for (auto &memoryRegion : filtered) { + ImGui::PushID(memoryRegion->region.getStartAddress()); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("0x%016llX - 0x%016llX", memoryRegion.region.getStartAddress(), memoryRegion.region.getEndAddress()); + ImGui::Text("0x%016llX - 0x%016llX", memoryRegion->region.getStartAddress(), memoryRegion->region.getEndAddress()); ImGui::TableNextColumn(); - ImGui::TextUnformatted(hex::toByteString(memoryRegion.region.getSize()).c_str()); + ImGui::TextUnformatted(hex::toByteString(memoryRegion->region.getSize()).c_str()); ImGui::TableNextColumn(); - if (ImGui::Selectable(memoryRegion.name.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) - ImHexApi::HexEditor::setSelection(memoryRegion.region); + if (ImGui::Selectable(memoryRegion->name.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) + ImHexApi::HexEditor::setSelection(memoryRegion->region); ImGui::PopID(); }