#include "Windowing/System/EditorWindowSynchronizationPlanner.h" #include "Windowing/System/EditorWindowPresentationPolicy.h" #include #include namespace XCEngine::UI::Editor::App { namespace { const EditorWindowHostSnapshot* FindHostWindowSnapshot( const std::vector& hostWindows, std::string_view windowId) { const auto it = std::find_if( hostWindows.begin(), hostWindows.end(), [windowId](const EditorWindowHostSnapshot& snapshot) { return snapshot.windowId == windowId; }); return it != hostWindows.end() ? &(*it) : nullptr; } bool AreWindowWorkspaceStatesEquivalent( const UIEditorWindowWorkspaceState& lhs, const UIEditorWindowWorkspaceState& rhs) { if (lhs.windowId != rhs.windowId) { return false; } return AreUIEditorWorkspaceLayoutSnapshotsEquivalent( BuildUIEditorWorkspaceLayoutSnapshot(lhs.workspace, lhs.session), BuildUIEditorWorkspaceLayoutSnapshot(rhs.workspace, rhs.session)); } } // namespace EditorWindowSynchronizationPlan EditorWindowSynchronizationPlanner::Build( const EditorWindowSynchronizationPlannerInput& input) { EditorWindowSynchronizationPlan plan = {}; if (input.panelRegistry == nullptr) { plan.errorMessage = "window synchronization planner missing panel registry"; return plan; } if (input.targetWindowSet == nullptr) { plan.errorMessage = "window synchronization planner missing target window set"; return plan; } plan.valid = true; plan.targetWindowSet = *input.targetWindowSet; plan.actions.reserve( input.targetWindowSet->windows.size() + input.hostWindows.size()); for (const UIEditorWindowWorkspaceState& targetWindowState : input.targetWindowSet->windows) { const bool primary = targetWindowState.windowId == input.targetWindowSet->primaryWindowId; const std::wstring title = ResolveEditorWindowPresentationTitle( input.primaryWindowTitle, *input.panelRegistry, targetWindowState, primary); const EditorWindowHostSnapshot* const existingSnapshot = FindHostWindowSnapshot(input.hostWindows, targetWindowState.windowId); if (existingSnapshot == nullptr) { EditorWindowSynchronizationAction action = {}; action.kind = EditorWindowSynchronizationActionKind::CreateWorkspaceWindow; action.create.windowState = targetWindowState; action.create.primary = primary; action.create.title = title; if (!input.preferredNewWindowId.empty() && targetWindowState.windowId == input.preferredNewWindowId) { action.create.placement = input.preferredPlacement; } plan.actions.push_back(std::move(action)); continue; } if (!existingSnapshot->workspaceWindow) { plan.valid = false; plan.errorMessage = "workspace synchronization rejected: window '" + targetWindowState.windowId + "' is not a workspace window"; plan.actions.clear(); return plan; } if (!existingSnapshot->running) { plan.valid = false; plan.errorMessage = "workspace synchronization rejected: window '" + targetWindowState.windowId + "' is not running"; plan.actions.clear(); return plan; } const bool needsUpdate = !existingSnapshot->hasWorkspaceProjection || !AreWindowWorkspaceStatesEquivalent( existingSnapshot->workspaceState, targetWindowState) || existingSnapshot->primary != primary || existingSnapshot->title != title; if (!needsUpdate) { continue; } EditorWindowSynchronizationAction action = {}; action.kind = EditorWindowSynchronizationActionKind::UpdateWorkspaceWindow; action.update.windowState = targetWindowState; action.update.primary = primary; action.update.title = title; plan.actions.push_back(std::move(action)); } for (const EditorWindowHostSnapshot& snapshot : input.hostWindows) { if (!snapshot.workspaceWindow || !snapshot.hasNativeWindow || !snapshot.running || snapshot.primary) { continue; } const bool existsInTarget = FindUIEditorWindowWorkspaceState(*input.targetWindowSet, snapshot.windowId) != nullptr; if (existsInTarget) { continue; } EditorWindowSynchronizationAction action = {}; action.kind = EditorWindowSynchronizationActionKind::CloseWorkspaceWindow; action.close.windowId = snapshot.windowId; plan.actions.push_back(std::move(action)); } return plan; } } // namespace XCEngine::UI::Editor::App