Preserve saved editor dock layouts

This commit is contained in:
2026-04-01 16:43:46 +08:00
parent 3f18530396
commit 6e2711f9e8
3 changed files with 67 additions and 4 deletions

View File

@@ -194,7 +194,7 @@ bool Application::SwitchProject(const std::string& projectPath) {
return false; return false;
} }
m_imguiSession.SetProjectPath(projectPath); const bool hasSavedDockLayout = m_imguiSession.SetProjectPath(projectPath);
m_editorContext->SetProjectPath(projectPath); m_editorContext->SetProjectPath(projectPath);
auto& logger = Debug::Logger::Get(); auto& logger = Debug::Logger::Get();
@@ -208,6 +208,11 @@ bool Application::SwitchProject(const std::string& projectPath) {
m_lastWindowTitle.clear(); m_lastWindowTitle.clear();
UpdateWindowTitle(); UpdateWindowTitle();
if (!hasSavedDockLayout) {
m_editorContext->GetEventBus().Publish(DockLayoutResetRequestedEvent{});
}
return true; return true;
} }

View File

@@ -6,6 +6,7 @@
#include "UI/DockHostStyle.h" #include "UI/DockHostStyle.h"
#include "UI/DockTabBarChrome.h" #include "UI/DockTabBarChrome.h"
#include <fstream>
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h> #include <imgui_internal.h>
@@ -24,6 +25,8 @@ public:
[this](const DockLayoutResetRequestedEvent&) { [this](const DockLayoutResetRequestedEvent&) {
RequestReset(); RequestReset();
}); });
m_layoutDirty = true;
m_forceRebuild = false;
} }
void Detach() { void Detach() {
@@ -34,10 +37,12 @@ public:
m_context = nullptr; m_context = nullptr;
m_resetLayoutHandlerId = 0; m_resetLayoutHandlerId = 0;
m_layoutDirty = true; m_layoutDirty = true;
m_forceRebuild = false;
} }
void RequestReset() { void RequestReset() {
m_layoutDirty = true; m_layoutDirty = true;
m_forceRebuild = true;
} }
void RenderDockspace() { void RenderDockspace() {
@@ -65,8 +70,11 @@ public:
} }
if (m_layoutDirty) { if (m_layoutDirty) {
BuildDefaultLayout(dockspaceId, viewport->Size); if (m_forceRebuild || !HasSavedDockLayout()) {
BuildDefaultLayout(dockspaceId, viewport->Size);
}
m_layoutDirty = false; m_layoutDirty = false;
m_forceRebuild = false;
} }
UI::ConfigureDockTabBarChrome(dockspaceId); UI::ConfigureDockTabBarChrome(dockspaceId);
@@ -74,6 +82,31 @@ public:
} }
private: private:
static bool HasSavedDockLayout() {
if (ImGui::GetCurrentContext() == nullptr) {
return false;
}
const char* iniFilename = ImGui::GetIO().IniFilename;
if (iniFilename == nullptr || iniFilename[0] == '\0') {
return false;
}
std::ifstream input(iniFilename, std::ios::in);
if (!input.is_open()) {
return false;
}
std::string line;
while (std::getline(input, line)) {
if (line == "[Docking][Data]") {
return true;
}
}
return false;
}
void BuildDefaultLayout(ImGuiID dockspaceId, const ImVec2& dockspaceSize) { void BuildDefaultLayout(ImGuiID dockspaceId, const ImVec2& dockspaceSize) {
ImGui::DockBuilderRemoveNode(dockspaceId); ImGui::DockBuilderRemoveNode(dockspaceId);
ImGui::DockBuilderAddNode(dockspaceId, m_dockspaceFlags | ImGuiDockNodeFlags_DockSpace); ImGui::DockBuilderAddNode(dockspaceId, m_dockspaceFlags | ImGuiDockNodeFlags_DockSpace);
@@ -97,6 +130,7 @@ private:
IEditorContext* m_context = nullptr; IEditorContext* m_context = nullptr;
uint64_t m_resetLayoutHandlerId = 0; uint64_t m_resetLayoutHandlerId = 0;
bool m_layoutDirty = true; bool m_layoutDirty = true;
bool m_forceRebuild = false;
ImGuiDockNodeFlags m_dockspaceFlags = ImGuiDockNodeFlags_NoWindowMenuButton; ImGuiDockNodeFlags m_dockspaceFlags = ImGuiDockNodeFlags_NoWindowMenuButton;
}; };

View File

@@ -5,6 +5,7 @@
#include <imgui.h> #include <imgui.h>
#include <filesystem> #include <filesystem>
#include <fstream>
#include <string> #include <string>
namespace XCEngine { namespace XCEngine {
@@ -48,15 +49,17 @@ public:
return m_iniPath; return m_iniPath;
} }
void SetProjectPath(const std::string& projectPath) { bool SetProjectPath(const std::string& projectPath) {
if (ImGui::GetCurrentContext() == nullptr) { if (ImGui::GetCurrentContext() == nullptr) {
return; return false;
} }
SaveSettings(); SaveSettings();
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ConfigureIniFile(projectPath, io); ConfigureIniFile(projectPath, io);
const bool hasSavedLayout = HasSavedDockLayoutOnDisk(m_iniPath);
ImGui::LoadIniSettingsFromDisk(m_iniPath.c_str()); ImGui::LoadIniSettingsFromDisk(m_iniPath.c_str());
return hasSavedLayout;
} }
private: private:
@@ -64,6 +67,27 @@ private:
static constexpr const char* kPrimaryUiFontPath = "C:/Windows/Fonts/segoeui.ttf"; static constexpr const char* kPrimaryUiFontPath = "C:/Windows/Fonts/segoeui.ttf";
static constexpr const char* kChineseFallbackFontPath = "C:/Windows/Fonts/msyh.ttc"; static constexpr const char* kChineseFallbackFontPath = "C:/Windows/Fonts/msyh.ttc";
static bool HasSavedDockLayoutOnDisk(const std::filesystem::path& iniPath) {
std::error_code ec;
if (!std::filesystem::is_regular_file(iniPath, ec) || ec) {
return false;
}
std::ifstream input(iniPath, std::ios::in);
if (!input.is_open()) {
return false;
}
std::string line;
while (std::getline(input, line)) {
if (line == "[Docking][Data]") {
return true;
}
}
return false;
}
void ConfigureIniFile(const std::string& projectPath, ImGuiIO& io) { void ConfigureIniFile(const std::string& projectPath, ImGuiIO& io) {
const std::filesystem::path configDir = std::filesystem::path(projectPath) / ".xceditor"; const std::filesystem::path configDir = std::filesystem::path(projectPath) / ".xceditor";
std::error_code ec; std::error_code ec;