new_editor: make window sync rollback safe
This commit is contained in:
@@ -10,6 +10,16 @@
|
||||
|
||||
namespace XCEngine::UI::Editor::App::Internal {
|
||||
|
||||
namespace {
|
||||
|
||||
struct ExistingWindowSnapshot {
|
||||
EditorWindow* window = nullptr;
|
||||
UIEditorWorkspaceController workspaceController = {};
|
||||
std::wstring title = {};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::wstring EditorWindowWorkspaceCoordinator::BuildWindowTitle(
|
||||
const UIEditorWorkspaceController& workspaceController) const {
|
||||
const std::string& activePanelId = workspaceController.GetWorkspace().activePanelId;
|
||||
@@ -54,13 +64,62 @@ bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet(
|
||||
const UIEditorWindowWorkspaceSet& windowSet,
|
||||
std::string_view preferredNewWindowId,
|
||||
const POINT& preferredScreenPoint) {
|
||||
const auto restoreWindowSnapshot = [](const ExistingWindowSnapshot& snapshot) {
|
||||
if (snapshot.window == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot.window->ReplaceWorkspaceController(snapshot.workspaceController);
|
||||
snapshot.window->SetTitle(snapshot.title);
|
||||
snapshot.window->ResetInteractionState();
|
||||
if (snapshot.window->GetHwnd() != nullptr) {
|
||||
SetWindowTextW(snapshot.window->GetHwnd(), snapshot.window->GetTitle().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
const auto destroyAndEraseWindowById = [this](std::string_view windowId) {
|
||||
auto& windows = m_hostRuntime.GetWindows();
|
||||
const auto it = std::find_if(
|
||||
windows.begin(),
|
||||
windows.end(),
|
||||
[windowId](const std::unique_ptr<EditorWindow>& candidate) {
|
||||
return candidate != nullptr && candidate->GetWindowId() == windowId;
|
||||
});
|
||||
if (it == windows.end() || *it == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EditorWindow& window = *it->get();
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (GetCapture() == hwnd) {
|
||||
ReleaseCapture();
|
||||
}
|
||||
|
||||
window.Shutdown();
|
||||
if (hwnd != nullptr && IsWindow(hwnd)) {
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
window.MarkDestroyed();
|
||||
windows.erase(it);
|
||||
return true;
|
||||
};
|
||||
|
||||
std::vector<std::string> windowIdsInSet = {};
|
||||
windowIdsInSet.reserve(windowSet.windows.size());
|
||||
std::vector<ExistingWindowSnapshot> existingWindowSnapshots = {};
|
||||
existingWindowSnapshots.reserve(windowSet.windows.size());
|
||||
std::vector<std::string> createdWindowIds = {};
|
||||
|
||||
for (const UIEditorWindowWorkspaceState& entry : windowSet.windows) {
|
||||
windowIdsInSet.push_back(entry.windowId);
|
||||
if (EditorWindow* existingWindow = m_hostRuntime.FindWindow(entry.windowId);
|
||||
existingWindow != nullptr) {
|
||||
existingWindow->ClearClosing();
|
||||
existingWindowSnapshots.push_back(ExistingWindowSnapshot{
|
||||
existingWindow,
|
||||
existingWindow->GetWorkspaceController(),
|
||||
existingWindow->GetTitle(),
|
||||
});
|
||||
existingWindow->ReplaceWorkspaceController(BuildWorkspaceControllerForWindow(entry));
|
||||
existingWindow->ResetInteractionState();
|
||||
if (!existingWindow->IsPrimary()) {
|
||||
@@ -93,8 +152,15 @@ bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet(
|
||||
}
|
||||
|
||||
if (m_hostRuntime.CreateEditorWindow(BuildWorkspaceControllerForWindow(entry), createParams) == nullptr) {
|
||||
for (const ExistingWindowSnapshot& snapshot : existingWindowSnapshots) {
|
||||
restoreWindowSnapshot(snapshot);
|
||||
}
|
||||
for (auto it = createdWindowIds.rbegin(); it != createdWindowIds.rend(); ++it) {
|
||||
destroyAndEraseWindowById(*it);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
createdWindowIds.push_back(entry.windowId);
|
||||
}
|
||||
|
||||
for (const std::unique_ptr<EditorWindow>& window : m_hostRuntime.GetWindows()) {
|
||||
@@ -110,6 +176,7 @@ bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet(
|
||||
windowIdsInSet.end(),
|
||||
window->GetWindowId()) != windowIdsInSet.end();
|
||||
if (!existsInWindowSet) {
|
||||
window->MarkClosing();
|
||||
PostMessageW(window->GetHwnd(), WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user