diff --git a/docs/plan/editor-core-refactor-plan.md b/docs/plan/editor-core-refactor-plan.md index e416d29b..af9ccbeb 100644 --- a/docs/plan/editor-core-refactor-plan.md +++ b/docs/plan/editor-core-refactor-plan.md @@ -67,6 +67,9 @@ Completed boundary cuts: and `Features/Project/ProjectPanel` owns the widget-tree projection. - Panel IDs live under `editor/app/Core/Panels`, and workspace panel runtime contracts live under `editor/app/Core/WorkspacePanels`. +- The generic workspace panel runtime-set implementation also lives under + `editor/app/Core/WorkspacePanels`; `Features/EditorWorkspacePanelRegistry.*` + owns only concrete panel adapters and the concrete factory. - Shared window category, lifecycle, chrome-policy, and native-host-policy contracts live under `editor/app/Core/Windowing`. - Utility-window kinds, descriptors, and panel contracts live under @@ -262,6 +265,9 @@ The feature registry header owns only: Reason: composition should depend on the panel runtime interface, not on the feature registry. Concrete feature construction belongs to `Features`. +The generic `EditorWorkspacePanelRuntimeSet` implementation belongs with the +Core workspace-panel runtime contract; the feature registry should only add +concrete panel adapters to the set. ### 3. Keep the First Cut Buildable @@ -282,6 +288,9 @@ contract and creates the landing zone for the next cut. Completed follow-up: +- `EditorWorkspacePanelRuntimeSet` generic behavior now lives under + `Core/WorkspacePanels`, leaving `Features/EditorWorkspacePanelRegistry.*` + responsible only for concrete workspace-panel adapters and factory wiring. - `EditorPanelServices` now carries the panel-facing references to session, project runtime, scene runtime, command focus, color-picker state, system interaction, text measurement, and utility-window requests. diff --git a/editor/AGENTS.md b/editor/AGENTS.md index e6d96ab7..51346a92 100644 --- a/editor/AGENTS.md +++ b/editor/AGENTS.md @@ -91,9 +91,9 @@ change. Scene viewport, Inspector, Project, Console, Color Picker, and component UI. - `app/Features/EditorWorkspacePanelRegistry.*` is the concrete workspace panel factory. It owns the concrete workspace panel adapters. Shared - workspace-panel runtime interfaces live under `app/Core/WorkspacePanels` - so `app/Composition/**` can depend on the contract without depending on the - feature registry. + workspace-panel runtime interfaces and runtime-set implementation live under + `app/Core/WorkspacePanels` so `app/Composition/**` can depend on the + contract without depending on the feature registry. - `app/Features/EditorUtilityWindowRegistry.*` is the concrete utility-window panel factory. Shared utility-window contracts and descriptors live under `app/Core/UtilityWindows` so windowing can resolve utility window shape @@ -257,7 +257,7 @@ inside pure shell/widget code. `Composition/EditorContext.h`; `EditorContext` remains a composition-owned aggregate and request bridge. - Workspace panels are adapted behind `EditorWorkspacePanelRuntimeSet`, whose - contract lives in `app/Core/WorkspacePanels/EditorWorkspacePanelRuntime.h`. + contract and generic runtime behavior live under `app/Core/WorkspacePanels`. 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`, @@ -491,6 +491,10 @@ ownership rule. `EditorWorkspacePanelRegistry.*`. `app/Composition/**` no longer directly owns or dispatches concrete Console, Hierarchy, Inspector, Project, or Scene panel classes. +- The generic `EditorWorkspacePanelRuntimeSet` implementation now lives under + `app/Core/WorkspacePanels`. `app/Features/EditorWorkspacePanelRegistry.*` + owns only concrete workspace-panel adapters and the concrete runtime-set + factory. - Shared app panel contracts started moving into `app/Core`: panel IDs now live under `app/Core/Panels`, and the workspace-panel runtime interface lives under `app/Core/WorkspacePanels`. `Application` is the composition root for diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 05ea344f..029b9216 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -216,6 +216,7 @@ set(XCUI_EDITOR_HOST_RENDERING_SOURCES if(XCENGINE_BUILD_XCUI_EDITOR_CORE) set(XCUI_EDITOR_APP_CORE_CONTRACT_SOURCES app/Core/UtilityWindows/EditorUtilityWindowRegistry.cpp + app/Core/WorkspacePanels/EditorWorkspacePanelRuntime.cpp ) set(XCUI_EDITOR_APP_STATE_SOURCES diff --git a/editor/app/Core/WorkspacePanels/EditorWorkspacePanelRuntime.cpp b/editor/app/Core/WorkspacePanels/EditorWorkspacePanelRuntime.cpp new file mode 100644 index 00000000..8b8f9bda --- /dev/null +++ b/editor/app/Core/WorkspacePanels/EditorWorkspacePanelRuntime.cpp @@ -0,0 +1,149 @@ +#include "WorkspacePanels/EditorWorkspacePanelRuntime.h" + +#include +#include +#include +#include + +namespace XCEngine::UI::Editor::App { + +namespace { + +template +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)); + } +} + +} // namespace + +void EditorWorkspacePanelRuntimeSet::AddPanel( + std::unique_ptr panel) { + if (panel != nullptr) { + m_panels.push_back(std::move(panel)); + } +} + +void EditorWorkspacePanelRuntimeSet::Initialize( + const EditorWorkspacePanelInitializationContext& context) { + for (const std::unique_ptr& panel : m_panels) { + panel->Initialize(context); + } +} + +void EditorWorkspacePanelRuntimeSet::Shutdown( + const EditorWorkspacePanelShutdownContext& context) { + for (const std::unique_ptr& panel : m_panels) { + panel->Shutdown(context); + } +} + +void EditorWorkspacePanelRuntimeSet::ResetInteractionState() { + for (const std::unique_ptr& panel : m_panels) { + panel->ResetInteractionState(); + } +} + +void EditorWorkspacePanelRuntimeSet::PrepareForShellDefinition( + EditorPanelServices& services, + UIEditorWorkspaceController& workspaceController) { + for (const std::unique_ptr& panel : m_panels) { + panel->PrepareForShellDefinition(services, workspaceController); + } +} + +void EditorWorkspacePanelRuntimeSet::UpdatePhase( + const EditorWorkspacePanelUpdateContext& context, + EditorWorkspacePanelUpdatePhase phase) { + const std::vector phasePanels = + BuildUpdateOrder(phase); + for (EditorWorkspacePanel* panel : phasePanels) { + panel->Update(context); + } +} + +void EditorWorkspacePanelRuntimeSet::AppendDrawPackets( + ::XCEngine::UI::UIDrawData& drawData) const { + for (const std::unique_ptr& 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& panel : m_panels) { + if (panel->HasActivePointerCapture()) { + return true; + } + } + + return false; +} + +EditorWorkspacePanelCursorKind +EditorWorkspacePanelRuntimeSet::GetHostedContentCursorKind() const { + for (const std::unique_ptr& 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& panel : m_panels) { + if (panel->GetActionRoute() == route) { + return panel->GetEditCommandRoute(); + } + } + + return nullptr; +} + +std::vector +EditorWorkspacePanelRuntimeSet::CollectFrameEvents() const { + std::vector events = {}; + for (const std::unique_ptr& panel : m_panels) { + std::vector panelEvents = + panel->CollectFrameEvents(); + events.insert( + events.end(), + std::make_move_iterator(panelEvents.begin()), + std::make_move_iterator(panelEvents.end())); + } + return events; +} + +std::vector EditorWorkspacePanelRuntimeSet::BuildUpdateOrder( + EditorWorkspacePanelUpdatePhase phase) const { + std::vector panels = {}; + panels.reserve(m_panels.size()); + for (const std::unique_ptr& 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; +} + +} // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Features/EditorWorkspacePanelRegistry.cpp b/editor/app/Features/EditorWorkspacePanelRegistry.cpp index 698364a1..af95e2dc 100644 --- a/editor/app/Features/EditorWorkspacePanelRegistry.cpp +++ b/editor/app/Features/EditorWorkspacePanelRegistry.cpp @@ -12,10 +12,8 @@ #include -#include -#include +#include #include -#include namespace XCEngine::UI::Editor::App { @@ -164,18 +162,6 @@ std::string DescribeHierarchyPanelEvent(const HierarchyPanel::Event& event) { return stream.str(); } -template -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 { @@ -466,129 +452,6 @@ private: } // namespace -void EditorWorkspacePanelRuntimeSet::AddPanel( - std::unique_ptr panel) { - if (panel != nullptr) { - m_panels.push_back(std::move(panel)); - } -} - -void EditorWorkspacePanelRuntimeSet::Initialize( - const EditorWorkspacePanelInitializationContext& context) { - for (const std::unique_ptr& panel : m_panels) { - panel->Initialize(context); - } -} - -void EditorWorkspacePanelRuntimeSet::Shutdown( - const EditorWorkspacePanelShutdownContext& context) { - for (const std::unique_ptr& panel : m_panels) { - panel->Shutdown(context); - } -} - -void EditorWorkspacePanelRuntimeSet::ResetInteractionState() { - for (const std::unique_ptr& panel : m_panels) { - panel->ResetInteractionState(); - } -} - -void EditorWorkspacePanelRuntimeSet::PrepareForShellDefinition( - EditorPanelServices& services, - UIEditorWorkspaceController& workspaceController) { - for (const std::unique_ptr& panel : m_panels) { - panel->PrepareForShellDefinition(services, workspaceController); - } -} - -void EditorWorkspacePanelRuntimeSet::UpdatePhase( - const EditorWorkspacePanelUpdateContext& context, - EditorWorkspacePanelUpdatePhase phase) { - const std::vector phasePanels = - BuildUpdateOrder(phase); - for (EditorWorkspacePanel* panel : phasePanels) { - panel->Update(context); - } -} - -void EditorWorkspacePanelRuntimeSet::AppendDrawPackets( - ::XCEngine::UI::UIDrawData& drawData) const { - for (const std::unique_ptr& 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& panel : m_panels) { - if (panel->HasActivePointerCapture()) { - return true; - } - } - - return false; -} - -EditorWorkspacePanelCursorKind -EditorWorkspacePanelRuntimeSet::GetHostedContentCursorKind() const { - for (const std::unique_ptr& 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& panel : m_panels) { - if (panel->GetActionRoute() == route) { - return panel->GetEditCommandRoute(); - } - } - - return nullptr; -} - -std::vector -EditorWorkspacePanelRuntimeSet::CollectFrameEvents() const { - std::vector events = {}; - for (const std::unique_ptr& panel : m_panels) { - std::vector panelEvents = - panel->CollectFrameEvents(); - events.insert( - events.end(), - std::make_move_iterator(panelEvents.begin()), - std::make_move_iterator(panelEvents.end())); - } - return events; -} - -std::vector EditorWorkspacePanelRuntimeSet::BuildUpdateOrder( - EditorWorkspacePanelUpdatePhase phase) const { - std::vector panels = {}; - panels.reserve(m_panels.size()); - for (const std::unique_ptr& 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());