Files
XCEngine/editor/src/Windowing/EditorWindowSystem.cpp

247 lines
8.4 KiB
C++
Raw Normal View History

#include <XCEditor/Windowing/EditorWindowSystem.h>
#include "Windowing/EditorWindowSynchronizationPlanner.h"
#include "Windowing/EditorWindowWorkspaceStore.h"
#include <XCEditor/Workspace/UIEditorWindowWorkspaceModel.h>
#include <algorithm>
#include <utility>
namespace XCEngine::UI::Editor {
EditorWindowSystem::EditorWindowSystem(UIEditorPanelRegistry panelRegistry)
: m_workspaceStore(std::make_unique<EditorWindowWorkspaceStore>(std::move(panelRegistry))) {}
EditorWindowSystem::~EditorWindowSystem() = default;
const UIEditorPanelRegistry& EditorWindowSystem::GetPanelRegistry() const {
return m_workspaceStore->GetPanelRegistry();
}
bool EditorWindowSystem::BootstrapPrimaryWindow(
std::string_view primaryWindowId,
2026-04-26 13:44:19 +08:00
const UIEditorWindowWorkspaceState& primaryWindowState,
std::string& outError) {
const std::string resolvedPrimaryWindowId =
primaryWindowId.empty() ? std::string("main-window") : std::string(primaryWindowId);
UIEditorWindowWorkspaceSet windowSet = {};
windowSet.primaryWindowId = resolvedPrimaryWindowId;
windowSet.activeWindowId = resolvedPrimaryWindowId;
2026-04-26 13:44:19 +08:00
UIEditorWindowWorkspaceState resolvedPrimaryWindowState = primaryWindowState;
resolvedPrimaryWindowState.windowId = resolvedPrimaryWindowId;
windowSet.windows.push_back(std::move(resolvedPrimaryWindowState));
return m_workspaceStore->TrySetWindowSet(std::move(windowSet), outError);
}
bool EditorWindowSystem::ValidateWindowSet(
const UIEditorWindowWorkspaceSet& windowSet,
std::string& outError) const {
return m_workspaceStore->ValidateWindowSet(windowSet, outError);
}
bool EditorWindowSystem::IsPrimaryWindowId(std::string_view windowId) const {
return m_workspaceStore->IsPrimaryWindowId(windowId);
}
const UIEditorWindowWorkspaceSet& EditorWindowSystem::GetWindowSet() const {
return m_workspaceStore->GetWindowSet();
}
const UIEditorWindowWorkspaceState* EditorWindowSystem::FindWindowState(
std::string_view windowId) const {
return FindUIEditorWindowWorkspaceState(GetWindowSet(), windowId);
}
UIEditorWindowWorkspaceController EditorWindowSystem::BuildWorkspaceMutationController() const {
return UIEditorWindowWorkspaceController(GetPanelRegistry(), GetWindowSet());
}
EditorWindowSynchronizationPlan EditorWindowSystem::BuildPlanForWindowSet(
const UIEditorWindowWorkspaceSet& targetWindowSet,
const std::vector<EditorWindowHostSnapshot>& hostWindows,
std::wstring_view primaryWindowTitle,
std::string_view preferredNewWindowId,
const EditorWindowSynchronizationPlacement& preferredPlacement,
std::string& outError) const {
return BuildSynchronizationPlan(
EditorWindowSynchronizationPlannerInput{
.targetWindowSet = &targetWindowSet,
.primaryWindowTitle = primaryWindowTitle,
.preferredNewWindowId = preferredNewWindowId,
.preferredPlacement = preferredPlacement,
.hostWindows = hostWindows,
},
outError);
}
EditorWindowSynchronizationPlan EditorWindowSystem::BuildPlanForWorkspaceMutationRequest(
const EditorWindowWorkspaceMutationRequest& request,
const std::vector<EditorWindowHostSnapshot>& hostWindows,
std::wstring_view primaryWindowTitle,
std::string& outError) const {
if (!request.IsValid()) {
outError = "live window mutation request missing window id";
return {};
}
UIEditorWindowWorkspaceSet nextWindowSet = GetWindowSet();
UIEditorWindowWorkspaceState* existingState =
FindMutableUIEditorWindowWorkspaceState(nextWindowSet, request.windowState.windowId);
if (existingState == nullptr) {
outError =
"live window mutation references unknown window '" +
request.windowState.windowId + "'";
return {};
}
existingState->workspace = request.windowState.workspace;
existingState->session = request.windowState.session;
return BuildPlanForWindowSet(
nextWindowSet,
hostWindows,
primaryWindowTitle,
{},
{},
outError);
}
EditorWindowSynchronizationPlan EditorWindowSystem::BuildPlanForDestroyedWindow(
std::string_view windowId,
const std::vector<EditorWindowHostSnapshot>& hostWindows,
std::wstring_view primaryWindowTitle,
std::string& outError) const {
if (windowId.empty()) {
outError = "window destroy event missing window id";
return {};
}
UIEditorWindowWorkspaceSet nextWindowSet = GetWindowSet();
const bool destroyedPrimary = nextWindowSet.primaryWindowId == windowId;
if (!RemoveWindowStateFromSet(nextWindowSet, windowId)) {
outError =
"window destroy event references unknown authoritative window '" +
std::string(windowId) + "'";
return {};
}
if (destroyedPrimary) {
EditorWindowSynchronizationPlan plan = {};
plan.valid = true;
plan.targetWindowSet = {};
for (const EditorWindowHostSnapshot& snapshot : hostWindows) {
if (!snapshot.workspaceWindow ||
!snapshot.hasNativeWindow ||
!snapshot.running ||
snapshot.windowId == windowId) {
continue;
}
EditorWindowSynchronizationAction action = {};
action.kind = EditorWindowSynchronizationActionKind::CloseWorkspaceWindow;
action.close.windowId = snapshot.windowId;
plan.actions.push_back(std::move(action));
}
outError.clear();
return plan;
}
return BuildPlanForWindowSet(
nextWindowSet,
hostWindows,
primaryWindowTitle,
{},
{},
outError);
}
EditorWindowSynchronizationPlan EditorWindowSystem::BuildSynchronizationPlan(
const EditorWindowSynchronizationPlannerInput& input,
std::string& outError) const {
if (input.targetWindowSet == nullptr) {
outError = "window synchronization planner missing target window set";
return {};
}
if (!ValidateWindowSet(*input.targetWindowSet, outError)) {
return {};
}
EditorWindowSynchronizationPlannerInput resolvedInput = input;
resolvedInput.panelRegistry = &GetPanelRegistry();
EditorWindowSynchronizationPlan plan =
EditorWindowSynchronizationPlanner::Build(resolvedInput);
if (!plan.valid) {
outError = plan.errorMessage;
return {};
}
outError.clear();
return plan;
}
bool EditorWindowSystem::CommitSynchronizationPlan(
const EditorWindowSynchronizationPlan& plan,
std::string& outError) {
if (!plan.valid) {
outError = !plan.errorMessage.empty()
? plan.errorMessage
: "cannot commit invalid synchronization plan";
return false;
}
if (plan.targetWindowSet.windows.empty()) {
m_workspaceStore->ClearWindowSet();
outError.clear();
return true;
}
return m_workspaceStore->TrySetWindowSet(plan.targetWindowSet, outError);
}
UIEditorWindowWorkspaceOperationResult EditorWindowSystem::EvaluateDetachPanelToNewWindow(
std::string_view sourceWindowId,
std::string_view sourceNodeId,
std::string_view panelId,
UIEditorWindowWorkspaceController& outController) const {
outController = BuildWorkspaceMutationController();
return outController.DetachPanelToNewWindow(sourceWindowId, sourceNodeId, panelId);
}
bool EditorWindowSystem::RemoveWindowStateFromSet(
UIEditorWindowWorkspaceSet& windowSet,
std::string_view windowId) {
const auto originalSize = windowSet.windows.size();
windowSet.windows.erase(
std::remove_if(
windowSet.windows.begin(),
windowSet.windows.end(),
[windowId](const UIEditorWindowWorkspaceState& state) {
return state.windowId == windowId;
}),
windowSet.windows.end());
if (windowSet.windows.size() == originalSize) {
return false;
}
if (windowSet.windows.empty()) {
windowSet = {};
return true;
}
if (windowSet.primaryWindowId == windowId ||
FindUIEditorWindowWorkspaceState(windowSet, windowSet.primaryWindowId) == nullptr) {
windowSet.primaryWindowId = windowSet.windows.front().windowId;
}
if (windowSet.activeWindowId == windowId ||
FindUIEditorWindowWorkspaceState(windowSet, windowSet.activeWindowId) == nullptr) {
windowSet.activeWindowId = windowSet.primaryWindowId;
}
return true;
}
} // namespace XCEngine::UI::Editor