From 6027062ac351af52bd640c7caa760c5f34d613dd Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Fri, 5 Jul 2024 13:57:35 +0200 Subject: [PATCH] Save/LoadLastRunWindowBounds: also save DpiWindowSizeFactor / restore size with DPI handling --- .../backend_impls/abstract_runner.cpp | 38 +++++++++++++ .../internal/backend_impls/abstract_runner.h | 1 + .../internal/hello_imgui_ini_settings.cpp | 55 ++++++++++++++++++- .../internal/hello_imgui_ini_settings.h | 1 + 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/hello_imgui/internal/backend_impls/abstract_runner.cpp b/src/hello_imgui/internal/backend_impls/abstract_runner.cpp index 5f8baacf..b01051a5 100644 --- a/src/hello_imgui/internal/backend_impls/abstract_runner.cpp +++ b/src/hello_imgui/internal/backend_impls/abstract_runner.cpp @@ -159,6 +159,39 @@ void AbstractRunner::PrepareWindowGeometry() params.appWindowParams.windowGeometry.size = windowBounds.size; } + +// If needed, change the size to match the current DPI versus the DPI when the size was saved +// (we want the window to "look" as big as it was when saved, even if the DPI has changed, +// or if we are on a different monitor / computer / OS) +void AbstractRunner::AdjustWindowBoundsAfterCreation_IfDpiChangedBetweenRuns() +{ + bool reloadLastSize = params.appWindowParams.restorePreviousGeometry && + HelloImGuiIniSettings::LoadLastRunWindowBounds(IniSettingsLocation(params)).has_value(); + if (!reloadLastSize) + return; + + std::optional lastRunDpiWindowSizeFactorOpt = HelloImGuiIniSettings::LoadLastRunDpiWindowSizeFactor(IniSettingsLocation(params)); + if (!lastRunDpiWindowSizeFactorOpt.has_value()) + return; + + float lastRunDpiWindowSizeFactor = lastRunDpiWindowSizeFactorOpt.value(); + float currentDpiWindowSizeFactor = params.dpiAwareParams.dpiWindowSizeFactor; + float ratio = currentDpiWindowSizeFactor / lastRunDpiWindowSizeFactor; + bool isSane = ratio > 0.25f && ratio < 4.f; + if (isSane && ratio != 1.f) + { + auto bounds = mBackendWindowHelper->GetWindowBounds(mWindow); + bounds.size = {(int)((float)bounds.size[0] * ratio), + (int)((float)bounds.size[1] * ratio)}; + bounds.position = { + (int)((float)bounds.position[0] * ratio), + (int)((float)bounds.position[1] * ratio) + }; + mBackendWindowHelper->SetWindowBounds(mWindow, bounds); + } +} + + bool AbstractRunner::WantAutoSize() { #ifdef __EMSCRIPTEN__ @@ -717,6 +750,7 @@ void AbstractRunner::Setup() //printf("Window resized by code\n"); } }; + Impl_CreateWindow(fnRenderCallbackDuringResize); #ifdef HELLOIMGUI_HAS_OPENGL @@ -729,7 +763,11 @@ void AbstractRunner::Setup() Impl_SetWindowIcon(); + // The order is important: first read the DPI aware params SetupDpiAwareParams(); + // Then adjust window size if needed + AdjustWindowBoundsAfterCreation_IfDpiChangedBetweenRuns(); + // This should be done before Impl_LinkPlatformAndRenderBackends() // because, in the case of glfw ImGui_ImplGlfw_InstallCallbacks diff --git a/src/hello_imgui/internal/backend_impls/abstract_runner.h b/src/hello_imgui/internal/backend_impls/abstract_runner.h index be28e974..9f198655 100644 --- a/src/hello_imgui/internal/backend_impls/abstract_runner.h +++ b/src/hello_imgui/internal/backend_impls/abstract_runner.h @@ -90,6 +90,7 @@ class AbstractRunner void SetupDpiAwareParams(); bool CheckDpiAwareParamsChanges(); void PrepareWindowGeometry(); + void AdjustWindowBoundsAfterCreation_IfDpiChangedBetweenRuns(); void HandleDpiOnSecondFrame(); void MakeWindowSizeRelativeTo96Ppi_IfRequired(); bool ShallSizeWindowRelativeTo96Ppi(); diff --git a/src/hello_imgui/internal/hello_imgui_ini_settings.cpp b/src/hello_imgui/internal/hello_imgui_ini_settings.cpp index 6bc7c2f9..235d3205 100644 --- a/src/hello_imgui/internal/hello_imgui_ini_settings.cpp +++ b/src/hello_imgui/internal/hello_imgui_ini_settings.cpp @@ -173,11 +173,13 @@ namespace HelloImGui void SaveLastRunWindowBounds(const std::string& iniPartsFilename, const ScreenBounds& windowBounds) { + auto& dpiAwareParams = HelloImGui::GetRunnerParams()->dpiAwareParams; IniParts iniParts = IniParts::LoadFromFile(iniPartsFilename); ini::IniFile iniFile; iniFile["AppWindow"]["WindowPosition"] = IntPairToString(windowBounds.position); iniFile["AppWindow"]["WindowSize"] = IntPairToString(windowBounds.size); + iniFile["AppWindow"]["DpiWindowSizeFactor"] = dpiAwareParams.dpiWindowSizeFactor; std::string iniContent = iniFile.encode(); iniParts.SetIniPart("AppWindow", iniContent); @@ -191,7 +193,6 @@ namespace HelloImGui if (!iniParts.HasIniPart("AppWindow")) return std::nullopt; - auto iniPartContent = iniParts.GetIniPart("AppWindow"); ini::IniFile iniFile; try @@ -206,16 +207,26 @@ namespace HelloImGui ScreenBounds screenBounds; bool failed = false; + if (iniFile.find("AppWindow") == iniFile.end()) + return std::nullopt; + auto & appWindowSection = iniFile["AppWindow"]; + + // Read Window Position { - auto strValue = iniFile["AppWindow"]["WindowPosition"].as(); + if (appWindowSection.find("WindowPosition") == appWindowSection.end()) + return std::nullopt; + auto strValue = appWindowSection["WindowPosition"].as(); auto intPair = StringToIntPair(strValue); if (intPair[0] >= 0) screenBounds.position = intPair; else failed = true; } + // Read Window Size { - auto strValue = iniFile["AppWindow"]["WindowSize"].as(); + if (appWindowSection.find("WindowSize") == appWindowSection.end()) + return std::nullopt; + auto strValue = appWindowSection["WindowSize"].as(); auto intPair = StringToIntPair(strValue); if (intPair[0] >= 0) screenBounds.size = intPair; @@ -230,6 +241,44 @@ namespace HelloImGui } + std::optional LoadLastRunDpiWindowSizeFactor(const std::string& iniPartsFilename) + { + IniParts iniParts = IniParts::LoadFromFile(iniPartsFilename); + + if (!iniParts.HasIniPart("AppWindow")) + return std::nullopt; + + auto iniPartContent = iniParts.GetIniPart("AppWindow"); + ini::IniFile iniFile; + try + { + iniFile.decode(iniPartContent); + } + catch (const std::exception &) + { + return std::nullopt; + } + + ScreenBounds screenBounds; + bool failed = false; + + if (iniFile.find("AppWindow") == iniFile.end()) + return std::nullopt; + auto &appWindowSection = iniFile["AppWindow"]; + + if (appWindowSection.find("DpiWindowSizeFactor") != appWindowSection.end()) + { + float dpiWindowSizeFactor_WhenSaved = + iniFile["AppWindow"]["DpiWindowSizeFactor"].as(); + bool isDpiSane = (dpiWindowSizeFactor_WhenSaved >= 0.1f) && + (dpiWindowSizeFactor_WhenSaved <= 10.f); + if (isDpiSane) + return dpiWindowSizeFactor_WhenSaved; + } + return std::nullopt; + } + + void LoadImGuiSettings(const std::string& iniPartsFilename, const std::string& layoutName) { std::string iniPartName = "ImGui_" + details::SanitizeIniNameOrCategory(layoutName); diff --git a/src/hello_imgui/internal/hello_imgui_ini_settings.h b/src/hello_imgui/internal/hello_imgui_ini_settings.h index 49c4a1ca..ed86d49b 100644 --- a/src/hello_imgui/internal/hello_imgui_ini_settings.h +++ b/src/hello_imgui/internal/hello_imgui_ini_settings.h @@ -61,6 +61,7 @@ namespace HelloImGui // void SaveLastRunWindowBounds(const std::string& iniPartsFilename, const ScreenBounds& windowBounds); std::optional LoadLastRunWindowBounds(const std::string& iniPartsFilename); + std::optional LoadLastRunDpiWindowSizeFactor(const std::string& iniPartsFilename); void SaveHelloImGuiMiscSettings(const std::string& iniPartsFilename, const RunnerParams& runnerParams); void LoadHelloImGuiMiscSettings(const std::string& iniPartsFilename, RunnerParams* inOutRunnerParams);