1
0
mirror of synced 2024-11-28 01:20:51 +01:00

feat: Added basic UI for the new pl section system

This commit is contained in:
WerWolv 2022-11-07 00:04:47 +01:00
parent 901b8f0424
commit 5bbc2fd94c
27 changed files with 301 additions and 186 deletions

@ -1 +1 @@
Subproject commit 22cfecfbffbc6dee4879b9f9cfaedc943aca5bd6
Subproject commit 2fc96aedca0f665957eec878d75403eff7de5a91

View File

@ -692,6 +692,7 @@ namespace hex {
style.WindowRounding = 0.0F;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigWindowsMoveFromTitleBarOnly = true;
if (glfwGetPrimaryMonitor() != nullptr) {
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");

View File

@ -21,22 +21,27 @@ namespace hex {
class HexEditor {
public:
HexEditor();
~HexEditor();
HexEditor(std::optional<u64> **selectionStart, std::optional<u64> **selectionEnd, float **scrollPosition);
void draw();
void draw(prv::Provider *provider, float height = ImGui::GetContentRegionAvail().y);
private:
enum class CellType { None, Hex, ASCII };
void drawCell(u64 address, u8 *data, size_t size, bool hovered, CellType cellType);
void drawCell(prv::Provider *provider, u64 address, u8 *data, size_t size, bool hovered, CellType cellType);
void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize) const;
void drawEditor(const ImVec2 &size);
void drawFooter(const ImVec2 &size);
void drawEditor(prv::Provider *provider, const ImVec2 &size);
void drawFooter(prv::Provider *provider, const ImVec2 &size);
void drawTooltip(u64 address, const u8 *data, size_t size);
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
std::optional<color_t> applySelectionColor(u64 byteAddress, std::optional<color_t> color);
public:
void setSelectionUnchecked(std::optional<u64> start, std::optional<u64> end) {
this->m_selectionStart = start;
this->m_selectionEnd = end;
}
void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
void setSelection(u128 start, u128 end) {
if (!ImHexApi::Provider::isValid())
@ -46,10 +51,10 @@ namespace hex {
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
this->m_selectionChanged = **this->m_selectionStart != start || **this->m_selectionEnd != end;
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
**this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
**this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
if (this->m_selectionChanged) {
EventManager::post<EventRegionSelected>(this->getSelection());
@ -61,15 +66,15 @@ namespace hex {
if (!isSelectionValid())
return Region::Invalid();
const auto start = std::min((*this->m_selectionStart)->value(), (*this->m_selectionEnd)->value());
const auto end = std::max((*this->m_selectionStart)->value(), (*this->m_selectionEnd)->value());
const auto start = std::min(this->m_selectionStart.value(), this->m_selectionEnd.value());
const auto end = std::max(this->m_selectionStart.value(), this->m_selectionEnd.value());
const size_t size = end - start + 1;
return { start, size };
}
[[nodiscard]] bool isSelectionValid() const {
return (*this->m_selectionStart)->has_value() && (*this->m_selectionEnd)->has_value();
return this->m_selectionStart.has_value() && this->m_selectionEnd.has_value();
}
void jumpToSelection(bool center = true) {
@ -135,10 +140,30 @@ namespace hex {
this->m_shouldUpdateScrollPosition = true;
}
void setForegroundHighlightCallback(const std::function<std::optional<color_t>(u64, const u8 *, size_t)> &callback) {
this->m_foregroundColorCallback = callback;
}
void setBackgroundHighlightCallback(const std::function<std::optional<color_t>(u64, const u8 *, size_t)> &callback) {
this->m_backgroundColorCallback = callback;
}
void setTooltipCallback(const std::function<void(u64, const u8 *, size_t)> &callback) {
this->m_tooltipCallback = callback;
}
[[nodiscard]] float getScrollPosition() const {
return this->m_scrollPosition;
}
void setScrollPosition(float scrollPosition) {
this->m_scrollPosition = scrollPosition;
}
private:
std::optional<u64> **m_selectionStart;
std::optional<u64> **m_selectionEnd;
float **m_scrollPosition;
std::optional<u64> m_selectionStart;
std::optional<u64> m_selectionEnd;
float m_scrollPosition = 0;
u16 m_bytesPerRow = 16;
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
@ -169,6 +194,11 @@ namespace hex {
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
std::optional<EncodingFile> m_currCustomEncoding;
static std::optional<color_t> defaultColorCallback(u64, const u8 *, size_t) { return std::nullopt; }
static void defaultTooltipCallback(u64, const u8 *, size_t) { }
std::function<std::optional<color_t>(u64, const u8 *, size_t)> m_foregroundColorCallback = defaultColorCallback, m_backgroundColorCallback = defaultColorCallback;
std::function<void(u64, const u8 *, size_t)> m_tooltipCallback = defaultTooltipCallback;
};
}

View File

@ -53,6 +53,7 @@ namespace hex::plugin::builtin {
std::vector<std::pair<pl::core::LogConsole::Level, std::string>> lastEvaluationLog;
std::map<std::string, pl::core::Token::Literal> lastEvaluationOutVars;
std::map<std::string, PatternVariable> patternVariables;
std::map<u64, pl::api::Section> sections;
std::list<EnvVar> envVarEntries;
} patternLanguage;

View File

@ -11,7 +11,7 @@
#include <windows.h>
#endif
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class DiskProvider : public hex::prv::Provider {
public:

View File

@ -15,7 +15,7 @@
#include <sys/fcntl.h>
#endif
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class FileProvider : public hex::prv::Provider {
public:

View File

@ -8,7 +8,7 @@
#include <string_view>
#include <thread>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class GDBProvider : public hex::prv::Provider {
public:

View File

@ -4,7 +4,7 @@
#include <IntervalTree.h>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class IntelHexProvider : public hex::prv::Provider {
public:

View File

@ -3,7 +3,7 @@
#include <hex/providers/provider.hpp>
#include <hex/api/localization.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class MemoryFileProvider : public hex::prv::Provider {
public:

View File

@ -2,7 +2,7 @@
#include <content/providers/intel_hex_provider.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class MotorolaSRECProvider : public IntelHexProvider {
public:

View File

@ -2,7 +2,7 @@
#include <hex/providers/provider.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
class NullProvider : public hex::prv::Provider {
public:

View File

@ -15,8 +15,8 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
static bool importBookmarks(prv::Provider *provider, const nlohmann::json &json);
static bool exportBookmarks(prv::Provider *provider, nlohmann::json &json);
static bool importBookmarks(hex::prv::Provider *provider, const nlohmann::json &json);
static bool exportBookmarks(hex::prv::Provider *provider, nlohmann::json &json);
void registerMenuItems();
private:

View File

@ -14,7 +14,7 @@ namespace hex::plugin::builtin {
class ViewHexEditor : public View {
public:
ViewHexEditor();
~ViewHexEditor();
~ViewHexEditor() override;
void drawContent() override;
@ -44,23 +44,23 @@ namespace hex::plugin::builtin {
}
bool isSelectionValid() {
return this->m_hexEditor->isSelectionValid();
return this->m_hexEditor.isSelectionValid();
}
Region getSelection() {
return this->m_hexEditor->getSelection();
return this->m_hexEditor.getSelection();
}
void setSelection(const Region &region) {
this->m_hexEditor->setSelection(region);
this->m_hexEditor.setSelection(region);
}
void setSelection(u128 start, u128 end) {
this->m_hexEditor->setSelection(start, end);
this->m_hexEditor.setSelection(start, end);
}
void jumpToSelection() {
this->m_hexEditor->jumpToSelection();
this->m_hexEditor.jumpToSelection();
}
private:
@ -70,13 +70,10 @@ namespace hex::plugin::builtin {
void registerEvents();
void registerMenuItems();
std::unique_ptr<HexEditor> m_hexEditor;
HexEditor m_hexEditor;
bool m_shouldOpenPopup = false;
std::unique_ptr<Popup> m_currPopup;
std::optional<u64> *m_selectionStart, *m_selectionEnd;
float *m_scrollPosition;
};
}

View File

@ -4,6 +4,7 @@
#include <hex/ui/view.hpp>
#include <content/helpers/pattern_drawer.hpp>
#include <hex/providers/provider.hpp>
#include <vector>
#include <tuple>
@ -18,7 +19,7 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
std::map<prv::Provider *, std::vector<pl::ptrn::Pattern*>> m_sortedPatterns;
std::map<hex::prv::Provider *, std::vector<pl::ptrn::Pattern*>> m_sortedPatterns;
hex::PatternDrawer m_patternDrawer;
};

View File

@ -4,7 +4,10 @@
#include <pl/pattern_language.hpp>
#include <pl/core/errors/error.hpp>
#include <hex/providers/provider.hpp>
#include <content/helpers/provider_extra_data.hpp>
#include <content/helpers/hex_editor.hpp>
#include <content/providers/memory_file_provider.hpp>
#include <cstring>
#include <filesystem>
@ -60,10 +63,14 @@ namespace hex::plugin::builtin {
bool m_syncPatternSourceCode = false;
bool m_autoLoadPatterns = true;
std::unique_ptr<MemoryFileProvider> m_sectionProvider = nullptr;
HexEditor m_hexEditor;
private:
void drawConsole(ImVec2 size, const std::vector<std::pair<pl::core::LogConsole::Level, std::string>> &console);
void drawEnvVars(ImVec2 size, std::list<PlData::EnvVar> &envVars);
void drawVariableSettings(ImVec2 size, std::map<std::string, PlData::PatternVariable> &patternVariables);
void drawSectionSelector(ImVec2 size, std::map<u64, pl::api::Section> &sections);
void drawPatternTooltip(pl::ptrn::Pattern *pattern);

View File

@ -19,7 +19,7 @@ namespace hex::plugin::builtin {
static void openFile(const std::fs::path &path) {
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
if (auto *fileProvider = dynamic_cast<prv::FileProvider*>(provider); fileProvider != nullptr) {
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider); fileProvider != nullptr) {
fileProvider->setPath(path);
if (fileProvider->open())
EventManager::post<EventProviderOpened>(fileProvider);

View File

@ -70,8 +70,7 @@ namespace hex {
/* Hex Editor */
HexEditor::HexEditor(std::optional<u64> **selectionStart, std::optional<u64> **selectionEnd, float **scrollPosition)
: m_selectionStart(selectionStart), m_selectionEnd(selectionEnd), m_scrollPosition(scrollPosition) {
HexEditor::HexEditor() {
this->m_currDataVisualizer = ContentRegistry::HexEditor::impl::getVisualizers()["hex.builtin.visualizer.hexadecimal.8bit"];
this->m_grayZeroHighlighter = ImHexApi::HexEditor::addForegroundHighlightingProvider([this](u64 address, const u8 *data, size_t size, bool hasColor) -> std::optional<color_t> {
@ -174,42 +173,6 @@ namespace hex {
return currColumn > 0 && (currColumn) < columnCount && ((currColumn) % 8) == 0;
}
static std::optional<color_t> queryBackgroundColor(u64 address, const u8 *data, size_t size) {
std::optional<color_t> result;
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions()) {
if (auto color = callback(address, data, size, result.has_value()); color.has_value())
return color.value();
}
if (result.has_value())
return result;
for (const auto &[id, highlighting] : ImHexApi::HexEditor::impl::getBackgroundHighlights()) {
if (highlighting.getRegion().overlaps({ address, size }))
return highlighting.getColor();
}
return std::nullopt;
}
static std::optional<color_t> queryForegroundColor(u64 address, const u8 *data, size_t size) {
std::optional<color_t> result;
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions()) {
if (auto color = callback(address, data, size, result.has_value()); color.has_value())
result = color;
}
if (result.has_value())
return result;
for (const auto &[id, highlighting] : ImHexApi::HexEditor::impl::getForegroundHighlights()) {
if (highlighting.getRegion().overlaps({ address, size }))
return highlighting.getColor();
}
return std::nullopt;
}
std::optional<color_t> HexEditor::applySelectionColor(u64 byteAddress, std::optional<color_t> color) {
if (isSelectionValid()) {
auto selection = getSelection();
@ -234,13 +197,12 @@ namespace hex {
ImColor color;
};
static CustomEncodingData queryCustomEncodingData(const EncodingFile &encodingFile, u64 address) {
static CustomEncodingData queryCustomEncodingData(prv::Provider *provider, const EncodingFile &encodingFile, u64 address) {
const auto longestSequence = encodingFile.getLongestSequence();
if (longestSequence == 0)
return { ".", 1, 0xFFFF8000 };
auto provider = ImHexApi::Provider::get();
size_t size = std::min<size_t>(longestSequence, provider->getActualSize() - address);
std::vector<u8> buffer(size);
@ -267,41 +229,17 @@ namespace hex {
return ImGui::GetCursorScreenPos() - ImGui::GetStyle().CellPadding;
}
static void drawTooltip(u64 address, const u8 *data, size_t size) {
void HexEditor::drawTooltip(u64 address, const u8 *data, size_t size) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, scaled(ImVec2(5, 5)));
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getTooltipFunctions()) {
callback(address, data, size);
}
for (const auto &[id, tooltip] : ImHexApi::HexEditor::impl::getTooltips()) {
if (tooltip.getRegion().overlaps({ address, size })) {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::ColorButton(tooltip.getValue().c_str(), ImColor(tooltip.getColor()));
ImGui::SameLine(0, 10);
ImGui::TextUnformatted(tooltip.getValue().c_str());
ImGui::PushStyleColor(ImGuiCol_TableRowBg, tooltip.getColor());
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, tooltip.getColor());
ImGui::EndTable();
ImGui::PopStyleColor(2);
}
ImGui::EndTooltip();
}
}
this->m_tooltipCallback(address, data, size);
ImGui::PopStyleVar();
}
void HexEditor::drawCell(u64 address, u8 *data, size_t size, bool hovered, CellType cellType) {
void HexEditor::drawCell(prv::Provider *provider, u64 address, u8 *data, size_t size, bool hovered, CellType cellType) {
static DataVisualizerAscii asciiVisualizer;
auto provider = ImHexApi::Provider::get();
if (this->m_shouldUpdateEditingValue) {
this->m_shouldUpdateEditingValue = false;
@ -396,7 +334,7 @@ namespace hex {
drawList->AddLine(cellPos + ImVec2(0, cellSize.y), cellPos + cellSize + ImVec2(1, 0), ImColor(SelectionFrameColor), 1.0F);
}
void HexEditor::drawEditor(const ImVec2 &size) {
void HexEditor::drawEditor(prv::Provider *provider, const ImVec2 &size) {
const float SeparatorColumWidth = 6_scaled;
const auto CharacterSize = ImGui::CalcTextSize("0");
@ -439,8 +377,7 @@ namespace hex {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImHexApi::Provider::isValid()) {
auto provider = ImHexApi::Provider::get();
if (provider != nullptr && provider->isReadable()) {
std::pair<Region, bool> validRegion = { Region::Invalid(), false };
const auto isCurrRegionValid = [&validRegion, &provider](u64 address){
@ -481,8 +418,8 @@ namespace hex {
// Query cell colors
if (x < std::ceil(float(validBytes) / bytesPerCell)) {
const auto foregroundColor = queryForegroundColor(byteAddress, &bytes[x * cellBytes], cellBytes);
const auto backgroundColor = queryBackgroundColor(byteAddress, &bytes[x * cellBytes], cellBytes);
const auto foregroundColor = this->m_foregroundColorCallback(byteAddress, &bytes[x * cellBytes], cellBytes);
const auto backgroundColor = this->m_backgroundColorCallback(byteAddress, &bytes[x * cellBytes], cellBytes);
cellColors.emplace_back(
foregroundColor,
@ -549,7 +486,7 @@ namespace hex {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushItemWidth((CharacterSize * maxCharsPerCell).x);
if (isCurrRegionValid(byteAddress))
this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex);
this->drawCell(provider, byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex);
else
ImGui::TextFormatted("{}", std::string(maxCharsPerCell, '?'));
ImGui::PopItemWidth();
@ -606,7 +543,7 @@ namespace hex {
if (!isCurrRegionValid(byteAddress))
ImGui::TextFormatted("?");
else
this->drawCell(byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII);
this->drawCell(provider, byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII);
ImGui::PopItemWidth();
ImGui::PopStyleVar();
}
@ -627,7 +564,7 @@ namespace hex {
do {
const u64 address = y * this->m_bytesPerRow + offset + provider->getBaseAddress() + provider->getCurrentPageAddress();
auto result = queryCustomEncodingData(*this->m_currCustomEncoding, address);
auto result = queryCustomEncodingData(provider, *this->m_currCustomEncoding, address);
offset += std::max<size_t>(1, result.advance);
encodingData.emplace_back(address, result);
@ -684,13 +621,13 @@ namespace hex {
auto fractionPerLine = 1.0 / (this->m_visibleRowCount + 1);
if (y == (u64(clipper.DisplayStart) + 3)) {
if (i128((*this->m_selectionEnd)->value() - provider->getBaseAddress() - provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 3) * this->m_bytesPerRow)) {
if (i128(this->m_selectionEnd.value() - provider->getBaseAddress() - provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 3) * this->m_bytesPerRow)) {
this->m_shouldScrollToSelection = false;
ImGui::SetScrollHereY(fractionPerLine * 5);
}
} else if (y == (u64(clipper.DisplayEnd) - 1)) {
if (i128((*this->m_selectionEnd)->value() - provider->getBaseAddress() - provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) {
if (i128(this->m_selectionEnd.value() - provider->getBaseAddress() - provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) {
this->m_shouldScrollToSelection = false;
ImGui::SetScrollHereY(fractionPerLine * (this->m_visibleRowCount));
}
@ -738,9 +675,9 @@ namespace hex {
if (!this->m_syncScrolling) {
if (this->m_shouldUpdateScrollPosition) {
this->m_shouldUpdateScrollPosition = false;
ImGui::SetScrollY(**this->m_scrollPosition);
ImGui::SetScrollY(this->m_scrollPosition);
} else {
**this->m_scrollPosition = ImGui::GetScrollY();
this->m_scrollPosition = ImGui::GetScrollY();
}
}
@ -756,9 +693,8 @@ namespace hex {
this->m_enteredEditingMode = false;
}
void HexEditor::drawFooter(const ImVec2 &size) {
if (ImHexApi::Provider::isValid()) {
auto provider = ImHexApi::Provider::get();
void HexEditor::drawFooter(prv::Provider *provider, const ImVec2 &size) {
if (provider != nullptr && provider->isReadable()) {
const auto pageCount = provider->getPageCount();
constexpr static u32 MinPage = 1;
@ -835,7 +771,7 @@ namespace hex {
drawTooltip(address, data, bytesPerCell);
auto endAddress = address + bytesPerCell - 1;
auto &selectionStart = **this->m_selectionStart;
auto &selectionStart = this->m_selectionStart;
if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
this->setSelection(selectionStart.value_or(address), endAddress);
@ -852,12 +788,14 @@ namespace hex {
}
}
void HexEditor::draw() {
const auto FooterSize = ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() * 2.3);
const auto TableSize = ImGui::GetContentRegionAvail() - ImVec2(0, FooterSize.y);
void HexEditor::draw(prv::Provider *provider, float height) {
const auto width = ImGui::GetContentRegionAvail().x;
this->drawEditor(TableSize);
this->drawFooter(FooterSize);
const auto FooterSize = ImVec2(width, ImGui::GetTextLineHeightWithSpacing() * 2.3F);
const auto TableSize = ImVec2(width, height - FooterSize.y);
this->drawEditor(provider, TableSize);
this->drawFooter(provider, FooterSize);
this->m_selectionChanged = false;
}

View File

@ -118,10 +118,12 @@ namespace hex {
}
void drawCommentTooltip(const pl::ptrn::Pattern &pattern) {
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && pattern.getComment() != nullptr) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(pattern.getComment()->c_str());
ImGui::EndTooltip();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
if (auto comment = pattern.getComment(); !comment.empty()) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(pattern.getComment().c_str());
ImGui::EndTooltip();
}
}
}

View File

@ -16,13 +16,13 @@ namespace hex::plugin::builtin {
void registerProviders() {
ContentRegistry::Provider::add<prv::FileProvider>(false);
ContentRegistry::Provider::add<prv::NullProvider>(false);
ContentRegistry::Provider::add<prv::DiskProvider>();
ContentRegistry::Provider::add<prv::GDBProvider>();
ContentRegistry::Provider::add<prv::IntelHexProvider>();
ContentRegistry::Provider::add<prv::MotorolaSRECProvider>();
ContentRegistry::Provider::add<prv::MemoryFileProvider>(false);
ContentRegistry::Provider::add<FileProvider>(false);
ContentRegistry::Provider::add<NullProvider>(false);
ContentRegistry::Provider::add<DiskProvider>();
ContentRegistry::Provider::add<GDBProvider>();
ContentRegistry::Provider::add<IntelHexProvider>();
ContentRegistry::Provider::add<MotorolaSRECProvider>();
ContentRegistry::Provider::add<MemoryFileProvider>(false);
ProjectFile::registerHandler({
.basePath = "providers",

View File

@ -24,7 +24,7 @@
#define lseek lseek64
#endif
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
DiskProvider::DiskProvider() : Provider() {

View File

@ -10,7 +10,7 @@
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
bool FileProvider::isAvailable() const {
return this->m_mappedFile != nullptr;

View File

@ -13,7 +13,7 @@
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
using namespace std::chrono_literals;

View File

@ -10,7 +10,7 @@
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
namespace intel_hex {

View File

@ -8,7 +8,7 @@
#include <hex/api/event.hpp>
#include <hex/helpers/file.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
bool MemoryFileProvider::open() {
this->m_data.resize(1);

View File

@ -6,7 +6,7 @@
#include <hex/helpers/file.hpp>
#include <hex/helpers/fmt.hpp>
namespace hex::plugin::builtin::prv {
namespace hex::plugin::builtin {
namespace motorola_srec {

View File

@ -463,14 +463,66 @@ namespace hex::plugin::builtin {
/* Hex Editor */
ViewHexEditor::ViewHexEditor() : View("hex.builtin.view.hex_editor.name") {
this->m_hexEditor = std::make_unique<HexEditor>(&this->m_selectionStart, &this->m_selectionEnd, &this->m_scrollPosition);
this->m_hexEditor.setForegroundHighlightCallback([](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
std::optional<color_t> result;
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions()) {
if (auto color = callback(address, data, size, result.has_value()); color.has_value())
result = color;
}
EventManager::subscribe<EventProviderChanged>(this, [this](auto *, auto *newProvider) {
auto &data = ProviderExtraData::get(newProvider).editor;
if (result.has_value())
return result;
this->m_selectionStart = &data.selectionStart;
this->m_selectionEnd = &data.selectionEnd;
this->m_scrollPosition = &data.scrollPosition;
for (const auto &[id, highlighting] : ImHexApi::HexEditor::impl::getForegroundHighlights()) {
if (highlighting.getRegion().overlaps({ address, size }))
return highlighting.getColor();
}
return std::nullopt;
});
this->m_hexEditor.setBackgroundHighlightCallback([](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
std::optional<color_t> result;
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions()) {
if (auto color = callback(address, data, size, result.has_value()); color.has_value())
return color.value();
}
if (result.has_value())
return result;
for (const auto &[id, highlighting] : ImHexApi::HexEditor::impl::getBackgroundHighlights()) {
if (highlighting.getRegion().overlaps({ address, size }))
return highlighting.getColor();
}
return std::nullopt;
});
this->m_hexEditor.setTooltipCallback([](u64 address, const u8 *data, size_t size) {
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getTooltipFunctions()) {
callback(address, data, size);
}
for (const auto &[id, tooltip] : ImHexApi::HexEditor::impl::getTooltips()) {
if (tooltip.getRegion().overlaps({ address, size })) {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::ColorButton(tooltip.getValue().c_str(), ImColor(tooltip.getColor()));
ImGui::SameLine(0, 10);
ImGui::TextUnformatted(tooltip.getValue().c_str());
ImGui::PushStyleColor(ImGuiCol_TableRowBg, tooltip.getColor());
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, tooltip.getColor());
ImGui::EndTable();
ImGui::PopStyleColor(2);
}
ImGui::EndTooltip();
}
}
});
this->registerShortcuts();
@ -532,7 +584,7 @@ namespace hex::plugin::builtin {
void ViewHexEditor::drawContent() {
if (ImGui::Begin(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
this->m_hexEditor->draw();
this->m_hexEditor.draw(ImHexApi::Provider::get());
this->drawPopup();
}
ImGui::End();
@ -645,20 +697,20 @@ namespace hex::plugin::builtin {
ShortcutManager::addShortcut(this, Keys::Up, [this] {
auto selection = getSelection();
if (selection.getEndAddress() >= this->m_hexEditor->getBytesPerRow()) {
auto pos = selection.getEndAddress() - this->m_hexEditor->getBytesPerRow();
if (selection.getEndAddress() >= this->m_hexEditor.getBytesPerRow()) {
auto pos = selection.getEndAddress() - this->m_hexEditor.getBytesPerRow();
this->setSelection(pos, pos);
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::Down, [this] {
auto selection = getSelection();
auto pos = selection.getEndAddress() + this->m_hexEditor->getBytesPerRow();
auto pos = selection.getEndAddress() + this->m_hexEditor.getBytesPerRow();
this->setSelection(pos, pos);
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, Keys::Left, [this] {
auto selection = getSelection();
@ -666,8 +718,8 @@ namespace hex::plugin::builtin {
if (selection.getEndAddress() > 0) {
auto pos = selection.getEndAddress() - 1;
this->setSelection(pos, pos);
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::Right, [this] {
@ -675,78 +727,78 @@ namespace hex::plugin::builtin {
auto pos = selection.getEndAddress() + 1;
this->setSelection(pos, pos);
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, Keys::PageUp, [this] {
auto selection = getSelection();
u64 visibleByteCount = this->m_hexEditor->getBytesPerRow() * this->m_hexEditor->getVisibleRowCount();
u64 visibleByteCount = this->m_hexEditor.getBytesPerRow() * this->m_hexEditor.getVisibleRowCount();
if (selection.getEndAddress() >= visibleByteCount) {
auto pos = selection.getEndAddress() - visibleByteCount;
this->setSelection(pos, pos);
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::PageDown, [this] {
auto selection = getSelection();
auto pos = selection.getEndAddress() + (this->m_hexEditor->getBytesPerRow() * this->m_hexEditor->getVisibleRowCount());
auto pos = selection.getEndAddress() + (this->m_hexEditor.getBytesPerRow() * this->m_hexEditor.getVisibleRowCount());
this->setSelection(pos, pos);
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
// Move selection around
ShortcutManager::addShortcut(this, SHIFT + Keys::Up, [this] {
auto selection = getSelection();
this->setSelection(std::max<u64>(selection.getStartAddress(), this->m_hexEditor->getBytesPerRow()) - this->m_hexEditor->getBytesPerRow(), selection.getEndAddress());
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->setSelection(std::max<u64>(selection.getStartAddress(), this->m_hexEditor.getBytesPerRow()) - this->m_hexEditor.getBytesPerRow(), selection.getEndAddress());
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, SHIFT + Keys::Down, [this] {
auto selection = getSelection();
this->setSelection(selection.getStartAddress() + this->m_hexEditor->getBytesPerRow(), selection.getEndAddress());
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->setSelection(selection.getStartAddress() + this->m_hexEditor.getBytesPerRow(), selection.getEndAddress());
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, SHIFT + Keys::Left, [this] {
auto selection = getSelection();
this->setSelection(std::max<u64>(selection.getStartAddress(), 1) - 1, selection.getEndAddress());
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, SHIFT + Keys::Right, [this] {
auto selection = getSelection();
this->setSelection(selection.getStartAddress() + 1, selection.getEndAddress());
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, Keys::PageUp, [this] {
auto selection = getSelection();
u64 visibleByteCount = this->m_hexEditor->getBytesPerRow() * this->m_hexEditor->getVisibleRowCount();
u64 visibleByteCount = this->m_hexEditor.getBytesPerRow() * this->m_hexEditor.getVisibleRowCount();
if (selection.getEndAddress() >= visibleByteCount) {
auto pos = selection.getEndAddress() - visibleByteCount;
this->setSelection(pos, selection.getEndAddress());
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::PageDown, [this] {
auto selection = getSelection();
auto pos = selection.getEndAddress() + (this->m_hexEditor->getBytesPerRow() * this->m_hexEditor->getVisibleRowCount());
auto pos = selection.getEndAddress() + (this->m_hexEditor.getBytesPerRow() * this->m_hexEditor.getVisibleRowCount());
this->setSelection(pos, selection.getEndAddress());
this->m_hexEditor->scrollToSelection();
this->m_hexEditor->jumpIfOffScreen();
this->m_hexEditor.scrollToSelection();
this->m_hexEditor.jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, CTRL + Keys::G, [this] {
@ -826,9 +878,25 @@ namespace hex::plugin::builtin {
region = getSelection();
});
EventManager::subscribe<EventProviderChanged>(this, [this](auto, auto) {
this->m_hexEditor->forceUpdateScrollPosition();
EventManager::subscribe<EventProviderChanged>(this, [this](auto *oldProvider, auto *newProvider) {
if (oldProvider != nullptr) {
auto &oldData = ProviderExtraData::get(oldProvider).editor;
auto selection = this->m_hexEditor.getSelection();
oldData.selectionStart = selection.getStartAddress();
oldData.selectionEnd = selection.getEndAddress();
oldData.scrollPosition = this->m_hexEditor.getScrollPosition();
}
if (newProvider != nullptr) {
auto &newData = ProviderExtraData::get(newProvider).editor;
this->m_hexEditor.setSelectionUnchecked(newData.selectionStart, newData.selectionEnd);
this->m_hexEditor.setScrollPosition(newData.scrollPosition);
}
this->m_hexEditor.forceUpdateScrollPosition();
if (isSelectionValid())
EventManager::post<EventRegionSelected>(getSelection());
});
@ -867,7 +935,7 @@ namespace hex::plugin::builtin {
View::showFileChooserPopup(paths, { {"Thingy Table File", "tbl"} },
[this](const auto &path) {
this->m_hexEditor->setCustomEncoding(EncodingFile(EncodingFile::Type::Thingy, path));
this->m_hexEditor.setCustomEncoding(EncodingFile(EncodingFile::Type::Thingy, path));
});
}
});

View File

@ -129,6 +129,10 @@ namespace hex::plugin::builtin {
this->drawVariableSettings(settingsSize, extraData.patternVariables);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.sections"_lang)) {
this->drawSectionSelector(settingsSize, extraData.sections);
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
@ -431,6 +435,58 @@ namespace hex::plugin::builtin {
ImGui::EndChild();
}
void ViewPatternEditor::drawSectionSelector(ImVec2 size, std::map<u64, pl::api::Section> &sections) {
if (ImGui::BeginTable("##sections_table", 3, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, size)) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.5F);
ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthStretch, 0.5F);
ImGui::TableSetupColumn("##button", ImGuiTableColumnFlags_WidthFixed, 20_scaled);
ImGui::TableHeadersRow();
for (auto &[id, section] : sections) {
ImGui::PushID(id);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(section.name.c_str());
ImGui::TableNextColumn();
ImGui::TextFormatted("{} | 0x{:02X}", hex::toByteString(section.data.size()), section.data.size());
ImGui::TableNextColumn();
if (ImGui::IconButton(ICON_VS_OPEN_PREVIEW, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
this->m_sectionProvider = std::make_unique<MemoryFileProvider>();
this->m_sectionProvider->resize(section.data.size());
this->m_sectionProvider->writeRaw(0, section.data.data(), section.data.size());
this->m_hexEditor.setBackgroundHighlightCallback([this, id](u64 address, const u8 *, size_t) -> std::optional<color_t> {
if (this->m_runningEvaluators != 0)
return std::nullopt;
if (!ImHexApi::Provider::isValid())
return std::nullopt;
std::optional<ImColor> color;
for (const auto &pattern : ProviderExtraData::getCurrent().patternLanguage.runtime->getPatternsAtAddress(address, id)) {
if (pattern->isHidden())
continue;
if (color.has_value())
color = ImAlphaBlendColors(*color, pattern->getColor());
else
color = pattern->getColor();
}
return color;
});
}
ImGui::PopID();
}
ImGui::EndTable();
}
}
void ViewPatternEditor::drawAlwaysVisible() {
auto provider = ImHexApi::Provider::get();
@ -470,6 +526,18 @@ namespace hex::plugin::builtin {
ImGui::EndPopup();
}
auto open = this->m_sectionProvider != nullptr && this->m_sectionProvider->isReadable();
if (open) {
ImGui::SetNextWindowSize(scaled(ImVec2(500, 650)), ImGuiCond_Appearing);
if (ImGui::Begin("hex.builtin.view.pattern_editor.section_popup"_lang, &open)) {
this->m_hexEditor.draw(this->m_sectionProvider.get());
}
ImGui::End();
}
if (!open)
this->m_sectionProvider = nullptr;
}
@ -517,12 +585,12 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
ImGui::TextFormatted(" {}", pattern->getEndian() == std::endian::little ? "hex.builtin.common.little"_lang : "hex.builtin.common.big"_lang);
if (const auto &comment = pattern->getComment(); comment != nullptr) {
if (const auto &comment = pattern->getComment(); !comment.empty()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextFormatted("{} ", "hex.builtin.common.comment"_lang);
ImGui::TableNextColumn();
ImGui::TextWrapped(" \"%s\"", comment->c_str());
ImGui::TextWrapped(" \"%s\"", comment.c_str());
}
ImGui::EndTable();
@ -626,6 +694,8 @@ namespace hex::plugin::builtin {
ON_SCOPE_EXIT {
patternLanguage.lastEvaluationLog = runtime->getConsoleLog();
patternLanguage.lastEvaluationOutVars = runtime->getOutVariables();
patternLanguage.sections = runtime->getSections();
this->m_runningEvaluators--;
this->m_lastEvaluationProcessed = false;