#include #include #include #include #include #include "../misc.h" #include "../config.h" #include "../logcat_entry.h" #include "../logcat_thread.h" #include "../fragments/export.h" #include "main.h" static inline void render_table_item_context_menu(const LogcatEntry& logcat_entry) { std::string text = to_string(logcat_entry); ImGui::TextDisabled("%s", text.c_str()); ImGui::Separator(); ImGui::PushFont(nullptr); if (ImGui::Selectable("Copy")) ImGui::SetClipboardText(text.c_str()); if (ImGui::Selectable("Copy Time")) { struct tm tm; char time_as_str[128] = {0}; strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&logcat_entry.time, &tm)); ImGui::SetClipboardText(time_as_str); } if (ImGui::Selectable("Copy User", false, logcat_entry.user ? 0 : ImGuiSelectableFlags_Disabled)) { ImGui::SetClipboardText(logcat_entry.user->c_str()); } if (ImGui::Selectable("Copy PID")) ImGui::SetClipboardText(std::to_string(logcat_entry.pid).c_str()); if (ImGui::Selectable("Copy TID")) ImGui::SetClipboardText(std::to_string(logcat_entry.tid).c_str()); if (ImGui::Selectable("Copy Buffer")) ImGui::SetClipboardText(to_string(logcat_entry.buffer)); if (ImGui::Selectable("Copy Priority")) ImGui::SetClipboardText(to_string(logcat_entry.priority)); if (ImGui::Selectable("Copy Tag")) ImGui::SetClipboardText(logcat_entry.tag.c_str()); if (ImGui::Selectable("Copy Message")) ImGui::SetClipboardText(logcat_entry.message.c_str()); ImGui::PopFont(); } static inline void render_table_item(const LogcatEntry& logcat_entry, size_t logcat_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 = logcat_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(&logcat_entry.time, &tm)); ImGui::TextUnformatted(time_as_str); table_item_popup(); } if (logcat_entry.user && ImGui::TableSetColumnIndex(1)) { ImGui::TextUnformatted(*logcat_entry.user); table_item_popup(); } if (ImGui::TableSetColumnIndex(2)) { ImGui::Text("%zu", logcat_entry.pid); table_item_popup(); } if (ImGui::TableSetColumnIndex(3)) { ImGui::Text("%zu", logcat_entry.tid); table_item_popup(); } if (ImGui::TableSetColumnIndex(4)) { ImGui::TextUnformatted(to_string(logcat_entry.buffer)); table_item_popup(); } if (ImGui::TableSetColumnIndex(5)) { ImGui::TextUnformatted(to_string(logcat_entry.priority)); table_item_popup(); } if (ImGui::TableSetColumnIndex(6)) { ImGui::TextUnformatted(logcat_entry.tag); table_item_popup(); } if (ImGui::TableSetColumnIndex(7)) { ImGui::TextUnformatted(logcat_entry.message); table_item_popup(); } } static inline void render_table(ImFont* monospace_font, std::vector& logcat_entries, std::vector& filtered_logcat_entry_offsets) { static size_t copying_entry_index; ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("User", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("PID", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("TID", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Buffer", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Priority", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Tag", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_None); ImGui::TableHeadersRow(); ImGui::PushFont(monospace_font); ImGuiListClipper clipper; clipper.Begin(static_cast(filtered_logcat_entry_offsets.size())); while (clipper.Step()) { for (int i_u = clipper.DisplayStart; i_u < clipper.DisplayEnd; i_u++) { assert(i_u >= 0); size_t i = static_cast(i_u); size_t logcat_entry_index = filtered_logcat_entry_offsets[i]; render_table_item(logcat_entries[logcat_entry_index], logcat_entry_index, ©ing_entry_index); } } clipper.End(); if (ImGui::BeginPopup("copy_popup")) { render_table_item_context_menu(logcat_entries[copying_entry_index]); ImGui::EndPopup(); } ImGui::PopFont(); if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { ImGui::SetScrollHereY(1.0f); } ImGui::EndTable(); } void main_window(bool latest_log_entries_read, ImFont* monospace_font, LogcatThread& logcat_thread, std::vector& logcat_entries, std::vector& filtered_logcat_entry_offsets, const Config& __restrict active_config, Config& __restrict inactive_config, bool* __restrict show_settings_window, bool* __restrict show_logs_window) { ImGui::SetNextWindowPos(ImGui::GetMainViewport()->WorkPos); ImGui::SetNextWindowSize(ImGui::GetMainViewport()->WorkSize); if (!ImGui::Begin("LogMeow", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus)) { ImGui::End(); return; } bool ctrl_comma_pressed = ImGui::IsKeyPressed(ImGuiMod_Shortcut | ImGuiKey_Comma); if ((ImGui::Button("Settings") || ctrl_comma_pressed) && !*show_settings_window) { inactive_config.logcat_command = active_config.logcat_command; inactive_config.normal_font_size = active_config.normal_font_size; inactive_config.monospace_font_size = active_config.monospace_font_size; copy_filters(inactive_config.filters, active_config.filters); copy_filters(inactive_config.exclusions, active_config.exclusions); *show_settings_window = true; } ImGui::SameLine(); bool ctrl_l_pressed = ImGui::IsKeyPressed(ImGuiMod_Shortcut | ImGuiKey_L); bool open_logs = latest_log_entries_read ? ImGui::Button("Logs") : ImGui::RedButton("Logs"); if (open_logs || ctrl_l_pressed) { *show_logs_window = true; } bool can_send_logcat_request = logcat_thread.logcat_process_request.load() == LogcatProcessRequest::None; bool logcat_running = logcat_thread.logcat_process_running.test(); ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted("Logcat:"); ImGui::SameLine(); if (!can_send_logcat_request) { ImGui::BeginDisabled(); } if (ImGui::Button("Start", !logcat_running)) { logcat_entries.clear(); filtered_logcat_entry_offsets.clear(); logcat_thread.logcat_process_request.store(LogcatProcessRequest::Start); } ImGui::SameLine(); if (ImGui::Button("Stop", logcat_running)) { logcat_thread.logcat_process_request.store(LogcatProcessRequest::Stop); } ImGui::SameLine(); if (ImGui::Button("Restart", logcat_running)) { logcat_entries.clear(); filtered_logcat_entry_offsets.clear(); logcat_thread.logcat_process_request.store(LogcatProcessRequest::Start); } if (!can_send_logcat_request) { ImGui::EndDisabled(); } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if (ImGui::Button("Export")) { ImGui::OpenPopup("export_logcat"); } if (ImGui::BeginPopup("export_logcat")) { export_fragment(logcat_entries, filtered_logcat_entry_offsets); ImGui::EndPopup(); } 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("logcat", 8, flags)) { render_table(monospace_font, logcat_entries, filtered_logcat_entry_offsets); } ImGui::End(); }