#include #include #include "../misc.h" #include "../log.h" #include "logs.h" static inline void render_table_item_context_menu(const LogEntry& log_entry) { struct tm tm; char time_as_str[128] = {0}; strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&log_entry.time, &tm)); ImGui::TextDisabled("[%s] %s", time_as_str, log_entry.message.c_str()); ImGui::Separator(); ImGui::PushFont(nullptr); if (ImGui::Selectable("Copy")) ImGui::SetClipboardText(to_string(log_entry).c_str()); if (ImGui::Selectable("Copy Time")) ImGui::SetClipboardText(time_as_str); if (ImGui::Selectable("Copy Message")) ImGui::SetClipboardText(log_entry.message.c_str()); ImGui::PopFont(); } static inline void render_table_item(const LogEntry& log_entry, size_t log_entry_index, size_t* copying_entry_index) { auto table_item_popup = [&]() { bool popup_was_open = ImGui::IsPopupOpen("copy_popup"); ImGui::OpenPopupOnItemClick("copy_popup"); if (!popup_was_open) { *copying_entry_index = log_entry_index; } }; ImGui::TableNextRow(); if (ImGui::TableSetColumnIndex(0)) { struct tm tm; char time_as_str[128] = {0}; strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&log_entry.time, &tm)); ImGui::TextUnformatted(time_as_str); table_item_popup(); } if (ImGui::TableSetColumnIndex(1)) { ImGui::TextUnformatted(log_entry.message); table_item_popup(); } } static inline void render_table(ImFont* monospace_font, bool* autoscrolling) { static size_t copying_entry_index; ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_None); ImGui::TableHeadersRow(); ImGui::PushFont(monospace_font); ImGuiListClipper clipper; clipper.Begin(static_cast(log_entries.size())); while (clipper.Step()) { for (int i_u = clipper.DisplayStart; i_u < clipper.DisplayEnd; i_u++) { // what'd we do if we log the error about an error failing to show logs assert(i_u >= 0); size_t i = static_cast(i_u); render_table_item(log_entries[i], i, ©ing_entry_index); } } clipper.End(); if (ImGui::BeginPopup("copy_popup")) { render_table_item_context_menu(log_entries[copying_entry_index]); ImGui::EndPopup(); } ImGui::PopFont(); if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { *autoscrolling = true; ImGui::SetScrollHereY(1.0f); } ImGui::EndTable(); } void logs_window(ImFont* monospace_font, bool* __restrict autoscrolling, bool* __restrict p_open) { if (!ImGui::BeginWithCloseShortcut("LogMeow Logs", p_open)) { ImGui::End(); return; } if (ImGui::Button("Clear")) { log_entries.clear(); } ImGui::SameLine(); if (ImGui::Button("Copy")) { std::string text; for (const LogEntry& entry : log_entries) { if (!text.empty()) { text += '\n'; } text += to_string(entry); } ImGui::SetClipboardText(text.c_str()); } ImGui::Separator(); // copied from imgui/imgui_demo.cpp: [SECTION] Example App: Debug Console / ShowExampleAppConsole() // and [SECTION] Example App: Long Text / ShowExampleAppLongText() // and [SECTION] Example App: Debug Log / ShowExampleAppLog() // and Tables/Vertical scrolling, with clipping const constexpr ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; if (ImGui::BeginTable("logs", 2, flags)) { render_table(monospace_font, autoscrolling); } ImGui::End(); }