Refactor editor product runtime state architecture

This commit is contained in:
2026-05-01 00:31:42 +08:00
parent af0b84e7d4
commit a4da05008f
45 changed files with 2218 additions and 1397 deletions

View File

@@ -67,7 +67,6 @@ set(EDITOR_UI_UNIT_TEST_SOURCES
set(EDITOR_APP_CORE_TEST_SOURCES
test_editor_host_command_bridge.cpp
test_editor_project_runtime.cpp
test_editor_runtime_coordinator.cpp
test_editor_scene_runtime_backend.cpp
test_editor_shell_asset_validation.cpp
test_editor_window_frame_orchestrator.cpp
@@ -132,6 +131,7 @@ if(TARGET XCEditorCore)
target_include_directories(editor_app_core_tests
PRIVATE
${CMAKE_SOURCE_DIR}/editor/src
${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/app/Composition
${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/app/Core
${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/app/Features
@@ -179,6 +179,7 @@ if(TARGET XCEditorCore)
target_include_directories(editor_app_feature_tests
PRIVATE
${CMAKE_SOURCE_DIR}/editor/src
${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/app/Composition
${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/app/Core
${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/app/Features
@@ -249,3 +250,74 @@ endif()
gtest_discover_tests(editor_windowing_phase1_tests
DISCOVERY_MODE POST_BUILD
)
add_executable(editor_runtime_state_tests
test_editor_runtime_command_service.cpp
test_editor_store.cpp
)
target_link_libraries(editor_runtime_state_tests
PRIVATE
XCEditorCore
GTest::gtest_main
)
target_include_directories(editor_runtime_state_tests
PRIVATE
${CMAKE_SOURCE_DIR}/editor/src
${CMAKE_SOURCE_DIR}/engine/include
)
if(MSVC)
target_compile_options(editor_runtime_state_tests PRIVATE /utf-8 /FS)
set_target_properties(editor_runtime_state_tests PROPERTIES
MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>"
COMPILE_PDB_NAME "editor_runtime_state_tests-compile"
COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb"
COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Debug"
COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Release"
COMPILE_PDB_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/MinSizeRel"
COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/RelWithDebInfo"
)
set_property(TARGET editor_runtime_state_tests PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()
gtest_discover_tests(editor_runtime_state_tests
DISCOVERY_MODE POST_BUILD
)
add_executable(editor_product_registry_tests
test_editor_product_registry.cpp
)
target_link_libraries(editor_product_registry_tests
PRIVATE
XCEditorCore
GTest::gtest_main
)
target_include_directories(editor_product_registry_tests
PRIVATE
${CMAKE_SOURCE_DIR}/editor/src
${CMAKE_SOURCE_DIR}/engine/include
)
if(MSVC)
target_compile_options(editor_product_registry_tests PRIVATE /utf-8 /FS)
set_target_properties(editor_product_registry_tests PROPERTIES
MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>"
COMPILE_PDB_NAME "editor_product_registry_tests-compile"
COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb"
COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Debug"
COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Release"
COMPILE_PDB_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/MinSizeRel"
COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/RelWithDebInfo"
)
set_property(TARGET editor_product_registry_tests PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()
gtest_discover_tests(editor_product_registry_tests
DISCOVERY_MODE POST_BUILD
)

View File

@@ -1,9 +1,10 @@
#include <gtest/gtest.h>
#include "Panels/EditorPanelIds.h"
#include "Commands/EditorEditCommandRoute.h"
#include "Commands/EditorHostCommandBridge.h"
#include "State/EditorCommandFocusService.h"
#include "Product/Commands/EditorHostCommandBridge.h"
#include "Product/Core/Commands/EditorEditCommandRoute.h"
#include "Product/Features/Workspace/Hierarchy/HierarchyWorkspaceFeature.h"
#include "Product/Features/Workspace/Project/ProjectWorkspaceFeature.h"
#include "Product/State/EditorCommandFocusService.h"
#include <XCEditor/Workspace/UIEditorWorkspaceController.h>
#include <utility>
@@ -293,7 +294,8 @@ TEST(EditorHostCommandBridgeTest, InspectorEditCommandsDelegateToBoundInspectorR
TEST(EditorHostCommandBridgeTest, ActivePanelRouteIsUsedAsFallbackWhenNoExplicitCommandFocusExists) {
UIEditorWorkspaceController controller =
MakeWorkspaceController(XCEngine::UI::Editor::App::kHierarchyPanelId);
MakeWorkspaceController(
XCEngine::UI::Editor::App::kHierarchyWorkspaceFeaturePanelId);
StubEditCommandRoute hierarchyRoute = {};
hierarchyRoute.evaluationResult.executable = true;
@@ -310,7 +312,8 @@ TEST(EditorHostCommandBridgeTest, ActivePanelRouteIsUsedAsFallbackWhenNoExplicit
TEST(EditorHostCommandBridgeTest, ExplicitCommandFocusOverridesActivePanelFallback) {
UIEditorWorkspaceController controller =
MakeWorkspaceController(XCEngine::UI::Editor::App::kProjectPanelId);
MakeWorkspaceController(
XCEngine::UI::Editor::App::kProjectWorkspaceFeaturePanelId);
EditorCommandFocusService commandFocus = {};
commandFocus.ClaimFocus(EditorActionRoute::Scene);

View File

@@ -0,0 +1,195 @@
#include <gtest/gtest.h>
#include "Product/Registry/EditorProductRegistry.h"
#include "Product/Runtime/Shell/EditorShellAssetBuilder.h"
#include <XCEditor/Shell/UIEditorShellAsset.h>
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
#include <XCEditor/Workspace/UIEditorWorkspaceModel.h>
#include <XCEditor/Workspace/UIEditorWorkspaceValidation.h>
#include <filesystem>
#include <string_view>
namespace XCEngine::UI::Editor::App {
namespace {
EditorRuntimePaths TestRuntimePaths() {
return EditorRuntimePaths{
.workspaceRoot = ".",
.executableRoot = ".",
.resourceRoot = "editor/resources",
.projectRoot = "project",
.captureRoot = "captures",
};
}
const UIEditorMenuDescriptor* FindMenu(
const UIEditorMenuModel& model,
std::string_view menuId) {
for (const UIEditorMenuDescriptor& menu : model.menus) {
if (menu.menuId == menuId) {
return &menu;
}
}
return nullptr;
}
const UIEditorMenuItemDescriptor* FindMenuItem(
const std::vector<UIEditorMenuItemDescriptor>& items,
std::string_view itemId) {
for (const UIEditorMenuItemDescriptor& item : items) {
if (item.itemId == itemId) {
return &item;
}
}
return nullptr;
}
const UIEditorCommandDescriptor* FindWorkspacePanelCommand(
const UIEditorCommandRegistry& registry,
std::string_view panelId) {
for (const UIEditorCommandDescriptor& command : registry.commands) {
if (command.kind == UIEditorCommandKind::Workspace &&
command.workspaceCommand.panelId == panelId) {
return &command;
}
}
return nullptr;
}
TEST(EditorProductRegistryTests, DefaultWorkspaceMetadataValidates) {
const EditorProductRegistryValidationResult validation =
ValidateEditorProductRegistry();
EXPECT_TRUE(validation.IsValid()) << validation.message;
const UIEditorPanelRegistry panelRegistry = BuildEditorWorkspacePanelRegistry();
ASSERT_EQ(panelRegistry.panels.size(), GetEditorWorkspaceFeatures().size());
const UIEditorWorkspaceModel workspace = BuildDefaultEditorWorkspaceModel();
const UIEditorWorkspaceValidationResult workspaceValidation =
ValidateUIEditorWorkspace(workspace);
EXPECT_TRUE(workspaceValidation.IsValid()) << workspaceValidation.message;
EXPECT_EQ(workspace.activePanelId, "scene");
}
TEST(EditorProductRegistryTests, WorkspaceCommandsAndViewMenuStayInSync) {
UIEditorCommandRegistry commandRegistry = {};
commandRegistry.commands = BuildEditorWorkspaceShellCommands();
const UIEditorCommandRegistryValidationResult commandValidation =
ValidateUIEditorCommandRegistry(commandRegistry);
EXPECT_TRUE(commandValidation.IsValid()) << commandValidation.message;
const UIEditorMenuDescriptor viewMenu = BuildEditorWorkspaceViewMenu();
const UIEditorMenuModel menuModel = { { viewMenu } };
const UIEditorMenuModelValidationResult menuValidation =
ValidateUIEditorMenuModel(menuModel, commandRegistry);
EXPECT_TRUE(menuValidation.IsValid()) << menuValidation.message;
const UIEditorCommandDescriptor* resetLayoutCommand =
FindUIEditorCommandDescriptor(commandRegistry, kEditorResetLayoutCommandId);
ASSERT_NE(resetLayoutCommand, nullptr);
EXPECT_EQ(
resetLayoutCommand->workspaceCommand.kind,
UIEditorWorkspaceCommandKind::ResetWorkspace);
EXPECT_EQ(
resetLayoutCommand->workspaceCommand.panelSource,
UIEditorCommandPanelSource::None);
const UIEditorMenuItemDescriptor* panelsSubmenu =
FindMenuItem(viewMenu.items, "view-panels");
ASSERT_NE(panelsSubmenu, nullptr);
ASSERT_EQ(panelsSubmenu->kind, UIEditorMenuItemKind::Submenu);
ASSERT_EQ(panelsSubmenu->children.size(), GetEditorWorkspaceFeatures().size());
for (const EditorWorkspaceFeatureDescriptor& feature : GetEditorWorkspaceFeatures()) {
const UIEditorCommandDescriptor* command =
FindWorkspacePanelCommand(commandRegistry, feature.panelId);
ASSERT_NE(command, nullptr);
EXPECT_EQ(command->displayName, feature.defaultTitle);
EXPECT_EQ(
command->workspaceCommand.kind,
UIEditorWorkspaceCommandKind::ActivatePanel);
EXPECT_EQ(
command->workspaceCommand.panelSource,
UIEditorCommandPanelSource::FixedPanelId);
const UIEditorMenuItemDescriptor* menuItem =
FindMenuItem(
panelsSubmenu->children,
std::string("view-panel-") + std::string(feature.panelId));
ASSERT_NE(menuItem, nullptr);
EXPECT_EQ(menuItem->label, feature.defaultTitle);
EXPECT_EQ(menuItem->commandId, command->commandId);
EXPECT_EQ(
menuItem->checkedState.source,
UIEditorMenuCheckedStateSource::PanelActive);
EXPECT_EQ(menuItem->checkedState.panelId, feature.panelId);
}
}
TEST(EditorProductRegistryTests, ShellAssetUsesRegistryWorkspacePreset) {
const EditorShellCommandPreset shellPreset = BuildEditorShellCommandPreset();
const UIEditorCommandRegistryValidationResult shellCommandValidation =
ValidateUIEditorCommandRegistry(shellPreset.commandRegistry);
EXPECT_TRUE(shellCommandValidation.IsValid()) << shellCommandValidation.message;
const UIEditorMenuModelValidationResult shellMenuValidation =
ValidateUIEditorMenuModel(
shellPreset.menuModel,
shellPreset.commandRegistry);
EXPECT_TRUE(shellMenuValidation.IsValid()) << shellMenuValidation.message;
UIEditorShortcutManager shortcutManager(shellPreset.commandRegistry);
for (const ::XCEngine::UI::UIShortcutBinding& binding : shellPreset.shortcutBindings) {
shortcutManager.RegisterBinding(binding);
}
const UIEditorShortcutManagerValidationResult shortcutValidation =
shortcutManager.ValidateConfiguration();
EXPECT_TRUE(shortcutValidation.IsValid()) << shortcutValidation.message;
const EditorShellAsset shell = BuildEditorApplicationShellAsset(TestRuntimePaths());
const EditorShellAssetValidationResult assetValidation =
ValidateEditorShellAsset(shell);
EXPECT_TRUE(assetValidation.IsValid()) << assetValidation.message;
const UIEditorPanelRegistry registryPanels = BuildEditorWorkspacePanelRegistry();
EXPECT_EQ(shell.panelRegistry.panels.size(), registryPanels.panels.size());
EXPECT_TRUE(
AreUIEditorWorkspaceModelsEquivalent(
shell.workspace,
BuildDefaultEditorWorkspaceModel()));
const UIEditorMenuDescriptor* assetViewMenu =
FindMenu(shell.shellDefinition.menuModel, "view");
ASSERT_NE(assetViewMenu, nullptr);
const UIEditorMenuDescriptor registryViewMenu = BuildEditorWorkspaceViewMenu();
ASSERT_EQ(assetViewMenu->items.size(), registryViewMenu.items.size());
ASSERT_NE(FindMenuItem(assetViewMenu->items, "view-panels"), nullptr);
for (const UIEditorCommandDescriptor& expected : shellPreset.commandRegistry.commands) {
const UIEditorCommandDescriptor* actual =
FindUIEditorCommandDescriptor(
shell.shortcutAsset.commandRegistry,
expected.commandId);
ASSERT_NE(actual, nullptr);
EXPECT_EQ(actual->displayName, expected.displayName);
EXPECT_EQ(actual->kind, expected.kind);
EXPECT_EQ(actual->workspaceCommand.kind, expected.workspaceCommand.kind);
EXPECT_EQ(
actual->workspaceCommand.panelSource,
expected.workspaceCommand.panelSource);
EXPECT_EQ(actual->workspaceCommand.panelId, expected.workspaceCommand.panelId);
}
EXPECT_EQ(
shell.shellDefinition.menuModel.menus.size(),
shellPreset.menuModel.menus.size());
EXPECT_EQ(
shell.shortcutAsset.bindings.size(),
shellPreset.shortcutBindings.size());
}
} // namespace
} // namespace XCEngine::UI::Editor::App

View File

@@ -1,5 +1,6 @@
#include "Project/EditorProjectRuntime.h"
#include "State/EditorSelectionService.h"
#include "Product/Services/Project/EditorProjectRuntime.h"
#include "Product/Runtime/Store/EditorStore.h"
#include "Product/State/EditorSelectionService.h"
#include <gtest/gtest.h>
@@ -7,6 +8,7 @@
#include <filesystem>
#include <fstream>
#include <string>
#include <utility>
namespace XCEngine::UI::Editor::App {
namespace {
@@ -185,5 +187,63 @@ TEST(EditorProjectRuntimeTests, BoundSelectionServiceBecomesTheSingleProjectSele
EXPECT_FALSE(runtime.HasSelection());
}
TEST(EditorProjectRuntimeTests, BoundStorePreservesPersistedCurrentFolderDuringInitialize) {
TemporaryRepo repo = {};
ASSERT_TRUE(repo.CreateDirectory("project/Assets/Scenes"));
ASSERT_TRUE(repo.CreateDirectory("project/Assets/Scripts"));
Product::EditorStore store = {};
Product::EditorState initialState = {};
initialState.session.currentProjectFolderId = "Assets/Scenes";
store.Reset(std::move(initialState));
EditorProjectRuntime runtime = {};
runtime.BindStore(&store);
ASSERT_TRUE(runtime.Initialize(repo.Root() / "project"));
EXPECT_EQ(store.GetState().session.currentProjectFolderId, "Assets/Scenes");
EXPECT_EQ(runtime.GetBrowserModel().GetCurrentFolderId(), "Assets/Scenes");
}
TEST(EditorProjectRuntimeTests, BoundStoreCanonicalizesInvalidPersistedCurrentFolderDuringInitialize) {
TemporaryRepo repo = {};
ASSERT_TRUE(repo.CreateDirectory("project/Assets/Scenes"));
Product::EditorStore store = {};
Product::EditorState initialState = {};
initialState.session.currentProjectFolderId = "Assets/Missing";
store.Reset(std::move(initialState));
EditorProjectRuntime runtime = {};
runtime.BindStore(&store);
ASSERT_TRUE(runtime.Initialize(repo.Root() / "project"));
EXPECT_EQ(store.GetState().session.currentProjectFolderId, "Assets");
EXPECT_EQ(runtime.GetBrowserModel().GetCurrentFolderId(), "Assets");
}
TEST(EditorProjectRuntimeTests, BoundStoreRemainsTheAuthoritativeCurrentFolderSourceAtRuntime) {
TemporaryRepo repo = {};
ASSERT_TRUE(repo.CreateDirectory("project/Assets/Scenes"));
ASSERT_TRUE(repo.CreateDirectory("project/Assets/Scripts"));
Product::EditorStore store = {};
store.Reset({});
EditorProjectRuntime runtime = {};
runtime.BindStore(&store);
ASSERT_TRUE(runtime.Initialize(repo.Root() / "project"));
ASSERT_TRUE(runtime.NavigateToFolder("Assets/Scenes"));
EXPECT_EQ(store.GetState().session.currentProjectFolderId, "Assets/Scenes");
EXPECT_EQ(runtime.GetBrowserModel().GetCurrentFolderId(), "Assets/Scenes");
const Product::EditorStore::DispatchResult dispatchResult =
store.Dispatch(Product::EditorCommand::SetCurrentProjectFolder("Assets/Scripts"));
ASSERT_TRUE(dispatchResult.handled);
ASSERT_TRUE(dispatchResult.stateChanged);
EXPECT_EQ(runtime.GetBrowserModel().GetCurrentFolderId(), "Assets/Scripts");
}
} // namespace
} // namespace XCEngine::UI::Editor::App

View File

@@ -0,0 +1,217 @@
#include <gtest/gtest.h>
#include "Product/Core/Scene/EditorSceneBackend.h"
#include "Product/Runtime/Store/EditorStore.h"
#include "Product/Services/Runtime/EditorRuntimeCommandService.h"
#include "Product/Services/Scene/EditorSceneRuntime.h"
#include <XCEngine/Scene/Scene.h>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
namespace XCEngine::UI::Editor::App {
namespace {
using ::XCEngine::Components::Scene;
class FakeEditorSceneBackend;
class FakeEditorScenePlaySession final : public EditorScenePlaySession {
public:
explicit FakeEditorScenePlaySession(FakeEditorSceneBackend& backend)
: m_backend(backend) {}
~FakeEditorScenePlaySession() override;
Scene* GetRuntimeScene() const override;
private:
FakeEditorSceneBackend& m_backend;
};
class FakeEditorSceneBackend final : public EditorSceneBackend {
public:
FakeEditorSceneBackend() {
editScene = std::make_unique<Scene>("Edit");
activeScene = editScene.get();
}
EditorStartupSceneResult EnsureStartupScene(
const std::filesystem::path&) override {
return EditorStartupSceneResult{
.ready = true,
.loadedFromDisk = true,
.scenePath = std::filesystem::path("D:/Project/Assets/Scenes/Main.xc"),
.sceneName = "Edit"
};
}
EditorSceneHierarchySnapshot BuildHierarchySnapshot() const override {
return {};
}
bool NewScene(std::string_view sceneName) override {
editScene = std::make_unique<Scene>(
sceneName.empty() ? std::string("Untitled") : std::string(sceneName));
activeScene = editScene.get();
return true;
}
bool OpenSceneAsset(const std::filesystem::path& scenePath) override {
lastOpenedScenePath = scenePath;
if (!openSceneResult) {
return false;
}
editScene = std::make_unique<Scene>(openedSceneName);
activeScene = editScene.get();
return true;
}
bool SaveActiveScene(const std::filesystem::path&) override {
return true;
}
Scene* GetActiveScene() const override {
return activeScene;
}
std::unique_ptr<EditorScenePlaySession> BeginPlaySession() override {
++beginPlaySessionCallCount;
runtimeScene = std::make_unique<Scene>("Runtime");
activeScene = runtimeScene.get();
return std::make_unique<FakeEditorScenePlaySession>(*this);
}
std::optional<EditorSceneObjectSnapshot> GetObjectSnapshot(
std::string_view) const override {
return std::nullopt;
}
bool AddComponent(std::string_view, std::string_view) override {
return false;
}
bool RenameGameObject(std::string_view, std::string_view) override {
return false;
}
bool DeleteGameObject(std::string_view) override {
return false;
}
std::string DuplicateGameObject(std::string_view) override {
return {};
}
bool ReparentGameObject(std::string_view, std::string_view) override {
return false;
}
bool MoveGameObjectBefore(std::string_view, std::string_view) override {
return false;
}
bool MoveGameObjectAfter(std::string_view, std::string_view) override {
return false;
}
bool MoveGameObjectToRoot(std::string_view) override {
return false;
}
void EndPlaySession() {
++endPlaySessionCallCount;
runtimeScene.reset();
activeScene = editScene.get();
}
std::unique_ptr<Scene> editScene = {};
std::unique_ptr<Scene> runtimeScene = {};
Scene* activeScene = nullptr;
std::filesystem::path lastOpenedScenePath = {};
int beginPlaySessionCallCount = 0;
int endPlaySessionCallCount = 0;
bool openSceneResult = true;
std::string openedSceneName = "Opened";
};
FakeEditorScenePlaySession::~FakeEditorScenePlaySession() {
m_backend.EndPlaySession();
}
Scene* FakeEditorScenePlaySession::GetRuntimeScene() const {
return m_backend.runtimeScene.get();
}
struct RuntimeCommandServiceHarness {
RuntimeCommandServiceHarness() {
auto backend = std::make_unique<FakeEditorSceneBackend>();
backendPtr = backend.get();
sceneRuntime.SetBackend(std::move(backend));
Product::EditorState initialState = {};
initialState.session.projectRoot = "D:/Project";
store.Reset(std::move(initialState));
const EditorStartupSceneResult startupScene =
sceneRuntime.Initialize("D:/Project");
EXPECT_TRUE(startupScene.ready);
EditorRuntimePaths runtimePaths = {};
runtimePaths.projectRoot = "D:/Project";
service.Initialize(store, sceneRuntime, runtimePaths, startupScene);
}
Product::EditorStore store = {};
EditorSceneRuntime sceneRuntime = {};
FakeEditorSceneBackend* backendPtr = nullptr;
EditorRuntimeCommandService service = {};
};
TEST(EditorRuntimeCommandServiceTests, InitializationProjectsStartupSceneIntoStoreSession) {
RuntimeCommandServiceHarness harness = {};
EXPECT_EQ(
harness.store.GetState().session.currentScenePath,
std::filesystem::path("D:/Project/Assets/Scenes/Main.xc"));
EXPECT_EQ(harness.store.GetState().session.currentSceneName, "Edit");
EXPECT_FALSE(harness.store.GetState().session.sceneDocumentDirty);
EXPECT_EQ(harness.store.GetState().session.runtimeMode, EditorRuntimeMode::Edit);
}
TEST(EditorRuntimeCommandServiceTests, FileAndRunCommandsMutateStoreSessionState) {
RuntimeCommandServiceHarness harness = {};
ASSERT_NE(harness.backendPtr, nullptr);
int notificationCount = 0;
harness.store.Subscribe(
[&](const Product::EditorState&) {
++notificationCount;
});
const UIEditorHostCommandDispatchResult newSceneResult =
harness.service.DispatchFileCommand("file.new_scene");
ASSERT_TRUE(newSceneResult.commandExecuted);
EXPECT_TRUE(harness.store.GetState().session.currentScenePath.empty());
EXPECT_EQ(harness.store.GetState().session.currentSceneName, "Untitled");
EXPECT_TRUE(harness.store.GetState().session.sceneDocumentDirty);
const UIEditorHostCommandDispatchResult playResult =
harness.service.DispatchRunCommand("run.play");
ASSERT_TRUE(playResult.commandExecuted);
EXPECT_EQ(harness.store.GetState().session.runtimeMode, EditorRuntimeMode::Play);
const UIEditorHostCommandDispatchResult stopResult =
harness.service.DispatchRunCommand("run.stop");
ASSERT_TRUE(stopResult.commandExecuted);
EXPECT_EQ(harness.store.GetState().session.runtimeMode, EditorRuntimeMode::Edit);
EXPECT_GE(notificationCount, 3);
}
} // namespace
} // namespace XCEngine::UI::Editor::App

View File

@@ -1,309 +0,0 @@
#include <gtest/gtest.h>
#include "Project/EditorProjectRuntime.h"
#include "Runtime/EditorRuntimeCoordinator.h"
#include "Scene/EditorSceneBackend.h"
#include "Scene/EditorSceneRuntime.h"
#include "State/EditorSession.h"
#include <XCEngine/Scene/Scene.h>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
namespace XCEngine::UI::Editor::App {
namespace {
using ::XCEngine::Components::Scene;
class FakeEditorSceneBackend;
class FakeEditorScenePlaySession final : public EditorScenePlaySession {
public:
explicit FakeEditorScenePlaySession(FakeEditorSceneBackend& backend)
: m_backend(backend) {}
~FakeEditorScenePlaySession() override;
Scene* GetRuntimeScene() const override;
private:
FakeEditorSceneBackend& m_backend;
};
class FakeEditorSceneBackend final : public EditorSceneBackend {
public:
FakeEditorSceneBackend() {
editScene = std::make_unique<Scene>("Edit");
activeScene = editScene.get();
}
EditorStartupSceneResult EnsureStartupScene(
const std::filesystem::path&) override {
return EditorStartupSceneResult{
.ready = true,
.loadedFromDisk = true,
.scenePath = std::filesystem::path("D:/Project/Assets/Scenes/Main.xc"),
.sceneName = "Edit"
};
}
EditorSceneHierarchySnapshot BuildHierarchySnapshot() const override {
return {};
}
bool NewScene(std::string_view sceneName) override {
editScene = std::make_unique<Scene>(
sceneName.empty() ? std::string("Untitled") : std::string(sceneName));
activeScene = editScene.get();
return true;
}
bool OpenSceneAsset(const std::filesystem::path& scenePath) override {
lastOpenedScenePath = scenePath;
if (!openSceneResult) {
return false;
}
editScene = std::make_unique<Scene>(openedSceneName);
activeScene = editScene.get();
return true;
}
bool SaveActiveScene(const std::filesystem::path&) override {
++saveActiveSceneCallCount;
savedActiveSceneWasEditScene = activeScene == editScene.get();
return true;
}
Scene* GetActiveScene() const override {
return activeScene;
}
std::unique_ptr<EditorScenePlaySession> BeginPlaySession() override {
++beginPlaySessionCallCount;
if (failBeginPlaySession) {
return nullptr;
}
runtimeScene = std::make_unique<Scene>("Runtime");
activeScene = runtimeScene.get();
return std::make_unique<FakeEditorScenePlaySession>(*this);
}
std::optional<EditorSceneObjectSnapshot> GetObjectSnapshot(
std::string_view) const override {
return std::nullopt;
}
bool AddComponent(std::string_view, std::string_view) override {
return false;
}
bool RenameGameObject(std::string_view, std::string_view) override {
return false;
}
bool DeleteGameObject(std::string_view) override {
return false;
}
std::string DuplicateGameObject(std::string_view) override {
return {};
}
bool ReparentGameObject(std::string_view, std::string_view) override {
return false;
}
bool MoveGameObjectBefore(std::string_view, std::string_view) override {
return false;
}
bool MoveGameObjectAfter(std::string_view, std::string_view) override {
return false;
}
bool MoveGameObjectToRoot(std::string_view) override {
return false;
}
void EndPlaySession() {
++endPlaySessionCallCount;
runtimeScene.reset();
activeScene = editScene.get();
}
Scene* EditScene() const {
return editScene.get();
}
Scene* RuntimeScene() const {
return runtimeScene.get();
}
std::unique_ptr<Scene> editScene = {};
std::unique_ptr<Scene> runtimeScene = {};
Scene* activeScene = nullptr;
std::filesystem::path lastOpenedScenePath = {};
int beginPlaySessionCallCount = 0;
int endPlaySessionCallCount = 0;
int saveActiveSceneCallCount = 0;
bool savedActiveSceneWasEditScene = false;
bool failBeginPlaySession = false;
bool openSceneResult = true;
std::string openedSceneName = "Opened";
};
FakeEditorScenePlaySession::~FakeEditorScenePlaySession() {
m_backend.EndPlaySession();
}
Scene* FakeEditorScenePlaySession::GetRuntimeScene() const {
return m_backend.RuntimeScene();
}
struct RuntimeCoordinatorHarness {
RuntimeCoordinatorHarness(
EditorRuntimePaths runtimePaths = {}) {
auto backend = std::make_unique<FakeEditorSceneBackend>();
backendPtr = backend.get();
sceneRuntime.SetBackend(std::move(backend));
const EditorStartupSceneResult startupScene =
sceneRuntime.Initialize("D:/Project");
EXPECT_TRUE(startupScene.ready);
coordinator.Initialize(
session,
sceneRuntime,
projectRuntime,
runtimePaths,
startupScene);
}
EditorSession session = {};
EditorProjectRuntime projectRuntime = {};
EditorSceneRuntime sceneRuntime = {};
FakeEditorSceneBackend* backendPtr = nullptr;
EditorRuntimeCoordinator coordinator = {};
};
TEST(EditorRuntimeCoordinatorTests, InitializeProjectsStartupSceneDocumentStateToSession) {
RuntimeCoordinatorHarness harness = {};
EXPECT_EQ(
harness.session.currentScenePath,
std::filesystem::path("D:/Project/Assets/Scenes/Main.xc"));
EXPECT_EQ(harness.session.currentSceneName, "Edit");
EXPECT_FALSE(harness.session.sceneDocumentDirty);
EXPECT_EQ(harness.session.runtimeMode, EditorRuntimeMode::Edit);
}
TEST(EditorRuntimeCoordinatorTests, ScriptRebuildEvaluationIsNoLongerHardcodedStub) {
EditorRuntimePaths runtimePaths = {};
runtimePaths.projectRoot = "D:/Project";
RuntimeCoordinatorHarness harness(runtimePaths);
const UIEditorHostCommandEvaluationResult evaluation =
harness.coordinator.EvaluateScriptCommand("scripts.rebuild");
EXPECT_NE(
evaluation.message,
"Script rebuild is owned by the runtime coordinator, but no in-process script assembly builder is bound.");
}
TEST(EditorRuntimeCoordinatorTests, NewSceneProjectsUnsavedDirtyDocumentStateToSession) {
RuntimeCoordinatorHarness harness = {};
const UIEditorHostCommandDispatchResult newSceneResult =
harness.coordinator.DispatchFileCommand("file.new_scene");
EXPECT_TRUE(newSceneResult.commandExecuted);
EXPECT_TRUE(harness.session.currentScenePath.empty());
EXPECT_EQ(harness.session.currentSceneName, "Untitled");
EXPECT_TRUE(harness.session.sceneDocumentDirty);
}
TEST(EditorRuntimeCoordinatorTests, OpenSceneProjectsCoordinatorOwnedDocumentStateToSession) {
RuntimeCoordinatorHarness harness = {};
ASSERT_NE(harness.backendPtr, nullptr);
harness.backendPtr->openedSceneName = "Opened Scene";
const std::filesystem::path scenePath =
"D:/Project/Assets/Scenes/Secondary.xc";
ASSERT_TRUE(harness.coordinator.RequestOpenSceneAsset(scenePath));
EXPECT_EQ(harness.backendPtr->lastOpenedScenePath, scenePath);
EXPECT_EQ(harness.session.currentScenePath, scenePath);
EXPECT_EQ(harness.session.currentSceneName, "Opened Scene");
EXPECT_FALSE(harness.session.sceneDocumentDirty);
}
TEST(EditorRuntimeCoordinatorTests, PlayModeRunsRuntimeSceneAndRestoresEditSceneOnStop) {
RuntimeCoordinatorHarness harness = {};
ASSERT_NE(harness.backendPtr, nullptr);
ASSERT_EQ(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->EditScene());
const UIEditorHostCommandDispatchResult playResult =
harness.coordinator.DispatchRunCommand("run.play");
EXPECT_TRUE(playResult.commandExecuted);
EXPECT_EQ(harness.session.runtimeMode, EditorRuntimeMode::Play);
EXPECT_EQ(harness.backendPtr->beginPlaySessionCallCount, 1);
EXPECT_EQ(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->RuntimeScene());
EXPECT_NE(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->EditScene());
const UIEditorHostCommandDispatchResult stopResult =
harness.coordinator.DispatchRunCommand("run.stop");
EXPECT_TRUE(stopResult.commandExecuted);
EXPECT_EQ(harness.session.runtimeMode, EditorRuntimeMode::Edit);
EXPECT_EQ(harness.backendPtr->endPlaySessionCallCount, 1);
EXPECT_EQ(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->EditScene());
}
TEST(EditorRuntimeCoordinatorTests, StepFromEditCreatesPausedPlaySession) {
RuntimeCoordinatorHarness harness = {};
ASSERT_NE(harness.backendPtr, nullptr);
const UIEditorHostCommandDispatchResult stepResult =
harness.coordinator.DispatchRunCommand("run.step");
EXPECT_TRUE(stepResult.commandExecuted);
EXPECT_EQ(harness.session.runtimeMode, EditorRuntimeMode::Paused);
EXPECT_EQ(harness.backendPtr->beginPlaySessionCallCount, 1);
EXPECT_EQ(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->RuntimeScene());
const UIEditorHostCommandDispatchResult stopResult =
harness.coordinator.DispatchRunCommand("run.stop");
EXPECT_TRUE(stopResult.commandExecuted);
EXPECT_EQ(harness.backendPtr->endPlaySessionCallCount, 1);
EXPECT_EQ(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->EditScene());
}
TEST(EditorRuntimeCoordinatorTests, SaveAfterStoppingPlayTargetsRestoredEditScene) {
RuntimeCoordinatorHarness harness = {};
ASSERT_NE(harness.backendPtr, nullptr);
ASSERT_TRUE(harness.coordinator.DispatchRunCommand("run.play").commandExecuted);
ASSERT_TRUE(harness.coordinator.DispatchRunCommand("run.stop").commandExecuted);
const UIEditorHostCommandDispatchResult saveResult =
harness.coordinator.DispatchFileCommand("file.save_scene");
EXPECT_TRUE(saveResult.commandExecuted);
EXPECT_EQ(harness.backendPtr->saveActiveSceneCallCount, 1);
EXPECT_TRUE(harness.backendPtr->savedActiveSceneWasEditScene);
}
TEST(EditorRuntimeCoordinatorTests, FailedPlaySessionLeavesEditorInEditMode) {
RuntimeCoordinatorHarness harness = {};
ASSERT_NE(harness.backendPtr, nullptr);
harness.backendPtr->failBeginPlaySession = true;
const UIEditorHostCommandDispatchResult playResult =
harness.coordinator.DispatchRunCommand("run.play");
EXPECT_FALSE(playResult.commandExecuted);
EXPECT_EQ(harness.session.runtimeMode, EditorRuntimeMode::Edit);
EXPECT_EQ(harness.backendPtr->beginPlaySessionCallCount, 1);
EXPECT_EQ(harness.backendPtr->endPlaySessionCallCount, 0);
EXPECT_EQ(harness.sceneRuntime.GetActiveScene(), harness.backendPtr->EditScene());
}
} // namespace
} // namespace XCEngine::UI::Editor::App

View File

@@ -1,5 +1,5 @@
#include "Scene/EditorSceneBackend.h"
#include "Scene/EditorSceneRuntime.h"
#include "Product/Core/Scene/EditorSceneBackend.h"
#include "Product/Services/Scene/EditorSceneRuntime.h"
#include <gtest/gtest.h>

View File

@@ -1,9 +1,8 @@
#include <gtest/gtest.h>
#include "EditorWorkspacePanelRegistry.h"
#include "EditorShellAssetBuilder.h"
#include "Panels/EditorPanelIds.h"
#include "Product/EditorProductManifest.h"
#include "Product/Features/Workspace/Game/GameWorkspaceFeature.h"
#include "Product/Registry/EditorProductRegistry.h"
#include "Product/Runtime/Shell/EditorShellAssetBuilder.h"
#include <XCEditor/Shell/UIEditorShellAsset.h>
@@ -13,15 +12,12 @@ namespace {
using XCEngine::Input::KeyCode;
using XCEngine::UI::Editor::App::BuildEditorApplicationShellAsset;
using XCEngine::UI::Editor::App::EditorProductManifestValidationCode;
using XCEngine::UI::Editor::App::EditorProductViewportKind;
using XCEngine::UI::Editor::App::EditorRuntimePaths;
using XCEngine::UI::Editor::App::EditorWorkspacePanelCompositionValidationCode;
using XCEngine::UI::Editor::App::FindEditorProductPanel;
using XCEngine::UI::Editor::App::GetEditorProductPanels;
using XCEngine::UI::Editor::App::kGamePanelId;
using XCEngine::UI::Editor::App::ValidateEditorProductManifest;
using XCEngine::UI::Editor::App::ValidateEditorWorkspacePanelComposition;
using XCEngine::UI::Editor::App::FindEditorWorkspaceFeature;
using XCEngine::UI::Editor::App::GetEditorWorkspaceFeatures;
using XCEngine::UI::Editor::App::kGameWorkspaceFeaturePanelId;
using XCEngine::UI::Editor::App::ValidateEditorProductRegistry;
using XCEngine::UI::Editor::EditorShellAssetValidationCode;
using XCEngine::UI::Editor::FindUIEditorPanelDescriptor;
using XCEngine::UI::Editor::UIEditorCommandPanelSource;
@@ -86,23 +82,14 @@ TEST(EditorShellAssetValidationTest, DefaultShellAssetPassesValidation) {
shellAsset.panelRegistry.panels.front().presentationKind);
}
TEST(EditorShellAssetValidationTest, ProductManifestIsPureDataAndCompositionIsComplete) {
const auto manifestValidation = ValidateEditorProductManifest();
EXPECT_EQ(manifestValidation.code, EditorProductManifestValidationCode::None)
<< manifestValidation.message;
ASSERT_TRUE(manifestValidation.IsValid());
const auto compositionValidation = ValidateEditorWorkspacePanelComposition();
EXPECT_EQ(
compositionValidation.code,
EditorWorkspacePanelCompositionValidationCode::None)
<< compositionValidation.message;
ASSERT_TRUE(compositionValidation.IsValid());
TEST(EditorShellAssetValidationTest, ProductRegistryAndCompositionAreComplete) {
const auto registryValidation = ValidateEditorProductRegistry();
ASSERT_TRUE(registryValidation.IsValid()) << registryValidation.message;
const auto shellAsset = BuildEditorApplicationShellAsset(TestRuntimePaths());
ASSERT_EQ(shellAsset.panelRegistry.panels.size(), GetEditorProductPanels().size());
ASSERT_EQ(shellAsset.panelRegistry.panels.size(), GetEditorWorkspaceFeatures().size());
const auto* gamePanel = FindEditorProductPanel(kGamePanelId);
const auto* gamePanel = FindEditorWorkspaceFeature(kGameWorkspaceFeaturePanelId);
ASSERT_NE(gamePanel, nullptr);
EXPECT_EQ(gamePanel->viewportKind, EditorProductViewportKind::Game);
EXPECT_TRUE(gamePanel->viewportPlaceholderStatus.empty());

View File

@@ -0,0 +1,100 @@
#include <gtest/gtest.h>
#include "Product/Runtime/Store/EditorStore.h"
#include <XCEditor/Workspace/UIEditorWorkspaceModel.h>
#include <filesystem>
#include <utility>
namespace XCEngine::UI::Editor::Product {
namespace {
TEST(EditorStoreTests, SetSceneDocumentStateNotifiesObserversWhenSessionChanges) {
EditorStore store = {};
EditorState initialState = {};
initialState.session.projectRoot = "D:/Project";
store.Reset(std::move(initialState));
int notificationCount = 0;
EditorState observedState = {};
store.Subscribe(
[&](const EditorState& state) {
++notificationCount;
observedState = state;
});
const EditorStore::DispatchResult result = store.Dispatch(
EditorCommand::SetSceneDocumentState(
"D:/Project/Assets/Scenes/Main.xc",
"Main",
true));
EXPECT_TRUE(result.handled);
EXPECT_TRUE(result.stateChanged);
EXPECT_EQ(notificationCount, 1);
EXPECT_EQ(
observedState.session.currentScenePath,
std::filesystem::path("D:/Project/Assets/Scenes/Main.xc"));
EXPECT_EQ(observedState.session.currentSceneName, "Main");
EXPECT_TRUE(observedState.session.sceneDocumentDirty);
}
TEST(EditorStoreTests, SetCurrentProjectFolderSkipsNotificationsWhenSessionDoesNotChange) {
EditorStore store = {};
store.Reset({});
int notificationCount = 0;
store.Subscribe(
[&](const EditorState&) {
++notificationCount;
});
const EditorStore::DispatchResult result = store.Dispatch(
EditorCommand::SetCurrentProjectFolder("Assets"));
EXPECT_TRUE(result.handled);
EXPECT_FALSE(result.stateChanged);
EXPECT_EQ(notificationCount, 0);
}
TEST(EditorStoreTests, SetWindowWorkspaceStateCommitsAuthoritativeWindowDraft) {
EditorStore store = {};
EditorState initialState = {};
initialState.windowWorkspace.primaryWindowId = "main";
initialState.windowWorkspace.activeWindowId = "main";
UIEditorWindowWorkspaceState mainWindow = {};
mainWindow.windowId = "main";
initialState.windowWorkspace.windows.push_back(mainWindow);
store.Reset(std::move(initialState));
UIEditorWorkspaceModel nextWorkspace = {};
nextWorkspace.root = BuildUIEditorWorkspaceSingleTabStack(
"root-tabs",
"scene",
"Scene",
true);
nextWorkspace.activePanelId = "scene";
UIEditorWorkspaceSession nextSession = {};
int notificationCount = 0;
store.Subscribe(
[&](const EditorState&) {
++notificationCount;
});
const EditorStore::DispatchResult result = store.Dispatch(
EditorCommand::SetWindowWorkspaceState("main", nextWorkspace, nextSession));
ASSERT_TRUE(result.handled);
ASSERT_TRUE(result.stateChanged);
EXPECT_EQ(notificationCount, 1);
const UIEditorWindowWorkspaceState* const storedWindow =
store.FindWindowWorkspaceState("main");
ASSERT_NE(storedWindow, nullptr);
EXPECT_EQ(storedWindow->workspace.activePanelId, "scene");
}
} // namespace
} // namespace XCEngine::UI::Editor::Product

View File

@@ -1,46 +1,18 @@
#include <gtest/gtest.h>
#include "Frame/EditorWindowFrameOrchestrator.h"
#include "Product/Runtime/Diagnostics/EditorFrameStatusController.h"
#include "Product/Runtime/Windowing/Frame/EditorWindowFrameOrchestrator.h"
#include <XCEditor/Shell/UIEditorShellInteraction.h>
#include <XCEditor/Workspace/UIEditorWorkspaceController.h>
#include <XCEngine/UI/DrawData.h>
#include <functional>
#include <optional>
namespace XCEngine::UI::Editor::App {
namespace {
class FakeShellDefinitionProvider final : public EditorShellDefinitionProvider {
public:
UIEditorShellInteractionDefinition BuildShellDefinition(
const UIEditorWorkspaceController&,
std::string_view,
std::string_view,
EditorShellVariant) const override {
return {};
}
};
class FakeFrameStatusService final : public EditorFrameStatusService {
public:
void SetStatus(std::string, std::string) override {}
void SetReadyStatus() override {}
std::string ComposeStatusText() const override { return {}; }
void UpdateStatusFromShellResult(
const UIEditorWorkspaceController&,
const UIEditorShellInteractionResult&) override {}
std::string DescribeWorkspaceState(
const UIEditorWorkspaceController&,
const UIEditorShellInteractionState&) const override {
return {};
}
std::vector<WorkspaceTraceEntry> SyncWorkspacePanelFrameEvents(
const std::vector<EditorWorkspacePanelFrameEvent>&) override {
return {};
}
};
class FakeWorkspaceShellRuntime final : public EditorWorkspaceShellRuntime {
public:
void Initialize(
@@ -60,8 +32,6 @@ public:
void SetViewportSurfacePresentationEnabled(bool) override {}
void Update(
const EditorShellDefinitionProvider&,
EditorFrameStatusService&,
UIEditorWorkspaceController&,
const ::XCEngine::UI::UIRect&,
const std::vector<::XCEngine::UI::UIInputEvent>&,
@@ -135,8 +105,7 @@ public:
TEST(EditorWindowFrameOrchestratorTests, UtilityWindowRequestsFlowThroughFrameTransferRequests) {
EditorWindowFrameOrchestrator orchestrator = {};
FakeShellDefinitionProvider shellDefinitionProvider = {};
FakeFrameStatusService frameStatusService = {};
EditorFrameStatusController frameStatusController = {};
FakeWorkspaceShellRuntime shellRuntime = {};
UIEditorWorkspaceController workspaceController = {};
::XCEngine::UI::UIDrawData drawData = {};
@@ -152,8 +121,7 @@ TEST(EditorWindowFrameOrchestratorTests, UtilityWindowRequestsFlowThroughFrameTr
const EditorWindowFrameTransferRequests transferRequests =
orchestrator.UpdateAndAppend(
shellDefinitionProvider,
frameStatusService,
frameStatusController,
&consumeUtilityWindowRequest,
workspaceController,
shellRuntime,

View File

@@ -2,7 +2,7 @@
#include <XCEditor/Shell/UIEditorShellCapturePolicy.h>
#include <XCEditor/Workspace/UIEditorWorkspaceCompose.h>
#include "EditorWindowPointerCapture.h"
#include "Product/Framework/Windowing/EditorWindowPointerCapture.h"
#include <gtest/gtest.h>

View File

@@ -1,9 +1,9 @@
#include <gtest/gtest.h>
#include "Game/GameViewportFeature.h"
#include "Panels/EditorPanelIds.h"
#include "State/EditorCommandFocusService.h"
#include "Viewport/GameViewportRenderService.h"
#include "Product/Features/Workspace/Game/GameViewportFeature.h"
#include "Product/Features/Workspace/Game/GameWorkspaceFeature.h"
#include "Product/Rendering/Viewport/GameViewportRenderService.h"
#include "Product/State/EditorCommandFocusService.h"
#include <XCEditor/Viewport/UIEditorViewportInputBridge.h>
@@ -39,7 +39,7 @@ UIEditorWorkspaceComposeState BuildGameComposeState(
const UIEditorViewportInputBridgeState& inputBridgeState) {
UIEditorWorkspaceComposeState composeState = {};
UIEditorWorkspacePanelPresentationState panelState = {};
panelState.panelId = std::string(kGamePanelId);
panelState.panelId = std::string(kGameWorkspaceFeaturePanelId);
panelState.viewportShellState.inputBridgeState = inputBridgeState;
composeState.panelStates.push_back(std::move(panelState));
return composeState;
@@ -51,7 +51,7 @@ UIEditorWorkspaceComposeFrame BuildGameComposeFrame(
const UISize& requestedViewportSize) {
UIEditorWorkspaceComposeFrame composeFrame = {};
UIEditorWorkspaceViewportComposeFrame viewportFrame = {};
viewportFrame.panelId = std::string(kGamePanelId);
viewportFrame.panelId = std::string(kGameWorkspaceFeaturePanelId);
viewportFrame.viewportShellFrame.inputFrame = inputFrame;
viewportFrame.viewportShellFrame.requestedViewportSize = requestedViewportSize;
viewportFrame.viewportShellFrame.slotLayout.inputRect = inputRect;

View File

@@ -1,5 +1,5 @@
#include "Hierarchy/HierarchyModel.h"
#include "Scene/EngineEditorSceneBackend.h"
#include "Product/Features/Workspace/Hierarchy/HierarchyModel.h"
#include "Product/Services/Scene/EngineEditorSceneBackend.h"
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Core/Asset/ResourceManager.h>

View File

@@ -1,11 +1,11 @@
#include "Inspector/Components/IInspectorComponentEditor.h"
#include "Inspector/Components/InspectorComponentEditorRegistry.h"
#include "Inspector/InspectorFieldValueApplier.h"
#include "Inspector/InspectorPresentationModel.h"
#include "Inspector/InspectorSubject.h"
#include "Project/EditorProjectRuntime.h"
#include "Scene/EditorSceneRuntime.h"
#include "Scene/EngineEditorSceneBackend.h"
#include "Product/Features/Workspace/Inspector/Components/IInspectorComponentEditor.h"
#include "Product/Features/Workspace/Inspector/Components/InspectorComponentEditorRegistry.h"
#include "Product/Features/Workspace/Inspector/InspectorFieldValueApplier.h"
#include "Product/Features/Workspace/Inspector/InspectorPresentationModel.h"
#include "Product/Features/Workspace/Inspector/InspectorSubject.h"
#include "Product/Services/Project/EditorProjectRuntime.h"
#include "Product/Services/Scene/EditorSceneRuntime.h"
#include "Product/Services/Scene/EngineEditorSceneBackend.h"
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Components/GameObject.h>

View File

@@ -1,4 +1,4 @@
#include "Project/ProjectBrowserModel.h"
#include "Product/Services/Project/ProjectBrowserModel.h"
#include <gtest/gtest.h>

View File

@@ -1,8 +1,7 @@
#include "Project/ProjectPanel.h"
#include "Assets/EditorIconService.h"
#include "SystemInteractionService.h"
#include "Panels/EditorPanelIds.h"
#include "Product/Core/Assets/EditorIconService.h"
#include "Product/Features/Workspace/Project/ProjectPanel.h"
#include "Product/Features/Workspace/Project/ProjectWorkspaceFeature.h"
#include "Product/Framework/System/SystemInteractionService.h"
#include <gtest/gtest.h>
@@ -117,7 +116,7 @@ private:
UIEditorHostedPanelDispatchEntry MakeProjectDispatchEntry() {
UIEditorHostedPanelDispatchEntry entry = {};
entry.panelId = std::string(kProjectPanelId);
entry.panelId = std::string(kProjectWorkspaceFeaturePanelId);
entry.presentationKind = UIEditorPanelPresentationKind::HostedContent;
entry.mounted = true;
entry.bounds = ::XCEngine::UI::UIRect(0.0f, 0.0f, 640.0f, 360.0f);

View File

@@ -1,4 +1,4 @@
#include "Viewport/SceneViewportRenderPlan.h"
#include "Product/Rendering/Viewport/SceneViewportRenderPlan.h"
#include <gtest/gtest.h>

View File

@@ -1,16 +1,15 @@
#include "Scene/EditorSceneRuntime.h"
#include "Scene/EngineEditorSceneBackend.h"
#include "Scene/SceneViewportController.h"
#include "Scene/SceneViewportSession.h"
#include "Inspector/InspectorSubject.h"
#include "Project/EditorProjectRuntime.h"
#include "Viewport/SceneViewportRenderService.h"
#include "Viewport/ViewportHostService.h"
#include "Viewport/ViewportRenderTargets.h"
#include "Viewport/ViewportRenderTargetUtils.h"
#include "State/EditorSelectionService.h"
#include "Panels/EditorPanelIds.h"
#include "Product/Features/Workspace/Inspector/InspectorSubject.h"
#include "Product/Features/Workspace/Scene/SceneViewportController.h"
#include "Product/Features/Workspace/Scene/SceneViewportSession.h"
#include "Product/Features/Workspace/Scene/SceneWorkspaceFeature.h"
#include "Product/Rendering/Viewport/SceneViewportRenderService.h"
#include "Product/Rendering/Viewport/ViewportHostService.h"
#include "Product/Rendering/Viewport/ViewportRenderTargets.h"
#include "Product/Rendering/Viewport/ViewportRenderTargetUtils.h"
#include "Product/Services/Project/EditorProjectRuntime.h"
#include "Product/Services/Scene/EditorSceneRuntime.h"
#include "Product/Services/Scene/EngineEditorSceneBackend.h"
#include "Product/State/EditorSelectionService.h"
#include <XCEditor/Viewport/UIEditorViewportInputBridge.h>
#include <XCEditor/Viewport/UIEditorViewportSlot.h>
@@ -185,7 +184,8 @@ UIEditorWorkspaceComposeState BuildSceneComposeState(
const UIEditorViewportInputBridgeState& inputBridgeState) {
UIEditorWorkspaceComposeState composeState = {};
UIEditorWorkspacePanelPresentationState panelState = {};
panelState.panelId = std::string(::XCEngine::UI::Editor::App::kScenePanelId);
panelState.panelId = std::string(
::XCEngine::UI::Editor::App::kSceneWorkspaceFeaturePanelId);
panelState.viewportShellState.inputBridgeState = inputBridgeState;
composeState.panelStates.push_back(std::move(panelState));
return composeState;
@@ -197,7 +197,8 @@ UIEditorWorkspaceComposeFrame BuildSceneComposeFrame(
const UISize& requestedViewportSize) {
UIEditorWorkspaceComposeFrame composeFrame = {};
UIEditorWorkspaceViewportComposeFrame viewportFrame = {};
viewportFrame.panelId = std::string(::XCEngine::UI::Editor::App::kScenePanelId);
viewportFrame.panelId = std::string(
::XCEngine::UI::Editor::App::kSceneWorkspaceFeaturePanelId);
viewportFrame.viewportShellFrame.inputFrame = inputFrame;
viewportFrame.viewportShellFrame.requestedViewportSize = requestedViewportSize;
viewportFrame.viewportShellFrame.slotLayout.inputRect = inputRect;

View File

@@ -1,4 +1,4 @@
#include "Viewport/ViewportObjectIdPicker.h"
#include "Product/Rendering/Viewport/ViewportObjectIdPicker.h"
#include <gtest/gtest.h>