feat: Finish up work on new pl section system
This commit is contained in:
parent
23ce2ec271
commit
4c5d2f6ebb
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
||||
Subproject commit 2fc96aedca0f665957eec878d75403eff7de5a91
|
||||
Subproject commit a74070f38e7deae8c82e827f3a84a0e2619d5981
|
@ -106,7 +106,7 @@ namespace hex {
|
||||
EVENT_DEF(EventDataChanged);
|
||||
EVENT_DEF(EventHighlightingChanged);
|
||||
EVENT_DEF(EventWindowClosing, GLFWwindow *);
|
||||
EVENT_DEF(EventRegionSelected, Region);
|
||||
EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion);
|
||||
EVENT_DEF(EventSettingsChanged);
|
||||
EVENT_DEF(EventAbnormalTermination, int);
|
||||
EVENT_DEF(EventOSThemeChanged);
|
||||
@ -138,6 +138,4 @@ namespace hex {
|
||||
EVENT_DEF(RequestShowYesNoQuestionPopup, std::string, std::function<void()>, std::function<void()>);
|
||||
EVENT_DEF(RequestShowFileChooserPopup, std::vector<std::fs::path>, std::vector<nfdfilteritem_t>, std::function<void(std::fs::path)>);
|
||||
|
||||
EVENT_DEF(QuerySelection, std::optional<Region> &);
|
||||
|
||||
}
|
@ -64,6 +64,14 @@ namespace hex {
|
||||
color_t m_color = 0x00;
|
||||
};
|
||||
|
||||
struct ProviderRegion : public Region {
|
||||
prv::Provider *provider;
|
||||
|
||||
[[nodiscard]] prv::Provider *getProvider() const { return this->provider; }
|
||||
|
||||
[[nodiscard]] Region getRegion() const { return { this->address, this->size }; }
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
|
||||
@ -75,6 +83,7 @@ namespace hex {
|
||||
std::map<u32, Tooltip> &getTooltips();
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions();
|
||||
|
||||
void setCurrentSelection(ProviderRegion region);
|
||||
}
|
||||
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color);
|
||||
@ -96,9 +105,10 @@ namespace hex {
|
||||
void removeForegroundHighlightingProvider(u32 id);
|
||||
|
||||
bool isSelectionValid();
|
||||
std::optional<Region> getSelection();
|
||||
void setSelection(const Region ®ion);
|
||||
void setSelection(u64 address, size_t size);
|
||||
std::optional<ProviderRegion> getSelection();
|
||||
void setSelection(const Region ®ion, prv::Provider *provider = nullptr);
|
||||
void setSelection(const ProviderRegion ®ion);
|
||||
void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,11 @@ namespace hex {
|
||||
return s_tooltipFunctions;
|
||||
}
|
||||
|
||||
static std::optional<ProviderRegion> s_currentSelection;
|
||||
void setCurrentSelection(std::optional<ProviderRegion> region) {
|
||||
s_currentSelection = region;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color) {
|
||||
@ -181,19 +186,20 @@ namespace hex {
|
||||
return getSelection().has_value();
|
||||
}
|
||||
|
||||
std::optional<Region> getSelection() {
|
||||
std::optional<Region> selection;
|
||||
EventManager::post<QuerySelection>(selection);
|
||||
|
||||
return selection;
|
||||
std::optional<ProviderRegion> getSelection() {
|
||||
return impl::s_currentSelection;
|
||||
}
|
||||
|
||||
void setSelection(const Region ®ion) {
|
||||
void setSelection(const Region ®ion, prv::Provider *provider) {
|
||||
setSelection(ProviderRegion { region, provider == nullptr ? Provider::get() : provider });
|
||||
}
|
||||
|
||||
void setSelection(const ProviderRegion ®ion) {
|
||||
EventManager::post<RequestSelectionChange>(region);
|
||||
}
|
||||
|
||||
void setSelection(u64 address, size_t size) {
|
||||
setSelection({ address, size });
|
||||
void setSelection(u64 address, size_t size, prv::Provider *provider) {
|
||||
setSelection({ { address, size }, provider == nullptr ? Provider::get() : provider });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -54,8 +54,9 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/views/view_find.cpp
|
||||
|
||||
source/content/helpers/math_evaluator.cpp
|
||||
source/content/helpers/pattern_drawer.cpp
|
||||
source/content/helpers/hex_editor.cpp
|
||||
|
||||
source/ui/hex_editor.cpp
|
||||
source/ui/pattern_drawer.cpp
|
||||
|
||||
source/lang/de_DE.cpp
|
||||
source/lang/en_US.cpp
|
||||
|
@ -12,9 +12,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool isReadable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return true; }
|
||||
[[nodiscard]] bool isResizable() const override { return true; }
|
||||
[[nodiscard]] bool isSavable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return !this->m_readOnly; }
|
||||
[[nodiscard]] bool isResizable() const override { return !this->m_readOnly; }
|
||||
[[nodiscard]] bool isSavable() const override { return !this->m_readOnly; }
|
||||
|
||||
[[nodiscard]] bool open() override;
|
||||
void close() override { }
|
||||
@ -42,8 +42,11 @@ namespace hex::plugin::builtin {
|
||||
void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); }
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; }
|
||||
|
||||
void setReadOnly(bool readOnly) { this->m_readOnly = readOnly; }
|
||||
|
||||
private:
|
||||
std::vector<u8> m_data;
|
||||
bool m_readOnly = false;
|
||||
};
|
||||
|
||||
}
|
@ -33,6 +33,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
u64 m_startAddress = 0;
|
||||
size_t m_validBytes = 0;
|
||||
prv::Provider *m_selectedProvider = nullptr;
|
||||
std::atomic<bool> m_dataValid = false;
|
||||
std::vector<InspectorCacheEntry> m_cachedData, m_workData;
|
||||
TaskHolder m_updateTask;
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
#include <content/helpers/hex_editor.hpp>
|
||||
#include <ui/hex_editor.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@ -70,7 +70,7 @@ namespace hex::plugin::builtin {
|
||||
void registerEvents();
|
||||
void registerMenuItems();
|
||||
|
||||
HexEditor m_hexEditor;
|
||||
ui::HexEditor m_hexEditor;
|
||||
|
||||
bool m_shouldOpenPopup = false;
|
||||
std::unique_ptr<Popup> m_currPopup;
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <content/helpers/pattern_drawer.hpp>
|
||||
#include <ui/pattern_drawer.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <vector>
|
||||
@ -20,7 +20,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
private:
|
||||
std::map<hex::prv::Provider *, std::vector<pl::ptrn::Pattern*>> m_sortedPatterns;
|
||||
hex::PatternDrawer m_patternDrawer;
|
||||
ui::PatternDrawer m_patternDrawer;
|
||||
};
|
||||
|
||||
}
|
@ -6,7 +6,8 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
#include <content/helpers/hex_editor.hpp>
|
||||
#include <ui/hex_editor.hpp>
|
||||
#include <ui/pattern_drawer.hpp>
|
||||
#include <content/providers/memory_file_provider.hpp>
|
||||
|
||||
#include <cstring>
|
||||
@ -14,6 +15,7 @@
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <TextEditor.h>
|
||||
|
||||
@ -63,9 +65,7 @@ namespace hex::plugin::builtin {
|
||||
bool m_syncPatternSourceCode = false;
|
||||
bool m_autoLoadPatterns = true;
|
||||
|
||||
std::unique_ptr<MemoryFileProvider> m_sectionProvider = nullptr;
|
||||
HexEditor m_hexEditor;
|
||||
|
||||
std::map<prv::Provider*, std::move_only_function<void()>> m_sectionWindowDrawer;
|
||||
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);
|
||||
|
@ -17,21 +17,22 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/providers/buffered_reader.hpp>
|
||||
|
||||
namespace hex {
|
||||
namespace hex::plugin::builtin::ui {
|
||||
|
||||
class HexEditor {
|
||||
public:
|
||||
HexEditor();
|
||||
explicit HexEditor(prv::Provider *provider = nullptr);
|
||||
~HexEditor();
|
||||
void draw(prv::Provider *provider, float height = ImGui::GetContentRegionAvail().y);
|
||||
void draw(float height = ImGui::GetContentRegionAvail().y);
|
||||
|
||||
void setProvider(prv::Provider *provider) { this->m_provider = provider; }
|
||||
private:
|
||||
enum class CellType { None, Hex, ASCII };
|
||||
|
||||
void drawCell(prv::Provider *provider, u64 address, u8 *data, size_t size, bool hovered, CellType cellType);
|
||||
void drawCell(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(prv::Provider *provider, const ImVec2 &size);
|
||||
void drawFooter(prv::Provider *provider, const ImVec2 &size);
|
||||
void drawEditor(const ImVec2 &size);
|
||||
void drawFooter(const ImVec2 &size);
|
||||
void drawTooltip(u64 address, const u8 *data, size_t size);
|
||||
|
||||
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
|
||||
@ -47,9 +48,7 @@ namespace hex {
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return;
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
|
||||
const size_t maxAddress = this->m_provider->getActualSize() + this->m_provider->getBaseAddress() - 1;
|
||||
|
||||
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
|
||||
|
||||
@ -57,7 +56,8 @@ namespace hex {
|
||||
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
||||
|
||||
if (this->m_selectionChanged) {
|
||||
EventManager::post<EventRegionSelected>(this->getSelection());
|
||||
auto selection = this->getSelection();
|
||||
EventManager::post<EventRegionSelected>(ImHexApi::HexEditor::ProviderRegion{ { selection.address, selection.size }, this->m_provider });
|
||||
this->m_shouldModifyValue = true;
|
||||
}
|
||||
}
|
||||
@ -161,6 +161,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
prv::Provider *m_provider;
|
||||
|
||||
std::optional<u64> m_selectionStart;
|
||||
std::optional<u64> m_selectionEnd;
|
||||
float m_scrollPosition = 0;
|
@ -4,14 +4,18 @@
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
namespace hex::plugin::builtin::ui {
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void draw(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, float height = 0.0F);
|
||||
|
||||
private:
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
public:
|
||||
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
|
||||
@ -39,5 +43,6 @@ namespace hex {
|
||||
|
||||
private:
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
std::vector<pl::ptrn::Pattern*> m_sortedPatterns;
|
||||
};
|
||||
}
|
@ -3,6 +3,9 @@
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace pl::ptrn { class Pattern; }
|
||||
namespace hex::prv { class Provider; }
|
||||
|
||||
namespace hex::plugin::builtin::ui {
|
||||
|
||||
|
||||
|
@ -466,7 +466,7 @@ namespace hex::plugin::builtin {
|
||||
class NodeDataSelection : public dp::Node {
|
||||
public:
|
||||
NodeDataSelection() : Node("hex.builtin.nodes.data_access.selection.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.size") }) {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](const Region ®ion) {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](const auto ®ion) {
|
||||
this->m_address = region.address;
|
||||
this->m_size = region.size;
|
||||
});
|
||||
|
@ -18,22 +18,26 @@ namespace hex::plugin::builtin {
|
||||
using NumberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle;
|
||||
|
||||
ViewDataInspector::ViewDataInspector() : View("hex.builtin.view.data_inspector.name") {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](const auto ®ion) {
|
||||
if (!ImHexApi::Provider::isValid() || region == Region::Invalid()) {
|
||||
this->m_validBytes = 0;
|
||||
} else {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
this->m_validBytes = u64(provider->getActualSize() - region.address);
|
||||
this->m_validBytes = u64(region.getProvider()->getActualSize() - region.address);
|
||||
this->m_startAddress = region.address;
|
||||
this->m_selectedProvider = region.getProvider();
|
||||
}
|
||||
|
||||
this->m_shouldInvalidate = true;
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderClosed>(this, [this](const auto*) {
|
||||
this->m_selectedProvider = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
ViewDataInspector::~ViewDataInspector() {
|
||||
EventManager::unsubscribe<EventRegionSelected>(this);
|
||||
EventManager::unsubscribe<EventProviderClosed>(this);
|
||||
}
|
||||
|
||||
void ViewDataInspector::drawContent() {
|
||||
@ -47,17 +51,18 @@ namespace hex::plugin::builtin {
|
||||
|
||||
this->m_updateTask = TaskManager::createBackgroundTask("Update Inspector",
|
||||
[this, validBytes = this->m_validBytes, startAddress = this->m_startAddress, endian = this->m_endian, invert = this->m_invert, numberDisplayStyle = this->m_numberDisplayStyle](auto &) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
this->m_workData.clear();
|
||||
|
||||
if (this->m_selectedProvider == nullptr)
|
||||
return;
|
||||
|
||||
// Decode bytes using registered inspectors
|
||||
for (auto &entry : ContentRegistry::DataInspector::getEntries()) {
|
||||
if (validBytes < entry.requiredSize)
|
||||
continue;
|
||||
|
||||
std::vector<u8> buffer(validBytes > entry.maxSize ? entry.maxSize : validBytes);
|
||||
provider->read(startAddress, buffer.data(), buffer.size());
|
||||
this->m_selectedProvider->read(startAddress, buffer.data(), buffer.size());
|
||||
|
||||
if (invert) {
|
||||
for (auto &byte : buffer)
|
||||
@ -81,14 +86,14 @@ namespace hex::plugin::builtin {
|
||||
pl::PatternLanguage runtime;
|
||||
ContentRegistry::PatternLanguage::configureRuntime(runtime, nullptr);
|
||||
|
||||
runtime.setDataSource([invert, provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
runtime.setDataSource([this, invert](u64 offset, u8 *buffer, size_t size) {
|
||||
this->m_selectedProvider->read(offset, buffer, size);
|
||||
|
||||
if (invert) {
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer[i] ^= 0xFF;
|
||||
}
|
||||
}, provider->getBaseAddress(), provider->getActualSize());
|
||||
}, this->m_selectedProvider->getBaseAddress(), this->m_selectedProvider->getActualSize());
|
||||
|
||||
runtime.setDangerousFunctionCallHandler([]{ return false; });
|
||||
runtime.setDefaultEndian(endian);
|
||||
@ -139,9 +144,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.data_inspector.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
if (ImHexApi::Provider::isValid() && provider->isReadable() && this->m_validBytes > 0) {
|
||||
if (this->m_selectedProvider != nullptr && this->m_selectedProvider->isReadable() && this->m_validBytes > 0) {
|
||||
if (ImGui::BeginTable("##datainspector", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg, ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * (this->m_cachedData.size() + 1)))) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("hex.builtin.view.data_inspector.table.name"_lang);
|
||||
@ -177,7 +180,7 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::InputText("##InspectorLineEditing", this->m_editingValue, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
auto bytes = (*editingFunction)(this->m_editingValue, this->m_endian);
|
||||
|
||||
provider->write(this->m_startAddress, bytes.data(), bytes.size());
|
||||
this->m_selectedProvider->write(this->m_startAddress, bytes.data(), bytes.size());
|
||||
this->m_editingValue.clear();
|
||||
editing = false;
|
||||
this->m_shouldInvalidate = true;
|
||||
|
@ -443,7 +443,7 @@ namespace hex::plugin::builtin {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
return Region { provider->getBaseAddress(), provider->getActualSize() };
|
||||
} else {
|
||||
return ImHexApi::HexEditor::getSelection().value();
|
||||
return ImHexApi::HexEditor::getSelection()->getRegion();
|
||||
}
|
||||
}();
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](const Region &) {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](const auto &) {
|
||||
for (auto &function : this->m_hashFunctions)
|
||||
function.reset();
|
||||
});
|
||||
|
@ -584,7 +584,10 @@ 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(ImHexApi::Provider::get());
|
||||
this->m_hexEditor.setProvider(ImHexApi::Provider::get());
|
||||
|
||||
this->m_hexEditor.draw();
|
||||
|
||||
this->drawPopup();
|
||||
}
|
||||
ImGui::End();
|
||||
@ -686,11 +689,13 @@ namespace hex::plugin::builtin {
|
||||
|
||||
// Remove selection
|
||||
ShortcutManager::addShortcut(this, Keys::Escape, [this] {
|
||||
auto &data = ProviderExtraData::getCurrent().editor;
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto &data = ProviderExtraData::get(provider).editor;
|
||||
|
||||
data.selectionStart.reset();
|
||||
data.selectionEnd.reset();
|
||||
EventManager::post<EventRegionSelected>(this->getSelection());
|
||||
|
||||
EventManager::post<EventRegionSelected>(ImHexApi::HexEditor::ProviderRegion{ this->getSelection(), provider });
|
||||
});
|
||||
|
||||
// Move cursor around
|
||||
@ -873,11 +878,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<QuerySelection>(this, [this](auto ®ion) {
|
||||
if (isSelectionValid())
|
||||
region = getSelection();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>(this, [this](auto *oldProvider, auto *newProvider) {
|
||||
if (oldProvider != nullptr) {
|
||||
auto &oldData = ProviderExtraData::get(oldProvider).editor;
|
||||
@ -897,8 +897,9 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
this->m_hexEditor.forceUpdateScrollPosition();
|
||||
if (isSelectionValid())
|
||||
EventManager::post<EventRegionSelected>(getSelection());
|
||||
if (isSelectionValid()) {
|
||||
EventManager::post<EventRegionSelected>(ImHexApi::HexEditor::ProviderRegion{ this->getSelection(), newProvider });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -25,89 +25,6 @@ namespace hex::plugin::builtin {
|
||||
EventManager::unsubscribe<EventHighlightingChanged>(this);
|
||||
}
|
||||
|
||||
static bool sortPatterns(prv::Provider *provider, const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) {
|
||||
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getDisplayName() > right->getDisplayName();
|
||||
else
|
||||
return left->getDisplayName() < right->getDisplayName();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getOffset() > right->getOffset();
|
||||
else
|
||||
return left->getOffset() < right->getOffset();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getSize() > right->getSize();
|
||||
else
|
||||
return left->getSize() < right->getSize();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) {
|
||||
size_t biggerSize = std::max(left->getSize(), right->getSize());
|
||||
std::vector<u8> leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00);
|
||||
|
||||
provider->read(left->getOffset(), leftBuffer.data(), left->getSize());
|
||||
provider->read(right->getOffset(), rightBuffer.data(), right->getSize());
|
||||
|
||||
if (left->getEndian() != std::endian::native)
|
||||
std::reverse(leftBuffer.begin(), leftBuffer.end());
|
||||
if (right->getEndian() != std::endian::native)
|
||||
std::reverse(rightBuffer.begin(), rightBuffer.end());
|
||||
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return leftBuffer > rightBuffer;
|
||||
else
|
||||
return leftBuffer < rightBuffer;
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getTypeName() > right->getTypeName();
|
||||
else
|
||||
return left->getTypeName() < right->getTypeName();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getColor() > right->getColor();
|
||||
else
|
||||
return left->getColor() < right->getColor();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool beginPatternTable(prv::Provider *&provider, const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns) {
|
||||
if (ImGui::BeginTable("##Patterntable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.var_name"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("name"));
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.color"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("color"));
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.offset"_lang, ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort, 0, ImGui::GetID("offset"));
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.size"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("size"));
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.type"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("type"));
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.value"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("value"));
|
||||
|
||||
auto sortSpecs = ImGui::TableGetSortSpecs();
|
||||
|
||||
if (!patterns.empty() && (sortSpecs->SpecsDirty || sortedPatterns.empty())) {
|
||||
sortedPatterns.clear();
|
||||
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::ptrn::Pattern> &pattern) {
|
||||
return pattern.get();
|
||||
});
|
||||
|
||||
std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs, &provider](pl::ptrn::Pattern *left, pl::ptrn::Pattern *right) -> bool {
|
||||
return sortPatterns(provider, sortSpecs, left, right);
|
||||
});
|
||||
|
||||
for (auto &pattern : sortedPatterns)
|
||||
pattern->sort([&sortSpecs, &provider](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){
|
||||
return sortPatterns(provider, sortSpecs, left, right);
|
||||
});
|
||||
|
||||
sortSpecs->SpecsDirty = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewPatternData::drawContent() {
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.pattern_data.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
@ -123,18 +40,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}();
|
||||
|
||||
auto &sortedPatterns = this->m_sortedPatterns[ImHexApi::Provider::get()];
|
||||
if (beginPatternTable(provider, patterns, sortedPatterns)) {
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
if (!sortedPatterns.empty()) {
|
||||
for (auto &pattern : sortedPatterns) {
|
||||
this->m_patternDrawer.draw(*pattern);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
this->m_patternDrawer.draw(patterns);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
@ -114,7 +114,7 @@ namespace hex::plugin::builtin {
|
||||
this->m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, true);
|
||||
|
||||
auto settingsSize = ImGui::GetContentRegionAvail();
|
||||
settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5;
|
||||
settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5F;
|
||||
|
||||
if (ImGui::BeginTabBar("##settings")) {
|
||||
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) {
|
||||
@ -438,8 +438,8 @@ namespace hex::plugin::builtin {
|
||||
void ViewPatternEditor::drawSectionSelector(ImVec2 size, std::map<u64, pl::api::Section> §ions) {
|
||||
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("hex.builtin.common.name"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F);
|
||||
ImGui::TableSetupColumn("hex.builtin.common.size"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F);
|
||||
ImGui::TableSetupColumn("##button", ImGuiTableColumnFlags_WidthFixed, 20_scaled);
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
@ -455,11 +455,13 @@ namespace hex::plugin::builtin {
|
||||
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());
|
||||
auto dataProvider = std::make_unique<MemoryFileProvider>();
|
||||
dataProvider->resize(section.data.size());
|
||||
dataProvider->writeRaw(0x00, section.data.data(), section.data.size());
|
||||
dataProvider->setReadOnly(true);
|
||||
|
||||
this->m_hexEditor.setBackgroundHighlightCallback([this, id](u64 address, const u8 *, size_t) -> std::optional<color_t> {
|
||||
auto hexEditor = ui::HexEditor();
|
||||
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())
|
||||
@ -478,6 +480,15 @@ namespace hex::plugin::builtin {
|
||||
|
||||
return color;
|
||||
});
|
||||
|
||||
auto patternProvider = ImHexApi::Provider::get();
|
||||
|
||||
this->m_sectionWindowDrawer[patternProvider] = [id, patternProvider, dataProvider = std::move(dataProvider), hexEditor, patternDrawer = ui::PatternDrawer()] mutable {
|
||||
hexEditor.setProvider(dataProvider.get());
|
||||
hexEditor.draw(480_scaled);
|
||||
|
||||
patternDrawer.draw(ProviderExtraData::get(patternProvider).patternLanguage.runtime->getAllPatterns(id), 150_scaled);
|
||||
};
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@ -527,17 +538,17 @@ namespace hex::plugin::builtin {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
auto open = this->m_sectionProvider != nullptr && this->m_sectionProvider->isReadable();
|
||||
auto open = this->m_sectionWindowDrawer.contains(provider);
|
||||
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());
|
||||
if (ImGui::Begin("hex.builtin.view.pattern_editor.section_popup"_lang, &open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
this->m_sectionWindowDrawer[provider]();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (!open)
|
||||
this->m_sectionProvider = nullptr;
|
||||
this->m_sectionWindowDrawer.erase(provider);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <content/helpers/hex_editor.hpp>
|
||||
#include <ui/hex_editor.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
@ -7,7 +7,7 @@
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
namespace hex {
|
||||
namespace hex::plugin::builtin::ui {
|
||||
|
||||
/* Data Visualizer */
|
||||
|
||||
@ -70,7 +70,7 @@ namespace hex {
|
||||
|
||||
/* Hex Editor */
|
||||
|
||||
HexEditor::HexEditor() {
|
||||
HexEditor::HexEditor(prv::Provider *provider) : m_provider(provider) {
|
||||
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> {
|
||||
@ -237,7 +237,7 @@ namespace hex {
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
void HexEditor::drawCell(prv::Provider *provider, u64 address, u8 *data, size_t size, bool hovered, CellType cellType) {
|
||||
void HexEditor::drawCell(u64 address, u8 *data, size_t size, bool hovered, CellType cellType) {
|
||||
static DataVisualizerAscii asciiVisualizer;
|
||||
|
||||
if (this->m_shouldUpdateEditingValue) {
|
||||
@ -253,7 +253,7 @@ namespace hex {
|
||||
else
|
||||
asciiVisualizer.draw(address, data, size, this->m_upperCaseHex);
|
||||
|
||||
if (hovered && provider->isWritable()) {
|
||||
if (hovered && this->m_provider->isWritable()) {
|
||||
// Enter editing mode when double-clicking a cell
|
||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||
this->m_editingAddress = address;
|
||||
@ -278,13 +278,13 @@ namespace hex {
|
||||
|
||||
if (shouldExitEditingMode || this->m_shouldModifyValue) {
|
||||
|
||||
provider->write(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size());
|
||||
this->m_provider->write(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size());
|
||||
|
||||
if (!this->m_selectionChanged && !ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
auto nextEditingAddress = *this->m_editingAddress + this->m_currDataVisualizer->getBytesPerCell();
|
||||
this->setSelection(nextEditingAddress, nextEditingAddress);
|
||||
|
||||
if (nextEditingAddress >= provider->getSize())
|
||||
if (nextEditingAddress >= this->m_provider->getSize())
|
||||
this->m_editingAddress = std::nullopt;
|
||||
else
|
||||
this->m_editingAddress = nextEditingAddress;
|
||||
@ -334,7 +334,7 @@ namespace hex {
|
||||
drawList->AddLine(cellPos + ImVec2(0, cellSize.y), cellPos + cellSize + ImVec2(1, 0), ImColor(SelectionFrameColor), 1.0F);
|
||||
}
|
||||
|
||||
void HexEditor::drawEditor(prv::Provider *provider, const ImVec2 &size) {
|
||||
void HexEditor::drawEditor(const ImVec2 &size) {
|
||||
const float SeparatorColumWidth = 6_scaled;
|
||||
const auto CharacterSize = ImGui::CalcTextSize("0");
|
||||
|
||||
@ -377,13 +377,13 @@ namespace hex {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (provider != nullptr && provider->isReadable()) {
|
||||
if (this->m_provider != nullptr && this->m_provider->isReadable()) {
|
||||
|
||||
std::pair<Region, bool> validRegion = { Region::Invalid(), false };
|
||||
const auto isCurrRegionValid = [&validRegion, &provider](u64 address){
|
||||
const auto isCurrRegionValid = [this, &validRegion](u64 address){
|
||||
auto &[currRegion, currRegionValid] = validRegion;
|
||||
if (!Region{ address, 1 }.isWithin(currRegion)) {
|
||||
validRegion = provider->getRegionValidity(address);
|
||||
validRegion = this->m_provider->getRegionValidity(address);
|
||||
}
|
||||
|
||||
return currRegionValid;
|
||||
@ -391,7 +391,7 @@ namespace hex {
|
||||
|
||||
ImGuiListClipper clipper;
|
||||
|
||||
clipper.Begin(std::ceil(provider->getSize() / (long double)(this->m_bytesPerRow)), CharacterSize.y);
|
||||
clipper.Begin(std::ceil(this->m_provider->getSize() / (long double)(this->m_bytesPerRow)), CharacterSize.y);
|
||||
while (clipper.Step()) {
|
||||
this->m_visibleRowCount = clipper.DisplayEnd - clipper.DisplayStart;
|
||||
|
||||
@ -401,18 +401,18 @@ namespace hex {
|
||||
// Draw address column
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted(this->m_upperCaseHex ? "{:08X}: " : "{:08x}: ", y * this->m_bytesPerRow + provider->getBaseAddress() + provider->getCurrentPageAddress());
|
||||
ImGui::TextFormatted(this->m_upperCaseHex ? "{:08X}: " : "{:08x}: ", y * this->m_bytesPerRow + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress());
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
const u8 validBytes = std::min<u64>(this->m_bytesPerRow, provider->getSize() - y * this->m_bytesPerRow);
|
||||
const u8 validBytes = std::min<u64>(this->m_bytesPerRow, this->m_provider->getSize() - y * this->m_bytesPerRow);
|
||||
|
||||
std::vector<u8> bytes(this->m_bytesPerRow, 0x00);
|
||||
provider->read(y * this->m_bytesPerRow + provider->getBaseAddress() + provider->getCurrentPageAddress(), bytes.data(), validBytes);
|
||||
this->m_provider->read(y * this->m_bytesPerRow + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress(), bytes.data(), validBytes);
|
||||
|
||||
std::vector<std::tuple<std::optional<color_t>, std::optional<color_t>>> cellColors;
|
||||
{
|
||||
for (u64 x = 0; x < std::ceil(float(validBytes) / bytesPerCell); x++) {
|
||||
const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + provider->getBaseAddress() + provider->getCurrentPageAddress();
|
||||
const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress();
|
||||
|
||||
const auto cellBytes = std::min<u64>(validBytes, bytesPerCell);
|
||||
|
||||
@ -438,7 +438,7 @@ namespace hex {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(3, 0));
|
||||
|
||||
for (u64 x = 0; x < columnCount; x++) {
|
||||
const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + provider->getBaseAddress() + provider->getCurrentPageAddress();
|
||||
const u64 byteAddress = y * this->m_bytesPerRow + x * bytesPerCell + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (isColumnSeparatorColumn(x, columnCount))
|
||||
@ -486,7 +486,7 @@ namespace hex {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushItemWidth((CharacterSize * maxCharsPerCell).x);
|
||||
if (isCurrRegionValid(byteAddress))
|
||||
this->drawCell(provider, byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex);
|
||||
this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered, CellType::Hex);
|
||||
else
|
||||
ImGui::TextFormatted("{}", std::string(maxCharsPerCell, '?'));
|
||||
ImGui::PopItemWidth();
|
||||
@ -513,7 +513,7 @@ namespace hex {
|
||||
for (u64 x = 0; x < this->m_bytesPerRow; x++) {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
const u64 byteAddress = y * this->m_bytesPerRow + x + provider->getBaseAddress() + provider->getCurrentPageAddress();
|
||||
const u64 byteAddress = y * this->m_bytesPerRow + x + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress();
|
||||
|
||||
const auto cellStartPos = getCellPosition();
|
||||
const auto cellSize = CharacterSize + ImVec2(this->m_characterCellPadding, 0);
|
||||
@ -543,7 +543,7 @@ namespace hex {
|
||||
if (!isCurrRegionValid(byteAddress))
|
||||
ImGui::TextFormatted("?");
|
||||
else
|
||||
this->drawCell(provider, byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII);
|
||||
this->drawCell(byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
@ -562,9 +562,9 @@ namespace hex {
|
||||
std::vector<std::pair<u64, CustomEncodingData>> encodingData;
|
||||
u32 offset = 0;
|
||||
do {
|
||||
const u64 address = y * this->m_bytesPerRow + offset + provider->getBaseAddress() + provider->getCurrentPageAddress();
|
||||
const u64 address = y * this->m_bytesPerRow + offset + this->m_provider->getBaseAddress() + this->m_provider->getCurrentPageAddress();
|
||||
|
||||
auto result = queryCustomEncodingData(provider, *this->m_currCustomEncoding, address);
|
||||
auto result = queryCustomEncodingData(this->m_provider, *this->m_currCustomEncoding, address);
|
||||
offset += std::max<size_t>(1, result.advance);
|
||||
|
||||
encodingData.emplace_back(address, result);
|
||||
@ -621,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() - this->m_provider->getBaseAddress() - this->m_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() - this->m_provider->getBaseAddress() - this->m_provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) {
|
||||
this->m_shouldScrollToSelection = false;
|
||||
ImGui::SetScrollHereY(fractionPerLine * (this->m_visibleRowCount));
|
||||
}
|
||||
@ -638,7 +638,7 @@ namespace hex {
|
||||
if (this->m_shouldJumpWhenOffScreen) {
|
||||
this->m_shouldJumpWhenOffScreen = false;
|
||||
|
||||
const auto pageAddress = provider->getCurrentPageAddress() + provider->getBaseAddress();
|
||||
const auto pageAddress = this->m_provider->getCurrentPageAddress() + this->m_provider->getBaseAddress();
|
||||
auto newSelection = getSelection();
|
||||
newSelection.address -= pageAddress;
|
||||
|
||||
@ -657,9 +657,9 @@ namespace hex {
|
||||
this->m_shouldJumpToSelection = false;
|
||||
|
||||
auto newSelection = getSelection();
|
||||
provider->setCurrentPage(provider->getPageOfAddress(newSelection.address).value_or(0));
|
||||
this->m_provider->setCurrentPage(this->m_provider->getPageOfAddress(newSelection.address).value_or(0));
|
||||
|
||||
const auto pageAddress = provider->getCurrentPageAddress() + provider->getBaseAddress();
|
||||
const auto pageAddress = this->m_provider->getCurrentPageAddress() + this->m_provider->getBaseAddress();
|
||||
auto scrollPos = (static_cast<long double>(newSelection.getStartAddress() - pageAddress) / this->m_bytesPerRow) * CharacterSize.y;
|
||||
bool scrollUpwards = scrollPos < ImGui::GetScrollY();
|
||||
auto scrollFraction = scrollUpwards ? 0.0F : (1.0F - ((1.0F / this->m_visibleRowCount) * 2));
|
||||
@ -693,12 +693,12 @@ namespace hex {
|
||||
this->m_enteredEditingMode = false;
|
||||
}
|
||||
|
||||
void HexEditor::drawFooter(prv::Provider *provider, const ImVec2 &size) {
|
||||
if (provider != nullptr && provider->isReadable()) {
|
||||
const auto pageCount = provider->getPageCount();
|
||||
void HexEditor::drawFooter(const ImVec2 &size) {
|
||||
if (this->m_provider != nullptr && this->m_provider->isReadable()) {
|
||||
const auto pageCount = this->m_provider->getPageCount();
|
||||
constexpr static u32 MinPage = 1;
|
||||
|
||||
const auto windowEndPos = ImGui::GetWindowPos() + ImGui::GetWindowSize() - ImGui::GetStyle().WindowPadding;
|
||||
const auto windowEndPos = ImGui::GetWindowPos() + size - ImGui::GetStyle().WindowPadding;
|
||||
ImGui::GetWindowDrawList()->AddLine(windowEndPos - ImVec2(0, size.y - 1_scaled), windowEndPos - size + ImVec2(0, 1_scaled), ImGui::GetColorU32(ImGuiCol_Separator), 2.0_scaled);
|
||||
|
||||
if (ImGui::BeginChild("##footer", size, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
@ -708,7 +708,7 @@ namespace hex {
|
||||
// Page slider
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
u32 page = provider->getCurrentPage() + 1;
|
||||
u32 page = this->m_provider->getCurrentPage() + 1;
|
||||
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.view.hex_editor.page"_lang);
|
||||
ImGui::SameLine();
|
||||
@ -716,7 +716,7 @@ namespace hex {
|
||||
ImGui::BeginDisabled(pageCount <= 1);
|
||||
{
|
||||
if (ImGui::SliderScalar("##page_selection", ImGuiDataType_U32, &page, &MinPage, &pageCount, hex::format("%d / {}", pageCount).c_str()))
|
||||
provider->setCurrentPage(page - 1);
|
||||
this->m_provider->setCurrentPage(page - 1);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
@ -724,7 +724,7 @@ namespace hex {
|
||||
// Page Address
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::TextFormatted("{0}: 0x{1:08X} - 0x{2:08X} ({1} - {2})", "hex.builtin.view.hex_editor.region"_lang, provider->getCurrentPageAddress(), provider->getSize());
|
||||
ImGui::TextFormatted("{0}: 0x{1:08X} - 0x{2:08X} ({1} - {2})", "hex.builtin.view.hex_editor.region"_lang, this->m_provider->getCurrentPageAddress(), this->m_provider->getSize());
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
@ -752,9 +752,9 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::TextFormatted("{0}: 0x{1:08X} (0x{2:X} | {3})", "hex.builtin.view.hex_editor.data_size"_lang,
|
||||
provider->getActualSize(),
|
||||
provider->getActualSize(),
|
||||
hex::toByteString(provider->getActualSize())
|
||||
this->m_provider->getActualSize(),
|
||||
this->m_provider->getActualSize(),
|
||||
hex::toByteString(this->m_provider->getActualSize())
|
||||
);
|
||||
}
|
||||
|
||||
@ -788,14 +788,14 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void HexEditor::draw(prv::Provider *provider, float height) {
|
||||
void HexEditor::draw(float height) {
|
||||
const auto width = ImGui::GetContentRegionAvail().x;
|
||||
|
||||
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->drawEditor(TableSize);
|
||||
this->drawFooter(FooterSize);
|
||||
|
||||
this->m_selectionChanged = false;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#include <content/helpers/pattern_drawer.hpp>
|
||||
#include <ui/pattern_drawer.hpp>
|
||||
|
||||
#include <pl/patterns/pattern_array_dynamic.hpp>
|
||||
#include <pl/patterns/pattern_array_static.hpp>
|
||||
@ -21,11 +21,12 @@
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace hex {
|
||||
namespace hex::plugin::builtin::ui {
|
||||
|
||||
namespace {
|
||||
|
||||
@ -414,7 +415,7 @@ namespace hex {
|
||||
|
||||
auto &displayEnd = this->getDisplayEnd(pattern);
|
||||
if (chunkCount > displayEnd) {
|
||||
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
ImGui::Selectable(hex::format("... ({})", "hex.builtin.pattern_drawer.double_click"_lang).c_str(), false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
displayEnd += DisplayEndStep;
|
||||
break;
|
||||
@ -470,4 +471,88 @@ namespace hex {
|
||||
auto [value, success] = this->m_displayEnd.emplace(&pattern, DisplayEndDefault);
|
||||
return value->second;
|
||||
}
|
||||
|
||||
static bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) {
|
||||
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getDisplayName() > right->getDisplayName();
|
||||
else
|
||||
return left->getDisplayName() < right->getDisplayName();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getOffset() > right->getOffset();
|
||||
else
|
||||
return left->getOffset() < right->getOffset();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getSize() > right->getSize();
|
||||
else
|
||||
return left->getSize() < right->getSize();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getValue() > right->getValue();
|
||||
else
|
||||
return left->getValue() < right->getValue();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getTypeName() > right->getTypeName();
|
||||
else
|
||||
return left->getTypeName() < right->getTypeName();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getColor() > right->getColor();
|
||||
else
|
||||
return left->getColor() < right->getColor();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns, float height) {
|
||||
if (ImGui::BeginTable("##Patterntable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, height))) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("hex.builtin.pattern_drawer.var_name"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("name"));
|
||||
ImGui::TableSetupColumn("hex.builtin.pattern_drawer.color"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("color"));
|
||||
ImGui::TableSetupColumn("hex.builtin.pattern_drawer.offset"_lang, ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort, 0, ImGui::GetID("offset"));
|
||||
ImGui::TableSetupColumn("hex.builtin.pattern_drawer.size"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("size"));
|
||||
ImGui::TableSetupColumn("hex.builtin.pattern_drawer.type"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("type"));
|
||||
ImGui::TableSetupColumn("hex.builtin.pattern_drawer.value"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("value"));
|
||||
|
||||
auto sortSpecs = ImGui::TableGetSortSpecs();
|
||||
|
||||
if (!patterns.empty() && (sortSpecs->SpecsDirty || sortedPatterns.empty())) {
|
||||
sortedPatterns.clear();
|
||||
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::ptrn::Pattern> &pattern) {
|
||||
return pattern.get();
|
||||
});
|
||||
|
||||
std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs](pl::ptrn::Pattern *left, pl::ptrn::Pattern *right) -> bool {
|
||||
return sortPatterns(sortSpecs, left, right);
|
||||
});
|
||||
|
||||
for (auto &pattern : sortedPatterns)
|
||||
pattern->sort([&sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){
|
||||
return sortPatterns(sortSpecs, left, right);
|
||||
});
|
||||
|
||||
sortSpecs->SpecsDirty = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PatternDrawer::draw(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, float height) {
|
||||
if (beginPatternTable(patterns, this->m_sortedPatterns, height)) {
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (auto &pattern : this->m_sortedPatterns) {
|
||||
this->draw(*pattern);
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user