diff --git a/src/hello_imgui/doc_params.md b/src/hello_imgui/doc_params.md index d03c0d56..75e4a9dd 100644 --- a/src/hello_imgui/doc_params.md +++ b/src/hello_imgui/doc_params.md @@ -1310,11 +1310,7 @@ struct DockingParams bool focusDockableWindow(const std::string& windowName); // `optional dockSpaceIdFromName(const std::string& dockSpaceName)`: - // may return the ImGuiID corresponding to the dockspace with this name. - // **Warning**: this will work reliably only if - // layoutCondition = DockingLayoutCondition::ApplicationStart. - // In other cases, the ID may be cached by ImGui himself at the first run, - // and HelloImGui will *not* know it on subsequent runs! + // returns the ImGuiID corresponding to the dockspace with this name std::optional dockSpaceIdFromName(const std::string& dockSpaceName); }; ``` diff --git a/src/hello_imgui/docking_params.h b/src/hello_imgui/docking_params.h index 104b78b9..9cff4c06 100644 --- a/src/hello_imgui/docking_params.h +++ b/src/hello_imgui/docking_params.h @@ -364,11 +364,7 @@ struct DockingParams bool focusDockableWindow(const std::string& windowName); // `optional dockSpaceIdFromName(const std::string& dockSpaceName)`: - // may return the ImGuiID corresponding to the dockspace with this name. - // **Warning**: this will work reliably only if - // layoutCondition = DockingLayoutCondition::ApplicationStart. - // In other cases, the ID may be cached by ImGui himself at the first run, - // and HelloImGui will *not* know it on subsequent runs! + // returns the ImGuiID corresponding to the dockspace with this name std::optional dockSpaceIdFromName(const std::string& dockSpaceName); }; // @@md diff --git a/src/hello_imgui/internal/docking_details.cpp b/src/hello_imgui/internal/docking_details.cpp index bf931ef6..0a477763 100644 --- a/src/hello_imgui/internal/docking_details.cpp +++ b/src/hello_imgui/internal/docking_details.cpp @@ -6,6 +6,7 @@ #include "hello_imgui/hello_imgui.h" #include "hello_imgui/internal/functional_utils.h" #include "imgui_internal.h" +#include "nlohmann/json.hpp" #include #include #include @@ -17,8 +18,60 @@ namespace HelloImGui // From hello_imgui.cpp bool ShouldRemoteDisplay(); +namespace SplitIdsHelper +{ + std::map gImGuiSplitIDs; + + bool ContainsSplit(const DockSpaceName& dockSpaceName) + { + return gImGuiSplitIDs.find(dockSpaceName) != gImGuiSplitIDs.end(); + } + + ImGuiID GetSplitId(const DockSpaceName& dockSpaceName) + { + IM_ASSERT(ContainsSplit(dockSpaceName) && "GetSplitId: dockSpaceName not found in gImGuiSplitIDs"); + return gImGuiSplitIDs.at(dockSpaceName); + } -std::map gImGuiSplitIDs; + void SetSplitId(const DockSpaceName& dockSpaceName, ImGuiID imguiId) + { + gImGuiSplitIDs[dockSpaceName] = imguiId; + } + + std::string SaveSplitIds() + { + // Serialize gImGuiSplitIDs using json + nlohmann::json j; + j["gImGuiSplitIDs"] = gImGuiSplitIDs; + return j.dump(); + } + + void LoadSplitIds(const std::string& jsonStr) + { + // Deserialize gImGuiSplitIDs using json + try + { + nlohmann::json j = nlohmann::json::parse(jsonStr); + gImGuiSplitIDs = j.at("gImGuiSplitIDs").get>(); + } + catch (const nlohmann::json::parse_error& e) + { + std::cerr << "LoadSplitIds: Failed to parse JSON: " << e.what() << std::endl; + } + catch (const nlohmann::json::type_error& e) + { + std::cerr << "LoadSplitIds: Type error during deserialization: " << e.what() << std::endl; + } + catch (const nlohmann::json::out_of_range& e) + { + std::cerr << "LoadSplitIds: Missing or incorrect key in JSON: " << e.what() << std::endl; + } + catch (const std::exception& e) + { + std::cerr << "LoadSplitIds: Unexpected error: " << e.what() << std::endl; + } + } +} static bool gShowTweakWindow = false; @@ -65,9 +118,9 @@ bool _makeImGuiWindowTabVisible(const std::string& windowName) void DoSplit(const DockingSplit & dockingSplit) { - IM_ASSERT(gImGuiSplitIDs.find(dockingSplit.initialDock) != gImGuiSplitIDs.end()); + IM_ASSERT(SplitIdsHelper::ContainsSplit(dockingSplit.initialDock) && "DoSplit: initialDock not found in gImGuiSplitIDs"); - ImGuiID initialDock_imguiId = gImGuiSplitIDs.at(dockingSplit.initialDock); + ImGuiID initialDock_imguiId = SplitIdsHelper::GetSplitId(dockingSplit.initialDock); ImGuiID newDock_imguiId = ImGui::DockBuilderSplitNode( initialDock_imguiId, @@ -76,8 +129,8 @@ void DoSplit(const DockingSplit & dockingSplit) nullptr, &initialDock_imguiId); - gImGuiSplitIDs[dockingSplit.initialDock] = initialDock_imguiId; - gImGuiSplitIDs[dockingSplit.newDock] = newDock_imguiId; + SplitIdsHelper::SetSplitId(dockingSplit.initialDock, initialDock_imguiId); + SplitIdsHelper::SetSplitId(dockingSplit.newDock, newDock_imguiId); // apply flags ImGuiDockNode* newDockNode = ImGui::DockBuilderGetNode(newDock_imguiId); @@ -94,10 +147,12 @@ void ApplyWindowDockingLocations( const std::vector & dockableWindows) { for (const auto & dockableWindow: dockableWindows) + { ImGui::DockBuilderDockWindow( dockableWindow.label.c_str(), - gImGuiSplitIDs[dockableWindow.dockSpaceName] + SplitIdsHelper::GetSplitId(dockableWindow.dockSpaceName) ); + } } std::vector _GetStaticallyOrderedLayoutsList(const RunnerParams& runnerParams) @@ -524,7 +579,7 @@ void ImplProvideFullScreenDockSpace(const RunnerParams& runnerParams) DoCreateFullScreenImGuiWindow(runnerParams, true); ImGuiID mainDockspaceId = ImGui::GetID("MainDockSpace"); ImGui::DockSpace(mainDockspaceId, ImVec2(0.0f, 0.0f), runnerParams.dockingParams.mainDockSpaceNodeFlags); - gImGuiSplitIDs["MainDockSpace"] = mainDockspaceId; + SplitIdsHelper::SetSplitId("MainDockSpace", mainDockspaceId); } void ConfigureImGuiDocking(const ImGuiWindowParams& imGuiWindowParams) @@ -602,10 +657,10 @@ bool DockingParams::focusDockableWindow(const std::string& windowName) std::optional DockingParams::dockSpaceIdFromName(const std::string& dockSpaceName) { - if (gImGuiSplitIDs.find(dockSpaceName) == gImGuiSplitIDs.end()) - return std::nullopt; + if (SplitIdsHelper::ContainsSplit(dockSpaceName)) + return SplitIdsHelper::GetSplitId(dockSpaceName); else - return gImGuiSplitIDs.at(dockSpaceName); + return std::nullopt; } diff --git a/src/hello_imgui/internal/hello_imgui_ini_settings.cpp b/src/hello_imgui/internal/hello_imgui_ini_settings.cpp index 235d3205..27a5c905 100644 --- a/src/hello_imgui/internal/hello_imgui_ini_settings.cpp +++ b/src/hello_imgui/internal/hello_imgui_ini_settings.cpp @@ -6,6 +6,14 @@ namespace HelloImGui { + // Encapsulated in docking_details.cpp + namespace SplitIdsHelper + { + std::string SaveSplitIds(); + void LoadSplitIds(const std::string&); + } + + std::string IntPairToString(std::array v); std::array StringToIntPair(const std::string& s); @@ -379,6 +387,21 @@ namespace HelloImGui } } + void LoadSplitIds(const std::string& iniPartsFilename) + { + const std::string iniPartName = "SplitIds"; + std::string serialized = LoadUserPref(iniPartsFilename, iniPartName); + if (!serialized.empty()) + SplitIdsHelper::LoadSplitIds(serialized); + } + + void SaveSplitIds(const std::string& iniPartsFilename) + { + const std::string iniPartName = "SplitIds"; + std::string serialized = SplitIdsHelper::SaveSplitIds(); + SaveUserPref(iniPartsFilename, iniPartName, serialized); + } + void LoadHelloImGuiMiscSettings(const std::string& iniPartsFilename, RunnerParams* inOutRunnerParams) { std::string iniPartName = "HelloImGui_Misc"; @@ -432,6 +455,8 @@ namespace HelloImGui ImGuiTheme::ApplyTheme(theme); } HelloImGui::SwitchLayout(layoutName); + + LoadSplitIds(iniPartsFilename); } void SaveHelloImGuiMiscSettings(const std::string& iniPartsFilename, const RunnerParams& runnerParams) @@ -455,6 +480,8 @@ namespace HelloImGui IniParts iniParts = IniParts::LoadFromFile(iniPartsFilename); iniParts.SetIniPart(iniPartName, iniFile.encode()); iniParts.WriteToFile(iniPartsFilename); + + SaveSplitIds(iniPartsFilename); }