b751f98e91
* ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
249 lines
10 KiB
C++
249 lines
10 KiB
C++
#include "content/views/view_bookmarks.hpp"
|
|
|
|
#include <hex/providers/provider.hpp>
|
|
#include <hex/helpers/fmt.hpp>
|
|
|
|
#include <hex/helpers/project_file_handler.hpp>
|
|
|
|
#include <cstring>
|
|
|
|
namespace hex::plugin::builtin {
|
|
|
|
ViewBookmarks::ViewBookmarks() : View("hex.builtin.view.bookmarks.name") {
|
|
EventManager::subscribe<RequestAddBookmark>(this, [this](Region region, std::string name, std::string comment, color_t color) {
|
|
if (name.empty()) {
|
|
name = hex::format("hex.builtin.view.bookmarks.default_title"_lang, region.address, region.address + region.size - 1);
|
|
}
|
|
|
|
if (color == 0x00)
|
|
color = ImGui::GetColorU32(ImGuiCol_Header);
|
|
|
|
|
|
this->m_bookmarks.push_back({ region,
|
|
name,
|
|
std::move(comment),
|
|
color,
|
|
false
|
|
});
|
|
|
|
ProjectFile::markDirty();
|
|
});
|
|
|
|
EventManager::subscribe<EventProjectFileLoad>(this, [this] {
|
|
this->m_bookmarks = ProjectFile::getBookmarks();
|
|
});
|
|
|
|
EventManager::subscribe<EventProjectFileStore>(this, [this] {
|
|
ProjectFile::setBookmarks(this->m_bookmarks);
|
|
});
|
|
|
|
EventManager::subscribe<EventFileUnloaded>(this, [this] {
|
|
this->m_bookmarks.clear();
|
|
});
|
|
|
|
|
|
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
|
hex::unused(data);
|
|
|
|
for (const auto &bookmark : this->m_bookmarks) {
|
|
if (Region { address, size }.isWithin(bookmark.region))
|
|
return bookmark.color;
|
|
}
|
|
|
|
return std::nullopt;
|
|
});
|
|
|
|
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
|
hex::unused(data);
|
|
for (const auto &bookmark : this->m_bookmarks) {
|
|
if (!Region { address, size }.isWithin(bookmark.region))
|
|
continue;
|
|
|
|
ImGui::BeginTooltip();
|
|
|
|
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::PushID(&bookmark);
|
|
{
|
|
ImGui::ColorButton("##color", ImColor(bookmark.color));
|
|
ImGui::SameLine(0, 10);
|
|
ImGui::TextUnformatted(bookmark.name.c_str());
|
|
|
|
if (ImGui::GetIO().KeyShift) {
|
|
ImGui::Indent();
|
|
if (ImGui::BeginTable("##extra_info", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoClip)) {
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextFormatted("Region: ");
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", bookmark.region.getStartAddress(), bookmark.region.getEndAddress());
|
|
|
|
if (!bookmark.comment.empty() && bookmark.comment[0] != '\x00') {
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextFormatted("Comment: ");
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextFormattedWrapped("\"{}\"", bookmark.comment);
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
ImGui::Unindent();
|
|
}
|
|
}
|
|
|
|
ImGui::PopID();
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bookmark.color);
|
|
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bookmark.color);
|
|
ImGui::EndTable();
|
|
ImGui::PopStyleColor(2);
|
|
}
|
|
|
|
ImGui::EndTooltip();
|
|
}
|
|
});
|
|
}
|
|
|
|
ViewBookmarks::~ViewBookmarks() {
|
|
EventManager::unsubscribe<RequestAddBookmark>(this);
|
|
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
|
EventManager::unsubscribe<EventProjectFileStore>(this);
|
|
EventManager::unsubscribe<EventFileUnloaded>(this);
|
|
|
|
this->m_bookmarks.clear();
|
|
}
|
|
|
|
void ViewBookmarks::drawContent() {
|
|
if (ImGui::Begin(View::toWindowName("hex.builtin.view.bookmarks.name").c_str(), &this->getWindowOpenState())) {
|
|
if (ImGui::BeginChild("##scrolling")) {
|
|
|
|
if (this->m_bookmarks.empty()) {
|
|
ImGui::TextFormattedCentered("hex.builtin.view.bookmarks.no_bookmarks"_lang);
|
|
}
|
|
|
|
u32 id = 1;
|
|
auto bookmarkToRemove = this->m_bookmarks.end();
|
|
for (auto iter = this->m_bookmarks.begin(); iter != this->m_bookmarks.end(); iter++) {
|
|
auto &[region, name, comment, color, locked] = *iter;
|
|
|
|
auto headerColor = ImColor(color);
|
|
auto hoverColor = ImColor(color);
|
|
hoverColor.Value.w *= 1.3F;
|
|
|
|
ImGui::PushID(id);
|
|
ImGui::PushStyleColor(ImGuiCol_Header, color);
|
|
ImGui::PushStyleColor(ImGuiCol_HeaderActive, color);
|
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, u32(hoverColor));
|
|
|
|
bool open = true;
|
|
if (ImGui::CollapsingHeader(name.c_str(), &open)) {
|
|
ImGui::TextUnformatted("hex.builtin.view.bookmarks.title.info"_lang);
|
|
ImGui::Separator();
|
|
ImGui::TextFormatted("hex.builtin.view.bookmarks.address"_lang, region.address, region.address + region.size - 1, region.size);
|
|
|
|
if (ImGui::BeginChild("hexData", ImVec2(0, ImGui::GetTextLineHeight() * 8), true)) {
|
|
size_t offset = region.address % 0x10;
|
|
|
|
for (u8 byte = 0; byte < 0x10; byte++) {
|
|
ImGui::TextFormattedDisabled("{0:02X}", byte);
|
|
ImGui::SameLine();
|
|
}
|
|
|
|
ImGui::NewLine();
|
|
|
|
// TODO: Clip this somehow
|
|
|
|
// First line
|
|
{
|
|
std::array<u8, 0x10> bytes = { 0 };
|
|
size_t byteCount = std::min<size_t>(0x10 - offset, region.size);
|
|
ImHexApi::Provider::get()->read(region.address, bytes.data() + offset, byteCount);
|
|
|
|
for (size_t byte = 0; byte < 0x10; byte++) {
|
|
if (byte < offset)
|
|
ImGui::TextUnformatted(" ");
|
|
else
|
|
ImGui::TextFormatted("{0:02X}", bytes[byte]);
|
|
ImGui::SameLine();
|
|
}
|
|
ImGui::NewLine();
|
|
}
|
|
|
|
// Other lines
|
|
{
|
|
std::array<u8, 0x10> bytes = { 0 };
|
|
for (u32 i = 0x10 - offset; i < region.size; i += 0x10) {
|
|
size_t byteCount = std::min<size_t>(region.size - i, 0x10);
|
|
ImHexApi::Provider::get()->read(region.address + i, bytes.data(), byteCount);
|
|
|
|
for (size_t byte = 0; byte < byteCount; byte++) {
|
|
ImGui::TextFormatted("{0:02X}", bytes[byte]);
|
|
ImGui::SameLine();
|
|
}
|
|
ImGui::NewLine();
|
|
}
|
|
}
|
|
}
|
|
ImGui::EndChild();
|
|
|
|
if (ImGui::Button("hex.builtin.view.bookmarks.button.jump"_lang))
|
|
ImHexApi::HexEditor::setSelection(region);
|
|
ImGui::SameLine(0, 15);
|
|
|
|
if (locked) {
|
|
if (ImGui::Button(ICON_FA_LOCK)) locked = false;
|
|
} else {
|
|
if (ImGui::Button(ICON_FA_UNLOCK)) locked = true;
|
|
}
|
|
|
|
ImGui::NewLine();
|
|
ImGui::TextUnformatted("hex.builtin.view.bookmarks.header.name"_lang);
|
|
ImGui::Separator();
|
|
|
|
ImGui::ColorEdit4("hex.builtin.view.bookmarks.header.color"_lang, (float *)&headerColor.Value, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoAlpha | (locked ? ImGuiColorEditFlags_NoPicker : ImGuiColorEditFlags_None));
|
|
color = headerColor;
|
|
ImGui::SameLine();
|
|
|
|
if (locked)
|
|
ImGui::TextUnformatted(name.data());
|
|
else
|
|
ImGui::InputText("##nameInput", name);
|
|
|
|
ImGui::NewLine();
|
|
ImGui::TextUnformatted("hex.builtin.view.bookmarks.header.comment"_lang);
|
|
ImGui::Separator();
|
|
|
|
if (locked)
|
|
ImGui::TextFormattedWrapped("{}", comment.data());
|
|
else
|
|
ImGui::InputTextMultiline("##commentInput", comment);
|
|
|
|
ImGui::NewLine();
|
|
}
|
|
|
|
if (!open)
|
|
bookmarkToRemove = iter;
|
|
|
|
ImGui::PopID();
|
|
ImGui::PopStyleColor(3);
|
|
id++;
|
|
}
|
|
|
|
if (bookmarkToRemove != this->m_bookmarks.end()) {
|
|
this->m_bookmarks.erase(bookmarkToRemove);
|
|
ProjectFile::markDirty();
|
|
}
|
|
}
|
|
ImGui::EndChild();
|
|
}
|
|
ImGui::End();
|
|
}
|
|
|
|
} |