Unify editor shell asset contracts
This commit is contained in:
@@ -42,8 +42,7 @@ struct StructuredEditorShellBinding {
|
|||||||
|
|
||||||
inline UIEditorShortcutManager BuildStructuredEditorShortcutManager(
|
inline UIEditorShortcutManager BuildStructuredEditorShortcutManager(
|
||||||
const EditorShellAsset& asset) {
|
const EditorShellAsset& asset) {
|
||||||
(void)asset;
|
return BuildEditorShellShortcutManager(asset);
|
||||||
return UIEditorShortcutManager(UIEditorCommandRegistry{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline StructuredEditorShellBinding BuildStructuredEditorShellBinding(
|
inline StructuredEditorShellBinding BuildStructuredEditorShellBinding(
|
||||||
|
|||||||
@@ -148,6 +148,14 @@ EditorShellAsset BuildDefaultEditorShellAsset(const std::filesystem::path& repoR
|
|||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIEditorShortcutManager BuildEditorShellShortcutManager(const EditorShellAsset& asset) {
|
||||||
|
UIEditorShortcutManager manager(asset.shortcutAsset.commandRegistry);
|
||||||
|
for (const XCEngine::UI::UIShortcutBinding& binding : asset.shortcutAsset.bindings) {
|
||||||
|
manager.RegisterBinding(binding);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
EditorShellAssetValidationResult ValidateEditorShellAsset(const EditorShellAsset& asset) {
|
EditorShellAssetValidationResult ValidateEditorShellAsset(const EditorShellAsset& asset) {
|
||||||
const UIEditorPanelRegistryValidationResult registryValidation =
|
const UIEditorPanelRegistryValidationResult registryValidation =
|
||||||
ValidateUIEditorPanelRegistry(asset.panelRegistry);
|
ValidateUIEditorPanelRegistry(asset.panelRegistry);
|
||||||
@@ -188,6 +196,26 @@ EditorShellAssetValidationResult ValidateEditorShellAsset(const EditorShellAsset
|
|||||||
return shellDefinitionValidation;
|
return shellDefinitionValidation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UIEditorMenuModelValidationResult shellMenuValidation =
|
||||||
|
ValidateUIEditorMenuModel(
|
||||||
|
asset.shellDefinition.menuModel,
|
||||||
|
asset.shortcutAsset.commandRegistry);
|
||||||
|
if (!shellMenuValidation.IsValid()) {
|
||||||
|
return MakeValidationError(
|
||||||
|
EditorShellAssetValidationCode::InvalidShellMenuModel,
|
||||||
|
shellMenuValidation.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIEditorShortcutManager shortcutManager =
|
||||||
|
BuildEditorShellShortcutManager(asset);
|
||||||
|
const UIEditorShortcutManagerValidationResult shortcutValidation =
|
||||||
|
shortcutManager.ValidateConfiguration();
|
||||||
|
if (!shortcutValidation.IsValid()) {
|
||||||
|
return MakeValidationError(
|
||||||
|
EditorShellAssetValidationCode::InvalidShortcutConfiguration,
|
||||||
|
shortcutValidation.message);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Core/UIEditorShortcutManager.h>
|
||||||
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
#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>
|
||||||
@@ -8,9 +9,15 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct EditorShellShortcutAsset {
|
||||||
|
UIEditorCommandRegistry commandRegistry = {};
|
||||||
|
std::vector<XCEngine::UI::UIShortcutBinding> bindings = {};
|
||||||
|
};
|
||||||
|
|
||||||
struct EditorShellAsset {
|
struct EditorShellAsset {
|
||||||
std::string screenId = "editor.shell";
|
std::string screenId = "editor.shell";
|
||||||
std::filesystem::path documentPath = {};
|
std::filesystem::path documentPath = {};
|
||||||
@@ -20,6 +27,7 @@ struct EditorShellAsset {
|
|||||||
UIEditorWorkspaceModel workspace = {};
|
UIEditorWorkspaceModel workspace = {};
|
||||||
UIEditorWorkspaceSession workspaceSession = {};
|
UIEditorWorkspaceSession workspaceSession = {};
|
||||||
UIEditorShellInteractionDefinition shellDefinition = {};
|
UIEditorShellInteractionDefinition shellDefinition = {};
|
||||||
|
EditorShellShortcutAsset shortcutAsset = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EditorShellAssetValidationCode : std::uint8_t {
|
enum class EditorShellAssetValidationCode : std::uint8_t {
|
||||||
@@ -27,6 +35,8 @@ enum class EditorShellAssetValidationCode : std::uint8_t {
|
|||||||
InvalidPanelRegistry,
|
InvalidPanelRegistry,
|
||||||
InvalidWorkspace,
|
InvalidWorkspace,
|
||||||
InvalidWorkspaceSession,
|
InvalidWorkspaceSession,
|
||||||
|
InvalidShellMenuModel,
|
||||||
|
InvalidShortcutConfiguration,
|
||||||
MissingPanelDescriptor,
|
MissingPanelDescriptor,
|
||||||
PanelTitleMismatch,
|
PanelTitleMismatch,
|
||||||
PanelPlaceholderMismatch,
|
PanelPlaceholderMismatch,
|
||||||
@@ -46,6 +56,7 @@ struct EditorShellAssetValidationResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
EditorShellAsset BuildDefaultEditorShellAsset(const std::filesystem::path& repoRoot);
|
EditorShellAsset BuildDefaultEditorShellAsset(const std::filesystem::path& repoRoot);
|
||||||
|
UIEditorShortcutManager BuildEditorShellShortcutManager(const EditorShellAsset& asset);
|
||||||
EditorShellAssetValidationResult ValidateEditorShellAsset(const EditorShellAsset& asset);
|
EditorShellAssetValidationResult ValidateEditorShellAsset(const EditorShellAsset& asset);
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor
|
} // namespace XCEngine::UI::Editor
|
||||||
|
|||||||
@@ -4,12 +4,31 @@
|
|||||||
|
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
||||||
|
|
||||||
|
#include <XCEngine/Input/InputTypes.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using XCEngine::Input::KeyCode;
|
||||||
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
||||||
using XCEngine::UI::Editor::EditorShellAssetValidationCode;
|
using XCEngine::UI::Editor::EditorShellAssetValidationCode;
|
||||||
using XCEngine::UI::Editor::FindUIEditorPanelDescriptor;
|
using XCEngine::UI::Editor::FindUIEditorPanelDescriptor;
|
||||||
|
using XCEngine::UI::Editor::UIEditorCommandPanelSource;
|
||||||
|
using XCEngine::UI::Editor::UIEditorMenuItemKind;
|
||||||
|
using XCEngine::UI::Editor::UIEditorWorkspaceCommandKind;
|
||||||
using XCEngine::UI::Editor::ValidateEditorShellAsset;
|
using XCEngine::UI::Editor::ValidateEditorShellAsset;
|
||||||
|
using XCEngine::UI::UIInputEventType;
|
||||||
|
using XCEngine::UI::UIShortcutBinding;
|
||||||
|
using XCEngine::UI::UIShortcutScope;
|
||||||
|
|
||||||
|
UIShortcutBinding MakeBinding(std::string commandId, KeyCode keyCode) {
|
||||||
|
UIShortcutBinding binding = {};
|
||||||
|
binding.commandId = std::move(commandId);
|
||||||
|
binding.scope = UIShortcutScope::Global;
|
||||||
|
binding.triggerEventType = UIInputEventType::KeyDown;
|
||||||
|
binding.chord.keyCode = static_cast<std::int32_t>(keyCode);
|
||||||
|
binding.chord.modifiers.control = true;
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
TEST(EditorShellAssetValidationTest, DefaultShellAssetPassesValidation) {
|
TEST(EditorShellAssetValidationTest, DefaultShellAssetPassesValidation) {
|
||||||
const auto shellAsset = BuildDefaultEditorShellAsset(".");
|
const auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
@@ -99,6 +118,50 @@ TEST(EditorShellAssetValidationTest, ValidationRejectsMissingRequiredShellPresen
|
|||||||
EditorShellAssetValidationCode::MissingRequiredShellPresentation);
|
EditorShellAssetValidationCode::MissingRequiredShellPresentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(EditorShellAssetValidationTest, ValidationRejectsInvalidShellMenuModel) {
|
||||||
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
|
shellAsset.shellDefinition.menuModel.menus = {
|
||||||
|
{
|
||||||
|
"window",
|
||||||
|
"Window",
|
||||||
|
{
|
||||||
|
{
|
||||||
|
UIEditorMenuItemKind::Command,
|
||||||
|
"reset-layout",
|
||||||
|
{},
|
||||||
|
"workspace.reset_layout",
|
||||||
|
{},
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
|
EXPECT_EQ(
|
||||||
|
validation.code,
|
||||||
|
EditorShellAssetValidationCode::InvalidShellMenuModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EditorShellAssetValidationTest, ValidationRejectsInvalidShortcutConfiguration) {
|
||||||
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
|
shellAsset.shortcutAsset.commandRegistry.commands = {
|
||||||
|
{
|
||||||
|
"workspace.reset_layout",
|
||||||
|
"Reset Layout",
|
||||||
|
{ UIEditorWorkspaceCommandKind::ResetWorkspace, UIEditorCommandPanelSource::None, {} }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
shellAsset.shortcutAsset.bindings = {
|
||||||
|
MakeBinding("missing.command", KeyCode::R)
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto validation = ValidateEditorShellAsset(shellAsset);
|
||||||
|
EXPECT_EQ(
|
||||||
|
validation.code,
|
||||||
|
EditorShellAssetValidationCode::InvalidShortcutConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(EditorShellAssetValidationTest, ValidationRejectsShellPresentationKindMismatch) {
|
TEST(EditorShellAssetValidationTest, ValidationRejectsShellPresentationKindMismatch) {
|
||||||
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
auto shellAsset = BuildDefaultEditorShellAsset(".");
|
||||||
ASSERT_EQ(
|
ASSERT_EQ(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
||||||
|
#include <XCEngine/Input/InputTypes.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>
|
||||||
|
|
||||||
@@ -18,15 +19,22 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using XCEngine::Input::KeyCode;
|
||||||
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
||||||
using XCEngine::UI::Editor::BuildStructuredEditorShellBinding;
|
using XCEngine::UI::Editor::BuildStructuredEditorShellBinding;
|
||||||
using XCEngine::UI::Editor::BuildStructuredEditorShellServices;
|
using XCEngine::UI::Editor::BuildStructuredEditorShellServices;
|
||||||
using XCEngine::UI::Editor::ResolveUIEditorShellInteractionModel;
|
using XCEngine::UI::Editor::ResolveUIEditorShellInteractionModel;
|
||||||
using XCEngine::UI::Editor::AreUIEditorWorkspaceModelsEquivalent;
|
using XCEngine::UI::Editor::AreUIEditorWorkspaceModelsEquivalent;
|
||||||
using XCEngine::UI::Editor::AreUIEditorWorkspaceSessionsEquivalent;
|
using XCEngine::UI::Editor::AreUIEditorWorkspaceSessionsEquivalent;
|
||||||
|
using XCEngine::UI::Editor::UIEditorCommandPanelSource;
|
||||||
|
using XCEngine::UI::Editor::UIEditorMenuItemKind;
|
||||||
|
using XCEngine::UI::Editor::UIEditorWorkspaceCommandKind;
|
||||||
using XCEngine::UI::UIDrawCommand;
|
using XCEngine::UI::UIDrawCommand;
|
||||||
using XCEngine::UI::UIDrawCommandType;
|
using XCEngine::UI::UIDrawCommandType;
|
||||||
using XCEngine::UI::UIDrawData;
|
using XCEngine::UI::UIDrawData;
|
||||||
|
using XCEngine::UI::UIInputEventType;
|
||||||
|
using XCEngine::UI::UIShortcutBinding;
|
||||||
|
using XCEngine::UI::UIShortcutScope;
|
||||||
using XCEngine::UI::Runtime::UIScreenAsset;
|
using XCEngine::UI::Runtime::UIScreenAsset;
|
||||||
using XCEngine::UI::Runtime::UIScreenFrameInput;
|
using XCEngine::UI::Runtime::UIScreenFrameInput;
|
||||||
using XCEngine::UI::Runtime::UIScreenPlayer;
|
using XCEngine::UI::Runtime::UIScreenPlayer;
|
||||||
@@ -137,6 +145,16 @@ bool ShellDefinitionsMatch(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIShortcutBinding MakeBinding(std::string commandId, KeyCode keyCode) {
|
||||||
|
UIShortcutBinding binding = {};
|
||||||
|
binding.commandId = std::move(commandId);
|
||||||
|
binding.scope = UIShortcutScope::Global;
|
||||||
|
binding.triggerEventType = UIInputEventType::KeyDown;
|
||||||
|
binding.chord.keyCode = static_cast<std::int32_t>(keyCode);
|
||||||
|
binding.chord.modifiers.control = true;
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST(EditorUIStructuredShellTest, AuthoredEditorShellLoadsFromRepositoryResources) {
|
TEST(EditorUIStructuredShellTest, AuthoredEditorShellLoadsFromRepositoryResources) {
|
||||||
@@ -173,9 +191,24 @@ TEST(EditorUIStructuredShellTest, AuthoredEditorShellLoadsFromRepositoryResource
|
|||||||
TEST(EditorUIStructuredShellTest, StructuredShellBindingUsesEditorShellAssetAsSingleSource) {
|
TEST(EditorUIStructuredShellTest, StructuredShellBindingUsesEditorShellAssetAsSingleSource) {
|
||||||
auto shell = BuildDefaultEditorShellAsset(RepoRootPath());
|
auto shell = BuildDefaultEditorShellAsset(RepoRootPath());
|
||||||
shell.shellDefinition.statusSegments.front().label = "Asset Contract";
|
shell.shellDefinition.statusSegments.front().label = "Asset Contract";
|
||||||
|
shell.shortcutAsset.commandRegistry.commands = {
|
||||||
|
{
|
||||||
|
"workspace.reset_layout",
|
||||||
|
"Reset Layout",
|
||||||
|
{ UIEditorWorkspaceCommandKind::ResetWorkspace, UIEditorCommandPanelSource::None, {} }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
shell.shortcutAsset.bindings = {
|
||||||
|
MakeBinding("workspace.reset_layout", KeyCode::R)
|
||||||
|
};
|
||||||
|
XCEngine::UI::Editor::UIEditorMenuItemDescriptor assetCommand = {};
|
||||||
|
assetCommand.kind = UIEditorMenuItemKind::Command;
|
||||||
|
assetCommand.itemId = "asset-reset-layout";
|
||||||
|
assetCommand.commandId = "workspace.reset_layout";
|
||||||
XCEngine::UI::Editor::UIEditorMenuDescriptor assetMenu = {};
|
XCEngine::UI::Editor::UIEditorMenuDescriptor assetMenu = {};
|
||||||
assetMenu.menuId = "asset";
|
assetMenu.menuId = "asset";
|
||||||
assetMenu.label = "Asset";
|
assetMenu.label = "Asset";
|
||||||
|
assetMenu.items = { assetCommand };
|
||||||
shell.shellDefinition.menuModel.menus = { assetMenu };
|
shell.shellDefinition.menuModel.menus = { assetMenu };
|
||||||
const auto binding = BuildStructuredEditorShellBinding(shell);
|
const auto binding = BuildStructuredEditorShellBinding(shell);
|
||||||
|
|
||||||
@@ -203,6 +236,10 @@ TEST(EditorUIStructuredShellTest, StructuredShellBindingUsesEditorShellAssetAsSi
|
|||||||
ASSERT_EQ(model.resolvedMenuModel.menus.size(), 1u);
|
ASSERT_EQ(model.resolvedMenuModel.menus.size(), 1u);
|
||||||
EXPECT_EQ(model.resolvedMenuModel.menus.front().menuId, "asset");
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().menuId, "asset");
|
||||||
EXPECT_EQ(model.resolvedMenuModel.menus.front().label, "Asset");
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().label, "Asset");
|
||||||
|
ASSERT_EQ(model.resolvedMenuModel.menus.front().items.size(), 1u);
|
||||||
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().items.front().commandId, "workspace.reset_layout");
|
||||||
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().items.front().label, "Reset Layout");
|
||||||
|
EXPECT_EQ(model.resolvedMenuModel.menus.front().items.front().shortcutText, "Ctrl+R");
|
||||||
ASSERT_EQ(model.statusSegments.size(), shell.shellDefinition.statusSegments.size());
|
ASSERT_EQ(model.statusSegments.size(), shell.shellDefinition.statusSegments.size());
|
||||||
EXPECT_EQ(model.statusSegments.front().label, shell.shellDefinition.statusSegments.front().label);
|
EXPECT_EQ(model.statusSegments.front().label, shell.shellDefinition.statusSegments.front().label);
|
||||||
ASSERT_EQ(
|
ASSERT_EQ(
|
||||||
|
|||||||
Reference in New Issue
Block a user