refactor: Rework features that use external libraries into optional plugins (#1470)

This commit is contained in:
Nik
2023-12-23 21:09:41 +01:00
committed by GitHub
parent 84bfd10416
commit 61bfe10bc2
149 changed files with 2940 additions and 2390 deletions

View File

@@ -0,0 +1,114 @@
#pragma once
#include <hex/ui/popup.hpp>
#include <hex/api/localization_manager.hpp>
#include <wolv/utils/string.hpp>
#include <functional>
#include <string>
namespace hex::ui {
class PopupFileChooser : public Popup<PopupFileChooser> {
public:
PopupFileChooser(const std::vector<std::fs::path> &basePaths, const std::vector<std::fs::path> &files, const std::vector<hex::fs::ItemFilter> &validExtensions, bool multiple, const std::function<void(std::fs::path)> &callback)
: hex::Popup<PopupFileChooser>("hex.ui.common.choose_file"),
m_indices({ }),
m_openCallback(callback),
m_validExtensions(validExtensions), m_multiple(multiple) {
for (const auto &path : files) {
std::fs::path adjustedPath;
for (const auto &basePath : basePaths) {
if (isSubpath(basePath, path)) {
adjustedPath = std::fs::relative(path, basePath);
break;
}
}
if (adjustedPath.empty())
adjustedPath = path.filename();
m_files.push_back({ path, adjustedPath });
}
std::sort(m_files.begin(), m_files.end(), [](const auto &a, const auto &b) {
return a.first < b.first;
});
}
void drawContent() override {
bool doubleClicked = false;
if (ImGui::BeginListBox("##files", scaled(ImVec2(500, 400)))) {
u32 index = 0;
for (auto &[path, pathName] : m_files) {
ImGui::PushID(index);
bool selected = m_indices.contains(index);
if (ImGui::Selectable(wolv::util::toUTF8String(pathName).c_str(), selected, ImGuiSelectableFlags_DontClosePopups)) {
if (!m_multiple) {
m_indices.clear();
m_indices.insert(index);
} else {
if (selected) {
m_indices.erase(index);
} else {
m_indices.insert(index);
}
}
}
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
doubleClicked = true;
ImGuiExt::InfoTooltip(wolv::util::toUTF8String(path).c_str());
ImGui::PopID();
index++;
}
ImGui::EndListBox();
}
if (ImGui::Button("hex.ui.common.open"_lang) || doubleClicked) {
for (const auto &index : m_indices)
m_openCallback(m_files[index].first);
Popup::close();
}
ImGui::SameLine();
if (ImGui::Button("hex.ui.common.browse"_lang)) {
fs::openFileBrowser(fs::DialogMode::Open, m_validExtensions, [this](const auto &path) {
m_openCallback(path);
Popup::close();
}, {}, m_multiple);
}
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
this->close();
}
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
return ImGuiWindowFlags_AlwaysAutoResize;
}
private:
static bool isSubpath(const std::fs::path &basePath, const std::fs::path &path) {
auto relativePath = std::fs::relative(path, basePath);
return !relativePath.empty() && relativePath.native()[0] != '.';
}
private:
std::set<u32> m_indices;
std::vector<std::pair<std::fs::path, std::fs::path>> m_files;
std::function<void(std::fs::path)> m_openCallback;
std::vector<hex::fs::ItemFilter> m_validExtensions;
bool m_multiple = false;
};
}

View File

@@ -0,0 +1,88 @@
#pragma once
#include <hex/ui/popup.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/api/imhex_api.hpp>
#include <functional>
#include <string>
namespace hex::ui {
namespace impl {
template<typename T>
class PopupNotification : public Popup<T> {
public:
PopupNotification(UnlocalizedString unlocalizedName, std::string message, std::function<void()> function)
: hex::Popup<T>(std::move(unlocalizedName), false),
m_message(std::move(message)), m_function(std::move(function)) { }
void drawContent() override {
ImGuiExt::TextFormattedWrapped("{}", m_message.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.ui.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
m_function();
ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
this->close();
}
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
return ImGuiWindowFlags_AlwaysAutoResize;
}
[[nodiscard]] ImVec2 getMinSize() const override {
return scaled({ 400, 100 });
}
[[nodiscard]] ImVec2 getMaxSize() const override {
return scaled({ 600, 300 });
}
private:
std::string m_message;
std::function<void()> m_function;
};
}
class PopupInfo : public impl::PopupNotification<PopupInfo> {
public:
explicit PopupInfo(std::string message)
: PopupNotification("hex.ui.common.info", std::move(message), [this] {
Popup::close();
}) { }
};
class PopupWarning : public impl::PopupNotification<PopupWarning> {
public:
explicit PopupWarning(std::string message)
: PopupNotification("hex.ui.common.warning", std::move(message), [this] {
Popup::close();
}) { }
};
class PopupError : public impl::PopupNotification<PopupError> {
public:
explicit PopupError(std::string message)
: PopupNotification("hex.ui.common.error", std::move(message), [this] {
Popup::close();
}) { }
};
class PopupFatal : public impl::PopupNotification<PopupFatal> {
public:
explicit PopupFatal(std::string message)
: PopupNotification("hex.ui.common.fatal", std::move(message), [this] {
ImHexApi::System::closeImHex();
Popup::close();
}) { }
};
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <hex/ui/popup.hpp>
#include <hex/api/localization_manager.hpp>
#include <functional>
#include <string>
namespace hex::ui {
class PopupQuestion : public Popup<PopupQuestion> {
public:
PopupQuestion(std::string message, std::function<void()> yesFunction, std::function<void()> noFunction)
: hex::Popup<PopupQuestion>("hex.ui.common.question", false),
m_message(std::move(message)),
m_yesFunction(std::move(yesFunction)), m_noFunction(std::move(noFunction)) { }
void drawContent() override {
ImGuiExt::TextFormattedWrapped("{}", m_message.c_str());
ImGui::NewLine();
ImGui::Separator();
auto width = ImGui::GetWindowWidth();
ImGui::SetCursorPosX(width / 9);
if (ImGui::Button("hex.ui.common.yes"_lang, ImVec2(width / 3, 0))) {
m_yesFunction();
this->close();
}
ImGui::SameLine();
ImGui::SetCursorPosX(width / 9 * 5);
if (ImGui::Button("hex.ui.common.no"_lang, ImVec2(width / 3, 0))) {
m_noFunction();
this->close();
}
ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
}
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
return ImGuiWindowFlags_AlwaysAutoResize;
}
[[nodiscard]] ImVec2 getMinSize() const override {
return scaled({ 400, 100 });
}
[[nodiscard]] ImVec2 getMaxSize() const override {
return scaled({ 600, 300 });
}
private:
std::string m_message;
std::function<void()> m_yesFunction, m_noFunction;
};
}

View File

@@ -0,0 +1,73 @@
#pragma once
#include <hex/ui/popup.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization_manager.hpp>
#include <functional>
#include <string>
#include <fonts/codicons_font.h>
namespace hex::ui {
class PopupTextInput : public Popup<PopupTextInput> {
public:
PopupTextInput(UnlocalizedString unlocalizedName, UnlocalizedString message, std::function<void(std::string)> function)
: hex::Popup<PopupTextInput>(std::move(unlocalizedName), false),
m_message(std::move(message)), m_function(std::move(function)) { }
void drawContent() override {
ImGuiExt::TextFormattedWrapped("{}", Lang(m_message));
ImGui::NewLine();
ImGui::PushItemWidth(-1);
if (m_justOpened) {
ImGui::SetKeyboardFocusHere();
m_justOpened = false;
}
ImGuiExt::InputTextIcon("##input", ICON_VS_SYMBOL_KEY, m_input);
ImGui::PopItemWidth();
ImGui::NewLine();
ImGui::Separator();
auto width = ImGui::GetWindowWidth();
ImGui::SetCursorPosX(width / 9);
if (ImGui::Button("hex.ui.common.okay"_lang, ImVec2(width / 3, 0)) || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter))) {
m_function(m_input);
this->close();
}
ImGui::SameLine();
ImGui::SetCursorPosX(width / 9 * 5);
if (ImGui::Button("hex.ui.common.cancel"_lang, ImVec2(width / 3, 0)) || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape))) {
this->close();
}
ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
}
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
return ImGuiWindowFlags_AlwaysAutoResize;
}
[[nodiscard]] ImVec2 getMinSize() const override {
return scaled({ 400, 100 });
}
[[nodiscard]] ImVec2 getMaxSize() const override {
return scaled({ 600, 300 });
}
private:
std::string m_input;
UnlocalizedString m_message;
std::function<void(std::string)> m_function;
bool m_justOpened = true;
};
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include <hex/api/imhex_api.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/ui/toast.hpp>
#include <fonts/codicons_font.h>
#include <hex/helpers/utils.hpp>
namespace hex::ui {
namespace impl {
template<typename T>
struct ToastNotification : Toast<T> {
ToastNotification(ImColor color, const char *icon, UnlocalizedString title, UnlocalizedString message)
: Toast<T>(color), m_icon(icon), m_title(std::move(title)), m_message(std::move(message)) {}
void drawContent() final {
ImGuiExt::TextFormattedColored(this->getColor(), "{}", m_icon);
ImGui::SameLine();
ImGui::PushFont(ImHexApi::Fonts::Bold());
{
ImGuiExt::TextFormatted("{}", hex::limitStringLength(Lang(m_title).get(), 30));
}
ImGui::PopFont();
ImGui::Separator();
ImGuiExt::TextFormattedWrapped("{}", hex::limitStringLength(Lang(m_message).get(), 60));
}
private:
const char *m_icon;
UnlocalizedString m_title, m_message;
};
}
struct ToastInfo : impl::ToastNotification<ToastInfo> {
ToastInfo(UnlocalizedString title, UnlocalizedString message)
: ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerInfo), ICON_VS_INFO, std::move(title), std::move(message)) {}
};
struct ToastWarn : impl::ToastNotification<ToastWarn> {
ToastWarn(UnlocalizedString title, UnlocalizedString message)
: ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerWarning), ICON_VS_WARNING, std::move(title), std::move(message)) {}
};
struct ToastError : impl::ToastNotification<ToastError> {
ToastError(UnlocalizedString title, UnlocalizedString message)
: ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerError), ICON_VS_ERROR, std::move(title), std::move(message)) {}
};
}

View File

@@ -0,0 +1,278 @@
#pragma once
#include <hex.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/encoding_file.hpp>
#include <imgui.h>
#include <hex/ui/view.hpp>
namespace hex::ui {
class HexEditor {
public:
explicit HexEditor(prv::Provider *provider = nullptr);
~HexEditor();
void draw(float height = ImGui::GetContentRegionAvail().y);
void setProvider(prv::Provider *provider) {
m_provider = provider;
m_currValidRegion = { Region::Invalid(), false };
}
void setUnknownDataCharacter(char character) { m_unknownDataCharacter = character; }
private:
enum class CellType { None, Hex, ASCII };
void drawCell(u64 address, const u8 *data, size_t size, bool hovered, CellType cellType);
void drawSelectionFrame(u32 x, u32 y, Region selection, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize, const ImColor &backgroundColor) const;
void drawEditor(const ImVec2 &size);
void drawFooter(const ImVec2 &size);
void drawTooltip(u64 address, const u8 *data, size_t size) const;
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) {
m_selectionStart = start;
m_selectionEnd = end;
m_cursorPosition = end;
}
void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
void setSelection(u128 start, u128 end) {
if (!ImHexApi::Provider::isValid())
return;
if (start > m_provider->getBaseAddress() + m_provider->getActualSize())
return;
if (start < m_provider->getBaseAddress())
return;
if (m_provider->getActualSize() == 0)
return;
const size_t maxAddress = m_provider->getActualSize() + m_provider->getBaseAddress() - 1;
constexpr static auto alignDown = [](u128 value, u128 alignment) {
return value & ~(alignment - 1);
};
m_selectionChanged = m_selectionStart != start || m_selectionEnd != end;
if (!m_selectionStart.has_value()) m_selectionStart = start;
if (!m_selectionEnd.has_value()) m_selectionEnd = end;
if (auto bytesPerCell = m_currDataVisualizer->getBytesPerCell(); bytesPerCell > 1) {
if (end > start) {
start = alignDown(start, bytesPerCell);
end = alignDown(end, bytesPerCell) + (bytesPerCell - 1);
} else {
start = alignDown(start, bytesPerCell) + (bytesPerCell - 1);
end = alignDown(end, bytesPerCell);
}
}
m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
m_cursorPosition = m_selectionEnd;
if (m_selectionChanged) {
auto selection = this->getSelection();
EventRegionSelected::post(ImHexApi::HexEditor::ProviderRegion{ { selection.address, selection.size }, m_provider });
m_shouldModifyValue = true;
}
}
[[nodiscard]] Region getSelection() const {
if (!isSelectionValid())
return Region::Invalid();
const auto start = std::min(m_selectionStart.value(), m_selectionEnd.value());
const auto end = std::max(m_selectionStart.value(), m_selectionEnd.value());
const size_t size = end - start + 1;
return { start, size };
}
[[nodiscard]] std::optional<u64> getCursorPosition() const {
return m_cursorPosition;
}
void setCursorPosition(u64 cursorPosition) {
m_cursorPosition = cursorPosition;
}
[[nodiscard]] bool isSelectionValid() const {
return m_selectionStart.has_value() && m_selectionEnd.has_value();
}
void jumpToSelection(bool center = true) {
m_shouldJumpToSelection = true;
if (center)
m_centerOnJump = true;
}
void scrollToSelection() {
m_shouldScrollToSelection = true;
}
void jumpIfOffScreen() {
m_shouldJumpWhenOffScreen = true;
}
[[nodiscard]] u16 getBytesPerRow() const {
return m_bytesPerRow;
}
[[nodiscard]] u16 getBytesPerCell() const {
return m_currDataVisualizer->getBytesPerCell();
}
void setBytesPerRow(u16 bytesPerRow) {
m_bytesPerRow = bytesPerRow;
}
[[nodiscard]] u16 getVisibleRowCount() const {
return m_visibleRowCount;
}
void setSelectionColor(color_t color) {
m_selectionColor = color;
}
void enableUpperCaseHex(bool upperCaseHex) {
m_upperCaseHex = upperCaseHex;
}
void enableGrayOutZeros(bool grayOutZeros) {
m_grayOutZero = grayOutZeros;
}
void enableShowAscii(bool showAscii) {
m_showAscii = showAscii;
}
void enableShowHumanReadableUnits(bool showHumanReadableUnits) {
m_showHumanReadableUnits = showHumanReadableUnits;
}
void enableSyncScrolling(bool syncScrolling) {
m_syncScrolling = syncScrolling;
}
void setByteCellPadding(u32 byteCellPadding) {
m_byteCellPadding = byteCellPadding;
}
void setCharacterCellPadding(u32 characterCellPadding) {
m_characterCellPadding = characterCellPadding;
}
[[nodiscard]] const std::optional<EncodingFile>& getCustomEncoding() const {
return m_currCustomEncoding;
}
void setCustomEncoding(const EncodingFile &encoding) {
m_currCustomEncoding = encoding;
m_encodingLineStartAddresses.clear();
}
void setCustomEncoding(EncodingFile &&encoding) {
m_currCustomEncoding = std::move(encoding);
m_encodingLineStartAddresses.clear();
}
void forceUpdateScrollPosition() {
m_shouldUpdateScrollPosition = true;
}
void setForegroundHighlightCallback(const std::function<std::optional<color_t>(u64, const u8 *, size_t)> &callback) {
m_foregroundColorCallback = callback;
}
void setBackgroundHighlightCallback(const std::function<std::optional<color_t>(u64, const u8 *, size_t)> &callback) {
m_backgroundColorCallback = callback;
}
void setTooltipCallback(const std::function<void(u64, const u8 *, size_t)> &callback) {
m_tooltipCallback = callback;
}
[[nodiscard]] float getScrollPosition() const {
return m_scrollPosition;
}
void setScrollPosition(float scrollPosition) {
m_scrollPosition = scrollPosition;
}
void setEditingAddress(u64 address) {
m_editingAddress = address;
m_shouldModifyValue = false;
m_enteredEditingMode = true;
m_editingBytes.resize(m_currDataVisualizer->getBytesPerCell());
m_provider->read(address + m_provider->getBaseAddress(), m_editingBytes.data(), m_editingBytes.size());
m_editingCellType = CellType::Hex;
}
void clearEditingAddress() {
m_editingAddress = std::nullopt;
}
private:
prv::Provider *m_provider;
std::optional<u64> m_selectionStart;
std::optional<u64> m_selectionEnd;
std::optional<u64> m_cursorPosition;
ImS64 m_scrollPosition = 0;
u16 m_bytesPerRow = 16;
std::endian m_dataVisualizerEndianness = std::endian::little;
std::shared_ptr<ContentRegistry::HexEditor::DataVisualizer> m_currDataVisualizer;
char m_unknownDataCharacter = '?';
bool m_shouldJumpToSelection = false;
bool m_centerOnJump = false;
bool m_shouldScrollToSelection = false;
bool m_shouldJumpWhenOffScreen = false;
bool m_shouldUpdateScrollPosition = false;
bool m_selectionChanged = false;
u16 m_visibleRowCount = 0;
CellType m_editingCellType = CellType::None;
std::optional<u64> m_editingAddress;
bool m_shouldModifyValue = false;
bool m_enteredEditingMode = false;
bool m_shouldUpdateEditingValue = false;
std::vector<u8> m_editingBytes;
color_t m_selectionColor = 0x00;
bool m_upperCaseHex = true;
bool m_grayOutZero = true;
bool m_showAscii = true;
bool m_showCustomEncoding = true;
bool m_showHumanReadableUnits = true;
bool m_syncScrolling = false;
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
bool m_footerCollapsed = true;
std::optional<EncodingFile> m_currCustomEncoding;
std::vector<u64> m_encodingLineStartAddresses;
std::pair<Region, bool> m_currValidRegion = { Region::Invalid(), false };
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

@@ -0,0 +1,122 @@
#pragma once
#include <hex/api/task_manager.hpp>
#include <hex/api/content_registry.hpp>
#include <pl/patterns/pattern.hpp>
#include <pl/pattern_visitor.hpp>
#include <pl/formatters.hpp>
#include <set>
struct ImGuiTableSortSpecs;
namespace hex::ui {
class PatternDrawer : public pl::PatternVisitor {
public:
PatternDrawer() {
m_formatters = pl::gen::fmt::createFormatters();
}
virtual ~PatternDrawer() = default;
void draw(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, pl::PatternLanguage *runtime = nullptr, float height = 0.0F);
enum class TreeStyle {
Default = 0,
AutoExpanded = 1,
Flattened = 2
};
void setTreeStyle(TreeStyle style) { m_treeStyle = style; }
void setSelectionCallback(std::function<void(Region)> callback) { m_selectionCallback = std::move(callback); }
void enableRowColoring(bool enabled) { m_rowColoring = enabled; }
void reset();
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;
void visit(pl::ptrn::PatternBitfieldArray& pattern) override;
void visit(pl::ptrn::PatternBitfield& pattern) override;
void visit(pl::ptrn::PatternBoolean& pattern) override;
void visit(pl::ptrn::PatternCharacter& pattern) override;
void visit(pl::ptrn::PatternEnum& pattern) override;
void visit(pl::ptrn::PatternFloat& pattern) override;
void visit(pl::ptrn::PatternPadding& pattern) override;
void visit(pl::ptrn::PatternPointer& pattern) override;
void visit(pl::ptrn::PatternSigned& pattern) override;
void visit(pl::ptrn::PatternString& pattern) override;
void visit(pl::ptrn::PatternStruct& pattern) override;
void visit(pl::ptrn::PatternUnion& pattern) override;
void visit(pl::ptrn::PatternUnsigned& pattern) override;
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
void visit(pl::ptrn::PatternWideString& pattern) override;
private:
constexpr static auto ChunkSize = 512;
constexpr static auto DisplayEndStep = 64;
void drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::IIterable &iterable, bool isInlined);
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
void makeSelectable(const pl::ptrn::Pattern &pattern);
void drawValueColumn(pl::ptrn::Pattern& pattern);
void drawVisualizer(const std::map<std::string, ContentRegistry::PatternLanguage::impl::Visualizer> &visualizers, const std::vector<pl::core::Token::Literal> &arguments, pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &iterable, bool reset);
void drawFavoriteColumn(const pl::ptrn::Pattern& pattern);
void drawColorColumn(const pl::ptrn::Pattern& pattern);
bool beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns, float height) const;
bool createTreeNode(const pl::ptrn::Pattern& pattern, bool leaf = false);
void createDefaultEntry(const pl::ptrn::Pattern &pattern);
void closeTreeNode(bool inlined) const;
bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) const;
bool isEditingPattern(const pl::ptrn::Pattern& pattern) const;
void resetEditing();
bool matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch) const;
void traversePatternTree(pl::ptrn::Pattern &pattern, std::vector<std::string> &patternPath, const std::function<void(pl::ptrn::Pattern&)> &callback);
std::string getDisplayName(const pl::ptrn::Pattern& pattern) const;
struct Filter {
std::vector<std::string> path;
std::optional<pl::core::Token::Literal> value;
};
std::optional<Filter> parseRValueFilter(const std::string &filter) const;
private:
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
std::vector<pl::ptrn::Pattern*> m_sortedPatterns;
const pl::ptrn::Pattern *m_editingPattern = nullptr;
u64 m_editingPatternOffset = 0;
TreeStyle m_treeStyle = TreeStyle::Default;
bool m_rowColoring = false;
pl::ptrn::Pattern *m_currVisualizedPattern = nullptr;
std::set<pl::ptrn::Pattern*> m_visualizedPatterns;
std::string m_lastVisualizerError;
std::string m_filterText;
Filter m_filter;
std::vector<std::string> m_currPatternPath;
std::map<std::vector<std::string>, std::unique_ptr<pl::ptrn::Pattern>> m_favorites;
std::map<std::string, std::vector<std::unique_ptr<pl::ptrn::Pattern>>> m_groups;
bool m_showFavoriteStars = false;
bool m_favoritesUpdated = false;
bool m_showSpecName = false;
TaskHolder m_favoritesUpdateTask;
std::function<void(Region)> m_selectionCallback = [](Region) { };
pl::gen::fmt::FormatterArray m_formatters;
};
}

View File

@@ -0,0 +1,61 @@
#pragma once
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace pl::ptrn { class Pattern; }
namespace hex::prv { class Provider; }
namespace hex::ui {
enum class RegionType : int {
EntireData,
Selection,
Region
};
inline void regionSelectionPicker(Region *region, prv::Provider *provider, RegionType *type, bool showHeader = true, bool firstEntry = false) {
if (showHeader)
ImGuiExt::Header("hex.ui.common.range"_lang, firstEntry);
if (ImGui::RadioButton("hex.ui.common.range.entire_data"_lang, *type == RegionType::EntireData))
*type = RegionType::EntireData;
if (ImGui::RadioButton("hex.ui.common.range.selection"_lang, *type == RegionType::Selection))
*type = RegionType::Selection;
if (ImGui::RadioButton("hex.ui.common.region"_lang, *type == RegionType::Region))
*type = RegionType::Region;
switch (*type) {
case RegionType::EntireData:
*region = { provider->getBaseAddress(), provider->getActualSize() };
break;
case RegionType::Selection:
*region = ImHexApi::HexEditor::getSelection().value_or(
ImHexApi::HexEditor::ProviderRegion {
{ 0, 1 },
provider }
).getRegion();
break;
case RegionType::Region:
ImGui::SameLine();
const auto width = ImGui::GetContentRegionAvail().x / 2 - ImGui::CalcTextSize(" - ").x / 2;
u64 start = region->getStartAddress(), end = region->getEndAddress();
ImGui::PushItemWidth(width);
ImGuiExt::InputHexadecimal("##start", &start);
ImGui::PopItemWidth();
ImGui::SameLine(0, 0);
ImGui::TextUnformatted(" - ");
ImGui::SameLine(0, 0);
ImGui::PushItemWidth(width);
ImGuiExt::InputHexadecimal("##end", &end);
ImGui::PopItemWidth();
*region = { start, (end - start) + 1 };
break;
}
}
}