#include "logs_window.hpp" #include #include #include #include #include "pane.hpp" namespace dusk::ui { namespace { const char* level_name(LogLevel level) { switch (level) { case LOG_LEVEL_TRACE: return "Trace"; case LOG_LEVEL_DEBUG: return "Debug"; case LOG_LEVEL_INFO: return "Info"; case LOG_LEVEL_WARN: return "Warn"; case LOG_LEVEL_ERROR: return "Error"; } return "?"; } const char* level_logger_name(LogLevel level) { switch (level) { case LOG_LEVEL_TRACE: return "TRACE"; case LOG_LEVEL_DEBUG: return "DEBUG"; case LOG_LEVEL_INFO: return "INFO"; case LOG_LEVEL_WARN: return "WARNING"; case LOG_LEVEL_ERROR: return "ERROR"; } return "?"; } const char* level_class(LogLevel level) { switch (level) { case LOG_LEVEL_TRACE: return "lvl-trace"; case LOG_LEVEL_DEBUG: return "lvl-debug"; case LOG_LEVEL_INFO: return "lvl-info"; case LOG_LEVEL_WARN: return "lvl-warn"; case LOG_LEVEL_ERROR: return "lvl-error"; } return "lvl-info"; } std::string format_time(int64_t timeMs) { const auto seconds = static_cast(timeMs / 1000); std::tm localTime{}; #if _WIN32 localtime_s(&localTime, &seconds); #else localtime_r(&seconds, &localTime); #endif std::array buffer{}; std::strftime(buffer.data(), buffer.size(), "%H:%M:%S", &localTime); return fmt::format("{}.{:03}", buffer.data(), timeMs % 1000); } void append_text(Rml::ElementDocument* doc, Rml::Element* parent, const Rml::String& text) { parent->AppendChild(doc->CreateTextNode(text)); } Rml::Element* append_span(Rml::ElementDocument* doc, Rml::Element* parent, const char* className, const Rml::String& text) { auto span = doc->CreateElement("span"); span->SetClass(className, true); append_text(doc, span.get(), text); return parent->AppendChild(std::move(span)); } } // namespace LogsWindow::LogsWindow(std::string modFilter) : Window{Props{.tabBar = false, .styleSheets = {"res/rml/logs.rcss"}}}, mModFilter{std::move(modFilter)} { mRoot->SetClass("logs", true); set_content([this](Rml::Element* content) { build_content(content); }); } void LogsWindow::build_content(Rml::Element* content) { auto* toolbar = append(content, "div"); toolbar->SetClass("log-toolbar", true); auto* title = append(toolbar, "div"); title->SetClass("log-title", true); title->SetInnerRML("Logs"); auto* modLabel = append(toolbar, "div"); modLabel->SetClass("log-title-mod", true); modLabel->SetInnerRML(mModFilter.empty() ? "All mods" : fmt::format("{}", escape(mModFilter))); append(toolbar, "div")->SetClass("log-toolbar-spacer", true); for (const LogLevel level : {LOG_LEVEL_TRACE, LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARN, LOG_LEVEL_ERROR}) { add_child(toolbar, ControlledButton::Props{ .text = level_name(level), .isSelected = [this, level] { return mMinLevel <= level; }, }) .on_pressed([this, level] { mMinLevel = level; rebuild_lines(); }); } append(toolbar, "div")->SetClass("log-toolbar-spacer", true); add_child