Refactor editor window synchronization flow
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
#include "Windowing/System/EditorWindowSystem.h"
|
||||
|
||||
#include "Windowing/System/EditorWindowSynchronizationPlanner.h"
|
||||
|
||||
#include <XCEditor/Workspace/UIEditorWindowWorkspaceModel.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
@@ -37,23 +42,6 @@ bool EditorWindowSystem::ValidateWindowSet(
|
||||
return m_workspaceStore.ValidateWindowSet(windowSet, outError);
|
||||
}
|
||||
|
||||
bool EditorWindowSystem::TrySetWindowSet(
|
||||
UIEditorWindowWorkspaceSet windowSet,
|
||||
std::string& outError) {
|
||||
return m_workspaceStore.TrySetWindowSet(std::move(windowSet), outError);
|
||||
}
|
||||
|
||||
bool EditorWindowSystem::UpsertWindowState(
|
||||
const UIEditorWindowWorkspaceState& windowState,
|
||||
bool primary,
|
||||
std::string& outError) {
|
||||
return m_workspaceStore.UpsertWindowState(windowState, primary, outError);
|
||||
}
|
||||
|
||||
void EditorWindowSystem::RemoveWindowState(std::string_view windowId, bool primary) {
|
||||
m_workspaceStore.RemoveWindowState(windowId, primary);
|
||||
}
|
||||
|
||||
bool EditorWindowSystem::IsPrimaryWindowId(std::string_view windowId) const {
|
||||
return m_workspaceStore.IsPrimaryWindowId(windowId);
|
||||
}
|
||||
@@ -66,6 +54,146 @@ UIEditorWindowWorkspaceController EditorWindowSystem::BuildWorkspaceMutationCont
|
||||
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::BuildPlanForLiveWindowMutation(
|
||||
std::string_view windowId,
|
||||
const UIEditorWorkspaceController& workspaceController,
|
||||
const std::vector<EditorWindowHostSnapshot>& hostWindows,
|
||||
std::wstring_view primaryWindowTitle,
|
||||
std::string& outError) const {
|
||||
if (windowId.empty()) {
|
||||
outError = "live window mutation missing window id";
|
||||
return {};
|
||||
}
|
||||
|
||||
UIEditorWindowWorkspaceSet nextWindowSet = GetWindowSet();
|
||||
UIEditorWindowWorkspaceState* existingState =
|
||||
FindMutableUIEditorWindowWorkspaceState(nextWindowSet, windowId);
|
||||
if (existingState == nullptr) {
|
||||
outError = "live window mutation references unknown window '" + std::string(windowId) + "'";
|
||||
return {};
|
||||
}
|
||||
|
||||
existingState->workspace = workspaceController.GetWorkspace();
|
||||
existingState->session = workspaceController.GetSession();
|
||||
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,
|
||||
@@ -75,4 +203,37 @@ UIEditorWindowWorkspaceOperationResult EditorWindowSystem::EvaluateDetachPanelTo
|
||||
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::App
|
||||
|
||||
Reference in New Issue
Block a user