feat: Added option to highlight pattern parents in the hex editor when hovering
This commit is contained in:
parent
dac45659c0
commit
ea601a7d03
@ -73,15 +73,18 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
|
||||
using HoveringFunction = std::function<bool(const prv::Provider *, u64, const u8*, size_t)>;
|
||||
|
||||
const std::map<u32, Highlighting>& getBackgroundHighlights();
|
||||
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();
|
||||
const std::map<u32, Highlighting>& getForegroundHighlights();
|
||||
const std::map<u32, HighlightingFunction>& getForegroundHighlightingFunctions();
|
||||
const std::map<u32, HoveringFunction>& getHoveringFunctions();
|
||||
const std::map<u32, Tooltip>& getTooltips();
|
||||
const std::map<u32, TooltipFunction>& getTooltipFunctions();
|
||||
|
||||
void setCurrentSelection(const std::optional<ProviderRegion> ®ion);
|
||||
void setHoveredRegion(const prv::Provider *provider, const Region ®ion);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,6 +173,19 @@ namespace hex {
|
||||
*/
|
||||
void removeForegroundHighlightingProvider(u32 id);
|
||||
|
||||
/**
|
||||
* @brief Adds a hovering provider to the Hex Editor using a callback function
|
||||
* @param function Function that draws the highlighting based on the hovered region
|
||||
* @return Unique ID used to remove the highlighting again later
|
||||
*/
|
||||
u32 addHoverHighlightProvider(const impl::HoveringFunction &function);
|
||||
|
||||
/**
|
||||
* @brief Removes a hovering color highlighting from the Hex Editor
|
||||
* @param id The ID of the highlighting to remove
|
||||
*/
|
||||
void removeHoverHighlightProvider(u32 id);
|
||||
|
||||
/**
|
||||
* @brief Checks if there's a valid selection in the Hex Editor right now
|
||||
*/
|
||||
@ -215,6 +231,12 @@ namespace hex {
|
||||
*/
|
||||
void addVirtualFile(const std::fs::path &path, std::vector<u8> data, Region region = Region::Invalid());
|
||||
|
||||
/**
|
||||
* @brief Gets the currently hovered cell region in the Hex Editor
|
||||
* @return
|
||||
*/
|
||||
const std::optional<Region>& getHoveredRegion(const prv::Provider *provider);
|
||||
|
||||
}
|
||||
|
||||
/* Functions to interact with Bookmarks */
|
||||
|
@ -32,19 +32,19 @@ namespace hex {
|
||||
return &this->get();
|
||||
}
|
||||
|
||||
T& get(prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
T& get(const prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
return m_data[provider];
|
||||
}
|
||||
|
||||
const T& get(prv::Provider *provider = ImHexApi::Provider::get()) const {
|
||||
const T& get(const prv::Provider *provider = ImHexApi::Provider::get()) const {
|
||||
return m_data.at(provider);
|
||||
}
|
||||
|
||||
void set(const T &data, prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
void set(const T &data, const prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
m_data[provider] = data;
|
||||
}
|
||||
|
||||
void set(T &&data, prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
void set(T &&data, const prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
m_data[provider] = std::move(data);
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ namespace hex {
|
||||
return m_data | std::views::values;
|
||||
}
|
||||
|
||||
void setOnCreateCallback(std::function<void(prv::Provider *, T&)> callback) {
|
||||
void setOnCreateCallback(std::function<void(const prv::Provider *, T&)> callback) {
|
||||
m_onCreateCallback = std::move(callback);
|
||||
}
|
||||
|
||||
@ -120,8 +120,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<prv::Provider *, T> m_data;
|
||||
std::function<void(prv::Provider *, T&)> m_onCreateCallback;
|
||||
std::map<const prv::Provider *, T> m_data;
|
||||
std::function<void(const prv::Provider *, T&)> m_onCreateCallback;
|
||||
};
|
||||
|
||||
}
|
@ -2,10 +2,11 @@
|
||||
|
||||
#include <hex/api/event_manager.hpp>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/providers/provider_data.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@ -67,11 +68,24 @@ namespace hex {
|
||||
return *s_tooltipFunctions;
|
||||
}
|
||||
|
||||
static AutoReset<std::map<u32, HoveringFunction>> s_hoveringFunctions;
|
||||
const std::map<u32, HoveringFunction>& getHoveringFunctions() {
|
||||
return *s_hoveringFunctions;
|
||||
}
|
||||
|
||||
static AutoReset<std::optional<ProviderRegion>> s_currentSelection;
|
||||
void setCurrentSelection(const std::optional<ProviderRegion> ®ion) {
|
||||
*s_currentSelection = region;
|
||||
}
|
||||
|
||||
static PerProvider<std::optional<Region>> s_hoveredRegion;
|
||||
void setHoveredRegion(const prv::Provider *provider, const Region ®ion) {
|
||||
if (region == Region::Invalid())
|
||||
s_hoveredRegion.get(provider).reset();
|
||||
else
|
||||
s_hoveredRegion.get(provider) = region;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color) {
|
||||
@ -150,6 +164,20 @@ namespace hex {
|
||||
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
||||
}
|
||||
|
||||
u32 addHoverHighlightProvider(const impl::HoveringFunction &function) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::s_hoveringFunctions->insert({ id, function });
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeHoverHighlightProvider(u32 id) {
|
||||
impl::s_hoveringFunctions->erase(id);
|
||||
}
|
||||
|
||||
static u32 tooltipId = 0;
|
||||
u32 addTooltip(Region region, std::string value, color_t color) {
|
||||
tooltipId++;
|
||||
@ -202,6 +230,11 @@ namespace hex {
|
||||
void addVirtualFile(const std::fs::path &path, std::vector<u8> data, Region region) {
|
||||
RequestAddVirtualFile::post(path, std::move(data), region);
|
||||
}
|
||||
|
||||
const std::optional<Region>& getHoveredRegion(const prv::Provider *provider) {
|
||||
return impl::s_hoveredRegion.get(provider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace hex::plugin::builtin {
|
||||
bool valid = false;
|
||||
|
||||
TaskHolder task;
|
||||
prv::Provider *analyzedProvider = nullptr;
|
||||
const prv::Provider *analyzedProvider = nullptr;
|
||||
Region analysisRegion = { 0, 0 };
|
||||
|
||||
ui::RegionType selectionType = ui::RegionType::EntireData;
|
||||
|
@ -221,7 +221,10 @@ namespace hex::plugin::builtin {
|
||||
|
||||
std::array<AccessData, 512> m_accessHistory = {};
|
||||
u32 m_accessHistoryIndex = 0;
|
||||
bool replace = false;
|
||||
bool m_parentHighlightingEnabled = true;
|
||||
bool m_replaceMode = false;
|
||||
|
||||
|
||||
static inline std::array<std::string,256> m_findHistory;
|
||||
static inline u32 m_findHistorySize = 0;
|
||||
static inline u32 m_findHistoryIndex = 0;
|
||||
|
@ -464,6 +464,7 @@
|
||||
"hex.builtin.setting.hex_editor.bytes_per_row": "Bytes per row",
|
||||
"hex.builtin.setting.hex_editor.char_padding": "Extra character cell padding",
|
||||
"hex.builtin.setting.hex_editor.highlight_color": "Selection highlight color",
|
||||
"hex.builtin.setting.hex_editor.pattern_parent_highlighting": "Highlight pattern parents on hover",
|
||||
"hex.builtin.setting.hex_editor.sync_scrolling": "Synchronize editor scroll position",
|
||||
"hex.builtin.setting.imhex": "ImHex",
|
||||
"hex.builtin.setting.imhex.recent_files": "Recent Files",
|
||||
|
@ -767,6 +767,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Settings::add<Widgets::SliderInteger>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.byte_padding", 0, 0, 50);
|
||||
ContentRegistry::Settings::add<Widgets::SliderInteger>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.char_padding", 0, 0, 50);
|
||||
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.pattern_parent_highlighting", true);
|
||||
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include <popups/popup_file_chooser.hpp>
|
||||
#include <content/popups/popup_blocking_task.hpp>
|
||||
#include <content/popups/hex_editor/popup_hex_editor_find.hpp>
|
||||
#include <wolv/utils/lock.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
@ -404,8 +406,20 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
m_hexEditor.setBackgroundHighlightCallback([this](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
|
||||
if (auto highlight = m_backgroundHighlights->find(address); highlight != m_backgroundHighlights->end())
|
||||
return highlight->second;
|
||||
bool hovered = false;
|
||||
for (const auto &[id, hoverFunction] : ImHexApi::HexEditor::impl::getHoveringFunctions()) {
|
||||
if (hoverFunction(m_hexEditor.getProvider(), address, data, size)) {
|
||||
hovered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto highlight = m_backgroundHighlights->find(address); highlight != m_backgroundHighlights->end()) {
|
||||
if (hovered)
|
||||
return ImAlphaBlendColors(highlight->second, 0xA0FFFFFF);
|
||||
else
|
||||
return highlight->second;
|
||||
}
|
||||
|
||||
std::optional<color_t> result;
|
||||
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions()) {
|
||||
|
@ -15,7 +15,7 @@ namespace hex::plugin::builtin {
|
||||
using namespace hex::literals;
|
||||
|
||||
ViewInformation::ViewInformation() : View::Window("hex.builtin.view.information.name", ICON_VS_GRAPH_LINE) {
|
||||
m_analysisData.setOnCreateCallback([](prv::Provider *provider, AnalysisData &data) {
|
||||
m_analysisData.setOnCreateCallback([](const prv::Provider *provider, AnalysisData &data) {
|
||||
data.analyzedProvider = provider;
|
||||
|
||||
for (const auto &informationSectionConstructor : ContentRegistry::DataInformation::impl::getInformationSectionConstructors()) {
|
||||
|
@ -37,7 +37,7 @@ namespace hex::plugin::builtin {
|
||||
(*m_patternDrawer)->jumpToPattern(pattern);
|
||||
});
|
||||
|
||||
m_patternDrawer.setOnCreateCallback([this](prv::Provider *provider, auto &drawer) {
|
||||
m_patternDrawer.setOnCreateCallback([this](const prv::Provider *provider, auto &drawer) {
|
||||
drawer = std::make_unique<ui::PatternDrawer>();
|
||||
|
||||
drawer->setSelectionCallback([](const pl::ptrn::Pattern *pattern) {
|
||||
|
@ -278,24 +278,24 @@ namespace hex::plugin::builtin {
|
||||
bool openFindPopup = false;
|
||||
ImGui::PushID(&this->m_textEditor);
|
||||
if (clickedMenuFind) {
|
||||
replace = false;
|
||||
m_replaceMode = false;
|
||||
openFindPopup = true;
|
||||
}
|
||||
|
||||
if (clickedMenuReplace) {
|
||||
replace = true;
|
||||
m_replaceMode = true;
|
||||
openFindPopup = true;
|
||||
}
|
||||
|
||||
// shortcuts to open the find/replace popup
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F, false) && ImGui::GetIO().KeyCtrl) {
|
||||
replace = false;
|
||||
m_replaceMode = false;
|
||||
openFindPopup = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_H, false) && ImGui::GetIO().KeyCtrl) {
|
||||
replace = true;
|
||||
m_replaceMode = true;
|
||||
openFindPopup = true;
|
||||
}
|
||||
}
|
||||
@ -350,7 +350,7 @@ namespace hex::plugin::builtin {
|
||||
windowPosForPopup.x += windowSize.x - popupSize.x;
|
||||
findReplaceHandler->SetFindWindowPos(windowPosForPopup);
|
||||
|
||||
if (replace) {
|
||||
if (m_replaceMode) {
|
||||
// Remove one window padding
|
||||
popupSize.y -= style.WindowPadding.y;
|
||||
// Add the replace window height
|
||||
@ -604,10 +604,10 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
bool oldReplace = replace;
|
||||
ImGuiExt::DimmedIconToggle(ICON_VS_TRIANGLE_DOWN, ICON_VS_TRIANGLE_RIGHT, &replace);
|
||||
if (oldReplace != replace) {
|
||||
if (replace)
|
||||
bool oldReplace = m_replaceMode;
|
||||
ImGuiExt::DimmedIconToggle(ICON_VS_TRIANGLE_DOWN, ICON_VS_TRIANGLE_RIGHT, &m_replaceMode);
|
||||
if (oldReplace != m_replaceMode) {
|
||||
if (m_replaceMode)
|
||||
requestFocusReplace = true;
|
||||
else
|
||||
requestFocusFind = true;
|
||||
@ -644,7 +644,7 @@ namespace hex::plugin::builtin {
|
||||
findReplaceHandler->SetFindWord(&m_textEditor,findWord);
|
||||
}
|
||||
|
||||
if ((!replace && requestFocus) || requestFocusFind) {
|
||||
if ((!m_replaceMode && requestFocus) || requestFocusFind) {
|
||||
ImGui::SetKeyboardFocusHere(-1);
|
||||
requestFocus = false;
|
||||
requestFocusFind = false;
|
||||
@ -755,7 +755,7 @@ namespace hex::plugin::builtin {
|
||||
if (ImGuiExt::IconButton(ICON_VS_ARROW_UP, ImVec4(1, 1, 1, 1)))
|
||||
upArrowFind = true;
|
||||
|
||||
if (replace) {
|
||||
if (m_replaceMode) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
@ -1837,6 +1837,10 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.parent_highlighting", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_parentHighlightingEnabled = bool(value.get<int>(false));
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8 *data, size_t size, bool) -> std::optional<color_t> {
|
||||
hex::unused(data, size);
|
||||
|
||||
@ -1859,6 +1863,26 @@ namespace hex::plugin::builtin {
|
||||
return color;
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *provider, u64 address, const u8 *, size_t) {
|
||||
if (!m_parentHighlightingEnabled) return false;
|
||||
|
||||
const auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
|
||||
|
||||
if (auto hoveredRegion = ImHexApi::HexEditor::getHoveredRegion(provider)) {
|
||||
for (const auto &pattern : runtime.getPatternsAtAddress(hoveredRegion->getStartAddress())) {
|
||||
const pl::ptrn::Pattern * checkPattern = pattern;
|
||||
if (auto parent = checkPattern->getParent(); parent != nullptr)
|
||||
checkPattern = parent;
|
||||
|
||||
if (checkPattern->getOffset() <= address && checkPattern->getOffset() + checkPattern->getSize() > address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
||||
hex::unused(data, size);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
#include <fonts/codicons_font.h>
|
||||
#include <hex/providers/buffered_reader.hpp>
|
||||
|
||||
namespace hex::ui {
|
||||
|
||||
@ -421,6 +422,7 @@ namespace hex::ui {
|
||||
ImGuiExt::TextFormattedCentered("{}", "hex.ui.hex_editor.no_bytes"_lang);
|
||||
}
|
||||
|
||||
Region hoveredCell = Region::Invalid();
|
||||
if (ImGui::BeginChild("Hex View", size, ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
this->drawScrollbar(CharacterSize);
|
||||
|
||||
@ -596,6 +598,11 @@ namespace hex::ui {
|
||||
this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex);
|
||||
else
|
||||
ImGuiExt::TextFormatted("{}", std::string(maxCharsPerCell, '?'));
|
||||
|
||||
if (cellHovered) {
|
||||
hoveredCell = { byteAddress, bytesPerCell };
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
@ -650,6 +657,11 @@ namespace hex::ui {
|
||||
ImGuiExt::TextFormattedDisabled("{}", m_unknownDataCharacter);
|
||||
else
|
||||
this->drawCell(byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII);
|
||||
|
||||
if (cellHovered) {
|
||||
hoveredCell = { byteAddress, bytesPerCell };
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
@ -733,6 +745,10 @@ namespace hex::ui {
|
||||
ImGui::Dummy({ 0, 0 });
|
||||
|
||||
this->handleSelection(address, data.advance, &bytes[address % m_bytesPerRow], cellHovered);
|
||||
|
||||
if (cellHovered) {
|
||||
hoveredCell = { address, data.advance };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -798,6 +814,8 @@ namespace hex::ui {
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImHexApi::HexEditor::impl::setHoveredRegion(m_provider, hoveredCell);
|
||||
|
||||
m_shouldScrollToSelection = false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user