diff --git a/CMakeLists.txt b/CMakeLists.txt index 3158f5b..dd9d8a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ project(logmeow CXX) find_package(SDL2 REQUIRED) find_package(Freetype 2 REQUIRED) find_package(nlohmann_json REQUIRED) -list(APPEND LIBS -lpcre2-8 -lpcre2-posix SDL2 nlohmann_json::nlohmann_json imgui) +list(APPEND LIBS -lpcre2-8 -lpcre2-posix SDL2 nlohmann_json::nlohmann_json imgui nfd) list(APPEND IMGUI_LIBS SDL2 Freetype::Freetype) set(INCLUDES "") @@ -19,7 +19,7 @@ set(DEFINITIONS "") # imgui include because https://github.com/ocornut/imgui/issues/6184#issuecomment-1439570929 list(APPEND INCLUDES thirdparty thirdparty/imgui /usr/include/SDL2) list(APPEND SOURCES main.cpp event_loop.cpp logcat_thread.cpp logcat_entry.cpp log.cpp config.cpp filters.cpp misc.cpp pcre2_wrapper.cpp - group_panel.cpp fragments/filters.cpp windows/logs.cpp windows/settings.cpp windows/main.cpp) + group_panel.cpp fragments/filters.cpp fragments/export.cpp windows/logs.cpp windows/settings.cpp windows/main.cpp) list(APPEND IMGUI_SOURCES thirdparty/imgui/imgui.cpp thirdparty/imgui/imgui_draw.cpp thirdparty/imgui/imgui_widgets.cpp thirdparty/imgui/imgui_tables.cpp thirdparty/imgui/misc/cpp/imgui_stdlib.cpp thirdparty/imgui/misc/freetype/imgui_freetype.cpp thirdparty/imgui/backends/imgui_impl_sdl2.cpp thirdparty/imgui/backends/imgui_impl_opengl3.cpp) @@ -88,6 +88,9 @@ target_compile_definitions(imgui PRIVATE ${DEFINITIONS}) # it seems like compilers may issue a warning for unknown warnings to ignore target_compile_options(imgui PRIVATE ${FLAGS} -Wno-unknown-warning-option -Wno-conversion) +set(NFD_PORTAL ON) +add_subdirectory(thirdparty/nativefiledialog-extended) + add_executable(${PROJECT_NAME} ${SOURCES}) set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/fragments/export.cpp b/fragments/export.cpp new file mode 100644 index 0000000..a02ed8f --- /dev/null +++ b/fragments/export.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + +#include "../file.h" +#include "../logcat_entry.h" +#include "export.h" + +enum class ExportAmount : int { + All = 0, + Filtered = 1, +}; + +static inline void export_logcat_entries(File& file, const std::vector& logcat_entries, + const std::vector& filtered_logcat_entry_offsets, ExportAmount export_amount, bool export_buffers); +static inline std::optional save_file_picker(); + +void export_fragment(const std::vector& logcat_entries, const std::vector& filtered_logcat_entry_offsets) { + static ExportAmount export_amount = ExportAmount::Filtered; + static bool export_buffers = true; + + ImGui::RadioButton("Export all entries", reinterpret_cast(&export_amount), static_cast(ExportAmount::All)); + ImGui::RadioButton("Export filtered entries", reinterpret_cast(&export_amount), static_cast(ExportAmount::Filtered)); + ImGui::Checkbox("Export buffers", &export_buffers); + ImGui::Separator(); + + if (ImGui::Button("Export to File")) { + std::optional file = save_file_picker(); + if (file) { + export_logcat_entries(*file, logcat_entries, filtered_logcat_entry_offsets, export_amount, export_buffers); + ImGui::CloseCurrentPopup(); + } + } + + ImGui::SameLine(); + if (ImGui::Button("Export to Clipboard")) { + // TODO exist + } +} + +static inline void export_logcat_entries(File& file, const std::vector& logcat_entries, + const std::vector& filtered_logcat_entry_offsets, ExportAmount export_amount, bool export_buffers) { + // TODO actually do the job + file.write(std::string("Count of all entries: ") + std::to_string(logcat_entries.size()) + '\n'); + file.write(std::string("Count of filtered entries: ") + std::to_string(filtered_logcat_entry_offsets.size()) + '\n'); + file.write(std::string("Export amount: ") + (export_amount == ExportAmount::All ? "all" : "filtered") + '\n'); + file.write(std::string("Export buffers: ") + (export_buffers ? "true" : "false") + '\n'); +} + +static inline std::optional save_file_picker() { + nfdchar_t* path; + nfdfilteritem_t filters[1] = {{"Log file", "log"}}; + nfdresult_t res = NFD_SaveDialog(&path, filters, 1, nullptr, "logcat.log"); + + if (res == NFD_OKAY) { + try { + File file(path, "w"); + NFD_FreePath(path); + return std::move(file); + } catch (const std::exception& e) { + NFD_FreePath(path); + log(std::string("Failed to open file from file picker: ") + e.what()); + } + } else if (res == NFD_CANCEL) { + // dialog was canceled, shrug + } else { + log(std::string("Failed to open file picker: ") + NFD_GetError()); + } + + return std::nullopt; +} diff --git a/fragments/export.h b/fragments/export.h new file mode 100644 index 0000000..bb0d666 --- /dev/null +++ b/fragments/export.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +struct LogcatEntry; // forward declaration from ../logcat_entry.h + +void export_fragment(const std::vector& logcat_entries, const std::vector& filtered_logcat_entry_offsets); diff --git a/main.cpp b/main.cpp index 023b161..f0eeb90 100644 --- a/main.cpp +++ b/main.cpp @@ -12,6 +12,7 @@ #else #include #endif +#include #include "log.h" #include "fonts.h" @@ -47,6 +48,13 @@ int main() { return 1; } + // Setup NFDe + if (NFD_Init() != NFD_OKAY) { + SDL_Quit(); + fprintf(stderr, "NFD_Init(): %s\n", NFD_GetError()); + return 1; + } + // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 @@ -178,6 +186,8 @@ int main() { ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); + NFD_Quit(); + SDL_GL_DeleteContext(gl_context); SDL_DestroyWindow(window); SDL_Quit(); diff --git a/thirdparty/nativefiledialog-extended b/thirdparty/nativefiledialog-extended new file mode 160000 index 0000000..7909f55 --- /dev/null +++ b/thirdparty/nativefiledialog-extended @@ -0,0 +1 @@ +Subproject commit 7909f55d912fe353ee2df6b08eec9313b50685f7 diff --git a/windows/main.cpp b/windows/main.cpp index 1530119..f3a1b1e 100644 --- a/windows/main.cpp +++ b/windows/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,6 +8,7 @@ #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) { @@ -166,6 +168,17 @@ void main_window(bool latest_log_entries_read, ImFont* monospace_font, LogcatThr 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()