#include "log_panel.hpp" #include #include "imgui.h" #include "injection_panel.hpp" #include "ui/app_chrome.hpp" #include "ui/text_match.hpp" namespace coop { void LogPanel::add_line(const LogRecord& rec) { if (first_millis_ == 0) { first_millis_ = rec.millis; } const double secs = static_cast(rec.millis - first_millis_) / 1000.0; char buf[256]; std::snprintf(buf, sizeof(buf), "[%8.3f] %s", secs, rec.text); lines_.push_back({buf, rec.level}); while (lines_.size() > kMaxLines) { lines_.pop_front(); } } void LogPanel::pull(InjectionPanel& injection) { injection.drain_logs([this](const LogRecord& rec) { add_line(rec); }); } void LogPanel::draw() { apply_panel_layout(Panel::Log); ImGui::Begin("Log"); if (ImGui::Button("Clear")) { lines_.clear(); first_millis_ = 0; } ImGui::SameLine(); ImGui::Checkbox("Auto-scroll", &autoscroll_); ImGui::SameLine(); ImGui::SetNextItemWidth(-1.0f); ImGui::InputTextWithHint("##logfilter", "filter...", filter_, sizeof(filter_)); ImGui::Separator(); if (ImGui::BeginChild("loglines", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar)) { const bool has_filter = filter_[0] != '\0'; for (const Line& line : lines_) { if (has_filter && !contains_ci(line.text, filter_)) { continue; } switch (line.level) { case LogLevel_Warn: ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", line.text.c_str()); // amber break; case LogLevel_Error: ImGui::TextColored(ImVec4(1.0f, 0.45f, 0.4f, 1.0f), "%s", line.text.c_str()); // red break; default: ImGui::TextUnformatted(line.text.c_str()); break; } } // Stick to the bottom while new lines arrive (unless the user scrolled up). if (autoscroll_ && ImGui::GetScrollY() >= ImGui::GetScrollMaxY() - 1.0f) { ImGui::SetScrollHereY(1.0f); } } ImGui::EndChild(); ImGui::End(); } } // namespace coop