1
0
mirror of synced 2025-02-20 04:01:01 +01:00

feat: Added new pattern inline visualizers

This commit is contained in:
WerWolv 2023-07-04 22:18:06 +02:00
parent 33566137c2
commit 86c4c8fa96
8 changed files with 119 additions and 33 deletions

View File

@ -258,6 +258,7 @@ namespace hex {
};
std::map<std::string, Visualizer> &getVisualizers();
std::map<std::string, Visualizer> &getInlineVisualizers();
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
@ -317,6 +318,15 @@ namespace hex {
*/
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
/**
* @brief Adds a new inline visualizer to the pattern language
* @note Inline visualizers are extensions to the [[hex::inline_visualize]] attribute, used to visualize data
* @param name The name of the visualizer
* @param func The function callback
* @param parameterCount The amount of parameters the function takes
*/
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
}
/* View Registry. Allows adding of new windows */

View File

@ -336,6 +336,11 @@ namespace hex {
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
}
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
log::debug("Registered new inline pattern visualizer function: {}", name);
impl::getInlineVisualizers()[name] = impl::Visualizer { parameterCount, function };
}
namespace impl {
@ -345,6 +350,12 @@ namespace hex {
return visualizers;
}
std::map<std::string, impl::Visualizer> &getInlineVisualizers() {
static std::map<std::string, impl::Visualizer> visualizers;
return visualizers;
}
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;

View File

@ -367,6 +367,7 @@ namespace hex::init {
ContentRegistry::PatternLanguage::impl::getFunctions().clear();
ContentRegistry::PatternLanguage::impl::getPragmas().clear();
ContentRegistry::PatternLanguage::impl::getVisualizers().clear();
ContentRegistry::PatternLanguage::impl::getInlineVisualizers().clear();
ContentRegistry::Views::impl::getEntries().clear();
impl::PopupBase::getOpenPopups().clear();

View File

@ -13,6 +13,7 @@ add_library(${PROJECT_NAME} SHARED
source/content/pl_builtin_functions.cpp
source/content/pl_pragmas.cpp
source/content/pl_visualizers.cpp
source/content/pl_inline_visualizers.cpp
source/content/settings_entries.cpp
source/content/tools_entries.cpp
source/content/data_processor_nodes.cpp

View File

@ -1,6 +1,7 @@
#pragma once
#include <hex/api/task.hpp>
#include <hex/api/content_registry.hpp>
#include <pl/patterns/pattern.hpp>
#include <pl/pattern_visitor.hpp>
@ -61,7 +62,7 @@ namespace hex::plugin::builtin::ui {
void makeSelectable(const pl::ptrn::Pattern &pattern);
void drawValueColumn(pl::ptrn::Pattern& pattern);
void drawVisualizer(const std::vector<pl::core::Token::Literal> &arguments, pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &iterable, bool reset);
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);
bool createTreeNode(const pl::ptrn::Pattern& pattern, bool leaf = false);

View File

@ -0,0 +1,68 @@
#include <hex/api/content_registry.hpp>
#include <imgui.h>
#include <pl/patterns/pattern.hpp>
#include <pl/patterns/pattern_padding.hpp>
#include <hex/helpers/fmt.hpp>
#include <fonts/codicons_font.h>
#include <romfs/romfs.hpp>
namespace hex::plugin::builtin {
namespace {
void drawColorInlineVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments) {
auto r = arguments[0].toFloatingPoint();
auto g = arguments[1].toFloatingPoint();
auto b = arguments[2].toFloatingPoint();
auto a = arguments[3].toFloatingPoint();
ImGui::ColorButton("color", ImVec4(r / 255.0F, g / 255.0F, b / 255.0F, a / 255.0F), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
}
void drawGaugeInlineVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments) {
auto value = arguments[0].toFloatingPoint();
const auto color = ImGui::GetStyleColorVec4(ImGuiCol_Text);
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(color.x, color.y, color.z, 0.2F));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(color.x, color.y, color.z, 0.5F));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0F);
ImGui::ProgressBar(value / 100.0F, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()), "");
ImGui::PopStyleVar(1);
ImGui::PopStyleColor(3);
}
void drawButtonInlineVisualizer(pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0.5F));
if (ImGui::Button(hex::format(" {} {}", ICON_VS_PLAY, pattern.getFormattedValue()).c_str(), ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()))) {
auto *evaluator = pattern.getEvaluator();
const auto functionName = arguments[0].toString(false);
const auto &function = evaluator->findFunction(functionName);
if (function.has_value())
function->func(evaluator, { pattern.clone() });
}
ImGui::PopStyleVar(2);
}
}
void registerPatternLanguageInlineVisualizers() {
ContentRegistry::PatternLanguage::addInlineVisualizer("color", drawColorInlineVisualizer, 4);
ContentRegistry::PatternLanguage::addInlineVisualizer("gauge", drawGaugeInlineVisualizer, 1);
ContentRegistry::PatternLanguage::addInlineVisualizer("button", drawButtonInlineVisualizer, 1);
}
}

View File

@ -15,6 +15,7 @@ namespace hex::plugin::builtin {
void registerPatternLanguageFunctions();
void registerPatternLanguagePragmas();
void registerPatternLanguageVisualizers();
void registerPatternLanguageInlineVisualizers();
void registerCommandPaletteCommands();
void registerSettings();
void loadSettings();
@ -57,6 +58,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
registerPatternLanguageFunctions();
registerPatternLanguagePragmas();
registerPatternLanguageVisualizers();
registerPatternLanguageInlineVisualizers();
registerCommandPaletteCommands();
registerSettings();
loadSettings();

View File

@ -219,11 +219,9 @@ namespace hex::plugin::builtin::ui {
ImGui::TableNextColumn();
}
void PatternDrawer::drawVisualizer(const std::vector<pl::core::Token::Literal> &arguments, pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &iterable, bool reset) {
void PatternDrawer::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) {
auto visualizerName = arguments.front().toString(true);
const auto &visualizers = ContentRegistry::PatternLanguage::impl::getVisualizers();
if (auto entry = visualizers.find(visualizerName); entry != visualizers.end()) {
const auto &[name, visualizer] = *entry;
if (visualizer.parameterCount != arguments.size() - 1) {
@ -248,12 +246,12 @@ namespace hex::plugin::builtin::ui {
const auto value = pattern.getFormattedValue();
const auto width = ImGui::GetColumnWidth();
if (const auto &arguments = pattern.getAttributeArguments("hex::visualize"); !arguments.empty()) {
if (const auto &visualizeArgs = pattern.getAttributeArguments("hex::visualize"); !visualizeArgs.empty()) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0.5F));
bool shouldReset = false;
if (ImGui::Button(hex::format("{} {}", ICON_VS_EYE_WATCH, value).c_str(), ImVec2(width, ImGui::GetTextLineHeight()))) {
if (ImGui::Button(hex::format(" {} {}", ICON_VS_EYE_WATCH, value).c_str(), ImVec2(width, ImGui::GetTextLineHeight()))) {
auto previousPattern = this->m_currVisualizedPattern;
this->m_currVisualizedPattern = &pattern;
@ -270,12 +268,14 @@ namespace hex::plugin::builtin::ui {
if (ImGui::BeginPopup("Visualizer")) {
if (this->m_currVisualizedPattern == &pattern) {
drawVisualizer(arguments, pattern, dynamic_cast<pl::ptrn::IIterable&>(pattern), !this->m_visualizedPatterns.contains(&pattern) || shouldReset);
drawVisualizer(ContentRegistry::PatternLanguage::impl::getVisualizers(), visualizeArgs, pattern, dynamic_cast<pl::ptrn::IIterable&>(pattern), !this->m_visualizedPatterns.contains(&pattern) || shouldReset);
this->m_visualizedPatterns.insert(&pattern);
}
ImGui::EndPopup();
}
} else if (const auto &inlineVisualizeArgs = pattern.getAttributeArguments("hex::inline_visualize"); !inlineVisualizeArgs.empty()) {
drawVisualizer(ContentRegistry::PatternLanguage::impl::getInlineVisualizers(), inlineVisualizeArgs, pattern, dynamic_cast<pl::ptrn::IIterable&>(pattern), true);
} else {
ImGui::TextFormatted("{}", value);
}
@ -660,20 +660,16 @@ namespace hex::plugin::builtin::ui {
drawSizeColumn(pattern);
drawTypenameColumn(pattern, "struct");
if (this->isEditingPattern(pattern)) {
if (pattern.getWriteFormatterFunction().empty())
ImGui::TextFormatted("{}", pattern.getFormattedValue());
else {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
auto value = pattern.toString();
if (ImGui::InputText("##Value", value, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
pattern.setValue(value);
this->resetEditing();
}
ImGui::PopItemWidth();
ImGui::PopStyleVar();
if (this->isEditingPattern(pattern) && !pattern.getWriteFormatterFunction().empty()) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
auto value = pattern.toString();
if (ImGui::InputText("##Value", value, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
pattern.setValue(value);
this->resetEditing();
}
ImGui::PopItemWidth();
ImGui::PopStyleVar();
} else {
drawValueColumn(pattern);
}
@ -712,20 +708,16 @@ namespace hex::plugin::builtin::ui {
drawSizeColumn(pattern);
drawTypenameColumn(pattern, "union");
if (this->isEditingPattern(pattern)) {
if (pattern.getWriteFormatterFunction().empty())
ImGui::TextFormatted("{}", pattern.getFormattedValue());
else {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
auto value = pattern.toString();
if (ImGui::InputText("##Value", value, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
pattern.setValue(value);
this->resetEditing();
}
ImGui::PopItemWidth();
ImGui::PopStyleVar();
if (this->isEditingPattern(pattern) && !pattern.getWriteFormatterFunction().empty()) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
auto value = pattern.toString();
if (ImGui::InputText("##Value", value, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
pattern.setValue(value);
this->resetEditing();
}
ImGui::PopItemWidth();
ImGui::PopStyleVar();
} else {
drawValueColumn(pattern);
}