From cb09cf3734377a7af8f994b85a9be1eb0dee2060 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Mon, 30 Dec 2024 12:07:21 +0100 Subject: [PATCH] feat: Added context menu and next/previous buttons to the data inspector --- .../content/views/view_data_inspector.hpp | 2 + plugins/builtin/romfs/lang/en_US.json | 2 + .../content/views/view_data_inspector.cpp | 72 ++++++++++++++++--- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/plugins/builtin/include/content/views/view_data_inspector.hpp b/plugins/builtin/include/content/views/view_data_inspector.hpp index ce3f672fe..5fbc55e77 100644 --- a/plugins/builtin/include/content/views/view_data_inspector.hpp +++ b/plugins/builtin/include/content/views/view_data_inspector.hpp @@ -24,6 +24,7 @@ namespace hex::plugin::builtin { ContentRegistry::DataInspector::impl::DisplayFunction displayFunction; std::optional editingFunction; bool editing; + u64 requiredSize; std::string filterValue; }; @@ -62,6 +63,7 @@ namespace hex::plugin::builtin { pl::PatternLanguage m_runtime; std::vector m_cachedData, m_workData; + std::optional m_selectedEntryName; TaskHolder m_updateTask; diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index b39bd4a52..9b49e0eb8 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -717,6 +717,8 @@ "hex.builtin.view.constants.row.desc": "Description", "hex.builtin.view.constants.row.name": "Name", "hex.builtin.view.constants.row.value": "Value", + "hex.builtin.view.data_inspector.menu.copy": "Copy Value", + "hex.builtin.view.data_inspector.menu.edit": "Edit Value", "hex.builtin.view.data_inspector.execution_error": "Custom row evaluation error", "hex.builtin.view.data_inspector.invert": "Invert", "hex.builtin.view.data_inspector.name": "Data Inspector", diff --git a/plugins/builtin/source/content/views/view_data_inspector.cpp b/plugins/builtin/source/content/views/view_data_inspector.cpp index 93eebd538..240359f30 100644 --- a/plugins/builtin/source/content/views/view_data_inspector.cpp +++ b/plugins/builtin/source/content/views/view_data_inspector.cpp @@ -91,6 +91,7 @@ namespace hex::plugin::builtin { entry.generatorFunction(buffer, m_endian, m_numberDisplayStyle), entry.editingFunction, false, + entry.requiredSize, entry.unlocalizedName ); } @@ -160,12 +161,13 @@ namespace hex::plugin::builtin { auto displayFunction = createPatternErrorDisplayFunction(); - // Insert the inspector into the list + // Insert the inspector containing the error message into the list m_workData.emplace_back( wolv::util::toUTF8String(path.filename()), std::move(displayFunction), std::nullopt, false, + 0, wolv::util::toUTF8String(path) ); @@ -215,6 +217,7 @@ namespace hex::plugin::builtin { displayFunction, editingFunction, false, + pattern->getSize(), wolv::util::toUTF8String(path) + ":" + pattern->getVariableName() ); @@ -223,12 +226,13 @@ namespace hex::plugin::builtin { } catch (const pl::core::err::EvaluatorError::Exception &) { auto displayFunction = createPatternErrorDisplayFunction(); - // Insert the inspector into the list + // Insert the inspector containing the error message into the list m_workData.emplace_back( wolv::util::toUTF8String(path.filename()), std::move(displayFunction), std::nullopt, false, + 0, wolv::util::toUTF8String(path) ); } @@ -260,6 +264,36 @@ namespace hex::plugin::builtin { }); } + const auto selection = ImHexApi::HexEditor::getSelection(); + const auto selectedEntryIt = std::find_if(m_cachedData.begin(), m_cachedData.end(), [this](const InspectorCacheEntry &entry) { + return entry.unlocalizedName == m_selectedEntryName; + }); + + u64 requiredSize = selectedEntryIt == m_cachedData.end() ? 0x00 : selectedEntryIt->requiredSize; + + ImGui::BeginDisabled(!selection.has_value() || !m_selectedEntryName.has_value()); + { + const auto buttonSize = ImVec2((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x, 0); + const auto baseAddress = m_selectedProvider->getBaseAddress(); + const auto providerSize = m_selectedProvider->getActualSize(); + const auto providerEndAddress = baseAddress + providerSize; + + ImGui::BeginDisabled(providerSize < requiredSize || selection->getStartAddress() < baseAddress + requiredSize); + if (ImGuiExt::DimmedIconButton(ICON_VS_ARROW_LEFT, ImGui::GetStyleColorVec4(ImGuiCol_Text), buttonSize)) { + ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress() - requiredSize, requiredSize }); + } + ImGui::EndDisabled(); + + ImGui::SameLine(); + + ImGui::BeginDisabled(providerSize < requiredSize || selection->getEndAddress() > providerEndAddress - requiredSize); + if (ImGuiExt::DimmedIconButton(ICON_VS_ARROW_RIGHT, ImGui::GetStyleColorVec4(ImGuiCol_Text), buttonSize)) { + ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress() + requiredSize, requiredSize }); + } + ImGui::EndDisabled(); + } + ImGui::EndDisabled(); + if (ImGui::BeginTable("##datainspector", m_tableEditingModeEnabled ? 3 : 2, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg, ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * (validLineCount + 1)))) { @@ -379,16 +413,36 @@ namespace hex::plugin::builtin { ImGui::SameLine(); // Handle copying the value to the clipboard when clicking the row - if (ImGui::Selectable("##InspectorLine", false, ImGuiSelectableFlags_SpanAllColumns | - ImGuiSelectableFlags_AllowOverlap)) { - ImGui::SetClipboardText(copyValue.c_str()); + if (ImGui::Selectable("##InspectorLine", m_selectedEntryName == entry.unlocalizedName, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap)) { + m_selectedEntryName = entry.unlocalizedName; + if (auto selection = ImHexApi::HexEditor::getSelection(); selection.has_value()) { + ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress(), entry.requiredSize }); + } } // Enter editing mode when double-clicking the row - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && - entry.editingFunction.has_value() && m_selectedProvider->isWritable()) { - entry.editing = true; - m_editingValue = copyValue; + const bool editable = entry.editingFunction.has_value() && m_selectedProvider->isWritable(); + if (ImGui::IsItemHovered()) { + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && editable) { + entry.editing = true; + m_editingValue = copyValue; + m_selectedEntryName.reset(); + } + if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { + ImGui::OpenPopup("##InspectorMenu"); + } + } + + if (ImGui::BeginPopup("##InspectorMenu")) { + if (ImGui::MenuItemEx("hex.builtin.view.data_inspector.menu.copy"_lang, ICON_VS_COPY)) { + ImGui::SetClipboardText(copyValue.c_str()); + } + if (ImGui::MenuItemEx("hex.builtin.view.data_inspector.menu.edit"_lang, ICON_VS_EDIT, nullptr, false, editable)) { + entry.editing = true; + m_editingValue = copyValue; + m_selectedEntryName.reset(); + } + ImGui::EndPopup(); } return;