From dab3f722e84e07058ef10abaa0cf1a67d1cf4d82 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Mon, 30 Dec 2024 22:32:06 +0100 Subject: [PATCH] feat: Added "Jump to address" option to data inspector row context menu --- .../include/hex/api/content_registry.hpp | 10 ++- lib/libimhex/source/api/content_registry.cpp | 8 ++ plugins/builtin/romfs/lang/en_US.json | 1 + .../builtin/source/content/data_inspector.cpp | 85 +++++++++++-------- .../content/views/view_data_inspector.cpp | 4 +- 5 files changed, 68 insertions(+), 40 deletions(-) diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index dbee17784..e5a51aae4 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -622,8 +622,7 @@ namespace hex { /* Data Inspector Registry. Allows adding of new types to the data inspector */ namespace DataInspector { - enum class NumberDisplayStyle - { + enum class NumberDisplayStyle : u8 { Decimal, Hexadecimal, Octal @@ -677,6 +676,13 @@ namespace hex { std::optional editingFunction = std::nullopt ); + /** + * @brief Allows adding new menu items to data inspector row context menus. Call this function inside the + * draw function of the data inspector row definition. + * @param function Callback that will draw menu items + */ + void drawMenuItems(const std::function &function); + } /* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */ diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index a8e3903a9..d12814eab 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -760,6 +760,14 @@ namespace hex { impl::s_entries->push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); } + void drawMenuItems(const std::function &function) { + if (ImGui::BeginPopup("##DataInspectorRowContextMenu")) { + function(); + ImGui::Separator(); + ImGui::EndPopup(); + } + } + } namespace ContentRegistry::DataProcessorNode { diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 9b49e0eb8..7f17fb6bb 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -91,6 +91,7 @@ "hex.builtin.inspector.i48": "int48_t", "hex.builtin.inspector.i64": "int64_t", "hex.builtin.inspector.i8": "int8_t", + "hex.builtin.inspector.jump_to_address": "Jump to address", "hex.builtin.inspector.long_double": "long double (128 bit)", "hex.builtin.inspector.rgb565": "RGB565 Color", "hex.builtin.inspector.rgba8": "RGBA8 Color", diff --git a/plugins/builtin/source/content/data_inspector.cpp b/plugins/builtin/source/content/data_inspector.cpp index 568b1f780..c33605ab0 100644 --- a/plugins/builtin/source/content/data_inspector.cpp +++ b/plugins/builtin/source/content/data_inspector.cpp @@ -13,6 +13,7 @@ #include #include +#include #include namespace hex::plugin::builtin { @@ -77,48 +78,60 @@ namespace hex::plugin::builtin { return {}; } - template - static std::string unsignedToString(const std::vector &buffer, std::endian endian, Style style) requires(sizeof(T) <= sizeof(u64)) { - if (buffer.size() < Size) - return { }; - - auto format = (style == Style::Decimal) ? "{0:d}" : ((style == Style::Hexadecimal) ? hex::format("0x{{0:0{}X}}", Size * 2) : hex::format("0o{{0:0{}o}}", Size * 3)); - + template + static T bufferToInteger(const std::vector &buffer, std::endian endian) { T value = 0x00; std::memcpy(&value, buffer.data(), std::min(sizeof(T), Size)); - return hex::format(format, hex::changeEndianness(value, Size, endian)); + + return hex::changeEndianness(value, Size, endian); + } + + template + static T bufferToInteger(const std::vector &buffer, std::endian endian) { + T value = 0x00; + std::memcpy(&value, buffer.data(), std::min(sizeof(T), Size)); + value = hex::changeEndianness(value, Size, endian); + if (Size != sizeof(T)) + value = hex::signExtend(Size * 8, value); + + return value; } template - static std::string signedToString(const std::vector &buffer, std::endian endian, Style style) requires(sizeof(T) <= sizeof(u64)) { + static std::string bufferToIntegerString(const std::vector &buffer, std::endian endian, Style style) requires(sizeof(T) <= sizeof(u64)) { if (buffer.size() < Size) return { }; auto format = (style == Style::Decimal) ? "{0:d}" : ((style == Style::Hexadecimal) ? hex::format("0x{{0:0{}X}}", Size * 2) : hex::format("0o{{0:0{}o}}", Size * 3)); - T value = 0x00; - std::memcpy(&value, buffer.data(), std::min(sizeof(T), Size)); - auto number = hex::changeEndianness(value, Size, endian); - if (Size != sizeof(T)) - number = hex::signExtend(Size * 8, number); - - return hex::format(format, number); + return hex::format(format, bufferToInteger(buffer, endian)); } template static std::string integerToString(const std::vector &buffer, std::endian endian, Style style) requires(sizeof(T) <= sizeof(u64)) { - if constexpr (std::unsigned_integral) - return unsignedToString(buffer, endian, style); - else if constexpr (std::signed_integral) - return signedToString(buffer, endian, style); + if constexpr (std::integral) + return bufferToIntegerString(buffer, endian, style); else return {}; } - template - static hex::ContentRegistry::DataInspector::impl::GeneratorFunction drawString(T func) { + template + static hex::ContentRegistry::DataInspector::impl::GeneratorFunction drawString(Func func) { return [func](const std::vector &buffer, std::endian endian, Style style) { - return [value = func(buffer, endian, style)]() -> std::string { ImGui::TextUnformatted(value.c_str()); return value; }; + return [buffer, endian, value = func(buffer, endian, style)]() -> std::string { + ContentRegistry::DataInspector::drawMenuItems([&] { + if (ImGui::MenuItemEx("hex.builtin.inspector.jump_to_address"_lang, ICON_VS_DEBUG_STEP_OUT)) { + auto address = bufferToInteger(buffer, endian); + if (address >= 0) { + ImHexApi::HexEditor::setSelection(Region { u64(address), sizeof(u8) }); + } + } + }); + + ImGui::TextUnformatted(value.c_str()); + + return value; + }; }; } @@ -156,62 +169,62 @@ namespace hex::plugin::builtin { ContentRegistry::DataInspector::add("hex.builtin.inspector.u8", sizeof(u8), - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.i8", sizeof(i8), - drawString(integerToString), - stringToInteger + drawString(integerToString), + stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.u16", sizeof(u16), - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.i16", sizeof(i16), - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.u24", 3, - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.i24", 3, - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.u32", sizeof(u32), - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.i32", sizeof(i32), - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.u48", 6, - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.i48", 6, - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.u64", sizeof(u64), - drawString(integerToString), + drawString(integerToString), stringToInteger ); ContentRegistry::DataInspector::add("hex.builtin.inspector.i64", sizeof(i64), - drawString(integerToString), + drawString(integerToString), stringToInteger ); diff --git a/plugins/builtin/source/content/views/view_data_inspector.cpp b/plugins/builtin/source/content/views/view_data_inspector.cpp index 240359f30..7dbd0d061 100644 --- a/plugins/builtin/source/content/views/view_data_inspector.cpp +++ b/plugins/builtin/source/content/views/view_data_inspector.cpp @@ -429,11 +429,11 @@ namespace hex::plugin::builtin { m_selectedEntryName.reset(); } if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { - ImGui::OpenPopup("##InspectorMenu"); + ImGui::OpenPopup("##DataInspectorRowContextMenu"); } } - if (ImGui::BeginPopup("##InspectorMenu")) { + if (ImGui::BeginPopup("##DataInspectorRowContextMenu")) { if (ImGui::MenuItemEx("hex.builtin.view.data_inspector.menu.copy"_lang, ICON_VS_COPY)) { ImGui::SetClipboardText(copyValue.c_str()); }