Refactor editor workspace panel runtime boundary
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
610
editor/app/Features/EditorWorkspacePanelRegistry.cpp
Normal file
610
editor/app/Features/EditorWorkspacePanelRegistry.cpp
Normal 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
|
||||
145
editor/app/Features/EditorWorkspacePanelRegistry.h
Normal file
145
editor/app/Features/EditorWorkspacePanelRegistry.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user