Internalize editor shell asset definition contract
This commit is contained in:
@@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
#include "Core/EditorShellAsset.h"
|
#include "Core/EditorShellAsset.h"
|
||||||
|
|
||||||
|
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
||||||
|
#include <XCEditor/Core/UIEditorShortcutManager.h>
|
||||||
|
#include <XCEditor/Core/UIEditorWorkspaceController.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Runtime/UIScreenDocumentHost.h>
|
#include <XCEngine/UI/Runtime/UIScreenDocumentHost.h>
|
||||||
#include <XCEngine/UI/Runtime/UIScreenPlayer.h>
|
#include <XCEngine/UI/Runtime/UIScreenPlayer.h>
|
||||||
|
|
||||||
@@ -24,6 +28,46 @@
|
|||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct StructuredEditorShellBinding {
|
||||||
|
::XCEngine::UI::Runtime::UIScreenAsset screenAsset = {};
|
||||||
|
UIEditorWorkspaceController workspaceController = {};
|
||||||
|
UIEditorShellInteractionDefinition shellDefinition = {};
|
||||||
|
UIEditorShortcutManager shortcutManager = {};
|
||||||
|
EditorShellAssetValidationResult assetValidation = {};
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsValid() const {
|
||||||
|
return assetValidation.IsValid();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline UIEditorShortcutManager BuildStructuredEditorShortcutManager(
|
||||||
|
const EditorShellAsset& asset) {
|
||||||
|
(void)asset;
|
||||||
|
return UIEditorShortcutManager(UIEditorCommandRegistry{});
|
||||||
|
}
|
||||||
|
|
||||||
|
inline StructuredEditorShellBinding BuildStructuredEditorShellBinding(
|
||||||
|
const EditorShellAsset& asset) {
|
||||||
|
StructuredEditorShellBinding binding = {};
|
||||||
|
binding.screenAsset.screenId = asset.screenId;
|
||||||
|
binding.screenAsset.documentPath = asset.documentPath.string();
|
||||||
|
binding.screenAsset.themePath = asset.themePath.string();
|
||||||
|
binding.workspaceController =
|
||||||
|
UIEditorWorkspaceController(asset.panelRegistry, asset.workspace, asset.workspaceSession);
|
||||||
|
binding.shellDefinition = asset.shellDefinition;
|
||||||
|
binding.shortcutManager = BuildStructuredEditorShortcutManager(asset);
|
||||||
|
binding.assetValidation = ValidateEditorShellAsset(asset);
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UIEditorShellInteractionServices BuildStructuredEditorShellServices(
|
||||||
|
const StructuredEditorShellBinding& binding) {
|
||||||
|
UIEditorShellInteractionServices services = {};
|
||||||
|
services.commandDispatcher = &binding.shortcutManager.GetCommandDispatcher();
|
||||||
|
services.shortcutManager = &binding.shortcutManager;
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
class Application {
|
class Application {
|
||||||
public:
|
public:
|
||||||
Application();
|
Application();
|
||||||
@@ -65,6 +109,8 @@ private:
|
|||||||
::XCEngine::UI::Runtime::UIScreenPlayer m_screenPlayer;
|
::XCEngine::UI::Runtime::UIScreenPlayer m_screenPlayer;
|
||||||
::XCEngine::UI::Runtime::UIScreenAsset m_screenAsset = {};
|
::XCEngine::UI::Runtime::UIScreenAsset m_screenAsset = {};
|
||||||
EditorShellAsset m_shellAssetDefinition = {};
|
EditorShellAsset m_shellAssetDefinition = {};
|
||||||
|
StructuredEditorShellBinding m_structuredShell = {};
|
||||||
|
UIEditorShellInteractionServices m_shellServices = {};
|
||||||
std::vector<TrackedFileState> m_trackedFiles = {};
|
std::vector<TrackedFileState> m_trackedFiles = {};
|
||||||
std::chrono::steady_clock::time_point m_startTime = {};
|
std::chrono::steady_clock::time_point m_startTime = {};
|
||||||
std::chrono::steady_clock::time_point m_lastFrameTime = {};
|
std::chrono::steady_clock::time_point m_lastFrameTime = {};
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
#include "EditorShellAsset.h"
|
#include "EditorShellAsset.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
Widgets::UIEditorStatusBarSegment BuildDefaultShellModeSegment() {
|
||||||
|
Widgets::UIEditorStatusBarSegment segment = {};
|
||||||
|
segment.segmentId = "mode";
|
||||||
|
segment.label = "Editor Shell";
|
||||||
|
segment.slot = Widgets::UIEditorStatusBarSlot::Leading;
|
||||||
|
segment.tone = Widgets::UIEditorStatusBarTextTone::Primary;
|
||||||
|
segment.interactive = false;
|
||||||
|
segment.showSeparator = true;
|
||||||
|
segment.desiredWidth = 112.0f;
|
||||||
|
return segment;
|
||||||
|
}
|
||||||
|
|
||||||
EditorShellAssetValidationResult MakeValidationError(
|
EditorShellAssetValidationResult MakeValidationError(
|
||||||
EditorShellAssetValidationCode code,
|
EditorShellAssetValidationCode code,
|
||||||
std::string message) {
|
std::string message) {
|
||||||
@@ -53,6 +66,74 @@ EditorShellAssetValidationResult ValidateWorkspacePanelsAgainstRegistry(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorShellAssetValidationResult ValidateShellDefinitionAgainstRegistry(
|
||||||
|
const UIEditorShellInteractionDefinition& definition,
|
||||||
|
const UIEditorPanelRegistry& panelRegistry) {
|
||||||
|
std::unordered_set<std::string> panelIds = {};
|
||||||
|
for (const UIEditorWorkspacePanelPresentationModel& presentation :
|
||||||
|
definition.workspacePresentations) {
|
||||||
|
if (!panelIds.insert(presentation.panelId).second) {
|
||||||
|
return MakeValidationError(
|
||||||
|
EditorShellAssetValidationCode::DuplicateShellPresentationPanelId,
|
||||||
|
"Shell definition presentation panel '" + presentation.panelId +
|
||||||
|
"' is duplicated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIEditorPanelDescriptor* descriptor =
|
||||||
|
FindUIEditorPanelDescriptor(panelRegistry, presentation.panelId);
|
||||||
|
if (descriptor == nullptr) {
|
||||||
|
return MakeValidationError(
|
||||||
|
EditorShellAssetValidationCode::MissingShellPresentationPanelDescriptor,
|
||||||
|
"Shell definition presentation panel '" + presentation.panelId +
|
||||||
|
"' is missing from the panel registry.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presentation.kind != descriptor->presentationKind) {
|
||||||
|
return MakeValidationError(
|
||||||
|
EditorShellAssetValidationCode::ShellPresentationKindMismatch,
|
||||||
|
"Shell definition presentation panel '" + presentation.panelId +
|
||||||
|
"' kind does not match the panel registry.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const UIEditorPanelDescriptor& descriptor : panelRegistry.panels) {
|
||||||
|
if (panelIds.find(descriptor.panelId) == panelIds.end()) {
|
||||||
|
return MakeValidationError(
|
||||||
|
EditorShellAssetValidationCode::MissingRequiredShellPresentation,
|
||||||
|
"Shell definition is missing presentation panel '" + descriptor.panelId +
|
||||||
|
"' required by the panel registry.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
UIEditorWorkspacePanelPresentationModel BuildShellPresentation(
|
||||||
|
const UIEditorPanelDescriptor& descriptor) {
|
||||||
|
UIEditorWorkspacePanelPresentationModel presentation = {};
|
||||||
|
presentation.panelId = descriptor.panelId;
|
||||||
|
presentation.kind = descriptor.presentationKind;
|
||||||
|
if (descriptor.presentationKind == UIEditorPanelPresentationKind::ViewportShell) {
|
||||||
|
presentation.viewportShellModel.spec.chrome.title = descriptor.defaultTitle;
|
||||||
|
presentation.viewportShellModel.spec.chrome.subtitle = "Editor Shell";
|
||||||
|
presentation.viewportShellModel.spec.chrome.showTopBar = true;
|
||||||
|
presentation.viewportShellModel.spec.chrome.showBottomBar = true;
|
||||||
|
presentation.viewportShellModel.frame.statusText = descriptor.defaultTitle;
|
||||||
|
}
|
||||||
|
return presentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIEditorShellInteractionDefinition BuildDefaultShellDefinition(
|
||||||
|
const UIEditorPanelRegistry& panelRegistry) {
|
||||||
|
UIEditorShellInteractionDefinition definition = {};
|
||||||
|
definition.statusSegments = { BuildDefaultShellModeSegment() };
|
||||||
|
definition.workspacePresentations.reserve(panelRegistry.panels.size());
|
||||||
|
for (const UIEditorPanelDescriptor& descriptor : panelRegistry.panels) {
|
||||||
|
definition.workspacePresentations.push_back(BuildShellPresentation(descriptor));
|
||||||
|
}
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EditorShellAsset BuildDefaultEditorShellAsset(const std::filesystem::path& repoRoot) {
|
EditorShellAsset BuildDefaultEditorShellAsset(const std::filesystem::path& repoRoot) {
|
||||||
@@ -63,6 +144,7 @@ EditorShellAsset BuildDefaultEditorShellAsset(const std::filesystem::path& repoR
|
|||||||
asset.panelRegistry = BuildDefaultEditorShellPanelRegistry();
|
asset.panelRegistry = BuildDefaultEditorShellPanelRegistry();
|
||||||
asset.workspace = BuildDefaultEditorShellWorkspaceModel();
|
asset.workspace = BuildDefaultEditorShellWorkspaceModel();
|
||||||
asset.workspaceSession = BuildDefaultUIEditorWorkspaceSession(asset.panelRegistry, asset.workspace);
|
asset.workspaceSession = BuildDefaultUIEditorWorkspaceSession(asset.panelRegistry, asset.workspace);
|
||||||
|
asset.shellDefinition = BuildDefaultShellDefinition(asset.panelRegistry);
|
||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +182,12 @@ EditorShellAssetValidationResult ValidateEditorShellAsset(const EditorShellAsset
|
|||||||
workspaceSessionValidation.message);
|
workspaceSessionValidation.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EditorShellAssetValidationResult shellDefinitionValidation =
|
||||||
|
ValidateShellDefinitionAgainstRegistry(asset.shellDefinition, asset.panelRegistry);
|
||||||
|
if (!shellDefinitionValidation.IsValid()) {
|
||||||
|
return shellDefinitionValidation;
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
||||||
@@ -18,6 +19,7 @@ struct EditorShellAsset {
|
|||||||
UIEditorPanelRegistry panelRegistry = {};
|
UIEditorPanelRegistry panelRegistry = {};
|
||||||
UIEditorWorkspaceModel workspace = {};
|
UIEditorWorkspaceModel workspace = {};
|
||||||
UIEditorWorkspaceSession workspaceSession = {};
|
UIEditorWorkspaceSession workspaceSession = {};
|
||||||
|
UIEditorShellInteractionDefinition shellDefinition = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EditorShellAssetValidationCode : std::uint8_t {
|
enum class EditorShellAssetValidationCode : std::uint8_t {
|
||||||
@@ -27,7 +29,11 @@ enum class EditorShellAssetValidationCode : std::uint8_t {
|
|||||||
InvalidWorkspaceSession,
|
InvalidWorkspaceSession,
|
||||||
MissingPanelDescriptor,
|
MissingPanelDescriptor,
|
||||||
PanelTitleMismatch,
|
PanelTitleMismatch,
|
||||||
PanelPlaceholderMismatch
|
PanelPlaceholderMismatch,
|
||||||
|
DuplicateShellPresentationPanelId,
|
||||||
|
MissingShellPresentationPanelDescriptor,
|
||||||
|
MissingRequiredShellPresentation,
|
||||||
|
ShellPresentationKindMismatch
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EditorShellAssetValidationResult {
|
struct EditorShellAssetValidationResult {
|
||||||
|
|||||||
@@ -16,6 +16,17 @@ TEST(EditorShellAssetValidationTest, DefaultShellAssetPassesValidation) {
|
|||||||
|
|
||||||
const auto validation = ValidateEditorShellAsset(shellAsset);
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
EXPECT_TRUE(validation.IsValid()) << validation.message;
|
EXPECT_TRUE(validation.IsValid()) << validation.message;
|
||||||
|
ASSERT_EQ(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.size(),
|
||||||
|
shellAsset.panelRegistry.panels.size());
|
||||||
|
ASSERT_EQ(shellAsset.shellDefinition.statusSegments.size(), 1u);
|
||||||
|
EXPECT_EQ(shellAsset.shellDefinition.statusSegments.front().label, "Editor Shell");
|
||||||
|
EXPECT_EQ(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.front().panelId,
|
||||||
|
"editor-foundation-root");
|
||||||
|
EXPECT_EQ(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.front().kind,
|
||||||
|
shellAsset.panelRegistry.panels.front().presentationKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EditorShellAssetValidationTest, ValidationRejectsWorkspacePanelMissingFromRegistry) {
|
TEST(EditorShellAssetValidationTest, ValidationRejectsWorkspacePanelMissingFromRegistry) {
|
||||||
@@ -50,4 +61,56 @@ TEST(EditorShellAssetValidationTest, ValidationRejectsInvalidWorkspaceSessionSta
|
|||||||
EXPECT_EQ(validation.code, EditorShellAssetValidationCode::InvalidWorkspaceSession);
|
EXPECT_EQ(validation.code, EditorShellAssetValidationCode::InvalidWorkspaceSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(EditorShellAssetValidationTest, ValidationRejectsShellPresentationMissingFromRegistry) {
|
||||||
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
|
ASSERT_EQ(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.size(),
|
||||||
|
shellAsset.panelRegistry.panels.size());
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.front().panelId =
|
||||||
|
"editor-foundation-root-renamed";
|
||||||
|
|
||||||
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
|
EXPECT_EQ(
|
||||||
|
validation.code,
|
||||||
|
EditorShellAssetValidationCode::MissingShellPresentationPanelDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EditorShellAssetValidationTest, ValidationRejectsDuplicateShellPresentationPanelId) {
|
||||||
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
|
ASSERT_EQ(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.size(),
|
||||||
|
shellAsset.panelRegistry.panels.size());
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.push_back(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.front());
|
||||||
|
|
||||||
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
|
EXPECT_EQ(
|
||||||
|
validation.code,
|
||||||
|
EditorShellAssetValidationCode::DuplicateShellPresentationPanelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EditorShellAssetValidationTest, ValidationRejectsMissingRequiredShellPresentation) {
|
||||||
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.clear();
|
||||||
|
|
||||||
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
|
EXPECT_EQ(
|
||||||
|
validation.code,
|
||||||
|
EditorShellAssetValidationCode::MissingRequiredShellPresentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EditorShellAssetValidationTest, ValidationRejectsShellPresentationKindMismatch) {
|
||||||
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
|
ASSERT_EQ(
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.size(),
|
||||||
|
shellAsset.panelRegistry.panels.size());
|
||||||
|
shellAsset.shellDefinition.workspacePresentations.front().kind =
|
||||||
|
XCEngine::UI::Editor::UIEditorPanelPresentationKind::ViewportShell;
|
||||||
|
|
||||||
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
|
EXPECT_EQ(
|
||||||
|
validation.code,
|
||||||
|
EditorShellAssetValidationCode::ShellPresentationKindMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "Core/EditorShellAsset.h"
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
||||||
|
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
||||||
|
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
||||||
#include <XCEngine/UI/Runtime/UIScreenDocumentHost.h>
|
#include <XCEngine/UI/Runtime/UIScreenDocumentHost.h>
|
||||||
#include <XCEngine/UI/Runtime/UIScreenPlayer.h>
|
#include <XCEngine/UI/Runtime/UIScreenPlayer.h>
|
||||||
|
|
||||||
@@ -16,6 +19,11 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
||||||
|
using XCEngine::UI::Editor::BuildStructuredEditorShellBinding;
|
||||||
|
using XCEngine::UI::Editor::BuildStructuredEditorShellServices;
|
||||||
|
using XCEngine::UI::Editor::ResolveUIEditorShellInteractionModel;
|
||||||
|
using XCEngine::UI::Editor::AreUIEditorWorkspaceModelsEquivalent;
|
||||||
|
using XCEngine::UI::Editor::AreUIEditorWorkspaceSessionsEquivalent;
|
||||||
using XCEngine::UI::UIDrawCommand;
|
using XCEngine::UI::UIDrawCommand;
|
||||||
using XCEngine::UI::UIDrawCommandType;
|
using XCEngine::UI::UIDrawCommandType;
|
||||||
using XCEngine::UI::UIDrawData;
|
using XCEngine::UI::UIDrawData;
|
||||||
@@ -56,23 +64,93 @@ bool ContainsPathWithFilename(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PanelRegistriesMatch(
|
||||||
|
const XCEngine::UI::Editor::UIEditorPanelRegistry& lhs,
|
||||||
|
const XCEngine::UI::Editor::UIEditorPanelRegistry& rhs) {
|
||||||
|
if (lhs.panels.size() != rhs.panels.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < lhs.panels.size(); ++index) {
|
||||||
|
const auto& left = lhs.panels[index];
|
||||||
|
const auto& right = rhs.panels[index];
|
||||||
|
if (left.panelId != right.panelId ||
|
||||||
|
left.defaultTitle != right.defaultTitle ||
|
||||||
|
left.presentationKind != right.presentationKind ||
|
||||||
|
left.placeholder != right.placeholder ||
|
||||||
|
left.canHide != right.canHide ||
|
||||||
|
left.canClose != right.canClose) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShellDefinitionsMatch(
|
||||||
|
const XCEngine::UI::Editor::UIEditorShellInteractionDefinition& lhs,
|
||||||
|
const XCEngine::UI::Editor::UIEditorShellInteractionDefinition& rhs) {
|
||||||
|
if (lhs.menuModel.menus.size() != rhs.menuModel.menus.size() ||
|
||||||
|
lhs.statusSegments.size() != rhs.statusSegments.size() ||
|
||||||
|
lhs.workspacePresentations.size() != rhs.workspacePresentations.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < lhs.menuModel.menus.size(); ++index) {
|
||||||
|
const auto& left = lhs.menuModel.menus[index];
|
||||||
|
const auto& right = rhs.menuModel.menus[index];
|
||||||
|
if (left.menuId != right.menuId ||
|
||||||
|
left.label != right.label ||
|
||||||
|
left.items.size() != right.items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < lhs.statusSegments.size(); ++index) {
|
||||||
|
const auto& left = lhs.statusSegments[index];
|
||||||
|
const auto& right = rhs.statusSegments[index];
|
||||||
|
if (left.segmentId != right.segmentId ||
|
||||||
|
left.label != right.label ||
|
||||||
|
left.slot != right.slot ||
|
||||||
|
left.tone != right.tone ||
|
||||||
|
left.interactive != right.interactive ||
|
||||||
|
left.showSeparator != right.showSeparator ||
|
||||||
|
left.desiredWidth != right.desiredWidth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < lhs.workspacePresentations.size(); ++index) {
|
||||||
|
const auto& left = lhs.workspacePresentations[index];
|
||||||
|
const auto& right = rhs.workspacePresentations[index];
|
||||||
|
if (left.panelId != right.panelId ||
|
||||||
|
left.kind != right.kind ||
|
||||||
|
left.viewportShellModel.spec.chrome.title != right.viewportShellModel.spec.chrome.title ||
|
||||||
|
left.viewportShellModel.spec.chrome.subtitle != right.viewportShellModel.spec.chrome.subtitle ||
|
||||||
|
left.viewportShellModel.spec.chrome.showTopBar != right.viewportShellModel.spec.chrome.showTopBar ||
|
||||||
|
left.viewportShellModel.spec.chrome.showBottomBar != right.viewportShellModel.spec.chrome.showBottomBar ||
|
||||||
|
left.viewportShellModel.frame.statusText != right.viewportShellModel.frame.statusText) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST(EditorUIStructuredShellTest, AuthoredEditorShellLoadsFromRepositoryResources) {
|
TEST(EditorUIStructuredShellTest, AuthoredEditorShellLoadsFromRepositoryResources) {
|
||||||
const auto shell = BuildDefaultEditorShellAsset(RepoRootPath());
|
const auto shell = BuildDefaultEditorShellAsset(RepoRootPath());
|
||||||
|
const auto binding = BuildStructuredEditorShellBinding(shell);
|
||||||
|
|
||||||
ASSERT_TRUE(std::filesystem::exists(shell.documentPath));
|
ASSERT_TRUE(binding.IsValid()) << binding.assetValidation.message;
|
||||||
ASSERT_TRUE(std::filesystem::exists(shell.themePath));
|
ASSERT_TRUE(std::filesystem::exists(std::filesystem::path(binding.screenAsset.documentPath)));
|
||||||
|
ASSERT_TRUE(std::filesystem::exists(std::filesystem::path(binding.screenAsset.themePath)));
|
||||||
UIScreenAsset asset = {};
|
|
||||||
asset.screenId = shell.screenId;
|
|
||||||
asset.documentPath = shell.documentPath.string();
|
|
||||||
asset.themePath = shell.themePath.string();
|
|
||||||
|
|
||||||
UIDocumentScreenHost host = {};
|
UIDocumentScreenHost host = {};
|
||||||
UIScreenPlayer player(host);
|
UIScreenPlayer player(host);
|
||||||
|
|
||||||
ASSERT_TRUE(player.Load(asset)) << player.GetLastError();
|
ASSERT_TRUE(player.Load(binding.screenAsset)) << player.GetLastError();
|
||||||
ASSERT_NE(player.GetDocument(), nullptr);
|
ASSERT_NE(player.GetDocument(), nullptr);
|
||||||
EXPECT_TRUE(player.GetDocument()->hasThemeDocument);
|
EXPECT_TRUE(player.GetDocument()->hasThemeDocument);
|
||||||
EXPECT_TRUE(ContainsPathWithFilename(player.GetDocument()->dependencies, "editor_shell.xctheme"));
|
EXPECT_TRUE(ContainsPathWithFilename(player.GetDocument()->dependencies, "editor_shell.xctheme"));
|
||||||
@@ -91,3 +169,49 @@ TEST(EditorUIStructuredShellTest, AuthoredEditorShellLoadsFromRepositoryResource
|
|||||||
EXPECT_FALSE(DrawDataContainsText(frame.drawData, "Right Pane Host"));
|
EXPECT_FALSE(DrawDataContainsText(frame.drawData, "Right Pane Host"));
|
||||||
EXPECT_FALSE(DrawDataContainsText(frame.drawData, "Bottom Pane Host"));
|
EXPECT_FALSE(DrawDataContainsText(frame.drawData, "Bottom Pane Host"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(EditorUIStructuredShellTest, StructuredShellBindingUsesEditorShellAssetAsSingleSource) {
|
||||||
|
auto shell = BuildDefaultEditorShellAsset(RepoRootPath());
|
||||||
|
shell.shellDefinition.statusSegments.front().label = "Asset Contract";
|
||||||
|
XCEngine::UI::Editor::UIEditorMenuDescriptor assetMenu = {};
|
||||||
|
assetMenu.menuId = "asset";
|
||||||
|
assetMenu.label = "Asset";
|
||||||
|
shell.shellDefinition.menuModel.menus = { assetMenu };
|
||||||
|
const auto binding = BuildStructuredEditorShellBinding(shell);
|
||||||
|
|
||||||
|
ASSERT_TRUE(binding.IsValid()) << binding.assetValidation.message;
|
||||||
|
EXPECT_EQ(binding.screenAsset.screenId, shell.screenId);
|
||||||
|
EXPECT_EQ(std::filesystem::path(binding.screenAsset.documentPath), shell.documentPath);
|
||||||
|
EXPECT_EQ(std::filesystem::path(binding.screenAsset.themePath), shell.themePath);
|
||||||
|
|
||||||
|
EXPECT_TRUE(PanelRegistriesMatch(binding.workspaceController.GetPanelRegistry(), shell.panelRegistry));
|
||||||
|
EXPECT_TRUE(AreUIEditorWorkspaceModelsEquivalent(binding.workspaceController.GetWorkspace(), shell.workspace));
|
||||||
|
EXPECT_TRUE(AreUIEditorWorkspaceSessionsEquivalent(binding.workspaceController.GetSession(), shell.workspaceSession));
|
||||||
|
EXPECT_TRUE(ShellDefinitionsMatch(binding.shellDefinition, shell.shellDefinition));
|
||||||
|
EXPECT_TRUE(binding.workspaceController.ValidateState().IsValid());
|
||||||
|
EXPECT_TRUE(binding.shortcutManager.ValidateConfiguration().IsValid());
|
||||||
|
|
||||||
|
const auto services = BuildStructuredEditorShellServices(binding);
|
||||||
|
ASSERT_NE(services.commandDispatcher, nullptr);
|
||||||
|
EXPECT_EQ(services.shortcutManager, &binding.shortcutManager);
|
||||||
|
|
||||||
|
const auto model = ResolveUIEditorShellInteractionModel(
|
||||||
|
binding.workspaceController,
|
||||||
|
binding.shellDefinition,
|
||||||
|
services);
|
||||||
|
|
||||||
|
ASSERT_EQ(model.resolvedMenuModel.menus.size(), 1u);
|
||||||
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().menuId, "asset");
|
||||||
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().label, "Asset");
|
||||||
|
ASSERT_EQ(model.statusSegments.size(), shell.shellDefinition.statusSegments.size());
|
||||||
|
EXPECT_EQ(model.statusSegments.front().label, shell.shellDefinition.statusSegments.front().label);
|
||||||
|
ASSERT_EQ(
|
||||||
|
model.workspacePresentations.size(),
|
||||||
|
shell.shellDefinition.workspacePresentations.size());
|
||||||
|
EXPECT_EQ(
|
||||||
|
model.workspacePresentations.front().panelId,
|
||||||
|
shell.shellDefinition.workspacePresentations.front().panelId);
|
||||||
|
EXPECT_EQ(
|
||||||
|
model.workspacePresentations.front().kind,
|
||||||
|
shell.shellDefinition.workspacePresentations.front().kind);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user