198 lines
7.5 KiB
C++
198 lines
7.5 KiB
C++
#include "Platform/Win32/WindowManager/Internal.h"
|
|
|
|
#include "State/EditorContext.h"
|
|
#include "Platform/Win32/EditorWindow.h"
|
|
|
|
#include <XCEditor/Workspace/UIEditorWindowWorkspaceController.h>
|
|
#include <XCEditor/Workspace/UIEditorWorkspaceController.h>
|
|
|
|
#include <algorithm>
|
|
|
|
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;
|
|
if (const UIEditorPanelDescriptor* descriptor =
|
|
FindUIEditorPanelDescriptor(
|
|
workspaceController.GetPanelRegistry(),
|
|
activePanelId);
|
|
descriptor != nullptr &&
|
|
!descriptor->defaultTitle.empty()) {
|
|
const std::string titleText = descriptor->defaultTitle + " - XCEngine Editor";
|
|
return std::wstring(titleText.begin(), titleText.end());
|
|
}
|
|
|
|
return std::wstring(L"XCEngine Editor");
|
|
}
|
|
|
|
RECT EditorWindowWorkspaceCoordinator::BuildDetachedWindowRect(const POINT& screenPoint) const {
|
|
RECT rect = {
|
|
screenPoint.x - 420,
|
|
screenPoint.y - 24,
|
|
screenPoint.x - 420 + 960,
|
|
screenPoint.y - 24 + 720
|
|
};
|
|
|
|
const HMONITOR monitor = MonitorFromPoint(screenPoint, MONITOR_DEFAULTTONEAREST);
|
|
MONITORINFO monitorInfo = {};
|
|
monitorInfo.cbSize = sizeof(monitorInfo);
|
|
if (monitor != nullptr && GetMonitorInfoW(monitor, &monitorInfo)) {
|
|
const RECT& workArea = monitorInfo.rcWork;
|
|
const LONG width = rect.right - rect.left;
|
|
const LONG height = rect.bottom - rect.top;
|
|
rect.left = (std::max)(workArea.left, (std::min)(rect.left, workArea.right - width));
|
|
rect.top = (std::max)(workArea.top, (std::min)(rect.top, workArea.bottom - height));
|
|
rect.right = rect.left + width;
|
|
rect.bottom = rect.top + height;
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
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()) {
|
|
existingWindow->SetTitle(
|
|
BuildWindowTitle(existingWindow->GetWorkspaceController()));
|
|
if (existingWindow->GetHwnd() != nullptr) {
|
|
SetWindowTextW(existingWindow->GetHwnd(), existingWindow->GetTitle().c_str());
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
EditorWindowHostRuntime::CreateParams createParams = {};
|
|
createParams.windowId = entry.windowId;
|
|
createParams.primary = entry.windowId == windowSet.primaryWindowId;
|
|
createParams.title =
|
|
createParams.primary
|
|
? std::wstring(
|
|
m_hostRuntime.GetHostConfig().primaryWindowTitle != nullptr &&
|
|
m_hostRuntime.GetHostConfig().primaryWindowTitle[0] != L'\0'
|
|
? m_hostRuntime.GetHostConfig().primaryWindowTitle
|
|
: L"XCEngine Editor")
|
|
: BuildWindowTitle(BuildWorkspaceControllerForWindow(entry));
|
|
if (entry.windowId == preferredNewWindowId) {
|
|
const RECT detachedRect = BuildDetachedWindowRect(preferredScreenPoint);
|
|
createParams.initialX = detachedRect.left;
|
|
createParams.initialY = detachedRect.top;
|
|
createParams.initialWidth = detachedRect.right - detachedRect.left;
|
|
createParams.initialHeight = detachedRect.bottom - detachedRect.top;
|
|
}
|
|
|
|
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()) {
|
|
if (window == nullptr ||
|
|
window->GetHwnd() == nullptr ||
|
|
window->IsPrimary()) {
|
|
continue;
|
|
}
|
|
|
|
const bool existsInWindowSet =
|
|
std::find(
|
|
windowIdsInSet.begin(),
|
|
windowIdsInSet.end(),
|
|
window->GetWindowId()) != windowIdsInSet.end();
|
|
if (!existsInWindowSet) {
|
|
window->MarkClosing();
|
|
PostMessageW(window->GetHwnd(), WM_CLOSE, 0, 0);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromController(
|
|
const UIEditorWindowWorkspaceController& windowWorkspaceController,
|
|
std::string_view preferredNewWindowId,
|
|
const POINT& preferredScreenPoint) {
|
|
return SynchronizeWindowsFromWindowSet(
|
|
windowWorkspaceController.GetWindowSet(),
|
|
preferredNewWindowId,
|
|
preferredScreenPoint);
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App::Internal
|