diff --git a/CMakeLists.txt b/CMakeLists.txt index ea786c8..2fad28a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,15 +26,17 @@ set(LIBS -lpcre2-8 -lpcre2-posix SDL2 imgui) set(IMGUI_LIBS SDL2 Freetype::Freetype) set(INCLUDES imgui imgui/backends imgui/misc/cpp imgui/freetype /usr/include/SDL2) -set(SOURCES main.cpp event_loop.cpp logcat_thread.cpp logcat_entry.cpp log.cpp config.cpp misc.cpp pcre2_wrapper.cpp) +set(SOURCES main.cpp event_loop.cpp logcat_thread.cpp logcat_entry.cpp log.cpp config.cpp misc.cpp pcre2_wrapper.cpp + windows/logs.cpp windows/settings.cpp windows/main.cpp) set(IMGUI_SOURCES imgui/imgui.cpp imgui/imgui_draw.cpp imgui/imgui_widgets.cpp imgui/imgui_tables.cpp imgui/misc/cpp/imgui_stdlib.cpp imgui/misc/freetype/imgui_freetype.cpp imgui/backends/imgui_impl_sdl.cpp imgui/backends/imgui_impl_opengl3.cpp) if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(SOURCES ${SOURCES} windows/debug.cpp) set(IMGUI_SOURCES ${IMGUI_SOURCES} imgui/imgui_demo.cpp) endif() -set(FLAGS "-fsanitize=undefined,thread") +set(FLAGS "-fsanitize=undefined,thread -DIMGUI_USER_CONFIG='\"../myimconfig.h\"'") # https://t.me/NightShadowsHangout/670691 set(FLAGS "${FLAGS} -Werror -Wall -Wextra -Wshadow -Wpedantic -Wno-gnu-anonymous-struct -fno-rtti -fPIC -Wconversion -Wno-unused-parameter -Wimplicit-fallthrough") # https://sourceforge.net/p/valgrind/mailman/valgrind-users/thread/Ygze8PzaQAYWlKDj%40wildebeest.org/ @@ -69,7 +71,7 @@ add_library(imgui STATIC ${IMGUI_SOURCES}) target_include_directories(imgui PRIVATE ${INCLUDES}) target_link_libraries(imgui PRIVATE ${IMGUI_LIBS}) # dear imgui has some fucky wucky with -Wconversion, hence -Wno-conversion -target_compile_options(imgui PRIVATE -Wno-conversion -DIMGUI_USER_CONFIG="../myimconfig.h") +target_compile_options(imgui PRIVATE -Wno-conversion) add_executable(${PROJECT_NAME} ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDES}) diff --git a/event_loop.cpp b/event_loop.cpp index 5cba8a3..0f689a6 100644 --- a/event_loop.cpp +++ b/event_loop.cpp @@ -1,21 +1,15 @@ #include -#include - -// for Test user assert -#ifndef NDEBUG -#include "myimconfig.h" -#endif #include "log.h" #include "config.h" #include "logcat_thread.h" -static std::string leftpad(std::string str, size_t characters) { - if (str.size() < characters) { - return str.insert(0, characters - str.size(), ' '); - } - return str; -} +#include "windows/logs.h" +#include "windows/settings.h" +#include "windows/main.h" +#ifndef NDEBUG + #include "windows/debug.h" +#endif static inline void write_config_and_update_structures(const Config& config) { try { @@ -42,195 +36,6 @@ static inline void check_for_logcat_items(LogcatThread& logcat_thread, std::vect } -static inline void settings_window(Config& config, float* config_write_timer, bool* show_settings_window) { - if (!ImGui::Begin("Settings", show_settings_window)) { - ImGui::End(); - return; - } - // TODO actually have process control - ImGui::Text("Logcat command only takes effect when logcat is not running"); - if (ImGui::InputTextWithHint("Logcat command", "adb logcat -Dv 'threadtime UTC epoch usec uid'", &config.logcat_command)) { - *config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f; - } - ImGui::Text("Font sizes only take effect when LogMeow is restarted"); -#ifdef USE_FONTCONFIG - if (ImGui::InputFloat("Normal font size", &config.normal_font_size, 0.5f, 1.0f, "%.3f")) { - *config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f; - } -#endif - if (ImGui::InputFloat("Monospace font size", &config.monospace_font_size, 0.5f, 1.0f, "%.3f")) { - *config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f; - } - ImGui::End(); -} - -static inline void logs_window(ImFont* monospace_font, bool* autoscrolling, bool* show_logs_window) { - if (!ImGui::Begin("LogMeow Logs", show_logs_window)) { - ImGui::End(); - return; - } - - if (ImGui::Button("Clear")) { - log_entries.clear(); - log_entry_line_offsets = {0}; - } - ImGui::SameLine(); - if (ImGui::Button("Copy")) { - ImGui::SetClipboardText(log_entries.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() - if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { - ImGui::PushFont(monospace_font); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - - ImGuiListClipper clipper; - clipper.Begin(static_cast(log_entry_line_offsets.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); - - const char* start_offset = &log_entries[log_entry_line_offsets[i]]; - const char* end_offset = log_entry_line_offsets.size() > i + 1 - ? &log_entries[log_entry_line_offsets[i + 1] - 1] - : &log_entries[log_entries.size()]; - ImGui::TextUnformatted(start_offset, end_offset); - } - } - clipper.End(); - - ImGui::PopStyleVar(); - ImGui::PopFont(); - if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { - *autoscrolling = true; - ImGui::SetScrollHereY(1.0f); - } - } - ImGui::EndChild(); - ImGui::End(); -} - -static inline void main_window(bool latest_log_entries_read, ImFont* monospace_font, std::vector& filtered_logcat_entries, - bool* show_settings_window, bool* show_logs_window, bool* run_event_loop) { - if (!ImGui::Begin("LogMeow", run_event_loop)) { - ImGui::End(); - return; - } - - if (ImGui::Button("Settings")) { - *show_settings_window = true; - } - - ImGui::SameLine(); - if (!latest_log_entries_read) { - ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0.0f, 0.6f, 0.6f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0.0f, 0.7f, 0.7f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0.0f, 0.8f, 0.8f)); - } - if (ImGui::Button("Logs")) { - *show_logs_window = true; - } - if (!latest_log_entries_read) { - ImGui::PopStyleColor(3); - } - - 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() - if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { - ImGui::PushFont(monospace_font); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - - ImGuiListClipper clipper; - clipper.Begin(static_cast(filtered_logcat_entries.size())); - while (clipper.Step()) { - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - LogcatEntry* logcat_entry = &filtered_logcat_entries[static_cast(i)]; - char time_as_str[128] = {0}; - strftime(time_as_str, 127 * sizeof(char), "%c", localtime(&logcat_entry->time)); - - std::string header = std::string(1, '[') + time_as_str + ' ' - + leftpad(logcat_entry->user.value_or(" "), 5) + ' ' - + leftpad(std::to_string(logcat_entry->pid), 5) + ' ' - + leftpad(std::to_string(logcat_entry->tid), 5) + ' ' - + leftpad(buffer_to(logcat_entry->buffer), 6) + ' ' - + leftpad(priority_to(logcat_entry->priority), 7) + "] "; - ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); - ImGui::TextUnformatted(header.data(), &header[header.size()]); - ImGui::PopStyleColor(); - - std::string line = logcat_entry->tag + ": " + logcat_entry->message; - ImGui::SameLine(); - ImGui::TextUnformatted(line.data(), &line[line.size()]); - } - } - clipper.End(); - - ImGui::PopStyleVar(); - ImGui::PopFont(); - if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { - ImGui::SetScrollHereY(1.0f); - } - } - ImGui::EndChild(); - ImGui::End(); -} - -#ifndef NDEBUG -static inline void debug_window(LogcatThread& logcat_thread) { - static bool show_demo_window = false; - static size_t add_log_entry_presses = 1; - static bool log_entry_every_second = false; - static float log_entry_every_second_delta; - - if (show_demo_window) { - ImGui::ShowDemoWindow(&show_demo_window); - } - if (!ImGui::Begin("LogMeow Debug")) { - ImGui::End(); - return; - } - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::Checkbox("Show Dear ImGui Demo Window", &show_demo_window); - - ImGui::Separator(); - if (ImGui::Button("Add Log Entry")) { - log(std::string("Debug log entry #") + std::to_string(add_log_entry_presses++) + " (activated via manual button press)"); - } - ImGui::SameLine(); - // returns true when it's pressed - if (ImGui::Checkbox("Add log entry every second", &log_entry_every_second)) { - log_entry_every_second_delta = 0.0f; - } - if (ImGui::Button("Add Log Entry with Newlines")) { - log("The following should have five spaces: \"\n\n\n\n\n\""); - } - if (ImGui::Button("Test user assert")) { - IM_ASSERT_USER_ERROR(0, "User assert tested"); - } - if (ImGui::Button("Request log entry from Logcat thread")) { - logcat_thread.debug_log_request.test_and_set(); - } - - if (log_entry_every_second) { - log_entry_every_second_delta += ImGui::GetIO().DeltaTime; - if (log_entry_every_second_delta >= 1.0f) { - log_entry_every_second_delta = 0.0f; - log(std::string("Debug log entry #") + std::to_string(add_log_entry_presses++) + " (activated by add log entry every second)"); - } - } - - ImGui::End(); -} -#endif - void event_loop(ImFont* monospace_font, Config& config, float* config_write_timer, LogcatThread& logcat_thread, bool* run_event_loop) { static bool show_settings_window = false; static bool show_logs_window = false; diff --git a/windows/debug.cpp b/windows/debug.cpp new file mode 100644 index 0000000..a8a073a --- /dev/null +++ b/windows/debug.cpp @@ -0,0 +1,53 @@ +#include +#include "../myimconfig.h" + +#include "../log.h" +#include "../logcat_thread.h" +#include "debug.h" + +void debug_window(LogcatThread& logcat_thread) { + static bool show_demo_window = false; + static size_t add_log_entry_presses = 1; + static bool log_entry_every_second = false; + static float log_entry_every_second_delta; + + if (show_demo_window) { + ImGui::ShowDemoWindow(&show_demo_window); + } + if (!ImGui::Begin("LogMeow Debug")) { + ImGui::End(); + return; + } + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Checkbox("Show Dear ImGui Demo Window", &show_demo_window); + + ImGui::Separator(); + if (ImGui::Button("Add Log Entry")) { + log(std::string("Debug log entry #") + std::to_string(add_log_entry_presses++) + " (activated via manual button press)"); + } + ImGui::SameLine(); + // returns true when it's pressed + if (ImGui::Checkbox("Add log entry every second", &log_entry_every_second)) { + log_entry_every_second_delta = 0.0f; + } + if (ImGui::Button("Add Log Entry with Newlines")) { + log("The following should have five spaces: \"\n\n\n\n\n\""); + } + if (ImGui::Button("Test user assert")) { + IM_ASSERT_USER_ERROR(0, "User assert tested"); + } + if (ImGui::Button("Request log entry from Logcat thread")) { + logcat_thread.debug_log_request.test_and_set(); + } + + if (log_entry_every_second) { + log_entry_every_second_delta += ImGui::GetIO().DeltaTime; + if (log_entry_every_second_delta >= 1.0f) { + log_entry_every_second_delta = 0.0f; + log(std::string("Debug log entry #") + std::to_string(add_log_entry_presses++) + " (activated by add log entry every second)"); + } + } + + ImGui::End(); +} diff --git a/windows/debug.h b/windows/debug.h new file mode 100644 index 0000000..3e2f8d8 --- /dev/null +++ b/windows/debug.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../logcat_thread.h" + +void debug_window(LogcatThread& logcat_thread); diff --git a/windows/logs.cpp b/windows/logs.cpp new file mode 100644 index 0000000..db18aae --- /dev/null +++ b/windows/logs.cpp @@ -0,0 +1,60 @@ +#include + +#include "../log.h" +#include "logs.h" + +static inline void logs_scrolling_region(ImFont* monospace_font, bool* autoscrolling) { + ImGui::PushFont(monospace_font); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + + ImGuiListClipper clipper; + clipper.Begin(static_cast(log_entry_line_offsets.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); + + const char* start_offset = &log_entries[log_entry_line_offsets[i]]; + const char* end_offset = log_entry_line_offsets.size() > i + 1 + ? &log_entries[log_entry_line_offsets[i + 1] - 1] + : &log_entries[log_entries.size()]; + ImGui::TextUnformatted(start_offset, end_offset); + } + } + clipper.End(); + + ImGui::PopStyleVar(); + ImGui::PopFont(); + + if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { + *autoscrolling = true; + ImGui::SetScrollHereY(1.0f); + } +} + +void logs_window(ImFont* monospace_font, bool* autoscrolling, bool* p_open) { + if (!ImGui::Begin("LogMeow Logs", p_open)) { + ImGui::End(); + return; + } + + if (ImGui::Button("Clear")) { + log_entries.clear(); + log_entry_line_offsets = {0}; + } + ImGui::SameLine(); + if (ImGui::Button("Copy")) { + ImGui::SetClipboardText(log_entries.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() + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { + logs_scrolling_region(monospace_font, autoscrolling); + } + ImGui::EndChild(); + ImGui::End(); +} diff --git a/windows/logs.h b/windows/logs.h new file mode 100644 index 0000000..5b05350 --- /dev/null +++ b/windows/logs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void logs_window(ImFont* monospace_font, bool* autoscrolling, bool* p_open); diff --git a/windows/main.cpp b/windows/main.cpp new file mode 100644 index 0000000..e522f79 --- /dev/null +++ b/windows/main.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +#include "../logcat_entry.h" +#include "main.h" + +static std::string leftpad(std::string str, size_t characters) { + if (str.size() < characters) { + return str.insert(0, characters - str.size(), ' '); + } + return str; +} + +static inline void main_scrolling_region(ImFont* monospace_font, std::vector& filtered_logcat_entries) { + ImGui::PushFont(monospace_font); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + + ImGuiListClipper clipper; + clipper.Begin(static_cast(filtered_logcat_entries.size())); + while (clipper.Step()) { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + LogcatEntry* logcat_entry = &filtered_logcat_entries[static_cast(i)]; + char time_as_str[128] = {0}; + strftime(time_as_str, 127 * sizeof(char), "%c", localtime(&logcat_entry->time)); + + std::string header = std::string(1, '[') + time_as_str + ' ' + + leftpad(logcat_entry->user.value_or(" "), 5) + ' ' + + leftpad(std::to_string(logcat_entry->pid), 5) + ' ' + + leftpad(std::to_string(logcat_entry->tid), 5) + ' ' + + leftpad(buffer_to(logcat_entry->buffer), 6) + ' ' + + leftpad(priority_to(logcat_entry->priority), 7) + "] "; + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); + ImGui::TextUnformatted(header.data(), &header[header.size()]); + ImGui::PopStyleColor(); + + std::string line = logcat_entry->tag + ": " + logcat_entry->message; + ImGui::SameLine(); + ImGui::TextUnformatted(line.data(), &line[line.size()]); + } + } + clipper.End(); + + ImGui::PopStyleVar(); + ImGui::PopFont(); + if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) { + ImGui::SetScrollHereY(1.0f); + } +} + +void main_window(bool latest_log_entries_read, ImFont* monospace_font, std::vector& filtered_logcat_entries, + bool* show_settings_window, bool* show_logs_window, bool* run_event_loop) { + if (!ImGui::Begin("LogMeow", run_event_loop)) { + ImGui::End(); + return; + } + + if (ImGui::Button("Settings")) { + *show_settings_window = true; + } + + ImGui::SameLine(); + if (!latest_log_entries_read) { + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0.0f, 0.8f, 0.8f)); + } + if (ImGui::Button("Logs")) { + *show_logs_window = true; + } + if (!latest_log_entries_read) { + ImGui::PopStyleColor(3); + } + + 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() + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { + main_scrolling_region(monospace_font, filtered_logcat_entries); + } + ImGui::EndChild(); + ImGui::End(); +} diff --git a/windows/main.h b/windows/main.h new file mode 100644 index 0000000..2092149 --- /dev/null +++ b/windows/main.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +#include "../logcat_entry.h" + +void main_window(bool latest_log_entries_read, ImFont* monospace_font, std::vector& filtered_logcat_entries, + bool* show_settings_window, bool* show_logs_window, bool* run_event_loop); diff --git a/windows/settings.cpp b/windows/settings.cpp new file mode 100644 index 0000000..abc7e4f --- /dev/null +++ b/windows/settings.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include "../config.h" +#include "settings.h" + +void settings_window(Config& config, float* config_write_timer, bool* p_open) { + if (!ImGui::Begin("Settings", p_open)) { + ImGui::End(); + return; + } + // TODO actually have process control + ImGui::Text("Logcat command only takes effect when logcat is not running"); + if (ImGui::InputTextWithHint("Logcat command", "adb logcat -Dv 'threadtime UTC epoch usec uid'", &config.logcat_command)) { + *config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f; + } + ImGui::Text("Font sizes only take effect when LogMeow is restarted"); +#ifdef USE_FONTCONFIG + if (ImGui::InputFloat("Normal font size", &config.normal_font_size, 0.5f, 1.0f, "%.3f")) { + *config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f; + } +#endif + if (ImGui::InputFloat("Monospace font size", &config.monospace_font_size, 0.5f, 1.0f, "%.3f")) { + *config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f; + } + ImGui::End(); +} diff --git a/windows/settings.h b/windows/settings.h new file mode 100644 index 0000000..2e4237c --- /dev/null +++ b/windows/settings.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../config.h" + +void settings_window(Config& config, float* config_write_timer, bool* p_open);