Refine editor shell asset contract
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "Core/EditorShellAsset.h"
|
||||
|
||||
#include <XCEditor/Core/UIEditorCommandDispatcher.h>
|
||||
#include <XCEditor/Core/UIEditorMenuModel.h>
|
||||
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
||||
@@ -40,11 +42,16 @@ using XCEngine::UI::UIPoint;
|
||||
using XCEngine::UI::UIPointerButton;
|
||||
using XCEngine::UI::UIRect;
|
||||
using XCEngine::UI::Editor::AppendUIEditorShellInteraction;
|
||||
using XCEngine::UI::Editor::BuildDefaultEditorShellAsset;
|
||||
using XCEngine::UI::Editor::BuildDefaultUIEditorWorkspaceSession;
|
||||
using XCEngine::UI::Editor::BuildEditorShellShortcutManager;
|
||||
using XCEngine::UI::Editor::BuildDefaultUIEditorWorkspaceController;
|
||||
using XCEngine::UI::Editor::BuildUIEditorWorkspacePanel;
|
||||
using XCEngine::UI::Editor::BuildUIEditorWorkspaceSplit;
|
||||
using XCEngine::UI::Editor::BuildUIEditorWorkspaceTabStack;
|
||||
using XCEngine::UI::Editor::CollectUIEditorWorkspaceVisiblePanels;
|
||||
using XCEngine::UI::Editor::EditorShellAsset;
|
||||
using XCEngine::UI::Editor::EditorShellAssetValidationResult;
|
||||
using XCEngine::UI::Editor::FindUIEditorWorkspaceViewportPresentationFrame;
|
||||
using XCEngine::UI::Editor::GetUIEditorCommandDispatchStatusName;
|
||||
using XCEngine::UI::Editor::UpdateUIEditorShellInteraction;
|
||||
@@ -64,6 +71,7 @@ using XCEngine::UI::Editor::UIEditorShellInteractionFrame;
|
||||
using XCEngine::UI::Editor::UIEditorShellInteractionResult;
|
||||
using XCEngine::UI::Editor::UIEditorShellInteractionServices;
|
||||
using XCEngine::UI::Editor::UIEditorShellInteractionState;
|
||||
using XCEngine::UI::Editor::UIEditorShortcutManager;
|
||||
using XCEngine::UI::Editor::UIEditorViewportInputBridgeFrame;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceCommandKind;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceController;
|
||||
@@ -71,6 +79,7 @@ using XCEngine::UI::Editor::UIEditorWorkspaceModel;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspacePanelPresentationModel;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceSession;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceSplitAxis;
|
||||
using XCEngine::UI::Editor::ValidateEditorShellAsset;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorStatusBarSegment;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorStatusBarSlot;
|
||||
using XCEngine::UI::Widgets::UIPopupDismissReason;
|
||||
@@ -380,6 +389,59 @@ UIEditorMenuModel BuildMenuModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
EditorShellAsset BuildScenarioShellAsset() {
|
||||
EditorShellAsset asset = BuildDefaultEditorShellAsset(ResolveRepoRootPath());
|
||||
asset.panelRegistry = BuildPanelRegistry();
|
||||
asset.workspace = BuildWorkspace();
|
||||
asset.workspaceSession =
|
||||
BuildDefaultUIEditorWorkspaceSession(asset.panelRegistry, asset.workspace);
|
||||
|
||||
asset.shellDefinition = {};
|
||||
asset.shellDefinition.menuModel = BuildMenuModel();
|
||||
asset.shellDefinition.statusSegments = {
|
||||
UIEditorStatusBarSegment{
|
||||
"mode",
|
||||
"Shell Contract",
|
||||
UIEditorStatusBarSlot::Leading,
|
||||
{},
|
||||
true,
|
||||
true,
|
||||
122.0f
|
||||
},
|
||||
UIEditorStatusBarSegment{
|
||||
"active",
|
||||
asset.workspace.activePanelId.empty()
|
||||
? std::string("(none)")
|
||||
: asset.workspace.activePanelId,
|
||||
UIEditorStatusBarSlot::Trailing,
|
||||
{},
|
||||
true,
|
||||
true,
|
||||
120.0f
|
||||
}
|
||||
};
|
||||
|
||||
asset.shellDefinition.workspacePresentations.reserve(asset.panelRegistry.panels.size());
|
||||
for (const auto& descriptor : asset.panelRegistry.panels) {
|
||||
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 Interaction";
|
||||
presentation.viewportShellModel.spec.chrome.showTopBar = true;
|
||||
presentation.viewportShellModel.spec.chrome.showBottomBar = true;
|
||||
presentation.viewportShellModel.frame.hasTexture = false;
|
||||
presentation.viewportShellModel.frame.statusText =
|
||||
"这里只验证 Editor 根壳交互,不接旧 editor 业务面板。";
|
||||
}
|
||||
asset.shellDefinition.workspacePresentations.push_back(std::move(presentation));
|
||||
}
|
||||
|
||||
asset.shortcutAsset.commandRegistry = BuildCommandRegistry();
|
||||
return asset;
|
||||
}
|
||||
|
||||
class ScenarioApp {
|
||||
public:
|
||||
int Run(HINSTANCE hInstance, int nCmdShow);
|
||||
@@ -406,9 +468,11 @@ private:
|
||||
NativeRenderer m_renderer = {};
|
||||
AutoScreenshotController m_autoScreenshot = {};
|
||||
std::filesystem::path m_captureRoot = {};
|
||||
EditorShellAsset m_shellAsset = {};
|
||||
EditorShellAssetValidationResult m_assetValidation = {};
|
||||
UIEditorWorkspaceController m_controller = {};
|
||||
UIEditorCommandDispatcher m_commandDispatcher = {};
|
||||
UIEditorMenuModel m_menuModel = {};
|
||||
UIEditorShortcutManager m_shortcutManager = {};
|
||||
UIEditorShellInteractionServices m_shellServices = {};
|
||||
UIEditorShellInteractionState m_interactionState = {};
|
||||
UIEditorShellInteractionFrame m_cachedFrame = {};
|
||||
std::vector<UIInputEvent> m_pendingInputEvents = {};
|
||||
@@ -623,12 +687,26 @@ void ScenarioApp::ResetScenario() {
|
||||
if (GetCapture() == m_hwnd) {
|
||||
ReleaseCapture();
|
||||
}
|
||||
m_controller = BuildDefaultUIEditorWorkspaceController(BuildPanelRegistry(), BuildWorkspace());
|
||||
m_commandDispatcher = UIEditorCommandDispatcher(BuildCommandRegistry());
|
||||
m_menuModel = BuildMenuModel();
|
||||
m_shellAsset = BuildScenarioShellAsset();
|
||||
m_shellAsset.captureRootPath = m_captureRoot;
|
||||
m_assetValidation = ValidateEditorShellAsset(m_shellAsset);
|
||||
m_controller = UIEditorWorkspaceController(
|
||||
m_shellAsset.panelRegistry,
|
||||
m_shellAsset.workspace,
|
||||
m_shellAsset.workspaceSession);
|
||||
m_shortcutManager = BuildEditorShellShortcutManager(m_shellAsset);
|
||||
m_shellServices = {};
|
||||
m_shellServices.commandDispatcher = &m_shortcutManager.GetCommandDispatcher();
|
||||
m_shellServices.shortcutManager = &m_shortcutManager;
|
||||
m_interactionState = {};
|
||||
m_cachedFrame = {};
|
||||
m_pendingInputEvents.clear();
|
||||
if (!m_assetValidation.IsValid()) {
|
||||
m_lastStatus = "Invalid";
|
||||
m_lastMessage = "场景 asset contract 非法: " + m_assetValidation.message;
|
||||
m_lastColor = kDanger;
|
||||
return;
|
||||
}
|
||||
m_lastStatus = "Ready";
|
||||
m_lastMessage = "等待交互。这里只验证 Editor 根壳统一交互 contract,不接旧 editor 业务。";
|
||||
m_lastColor = kWarning;
|
||||
@@ -732,42 +810,14 @@ void ScenarioApp::ApplyHostCaptureRequests(const UIEditorShellInteractionResult&
|
||||
}
|
||||
|
||||
UIEditorShellInteractionDefinition ScenarioApp::BuildInteractionDefinition() const {
|
||||
UIEditorShellInteractionDefinition definition = {};
|
||||
definition.menuModel = m_menuModel;
|
||||
definition.statusSegments = {
|
||||
UIEditorStatusBarSegment{
|
||||
"mode",
|
||||
"Shell Contract",
|
||||
UIEditorStatusBarSlot::Leading,
|
||||
{},
|
||||
true,
|
||||
true,
|
||||
122.0f
|
||||
},
|
||||
UIEditorStatusBarSegment{
|
||||
"active",
|
||||
m_controller.GetWorkspace().activePanelId.empty()
|
||||
UIEditorShellInteractionDefinition definition = m_shellAsset.shellDefinition;
|
||||
for (UIEditorStatusBarSegment& segment : definition.statusSegments) {
|
||||
if (segment.segmentId == "active") {
|
||||
segment.label = m_controller.GetWorkspace().activePanelId.empty()
|
||||
? std::string("(none)")
|
||||
: m_controller.GetWorkspace().activePanelId,
|
||||
UIEditorStatusBarSlot::Trailing,
|
||||
{},
|
||||
true,
|
||||
true,
|
||||
120.0f
|
||||
: m_controller.GetWorkspace().activePanelId;
|
||||
}
|
||||
};
|
||||
|
||||
UIEditorWorkspacePanelPresentationModel presentation = {};
|
||||
presentation.panelId = "scene";
|
||||
presentation.kind = UIEditorPanelPresentationKind::ViewportShell;
|
||||
presentation.viewportShellModel.spec.chrome.title = "Scene";
|
||||
presentation.viewportShellModel.spec.chrome.subtitle = "Editor Shell Interaction";
|
||||
presentation.viewportShellModel.spec.chrome.showTopBar = true;
|
||||
presentation.viewportShellModel.spec.chrome.showBottomBar = true;
|
||||
presentation.viewportShellModel.frame.hasTexture = false;
|
||||
presentation.viewportShellModel.frame.statusText =
|
||||
"这里只验证 Editor 根壳交互,不接旧 editor 业务面板。";
|
||||
definition.workspacePresentations = { presentation };
|
||||
}
|
||||
return definition;
|
||||
}
|
||||
|
||||
@@ -783,7 +833,7 @@ void ScenarioApp::SetInteractionResult(const UIEditorShellInteractionResult& res
|
||||
|
||||
if (result.commandTriggered) {
|
||||
m_lastStatus = "Triggered";
|
||||
m_lastMessage = "命令已命中,但当前场景没有把 dispatcher 接到 root shell。";
|
||||
m_lastMessage = "命令已命中,但本帧没有完成 dispatch。请检查 shell services / asset contract。";
|
||||
m_lastColor = kWarning;
|
||||
return;
|
||||
}
|
||||
@@ -866,15 +916,13 @@ void ScenarioApp::SetDispatchResult(const UIEditorCommandDispatchResult& result)
|
||||
void ScenarioApp::RenderFrame() {
|
||||
UpdateLayout();
|
||||
const UIEditorShellInteractionDefinition definition = BuildInteractionDefinition();
|
||||
UIEditorShellInteractionServices services = {};
|
||||
services.commandDispatcher = &m_commandDispatcher;
|
||||
m_cachedFrame = UpdateUIEditorShellInteraction(
|
||||
m_interactionState,
|
||||
m_controller,
|
||||
m_shellRect,
|
||||
definition,
|
||||
m_pendingInputEvents,
|
||||
services);
|
||||
m_shellServices);
|
||||
m_pendingInputEvents.clear();
|
||||
ApplyHostCaptureRequests(m_cachedFrame.result);
|
||||
SetInteractionResult(m_cachedFrame.result);
|
||||
@@ -916,6 +964,11 @@ void ScenarioApp::RenderFrame() {
|
||||
addStateLine("Open Root", m_cachedFrame.openRootMenuId.empty() ? "(none)" : m_cachedFrame.openRootMenuId, kTextPrimary);
|
||||
addStateLine("Popup Chain", JoinPopupChainIds(m_interactionState), kTextPrimary, 11.0f);
|
||||
addStateLine("Submenu Path", JoinSubmenuPathIds(m_interactionState), kTextPrimary, 11.0f);
|
||||
addStateLine(
|
||||
"Asset Validation",
|
||||
m_assetValidation.IsValid() ? "OK" : m_assetValidation.message,
|
||||
m_assetValidation.IsValid() ? kSuccess : kDanger,
|
||||
11.0f);
|
||||
addStateLine("Selected Presentation", selectedPresentation, kTextPrimary, 11.0f);
|
||||
addStateLine("Active Panel", m_controller.GetWorkspace().activePanelId.empty() ? "(none)" : m_controller.GetWorkspace().activePanelId, kTextPrimary, 11.0f);
|
||||
addStateLine("Focused", FormatBool(m_cachedFrame.focused), m_cachedFrame.focused ? kSuccess : kTextMuted);
|
||||
|
||||
Reference in New Issue
Block a user