160 lines
5.6 KiB
C++
160 lines
5.6 KiB
C++
#include <XCEditor/Workspace/UIEditorWindowWorkspaceModel.h>
|
|
#include <XCEditor/Workspace/UIEditorWorkspaceValidation.h>
|
|
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
|
|
namespace XCEngine::UI::Editor {
|
|
|
|
namespace {
|
|
|
|
UIEditorWindowWorkspaceValidationResult MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode code,
|
|
std::string message) {
|
|
UIEditorWindowWorkspaceValidationResult result = {};
|
|
result.code = code;
|
|
result.message = std::move(message);
|
|
return result;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
UIEditorWindowWorkspaceSet BuildDefaultUIEditorWindowWorkspaceSet(
|
|
const UIEditorPanelRegistry& panelRegistry,
|
|
const UIEditorWorkspaceModel& workspace,
|
|
std::string primaryWindowId) {
|
|
if (primaryWindowId.empty()) {
|
|
primaryWindowId = "main-window";
|
|
}
|
|
|
|
UIEditorWindowWorkspaceSet windowSet = {};
|
|
windowSet.primaryWindowId = primaryWindowId;
|
|
windowSet.activeWindowId = primaryWindowId;
|
|
|
|
UIEditorWindowWorkspaceState state = {};
|
|
state.windowId = primaryWindowId;
|
|
state.workspace = CanonicalizeUIEditorWorkspaceModel(workspace);
|
|
state.session = BuildDefaultUIEditorWorkspaceSession(panelRegistry, state.workspace);
|
|
windowSet.windows.push_back(std::move(state));
|
|
return windowSet;
|
|
}
|
|
|
|
const UIEditorWindowWorkspaceState* FindUIEditorWindowWorkspaceState(
|
|
const UIEditorWindowWorkspaceSet& windowSet,
|
|
std::string_view windowId) {
|
|
for (const UIEditorWindowWorkspaceState& state : windowSet.windows) {
|
|
if (state.windowId == windowId) {
|
|
return &state;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
UIEditorWindowWorkspaceState* FindMutableUIEditorWindowWorkspaceState(
|
|
UIEditorWindowWorkspaceSet& windowSet,
|
|
std::string_view windowId) {
|
|
for (UIEditorWindowWorkspaceState& state : windowSet.windows) {
|
|
if (state.windowId == windowId) {
|
|
return &state;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
UIEditorWindowWorkspaceValidationResult ValidateUIEditorWindowWorkspaceSet(
|
|
const UIEditorPanelRegistry& panelRegistry,
|
|
const UIEditorWindowWorkspaceSet& windowSet) {
|
|
const UIEditorPanelRegistryValidationResult registryValidation =
|
|
ValidateUIEditorPanelRegistry(panelRegistry);
|
|
if (!registryValidation.IsValid()) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::InvalidPanelRegistry,
|
|
registryValidation.message);
|
|
}
|
|
|
|
if (windowSet.primaryWindowId.empty()) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::MissingPrimaryWindow,
|
|
"Primary window id must not be empty.");
|
|
}
|
|
|
|
if (windowSet.activeWindowId.empty()) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::MissingActiveWindow,
|
|
"Active window id must not be empty.");
|
|
}
|
|
|
|
std::unordered_set<std::string> seenWindowIds = {};
|
|
std::unordered_map<std::string, std::string> panelOwners = {};
|
|
bool hasPrimaryWindow = false;
|
|
bool hasActiveWindow = false;
|
|
for (const UIEditorWindowWorkspaceState& state : windowSet.windows) {
|
|
if (state.windowId.empty()) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::EmptyWindowId,
|
|
"Window id must not be empty.");
|
|
}
|
|
|
|
if (!seenWindowIds.insert(state.windowId).second) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::DuplicateWindowId,
|
|
"Window id '" + state.windowId + "' is duplicated.");
|
|
}
|
|
|
|
if (state.windowId == windowSet.primaryWindowId) {
|
|
hasPrimaryWindow = true;
|
|
}
|
|
if (state.windowId == windowSet.activeWindowId) {
|
|
hasActiveWindow = true;
|
|
}
|
|
|
|
const UIEditorWorkspaceValidationResult workspaceValidation =
|
|
ValidateUIEditorWorkspace(state.workspace);
|
|
if (!workspaceValidation.IsValid()) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::InvalidWorkspace,
|
|
"Window '" + state.windowId + "' workspace invalid: " +
|
|
workspaceValidation.message);
|
|
}
|
|
|
|
const UIEditorWorkspaceSessionValidationResult sessionValidation =
|
|
ValidateUIEditorWorkspaceSession(panelRegistry, state.workspace, state.session);
|
|
if (!sessionValidation.IsValid()) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::InvalidSession,
|
|
"Window '" + state.windowId + "' session invalid: " +
|
|
sessionValidation.message);
|
|
}
|
|
|
|
for (const UIEditorPanelSessionState& panelState : state.session.panelStates) {
|
|
const auto [ownerIt, inserted] =
|
|
panelOwners.emplace(panelState.panelId, state.windowId);
|
|
if (!inserted) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::DuplicatePanelAcrossWindows,
|
|
"Panel '" + panelState.panelId + "' is present in both window '" +
|
|
ownerIt->second + "' and window '" + state.windowId + "'.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasPrimaryWindow) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::MissingPrimaryWindow,
|
|
"Primary window '" + windowSet.primaryWindowId + "' does not exist.");
|
|
}
|
|
|
|
if (!hasActiveWindow) {
|
|
return MakeValidationError(
|
|
UIEditorWindowWorkspaceValidationCode::MissingActiveWindow,
|
|
"Active window '" + windowSet.activeWindowId + "' does not exist.");
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor
|