Refactor editor workspace panel runtime boundary

This commit is contained in:
2026-04-27 01:58:23 +08:00
parent 672d3f75d3
commit 31df10ffb6
15 changed files with 851 additions and 345 deletions

View File

@@ -48,6 +48,10 @@ change.
passes.
- `app/Features/` contains user-facing panels and editor tools: Hierarchy,
Scene viewport, Inspector, Project, Console, Color Picker, and component UI.
- `app/Features/EditorWorkspacePanelRegistry.*` is the single composition
entry point for workspace panel runtimes. It owns the concrete workspace
panel adapters and keeps `app/Composition/**` from depending on individual
feature-panel classes.
- `app/Project/`, `app/Scene/`, and `app/State/` hold application services that
panels should use instead of owning global state themselves.
@@ -104,10 +108,9 @@ change.
through to the authoritative window workspace state; a copied controller is
only a preview.
- `EditorShellRuntime` owns per-window interactive runtime state: viewport host
service, built-in icons, hosted panels, scene viewport feature, shell
interaction state/frame, splitter correction state, trace entries, draw
composer, interaction engine, hosted panel coordinator, and session
coordinator.
service, built-in icons, the workspace panel runtime set, shell interaction
state/frame, splitter correction state, trace entries, draw composer,
interaction engine, hosted panel coordinator, and session coordinator.
- `EditorWindowRuntimeController` owns the content controller, render runtime,
screenshot controller, title-bar logo texture, text measurer access, DPI
scale, and frame-rate display.
@@ -178,17 +181,27 @@ inside pure shell/widget code.
capture root, and status-bar definitions.
- Panel IDs are centralized in `EditorPanelIds.h`; prefer these constants over
raw string literals in app code.
- Workspace panels are adapted behind `EditorWorkspacePanelRuntimeSet`.
Composition code should ask that runtime set to initialize, prepare command
routes, update, draw, expose cursor/capture state, and collect frame events
instead of directly naming `HierarchyPanel`, `ProjectPanel`, `InspectorPanel`,
`ConsolePanel`, or `SceneViewportFeature`.
- Hosted panels receive mounted bounds and filtered input through
`UIEditorHostedPanelDispatchFrame`.
`UIEditorHostedPanelDispatchFrame`; concrete workspace-panel adapters resolve
their own dispatch entries from that frame.
- `EditorShellHostedPanelCoordinator` filters hosted-panel input when shell
capture owns the pointer stream, updates scene viewport state, wires app
services into panels, dispatches hosted panels, and syncs command focus.
capture owns the pointer stream, then updates `EditorWorkspacePanelRuntimeSet`.
Concrete adapters wire app services into their panels and the runtime set
syncs command focus before after-focus panels such as Console read session
state.
- `EditorHostCommandBridge` routes host commands to focused edit routes,
project asset routes, scene routes, inspector routes, workspace commands, or
the app exit handler.
- `WorkspaceEventSync` is the current place where hierarchy/project frame
events update app status, selection-backed session state, scene-open requests,
and runtime trace entries.
- `WorkspaceEventSync` consumes generic `EditorWorkspacePanelFrameEvent`
entries from the workspace panel runtime set. Concrete hierarchy/project
event formatting lives behind the feature registry, while this sync layer
owns selection-backed session state, scene-open requests, status updates, and
runtime trace entries.
## Viewport Rendering
@@ -212,13 +225,14 @@ inside pure shell/widget code.
- Add reusable widgets, docking/workspace behavior, shell interaction, or field
logic to `include/XCEditor/**` and `src/**`, with unit coverage in
`tests/UI/Editor/unit`.
- Add product editor behavior to `app/Features/**`, then wire it through
`EditorShellAssetBuilder`, `EditorShellRuntime`,
`EditorShellHostedPanelCoordinator`, `EditorShellDrawComposer`, command
routing, and app state services as needed.
- Add product editor behavior to `app/Features/**`. Workspace panels must
enter composition through `EditorWorkspacePanelRegistry.*` and the
`EditorWorkspacePanel` adapter interface; do not include concrete feature
panel headers from `EditorShellRuntime`, `EditorShellHostedPanelCoordinator`,
`EditorShellDrawComposer`, or `EditorShellSessionCoordinator`.
- Add new workspace panels by updating the panel ID constants, panel registry,
default workspace model, shell presentation, content dispatch, drawing, and
command/menu entries together.
default workspace model, shell presentation, workspace panel runtime adapter,
and command/menu entries together.
- Add new utility windows through `EditorUtilityWindowKind`,
`EditorUtilityWindowRegistry`, an `EditorUtilityWindowPanel`, and the
context/request path. Do not model utility windows as workspace panels unless
@@ -321,3 +335,7 @@ ownership rule.
remains a single `XCEditor` target with output name `XCEngine`, and
manual-validation hosts use the shared Core UI validation host instead of an
editor app host target.
- Workspace panel runtimes are now behind `EditorWorkspacePanelRuntimeSet` and
`EditorWorkspacePanelRegistry.*`. `app/Composition/**` no longer directly
owns or dispatches concrete Console, Hierarchy, Inspector, Project, or Scene
panel classes.

View File

@@ -240,6 +240,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
set(XCUI_EDITOR_APP_FEATURE_SOURCES
app/Features/Console/ConsolePanel.cpp
app/Features/ColorPicker/ColorPickerPanel.cpp
app/Features/EditorWorkspacePanelRegistry.cpp
app/Features/Hierarchy/HierarchyModel.cpp
app/Features/Hierarchy/HierarchyPanel.cpp
app/Features/Inspector/AddComponentPanel.cpp

View File

@@ -1,10 +1,6 @@
#include "Composition/EditorShellDrawComposer.h"
#include "Features/Console/ConsolePanel.h"
#include "Features/Hierarchy/HierarchyPanel.h"
#include "Features/Inspector/InspectorPanel.h"
#include "Features/Project/ProjectPanel.h"
#include "Features/Scene/SceneViewportFeature.h"
#include "Features/EditorWorkspacePanelRegistry.h"
#include "Rendering/Assets/BuiltInIcons.h"
#include <XCEditor/Foundation/UIEditorTheme.h>
@@ -146,26 +142,7 @@ void EditorShellDrawComposer::Append(
palette.shellPalette,
metrics.shellMetrics);
});
AppendDrawPacket(
drawData,
"XCEditorPanel.Console",
[&](UIDrawList& drawList) { context.consolePanel.Append(drawList); });
AppendDrawPacket(
drawData,
"XCEditorPanel.Hierarchy",
[&](UIDrawList& drawList) { context.hierarchyPanel.Append(drawList); });
AppendDrawPacket(
drawData,
"XCEditorPanel.Inspector",
[&](UIDrawList& drawList) { context.inspectorPanel.Append(drawList); });
AppendDrawPacket(
drawData,
"XCEditorPanel.Project",
[&](UIDrawList& drawList) { context.projectPanel.Append(drawList); });
AppendDrawPacket(
drawData,
"XCEditorPanel.SceneOverlay",
[&](UIDrawList& drawList) { context.sceneViewportFeature.Append(drawList); });
context.workspacePanels.AppendDrawPackets(drawData);
AppendDrawPacket(
drawData,
"XCEditorShell.Compose.Overlay",

View File

@@ -12,21 +12,13 @@ struct UIEditorShellInteractionState;
namespace XCEngine::UI::Editor::App {
class BuiltInIcons;
class ConsolePanel;
class HierarchyPanel;
class InspectorPanel;
class ProjectPanel;
class SceneViewportFeature;
class EditorWorkspacePanelRuntimeSet;
struct EditorShellDrawComposerContext {
const UIEditorShellInteractionFrame& shellFrame;
const UIEditorShellInteractionState& shellInteractionState;
const BuiltInIcons& builtInIcons;
const ConsolePanel& consolePanel;
const HierarchyPanel& hierarchyPanel;
const InspectorPanel& inspectorPanel;
const ProjectPanel& projectPanel;
const SceneViewportFeature& sceneViewportFeature;
const EditorWorkspacePanelRuntimeSet& workspacePanels;
};
class EditorShellDrawComposer final {

View File

@@ -1,12 +1,6 @@
#include "Composition/EditorShellHostedPanelCoordinator.h"
#include "Composition/EditorContext.h"
#include "Composition/EditorPanelIds.h"
#include "Features/Console/ConsolePanel.h"
#include "Features/Hierarchy/HierarchyPanel.h"
#include "Features/Inspector/InspectorPanel.h"
#include "Features/Project/ProjectPanel.h"
#include "Features/Scene/SceneViewportFeature.h"
#include "Features/EditorWorkspacePanelRegistry.h"
#include <XCEditor/Panels/UIEditorHostedPanelDispatch.h>
#include <XCEditor/Shell/UIEditorShellCapturePolicy.h>
@@ -14,23 +8,6 @@
namespace XCEngine::UI::Editor::App {
namespace {
const UIEditorHostedPanelDispatchEntry& ResolveHostedPanelDispatchEntry(
const UIEditorHostedPanelDispatchFrame& dispatchFrame,
std::string_view panelId) {
static const UIEditorHostedPanelDispatchEntry kEmptyEntry = {};
if (const UIEditorHostedPanelDispatchEntry* entry =
FindUIEditorHostedPanelDispatchEntry(dispatchFrame, panelId);
entry != nullptr) {
return *entry;
}
return kEmptyEntry;
}
} // namespace
void EditorShellHostedPanelCoordinator::Update(
const EditorShellHostedPanelCoordinatorContext& context) const {
const bool shellOwnsHostedContentPointerStream =
@@ -42,39 +19,13 @@ void EditorShellHostedPanelCoordinator::Update(
context.inputEvents,
shellOwnsHostedContentPointerStream);
const UIEditorHostedPanelDispatchFrame& hostedPanelDispatchFrame =
context.shellFrame.hostedPanelDispatchFrame;
const UIEditorHostedPanelDispatchEntry& hierarchyDispatchEntry =
ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kHierarchyPanelId);
const UIEditorHostedPanelDispatchEntry& projectDispatchEntry =
ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kProjectPanelId);
const UIEditorHostedPanelDispatchEntry& inspectorDispatchEntry =
ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kInspectorPanelId);
const UIEditorHostedPanelDispatchEntry& consoleDispatchEntry =
ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kConsolePanelId);
context.sceneViewportFeature.Update(
context.context.GetSceneRuntime(),
context.shellInteractionState.workspaceInteractionState.composeState,
context.shellFrame.workspaceInteractionFrame.composeFrame);
context.projectPanel.SetProjectRuntime(&context.context.GetProjectRuntime());
context.projectPanel.SetCommandFocusService(&context.context.GetCommandFocusService());
context.projectPanel.SetSystemInteractionHost(context.context.GetSystemInteractionHost());
context.inspectorPanel.SetCommandFocusService(&context.context.GetCommandFocusService());
context.hierarchyPanel.Update(
hierarchyDispatchEntry,
hostedContentEvents);
context.projectPanel.Update(
projectDispatchEntry,
hostedContentEvents);
context.inspectorPanel.Update(
context.context,
inspectorDispatchEntry,
hostedContentEvents);
context.context.SyncSessionFromCommandFocusService();
context.consolePanel.Update(
context.context.GetSession(),
consoleDispatchEntry);
context.workspacePanels.Update(
EditorWorkspacePanelUpdateContext{
.context = context.context,
.shellFrame = context.shellFrame,
.shellInteractionState = context.shellInteractionState,
.hostedContentEvents = hostedContentEvents,
});
}
} // namespace XCEngine::UI::Editor::App

View File

@@ -17,12 +17,8 @@ struct UIEditorShellInteractionState;
namespace XCEngine::UI::Editor::App {
class ConsolePanel;
class EditorContext;
class HierarchyPanel;
class InspectorPanel;
class ProjectPanel;
class SceneViewportFeature;
class EditorWorkspacePanelRuntimeSet;
struct EditorShellHostedPanelCoordinatorContext {
EditorContext& context;
@@ -30,11 +26,7 @@ struct EditorShellHostedPanelCoordinatorContext {
UIEditorShellInteractionState& shellInteractionState;
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents;
bool shellInteractiveCaptureActive = false;
ConsolePanel& consolePanel;
HierarchyPanel& hierarchyPanel;
InspectorPanel& inspectorPanel;
ProjectPanel& projectPanel;
SceneViewportFeature& sceneViewportFeature;
EditorWorkspacePanelRuntimeSet& workspacePanels;
};
class EditorShellHostedPanelCoordinator final {

View File

@@ -2,7 +2,6 @@
#include "Rendering/Host/UiTextureHost.h"
#include "Rendering/Host/ViewportRenderHost.h"
#include "Composition/EditorContext.h"
#include "Composition/EditorPanelIds.h"
#include <XCEditor/Shell/UIEditorShellCapturePolicy.h>
#include <XCEngine/Rendering/RenderContext.h>
@@ -14,16 +13,15 @@ void EditorShellRuntime::Initialize(
UIEditorTextMeasurer& textMeasurer) {
m_textureHost = &textureHost;
m_builtInIcons.Initialize(textureHost);
m_sceneViewportFeature.Initialize(
repoRoot,
textureHost,
&m_builtInIcons,
m_viewportHostService);
m_hierarchyPanel.SetBuiltInIcons(&m_builtInIcons);
m_hierarchyPanel.SetTextMeasurer(&textMeasurer);
m_projectPanel.SetBuiltInIcons(&m_builtInIcons);
m_projectPanel.SetTextMeasurer(&textMeasurer);
m_hierarchyPanel.Initialize();
m_workspacePanels = CreateEditorWorkspacePanelRuntimeSet();
m_workspacePanels.Initialize(
EditorWorkspacePanelInitializationContext{
.repoRoot = repoRoot,
.textureHost = textureHost,
.textMeasurer = textMeasurer,
.builtInIcons = m_builtInIcons,
.viewportHostService = m_viewportHostService,
});
}
void EditorShellRuntime::AttachViewportWindowRenderer(Rendering::Host::ViewportRenderHost& renderer) {
@@ -43,12 +41,17 @@ void EditorShellRuntime::Shutdown() {
m_shellInteractionState = {};
m_splitterDragCorrectionState = {};
m_traceEntries.clear();
m_sceneEditCommandRoute = {};
if (m_textureHost != nullptr) {
m_sceneViewportFeature.Shutdown(*m_textureHost, m_viewportHostService);
m_workspacePanels.Shutdown(
EditorWorkspacePanelShutdownContext{
.textureHost = *m_textureHost,
.viewportHostService = m_viewportHostService,
});
m_workspacePanels = {};
m_builtInIcons.Shutdown();
m_textureHost = nullptr;
} else {
m_workspacePanels = {};
m_builtInIcons.Shutdown();
}
m_viewportHostService.Shutdown();
@@ -59,9 +62,7 @@ void EditorShellRuntime::ResetInteractionState() {
m_shellInteractionState = {};
m_splitterDragCorrectionState = {};
m_traceEntries.clear();
m_sceneViewportFeature.ResetInteractionState();
m_hierarchyPanel.ResetInteractionState();
m_projectPanel.ResetInteractionState();
m_workspacePanels.ResetInteractionState();
}
const UIEditorShellInteractionFrame& EditorShellRuntime::GetShellFrame() const {
@@ -91,8 +92,8 @@ void EditorShellRuntime::ClearExternalDockHostDropPreview() {
.dockHostState.dropPreview = {};
}
ProjectPanel::CursorKind EditorShellRuntime::GetHostedContentCursorKind() const {
return m_projectPanel.GetCursorKind();
EditorWorkspacePanelCursorKind EditorShellRuntime::GetHostedContentCursorKind() const {
return m_workspacePanels.GetHostedContentCursorKind();
}
Widgets::UIEditorDockHostCursorKind EditorShellRuntime::GetDockCursorKind() const {
@@ -121,8 +122,7 @@ UIEditorDockHostTabDropTarget EditorShellRuntime::ResolveDockTabDropTarget(
}
bool EditorShellRuntime::HasHostedContentCapture() const {
return m_hierarchyPanel.HasActivePointerCapture() ||
m_projectPanel.HasActivePointerCapture();
return m_workspacePanels.HasActivePointerCapture();
}
bool EditorShellRuntime::HasShellInteractiveCapture() const {
@@ -148,11 +148,7 @@ void EditorShellRuntime::Append(::XCEngine::UI::UIDrawData& drawData) const {
.shellFrame = m_shellFrame,
.shellInteractionState = m_shellInteractionState,
.builtInIcons = m_builtInIcons,
.consolePanel = m_consolePanel,
.hierarchyPanel = m_hierarchyPanel,
.inspectorPanel = m_inspectorPanel,
.projectPanel = m_projectPanel,
.sceneViewportFeature = m_sceneViewportFeature,
.workspacePanels = m_workspacePanels,
},
drawData);
}
@@ -178,11 +174,7 @@ void EditorShellRuntime::Update(
.workspaceController = workspaceController,
.captureText = captureText,
.shellVariant = shellVariant,
.hierarchyPanel = m_hierarchyPanel,
.inspectorPanel = m_inspectorPanel,
.projectPanel = m_projectPanel,
.sceneEditCommandRoute = m_sceneEditCommandRoute,
.sceneViewportFeature = m_sceneViewportFeature,
.workspacePanels = m_workspacePanels,
});
};
m_interactionEngine.Update(
@@ -210,16 +202,11 @@ void EditorShellRuntime::Update(
.shellInteractionState = m_shellInteractionState,
.inputEvents = inputEvents,
.shellInteractiveCaptureActive = HasShellInteractiveCapture(),
.consolePanel = m_consolePanel,
.hierarchyPanel = m_hierarchyPanel,
.inspectorPanel = m_inspectorPanel,
.projectPanel = m_projectPanel,
.sceneViewportFeature = m_sceneViewportFeature,
.workspacePanels = m_workspacePanels,
});
m_traceEntries = SyncWorkspaceEvents(
context,
m_hierarchyPanel.GetFrameEvents(),
m_projectPanel.GetFrameEvents());
m_workspacePanels.CollectFrameEvents());
}
} // namespace XCEngine::UI::Editor::App

View File

@@ -5,12 +5,7 @@
#include "Composition/EditorShellInteractionEngine.h"
#include "Composition/EditorShellSessionCoordinator.h"
#include "Composition/EditorShellVariant.h"
#include "Features/Console/ConsolePanel.h"
#include "Features/Hierarchy/HierarchyPanel.h"
#include "Features/Inspector/InspectorPanel.h"
#include "Features/Project/ProjectPanel.h"
#include "Features/Scene/SceneEditCommandRoute.h"
#include "Features/Scene/SceneViewportFeature.h"
#include "Features/EditorWorkspacePanelRegistry.h"
#include "Rendering/Assets/BuiltInIcons.h"
#include "Rendering/Viewport/ViewportHostService.h"
#include "Composition/WorkspaceEventSync.h"
@@ -82,7 +77,7 @@ public:
const Widgets::UIEditorDockHostDropPreviewState& preview);
void ClearExternalDockHostDropPreview();
ProjectPanel::CursorKind GetHostedContentCursorKind() const;
EditorWorkspacePanelCursorKind GetHostedContentCursorKind() const;
Widgets::UIEditorDockHostCursorKind GetDockCursorKind() const;
bool TryResolveDockTabDragHotspot(
std::string_view nodeId,
@@ -97,14 +92,9 @@ public:
private:
ViewportHostService m_viewportHostService = {};
SceneViewportFeature m_sceneViewportFeature = {};
BuiltInIcons m_builtInIcons = {};
Rendering::Host::UiTextureHost* m_textureHost = nullptr;
ConsolePanel m_consolePanel = {};
HierarchyPanel m_hierarchyPanel = {};
InspectorPanel m_inspectorPanel = {};
ProjectPanel m_projectPanel = {};
SceneEditCommandRoute m_sceneEditCommandRoute = {};
EditorWorkspacePanelRuntimeSet m_workspacePanels = {};
UIEditorShellInteractionState m_shellInteractionState = {};
UIEditorShellInteractionFrame m_shellFrame = {};
std::vector<WorkspaceTraceEntry> m_traceEntries = {};

View File

@@ -1,29 +1,20 @@
#include "Composition/EditorShellSessionCoordinator.h"
#include "Composition/EditorContext.h"
#include "Features/Hierarchy/HierarchyPanel.h"
#include "Features/Inspector/InspectorPanel.h"
#include "Features/Project/ProjectPanel.h"
#include "Features/Scene/SceneEditCommandRoute.h"
#include "Features/Scene/SceneViewportFeature.h"
#include "Features/EditorWorkspacePanelRegistry.h"
namespace XCEngine::UI::Editor::App {
UIEditorShellInteractionDefinition EditorShellSessionCoordinator::PrepareShellDefinition(
const EditorShellSessionCoordinatorContext& context) const {
context.hierarchyPanel.SetSceneRuntime(&context.context.GetSceneRuntime());
context.hierarchyPanel.SetCommandFocusService(&context.context.GetCommandFocusService());
context.sceneEditCommandRoute.BindSceneRuntime(&context.context.GetSceneRuntime());
context.sceneViewportFeature.SetCommandFocusService(
&context.context.GetCommandFocusService());
// Keep the previous render request available for readback-based picking during
// this update, then refresh it again after camera/navigation state changes.
context.sceneViewportFeature.SyncRenderRequest(context.context.GetSceneRuntime());
context.workspacePanels.PrepareForShellDefinition(
context.context,
context.workspaceController);
context.context.BindEditCommandRoutes(
&context.hierarchyPanel,
&context.projectPanel,
&context.sceneEditCommandRoute,
&context.inspectorPanel);
context.workspacePanels.FindCommandRoute(EditorActionRoute::Hierarchy),
context.workspacePanels.FindCommandRoute(EditorActionRoute::Project),
context.workspacePanels.FindCommandRoute(EditorActionRoute::Scene),
context.workspacePanels.FindCommandRoute(EditorActionRoute::Inspector));
context.context.SyncSessionFromWorkspace(context.workspaceController);
return context.context.BuildShellDefinition(
context.workspaceController,

View File

@@ -10,22 +10,14 @@
namespace XCEngine::UI::Editor::App {
class EditorContext;
class HierarchyPanel;
class InspectorPanel;
class ProjectPanel;
class SceneEditCommandRoute;
class SceneViewportFeature;
class EditorWorkspacePanelRuntimeSet;
struct EditorShellSessionCoordinatorContext {
EditorContext& context;
UIEditorWorkspaceController& workspaceController;
std::string_view captureText;
EditorShellVariant shellVariant = EditorShellVariant::Primary;
HierarchyPanel& hierarchyPanel;
InspectorPanel& inspectorPanel;
ProjectPanel& projectPanel;
SceneEditCommandRoute& sceneEditCommandRoute;
SceneViewportFeature& sceneViewportFeature;
EditorWorkspacePanelRuntimeSet& workspacePanels;
};
class EditorShellSessionCoordinator final {

View File

@@ -2,145 +2,13 @@
#include "Composition/EditorContext.h"
#include "Composition/EditorPanelIds.h"
#include <sstream>
#include <utility>
namespace XCEngine::UI::Editor::App {
namespace {
std::string_view DescribeProjectItemKind(ProjectBrowserModel::ItemKind kind) {
switch (kind) {
case ProjectBrowserModel::ItemKind::Folder:
return "Folder";
case ProjectBrowserModel::ItemKind::Scene:
return "Scene";
case ProjectBrowserModel::ItemKind::Model:
return "Model";
case ProjectBrowserModel::ItemKind::Material:
return "Material";
case ProjectBrowserModel::ItemKind::Texture:
return "Texture";
case ProjectBrowserModel::ItemKind::Script:
return "Script";
case ProjectBrowserModel::ItemKind::File:
default:
return "File";
}
}
std::string DescribeProjectPanelEvent(const ProjectPanel::Event& event) {
std::ostringstream stream = {};
switch (event.kind) {
case ProjectPanel::EventKind::AssetSelected:
stream << "AssetSelected";
break;
case ProjectPanel::EventKind::AssetSelectionCleared:
stream << "AssetSelectionCleared";
break;
case ProjectPanel::EventKind::FolderNavigated:
stream << "FolderNavigated";
break;
case ProjectPanel::EventKind::AssetOpened:
stream << "AssetOpened";
break;
case ProjectPanel::EventKind::RenameRequested:
stream << "RenameRequested";
break;
case ProjectPanel::EventKind::ContextMenuRequested:
stream << "ContextMenuRequested";
break;
case ProjectPanel::EventKind::None:
default:
stream << "None";
break;
}
stream << " source=";
switch (event.source) {
case ProjectPanel::EventSource::Tree:
stream << "Tree";
break;
case ProjectPanel::EventSource::Breadcrumb:
stream << "Breadcrumb";
break;
case ProjectPanel::EventSource::GridPrimary:
stream << "GridPrimary";
break;
case ProjectPanel::EventSource::GridDoubleClick:
stream << "GridDoubleClick";
break;
case ProjectPanel::EventSource::GridSecondary:
stream << "GridSecondary";
break;
case ProjectPanel::EventSource::GridDrag:
stream << "GridDrag";
break;
case ProjectPanel::EventSource::Command:
stream << "Command";
break;
case ProjectPanel::EventSource::Background:
stream << "Background";
break;
case ProjectPanel::EventSource::None:
default:
stream << "None";
break;
}
if (!event.itemId.empty()) {
stream << " item=" << event.itemId;
}
if (!event.displayName.empty()) {
stream << " label=" << event.displayName;
}
if (!event.itemId.empty()) {
stream << " kind=" << DescribeProjectItemKind(event.itemKind);
}
return stream.str();
}
std::string DescribeHierarchyPanelEvent(const HierarchyPanel::Event& event) {
std::ostringstream stream = {};
switch (event.kind) {
case HierarchyPanel::EventKind::SelectionChanged:
stream << "SelectionChanged";
break;
case HierarchyPanel::EventKind::Reparented:
stream << "Reparented";
break;
case HierarchyPanel::EventKind::MovedToRoot:
stream << "MovedToRoot";
break;
case HierarchyPanel::EventKind::RenameRequested:
stream << "RenameRequested";
break;
case HierarchyPanel::EventKind::None:
default:
stream << "None";
break;
}
if (!event.itemId.empty()) {
stream << " item=" << event.itemId;
}
if (!event.targetItemId.empty()) {
stream << " target=" << event.targetItemId;
}
if (!event.label.empty()) {
stream << " label=" << event.label;
}
return stream.str();
}
} // namespace
std::vector<WorkspaceTraceEntry> SyncWorkspaceEvents(
EditorContext& context,
const std::vector<HierarchyPanel::Event>& hierarchyPanelEvents,
const std::vector<ProjectPanel::Event>& projectPanelEvents) {
const std::vector<EditorWorkspacePanelFrameEvent>& panelEvents) {
std::vector<WorkspaceTraceEntry> entries = {};
context.SyncSessionFromSelectionService();
if (const std::optional<std::filesystem::path> scenePath =
@@ -150,16 +18,9 @@ std::vector<WorkspaceTraceEntry> SyncWorkspaceEvents(
context.SyncSessionFromSelectionService();
}
for (const HierarchyPanel::Event& event : hierarchyPanelEvents) {
const std::string message = DescribeHierarchyPanelEvent(event);
context.SetStatus("Hierarchy", message);
entries.push_back(WorkspaceTraceEntry{ std::string(kHierarchyPanelId), std::move(message) });
}
for (const ProjectPanel::Event& event : projectPanelEvents) {
const std::string message = DescribeProjectPanelEvent(event);
context.SetStatus("Project", message);
entries.push_back(WorkspaceTraceEntry{ std::string(kProjectPanelId), std::move(message) });
for (const EditorWorkspacePanelFrameEvent& event : panelEvents) {
context.SetStatus(event.status, event.message);
entries.push_back(WorkspaceTraceEntry{ event.traceChannel, event.message });
}
return entries;

View File

@@ -1,7 +1,6 @@
#pragma once
#include "Features/Hierarchy/HierarchyPanel.h"
#include "Features/Project/ProjectPanel.h"
#include "Features/EditorWorkspacePanelRegistry.h"
#include <string>
#include <vector>
@@ -17,8 +16,7 @@ struct WorkspaceTraceEntry {
std::vector<WorkspaceTraceEntry> SyncWorkspaceEvents(
EditorContext& context,
const std::vector<HierarchyPanel::Event>& hierarchyPanelEvents,
const std::vector<ProjectPanel::Event>& projectPanelEvents);
const std::vector<EditorWorkspacePanelFrameEvent>& panelEvents);
} // namespace XCEngine::UI::Editor::App

View File

@@ -0,0 +1,610 @@
#include "Features/EditorWorkspacePanelRegistry.h"
#include "Composition/EditorPanelIds.h"
#include "Features/Console/ConsolePanel.h"
#include "Features/Hierarchy/HierarchyPanel.h"
#include "Features/Inspector/InspectorPanel.h"
#include "Features/Project/ProjectPanel.h"
#include "Features/Scene/SceneEditCommandRoute.h"
#include "Features/Scene/SceneViewportFeature.h"
#include "Rendering/Assets/BuiltInIcons.h"
#include "Rendering/Viewport/ViewportHostService.h"
#include "Composition/EditorContext.h"
#include <XCEditor/Panels/UIEditorHostedPanelDispatch.h>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <utility>
namespace XCEngine::UI::Editor::App {
namespace {
constexpr int kSceneUpdatePriority = 0;
constexpr int kHierarchyUpdatePriority = 10;
constexpr int kProjectUpdatePriority = 20;
constexpr int kInspectorUpdatePriority = 30;
constexpr int kConsoleUpdatePriority = 40;
const UIEditorHostedPanelDispatchEntry& ResolveHostedPanelDispatchEntry(
const UIEditorHostedPanelDispatchFrame& dispatchFrame,
std::string_view panelId) {
static const UIEditorHostedPanelDispatchEntry kEmptyEntry = {};
if (const UIEditorHostedPanelDispatchEntry* entry =
FindUIEditorHostedPanelDispatchEntry(dispatchFrame, panelId);
entry != nullptr) {
return *entry;
}
return kEmptyEntry;
}
std::string_view DescribeProjectItemKind(ProjectBrowserModel::ItemKind kind) {
switch (kind) {
case ProjectBrowserModel::ItemKind::Folder:
return "Folder";
case ProjectBrowserModel::ItemKind::Scene:
return "Scene";
case ProjectBrowserModel::ItemKind::Model:
return "Model";
case ProjectBrowserModel::ItemKind::Material:
return "Material";
case ProjectBrowserModel::ItemKind::Texture:
return "Texture";
case ProjectBrowserModel::ItemKind::Script:
return "Script";
case ProjectBrowserModel::ItemKind::File:
default:
return "File";
}
}
std::string DescribeProjectPanelEvent(const ProjectPanel::Event& event) {
std::ostringstream stream = {};
switch (event.kind) {
case ProjectPanel::EventKind::AssetSelected:
stream << "AssetSelected";
break;
case ProjectPanel::EventKind::AssetSelectionCleared:
stream << "AssetSelectionCleared";
break;
case ProjectPanel::EventKind::FolderNavigated:
stream << "FolderNavigated";
break;
case ProjectPanel::EventKind::AssetOpened:
stream << "AssetOpened";
break;
case ProjectPanel::EventKind::RenameRequested:
stream << "RenameRequested";
break;
case ProjectPanel::EventKind::ContextMenuRequested:
stream << "ContextMenuRequested";
break;
case ProjectPanel::EventKind::None:
default:
stream << "None";
break;
}
stream << " source=";
switch (event.source) {
case ProjectPanel::EventSource::Tree:
stream << "Tree";
break;
case ProjectPanel::EventSource::Breadcrumb:
stream << "Breadcrumb";
break;
case ProjectPanel::EventSource::GridPrimary:
stream << "GridPrimary";
break;
case ProjectPanel::EventSource::GridDoubleClick:
stream << "GridDoubleClick";
break;
case ProjectPanel::EventSource::GridSecondary:
stream << "GridSecondary";
break;
case ProjectPanel::EventSource::GridDrag:
stream << "GridDrag";
break;
case ProjectPanel::EventSource::Command:
stream << "Command";
break;
case ProjectPanel::EventSource::Background:
stream << "Background";
break;
case ProjectPanel::EventSource::None:
default:
stream << "None";
break;
}
if (!event.itemId.empty()) {
stream << " item=" << event.itemId;
}
if (!event.displayName.empty()) {
stream << " label=" << event.displayName;
}
if (!event.itemId.empty()) {
stream << " kind=" << DescribeProjectItemKind(event.itemKind);
}
return stream.str();
}
std::string DescribeHierarchyPanelEvent(const HierarchyPanel::Event& event) {
std::ostringstream stream = {};
switch (event.kind) {
case HierarchyPanel::EventKind::SelectionChanged:
stream << "SelectionChanged";
break;
case HierarchyPanel::EventKind::Reparented:
stream << "Reparented";
break;
case HierarchyPanel::EventKind::MovedToRoot:
stream << "MovedToRoot";
break;
case HierarchyPanel::EventKind::RenameRequested:
stream << "RenameRequested";
break;
case HierarchyPanel::EventKind::None:
default:
stream << "None";
break;
}
if (!event.itemId.empty()) {
stream << " item=" << event.itemId;
}
if (!event.targetItemId.empty()) {
stream << " target=" << event.targetItemId;
}
if (!event.label.empty()) {
stream << " label=" << event.label;
}
return stream.str();
}
template<typename AppendFn>
void AppendDrawPacket(
::XCEngine::UI::UIDrawData& drawData,
std::string debugName,
AppendFn&& appendFn) {
::XCEngine::UI::UIDrawList drawList(std::move(debugName));
appendFn(drawList);
if (!drawList.Empty()) {
drawData.AddDrawList(std::move(drawList));
}
}
class ConsoleWorkspacePanel final : public EditorWorkspacePanel {
public:
std::string_view GetPanelId() const override {
return kConsolePanelId;
}
std::string_view GetDrawListId() const override {
return "XCEditorPanel.Console";
}
EditorActionRoute GetActionRoute() const override {
return EditorActionRoute::Console;
}
EditorWorkspacePanelUpdatePhase GetUpdatePhase() const override {
return EditorWorkspacePanelUpdatePhase::AfterCommandFocusSync;
}
int GetUpdatePriority() const override {
return kConsoleUpdatePriority;
}
void Update(const EditorWorkspacePanelUpdateContext& context) override {
m_panel.Update(
context.context.GetSession(),
ResolveHostedPanelDispatchEntry(
context.shellFrame.hostedPanelDispatchFrame,
GetPanelId()));
}
void Append(::XCEngine::UI::UIDrawList& drawList) const override {
m_panel.Append(drawList);
}
private:
ConsolePanel m_panel = {};
};
class HierarchyWorkspacePanel final : public EditorWorkspacePanel {
public:
std::string_view GetPanelId() const override {
return kHierarchyPanelId;
}
std::string_view GetDrawListId() const override {
return "XCEditorPanel.Hierarchy";
}
EditorActionRoute GetActionRoute() const override {
return EditorActionRoute::Hierarchy;
}
int GetUpdatePriority() const override {
return kHierarchyUpdatePriority;
}
void Initialize(const EditorWorkspacePanelInitializationContext& context) override {
m_panel.SetBuiltInIcons(&context.builtInIcons);
m_panel.SetTextMeasurer(&context.textMeasurer);
m_panel.Initialize();
}
void ResetInteractionState() override {
m_panel.ResetInteractionState();
}
void PrepareForShellDefinition(
EditorContext& context,
UIEditorWorkspaceController&) override {
m_panel.SetSceneRuntime(&context.GetSceneRuntime());
m_panel.SetCommandFocusService(&context.GetCommandFocusService());
}
void Update(const EditorWorkspacePanelUpdateContext& context) override {
m_panel.Update(
ResolveHostedPanelDispatchEntry(
context.shellFrame.hostedPanelDispatchFrame,
GetPanelId()),
context.hostedContentEvents);
}
void Append(::XCEngine::UI::UIDrawList& drawList) const override {
m_panel.Append(drawList);
}
bool HasActivePointerCapture() const override {
return m_panel.HasActivePointerCapture();
}
EditorEditCommandRoute* GetEditCommandRoute() override {
return &m_panel;
}
std::vector<EditorWorkspacePanelFrameEvent> CollectFrameEvents() const override {
std::vector<EditorWorkspacePanelFrameEvent> events = {};
for (const HierarchyPanel::Event& event : m_panel.GetFrameEvents()) {
events.push_back(EditorWorkspacePanelFrameEvent{
.status = std::string(kHierarchyPanelTitle),
.traceChannel = std::string(kHierarchyPanelId),
.message = DescribeHierarchyPanelEvent(event),
});
}
return events;
}
private:
HierarchyPanel m_panel = {};
};
class InspectorWorkspacePanel final : public EditorWorkspacePanel {
public:
std::string_view GetPanelId() const override {
return kInspectorPanelId;
}
std::string_view GetDrawListId() const override {
return "XCEditorPanel.Inspector";
}
EditorActionRoute GetActionRoute() const override {
return EditorActionRoute::Inspector;
}
int GetUpdatePriority() const override {
return kInspectorUpdatePriority;
}
void Update(const EditorWorkspacePanelUpdateContext& context) override {
m_panel.SetCommandFocusService(&context.context.GetCommandFocusService());
m_panel.Update(
context.context,
ResolveHostedPanelDispatchEntry(
context.shellFrame.hostedPanelDispatchFrame,
GetPanelId()),
context.hostedContentEvents);
}
void Append(::XCEngine::UI::UIDrawList& drawList) const override {
m_panel.Append(drawList);
}
EditorEditCommandRoute* GetEditCommandRoute() override {
return &m_panel;
}
private:
InspectorPanel m_panel = {};
};
class ProjectWorkspacePanel final : public EditorWorkspacePanel {
public:
std::string_view GetPanelId() const override {
return kProjectPanelId;
}
std::string_view GetDrawListId() const override {
return "XCEditorPanel.Project";
}
EditorActionRoute GetActionRoute() const override {
return EditorActionRoute::Project;
}
int GetUpdatePriority() const override {
return kProjectUpdatePriority;
}
void Initialize(const EditorWorkspacePanelInitializationContext& context) override {
m_panel.SetBuiltInIcons(&context.builtInIcons);
m_panel.SetTextMeasurer(&context.textMeasurer);
}
void ResetInteractionState() override {
m_panel.ResetInteractionState();
}
void Update(const EditorWorkspacePanelUpdateContext& context) override {
m_panel.SetProjectRuntime(&context.context.GetProjectRuntime());
m_panel.SetCommandFocusService(&context.context.GetCommandFocusService());
m_panel.SetSystemInteractionHost(context.context.GetSystemInteractionHost());
m_panel.Update(
ResolveHostedPanelDispatchEntry(
context.shellFrame.hostedPanelDispatchFrame,
GetPanelId()),
context.hostedContentEvents);
}
void Append(::XCEngine::UI::UIDrawList& drawList) const override {
m_panel.Append(drawList);
}
bool HasActivePointerCapture() const override {
return m_panel.HasActivePointerCapture();
}
EditorWorkspacePanelCursorKind GetCursorKind() const override {
switch (m_panel.GetCursorKind()) {
case ProjectPanel::CursorKind::ResizeEW:
return EditorWorkspacePanelCursorKind::ResizeEW;
case ProjectPanel::CursorKind::Arrow:
default:
return EditorWorkspacePanelCursorKind::Arrow;
}
}
EditorEditCommandRoute* GetEditCommandRoute() override {
return &m_panel;
}
std::vector<EditorWorkspacePanelFrameEvent> CollectFrameEvents() const override {
std::vector<EditorWorkspacePanelFrameEvent> events = {};
for (const ProjectPanel::Event& event : m_panel.GetFrameEvents()) {
events.push_back(EditorWorkspacePanelFrameEvent{
.status = std::string(kProjectPanelTitle),
.traceChannel = std::string(kProjectPanelId),
.message = DescribeProjectPanelEvent(event),
});
}
return events;
}
private:
ProjectPanel m_panel = {};
};
class SceneWorkspacePanel final : public EditorWorkspacePanel {
public:
std::string_view GetPanelId() const override {
return kScenePanelId;
}
std::string_view GetDrawListId() const override {
return "XCEditorPanel.SceneOverlay";
}
EditorActionRoute GetActionRoute() const override {
return EditorActionRoute::Scene;
}
int GetUpdatePriority() const override {
return kSceneUpdatePriority;
}
void Initialize(const EditorWorkspacePanelInitializationContext& context) override {
m_feature.Initialize(
context.repoRoot,
context.textureHost,
&context.builtInIcons,
context.viewportHostService);
}
void Shutdown(const EditorWorkspacePanelShutdownContext& context) override {
m_feature.Shutdown(context.textureHost, context.viewportHostService);
m_commandRoute.BindSceneRuntime(nullptr);
}
void ResetInteractionState() override {
m_feature.ResetInteractionState();
}
void PrepareForShellDefinition(
EditorContext& context,
UIEditorWorkspaceController&) override {
m_commandRoute.BindSceneRuntime(&context.GetSceneRuntime());
m_feature.SetCommandFocusService(&context.GetCommandFocusService());
m_feature.SyncRenderRequest(context.GetSceneRuntime());
}
void Update(const EditorWorkspacePanelUpdateContext& context) override {
m_feature.Update(
context.context.GetSceneRuntime(),
context.shellInteractionState.workspaceInteractionState.composeState,
context.shellFrame.workspaceInteractionFrame.composeFrame);
}
void Append(::XCEngine::UI::UIDrawList& drawList) const override {
m_feature.Append(drawList);
}
EditorEditCommandRoute* GetEditCommandRoute() override {
return &m_commandRoute;
}
private:
SceneViewportFeature m_feature = {};
SceneEditCommandRoute m_commandRoute = {};
};
} // namespace
void EditorWorkspacePanelRuntimeSet::AddPanel(
std::unique_ptr<EditorWorkspacePanel> panel) {
if (panel != nullptr) {
m_panels.push_back(std::move(panel));
}
}
void EditorWorkspacePanelRuntimeSet::Initialize(
const EditorWorkspacePanelInitializationContext& context) {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
panel->Initialize(context);
}
}
void EditorWorkspacePanelRuntimeSet::Shutdown(
const EditorWorkspacePanelShutdownContext& context) {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
panel->Shutdown(context);
}
}
void EditorWorkspacePanelRuntimeSet::ResetInteractionState() {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
panel->ResetInteractionState();
}
}
void EditorWorkspacePanelRuntimeSet::PrepareForShellDefinition(
EditorContext& context,
UIEditorWorkspaceController& workspaceController) {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
panel->PrepareForShellDefinition(context, workspaceController);
}
}
void EditorWorkspacePanelRuntimeSet::Update(
const EditorWorkspacePanelUpdateContext& context) {
const std::vector<EditorWorkspacePanel*> mainPanels =
BuildUpdateOrder(EditorWorkspacePanelUpdatePhase::Main);
for (EditorWorkspacePanel* panel : mainPanels) {
panel->Update(context);
}
context.context.SyncSessionFromCommandFocusService();
const std::vector<EditorWorkspacePanel*> afterFocusSyncPanels =
BuildUpdateOrder(EditorWorkspacePanelUpdatePhase::AfterCommandFocusSync);
for (EditorWorkspacePanel* panel : afterFocusSyncPanels) {
panel->Update(context);
}
}
void EditorWorkspacePanelRuntimeSet::AppendDrawPackets(
::XCEngine::UI::UIDrawData& drawData) const {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
AppendDrawPacket(
drawData,
std::string(panel->GetDrawListId()),
[&](::XCEngine::UI::UIDrawList& drawList) {
panel->Append(drawList);
});
}
}
bool EditorWorkspacePanelRuntimeSet::HasActivePointerCapture() const {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
if (panel->HasActivePointerCapture()) {
return true;
}
}
return false;
}
EditorWorkspacePanelCursorKind
EditorWorkspacePanelRuntimeSet::GetHostedContentCursorKind() const {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
const EditorWorkspacePanelCursorKind cursorKind = panel->GetCursorKind();
if (cursorKind != EditorWorkspacePanelCursorKind::Arrow) {
return cursorKind;
}
}
return EditorWorkspacePanelCursorKind::Arrow;
}
EditorEditCommandRoute* EditorWorkspacePanelRuntimeSet::FindCommandRoute(
EditorActionRoute route) {
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
if (panel->GetActionRoute() == route) {
return panel->GetEditCommandRoute();
}
}
return nullptr;
}
std::vector<EditorWorkspacePanelFrameEvent>
EditorWorkspacePanelRuntimeSet::CollectFrameEvents() const {
std::vector<EditorWorkspacePanelFrameEvent> events = {};
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
std::vector<EditorWorkspacePanelFrameEvent> panelEvents =
panel->CollectFrameEvents();
events.insert(
events.end(),
std::make_move_iterator(panelEvents.begin()),
std::make_move_iterator(panelEvents.end()));
}
return events;
}
std::vector<EditorWorkspacePanel*> EditorWorkspacePanelRuntimeSet::BuildUpdateOrder(
EditorWorkspacePanelUpdatePhase phase) const {
std::vector<EditorWorkspacePanel*> panels = {};
panels.reserve(m_panels.size());
for (const std::unique_ptr<EditorWorkspacePanel>& panel : m_panels) {
if (panel->GetUpdatePhase() == phase) {
panels.push_back(panel.get());
}
}
std::sort(
panels.begin(),
panels.end(),
[](const EditorWorkspacePanel* left, const EditorWorkspacePanel* right) {
return left->GetUpdatePriority() < right->GetUpdatePriority();
});
return panels;
}
EditorWorkspacePanelRuntimeSet CreateEditorWorkspacePanelRuntimeSet() {
EditorWorkspacePanelRuntimeSet panels = {};
panels.AddPanel(std::make_unique<ConsoleWorkspacePanel>());
panels.AddPanel(std::make_unique<HierarchyWorkspacePanel>());
panels.AddPanel(std::make_unique<InspectorWorkspacePanel>());
panels.AddPanel(std::make_unique<ProjectWorkspacePanel>());
panels.AddPanel(std::make_unique<SceneWorkspacePanel>());
return panels;
}
} // namespace XCEngine::UI::Editor::App

View File

@@ -0,0 +1,145 @@
#pragma once
#include "Commands/EditorEditCommandRoute.h"
#include "State/EditorSession.h"
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
#include <XCEditor/Panels/UIEditorHostedPanelDispatch.h>
#include <XCEditor/Shell/UIEditorShellInteraction.h>
#include <XCEditor/Workspace/UIEditorWorkspaceController.h>
#include <XCEngine/UI/DrawData.h>
#include <cstdint>
#include <filesystem>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI {
struct UIInputEvent;
} // namespace XCEngine::UI
namespace XCEngine::UI::Editor::Rendering::Host {
class UiTextureHost;
} // namespace XCEngine::UI::Editor::Rendering::Host
namespace XCEngine::UI::Editor::App {
class BuiltInIcons;
class EditorContext;
class ViewportHostService;
enum class EditorWorkspacePanelCursorKind : std::uint8_t {
Arrow = 0,
ResizeEW
};
enum class EditorWorkspacePanelUpdatePhase : std::uint8_t {
Main = 0,
AfterCommandFocusSync
};
struct EditorWorkspacePanelFrameEvent {
std::string status = {};
std::string traceChannel = {};
std::string message = {};
};
struct EditorWorkspacePanelInitializationContext {
const std::filesystem::path& repoRoot;
Rendering::Host::UiTextureHost& textureHost;
UIEditorTextMeasurer& textMeasurer;
BuiltInIcons& builtInIcons;
ViewportHostService& viewportHostService;
};
struct EditorWorkspacePanelShutdownContext {
Rendering::Host::UiTextureHost& textureHost;
ViewportHostService& viewportHostService;
};
struct EditorWorkspacePanelUpdateContext {
EditorContext& context;
UIEditorShellInteractionFrame& shellFrame;
UIEditorShellInteractionState& shellInteractionState;
const std::vector<::XCEngine::UI::UIInputEvent>& hostedContentEvents;
};
class EditorWorkspacePanel {
public:
virtual ~EditorWorkspacePanel() = default;
virtual std::string_view GetPanelId() const = 0;
virtual std::string_view GetDrawListId() const = 0;
virtual EditorActionRoute GetActionRoute() const = 0;
virtual void Initialize(const EditorWorkspacePanelInitializationContext&) {}
virtual void Shutdown(const EditorWorkspacePanelShutdownContext&) {}
virtual void ResetInteractionState() {}
virtual void PrepareForShellDefinition(
EditorContext& context,
UIEditorWorkspaceController& workspaceController) {
(void)context;
(void)workspaceController;
}
virtual EditorWorkspacePanelUpdatePhase GetUpdatePhase() const {
return EditorWorkspacePanelUpdatePhase::Main;
}
virtual int GetUpdatePriority() const {
return 0;
}
virtual void Update(const EditorWorkspacePanelUpdateContext& context) = 0;
virtual void Append(::XCEngine::UI::UIDrawList& drawList) const = 0;
virtual bool HasActivePointerCapture() const {
return false;
}
virtual EditorWorkspacePanelCursorKind GetCursorKind() const {
return EditorWorkspacePanelCursorKind::Arrow;
}
virtual EditorEditCommandRoute* GetEditCommandRoute() {
return nullptr;
}
virtual std::vector<EditorWorkspacePanelFrameEvent> CollectFrameEvents() const {
return {};
}
};
class EditorWorkspacePanelRuntimeSet final {
public:
EditorWorkspacePanelRuntimeSet() = default;
EditorWorkspacePanelRuntimeSet(const EditorWorkspacePanelRuntimeSet&) = delete;
EditorWorkspacePanelRuntimeSet& operator=(const EditorWorkspacePanelRuntimeSet&) = delete;
EditorWorkspacePanelRuntimeSet(EditorWorkspacePanelRuntimeSet&&) noexcept = default;
EditorWorkspacePanelRuntimeSet& operator=(EditorWorkspacePanelRuntimeSet&&) noexcept = default;
void AddPanel(std::unique_ptr<EditorWorkspacePanel> panel);
void Initialize(const EditorWorkspacePanelInitializationContext& context);
void Shutdown(const EditorWorkspacePanelShutdownContext& context);
void ResetInteractionState();
void PrepareForShellDefinition(
EditorContext& context,
UIEditorWorkspaceController& workspaceController);
void Update(const EditorWorkspacePanelUpdateContext& context);
void AppendDrawPackets(::XCEngine::UI::UIDrawData& drawData) const;
bool HasActivePointerCapture() const;
EditorWorkspacePanelCursorKind GetHostedContentCursorKind() const;
EditorEditCommandRoute* FindCommandRoute(EditorActionRoute route);
std::vector<EditorWorkspacePanelFrameEvent> CollectFrameEvents() const;
private:
std::vector<EditorWorkspacePanel*> BuildUpdateOrder(
EditorWorkspacePanelUpdatePhase phase) const;
std::vector<std::unique_ptr<EditorWorkspacePanel>> m_panels = {};
};
EditorWorkspacePanelRuntimeSet CreateEditorWorkspacePanelRuntimeSet();
} // namespace XCEngine::UI::Editor::App

View File

@@ -9,11 +9,12 @@ namespace XCEngine::UI::Editor::App {
namespace {
EditorWindowContentCursorKind ToContentCursorKind(ProjectPanel::CursorKind cursorKind) {
EditorWindowContentCursorKind ToContentCursorKind(
EditorWorkspacePanelCursorKind cursorKind) {
switch (cursorKind) {
case ProjectPanel::CursorKind::ResizeEW:
case EditorWorkspacePanelCursorKind::ResizeEW:
return EditorWindowContentCursorKind::ResizeEW;
case ProjectPanel::CursorKind::Arrow:
case EditorWorkspacePanelCursorKind::Arrow:
default:
return EditorWindowContentCursorKind::Arrow;
}