feat: Added per-byte highlights to the hex editor minimap
This commit is contained in:
parent
5d59b8599d
commit
c5f5973a9d
@ -1086,7 +1086,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
struct MiniMapVisualizer {
|
||||
using Callback = std::function<ImColor(const std::vector<u8>&)>;
|
||||
using Callback = std::function<void(u64, std::span<const u8>, std::vector<ImColor>&)>;
|
||||
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
|
@ -175,8 +175,12 @@
|
||||
"hex.builtin.menu.view.demo": "Show ImGui Demo",
|
||||
"hex.builtin.menu.view.fps": "Display FPS",
|
||||
"hex.builtin.minimap_visualizer.entropy": "Local Entropy",
|
||||
"hex.builtin.minimap_visualizer.zeros": "Zeros Count",
|
||||
"hex.builtin.minimap_visualizer.ascii": "ASCII Count",
|
||||
"hex.builtin.minimap_visualizer.zero_count": "Zeros Count",
|
||||
"hex.builtin.minimap_visualizer.zeros": "Zeros",
|
||||
"hex.builtin.minimap_visualizer.ascii_count": "ASCII Count",
|
||||
"hex.builtin.minimap_visualizer.byte_type": "Byte Type",
|
||||
"hex.builtin.minimap_visualizer.highlights": "Highlights",
|
||||
"hex.builtin.minimap_visualizer.byte_magnitude": "Byte Magnitude",
|
||||
"hex.builtin.nodes.arithmetic": "Arithmetic",
|
||||
"hex.builtin.nodes.arithmetic.add": "Addition",
|
||||
"hex.builtin.nodes.arithmetic.add.header": "Add",
|
||||
|
@ -175,8 +175,8 @@
|
||||
"hex.builtin.menu.view.demo": "ImGui demó megjelenítése",
|
||||
"hex.builtin.menu.view.fps": "FPS megjelenítése",
|
||||
"hex.builtin.minimap_visualizer.entropy": "Lokális entrópia",
|
||||
"hex.builtin.minimap_visualizer.zeros": "Zéró mennyiség",
|
||||
"hex.builtin.minimap_visualizer.ascii": "ASCII mennyiség",
|
||||
"hex.builtin.minimap_visualizer.zero_count": "Zéró mennyiség",
|
||||
"hex.builtin.minimap_visualizer.ascii_count": "ASCII mennyiség",
|
||||
"hex.builtin.nodes.arithmetic": "Aritmetika",
|
||||
"hex.builtin.nodes.arithmetic.add": "Összeadás",
|
||||
"hex.builtin.nodes.arithmetic.add.header": "Összead",
|
||||
|
@ -201,9 +201,9 @@
|
||||
"hex.builtin.menu.workspace.layout": "布局",
|
||||
"hex.builtin.menu.workspace.layout.lock": "锁定布局",
|
||||
"hex.builtin.menu.workspace.layout.save": "保存布局",
|
||||
"hex.builtin.minimap_visualizer.ascii": "ASCII 计数",
|
||||
"hex.builtin.minimap_visualizer.ascii_count": "ASCII 计数",
|
||||
"hex.builtin.minimap_visualizer.entropy": "局部熵",
|
||||
"hex.builtin.minimap_visualizer.zeros": "0 计数",
|
||||
"hex.builtin.minimap_visualizer.zero_count": "0 计数",
|
||||
"hex.builtin.nodes.arithmetic": "运算",
|
||||
"hex.builtin.nodes.arithmetic.add": "加法",
|
||||
"hex.builtin.nodes.arithmetic.add.header": "加法",
|
||||
|
@ -1,9 +1,13 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <wolv/utils/lock.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@ -12,7 +16,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
namespace {
|
||||
|
||||
ImColor entropyMiniMapVisualizer(const std::vector<u8> &data) {
|
||||
void entropyMiniMapVisualizer(u64, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
std::array<u8, 256> frequencies = { 0 };
|
||||
for (u8 byte : data)
|
||||
frequencies[byte] += 1;
|
||||
@ -34,35 +38,99 @@ namespace hex::plugin::builtin {
|
||||
color = ImColor::HSV(static_cast<float>(hue) / 0.75F, 0.8F, 1.0F);
|
||||
}
|
||||
|
||||
return color;
|
||||
output.push_back(color);
|
||||
}
|
||||
|
||||
ImColor zerosMiniMapVisualizer(const std::vector<u8> &data) {
|
||||
void zerosCountMiniMapVisualizer(u64, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
u32 zerosCount = 0;
|
||||
for (u8 byte : data) {
|
||||
if (byte == 0x00)
|
||||
zerosCount += 1;
|
||||
}
|
||||
|
||||
return ImColor::HSV(0.0F, 0.0F, 1.0F - (double(zerosCount) / data.size()));
|
||||
output.push_back(ImColor::HSV(0.0F, 0.0F, 1.0F - (double(zerosCount) / data.size())));
|
||||
}
|
||||
|
||||
ImColor byteTypeMiniMapVisualizer(const std::vector<u8> &data) {
|
||||
void zerosMiniMapVisualizer(u64, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
for (u8 byte : data) {
|
||||
if (byte == 0x00)
|
||||
output.push_back(ImColor(1.0F, 1.0F, 1.0F, 1.0F));
|
||||
else
|
||||
output.push_back(ImColor(0.0F, 0.0F, 0.0F, 1.0F));
|
||||
}
|
||||
}
|
||||
|
||||
void byteTypeMiniMapVisualizer(u64, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
for (u8 byte : data) {
|
||||
if (std::isalpha(byte))
|
||||
output.emplace_back(1.0F, 0.0F, 0.0F, 1.0F);
|
||||
else if (std::isdigit(byte))
|
||||
output.emplace_back(0.0F, 1.0F, 0.0F, 1.0F);
|
||||
else if (std::isspace(byte))
|
||||
output.emplace_back(0.0F, 0.0F, 1.0F, 1.0F);
|
||||
else if (std::iscntrl(byte))
|
||||
output.emplace_back(0.5F, 0.5F, 0.5F, 1.0F);
|
||||
else
|
||||
output.emplace_back(0.0F, 0.0F, 0.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
void asciiCountMiniMapVisualizer(u64, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
u8 asciiCount = 0;
|
||||
for (u8 byte : data) {
|
||||
if (std::isprint(byte))
|
||||
asciiCount += 1;
|
||||
}
|
||||
|
||||
return ImColor::HSV(0.5F, 0.5F, (double(asciiCount) / data.size()));
|
||||
output.push_back(ImColor::HSV(0.5F, 0.5F, (double(asciiCount) / data.size())));
|
||||
}
|
||||
|
||||
void byteMagnitudeMiniMapVisualizer(u64, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
for (u8 byte : data) {
|
||||
output.push_back(ImColor::HSV(0.0F, 0.0F, static_cast<float>(byte) / 255.0F));
|
||||
}
|
||||
}
|
||||
|
||||
void highlightsMiniMapVisualizer(u64 address, std::span<const u8> data, std::vector<ImColor> &output) {
|
||||
for (size_t i = 0; i < data.size(); i += 1) {
|
||||
std::optional<ImColor> result;
|
||||
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions()) {
|
||||
if (auto color = callback(address + i, data.data() + i, 1, result.has_value()); color.has_value())
|
||||
result = color;
|
||||
}
|
||||
|
||||
if (!result.has_value()) {
|
||||
for (const auto &[id, highlighting] : ImHexApi::HexEditor::impl::getBackgroundHighlights()) {
|
||||
if (highlighting.getRegion().overlaps({ address, 1 })) {
|
||||
result = highlighting.getColor();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.has_value()) {
|
||||
result->Value.w = 1.0F;
|
||||
} else {
|
||||
if (auto region = ImHexApi::HexEditor::getSelection(); region.has_value()) {
|
||||
if (region->overlaps({ address + i, 1 }))
|
||||
result = 0x60C08080;
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(result.value_or(ImColor()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void registerMiniMapVisualizers() {
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.entropy", entropyMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.zeros", zerosMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.ascii", byteTypeMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.entropy", entropyMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.zero_count", zerosCountMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.zeros", zerosMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.ascii_count", asciiCountMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.byte_type", byteTypeMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.highlights", highlightsMiniMapVisualizer);
|
||||
ContentRegistry::HexEditor::addMiniMapVisualizer("hex.builtin.minimap_visualizer.byte_magnitude", byteMagnitudeMiniMapVisualizer);
|
||||
}
|
||||
|
||||
}
|
@ -195,7 +195,10 @@ namespace hex::ui {
|
||||
}
|
||||
|
||||
void HexEditor::drawMinimap(ImVec2 characterSize) {
|
||||
ImS64 numRows = m_provider == nullptr ? 0 : (m_provider->getSize() / m_bytesPerRow) + ((m_provider->getSize() % m_bytesPerRow) == 0 ? 0 : 1);
|
||||
if (m_provider == nullptr)
|
||||
return;
|
||||
|
||||
ImS64 numRows = (m_provider->getSize() / m_bytesPerRow) + ((m_provider->getSize() % m_bytesPerRow) == 0 ? 0 : 1);
|
||||
|
||||
auto window = ImGui::GetCurrentWindowRead();
|
||||
const auto outerRect = window->Rect();
|
||||
@ -239,14 +242,25 @@ namespace hex::ui {
|
||||
drawList->ChannelsSetCurrent(0);
|
||||
|
||||
std::vector<u8> rowData(m_bytesPerRow);
|
||||
std::vector<ImColor> rowColors;
|
||||
const auto drawStart = std::max<ImS64>(0, scrollPos - grabPos);
|
||||
for (ImS64 y = drawStart; y < std::min<ImS64>(drawStart + rowCount, m_provider->getSize() / m_bytesPerRow); y += 1) {
|
||||
const auto rowStart = bb.Min + ImVec2(0, (y - drawStart) * rowHeight);
|
||||
const auto rowEnd = rowStart + ImVec2(bb.GetSize().x, rowHeight);
|
||||
const auto rowSize = rowEnd - rowStart;
|
||||
|
||||
m_provider->read(y * m_bytesPerRow + m_provider->getBaseAddress() + m_provider->getCurrentPageAddress(), rowData.data(), rowData.size());
|
||||
const auto address = y * m_bytesPerRow + m_provider->getBaseAddress() + m_provider->getCurrentPageAddress();
|
||||
m_provider->read(address, rowData.data(), rowData.size());
|
||||
|
||||
drawList->AddRectFilled(rowStart, rowEnd, m_miniMapVisualizer->callback(rowData));
|
||||
m_miniMapVisualizer->callback(address, rowData, rowColors);
|
||||
|
||||
const auto cellSize = rowSize / ImVec2(rowColors.size(), 1);
|
||||
ImVec2 cellPos = rowStart;
|
||||
for (const auto &rowColor : rowColors) {
|
||||
drawList->AddRectFilled(cellPos, cellPos + cellSize, rowColor);
|
||||
cellPos.x += cellSize.x;
|
||||
}
|
||||
rowColors.clear();
|
||||
}
|
||||
|
||||
drawList->ChannelsMerge();
|
||||
|
Loading…
x
Reference in New Issue
Block a user