diff --git a/wpigui/src/main/native/cpp/wpigui.cpp b/wpigui/src/main/native/cpp/wpigui.cpp index 4b200b5af9..eb7bc1d225 100644 --- a/wpigui/src/main/native/cpp/wpigui.cpp +++ b/wpigui/src/main/native/cpp/wpigui.cpp @@ -146,7 +146,12 @@ bool gui::Initialize(const char* title, int width, int height) { iniHandler.WriteAllFn = IniWriteAll; ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler); - io.IniFilename = gContext->iniPath.c_str(); + if (gContext->loadSettings) { + gContext->loadSettings(); + io.IniFilename = nullptr; + } else { + io.IniFilename = gContext->iniPath.c_str(); + } for (auto&& initialize : gContext->initializers) { if (initialize) { @@ -155,7 +160,11 @@ bool gui::Initialize(const char* title, int width, int height) { } // Load INI file - ImGui::LoadIniSettingsFromDisk(io.IniFilename); + if (gContext->loadIniSettings) { + gContext->loadIniSettings(); + } else if (io.IniFilename) { + ImGui::LoadIniSettingsFromDisk(io.IniFilename); + } // Set initial window settings glfwWindowHint(GLFW_MAXIMIZED, gContext->maximized ? GLFW_TRUE : GLFW_FALSE); @@ -283,6 +292,20 @@ void gui::Main() { // Poll and handle events (inputs, window resize, etc.) glfwPollEvents(); PlatformRenderFrame(); + + // custom saving + if (gContext->saveSettings) { + auto& io = ImGui::GetIO(); + if (io.WantSaveIniSettings) { + gContext->saveSettings(false); + io.WantSaveIniSettings = false; // reset flag + } + } + } + + // Save (if custom save) + if (gContext->saveSettings) { + gContext->saveSettings(true); } // Cleanup @@ -292,7 +315,7 @@ void gui::Main() { ImGui::DestroyContext(); // Delete the save file if requested. - if (gContext->resetOnExit) { + if (!gContext->saveSettings && gContext->resetOnExit) { fs::remove(fs::path{gContext->iniPath}); } @@ -367,6 +390,14 @@ void gui::AddLateExecute(std::function execute) { } } +void gui::ConfigureCustomSaveSettings(std::function load, + std::function loadIni, + std::function save) { + gContext->loadSettings = load; + gContext->loadIniSettings = loadIni; + gContext->saveSettings = save; +} + GLFWwindow* gui::GetSystemWindow() { return gContext->window; } @@ -416,27 +447,31 @@ void gui::SetClearColor(ImVec4 color) { gContext->clearColor = color; } -void gui::ConfigurePlatformSaveFile(const std::string& name) { - gContext->iniPath = name; +std::string gui::GetPlatformSaveFileDir() { #if defined(_MSC_VER) const char* env = std::getenv("APPDATA"); if (env) { - gContext->iniPath = env + std::string("/" + name); + return env + std::string("/"); } #elif defined(__APPLE__) const char* env = std::getenv("HOME"); if (env) { - gContext->iniPath = env + std::string("/Library/Preferences/" + name); + return env + std::string("/Library/Preferences/"); } #else const char* xdg = std::getenv("XDG_CONFIG_HOME"); const char* env = std::getenv("HOME"); if (xdg) { - gContext->iniPath = xdg + std::string("/" + name); + return xdg + std::string("/"); } else if (env) { - gContext->iniPath = env + std::string("/.config/" + name); + return env + std::string("/.config/"); } #endif + return ""; +} + +void gui::ConfigurePlatformSaveFile(const std::string& name) { + gContext->iniPath = GetPlatformSaveFileDir() + name; } void gui::EmitViewMenu() { @@ -473,7 +508,9 @@ void gui::EmitViewMenu() { ImGui::EndMenu(); } - ImGui::MenuItem("Reset UI on Exit?", nullptr, &gContext->resetOnExit); + if (!gContext->saveSettings) { + ImGui::MenuItem("Reset UI on Exit?", nullptr, &gContext->resetOnExit); + } ImGui::EndMenu(); } } diff --git a/wpigui/src/main/native/include/wpigui.h b/wpigui/src/main/native/include/wpigui.h index 7860f0debd..d4602b5951 100644 --- a/wpigui/src/main/native/include/wpigui.h +++ b/wpigui/src/main/native/include/wpigui.h @@ -79,6 +79,36 @@ void AddEarlyExecute(std::function execute); */ void AddLateExecute(std::function execute); +/** + * Customizes save/load behavior. + * + * By default, the integrated ImGui functions are used for this; + * ImGui::LoadIniSettingsFromDisk(io.IniFilename) is called at startup, and + * ImGui default automatic save file handling is used via io.IniFilename. + * + * Calling this function results in the load function being called at startup, + * io.IniFilename set to null (which disables ImGui's integrated file saving), + * and the save function being called when io.WantSaveIniSettings is true. + * The loadIni function should call ImGui::LoadIniSettingsFromMemory() to load + * ImGui save data, and the save function should call + * ImGui::SaveIniSettingsToMemory() to get ImGui save data. + * + * The load function is called PRIOR to AddInit() functions, and the loadIni + * function is called AFTER to AddInit() functions. This allows initialize + * functions that use custom storage to handle the loaded values, and initialize + * functions that use INI storage to add hooks prior to the load INI occurring. + * + * This must be called prior to Initialize(). + * + * @param load load function + * @param loadIni load INI function + * @param save save function; false is passed periodically, true is passed once + * when the main loop is exiting + */ +void ConfigureCustomSaveSettings(std::function load, + std::function loadIni, + std::function save); + /** * Gets GLFW window handle. */ @@ -137,6 +167,14 @@ void SetStyle(Style style); */ void SetClearColor(ImVec4 color); +/** + * Gets the (platform-specific) absolute directory for save files. + * + * @return Absolute path, including trailing "/". Empty string if directory + * could not be determined. + */ +std::string GetPlatformSaveFileDir(); + /** * Configures a save file (.ini) in a platform specific location. On Windows, * the .ini is saved in %APPDATA%; on macOS the .ini is saved in diff --git a/wpigui/src/main/native/include/wpigui_internal.h b/wpigui/src/main/native/include/wpigui_internal.h index 13e504cccf..4b658a82f8 100644 --- a/wpigui/src/main/native/include/wpigui_internal.h +++ b/wpigui/src/main/native/include/wpigui_internal.h @@ -40,6 +40,9 @@ struct Context : public SavedSettings { GLFWwindow* window = nullptr; + std::function loadSettings; + std::function loadIniSettings; + std::function saveSettings; std::vector> initializers; std::vector> windowScalers; std::vector