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

@@ -4,8 +4,8 @@
#include <hex/helpers/crypto.hpp>
#include <content/popups/popup_notification.hpp>
#include <content/popups/popup_text_input.hpp>
#include <popups/popup_notification.hpp>
#include <popups/popup_text_input.hpp>
#include <nlohmann/json.hpp>
#include <romfs/romfs.hpp>
@@ -276,11 +276,11 @@ namespace hex::plugin::builtin {
if (password.empty())
achievement.setUnlocked(true);
else
PopupTextInput::open("Enter Password", "Enter the password to unlock this achievement", [password, &achievement](const std::string &input) {
ui::PopupTextInput::open("Enter Password", "Enter the password to unlock this achievement", [password, &achievement](const std::string &input) {
if (input == password)
achievement.setUnlocked(true);
else
PopupInfo::open("The password you entered was incorrect.");
ui::PopupInfo::open("The password you entered was incorrect.");
});
});
@@ -301,7 +301,7 @@ namespace hex::plugin::builtin {
return false;
}
PopupInfo::open(challengeDescription);
ui::PopupInfo::open(challengeDescription);
return true;

View File

@@ -197,7 +197,7 @@ namespace hex::plugin::builtin {
class NodeBufferPatch : public dp::Node {
public:
NodeBufferPatch() : Node("hex.builtin.nodes.buffer.patch.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.patch.input.patch"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.common.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { }
NodeBufferPatch() : Node("hex.builtin.nodes.buffer.patch.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.patch.input.patch"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.ui.common.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { }
void process() override {
auto buffer = this->getBufferOnInput(0);

View File

@@ -14,8 +14,8 @@
#include <wolv/io/fs.hpp>
#include <wolv/utils/string.hpp>
#include <content/popups/popup_notification.hpp>
#include <content/popups/popup_question.hpp>
#include <popups/popup_notification.hpp>
#include <popups/popup_question.hpp>
#include <content/popups/popup_tasks_waiting.hpp>
#include <content/popups/popup_unsaved_changes.hpp>
@@ -26,7 +26,7 @@ namespace hex::plugin::builtin {
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider); fileProvider != nullptr) {
fileProvider->setPath(path);
if (!provider->open() || !provider->isAvailable()) {
PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
} else {
EventProviderOpened::post(fileProvider);
@@ -41,7 +41,7 @@ namespace hex::plugin::builtin {
imhexClosing = false;
if (ImHexApi::Provider::isDirty() && !imhexClosing) {
glfwSetWindowShouldClose(window, GLFW_FALSE);
PopupQuestion::open("hex.builtin.popup.exit_application.desc"_lang,
ui::PopupQuestion::open("hex.builtin.popup.exit_application.desc"_lang,
[] {
imhexClosing = true;
for (const auto &provider : auto(ImHexApi::Provider::getProviders()))
@@ -104,7 +104,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) {
if (path.extension() == ".hexproj") {
if (!ProjectFile::load(path)) {
PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
ui::PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
} else {
FileProvider* newProvider = static_cast<FileProvider*>(
@@ -128,7 +128,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
[](const auto &path) {
if (!ProjectFile::load(path)) {
PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
ui::PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
});
}
@@ -149,7 +149,7 @@ namespace hex::plugin::builtin {
return;
}
if (!provider->open()) {
PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return;
}
@@ -158,7 +158,7 @@ namespace hex::plugin::builtin {
}
else if (!provider->hasLoadInterface()) {
if (!provider->open() || !provider->isAvailable()) {
PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return;
}
@@ -172,22 +172,22 @@ namespace hex::plugin::builtin {
});
RequestOpenInfoPopup::subscribe([](const std::string &message) {
PopupInfo::open(message);
ui::PopupInfo::open(message);
});
RequestOpenErrorPopup::subscribe([](const std::string &message) {
PopupError::open(message);
ui::PopupError::open(message);
});
RequestOpenFatalPopup::subscribe([](const std::string &message) {
PopupFatal::open(message);
ui::PopupFatal::open(message);
});
fs::setFileBrowserErrorCallback([](const std::string& errMsg){
#if defined(NFD_PORTAL)
PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));
ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));
#else
PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.common"_lang, errMsg));
ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.common"_lang, errMsg));
#endif
});

View File

@@ -3,7 +3,7 @@
#include <hex/api/project_file_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <wolv/utils/string.hpp>
@@ -13,7 +13,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
[](const auto &path) {
if (!ProjectFile::load(path)) {
PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
ui::PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
});
}
@@ -21,7 +21,7 @@ namespace hex::plugin::builtin {
void saveProject() {
if (ImHexApi::Provider::isValid() && ProjectFile::hasPath()) {
if (!ProjectFile::store()) {
PopupError::open("hex.builtin.popup.error.project.save"_lang);
ui::PopupError::open("hex.builtin.popup.error.project.save"_lang);
} else {
log::debug("Project saved");
}
@@ -36,7 +36,7 @@ namespace hex::plugin::builtin {
}
if (!ProjectFile::store(path)) {
PopupError::open("hex.builtin.popup.error.project.save"_lang);
ui::PopupError::open("hex.builtin.popup.error.project.save"_lang);
}
});
}

View File

@@ -1,16 +1,16 @@
#include <hex/helpers/logger.hpp>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
namespace hex::plugin::builtin {
void showError(const std::string& message){
PopupError::open(message);
ui::PopupError::open(message);
log::error(message);
}
void showWarning(const std::string& message){
PopupWarning::open(message);
ui::PopupWarning::open(message);
log::warn(message);
}
}

View File

@@ -14,8 +14,8 @@
#include <hex/helpers/debugging.hpp>
#include <content/global_actions.hpp>
#include <content/popups/popup_notification.hpp>
#include <content/popups/popup_text_input.hpp>
#include <popups/popup_notification.hpp>
#include <popups/popup_text_input.hpp>
#include <hex/api/workspace_manager.hpp>
#include <wolv/io/file.hpp>
@@ -50,19 +50,19 @@ namespace hex::plugin::builtin {
TaskManager::doLater([error]{
switch (error) {
case IPSError::InvalidPatchHeader:
PopupError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_header_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_header_error"_lang);
break;
case IPSError::AddressOutOfRange:
PopupError::open("hex.builtin.menu.file.export.ips.popup.address_out_of_range_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.address_out_of_range_error"_lang);
break;
case IPSError::PatchTooLarge:
PopupError::open("hex.builtin.menu.file.export.ips.popup.patch_too_large_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.patch_too_large_error"_lang);
break;
case IPSError::InvalidPatchFormat:
PopupError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_format_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_format_error"_lang);
break;
case IPSError::MissingEOF:
PopupError::open("hex.builtin.menu.file.export.ips.popup.missing_eof_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.missing_eof_error"_lang);
break;
}
});
@@ -77,7 +77,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
wolv::io::File inputFile(path, wolv::io::File::Mode::Read);
if (!inputFile.isValid()) {
PopupError::open("hex.builtin.menu.file.import.base64.popup.open_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.import.base64.popup.open_error"_lang);
return;
}
@@ -87,26 +87,26 @@ namespace hex::plugin::builtin {
auto data = crypt::decode64(base64);
if (data.empty())
PopupError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang);
else {
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const std::fs::path &path) {
wolv::io::File outputFile(path, wolv::io::File::Mode::Create);
if (!outputFile.isValid())
PopupError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang);
outputFile.writeVector(data);
});
}
} else {
PopupError::open("hex.builtin.popup.file_open_error"_lang);
ui::PopupError::open("hex.builtin.popup.file_open_error"_lang);
}
});
}
void importIPSPatch() {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [path](auto &task) {
auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector();
auto patch = Patches::fromIPSPatch(patchData);
if (!patch.has_value()) {
@@ -132,7 +132,7 @@ namespace hex::plugin::builtin {
void importIPS32Patch() {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [path](auto &task) {
auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector();
auto patch = Patches::fromIPS32Patch(patchData);
if (!patch.has_value()) {
@@ -158,12 +158,12 @@ namespace hex::plugin::builtin {
void importModifiedFile() {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [path](auto &task) {
auto provider = ImHexApi::Provider::get();
auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector();
if (patchData.size() != provider->getActualSize()) {
PopupError::open("hex.builtin.menu.file.import.modified_file.popup.invalid_size"_lang);
ui::PopupError::open("hex.builtin.menu.file.import.modified_file.popup.invalid_size"_lang);
return;
}
@@ -199,11 +199,11 @@ namespace hex::plugin::builtin {
void exportBase64() {
fs::openFileBrowser(fs::DialogMode::Save, {}, [](const auto &path) {
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [path](auto &) {
wolv::io::File outputFile(path, wolv::io::File::Mode::Create);
if (!outputFile.isValid()) {
TaskManager::doLater([] {
PopupError::open("hex.builtin.menu.file.export.base64.popup.export_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.base64.popup.export_error"_lang);
});
return;
}
@@ -238,7 +238,7 @@ namespace hex::plugin::builtin {
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid()) {
TaskManager::doLater([] {
PopupError::open("hex.builtin.menu.file.export.as_language.popup.export_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.as_language.popup.export_error"_lang);
});
return;
}
@@ -251,7 +251,7 @@ namespace hex::plugin::builtin {
}
void exportReport() {
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [](auto &) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [](auto &) {
std::string data;
for (const auto &provider : ImHexApi::Provider::getProviders()) {
@@ -269,7 +269,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Save, { { "Markdown File", "md" }}, [&data](const auto &path) {
auto file = wolv::io::File(path, wolv::io::File::Mode::Create);
if (!file.isValid()) {
PopupError::open("hex.builtin.menu.file.export.report.popup.export_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.report.popup.export_error"_lang);
return;
}
@@ -295,14 +295,14 @@ namespace hex::plugin::builtin {
patches->get().at(0x00454F45) = value;
}
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [patches](auto &) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [patches](auto &) {
auto data = patches->toIPSPatch();
TaskManager::doLater([data] {
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
auto file = wolv::io::File(path, wolv::io::File::Mode::Create);
if (!file.isValid()) {
PopupError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang);
return;
}
@@ -334,14 +334,14 @@ namespace hex::plugin::builtin {
patches->get().at(0x45454F45) = value;
}
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [patches](auto &) {
TaskManager::createTask("hex.ui.common.processing", TaskManager::NoProgress, [patches](auto &) {
auto data = patches->toIPS32Patch();
TaskManager::doLater([data] {
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
auto file = wolv::io::File(path, wolv::io::File::Mode::Create);
if (!file.isValid()) {
PopupError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang);
ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang);
return;
}
@@ -542,14 +542,14 @@ namespace hex::plugin::builtin {
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.workspace", 4000);
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.layout", "hex.builtin.menu.workspace.layout.save" }, 1100, Shortcut::None, [] {
PopupTextInput::open("hex.builtin.popup.save_layout.title", "hex.builtin.popup.save_layout.desc", [](const std::string &name) {
ui::PopupTextInput::open("hex.builtin.popup.save_layout.title", "hex.builtin.popup.save_layout.desc", [](const std::string &name) {
LayoutManager::save(name);
});
}, ImHexApi::Provider::isValid);
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.layout" }, 1150, [] {
bool locked = LayoutManager::isLayoutLocked();
if (ImGui::MenuItem("hex.builtin.menu.workspace.layout.lock", nullptr, &locked, ImHexApi::Provider::isValid())) {
if (ImGui::MenuItem("hex.builtin.menu.workspace.layout.lock"_lang, nullptr, &locked, ImHexApi::Provider::isValid())) {
LayoutManager::lockLayout(locked);
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.layout_locked", locked);
}
@@ -584,7 +584,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.workspace" }, 3000);
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.create" }, 3100, Shortcut::None, [] {
PopupTextInput::open("hex.builtin.popup.create_workspace.title", "hex.builtin.popup.create_workspace.desc", [](const std::string &name) {
ui::PopupTextInput::open("hex.builtin.popup.create_workspace.title", "hex.builtin.popup.create_workspace.desc", [](const std::string &name) {
WorkspaceManager::createWorkspace(name);
});
}, ImHexApi::Provider::isValid);

View File

@@ -1,66 +0,0 @@
#include <hex/api/content_registry.hpp>
#include <imgui.h>
#include <pl/patterns/pattern.hpp>
#include <hex/helpers/fmt.hpp>
#include <fonts/codicons_font.h>
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() {
using ParamCount = pl::api::FunctionParameterCount;
ContentRegistry::PatternLanguage::addInlineVisualizer("color", drawColorInlineVisualizer, ParamCount::exactly(4));
ContentRegistry::PatternLanguage::addInlineVisualizer("gauge", drawGaugeInlineVisualizer, ParamCount::exactly(1));
ContentRegistry::PatternLanguage::addInlineVisualizer("button", drawButtonInlineVisualizer, ParamCount::exactly(1));
}
}

View File

@@ -1,36 +1,18 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <pl/patterns/pattern.hpp>
#include <pl/core/evaluator.hpp>
namespace hex::plugin::builtin {
void drawLinePlotVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawScatterPlotVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawImageVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawBitmapVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawDisassemblyVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void draw3DVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawSoundVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawChunkBasedEntropyVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawHexVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawCoordinateVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawTimestampVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void drawChunkBasedEntropyVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
void registerPatternLanguageVisualizers() {
using ParamCount = pl::api::FunctionParameterCount;
ContentRegistry::PatternLanguage::addVisualizer("line_plot", drawLinePlotVisualizer, ParamCount::exactly(1));
ContentRegistry::PatternLanguage::addVisualizer("scatter_plot", drawScatterPlotVisualizer, ParamCount::exactly(2));
ContentRegistry::PatternLanguage::addVisualizer("image", drawImageVisualizer, ParamCount::exactly(1));
ContentRegistry::PatternLanguage::addVisualizer("bitmap", drawBitmapVisualizer, ParamCount::exactly(3));
ContentRegistry::PatternLanguage::addVisualizer("disassembler", drawDisassemblyVisualizer, ParamCount::exactly(4));
ContentRegistry::PatternLanguage::addVisualizer("3d", draw3DVisualizer, ParamCount::between(2, 6));
ContentRegistry::PatternLanguage::addVisualizer("sound", drawSoundVisualizer, ParamCount::exactly(3));
ContentRegistry::PatternLanguage::addVisualizer("hex_viewer", drawHexVisualizer, ParamCount::exactly(1));
ContentRegistry::PatternLanguage::addVisualizer("chunk_entropy", drawChunkBasedEntropyVisualizer, ParamCount::exactly(2));
ContentRegistry::PatternLanguage::addVisualizer("hex_viewer", drawHexVisualizer, ParamCount::exactly(1));
ContentRegistry::PatternLanguage::addVisualizer("coordinates", drawCoordinateVisualizer, ParamCount::exactly(2));
ContentRegistry::PatternLanguage::addVisualizer("timestamp", drawTimestampVisualizer, ParamCount::exactly(1));
}
}
}

View File

@@ -1,908 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <fonts/codicons_font.h>
#include <fonts/blendericons_font.h>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex/helpers/opengl.hpp>
#include <opengl_support.h>
#include <GLFW/glfw3.h>
#include <numbers>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization_manager.hpp>
#include <romfs/romfs.hpp>
namespace hex::plugin::builtin {
namespace {
enum class IndexType {
U8,
U16,
U32,
Invalid,
};
struct Vectors {
std::vector<float> vertices;
std::vector<float> normals;
std::vector<float> colors;
std::vector<float> uv1;
std::vector<u8> indices8;
std::vector<u16> indices16;
std::vector<u32> indices32;
};
struct LineVectors {
std::vector<float> vertices;
std::vector<float> colors;
std::vector<u8> indices8;
std::vector<u16> indices16;
std::vector<u32> indices32;
};
struct Buffers {
gl::Buffer<float> vertices;
gl::Buffer<float> normals;
gl::Buffer<float> colors;
gl::Buffer<float> uv1;
gl::Buffer<u8> indices8;
gl::Buffer<u16> indices16;
gl::Buffer<u32> indices32;
};
struct LineBuffers {
gl::Buffer<float> vertices;
gl::Buffer<float> colors;
gl::Buffer<u8> indices8;
gl::Buffer<u16> indices16;
gl::Buffer<u32> indices32;
};
ImVec2 s_renderingWindowSize;
int s_drawMode = GL_TRIANGLES;
float s_nearLimit = 0.9F;
float s_farLimit = 100.0F;
float s_scaling = 1.0F;
float s_max;
bool s_isPerspective = true;
bool s_drawAxes = true;
bool s_drawGrid = true;
bool s_drawLightSource = true;
bool s_drawTexture = false;
bool s_shouldReset = false;
bool s_shouldUpdateLightSource = true;
bool s_shouldUpdateTexture = false;
IndexType s_indexType;
ImGuiExt::Texture s_modelTexture;
gl::Vector<float, 3> s_translation = { { 0.0F, 0.0F, -3.0F } };
gl::Vector<float, 3> s_rotation = { { 0.0F, 0.0F, 0.0F } };
gl::Vector<float, 3> s_lightPosition = { { -0.7F, 0.0F, 0.0F } };
gl::Vector<float, 4> s_lightBrightness = { { 0.5F, 0.5F, 0.5F, 32.0F } };
gl::Vector<float, 3> s_lightColor = { { 1.0F, 1.0F, 1.0f } };
gl::Matrix<float, 4, 4> s_rotate = gl::Matrix<float, 4, 4>::identity();
ImGuiExt::Texture s_texture;
std::fs::path s_texturePath;
template<typename T>
void indicesForLines(std::vector<T> &vertexIndices) {
std::vector<u32> indices;
u32 vertexCount = vertexIndices.size() / 3;
indices.resize(vertexCount * 6);
for (u32 i = 0; i < vertexCount; ++i) {
indices[i * 6] = vertexIndices[3 * i];
indices[i * 6 + 1] = vertexIndices[3 * i + 1];
indices[i * 6 + 2] = vertexIndices[3 * i + 1];
indices[i * 6 + 3] = vertexIndices[3 * i + 2];
indices[i * 6 + 4] = vertexIndices[3 * i + 2];
indices[i * 6 + 5] = vertexIndices[3 * i];
}
vertexIndices.resize(indices.size());
for (u32 i = 0; i < indices.size(); ++i)
vertexIndices[i] = indices[i];
}
float getBoundingBox(const std::vector<float> &vertices) {
gl::Vector<float, 4> minWorld(std::numeric_limits<float>::infinity()), maxWorld(-std::numeric_limits<float>::infinity());
for (u32 i = 0; i < vertices.size(); i += 3) {
if (vertices[i] < minWorld[0]) minWorld[0] = vertices[i];
if (vertices[i + 1] < minWorld[1]) minWorld[1] = vertices[i + 1];
if (vertices[i + 2] < minWorld[2]) minWorld[2] = vertices[i + 2];
if (vertices[i] > maxWorld[0]) maxWorld[0] = vertices[i];
if (vertices[i + 1] > maxWorld[1]) maxWorld[1] = vertices[i + 1];
if (vertices[i + 2] > maxWorld[2]) maxWorld[2] = vertices[i + 2];
}
minWorld[3] = 1;
maxWorld[3] = 1;
gl::Vector<float, 4> minCamera = minWorld, maxCamera = maxWorld;
if (maxCamera[3] != 0)
maxCamera = maxCamera * (1.0f / maxCamera[3]);
if (minCamera[3] != 0)
minCamera = minCamera * (1.0f / minCamera[3]);
float maxx = std::max(std::fabs(minCamera[0]), std::fabs(maxCamera[0]));
float maxy = std::max(std::fabs(minCamera[1]), std::fabs(maxCamera[1]));
return std::max(maxx, maxy);
}
void setDefaultColors(std::vector<float> &colors, float size, u32 color) {
colors.resize(size / 3 * 4);
float red = float((color >> 0) & 0xFF) / 255.0F;
float green = float((color >> 8) & 0xFF) / 255.0F;
float blue = float((color >> 16) & 0xFF) / 255.0F;
float alpha = float((color >> 24) & 0xFF) / 255.0F;
for (u32 i = 0; i < colors.size(); i += 4) {
colors[i] = red;
colors[i + 1] = green;
colors[i + 2] = blue;
colors[i + 3] = alpha;
}
}
void setNormals(const std::vector<float> &vertices, std::vector<float> &normals) {
for (u32 i = 0; i < normals.size(); i += 9) {
auto v1 = gl::Vector<float, 3>({vertices[i], vertices[i + 1], vertices[i + 2]});
auto v2 = gl::Vector<float, 3>({vertices[i + 3], vertices[i + 4], vertices[i + 5]});
auto v3 = gl::Vector<float, 3>({vertices[i + 6], vertices[i + 7], vertices[i + 8]});
auto normal = ((v2 - v1).cross(v3 - v1));
normals[i] += normal[0];
normals[i + 1] += normal[1];
normals[i + 2] += normal[2];
normals[i + 3] += normal[0];
normals[i + 4] += normal[1];
normals[i + 5] += normal[2];
normals[i + 6] += normal[0];
normals[i + 7] += normal[1];
normals[i + 8] += normal[2];
}
for (u32 i = 0; i < normals.size(); i += 3) {
auto normal = gl::Vector<float, 3>({normals[i], normals[i + 1], normals[i + 2]});
normal.normalize();
normals[i] = normal[0];
normals[i + 1] = normal[1];
normals[i + 2] = normal[2];
}
}
void setNormalsWithIndices(const std::vector<float> &vertices, std::vector<float> &normals, const std::vector<u32> &indices) {
for (u32 i = 0; i < indices.size(); i += 3) {
auto idx = indices[i];
auto idx1 = indices[i + 1];
auto idx2 = indices[i + 2];
auto v1 = gl::Vector<float, 3>({vertices[3 * idx], vertices[3 * idx + 1], vertices[3 * idx + 2]});
auto v2 = gl::Vector<float, 3>(
{vertices[3 * idx1], vertices[3 * idx1 + 1], vertices[3 * idx1 + 2]});
auto v3 = gl::Vector<float, 3>(
{vertices[3 * idx2], vertices[3 * idx2 + 1], vertices[3 * idx2 + 2]});
auto weighted = ((v2 - v1).cross(v3 - v1));
normals[3 * idx] += weighted[0];
normals[3 * idx + 1] += weighted[1];
normals[3 * idx + 2] += weighted[2];
normals[3 * idx1] += weighted[0];
normals[3 * idx1 + 1] += weighted[1];
normals[3 * idx1 + 2] += weighted[2];
normals[3 * idx2] += weighted[0];
normals[3 * idx2 + 1] += weighted[1];
normals[3 * idx2 + 2] += weighted[2];
}
for (u32 i = 0; i < normals.size(); i += 3) {
auto normal = gl::Vector<float, 3>({normals[i], normals[i + 1], normals[i + 2]});
auto mag = normal.magnitude();
if (mag > 0.001F) {
normals[i] = normal[0] / mag;
normals[i + 1] = normal[1] / mag;
normals[i + 2] = normal[2] / mag;
}
}
}
void loadVectors(Vectors &vectors, IndexType indexType) {
s_max = getBoundingBox(vectors.vertices);
if (s_drawTexture)
setDefaultColors(vectors.colors, vectors.vertices.size(), 0x00000000);
else if (vectors.colors.empty())
setDefaultColors(vectors.colors, vectors.vertices.size(), 0xFF337FFF);
if (vectors.normals.empty()) {
vectors.normals.resize(vectors.vertices.size());
if ((indexType == IndexType::U8 && vectors.indices8.empty()) || (indexType == IndexType::Invalid) ||
(indexType == IndexType::U16 && vectors.indices16.empty()) ||
(indexType == IndexType::U32 && vectors.indices32.empty())) {
setNormals(vectors.vertices, vectors.normals);
} else {
std::vector<u32> indices;
if (indexType == IndexType::U16) {
indices.resize(vectors.indices16.size());
for (u32 i = 0; i < vectors.indices16.size(); ++i)
indices[i] = vectors.indices16[i];
} else if (indexType == IndexType::U8) {
indices.resize(vectors.indices8.size());
for (u32 i = 0; i < vectors.indices8.size(); ++i)
indices[i] = vectors.indices8[i];
} else {
indices.resize(vectors.indices32.size());
for (u32 i = 0; i < vectors.indices32.size(); ++i)
indices[i] = vectors.indices32[i];
}
setNormalsWithIndices(vectors.vertices, vectors.normals, indices);
}
}
}
void loadLineVectors(LineVectors &lineVectors, IndexType indexType) {
s_max = getBoundingBox(lineVectors.vertices);
if (lineVectors.colors.empty())
setDefaultColors(lineVectors.colors, lineVectors.vertices.size(), 0xFF337FFF);
std::vector<u32> indices;
if (indexType == IndexType::U8)
indicesForLines(lineVectors.indices8);
else if (indexType == IndexType::U16)
indicesForLines(lineVectors.indices16);
else
indicesForLines(lineVectors.indices32);
}
void processKeyEvent(ImGuiKey key, float &variable, float incr, float accel) {
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(key))) {
auto temp = variable + incr * accel;
if (variable * temp < 0.0F)
variable = 0.0F;
else
variable = temp;
}
}
void processInputEvents(gl::Vector<float, 3> &rotation, gl::Vector<float, 3> &translation, float &scaling, float &nearLimit, float &farLimit) {
auto accel = 1.0F;
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftShift)) ||
ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_RightShift)))
accel = 10.0F;
auto dragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle);
if (dragDelta.x != 0) {
rotation[1] += dragDelta.x * 0.0075F * accel;
}
if (dragDelta.y != 0) {
rotation[0] += dragDelta.y * 0.0075F * accel;
}
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Middle);
dragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
translation[0] += dragDelta.x * 0.0075F * accel;
translation[1] -= dragDelta.y * 0.0075F * accel;
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Right);
auto scrollDelta = ImGui::GetIO().MouseWheel;
scaling += scrollDelta * 0.1F * accel;
if (scaling < 0.01F)
scaling = 0.01F;
processKeyEvent(ImGuiKey_Keypad4, translation[0], -0.1F, accel);
processKeyEvent(ImGuiKey_Keypad6, translation[0], 0.1F, accel);
processKeyEvent(ImGuiKey_Keypad8, translation[1], 0.1F, accel);
processKeyEvent(ImGuiKey_Keypad2, translation[1], -0.1F, accel);
processKeyEvent(ImGuiKey_Keypad1, translation[2], 0.1F, accel);
processKeyEvent(ImGuiKey_Keypad7, translation[2], -0.1F, accel);
processKeyEvent(ImGuiKey_Keypad9, nearLimit, -0.01F, accel);
processKeyEvent(ImGuiKey_Keypad3, nearLimit, 0.01F, accel);
if (ImHexApi::System::isDebugBuild()) {
processKeyEvent(ImGuiKey_KeypadDivide, farLimit, -1.0F, accel);
processKeyEvent(ImGuiKey_KeypadMultiply, farLimit, 1.0F, accel);
}
processKeyEvent(ImGuiKey_KeypadAdd, rotation[2], -0.075F, accel);
processKeyEvent(ImGuiKey_KeypadSubtract, rotation[2], 0.075F, accel);
rotation[2] = std::fmod(rotation[2], 2 * std::numbers::pi);
}
void bindBuffers(Buffers &buffers, const gl::VertexArray &vertexArray, Vectors vectors, IndexType indexType) {
buffers.vertices = {};
buffers.normals = {};
buffers.colors = {};
buffers.uv1 = {};
buffers.indices8 = {};
buffers.indices16 = {};
buffers.indices32 = {};
vertexArray.bind();
buffers.vertices = gl::Buffer<float>(gl::BufferType::Vertex, vectors.vertices);
buffers.colors = gl::Buffer<float>(gl::BufferType::Vertex, vectors.colors);
buffers.normals = gl::Buffer<float>(gl::BufferType::Vertex, vectors.normals);
if (indexType == IndexType::U8)
buffers.indices8 = gl::Buffer<u8>(gl::BufferType::Index, vectors.indices8);
else if (indexType == IndexType::U16)
buffers.indices16 = gl::Buffer<u16>(gl::BufferType::Index, vectors.indices16);
else
buffers.indices32 = gl::Buffer<u32>(gl::BufferType::Index, vectors.indices32);
if (!vectors.uv1.empty())
buffers.uv1 = gl::Buffer<float>(gl::BufferType::Vertex, vectors.uv1);
vertexArray.addBuffer(0, buffers.vertices);
vertexArray.addBuffer(1, buffers.colors, 4);
vertexArray.addBuffer(2, buffers.normals);
if (!vectors.uv1.empty())
vertexArray.addBuffer(3, buffers.uv1, 2);
buffers.vertices.unbind();
buffers.colors.unbind();
buffers.normals.unbind();
if (!vectors.uv1.empty())
buffers.uv1.unbind();
if (indexType == IndexType::U8)
buffers.indices8.unbind();
else if (indexType == IndexType::U16)
buffers.indices16.unbind();
else if (indexType == IndexType::U32)
buffers.indices32.unbind();
vertexArray.unbind();
}
void bindLineBuffers(LineBuffers &lineBuffers, const gl::VertexArray &vertexArray, const LineVectors &lineVectors, IndexType indexType) {
lineBuffers.vertices = {};
lineBuffers.colors = {};
lineBuffers.indices8 = {};
lineBuffers.indices16 = {};
lineBuffers.indices32 = {};
vertexArray.bind();
lineBuffers.vertices = gl::Buffer<float>(gl::BufferType::Vertex, lineVectors.vertices);
lineBuffers.colors = gl::Buffer<float>(gl::BufferType::Vertex, lineVectors.colors);
if (indexType == IndexType::U8)
lineBuffers.indices8 = gl::Buffer<u8>(gl::BufferType::Index, lineVectors.indices8);
else if (indexType == IndexType::U16)
lineBuffers.indices16 = gl::Buffer<u16>(gl::BufferType::Index, lineVectors.indices16);
else
lineBuffers.indices32 = gl::Buffer<u32>(gl::BufferType::Index, lineVectors.indices32);
vertexArray.addBuffer(0, lineBuffers.vertices);
vertexArray.addBuffer(1, lineBuffers.colors, 4);
lineBuffers.vertices.unbind();
lineBuffers.colors.unbind();
if (indexType == IndexType::U8)
lineBuffers.indices8.unbind();
else if (indexType == IndexType::U16)
lineBuffers.indices16.unbind();
else if (indexType == IndexType::U32)
lineBuffers.indices32.unbind();
vertexArray.unbind();
}
void drawWindow(const ImGuiExt::Texture &texture, ImVec2 &renderingWindowSize, const gl::Matrix<float, 4, 4> &mvp) {
auto textureSize = texture.getSize();
auto textureWidth = textureSize.x;
auto textureHeight = textureSize.y;
ImVec2 screenPos = ImGui::GetCursorScreenPos();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowSizeConstraints(scaled({ 350, 350 }), ImVec2(FLT_MAX, FLT_MAX));
if (ImGui::BeginChild("##image", textureSize, ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_Border, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
renderingWindowSize = ImGui::GetContentRegionAvail();
ImGui::Image(texture, textureSize, ImVec2(0, 1), ImVec2(1, 0));
if (s_drawAxes) {
gl::Matrix<float, 4, 4> axes = gl::Matrix<float, 4, 4>::identity();
axes(0, 3) = 1.0f;
axes(1, 3) = 1.0f;
axes(2, 3) = 1.0f;
axes = axes * mvp;
bool showX = axes(0, 3) > 0.0f;
bool showY = axes(1, 3) > 0.0f;
bool showZ = axes(2, 3) > 0.0f;
axes.updateRow(0, axes.getRow(0) * (1.0f / axes(0, 3)));
axes.updateRow(1, axes.getRow(1) * (1.0f / axes(1, 3)));
axes.updateRow(2, axes.getRow(2) * (1.0f / axes(2, 3)));
auto axesPosx = (axes.getColumn(0) + 1.0f) * (textureWidth / 2.0f);
auto axesPosy = (axes.getColumn(1) + 1.0f) * (-textureHeight / 2.0f) + textureHeight;
ImDrawList *drawList = ImGui::GetWindowDrawList();
if (showX)
drawList->AddText(ImVec2(axesPosx[0], axesPosy[0]) + screenPos, IM_COL32(255, 0, 0, 255), "X");
if (showY)
drawList->AddText(ImVec2(axesPosx[1], axesPosy[1]) + screenPos, IM_COL32(0, 255, 0, 255), "Y");
if (showZ)
drawList->AddText(ImVec2(axesPosx[2], axesPosy[2]) + screenPos, IM_COL32(0, 0, 255, 255), "Z");
}
if (ImHexApi::System::isDebugBuild()) {
auto mousePos = ImClamp(ImGui::GetMousePos() - screenPos, { 0, 0 }, textureSize);
ImDrawList *drawList = ImGui::GetWindowDrawList();
drawList->AddText(
screenPos + scaled({ 5, 5 }),
ImGui::GetColorU32(ImGuiCol_Text),
hex::format("X: {:.5}\nY: {:.5}", mousePos.x, mousePos.y).c_str());
}
}
ImGui::EndChild();
ImGui::PopStyleVar();
// Draw axis arrows toggle
{
ImGui::PushID(1);
if (ImGuiExt::DimmedIconToggle(ICON_BI_EMPTY_ARROWS, &s_drawAxes))
s_shouldReset = true;
ImGui::PopID();
}
ImGui::SameLine();
// Draw grid toggle
{
ImGui::PushID(2);
if (ImGuiExt::DimmedIconToggle(s_isPerspective ? ICON_BI_GRID : ICON_VS_SYMBOL_NUMBER, &s_drawGrid))
s_shouldReset = true;
ImGui::PopID();
}
ImGui::SameLine();
// Draw light source toggle
{
ImGui::PushID(3);
if (ImGuiExt::DimmedIconToggle(ICON_VS_LIGHTBULB, &s_drawLightSource))
s_shouldReset = true;
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("LightSettings");
}
if (ImGui::BeginPopup("LightSettings")) {
if (ImGui::DragFloat3("hex.builtin.pl_visualizer.3d.light_position"_lang, s_lightPosition.data(), 0.05F)) {
s_shouldUpdateLightSource = true;
}
ImGui::SliderFloat("hex.builtin.pl_visualizer.3d.ambient_brightness"_lang, &s_lightBrightness.data()[0], 0, 2);
ImGui::SliderFloat("hex.builtin.pl_visualizer.3d.diffuse_brightness"_lang, &s_lightBrightness.data()[1], 0, 2);
ImGui::SliderFloat("hex.builtin.pl_visualizer.3d.specular_brightness"_lang, &s_lightBrightness.data()[2], 0, 2);
ImGui::SliderFloat("hex.builtin.pl_visualizer.3d.object_reflectiveness"_lang, &s_lightBrightness.data()[3], 0, 64);
if (ImGui::ColorEdit3("hex.builtin.pl_visualizer.3d.light_color"_lang, s_lightColor.data()))
s_shouldUpdateLightSource = true;
ImGui::EndPopup();
}
ImGui::PopID();
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
// Draw projection toggle
{
ImGui::PushID(4);
if (ImGuiExt::DimmedIconToggle(ICON_BI_VIEW_PERSPECTIVE, ICON_BI_VIEW_ORTHO, &s_isPerspective)) {
s_shouldReset = true;
}
ImGui::PopID();
}
ImGui::SameLine();
// Draw solid / line mode toggle
{
ImGui::PushID(4);
bool isSolid = s_drawMode == GL_TRIANGLES;
if (ImGuiExt::DimmedIconToggle(ICON_BI_MOD_SOLIDIFY, ICON_BI_CUBE , &isSolid)) {
s_shouldReset = true;
s_drawMode = isSolid ? GL_TRIANGLES : GL_LINES;
}
ImGui::PopID();
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if (ImGuiExt::DimmedButton("hex.builtin.common.reset"_lang, ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
s_translation = { { 0.0F, 0.0F, -3.0F } };
s_rotation = { { 0.0F, 0.0F, 0.0F } };
s_scaling = 1.0F;
}
// Draw more settings
if (ImGui::CollapsingHeader("hex.builtin.pl_visualizer.3d.more_settings"_lang)) {
if (ImGuiExt::InputFilePicker("hex.builtin.pl_visualizer.3d.texture_file"_lang, s_texturePath, {}))
s_shouldUpdateTexture = true;
}
}
}
void draw3DVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static gl::LightSourceVectors sourceVectors(20);
static gl::VertexArray sourceVertexArray = gl::VertexArray();
static gl::LightSourceBuffers sourceBuffers(sourceVertexArray, sourceVectors);
static gl::VertexArray gridVertexArray = gl::VertexArray();
static gl::GridVectors gridVectors(9);
static gl::GridBuffers gridBuffers(gridVertexArray, gridVectors);
static gl::VertexArray axesVertexArray = gl::VertexArray();
static gl::AxesVectors axesVectors;
static gl::AxesBuffers axesBuffers(axesVertexArray, axesVectors);
static gl::VertexArray vertexArray = gl::VertexArray();
static Buffers buffers;
static LineBuffers lineBuffers;
std::shared_ptr<pl::ptrn::Pattern> verticesPattern = arguments[0].toPattern();
std::shared_ptr<pl::ptrn::Pattern> indicesPattern = arguments[1].toPattern();
std::shared_ptr<pl::ptrn::Pattern> normalsPattern = nullptr;
std::shared_ptr<pl::ptrn::Pattern> colorsPattern = nullptr;
std::shared_ptr<pl::ptrn::Pattern> uvPattern1 = nullptr;
std::string textureFile;
if (arguments.size() > 2) {
normalsPattern = arguments[2].toPattern();
if (arguments.size() > 3) {
colorsPattern = arguments[3].toPattern();
if (arguments.size() > 4) {
uvPattern1 = arguments[4].toPattern();
if (arguments.size() > 5)
textureFile = arguments[5].toString();
}
}
}
if (shouldReset)
s_shouldReset = true;
const auto fontSize = ImGui::GetFontSize();
const auto framePad = ImGui::GetStyle().FramePadding;
float minSize = fontSize * 8_scaled + framePad.x * 20_scaled;
minSize = minSize > 200_scaled ? minSize : 200_scaled;
if (s_renderingWindowSize.x <= 0 || s_renderingWindowSize.y <= 0)
s_renderingWindowSize = { minSize, minSize };
if (!textureFile.empty())
s_texturePath = textureFile;
else
s_drawTexture = false;
if (s_renderingWindowSize.x < minSize)
s_renderingWindowSize.x = minSize;
if (s_renderingWindowSize.y < minSize)
s_renderingWindowSize.y = minSize;
gl::Matrix<float, 4, 4> mvp(0);
processInputEvents(s_rotation, s_translation, s_scaling, s_nearLimit, s_farLimit);
if (s_shouldReset) {
s_shouldReset = false;
auto *iterable = dynamic_cast<pl::ptrn::IIterable*>(indicesPattern.get());
if (iterable != nullptr && iterable->getEntryCount() > 0) {
const auto &content = iterable->getEntry(0);
if (content->getSize() == 1) {
s_indexType = IndexType::U8;
} else if (content->getSize() == 2) {
s_indexType = IndexType::U16;
} else if (content->getSize() == 4) {
s_indexType = IndexType::U32;
} else {
s_indexType = IndexType::Invalid;
}
}
if (s_drawMode == GL_TRIANGLES) {
Vectors vectors;
vectors.vertices = patternToArray<float>(verticesPattern.get());
if (s_indexType == IndexType::U16)
vectors.indices16 = patternToArray<u16>(indicesPattern.get());
else if (s_indexType == IndexType::U32)
vectors.indices32 = patternToArray<u32>(indicesPattern.get());
else if (s_indexType == IndexType::U8)
vectors.indices8 = patternToArray<u8>(indicesPattern.get());
if (colorsPattern != nullptr)
vectors.colors = patternToArray<float>(colorsPattern.get());
if (normalsPattern != nullptr)
vectors.normals = patternToArray<float>(normalsPattern.get());
if (uvPattern1 != nullptr)
vectors.uv1 = patternToArray<float>(uvPattern1.get());
loadVectors(vectors, s_indexType);
bindBuffers(buffers, vertexArray, vectors, s_indexType);
} else {
LineVectors lineVectors;
lineVectors.vertices = patternToArray<float>(verticesPattern.get());
if (s_indexType == IndexType::U16)
lineVectors.indices16 = patternToArray<u16>(indicesPattern.get());
else if (s_indexType == IndexType::U32)
lineVectors.indices32 = patternToArray<u32>(indicesPattern.get());
else if (s_indexType == IndexType::U8)
lineVectors.indices8 = patternToArray<u8>(indicesPattern.get());
if (colorsPattern != nullptr)
lineVectors.colors = patternToArray<float>(colorsPattern.get());
loadLineVectors(lineVectors, s_indexType);
bindLineBuffers(lineBuffers, vertexArray, lineVectors, s_indexType);
}
}
if (s_shouldUpdateLightSource) {
s_shouldUpdateLightSource = false;
sourceVectors.moveTo(s_lightPosition);
sourceVectors.setColor(s_lightColor[0], s_lightColor[1], s_lightColor[2]);
sourceBuffers.moveVertices(sourceVertexArray, sourceVectors);
sourceBuffers.updateColors(sourceVertexArray, sourceVectors);
}
{
gl::Matrix<float, 4, 4> model(0);
gl::Matrix<float, 4, 4> scaledModel(0);
gl::Matrix<float, 4, 4> view(0);
gl::Matrix<float, 4, 4> projection(0);
unsigned width = std::floor(s_renderingWindowSize.x);
unsigned height = std::floor(s_renderingWindowSize.y);
gl::FrameBuffer frameBuffer(width, height);
gl::Texture renderTexture(width, height);
frameBuffer.attachTexture(renderTexture);
frameBuffer.bind();
s_rotate = gl::getRotationMatrix<float>(s_rotation, true, gl::RotationSequence::ZYX);
gl::Matrix<float, 4, 4> scale = gl::Matrix<float, 4, 4>::identity();
gl::Matrix<float, 4, 4> scaleForVertices = gl::Matrix<float, 4, 4>::identity();
gl::Matrix<float, 4, 4> translate = gl::Matrix<float, 4, 4>::identity();
float totalScale;
float viewWidth = s_renderingWindowSize.x / 500.0f;
float viewHeight = s_renderingWindowSize.y / 500.0f;
glViewport(0,0 , GLsizei(renderTexture.getWidth()), GLsizei(renderTexture.getHeight()));
glDepthRangef(s_nearLimit, s_farLimit);
glClearColor(0.00F, 0.00F, 0.00F, 0.00f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
if (s_isPerspective == 0) {
projection = gl::GetOrthographicMatrix(viewWidth, viewHeight, s_nearLimit, s_farLimit, false);
totalScale = s_scaling / (std::fabs(s_translation[2]));
scale(0, 0) = totalScale;
scale(1, 1) = totalScale;
scale(2, 2) = totalScale;
translate(3, 0) = s_translation[0] / std::fabs(s_translation[2]);
translate(3, 1) = s_translation[1] / std::fabs(s_translation[2]);
translate(3, 2) = s_translation[2];
} else {
projection = gl::GetPerspectiveMatrix(viewWidth, viewHeight, s_nearLimit, s_farLimit, false);
totalScale = s_scaling;
scale(0, 0) = totalScale;
scale(1, 1) = totalScale;
scale(2, 2) = totalScale;
translate(3, 0) = s_translation[0];
translate(3, 1) = s_translation[1];
translate(3, 2) = s_translation[2];
}
totalScale /= (3.0f * s_max);
scaleForVertices(0, 0) = totalScale;
scaleForVertices(1, 1) = totalScale;
scaleForVertices(2, 2) = totalScale;
model = s_rotate * scale;
scaledModel = s_rotate * scaleForVertices;
view = translate;
mvp = model * view * projection;
if (s_drawMode == GL_TRIANGLES) {
static gl::Shader shader = gl::Shader(romfs::get("shaders/default/vertex.glsl").string(),
romfs::get("shaders/default/fragment.glsl").string());
shader.bind();
shader.setUniform("modelScale", scaledModel);
shader.setUniform("modelMatrix", model);
shader.setUniform("viewMatrix", view);
shader.setUniform("projectionMatrix",projection);
shader.setUniform("lightPosition", s_lightPosition);
shader.setUniform("lightBrightness", s_lightBrightness);
shader.setUniform("lightColor", s_lightColor);
vertexArray.bind();
if (s_shouldUpdateTexture) {
s_shouldUpdateTexture = false;
s_modelTexture = ImGuiExt::Texture(s_texturePath, ImGuiExt::Texture::Filter::Nearest);
}
if (s_drawTexture)
glBindTexture(GL_TEXTURE_2D, s_modelTexture);
if (s_indexType == IndexType::U8) {
buffers.indices8.bind();
if (buffers.indices8.getSize() == 0)
buffers.vertices.draw(s_drawMode);
else
buffers.indices8.draw(s_drawMode);
buffers.indices8.unbind();
} else if (s_indexType == IndexType::U16) {
buffers.indices16.bind();
if (buffers.indices16.getSize() == 0)
buffers.vertices.draw(s_drawMode);
else
buffers.indices16.draw(s_drawMode);
buffers.indices16.unbind();
} else {
buffers.indices32.bind();
if (buffers.indices32.getSize() == 0)
buffers.vertices.draw(s_drawMode);
else
buffers.indices32.draw(s_drawMode);
buffers.indices32.unbind();
}
} else {
static gl::Shader lineShader = gl::Shader(
romfs::get("shaders/default/lineVertex.glsl").string(),
romfs::get("shaders/default/lineFragment.glsl").string());
lineShader.bind();
lineShader.setUniform("modelMatrix", scaledModel);
lineShader.setUniform("viewMatrix", view);
lineShader.setUniform("projectionMatrix", projection);
vertexArray.bind();
if (s_indexType == IndexType::U8) {
lineBuffers.indices8.bind();
if (lineBuffers.indices8.getSize() == 0)
lineBuffers.vertices.draw(s_drawMode);
else
lineBuffers.indices8.draw(s_drawMode);
lineBuffers.indices8.unbind();
} else if (s_indexType == IndexType::U16) {
lineBuffers.indices16.bind();
if (lineBuffers.indices16.getSize() == 0)
lineBuffers.vertices.draw(s_drawMode);
else
lineBuffers.indices16.draw(s_drawMode);
lineBuffers.indices16.unbind();
} else {
lineBuffers.indices32.bind();
if (lineBuffers.indices32.getSize() == 0)
lineBuffers.vertices.draw(s_drawMode);
else
lineBuffers.indices32.draw(s_drawMode);
lineBuffers.indices32.unbind();
}
}
if (s_drawGrid || s_drawAxes) {
static auto gridAxesShader = gl::Shader(
romfs::get("shaders/default/lineVertex.glsl").string(),
romfs::get("shaders/default/lineFragment.glsl").string());
gridAxesShader.bind();
gridAxesShader.setUniform("modelMatrix", model);
gridAxesShader.setUniform("viewMatrix", view);
gridAxesShader.setUniform("projectionMatrix", projection);
if (s_drawGrid) {
gridVertexArray.bind();
gridBuffers.getIndices().bind();
gridBuffers.getIndices().draw(GL_LINES);
gridBuffers.getIndices().unbind();
gridVertexArray.unbind();
}
if (s_drawAxes) {
axesVertexArray.bind();
axesBuffers.getIndices().bind();
axesBuffers.getIndices().draw(GL_LINES);
axesBuffers.getIndices().unbind();
axesVertexArray.unbind();
}
gridAxesShader.unbind();
}
if (s_drawLightSource) {
static auto sourceShader = gl::Shader(
romfs::get("shaders/default/lightVertex.glsl").string(),
romfs::get("shaders/default/lightFragment.glsl").string());
sourceShader.bind();
sourceShader.setUniform("modelMatrix", model);
sourceShader.setUniform("viewMatrix", view);
sourceShader.setUniform("projectionMatrix", projection);
sourceVertexArray.bind();
sourceBuffers.getIndices().bind();
sourceBuffers.getIndices().draw(GL_TRIANGLES);
sourceBuffers.getIndices().unbind();
sourceVertexArray.unbind();
sourceShader.unbind();
}
vertexArray.unbind();
frameBuffer.unbind();
s_texture = ImGuiExt::Texture(renderTexture.release(), GLsizei(renderTexture.getWidth()), GLsizei(renderTexture.getHeight()));
drawWindow(s_texture, s_renderingWindowSize, mvp);
}
}
}

View File

@@ -1,13 +1,11 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <implot.h>
#include <imgui.h>
#include <content/helpers/diagrams.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
#include <pl/patterns/pattern.hpp>
namespace hex::plugin::builtin {
void drawChunkBasedEntropyVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {

View File

@@ -1,116 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <imgui.h>
#include <hex/api/task_manager.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/helpers/http_requests.hpp>
#include <nlohmann/json.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
#include <romfs/romfs.hpp>
namespace hex::plugin::builtin {
void drawCoordinateVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static ImVec2 coordinate;
static double latitude, longitude;
static std::string address;
static std::mutex addressMutex;
static TaskHolder addressTask;
static auto mapTexture = ImGuiExt::Texture(romfs::get("assets/common/map.jpg").span(), ImGuiExt::Texture::Filter::Linear);
static ImVec2 mapSize = scaled(ImVec2(500, 500 / mapTexture.getAspectRatio()));
if (shouldReset) {
std::scoped_lock lock(addressMutex);
address.clear();
latitude = arguments[0].toFloatingPoint();
longitude = arguments[1].toFloatingPoint();
// Convert latitude and longitude to X/Y coordinates on the image
coordinate.x = float((longitude + 180) / 360 * mapSize.x);
coordinate.y = float((-latitude + 90) / 180 * mapSize.y);
}
const auto startPos = ImGui::GetWindowPos() + ImGui::GetCursorPos();
// Draw background image
ImGui::Image(mapTexture, mapSize);
// Draw Longitude / Latitude text below image
ImGui::PushTextWrapPos(startPos.x + mapSize.x);
ImGuiExt::TextFormattedWrapped("{}: {:.0f}° {:.0f}' {:.4f}\" {} | {}: {:.0f}° {:.0f}' {:.4f}\" {}",
"hex.builtin.pl_visualizer.coordinates.latitude"_lang,
std::floor(std::abs(latitude)),
std::floor(std::abs(latitude - std::floor(latitude)) * 60),
(std::abs(latitude - std::floor(latitude)) * 60 - std::floor(std::abs(latitude - std::floor(latitude)) * 60)) * 60,
latitude >= 0 ? "N" : "S",
"hex.builtin.pl_visualizer.coordinates.longitude"_lang,
std::floor(std::abs(longitude)),
std::floor(std::abs(longitude - std::floor(longitude)) * 60),
(std::abs(longitude - std::floor(longitude)) * 60 - std::floor(std::abs(longitude - std::floor(longitude)) * 60)) * 60,
longitude >= 0 ? "E" : "W"
);
ImGui::PopTextWrapPos();
if (addressTask.isRunning()) {
ImGuiExt::TextSpinner("hex.builtin.pl_visualizer.coordinates.querying"_lang);
} else if (address.empty()) {
if (ImGuiExt::DimmedButton("hex.builtin.pl_visualizer.coordinates.query"_lang)) {
addressTask = TaskManager::createBackgroundTask("hex.builtin.pl_visualizer.coordinates.querying"_lang, [lat = latitude, lon = longitude](auto &) {
constexpr static auto ApiURL = "https://geocode.maps.co/reverse?lat={}&lon={}&format=jsonv2";
HttpRequest request("GET", hex::format(ApiURL, lat, lon));
auto response = request.execute().get();
if (!response.isSuccess())
return;
try {
auto json = nlohmann::json::parse(response.getData());
auto jsonAddr = json["address"];
std::scoped_lock lock(addressMutex);
if (jsonAddr.contains("village")) {
address = hex::format("{} {}, {} {}",
jsonAddr["village"].get<std::string>(),
jsonAddr["county"].get<std::string>(),
jsonAddr["state"].get<std::string>(),
jsonAddr["country"].get<std::string>());
} else if (jsonAddr.contains("city")) {
address = hex::format("{}, {} {}, {} {}",
jsonAddr["road"].get<std::string>(),
jsonAddr["quarter"].get<std::string>(),
jsonAddr["city"].get<std::string>(),
jsonAddr["state"].get<std::string>(),
jsonAddr["country"].get<std::string>());
}
} catch (std::exception &) {
address = std::string("hex.builtin.pl_visualizer.coordinates.querying_no_address"_lang);
}
});
}
} else {
ImGui::PushTextWrapPos(startPos.x + mapSize.x);
ImGuiExt::TextFormattedWrapped("{}", address);
ImGui::PopTextWrapPos();
}
// Draw crosshair pointing to the coordinates
{
constexpr static u32 CrossHairColor = 0xFF00D0D0;
constexpr static u32 BorderColor = 0xFF000000;
auto drawList = ImGui::GetWindowDrawList();
drawList->AddLine(startPos + ImVec2(coordinate.x, 0), startPos + ImVec2(coordinate.x, mapSize.y), CrossHairColor, 2_scaled);
drawList->AddLine(startPos + ImVec2(0, coordinate.y), startPos + ImVec2(mapSize.x, coordinate.y), CrossHairColor, 2_scaled);
drawList->AddCircleFilled(startPos + coordinate, 5, CrossHairColor);
drawList->AddCircle(startPos + coordinate, 5, BorderColor);
}
}
}

View File

@@ -1,70 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <imgui.h>
#include <capstone/capstone.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/api/localization_manager.hpp>
namespace hex::plugin::builtin {
void drawDisassemblyVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
struct Disassembly {
u64 address;
std::vector<u8> bytes;
std::string instruction;
};
static std::vector<Disassembly> disassembly;
if (shouldReset) {
auto pattern = arguments[0].toPattern();
auto baseAddress = arguments[1].toUnsigned();
auto architecture = arguments[2].toUnsigned();
auto mode = arguments[3].toUnsigned();
disassembly.clear();
csh capstone;
if (cs_open(static_cast<cs_arch>(architecture), static_cast<cs_mode>(mode), &capstone) == CS_ERR_OK) {
cs_option(capstone, CS_OPT_SKIPDATA, CS_OPT_ON);
auto data = pattern->getBytes();
cs_insn *instructions = nullptr;
size_t instructionCount = cs_disasm(capstone, data.data(), data.size(), baseAddress, 0, &instructions);
for (size_t i = 0; i < instructionCount; i++) {
disassembly.push_back({ instructions[i].address, { instructions[i].bytes, instructions[i].bytes + instructions[i].size }, hex::format("{} {}", instructions[i].mnemonic, instructions[i].op_str) });
}
cs_free(instructions, instructionCount);
cs_close(&capstone);
}
}
if (ImGui::BeginTable("##disassembly", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, scaled(ImVec2(0, 300)))) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.builtin.common.address"_lang);
ImGui::TableSetupColumn("hex.builtin.common.bytes"_lang);
ImGui::TableSetupColumn("hex.builtin.common.instruction"_lang);
ImGui::TableHeadersRow();
for (auto &entry : disassembly) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:08X}", entry.address);
ImGui::TableNextColumn();
std::string bytes;
for (auto byte : entry.bytes)
bytes += hex::format("{0:02X} ", byte);
ImGui::TextUnformatted(bytes.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.instruction.c_str());
}
ImGui::EndTable();
}
}
}

View File

@@ -1,9 +1,10 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <imgui.h>
#include <pl/pattern_language.hpp>
#include <pl/patterns/pattern.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
#include <ui/hex_editor.hpp>
#include <content/providers/memory_file_provider.hpp>

View File

@@ -1,61 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <implot.h>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
void drawImageVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static ImGuiExt::Texture texture;
static float scale = 1.0F;
if (shouldReset) {
auto pattern = arguments[0].toPattern();
auto data = pattern->getBytes();
texture = ImGuiExt::Texture(data.data(), data.size(), ImGuiExt::Texture::Filter::Nearest);
scale = 200_scaled / texture.getSize().x;
}
if (texture.isValid())
ImGui::Image(texture, texture.getSize() * scale);
if (ImGui::IsWindowHovered()) {
auto scrollDelta = ImGui::GetIO().MouseWheel;
if (scrollDelta != 0.0F) {
scale += scrollDelta * 0.1F;
scale = std::clamp(scale, 0.1F, 10.0F);
}
}
}
void drawBitmapVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static ImGuiExt::Texture texture;
static float scale = 1.0F;
if (shouldReset) {
auto pattern = arguments[0].toPattern();
auto width = arguments[1].toUnsigned();
auto height = arguments[2].toUnsigned();
auto data = pattern->getBytes();
texture = ImGuiExt::Texture(data.data(), data.size(), ImGuiExt::Texture::Filter::Nearest, width, height);
}
if (texture.isValid())
ImGui::Image(texture, texture.getSize() * scale);
if (ImGui::IsWindowHovered()) {
auto scrollDelta = ImGui::GetIO().MouseWheel;
if (scrollDelta != 0.0F) {
scale += scrollDelta * 0.1F;
scale = std::clamp(scale, 0.1F, 10.0F);
}
}
}
}

View File

@@ -1,30 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <implot.h>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
void drawLinePlotVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static std::vector<float> values;
auto dataPattern = arguments[0].toPattern();
if (ImPlot::BeginPlot("##plot", ImVec2(400, 250), ImPlotFlags_CanvasOnly)) {
ImPlot::SetupAxes("X", "Y", ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit);
if (shouldReset) {
values.clear();
values = sampleData(patternToArray<float>(dataPattern.get()), ImPlot::GetPlotSize().x * 4);
}
ImPlot::PlotLine("##line", values.data(), values.size());
ImPlot::EndPlot();
}
}
}

View File

@@ -1,33 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <implot.h>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
void drawScatterPlotVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static std::vector<float> xValues, yValues;
auto xPattern = arguments[0].toPattern();
auto yPattern = arguments[1].toPattern();
if (ImPlot::BeginPlot("##plot", ImVec2(400, 250), ImPlotFlags_CanvasOnly)) {
ImPlot::SetupAxes("X", "Y", ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit);
if (shouldReset) {
xValues.clear(); yValues.clear();
xValues = sampleData(patternToArray<float>(xPattern.get()), ImPlot::GetPlotSize().x * 4);
yValues = sampleData(patternToArray<float>(yPattern.get()), ImPlot::GetPlotSize().x * 4);
}
ImPlot::PlotScatter("##scatter", xValues.data(), yValues.data(), xValues.size());
ImPlot::EndPlot();
}
}
}

View File

@@ -1,124 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <implot.h>
#include <imgui.h>
#include <miniaudio.h>
#include <fonts/codicons_font.h>
#include <hex/api/task_manager.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
void drawSoundVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
auto wavePattern = arguments[0].toPattern();
auto channels = arguments[1].toUnsigned();
auto sampleRate = arguments[2].toUnsigned();
static std::vector<i16> waveData, sampledData;
static ma_device audioDevice;
static ma_device_config deviceConfig;
static bool shouldStop = false;
static u64 index = 0;
static TaskHolder resetTask;
if (sampleRate == 0)
throw std::logic_error(hex::format("Invalid sample rate: {}", sampleRate));
else if (channels == 0)
throw std::logic_error(hex::format("Invalid channel count: {}", channels));
if (shouldReset) {
waveData.clear();
resetTask = TaskManager::createTask("Visualizing...", TaskManager::NoProgress, [=](Task &) {
ma_device_stop(&audioDevice);
waveData = patternToArray<i16>(wavePattern.get());
sampledData = sampleData(waveData, 300_scaled * 4);
index = 0;
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = ma_format_s16;
deviceConfig.playback.channels = channels;
deviceConfig.sampleRate = sampleRate;
deviceConfig.pUserData = &waveData;
deviceConfig.dataCallback = [](ma_device *device, void *pOutput, const void *, ma_uint32 frameCount) {
if (index >= waveData.size()) {
index = 0;
shouldStop = true;
return;
}
ma_copy_pcm_frames(pOutput, waveData.data() + index, frameCount, device->playback.format, device->playback.channels);
index += frameCount;
};
ma_device_init(nullptr, &deviceConfig, &audioDevice);
});
}
ImGui::BeginDisabled(resetTask.isRunning());
ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, ImVec2(0, 0));
if (ImPlot::BeginPlot("##amplitude_plot", scaled(ImVec2(300, 80)), ImPlotFlags_CanvasOnly | ImPlotFlags_NoFrame | ImPlotFlags_NoInputs)) {
ImPlot::SetupAxes("##time", "##amplitude", ImPlotAxisFlags_NoDecorations | ImPlotAxisFlags_NoMenus, ImPlotAxisFlags_NoDecorations | ImPlotAxisFlags_NoMenus);
ImPlot::SetupAxesLimits(0, waveData.size(), std::numeric_limits<i16>::min(), std::numeric_limits<i16>::max(), ImGuiCond_Always);
double dragPos = index;
if (ImPlot::DragLineX(1, &dragPos, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
if (dragPos < 0) dragPos = 0;
if (dragPos >= waveData.size()) dragPos = waveData.size() - 1;
index = dragPos;
}
ImPlot::PlotLine("##audio", sampledData.data(), sampledData.size());
ImPlot::EndPlot();
}
ImPlot::PopStyleVar();
{
const u64 min = 0, max = waveData.size();
ImGui::PushItemWidth(300_scaled);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::SliderScalar("##index", ImGuiDataType_U64, &index, &min, &max, "");
ImGui::PopStyleVar();
ImGui::PopItemWidth();
}
if (shouldStop) {
shouldStop = false;
ma_device_stop(&audioDevice);
}
bool playing = ma_device_is_started(&audioDevice);
if (ImGuiExt::IconButton(playing ? ICON_VS_DEBUG_PAUSE : ICON_VS_PLAY, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
if (playing)
ma_device_stop(&audioDevice);
else
ma_device_start(&audioDevice);
}
ImGui::SameLine();
if (ImGuiExt::IconButton(ICON_VS_DEBUG_STOP, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
index = 0;
ma_device_stop(&audioDevice);
}
ImGui::EndDisabled();
ImGui::SameLine();
if (resetTask.isRunning())
ImGuiExt::TextSpinner("");
else
ImGuiExt::TextFormatted("{:02d}:{:02d} / {:02d}:{:02d}",
(index / sampleRate) / 60, (index / sampleRate) % 60,
(waveData.size() / sampleRate) / 60, (waveData.size() / sampleRate) % 60);
}
}

View File

@@ -1,107 +0,0 @@
#include <hex/helpers/utils.hpp>
#include <content/pl_visualizers/visualizer_helpers.hpp>
#include <numbers>
#include <imgui.h>
#include <hex/api/imhex_api.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
#include <chrono>
#include <fmt/chrono.h>
namespace hex::plugin::builtin {
void drawTimestampVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments) {
time_t timestamp = arguments[0].toUnsigned();
auto tm = fmt::gmtime(timestamp);
auto date = std::chrono::year_month_day(std::chrono::year(tm.tm_year + 1900), std::chrono::month(tm.tm_mon + 1), std::chrono::day(tm.tm_mday));
auto lastMonthDay = std::chrono::year_month_day_last(date.year(), date.month() / std::chrono::last);
auto firstWeekDay = std::chrono::weekday(std::chrono::year_month_day(date.year(), date.month(), std::chrono::day(1)));
const auto scale = 1_scaled * (ImHexApi::Fonts::getFontSize() / ImHexApi::Fonts::DefaultFontSize);
// Draw calendar
if (ImGui::BeginTable("##month_table", 2)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
// Draw centered month name and year
ImGuiExt::TextFormattedCenteredHorizontal("{:%B %Y}", tm);
if (ImGui::BeginTable("##days_table", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX, ImVec2(160, 120) * scale)) {
constexpr static auto ColumnFlags = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoReorder | ImGuiTableColumnFlags_NoHide;
ImGui::TableSetupColumn("M", ColumnFlags);
ImGui::TableSetupColumn("T", ColumnFlags);
ImGui::TableSetupColumn("W", ColumnFlags);
ImGui::TableSetupColumn("T", ColumnFlags);
ImGui::TableSetupColumn("F", ColumnFlags);
ImGui::TableSetupColumn("S", ColumnFlags);
ImGui::TableSetupColumn("S", ColumnFlags);
ImGui::TableHeadersRow();
ImGui::TableNextRow();
// Skip days before the first day of the month
for (u8 i = 0; i < firstWeekDay.c_encoding() - 1; ++i)
ImGui::TableNextColumn();
// Draw days
for (u8 i = 1; i <= u32(lastMonthDay.day()); ++i) {
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{:02}", i);
if (std::chrono::day(i) == date.day())
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGuiExt::GetCustomColorU32(ImGuiCustomCol_ToolbarRed));
if (std::chrono::weekday(std::chrono::year_month_day(date.year(), date.month(), std::chrono::day(i))) == std::chrono::Sunday)
ImGui::TableNextRow();
}
ImGui::EndTable();
}
ImGui::TableNextColumn();
// Draw analog clock
const auto size = ImVec2(120, 120) * scale;
if (ImGui::BeginChild("##clock", size + ImVec2(0, ImGui::GetTextLineHeightWithSpacing()))) {
// Draw centered digital hour, minute and seconds
ImGuiExt::TextFormattedCenteredHorizontal("{:%H:%M:%S}", tm);
auto drawList = ImGui::GetWindowDrawList();
const auto center = ImGui::GetWindowPos() + ImVec2(0, ImGui::GetTextLineHeightWithSpacing()) + size / 2;
// Draw clock face
drawList->AddCircle(center, size.x / 2, ImGui::GetColorU32(ImGuiCol_TextDisabled), 0);
auto sectionPos = [](float i) {
return ImVec2(std::sin(-i * 30.0F * std::numbers::pi / 180.0F + std::numbers::pi / 2), std::cos(-i * 30.0F * std::numbers::pi / 180.0F + std::numbers::pi / 2));
};
// Draw clock sections and numbers
for (u8 i = 0; i < 12; ++i) {
auto text = hex::format("{}", (((i + 2) % 12) + 1));
drawList->AddLine(center + sectionPos(i) * size / 2.2, center + sectionPos(i) * size / 2, ImGui::GetColorU32(ImGuiCol_TextDisabled), 1_scaled);
drawList->AddText(center + sectionPos(i) * size / 3 - ImGui::CalcTextSize(text.c_str()) / 2, ImGui::GetColorU32(ImGuiCol_Text), text.c_str());
}
// Draw hour hand
drawList->AddLine(center, center + sectionPos((tm.tm_hour + 9) % 12 + float(tm.tm_min) / 60.0) * size / 3.5, ImGui::GetColorU32(ImGuiCol_TextDisabled), 3_scaled);
// Draw minute hand
drawList->AddLine(center, center + sectionPos((float(tm.tm_min) / 5.0F) - 3) * size / 2.5, ImGui::GetColorU32(ImGuiCol_TextDisabled), 3_scaled);
// Draw second hand
drawList->AddLine(center, center + sectionPos((float(tm.tm_sec) / 5.0F) - 3) * size / 2.5, ImGuiExt::GetCustomColorU32(ImGuiCustomCol_ToolbarRed), 2_scaled);
}
ImGui::EndChild();
ImGui::EndTable();
}
}
}

View File

@@ -9,7 +9,7 @@
#include "content/providers/memory_file_provider.hpp"
#include "content/providers/view_provider.hpp"
#include <content/providers/process_memory_provider.hpp>
#include "content/popups/popup_notification.hpp"
#include <popups/popup_notification.hpp>
#include "content/helpers/notification.hpp"
#include <hex/api/project_file_manager.hpp>

View File

@@ -289,7 +289,7 @@ namespace hex::plugin::builtin {
ImGui::Separator();
ImGuiExt::InputHexadecimal("hex.builtin.common.size"_lang, &m_size, ImGuiInputTextFlags_CharsHexadecimal);
ImGuiExt::InputHexadecimal("hex.ui.common.size"_lang, &m_size, ImGuiInputTextFlags_CharsHexadecimal);
if (m_port < 0)
m_port = 0;

View File

@@ -1,6 +1,6 @@
#include "content/providers/memory_file_provider.hpp"
#include "content/providers/file_provider.hpp"
#include "content/popups/popup_text_input.hpp"
#include <popups/popup_text_input.hpp>
#include <cstring>
@@ -146,7 +146,7 @@ namespace hex::plugin::builtin {
}
void MemoryFileProvider::renameFile() {
PopupTextInput::open("hex.builtin.provider.mem_file.rename", "hex.builtin.provider.mem_file.rename.desc", [this](const std::string &name) {
ui::PopupTextInput::open("hex.builtin.provider.mem_file.rename", "hex.builtin.provider.mem_file.rename.desc", [this](const std::string &name) {
m_name = name;
RequestUpdateWindowTitle::post();
});

View File

@@ -252,9 +252,9 @@ namespace hex::plugin::builtin {
#endif
if (ImGui::BeginTable("##module_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, ImVec2(availableX, availableY))) {
ImGui::TableSetupColumn("hex.builtin.common.region"_lang);
ImGui::TableSetupColumn("hex.builtin.common.size"_lang);
ImGui::TableSetupColumn("hex.builtin.common.name"_lang);
ImGui::TableSetupColumn("hex.ui.common.region"_lang);
ImGui::TableSetupColumn("hex.ui.common.size"_lang);
ImGui::TableSetupColumn("hex.ui.common.name"_lang);
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableHeadersRow();

View File

@@ -15,7 +15,7 @@
#include <wolv/utils/string.hpp>
#include <content/recent.hpp>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <fonts/codicons_font.h>
namespace hex::plugin::builtin::recent {
@@ -131,7 +131,7 @@ namespace hex::plugin::builtin::recent {
if (!recentFile.isValid())
continue;
std::string displayName = hex::format("[{}] {}", "hex.builtin.common.project"_lang, wolv::util::toUTF8String(projectFileName));
std::string displayName = hex::format("[{}] {}", "hex.ui.common.project"_lang, wolv::util::toUTF8String(projectFileName));
nlohmann::json recentEntry {
{"type", "project"},
@@ -224,7 +224,7 @@ namespace hex::plugin::builtin::recent {
provider->loadSettings(recentEntry.data);
if (!provider->open() || !provider->isAvailable()) {
PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return;
}
@@ -269,21 +269,21 @@ namespace hex::plugin::builtin::recent {
if (ImGui::BeginTable("##RecentEntryTooltip", 2, ImGuiTableFlags_RowBg)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.common.name"_lang);
ImGui::TextUnformatted("hex.ui.common.name"_lang);
ImGui::TableNextColumn();
ImGui::TextUnformatted(recentEntry.displayName.c_str());
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.common.type"_lang);
ImGui::TextUnformatted("hex.ui.common.type"_lang);
ImGui::TableNextColumn();
if (isProject) {
ImGui::TextUnformatted("hex.builtin.common.project"_lang);
ImGui::TextUnformatted("hex.ui.common.project"_lang);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.common.path"_lang);
ImGui::TextUnformatted("hex.ui.common.path"_lang);
ImGui::TableNextColumn();
ImGui::TextUnformatted(recentEntry.data["path"].get<std::string>().c_str());
} else {
@@ -303,7 +303,7 @@ namespace hex::plugin::builtin::recent {
}
if (ImGui::BeginPopup(popupID.c_str())) {
if (ImGui::MenuItem("hex.builtin.common.remove"_lang)) {
if (ImGui::MenuItem("hex.ui.common.remove"_lang)) {
shouldRemove = true;
}
ImGui::EndPopup();

View File

@@ -197,7 +197,7 @@ namespace hex::plugin::builtin {
auto format = [this] -> std::string {
auto value = m_value * 30;
if (value == 0)
return "hex.builtin.common.off"_lang;
return "hex.ui.common.off"_lang;
else if (value < 60)
return hex::format("hex.builtin.setting.general.auto_backup_time.format.simple"_lang, value);
else

View File

@@ -9,7 +9,7 @@
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <wolv/io/file.hpp>
@@ -113,7 +113,7 @@ namespace hex::plugin::builtin {
wolv::io::File output(outputPath, wolv::io::File::Mode::Create);
if (!output.isValid()) {
PopupError::open("hex.builtin.tools.file_tools.combiner.error.open_output"_lang);
ui::PopupError::open("hex.builtin.tools.file_tools.combiner.error.open_output"_lang);
return;
}
@@ -126,7 +126,7 @@ namespace hex::plugin::builtin {
wolv::io::File input(file, wolv::io::File::Mode::Read);
if (!input.isValid()) {
PopupError::open(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, wolv::util::toUTF8String(file)));
ui::PopupError::open(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, wolv::util::toUTF8String(file)));
return;
}
@@ -142,7 +142,7 @@ namespace hex::plugin::builtin {
selectedIndex = 0;
outputPath.clear();
PopupInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang);
ui::PopupInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang);
});
}
}

View File

@@ -7,7 +7,7 @@
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp>
@@ -54,7 +54,7 @@ namespace hex::plugin::builtin {
wolv::io::File file(selectedFile, wolv::io::File::Mode::Write);
if (!file.isValid()) {
PopupError::open("hex.builtin.tools.file_tools.shredder.error.open"_lang);
ui::PopupError::open("hex.builtin.tools.file_tools.shredder.error.open"_lang);
return;
}
@@ -128,7 +128,7 @@ namespace hex::plugin::builtin {
file.remove();
PopupInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang);
ui::PopupInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang);
});
}
}

View File

@@ -9,7 +9,7 @@
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp>
@@ -101,12 +101,12 @@ namespace hex::plugin::builtin {
wolv::io::File file(selectedFile, wolv::io::File::Mode::Read);
if (!file.isValid()) {
PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.open"_lang);
ui::PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.open"_lang);
return;
}
if (file.getSize() < splitSize) {
PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.size"_lang);
ui::PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.size"_lang);
return;
}
@@ -122,7 +122,7 @@ namespace hex::plugin::builtin {
wolv::io::File partFile(path, wolv::io::File::Mode::Create);
if (!partFile.isValid()) {
PopupError::open(hex::format("hex.builtin.tools.file_tools.splitter.picker.error.create"_lang, index));
ui::PopupError::open(hex::format("hex.builtin.tools.file_tools.splitter.picker.error.create"_lang, index));
return;
}
@@ -135,7 +135,7 @@ namespace hex::plugin::builtin {
index++;
}
PopupInfo::open("hex.builtin.tools.file_tools.splitter.picker.success"_lang);
ui::PopupInfo::open("hex.builtin.tools.file_tools.splitter.picker.success"_lang);
});
}
}

View File

@@ -21,7 +21,7 @@ namespace hex::plugin::builtin {
});
}
} else {
if (ImGui::Button("hex.builtin.common.cancel"_lang)) {
if (ImGui::Button("hex.ui.common.cancel"_lang)) {
request.cancel();
}
}
@@ -33,9 +33,9 @@ namespace hex::plugin::builtin {
ImGuiExt::Header("hex.builtin.tools.file_uploader.recent"_lang);
if (ImGui::BeginTable("##links", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg, ImVec2(0, 200))) {
ImGui::TableSetupColumn("hex.builtin.common.file"_lang);
ImGui::TableSetupColumn("hex.builtin.common.link"_lang);
ImGui::TableSetupColumn("hex.builtin.common.size"_lang);
ImGui::TableSetupColumn("hex.ui.common.file"_lang);
ImGui::TableSetupColumn("hex.ui.common.link"_lang);
ImGui::TableSetupColumn("hex.ui.common.size"_lang);
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableHeadersRow();
@@ -81,11 +81,11 @@ namespace hex::plugin::builtin {
json.at("data").at("file").at("metadata").at("size").at("readable")
});
} catch (...) {
PopupError::open("hex.builtin.tools.file_uploader.invalid_response"_lang);
ui::PopupError::open("hex.builtin.tools.file_uploader.invalid_response"_lang);
}
} else if (response.getStatusCode() == 0) {
// Canceled by user, no action needed
} else PopupError::open(hex::format("hex.builtin.tools.file_uploader.error"_lang, response.getStatusCode()));
} else ui::PopupError::open(hex::format("hex.builtin.tools.file_uploader.error"_lang, response.getStatusCode()));
uploadProcess = {};
currFile.clear();

View File

@@ -13,7 +13,7 @@
#include <implot.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
namespace hex::plugin::builtin {
@@ -46,7 +46,7 @@ namespace hex::plugin::builtin {
// Task exception popup
for (const auto &task : TaskManager::getRunningTasks()) {
if (task->hadException()) {
PopupError::open(hex::format("hex.builtin.popup.error.task_exception"_lang, Lang(task->getUnlocalizedName()), task->getExceptionMessage()));
ui::PopupError::open(hex::format("hex.builtin.popup.error.task_exception"_lang, Lang(task->getUnlocalizedName()), task->getExceptionMessage()));
task->clearException();
break;
}

View File

@@ -6,13 +6,11 @@
#include "content/views/view_about.hpp"
#include "content/views/view_tools.hpp"
#include "content/views/view_data_inspector.hpp"
#include "content/views/view_disassembler.hpp"
#include "content/views/view_bookmarks.hpp"
#include "content/views/view_patches.hpp"
#include "content/views/view_command_palette.hpp"
#include "content/views/view_settings.hpp"
#include "content/views/view_data_processor.hpp"
#include "content/views/view_yara.hpp"
#include "content/views/view_constants.hpp"
#include "content/views/view_store.hpp"
#include "content/views/view_diff.hpp"
@@ -33,7 +31,6 @@ namespace hex::plugin::builtin {
ContentRegistry::Views::add<ViewDataInspector>();
ContentRegistry::Views::add<ViewHashes>();
ContentRegistry::Views::add<ViewInformation>();
ContentRegistry::Views::add<ViewDisassembler>();
ContentRegistry::Views::add<ViewBookmarks>();
ContentRegistry::Views::add<ViewPatches>();
ContentRegistry::Views::add<ViewTools>();
@@ -41,7 +38,6 @@ namespace hex::plugin::builtin {
ContentRegistry::Views::add<ViewAbout>();
ContentRegistry::Views::add<ViewSettings>();
ContentRegistry::Views::add<ViewDataProcessor>();
ContentRegistry::Views::add<ViewYara>();
ContentRegistry::Views::add<ViewConstants>();
ContentRegistry::Views::add<ViewStore>();
ContentRegistry::Views::add<ViewDiff>();

View File

@@ -351,30 +351,24 @@ namespace hex::plugin::builtin {
ImGui::TableHeadersRow();
ImGuiListClipper clipper;
clipper.Begin(plugins.size());
for (const auto &plugin : plugins) {
if (plugin.isLibraryPlugin())
continue;
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
const auto &plugin = plugins[i];
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(
plugin.isBuiltinPlugin() ? ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_Highlight) : ImGui::GetStyleColorVec4(ImGuiCol_Text),
"{}", plugin.getPluginName().c_str()
);
ImGui::TableNextColumn();
ImGui::TextUnformatted(plugin.getPluginAuthor().c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(plugin.getPluginDescription().c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(plugin.isLoaded() ? ICON_VS_CHECK : ICON_VS_CLOSE);
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(
plugin.isBuiltinPlugin() ? ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_Highlight) : ImGui::GetStyleColorVec4(ImGuiCol_Text),
"{}", plugin.getPluginName().c_str()
);
ImGui::TableNextColumn();
ImGui::TextUnformatted(plugin.getPluginAuthor().c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(plugin.getPluginDescription().c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(plugin.isLoaded() ? ICON_VS_CHECK : ICON_VS_CLOSE);
}
clipper.End();
ImGui::EndTable();
}
}
@@ -480,7 +474,7 @@ namespace hex::plugin::builtin {
}
} else {
// Draw a spinner while the release notes are loading
ImGuiExt::TextSpinner("hex.builtin.common.loading"_lang);
ImGuiExt::TextSpinner("hex.ui.common.loading"_lang);
}
}
@@ -597,7 +591,7 @@ namespace hex::plugin::builtin {
} catch (std::exception &e) {
commits.emplace_back(
"hex.builtin.common.error"_lang,
"hex.ui.common.error"_lang,
e.what(),
"",
"",
@@ -607,7 +601,7 @@ namespace hex::plugin::builtin {
} else {
// An error occurred, display it
commits.emplace_back(
"hex.builtin.common.error"_lang,
"hex.ui.common.error"_lang,
"HTTP " + std::to_string(response.getStatusCode()),
"",
"",
@@ -616,7 +610,7 @@ namespace hex::plugin::builtin {
}
} else {
// Draw a spinner while the commits are loading
ImGuiExt::TextSpinner("hex.builtin.common.loading"_lang);
ImGuiExt::TextSpinner("hex.ui.common.loading"_lang);
}
}

View File

@@ -104,7 +104,7 @@ namespace hex::plugin::builtin {
// Draw region
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{}: ", "hex.builtin.common.region"_lang.get());
ImGuiExt::TextFormatted("{}: ", "hex.ui.common.region"_lang.get());
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("[ 0x{:08X} - 0x{:08X} ] ", bookmark.region.getStartAddress(), bookmark.region.getEndAddress());
@@ -354,7 +354,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight);
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.common.address"_lang);
ImGui::TextUnformatted("hex.ui.common.address"_lang);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
@@ -405,7 +405,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
// Draw size of the bookmark
ImGui::TextUnformatted("hex.builtin.common.size"_lang);
ImGui::TextUnformatted("hex.ui.common.size"_lang);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted(hex::toByteString(region.size));

View File

@@ -332,7 +332,7 @@ namespace hex::plugin::builtin {
ImGui::EndTable();
}
ImGuiExt::DimmedButtonToggle("hex.builtin.common.edit"_lang, &m_tableEditingModeEnabled, ImVec2(ImGui::GetContentRegionAvail().x, 0));
ImGuiExt::DimmedButtonToggle("hex.ui.common.edit"_lang, &m_tableEditingModeEnabled, ImVec2(ImGui::GetContentRegionAvail().x, 0));
ImGui::NewLine();
ImGui::Separator();
@@ -350,9 +350,9 @@ namespace hex::plugin::builtin {
}
}();
std::array options = { "hex.builtin.common.little"_lang, "hex.builtin.common.big"_lang };
std::array options = { "hex.ui.common.little"_lang, "hex.ui.common.big"_lang };
if (ImGui::SliderInt("hex.builtin.common.endian"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
if (ImGui::SliderInt("hex.ui.common.endian"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
m_shouldInvalidate = true;
switch (selection) {
@@ -373,9 +373,9 @@ namespace hex::plugin::builtin {
case NumberDisplayStyle::Octal: return 2;
}
}();
std::array options = { "hex.builtin.common.decimal"_lang, "hex.builtin.common.hexadecimal"_lang, "hex.builtin.common.octal"_lang };
std::array options = { "hex.ui.common.decimal"_lang, "hex.ui.common.hexadecimal"_lang, "hex.ui.common.octal"_lang };
if (ImGui::SliderInt("hex.builtin.common.number_format"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
if (ImGui::SliderInt("hex.ui.common.number_format"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
m_shouldInvalidate = true;
switch (selection) {
@@ -390,7 +390,7 @@ namespace hex::plugin::builtin {
// Draw invert setting
{
int selection = m_invert ? 1 : 0;
std::array options = { "hex.builtin.common.no"_lang, "hex.builtin.common.yes"_lang };
std::array options = { "hex.ui.common.no"_lang, "hex.ui.common.yes"_lang };
if (ImGui::SliderInt("hex.builtin.view.data_inspector.invert"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
m_shouldInvalidate = true;

View File

@@ -1,5 +1,5 @@
#include "content/views/view_data_processor.hpp"
#include "content/popups/popup_notification.hpp"
#include <popups/popup_notification.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/project_file_manager.hpp>
@@ -852,7 +852,7 @@ namespace hex::plugin::builtin {
int nodeId;
if (ImNodes::IsNodeHovered(&nodeId) && workspace.currNodeError.has_value() && workspace.currNodeError->node->getId() == nodeId) {
ImGui::BeginTooltip();
ImGui::TextUnformatted("hex.builtin.common.error"_lang);
ImGui::TextUnformatted("hex.ui.common.error"_lang);
ImGui::Separator();
ImGui::TextUnformatted(workspace.currNodeError->message.c_str());
ImGui::EndTooltip();
@@ -1194,7 +1194,7 @@ namespace hex::plugin::builtin {
m_updateNodePositions = true;
} catch (nlohmann::json::exception &e) {
PopupError::open(hex::format("Failed to load nodes: {}", e.what()));
ui::PopupError::open(hex::format("Failed to load nodes: {}", e.what()));
}
}

View File

@@ -262,9 +262,9 @@ namespace hex::plugin::builtin {
// Draw the differences table
if (ImGui::BeginTable("##differences", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable, ImVec2(0, 200_scaled))) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.builtin.common.begin"_lang);
ImGui::TableSetupColumn("hex.builtin.common.end"_lang);
ImGui::TableSetupColumn("hex.builtin.common.type"_lang);
ImGui::TableSetupColumn("hex.ui.common.begin"_lang);
ImGui::TableSetupColumn("hex.ui.common.end"_lang);
ImGui::TableSetupColumn("hex.ui.common.type"_lang);
ImGui::TableHeadersRow();
// Draw the differences if the providers have been analyzed

View File

@@ -1,451 +0,0 @@
#include "content/views/view_disassembler.hpp"
#include <hex/providers/provider.hpp>
#include <hex/helpers/fmt.hpp>
#include <cstring>
using namespace std::literals::string_literals;
namespace hex::plugin::builtin {
ViewDisassembler::ViewDisassembler() : View::Window("hex.builtin.view.disassembler.name") {
EventProviderDeleted::subscribe(this, [this](const auto*) {
m_disassembly.clear();
});
}
ViewDisassembler::~ViewDisassembler() {
EventDataChanged::unsubscribe(this);
EventRegionSelected::unsubscribe(this);
EventProviderDeleted::unsubscribe(this);
}
void ViewDisassembler::disassemble() {
m_disassembly.clear();
m_disassemblerTask = TaskManager::createTask("hex.builtin.view.disassembler.disassembling", m_codeRegion.getSize(), [this](auto &task) {
csh capstoneHandle;
cs_insn *instructions = nullptr;
cs_mode mode = m_mode;
// Create a capstone disassembler instance
if (cs_open(Disassembler::toCapstoneArchitecture(m_architecture), mode, &capstoneHandle) == CS_ERR_OK) {
// Tell capstone to skip data bytes
cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
auto provider = ImHexApi::Provider::get();
std::vector<u8> buffer(2048, 0x00);
size_t size = m_codeRegion.getSize();
// Read the data in chunks and disassemble it
for (u64 address = 0; address < size; address += 2048) {
task.update(address);
// Read a chunk of data
size_t bufferSize = std::min(u64(2048), (size - address));
provider->read(m_codeRegion.getStartAddress() + address, buffer.data(), bufferSize);
// Ask capstone to disassemble the data
size_t instructionCount = cs_disasm(capstoneHandle, buffer.data(), bufferSize, m_baseAddress + address, 0, &instructions);
if (instructionCount == 0)
break;
// Reserve enough space for the disassembly
m_disassembly.reserve(m_disassembly.size() + instructionCount);
// Convert the capstone instructions to our disassembly format
u64 usedBytes = 0;
for (u32 i = 0; i < instructionCount; i++) {
const auto &instr = instructions[i];
Disassembly disassembly = { };
disassembly.address = instr.address;
disassembly.offset = m_codeRegion.getStartAddress() + address + usedBytes;
disassembly.size = instr.size;
disassembly.mnemonic = instr.mnemonic;
disassembly.operators = instr.op_str;
for (u16 j = 0; j < instr.size; j++)
disassembly.bytes += hex::format("{0:02X} ", instr.bytes[j]);
disassembly.bytes.pop_back();
m_disassembly.push_back(disassembly);
usedBytes += instr.size;
}
// If capstone couldn't disassemble all bytes in the buffer, we might have cut off an instruction
// Adjust the address,so it's being disassembled when we read the next chunk
if (instructionCount < bufferSize)
address -= (bufferSize - usedBytes);
// Clean up the capstone instructions
cs_free(instructions, instructionCount);
}
cs_close(&capstoneHandle);
}
});
}
void ViewDisassembler::drawContent() {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
ImGuiExt::Header("hex.builtin.view.disassembler.position"_lang, true);
// Draw base address input
ImGuiExt::InputHexadecimal("hex.builtin.view.disassembler.base"_lang, &m_baseAddress, ImGuiInputTextFlags_CharsHexadecimal);
// Draw region selection picker
ui::regionSelectionPicker(&m_codeRegion, provider, &m_range);
// Draw settings
{
ImGuiExt::Header("hex.builtin.common.settings"_lang);
// Draw architecture selector
if (ImGui::Combo("hex.builtin.view.disassembler.arch"_lang, reinterpret_cast<int *>(&m_architecture), Disassembler::ArchitectureNames.data(), Disassembler::getArchitectureSupportedCount()))
m_mode = cs_mode(0);
// Draw sub-settings for each architecture
if (ImGuiExt::BeginBox()) {
// Draw endian radio buttons. This setting is available for all architectures
static int littleEndian = true;
ImGui::RadioButton("hex.builtin.common.little_endian"_lang, &littleEndian, true);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.common.big_endian"_lang, &littleEndian, false);
ImGui::NewLine();
// Draw architecture specific settings
switch (m_architecture) {
case Architecture::ARM:
{
static int mode = CS_MODE_ARM;
ImGui::RadioButton("hex.builtin.view.disassembler.arm.arm"_lang, &mode, CS_MODE_ARM);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.arm.thumb"_lang, &mode, CS_MODE_THUMB);
static int extraMode = 0;
ImGui::RadioButton("hex.builtin.view.disassembler.arm.default"_lang, &extraMode, 0);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.arm.cortex_m"_lang, &extraMode, CS_MODE_MCLASS);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.arm.armv8"_lang, &extraMode, CS_MODE_V8);
m_mode = cs_mode(mode | extraMode);
}
break;
case Architecture::MIPS:
{
static int mode = CS_MODE_MIPS32;
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips32"_lang, &mode, CS_MODE_MIPS32);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips64"_lang, &mode, CS_MODE_MIPS64);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips32R6"_lang, &mode, CS_MODE_MIPS32R6);
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips2"_lang, &mode, CS_MODE_MIPS2);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips3"_lang, &mode, CS_MODE_MIPS3);
static bool microMode;
ImGui::Checkbox("hex.builtin.view.disassembler.mips.micro"_lang, &microMode);
m_mode = cs_mode(mode | (microMode ? CS_MODE_MICRO : cs_mode(0)));
}
break;
case Architecture::X86:
{
static int mode = CS_MODE_32;
ImGui::RadioButton("hex.builtin.view.disassembler.16bit"_lang, &mode, CS_MODE_16);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.32bit"_lang, &mode, CS_MODE_32);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.64bit"_lang, &mode, CS_MODE_64);
m_mode = cs_mode(mode);
}
break;
case Architecture::PPC:
{
static int mode = CS_MODE_32;
ImGui::RadioButton("hex.builtin.view.disassembler.32bit"_lang, &mode, CS_MODE_32);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.64bit"_lang, &mode, CS_MODE_64);
static bool qpx = false;
ImGui::Checkbox("hex.builtin.view.disassembler.ppc.qpx"_lang, &qpx);
#if CS_API_MAJOR >= 5
static bool spe = false;
ImGui::Checkbox("hex.builtin.view.disassembler.ppc.spe"_lang, &spe);
static bool booke = false;
ImGui::Checkbox("hex.builtin.view.disassembler.ppc.booke"_lang, &booke);
m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0)) | (spe ? CS_MODE_SPE : cs_mode(0)) | (booke ? CS_MODE_BOOKE : cs_mode(0)));
#else
m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0)));
#endif
}
break;
case Architecture::SPARC:
{
static bool v9Mode = false;
ImGui::Checkbox("hex.builtin.view.disassembler.sparc.v9"_lang, &v9Mode);
m_mode = cs_mode(v9Mode ? CS_MODE_V9 : cs_mode(0));
}
break;
#if CS_API_MAJOR >= 5
case Architecture::RISCV:
{
static int mode = CS_MODE_RISCV32;
ImGui::RadioButton("hex.builtin.view.disassembler.32bit"_lang, &mode, CS_MODE_RISCV32);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.64bit"_lang, &mode, CS_MODE_RISCV64);
static bool compressed = false;
ImGui::Checkbox("hex.builtin.view.disassembler.riscv.compressed"_lang, &compressed);
m_mode = cs_mode(mode | (compressed ? CS_MODE_RISCVC : cs_mode(0)));
}
break;
#endif
case Architecture::M68K:
{
static int selectedMode = 0;
std::pair<const char *, cs_mode> modes[] = {
{"hex.builtin.view.disassembler.m68k.000"_lang, CS_MODE_M68K_000},
{ "hex.builtin.view.disassembler.m68k.010"_lang, CS_MODE_M68K_010},
{ "hex.builtin.view.disassembler.m68k.020"_lang, CS_MODE_M68K_020},
{ "hex.builtin.view.disassembler.m68k.030"_lang, CS_MODE_M68K_030},
{ "hex.builtin.view.disassembler.m68k.040"_lang, CS_MODE_M68K_040},
{ "hex.builtin.view.disassembler.m68k.060"_lang, CS_MODE_M68K_060},
};
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) {
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
if (ImGui::Selectable(modes[i].first))
selectedMode = i;
}
ImGui::EndCombo();
}
m_mode = cs_mode(modes[selectedMode].second);
}
break;
case Architecture::M680X:
{
static int selectedMode = 0;
std::pair<const char *, cs_mode> modes[] = {
{"hex.builtin.view.disassembler.m680x.6301"_lang, CS_MODE_M680X_6301 },
{ "hex.builtin.view.disassembler.m680x.6309"_lang, CS_MODE_M680X_6309 },
{ "hex.builtin.view.disassembler.m680x.6800"_lang, CS_MODE_M680X_6800 },
{ "hex.builtin.view.disassembler.m680x.6801"_lang, CS_MODE_M680X_6801 },
{ "hex.builtin.view.disassembler.m680x.6805"_lang, CS_MODE_M680X_6805 },
{ "hex.builtin.view.disassembler.m680x.6808"_lang, CS_MODE_M680X_6808 },
{ "hex.builtin.view.disassembler.m680x.6809"_lang, CS_MODE_M680X_6809 },
{ "hex.builtin.view.disassembler.m680x.6811"_lang, CS_MODE_M680X_6811 },
{ "hex.builtin.view.disassembler.m680x.cpu12"_lang, CS_MODE_M680X_CPU12},
{ "hex.builtin.view.disassembler.m680x.hcs08"_lang, CS_MODE_M680X_HCS08},
};
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) {
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
if (ImGui::Selectable(modes[i].first))
selectedMode = i;
}
ImGui::EndCombo();
}
m_mode = cs_mode(modes[selectedMode].second);
}
break;
#if CS_API_MAJOR >= 5
case Architecture::MOS65XX:
{
static int selectedMode = 0;
std::pair<const char *, cs_mode> modes[] = {
{"hex.builtin.view.disassembler.mos65xx.6502"_lang, CS_MODE_MOS65XX_6502 },
{ "hex.builtin.view.disassembler.mos65xx.65c02"_lang, CS_MODE_MOS65XX_65C02 },
{ "hex.builtin.view.disassembler.mos65xx.w65c02"_lang, CS_MODE_MOS65XX_W65C02 },
{ "hex.builtin.view.disassembler.mos65xx.65816"_lang, CS_MODE_MOS65XX_65816 },
{ "hex.builtin.view.disassembler.mos65xx.65816_long_m"_lang, CS_MODE_MOS65XX_65816_LONG_M },
{ "hex.builtin.view.disassembler.mos65xx.65816_long_x"_lang, CS_MODE_MOS65XX_65816_LONG_X },
{ "hex.builtin.view.disassembler.mos65xx.65816_long_mx"_lang, CS_MODE_MOS65XX_65816_LONG_MX},
};
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) {
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
if (ImGui::Selectable(modes[i].first))
selectedMode = i;
}
ImGui::EndCombo();
}
m_mode = cs_mode(modes[selectedMode].second);
}
break;
#endif
#if CS_API_MAJOR >= 5
case Architecture::BPF:
{
static int mode = CS_MODE_BPF_CLASSIC;
ImGui::RadioButton("hex.builtin.view.disassembler.bpf.classic"_lang, &mode, CS_MODE_BPF_CLASSIC);
ImGui::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.bpf.extended"_lang, &mode, CS_MODE_BPF_EXTENDED);
m_mode = cs_mode(mode);
}
break;
case Architecture::SH:
{
static u32 selectionMode = 0;
static bool fpu = false;
static bool dsp = false;
std::pair<const char*, cs_mode> modes[] = {
{ "hex.builtin.view.disassembler.sh.sh2"_lang, CS_MODE_SH2 },
{ "hex.builtin.view.disassembler.sh.sh2a"_lang, CS_MODE_SH2A },
{ "hex.builtin.view.disassembler.sh.sh3"_lang, CS_MODE_SH3 },
{ "hex.builtin.view.disassembler.sh.sh4"_lang, CS_MODE_SH4 },
{ "hex.builtin.view.disassembler.sh.sh4a"_lang, CS_MODE_SH4A },
};
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectionMode].first)) {
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
if (ImGui::Selectable(modes[i].first))
selectionMode = i;
}
ImGui::EndCombo();
}
ImGui::Checkbox("hex.builtin.view.disassembler.sh.fpu"_lang, &fpu);
ImGui::SameLine();
ImGui::Checkbox("hex.builtin.view.disassembler.sh.dsp"_lang, &dsp);
m_mode = cs_mode(modes[selectionMode].second | (fpu ? CS_MODE_SHFPU : cs_mode(0)) | (dsp ? CS_MODE_SHDSP : cs_mode(0)));
}
break;
case Architecture::TRICORE:
{
static u32 selectionMode = 0;
std::pair<const char*, cs_mode> modes[] = {
{ "hex.builtin.view.disassembler.tricore.110"_lang, CS_MODE_TRICORE_110 },
{ "hex.builtin.view.disassembler.tricore.120"_lang, CS_MODE_TRICORE_120 },
{ "hex.builtin.view.disassembler.tricore.130"_lang, CS_MODE_TRICORE_130 },
{ "hex.builtin.view.disassembler.tricore.131"_lang, CS_MODE_TRICORE_131 },
{ "hex.builtin.view.disassembler.tricore.160"_lang, CS_MODE_TRICORE_160 },
{ "hex.builtin.view.disassembler.tricore.161"_lang, CS_MODE_TRICORE_161 },
{ "hex.builtin.view.disassembler.tricore.162"_lang, CS_MODE_TRICORE_162 },
};
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectionMode].first)) {
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
if (ImGui::Selectable(modes[i].first))
selectionMode = i;
}
ImGui::EndCombo();
}
m_mode = cs_mode(modes[selectionMode].second);
}
break;
case Architecture::WASM:
#endif
case Architecture::EVM:
case Architecture::TMS320C64X:
case Architecture::ARM64:
case Architecture::SYSZ:
case Architecture::XCORE:
m_mode = cs_mode(0);
break;
}
ImGuiExt::EndBox();
}
}
// Draw disassemble button
ImGui::BeginDisabled(m_disassemblerTask.isRunning());
{
if (ImGui::Button("hex.builtin.view.disassembler.disassemble"_lang))
this->disassemble();
}
ImGui::EndDisabled();
// Draw a spinner if the disassembler is running
if (m_disassemblerTask.isRunning()) {
ImGui::SameLine();
ImGuiExt::TextSpinner("hex.builtin.view.disassembler.disassembling"_lang);
}
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.disassembler.disassembly.title"_lang);
ImGui::Separator();
// Draw disassembly table
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.address"_lang);
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.offset"_lang);
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.bytes"_lang);
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.title"_lang);
if (!m_disassemblerTask.isRunning()) {
ImGuiListClipper clipper;
clipper.Begin(m_disassembly.size());
ImGui::TableHeadersRow();
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
const auto &instruction = m_disassembly[i];
ImGui::TableNextRow();
ImGui::TableNextColumn();
// Draw a selectable label for the address
ImGui::PushID(i);
if (ImGui::Selectable("##DisassemblyLine", false, ImGuiSelectableFlags_SpanAllColumns)) {
ImHexApi::HexEditor::setSelection(instruction.offset, instruction.size);
}
ImGui::PopID();
// Draw instruction address
ImGui::SameLine();
ImGuiExt::TextFormatted("0x{0:X}", instruction.address);
// Draw instruction offset
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:X}", instruction.offset);
// Draw instruction bytes
ImGui::TableNextColumn();
ImGui::TextUnformatted(instruction.bytes.c_str());
// Draw instruction mnemonic and operands
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(ImColor(0xFFD69C56), "{}", instruction.mnemonic);
ImGui::SameLine();
ImGui::TextUnformatted(instruction.operators.c_str());
}
}
clipper.End();
}
ImGui::EndTable();
}
}
}
}

View File

@@ -62,7 +62,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{}: ", "hex.builtin.common.region"_lang);
ImGuiExt::TextFormatted("{}: ", "hex.ui.common.region"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", region.getStartAddress(), region.getEndAddress());
@@ -663,11 +663,11 @@ namespace hex::plugin::builtin {
if (ImGui::BeginTabBar("SearchMethods")) {
const std::array<std::string, 5> StringTypes = {
"hex.builtin.common.encoding.ascii"_lang,
"hex.builtin.common.encoding.utf16le"_lang,
"hex.builtin.common.encoding.utf16be"_lang,
hex::format("{} + {}", "hex.builtin.common.encoding.ascii"_lang, "hex.builtin.common.encoding.utf16le"_lang),
hex::format("{} + {}", "hex.builtin.common.encoding.ascii"_lang, "hex.builtin.common.encoding.utf16be"_lang)
"hex.ui.common.encoding.ascii"_lang,
"hex.ui.common.encoding.utf16le"_lang,
"hex.ui.common.encoding.utf16be"_lang,
hex::format("{} + {}", "hex.ui.common.encoding.ascii"_lang, "hex.ui.common.encoding.utf16le"_lang),
hex::format("{} + {}", "hex.ui.common.encoding.ascii"_lang, "hex.ui.common.encoding.utf16be"_lang)
};
auto &mode = m_searchSettings.mode;
@@ -679,7 +679,7 @@ namespace hex::plugin::builtin {
if (settings.minLength < 1)
settings.minLength = 1;
if (ImGui::BeginCombo("hex.builtin.common.type"_lang, StringTypes[std::to_underlying(settings.type)].c_str())) {
if (ImGui::BeginCombo("hex.ui.common.type"_lang, StringTypes[std::to_underlying(settings.type)].c_str())) {
for (size_t i = 0; i < StringTypes.size(); i++) {
auto type = static_cast<SearchSettings::StringType>(i);
@@ -711,9 +711,9 @@ namespace hex::plugin::builtin {
mode = SearchSettings::Mode::Sequence;
ImGuiExt::InputTextIcon("hex.builtin.common.value"_lang, ICON_VS_SYMBOL_KEY, settings.sequence);
ImGuiExt::InputTextIcon("hex.ui.common.value"_lang, ICON_VS_SYMBOL_KEY, settings.sequence);
if (ImGui::BeginCombo("hex.builtin.common.type"_lang, StringTypes[std::to_underlying(settings.type)].c_str())) {
if (ImGui::BeginCombo("hex.ui.common.type"_lang, StringTypes[std::to_underlying(settings.type)].c_str())) {
for (size_t i = 0; i < StringTypes.size() - 2; i++) {
auto type = static_cast<SearchSettings::StringType>(i);
@@ -738,7 +738,7 @@ namespace hex::plugin::builtin {
if (settings.minLength < 1)
settings.minLength = 1;
if (ImGui::BeginCombo("hex.builtin.common.type"_lang, StringTypes[std::to_underlying(settings.type)].c_str())) {
if (ImGui::BeginCombo("hex.ui.common.type"_lang, StringTypes[std::to_underlying(settings.type)].c_str())) {
for (size_t i = 0; i < StringTypes.size(); i++) {
auto type = static_cast<SearchSettings::StringType>(i);
@@ -794,7 +794,7 @@ namespace hex::plugin::builtin {
if (ImGuiExt::InputTextIcon("hex.builtin.view.find.value.min"_lang, ICON_VS_SYMBOL_NUMERIC, settings.inputMin)) edited = true;
if (ImGuiExt::InputTextIcon("hex.builtin.view.find.value.max"_lang, ICON_VS_SYMBOL_NUMERIC, settings.inputMax)) edited = true;
} else {
if (ImGuiExt::InputTextIcon("hex.builtin.common.value"_lang, ICON_VS_SYMBOL_NUMERIC, settings.inputMin)) {
if (ImGuiExt::InputTextIcon("hex.ui.common.value"_lang, ICON_VS_SYMBOL_NUMERIC, settings.inputMin)) {
edited = true;
settings.inputMax = settings.inputMin;
}
@@ -810,19 +810,19 @@ namespace hex::plugin::builtin {
ImGui::NewLine();
const std::array<std::string, 10> InputTypes = {
"hex.builtin.common.type.u8"_lang,
"hex.builtin.common.type.u16"_lang,
"hex.builtin.common.type.u32"_lang,
"hex.builtin.common.type.u64"_lang,
"hex.builtin.common.type.i8"_lang,
"hex.builtin.common.type.i16"_lang,
"hex.builtin.common.type.i32"_lang,
"hex.builtin.common.type.i64"_lang,
"hex.builtin.common.type.f32"_lang,
"hex.builtin.common.type.f64"_lang
"hex.ui.common.type.u8"_lang,
"hex.ui.common.type.u16"_lang,
"hex.ui.common.type.u32"_lang,
"hex.ui.common.type.u64"_lang,
"hex.ui.common.type.i8"_lang,
"hex.ui.common.type.i16"_lang,
"hex.ui.common.type.i32"_lang,
"hex.ui.common.type.i64"_lang,
"hex.ui.common.type.f32"_lang,
"hex.ui.common.type.f64"_lang
};
if (ImGui::BeginCombo("hex.builtin.common.type"_lang, InputTypes[std::to_underlying(settings.type)].c_str())) {
if (ImGui::BeginCombo("hex.ui.common.type"_lang, InputTypes[std::to_underlying(settings.type)].c_str())) {
for (size_t i = 0; i < InputTypes.size(); i++) {
auto type = static_cast<SearchSettings::Value::Type>(i);
@@ -843,8 +843,8 @@ namespace hex::plugin::builtin {
}
}();
std::array options = { "hex.builtin.common.little"_lang, "hex.builtin.common.big"_lang };
if (ImGui::SliderInt("hex.builtin.common.endian"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
std::array options = { "hex.ui.common.little"_lang, "hex.ui.common.big"_lang };
if (ImGui::SliderInt("hex.ui.common.endian"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
edited = true;
switch (selection) {
default:
@@ -932,9 +932,9 @@ namespace hex::plugin::builtin {
if (ImGui::BeginTable("##entries", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImMax(ImGui::GetContentRegionAvail(), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5)))) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.builtin.common.offset"_lang, 0, -1, ImGui::GetID("offset"));
ImGui::TableSetupColumn("hex.builtin.common.size"_lang, 0, -1, ImGui::GetID("size"));
ImGui::TableSetupColumn("hex.builtin.common.value"_lang, 0, -1, ImGui::GetID("value"));
ImGui::TableSetupColumn("hex.ui.common.offset"_lang, 0, -1, ImGui::GetID("offset"));
ImGui::TableSetupColumn("hex.ui.common.size"_lang, 0, -1, ImGui::GetID("size"));
ImGui::TableSetupColumn("hex.ui.common.value"_lang, 0, -1, ImGui::GetID("value"));
auto sortSpecs = ImGui::TableGetSortSpecs();

View File

@@ -13,7 +13,7 @@
#include <wolv/math_eval/math_evaluator.hpp>
#include <content/providers/view_provider.hpp>
#include <content/popups/popup_file_chooser.hpp>
#include <popups/popup_file_chooser.hpp>
#include <imgui_internal.h>
#include <content/popups/popup_blocking_task.hpp>
@@ -214,7 +214,7 @@ namespace hex::plugin::builtin {
}
if (!m_searchTask.isRunning() && !searchSequence.empty() && m_shouldSearch) {
m_searchTask = TaskManager::createTask("hex.builtin.common.processing", ImHexApi::Provider::get()->getActualSize(), [this, editor, searchSequence](auto &) {
m_searchTask = TaskManager::createTask("hex.ui.common.processing", ImHexApi::Provider::get()->getActualSize(), [this, editor, searchSequence](auto &) {
for (u8 retry = 0; retry < 2; retry++) {
auto region = this->findSequence(searchSequence, m_backwards);
@@ -349,7 +349,7 @@ namespace hex::plugin::builtin {
editor->closePopup();
}
ImGuiExt::ConfirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
ImGuiExt::ConfirmButtons("hex.ui.common.set"_lang, "hex.ui.common.cancel"_lang,
[&, this]{
setBaseAddress(m_baseAddress);
editor->closePopup();
@@ -383,7 +383,7 @@ namespace hex::plugin::builtin {
editor->closePopup();
}
ImGuiExt::ConfirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
ImGuiExt::ConfirmButtons("hex.ui.common.set"_lang, "hex.ui.common.cancel"_lang,
[&, this]{
setPageSize(m_pageSize);
editor->closePopup();
@@ -421,7 +421,7 @@ namespace hex::plugin::builtin {
editor->closePopup();
}
ImGuiExt::ConfirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
ImGuiExt::ConfirmButtons("hex.ui.common.set"_lang, "hex.ui.common.cancel"_lang,
[&, this]{
this->resize(m_size);
editor->closePopup();
@@ -448,10 +448,10 @@ namespace hex::plugin::builtin {
void draw(ViewHexEditor *editor) override {
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.insert"_lang);
ImGuiExt::InputHexadecimal("hex.builtin.common.address"_lang, &m_address);
ImGuiExt::InputHexadecimal("hex.builtin.common.size"_lang, &m_size);
ImGuiExt::InputHexadecimal("hex.ui.common.address"_lang, &m_address);
ImGuiExt::InputHexadecimal("hex.ui.common.size"_lang, &m_size);
ImGuiExt::ConfirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
ImGuiExt::ConfirmButtons("hex.ui.common.set"_lang, "hex.ui.common.cancel"_lang,
[&, this]{
insert(m_address, m_size);
editor->closePopup();
@@ -479,10 +479,10 @@ namespace hex::plugin::builtin {
void draw(ViewHexEditor *editor) override {
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.remove"_lang);
ImGuiExt::InputHexadecimal("hex.builtin.common.address"_lang, &m_address);
ImGuiExt::InputHexadecimal("hex.builtin.common.size"_lang, &m_size);
ImGuiExt::InputHexadecimal("hex.ui.common.address"_lang, &m_address);
ImGuiExt::InputHexadecimal("hex.ui.common.size"_lang, &m_size);
ImGuiExt::ConfirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
ImGuiExt::ConfirmButtons("hex.ui.common.set"_lang, "hex.ui.common.cancel"_lang,
[&, this]{
remove(m_address, m_size);
editor->closePopup();
@@ -510,14 +510,14 @@ namespace hex::plugin::builtin {
void draw(ViewHexEditor *editor) override {
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.fill"_lang);
ImGuiExt::InputHexadecimal("hex.builtin.common.address"_lang, &m_address);
ImGuiExt::InputHexadecimal("hex.builtin.common.size"_lang, &m_size);
ImGuiExt::InputHexadecimal("hex.ui.common.address"_lang, &m_address);
ImGuiExt::InputHexadecimal("hex.ui.common.size"_lang, &m_size);
ImGui::Separator();
ImGuiExt::InputTextIcon("hex.builtin.common.bytes"_lang, ICON_VS_SYMBOL_NAMESPACE, m_input);
ImGuiExt::InputTextIcon("hex.ui.common.bytes"_lang, ICON_VS_SYMBOL_NAMESPACE, m_input);
ImGuiExt::ConfirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
ImGuiExt::ConfirmButtons("hex.ui.common.set"_lang, "hex.ui.common.cancel"_lang,
[&, this] {
fill(m_address, m_size, m_input);
editor->closePopup();
@@ -640,6 +640,9 @@ namespace hex::plugin::builtin {
EventProviderChanged::unsubscribe(this);
EventProviderOpened::unsubscribe(this);
EventHighlightingChanged::unsubscribe(this);
EventSettingsChanged::unsubscribe(this);
ContentRegistry::Settings::write("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.bytes_per_row", m_hexEditor.getBytesPerRow());
}
void ViewHexEditor::drawPopup() {
@@ -1037,6 +1040,14 @@ namespace hex::plugin::builtin {
return true;
}
});
m_hexEditor.setBytesPerRow(ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.bytes_per_row", m_hexEditor.getBytesPerRow()));
EventSettingsChanged::subscribe(this, [this] {
m_hexEditor.setSelectionColor(ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080));
m_hexEditor.enableSyncScrolling(ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", false));
m_hexEditor.setByteCellPadding(ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", 0));
m_hexEditor.setCharacterCellPadding(ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", 0));
});
}
void ViewHexEditor::registerMenuItems() {
@@ -1079,7 +1090,7 @@ namespace hex::plugin::builtin {
}
}
PopupFileChooser::open(basePaths, paths, std::vector<hex::fs::ItemFilter>{ {"Thingy Table File", "tbl"} }, false,
ui::PopupFileChooser::open(basePaths, paths, std::vector<hex::fs::ItemFilter>{ {"Thingy Table File", "tbl"} }, false,
[this](const auto &path) {
TaskManager::createTask("Loading encoding file", 0, [this, path](auto&) {
auto encoding = EncodingFile(EncodingFile::Type::Thingy, path);
@@ -1280,13 +1291,13 @@ namespace hex::plugin::builtin {
return (value >= provider->getBaseAddress()) && (value < (provider->getBaseAddress() + provider->getActualSize()));
};
if (ImGui::MenuItem(hex::format("0x{:08X}", littleEndianValue).c_str(), "hex.builtin.common.little_endian"_lang, false, canJumpTo(littleEndianValue))) {
if (ImGui::MenuItem(hex::format("0x{:08X}", littleEndianValue).c_str(), "hex.ui.common.little_endian"_lang, false, canJumpTo(littleEndianValue))) {
if (value < provider->getBaseAddress() + provider->getActualSize()) {
ImHexApi::HexEditor::setSelection(littleEndianValue, 1);
}
}
if (ImGui::MenuItem(hex::format("0x{:08X}", bigEndianValue).c_str(), "hex.builtin.common.big_endian"_lang, false, canJumpTo(bigEndianValue))) {
if (ImGui::MenuItem(hex::format("0x{:08X}", bigEndianValue).c_str(), "hex.ui.common.big_endian"_lang, false, canJumpTo(bigEndianValue))) {
if (value < provider->getBaseAddress() + provider->getActualSize()) {
ImHexApi::HexEditor::setSelection(bigEndianValue, 1);
}

View File

@@ -14,7 +14,7 @@
#include <implot.h>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
namespace hex::plugin::builtin {
@@ -48,7 +48,7 @@ namespace hex::plugin::builtin {
ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) {
PopupInfo::open("hex.builtin.view.information.magic_db_added"_lang);
ui::PopupInfo::open("hex.builtin.view.information.magic_db_added"_lang);
return true;
}
}
@@ -141,7 +141,7 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
ImGui::BeginDisabled(m_analyzerTask.isRunning());
ImGuiExt::BeginSubWindow("hex.builtin.common.settings"_lang);
ImGuiExt::BeginSubWindow("hex.ui.common.settings"_lang);
{
if (ImGui::BeginTable("SettingsTable", 2, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingFixedSame, ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
ImGui::TableSetupColumn("Left", ImGuiTableColumnFlags_WidthStretch, 0.5F);

View File

@@ -19,8 +19,8 @@
#include <hex/helpers/fmt.hpp>
#include <fmt/chrono.h>
#include <content/popups/popup_file_chooser.hpp>
#include <content/popups/popup_question.hpp>
#include <popups/popup_file_chooser.hpp>
#include <popups/popup_question.hpp>
#include <nlohmann/json.hpp>
#include <chrono>
@@ -360,7 +360,7 @@ namespace hex::plugin::builtin {
}
if (m_dangerousFunctionCalled && !ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopup)) {
PopupQuestion::open("hex.builtin.view.pattern_editor.dangerous_function.desc"_lang,
ui::PopupQuestion::open("hex.builtin.view.pattern_editor.dangerous_function.desc"_lang,
[this] {
m_dangerousFunctionsAllowed = DangerousFunctionPerms::Allow;
}, [this] {
@@ -567,8 +567,8 @@ namespace hex::plugin::builtin {
if (ImGui::BeginTable("##sections_table", 3, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, size)) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.builtin.common.name"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F);
ImGui::TableSetupColumn("hex.builtin.common.size"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F);
ImGui::TableSetupColumn("hex.ui.common.name"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F);
ImGui::TableSetupColumn("hex.ui.common.size"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F);
ImGui::TableSetupColumn("##button", ImGuiTableColumnFlags_WidthFixed, 20_scaled);
ImGui::TableHeadersRow();
@@ -903,32 +903,32 @@ namespace hex::plugin::builtin {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{} ", "hex.builtin.common.type"_lang);
ImGuiExt::TextFormatted("{} ", "hex.ui.common.type"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted(" {}", pattern->getTypeName());
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{} ", "hex.builtin.common.address"_lang);
ImGuiExt::TextFormatted("{} ", "hex.ui.common.address"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted(" 0x{:08X}", pattern->getOffset());
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{} ", "hex.builtin.common.size"_lang);
ImGuiExt::TextFormatted("{} ", "hex.ui.common.size"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted(" {}", hex::toByteString(pattern->getSize()));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{} ", "hex.builtin.common.endian"_lang);
ImGuiExt::TextFormatted("{} ", "hex.ui.common.endian"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted(" {}", pattern->getEndian() == std::endian::little ? "hex.builtin.common.little"_lang : "hex.builtin.common.big"_lang);
ImGuiExt::TextFormatted(" {}", pattern->getEndian() == std::endian::little ? "hex.ui.common.little"_lang : "hex.ui.common.big"_lang);
if (const auto &comment = pattern->getComment(); !comment.empty()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{} ", "hex.builtin.common.comment"_lang);
ImGuiExt::TextFormatted("{} ", "hex.ui.common.comment"_lang);
ImGui::TableNextColumn();
ImGui::TextWrapped(" \"%s\"", comment.c_str());
}
@@ -1208,7 +1208,7 @@ namespace hex::plugin::builtin {
}
}
PopupFileChooser::open(basePaths, paths, std::vector<hex::fs::ItemFilter>{ { "Pattern File", "hexpat" } }, false,
ui::PopupFileChooser::open(basePaths, paths, std::vector<hex::fs::ItemFilter>{ { "Pattern File", "hexpat" } }, false,
[this, provider](const std::fs::path &path) {
this->loadPatternFile(path, provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.patterns", "hex.builtin.achievement.patterns.load_existing.name");

View File

@@ -1,6 +1,6 @@
#include "content/views/view_provider_settings.hpp"
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <hex/api/content_registry.hpp>
namespace hex::plugin::builtin {
@@ -37,7 +37,7 @@ namespace hex::plugin::builtin {
ImGui::Separator();
ImGui::BeginDisabled(!settingsValid);
if (ImGui::Button("hex.builtin.common.open"_lang)) {
if (ImGui::Button("hex.ui.common.open"_lang)) {
if (provider->open()) {
EventProviderOpened::post(provider);
@@ -49,9 +49,9 @@ namespace hex::plugin::builtin {
ImGui::CloseCurrentPopup();
auto errorMessage = provider->getErrorMessage();
if (errorMessage.empty()) {
PopupError::open("hex.builtin.view.provider_settings.load_error"_lang);
ui::PopupError::open("hex.builtin.view.provider_settings.load_error"_lang);
} else {
PopupError::open(hex::format("hex.builtin.view.provider_settings.load_error_details"_lang, errorMessage));
ui::PopupError::open(hex::format("hex.builtin.view.provider_settings.load_error_details"_lang, errorMessage));
}
TaskManager::doLater([=] { ImHexApi::Provider::remove(provider); });
}
@@ -60,7 +60,7 @@ namespace hex::plugin::builtin {
ImGui::SameLine();
if (ImGui::Button("hex.builtin.common.cancel"_lang)) {
if (ImGui::Button("hex.ui.common.cancel"_lang)) {
ImGui::CloseCurrentPopup();
this->getWindowOpenState() = false;
TaskManager::doLater([=] { ImHexApi::Provider::remove(provider); });

View File

@@ -5,7 +5,7 @@
#include <nlohmann/json.hpp>
#include <content/popups/popup_question.hpp>
#include <popups/popup_question.hpp>
namespace hex::plugin::builtin {
@@ -111,7 +111,7 @@ namespace hex::plugin::builtin {
// If a restart is required, ask the user if they want to restart
if (!this->getWindowOpenState() && m_triggerPopup) {
m_triggerPopup = false;
PopupQuestion::open("hex.builtin.view.settings.restart_question"_lang,
ui::PopupQuestion::open("hex.builtin.view.settings.restart_question"_lang,
ImHexApi::System::restartImHex,
[this]{
m_restartRequested = false;

View File

@@ -5,7 +5,7 @@
#include <hex/api/content_registry.hpp>
#include <content/popups/popup_notification.hpp>
#include <popups/popup_notification.hpp>
#include <imgui.h>
@@ -310,7 +310,7 @@ namespace hex::plugin::builtin {
}
if (!downloading) {
PopupError::open("hex.builtin.view.store.download_error"_lang);
ui::PopupError::open("hex.builtin.view.store.download_error"_lang);
return false;
}

View File

@@ -1,446 +0,0 @@
#include "content/views/view_yara.hpp"
#include <hex/api/content_registry.hpp>
#include <hex/api/project_file_manager.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <content/popups/popup_notification.hpp>
#include <content/popups/popup_file_chooser.hpp>
// <yara/types.h>'s RE type has a zero-sized array, which is not allowed in ISO C++.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <yara.h>
#pragma GCC diagnostic pop
#include <filesystem>
#include <thread>
#include <wolv/io/file.hpp>
#include <wolv/io/fs.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/literals.hpp>
namespace hex::plugin::builtin {
using namespace wolv::literals;
ViewYara::ViewYara() : View::Window("hex.builtin.view.yara.name") {
yr_initialize();
ContentRegistry::FileHandler::add({ ".yar", ".yara" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Yara)) {
if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) {
PopupInfo::open("hex.builtin.view.yara.rule_added"_lang);
return true;
}
}
return false;
});
ProjectFile::registerPerProviderHandler({
.basePath = "yara.json",
.required = false,
.load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
auto fileContent = tar.readString(basePath);
if (fileContent.empty())
return true;
auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end());
if (!data.contains("rules"))
return false;
auto &rules = data["rules"];
if (!rules.is_array())
return false;
m_matches.get(provider).clear();
for (auto &rule : rules) {
if (!rule.contains("name") || !rule.contains("path"))
return false;
auto &name = rule["name"];
auto &path = rule["path"];
if (!name.is_string() || !path.is_string())
return false;
m_rules.get(provider).emplace_back(std::fs::path(name.get<std::string>()), std::fs::path(path.get<std::string>()));
}
return true;
},
.store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
nlohmann::json data;
data["rules"] = nlohmann::json::array();
for (auto &[name, path] : m_rules.get(provider)) {
data["rules"].push_back({
{ "name", wolv::util::toUTF8String(name) },
{ "path", wolv::util::toUTF8String(path) }
});
}
tar.writeString(basePath, data.dump(4));
return true;
}
});
}
ViewYara::~ViewYara() {
yr_finalize();
}
void ViewYara::drawContent() {
ImGuiExt::Header("hex.builtin.view.yara.header.rules"_lang, true);
if (ImGui::BeginListBox("##rules", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 5))) {
for (u32 i = 0; i < m_rules->size(); i++) {
const bool selected = (m_selectedRule == i);
if (ImGui::Selectable(wolv::util::toUTF8String((*m_rules)[i].first).c_str(), selected)) {
m_selectedRule = i;
}
}
ImGui::EndListBox();
}
if (ImGuiExt::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
const auto basePaths = fs::getDefaultPaths(fs::ImHexPath::Yara);
std::vector<std::fs::path> paths;
for (const auto &path : basePaths) {
std::error_code error;
for (const auto &entry : std::fs::recursive_directory_iterator(path, error)) {
if (!entry.is_regular_file()) continue;
if (entry.path().extension() != ".yara" && entry.path().extension() != ".yar") continue;
paths.push_back(entry);
}
}
PopupFileChooser::open(basePaths, paths, std::vector<hex::fs::ItemFilter>{ { "Yara File", "yara" }, { "Yara File", "yar" } }, true,
[&](const auto &path) {
m_rules->push_back({ path.filename(), path });
});
}
ImGui::SameLine();
if (ImGuiExt::IconButton(ICON_VS_REMOVE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
if (m_selectedRule < m_rules->size()) {
m_rules->erase(m_rules->begin() + m_selectedRule);
m_selectedRule = std::min(m_selectedRule, u32(m_rules->size() - 1));
}
}
ImGui::NewLine();
if (ImGui::Button("hex.builtin.view.yara.match"_lang)) this->applyRules();
ImGui::SameLine();
if (m_matcherTask.isRunning()) {
ImGui::SameLine();
ImGuiExt::TextSpinner("hex.builtin.view.yara.matching"_lang);
}
ImGuiExt::Header("hex.builtin.view.yara.header.matches"_lang);
auto matchesTableSize = ImGui::GetContentRegionAvail();
matchesTableSize.y *= 3.75 / 5.0;
matchesTableSize.y -= ImGui::GetTextLineHeightWithSpacing();
if (ImGui::BeginTable("matches", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, matchesTableSize)) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.builtin.view.yara.matches.identifier"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("identifier"));
ImGui::TableSetupColumn("hex.builtin.view.yara.matches.variable"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("variable"));
ImGui::TableSetupColumn("hex.builtin.common.address"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("address"));
ImGui::TableSetupColumn("hex.builtin.common.size"_lang, ImGuiTableColumnFlags_PreferSortAscending, 0, ImGui::GetID("size"));
ImGui::TableHeadersRow();
auto sortSpecs = ImGui::TableGetSortSpecs();
if (!m_matches->empty() && (sortSpecs->SpecsDirty || m_sortedMatches->empty())) {
m_sortedMatches->clear();
std::transform(m_matches->begin(), m_matches->end(), std::back_inserter(*m_sortedMatches), [](auto &match) {
return &match;
});
std::sort(m_sortedMatches->begin(), m_sortedMatches->end(), [&sortSpecs](const YaraMatch *left, const YaraMatch *right) -> bool {
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("identifier"))
return left->identifier < right->identifier;
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("variable"))
return left->variable < right->variable;
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("address"))
return left->address < right->address;
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size"))
return left->size < right->size;
else
return false;
});
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Descending)
std::reverse(m_sortedMatches->begin(), m_sortedMatches->end());
sortSpecs->SpecsDirty = false;
}
if (!m_matcherTask.isRunning()) {
ImGuiListClipper clipper;
clipper.Begin(m_sortedMatches->size());
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
auto &[identifier, variableName, address, size, wholeDataMatch, highlightId, tooltipId] = *(*m_sortedMatches)[i];
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID(i);
if (ImGui::Selectable("match", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap)) {
ImHexApi::HexEditor::setSelection(address, size);
}
ImGui::PopID();
ImGui::SameLine();
ImGui::TextUnformatted(identifier.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(variableName.c_str());
if (!wholeDataMatch) {
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:X} : 0x{1:X}", address, address + size - 1);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:X}", size);
} else {
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.yara.whole_data"_lang);
ImGui::TableNextColumn();
ImGui::TextUnformatted("");
}
}
}
clipper.End();
}
ImGui::EndTable();
}
auto consoleSize = ImGui::GetContentRegionAvail();
if (ImGui::BeginChild("##console", consoleSize, true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_HorizontalScrollbar)) {
ImGuiListClipper clipper;
clipper.Begin(m_consoleMessages.size());
while (clipper.Step())
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
const auto &message = m_consoleMessages[i];
if (ImGui::Selectable(message.c_str()))
ImGui::SetClipboardText(message.c_str());
}
}
ImGui::EndChild();
}
void ViewYara::clearResult() {
for (const auto &match : *m_matches) {
ImHexApi::HexEditor::removeBackgroundHighlight(match.highlightId);
ImHexApi::HexEditor::removeTooltip(match.tooltipId);
}
m_matches->clear();
m_consoleMessages.clear();
}
void ViewYara::applyRules() {
this->clearResult();
m_matcherTask = TaskManager::createTask("hex.builtin.view.yara.matching", 0, [this](auto &task) {
if (!ImHexApi::Provider::isValid()) return;
struct ResultContext {
Task *task = nullptr;
std::vector<YaraMatch> newMatches;
std::vector<std::string> consoleMessages;
};
ResultContext resultContext;
resultContext.task = &task;
for (const auto &[fileName, filePath] : *m_rules) {
YR_COMPILER *compiler = nullptr;
yr_compiler_create(&compiler);
ON_SCOPE_EXIT {
yr_compiler_destroy(compiler);
};
auto currFilePath = wolv::util::toUTF8String(wolv::io::fs::toShortPath(filePath));
yr_compiler_set_include_callback(
compiler,
[](const char *includeName, const char *, const char *, void *userData) -> const char * {
wolv::io::File file(std::fs::path(static_cast<const char *>(userData)).parent_path() / includeName, wolv::io::File::Mode::Read);
if (!file.isValid())
return nullptr;
auto size = file.getSize();
char *buffer = new char[size + 1];
file.readBuffer(reinterpret_cast<u8 *>(buffer), size);
buffer[size] = 0x00;
return buffer;
},
[](const char *ptr, void *userData) {
hex::unused(userData);
delete[] ptr;
},
currFilePath.data()
);
wolv::io::File file((*m_rules)[m_selectedRule].second, wolv::io::File::Mode::Read);
if (!file.isValid()) return;
if (yr_compiler_add_file(compiler, file.getHandle(), nullptr, nullptr) != 0) {
std::string errorMessage(0xFFFF, '\x00');
yr_compiler_get_error_message(compiler, errorMessage.data(), errorMessage.size());
TaskManager::doLater([this, errorMessage = wolv::util::trim(errorMessage)] {
this->clearResult();
m_consoleMessages.push_back(hex::format("hex.builtin.view.yara.error"_lang, errorMessage));
});
return;
}
YR_RULES *yaraRules;
yr_compiler_get_rules(compiler, &yaraRules);
ON_SCOPE_EXIT { yr_rules_destroy(yaraRules); };
YR_MEMORY_BLOCK_ITERATOR iterator;
struct ScanContext {
Task *task = nullptr;
std::vector<u8> buffer;
YR_MEMORY_BLOCK currBlock = {};
};
ScanContext context;
context.task = &task;
context.currBlock.base = 0;
context.currBlock.fetch_data = [](auto *block) -> const u8 * {
auto &context = *static_cast<ScanContext *>(block->context);
auto provider = ImHexApi::Provider::get();
context.buffer.resize(context.currBlock.size);
if (context.buffer.empty())
return nullptr;
block->size = context.currBlock.size;
provider->read(context.currBlock.base + provider->getBaseAddress(), context.buffer.data(), context.buffer.size());
return context.buffer.data();
};
iterator.file_size = [](auto *iterator) -> u64 {
hex::unused(iterator);
return ImHexApi::Provider::get()->getActualSize();
};
iterator.context = &context;
iterator.first = [](YR_MEMORY_BLOCK_ITERATOR *iterator) -> YR_MEMORY_BLOCK *{
auto &context = *static_cast<ScanContext *>(iterator->context);
context.currBlock.base = 0;
context.currBlock.size = 0;
context.buffer.clear();
iterator->last_error = ERROR_SUCCESS;
return iterator->next(iterator);
};
iterator.next = [](YR_MEMORY_BLOCK_ITERATOR *iterator) -> YR_MEMORY_BLOCK * {
auto &context = *static_cast<ScanContext *>(iterator->context);
u64 address = context.currBlock.base + context.currBlock.size;
iterator->last_error = ERROR_SUCCESS;
context.currBlock.base = address;
context.currBlock.size = std::min<size_t>(ImHexApi::Provider::get()->getActualSize() - address, 10_MiB);
context.currBlock.context = &context;
context.task->update(address);
if (context.currBlock.size == 0) return nullptr;
return &context.currBlock;
};
yr_rules_scan_mem_blocks(
yaraRules, &iterator, 0, [](YR_SCAN_CONTEXT *context, int message, void *data, void *userData) -> int {
auto &results = *static_cast<ResultContext *>(userData);
switch (message) {
case CALLBACK_MSG_RULE_MATCHING:
{
auto rule = static_cast<YR_RULE *>(data);
if (rule->strings != nullptr) {
YR_STRING *string = nullptr;
YR_MATCH *match = nullptr;
yr_rule_strings_foreach(rule, string) {
yr_string_matches_foreach(context, string, match) {
results.newMatches.push_back({ rule->identifier, string->identifier, u64(match->offset), size_t(match->match_length), false, 0, 0 });
}
}
} else {
results.newMatches.push_back({ rule->identifier, "", 0, 0, true, 0, 0 });
}
}
break;
case CALLBACK_MSG_CONSOLE_LOG:
{
results.consoleMessages.emplace_back(static_cast<const char *>(data));
}
break;
default:
break;
}
return results.task->shouldInterrupt() ? CALLBACK_ABORT : CALLBACK_CONTINUE;
},
&resultContext,
0);
}
TaskManager::doLater([this, resultContext] {
for (const auto &match : *m_matches) {
ImHexApi::HexEditor::removeBackgroundHighlight(match.highlightId);
ImHexApi::HexEditor::removeTooltip(match.tooltipId);
}
m_consoleMessages = resultContext.consoleMessages;
std::move(resultContext.newMatches.begin(), resultContext.newMatches.end(), std::back_inserter(*m_matches));
auto uniques = std::set(m_matches->begin(), m_matches->end(), [](const auto &l, const auto &r) {
return std::tie(l.address, l.size, l.wholeDataMatch, l.identifier, l.variable) <
std::tie(r.address, r.size, r.wholeDataMatch, r.identifier, r.variable);
});
m_matches->clear();
std::move(uniques.begin(), uniques.end(), std::back_inserter(*m_matches));
constexpr static color_t YaraColor = 0x70B4771F;
for (auto &match : uniques) {
match.highlightId = ImHexApi::HexEditor::addBackgroundHighlight({ match.address, match.size }, YaraColor);
match.tooltipId = ImHexApi::HexEditor::addTooltip({ match. address, match.size }, hex::format("{0} [{1}]", match.identifier, match.variable), YaraColor);
}
});
});
}
}

View File

@@ -29,7 +29,7 @@
#include <string>
#include <random>
#include <content/popups/popup_question.hpp>
#include <popups/popup_question.hpp>
#include <hex/api/tutorial_manager.hpp>
#include <hex/api/workspace_manager.hpp>
@@ -126,13 +126,13 @@ namespace hex::plugin::builtin {
ImGui::NewLine();
static bool dontShowAgain = false;
if (ImGui::Checkbox("hex.builtin.common.dont_show_again"_lang, &dontShowAgain)) {
if (ImGui::Checkbox("hex.ui.common.dont_show_again"_lang, &dontShowAgain)) {
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", !dontShowAgain);
}
ImGui::SameLine((ImGui::GetMainViewport()->Size / 3 - ImGui::CalcTextSize("hex.builtin.common.close"_lang) - ImGui::GetStyle().FramePadding).x);
ImGui::SameLine((ImGui::GetMainViewport()->Size / 3 - ImGui::CalcTextSize("hex.ui.common.close"_lang) - ImGui::GetStyle().FramePadding).x);
if (ImGui::Button("hex.builtin.common.close"_lang) || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
if (ImGui::Button("hex.ui.common.close"_lang) || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
Popup::close();
}
};
@@ -508,7 +508,7 @@ namespace hex::plugin::builtin {
}
if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "") == "") {
PopupQuestion::open("hex.builtin.popup.play_tutorial.desc"_lang,
ui::PopupQuestion::open("hex.builtin.popup.play_tutorial.desc"_lang,
[]{
TutorialManager::startTutorial("hex.builtin.tutorial.introduction");
},