diff --git a/lib/libimhex/include/hex/helpers/logger.hpp b/lib/libimhex/include/hex/helpers/logger.hpp index a66c8096f..c3cfa9b4b 100644 --- a/lib/libimhex/include/hex/helpers/logger.hpp +++ b/lib/libimhex/include/hex/helpers/logger.hpp @@ -20,12 +20,20 @@ namespace hex::log { bool isRedirected(); [[maybe_unused]] void redirectToFile(); - extern std::mutex s_loggerMutex; + extern std::mutex g_loggerMutex; + struct LogEntry { + std::string project; + std::string level; + std::string message; + }; + + std::vector& getLogEntries(); } namespace { + [[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) { const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); @@ -41,22 +49,25 @@ namespace hex::log { template [[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) { - std::scoped_lock lock(impl::s_loggerMutex); + std::scoped_lock lock(impl::g_loggerMutex); auto dest = impl::getDestination(); printPrefix(dest, ts, level); - fmt::print(dest, fmt::runtime(fmt), args...); - fmt::print(dest, "\n"); + + auto message = fmt::format(fmt::runtime(fmt), args...); + fmt::print(dest, "{}\n", message); + + impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, level, std::move(message) }); } } [[maybe_unused]] void debug(const std::string &fmt, auto &&...args) { -#if defined(DEBUG) - hex::log::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...); -#else - hex::unused(fmt, args...); -#endif + #if defined(DEBUG) + hex::log::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...); + #else + impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...) }); + #endif } [[maybe_unused]] void info(const std::string &fmt, auto &&...args) { diff --git a/lib/libimhex/source/helpers/logger.cpp b/lib/libimhex/source/helpers/logger.cpp index c26494a55..99ab66b67 100644 --- a/lib/libimhex/source/helpers/logger.cpp +++ b/lib/libimhex/source/helpers/logger.cpp @@ -7,7 +7,7 @@ namespace hex::log::impl { static wolv::io::File s_loggerFile; - std::mutex s_loggerMutex; + std::mutex g_loggerMutex; FILE *getDestination() { if (s_loggerFile.isValid()) @@ -36,4 +36,10 @@ namespace hex::log::impl { } } + + std::vector& getLogEntries() { + static std::vector logEntries; + return logEntries; + } + } \ No newline at end of file diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index acbde6d8d..c4706f5c0 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -61,6 +61,7 @@ add_library(${PROJECT_NAME} SHARED source/content/views/view_provider_settings.cpp source/content/views/view_find.cpp source/content/views/view_theme_manager.cpp + source/content/views/view_logs.cpp source/content/helpers/math_evaluator.cpp source/content/helpers/notification.cpp diff --git a/plugins/builtin/include/content/views/view_logs.hpp b/plugins/builtin/include/content/views/view_logs.hpp new file mode 100644 index 000000000..78ccef6fa --- /dev/null +++ b/plugins/builtin/include/content/views/view_logs.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include +#include + +#include +#include + +namespace hex::plugin::builtin { + + class ViewLogs : public View { + public: + ViewLogs(); + ~ViewLogs() override = default; + + void drawContent() override; + + [[nodiscard]] bool isAvailable() const override { return true; } + [[nodiscard]] bool hasViewMenuItemEntry() const override { return false; } + + private: + int m_logLevel = 1; + bool m_viewOpen = false; + }; + +} \ No newline at end of file diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 59012b11e..eb101c4b3 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -828,6 +828,10 @@ "hex.builtin.view.information.plain_text": "This data is most likely plain text.", "hex.builtin.view.information.plain_text_percentage": "Plain text percentage", "hex.builtin.view.information.provider_information": "Provider Information", + "hex.builtin.view.logs.component": "Component", + "hex.builtin.view.logs.log_level": "Log Level", + "hex.builtin.view.logs.message": "Message", + "hex.builtin.view.logs.name": "Log Console", "hex.builtin.view.patches.name": "Patches", "hex.builtin.view.patches.offset": "Offset", "hex.builtin.view.patches.orig": "Original value", diff --git a/plugins/builtin/source/content/views.cpp b/plugins/builtin/source/content/views.cpp index 564b657f2..fc59586ff 100644 --- a/plugins/builtin/source/content/views.cpp +++ b/plugins/builtin/source/content/views.cpp @@ -19,6 +19,7 @@ #include "content/views/view_provider_settings.hpp" #include "content/views/view_find.hpp" #include "content/views/view_theme_manager.hpp" +#include "content/views/view_logs.hpp" namespace hex::plugin::builtin { @@ -44,6 +45,7 @@ namespace hex::plugin::builtin { ContentRegistry::Views::add(); ContentRegistry::Views::add(); ContentRegistry::Views::add(); + ContentRegistry::Views::add(); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_logs.cpp b/plugins/builtin/source/content/views/view_logs.cpp new file mode 100644 index 000000000..e2bfed2ff --- /dev/null +++ b/plugins/builtin/source/content/views/view_logs.cpp @@ -0,0 +1,87 @@ +#include "content/views/view_logs.hpp" + +#include + +namespace hex::plugin::builtin { + + ViewLogs::ViewLogs() : View("hex.builtin.view.logs.name") { + ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.extras", "hex.builtin.view.logs.name" }, 2500, Shortcut::None, [&, this] { + this->m_viewOpen = true; + this->getWindowOpenState() = true; + }); + } + + static ImColor getColor(std::string_view level) { + if (level.contains("DEBUG")) + return ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen); + else if (level.contains("INFO")) + return ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue); + else if (level.contains("WARN")) + return ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarYellow); + else if (level.contains("ERROR")) + return ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed); + else if (level.contains("FATAL")) + return ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarPurple); + return ImGui::GetStyleColorVec4(ImGuiCol_Text); + } + + static bool shouldDisplay(std::string_view messageLevel, int currLevel) { + if (currLevel == 0) + return true; + else if (currLevel == 1 && messageLevel.contains("INFO")) + return true; + else if (currLevel == 2 && messageLevel.contains("WARN")) + return true; + else if (currLevel == 3 && messageLevel.contains("ERROR")) + return true; + else if (currLevel == 4 && messageLevel.contains("FATAL")) + return true; + return false; + } + + void ViewLogs::drawContent() { + if (ImGui::Begin(View::toWindowName("hex.builtin.view.logs.name").c_str(), &this->m_viewOpen, ImGuiWindowFlags_NoCollapse)) { + + ImGui::Combo("hex.builtin.view.logs.log_level"_lang, &this->m_logLevel, "DEBUG\0INFO\0WARNING\0ERROR\0FATAL\0"); + + if (ImGui::BeginTable("##logs", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY)) { + ImGui::TableSetupColumn("hex.builtin.view.logs.component"_lang, ImGuiTableColumnFlags_WidthFixed, 100_scaled); + ImGui::TableSetupColumn("hex.builtin.view.logs.message"_lang); + ImGui::TableSetupScrollFreeze(0, 1); + + ImGui::TableHeadersRow(); + + const auto &logs = log::impl::getLogEntries(); + ImGuiListClipper clipper; + clipper.Begin(logs.size()); + + while (clipper.Step()) { + auto end = 0; + for (size_t i = clipper.DisplayStart; i < std::min(clipper.DisplayEnd + end, logs.size()); i++) { + const auto &log = logs[i]; + + if (!shouldDisplay(log.level, this->m_logLevel)) { + end++; + clipper.ItemsCount--; + continue; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(log.project.c_str()); + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Text, getColor(log.level).Value); + ImGui::TextUnformatted(log.message.c_str()); + ImGui::PopStyleColor(); + } + } + + ImGui::EndTable(); + } + } + ImGui::End(); + + this->getWindowOpenState() = this->m_viewOpen; + } + +} \ No newline at end of file diff --git a/resources/projects/splash_screen.svg b/resources/projects/splash_screen.svg index 76dd26e7c..6ecfa3d92 100644 --- a/resources/projects/splash_screen.svg +++ b/resources/projects/splash_screen.svg @@ -28,11 +28,11 @@ inkscape:deskcolor="#505050" inkscape:document-units="mm" inkscape:zoom="0.25" - inkscape:cx="-426" + inkscape:cx="-428" inkscape:cy="1558" inkscape:window-width="2560" - inkscape:window-height="1369" - inkscape:window-x="2552" + inkscape:window-height="1417" + inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="layer1" />