# XCUI Editor Agent Guide 这份文档面向在 `editor/` 下工作的 coding agent / 开发者。它描述当前 editor 的真实工程边界、窗口架构和修改约束,不是产品说明。 如果本文和当前代码、`editor/CMakeLists.txt`、实际目录结构冲突,以当前 checkout 为准,并在本次工作里同步修正文档。 ## 1. 当前定位 `editor/` 是当前 editor 应用主线。 当前工程事实: - 可复用 UI framework 的真实构建目标是 `XCUIEditorLib`。 - editor 应用的真实可执行目标是 `XCUIEditorApp`。 - `XCUIEditorApp` 的输出名是 `XCEngine`,产物为 `XCEngine.exe`。 - `editor/src` + `editor/include/XCEditor` 是 XCEditor framework。 - `editor/app` 是具体 XCEngine editor 应用层。 - `editor/resources` 存放 editor 自有图标和 scene viewport shader。 当前 `editor/CMakeLists.txt` 并没有把 app core、windowing seam、Win32 host、rendering host 拆成独立生产 target。除了 `XCUIEditorLib` 之外,其余 app / windowing / platform / rendering 代码仍直接编进 `XCUIEditorApp`。 `XCUIEditorAppLib`、`XCUIEditorAppCore`、`XCUIEditorHost` 不是当前 `editor/CMakeLists.txt` 里真实定义的生产 target;它们只在部分测试脚本或清理逻辑里作为条件名称出现。不要把这些名字当成当前已经存在的模块边界。 ## 2. 当前分层 推荐按下面五层理解和修改,但要记住这主要是目录和语义边界,不是已经被 CMake 强制落实的编译边界: 1. `editor/src` / `editor/include/XCEditor` XCEditor framework。这里应保持通用,不依赖具体 editor app、Win32 宿主或 D3D12 实现。 2. `editor/app/Composition`、`Commands`、`Features`、`Project`、`Scene`、`State`、`Support`、`System`、`UtilityWindows` editor 应用语义层。这里放 panel 组合、项目/场景运行时、选择状态、命令桥接、utility window 描述和 app 侧服务。 3. `editor/app/Windowing` 平台无关的窗口主线。这里放 content controller contract、frame transfer request、workspace synchronization planner / presentation policy / authoritative window set。 4. `editor/app/Platform/Win32` Win32 host。这里负责 native window、消息分发、生命周期、输入翻译、窗口 chrome、host runtime 和 coordinator。 5. `editor/app/Rendering` editor 渲染宿主。这里负责 D3D12 UI 渲染、窗口 render loop、swapchain、viewport 资源和 scene viewport pass。 依赖方向尽量保持为: ```text XCEditor framework <- app semantics <- app/windowing <- Platform/Win32 <- app/Rendering ``` 现实约束: - 当前只有 `XCUIEditorLib` 是真实独立 target。 - 其余层级只是目录和 ownership 约定。 - 修改时仍要主动控制 include 方向,避免把“语义上应该分层”写回成硬耦合。 ## 3. 顶层启动流程 入口: ```text app/main.cpp -> RunXCUIEditorApp -> Application::Run ``` 当前启动主线: ```text Application -> EditorContext -> Win32SystemInteractionHost -> EditorWindowSystem -> EditorWindowManager -> EditorWindowHostRuntime -> EditorWindowWorkspaceCoordinator -> EditorUtilityWindowCoordinator -> EditorWindowLifecycleCoordinator ``` primary workspace window 的 bootstrap 顺序是: ```text EditorContext::BuildWorkspaceController() -> EditorWindowSystem::BootstrapPrimaryWindow(...) -> EditorWindowManager::CreateWorkspaceWindow(...) ``` 不要把 primary window authority 初始化放回 Win32 host。当前 authoritative bootstrap 已经在 `EditorWindowSystem`。 ## 4. 当前窗口系统事实 ### 4.1 Authority / Planner / Host Execution 当前多窗口 workspace 主线里,几个核心对象的职责是: - `EditorWindowSystem` - 持有 authoritative `UIEditorWindowWorkspaceSet` - 通过 `EditorWindowWorkspaceStore` 做 validation / commit - 构建 synchronization plan - 处理显式 `workspaceMutation` request - 处理 destroyed window reconciliation - `EditorWindowWorkspaceCoordinator` - 采集 host snapshot - 调用 `EditorWindowSystem` 生成 plan - 执行 host-side create / update / close - 处理 global tab drag、detach、cross-window dock/drop - 处理 window presentation refresh - 在 native destroy 时回到 `EditorWindowSystem` 做 reconcile 重要事实: - `EditorWindowWorkspaceCoordinator` 已不再直接写 authority store。 - 但它仍然很厚,仍同时承担 host 执行、presentation refresh、drag/detach 流程和部分回滚时序。 - 当前不要把它描述成“纯粹的薄 host adapter”。 ### 4.2 Live Workspace Projection 还没有完全去状态化 `EditorWorkspaceWindowContentController` 当前内部仍持有: - `UIEditorWorkspaceController` - `EditorShellRuntime` - `EditorWindowFrameOrchestrator` 这意味着当前 workspace window 仍然有一个 live mutable controller。它已经不是 authority,但也还不是完全只读 projection。 当前真实行为是: - `EditorWorkspaceWindowContentController::UpdateAndAppend(...)` 会在 layout snapshot 发生变化时发出显式 `workspaceMutation` request。 - `EditorWorkspaceWindowContentController` 现在持有显式 `EditorWorkspaceWindowProjection`,host 常规同步 / presentation 路径优先消费 projection refresh,而不是整体替换 live controller。 - `EditorWindow::TryGetWorkspaceController()` 仍保留给局部交互 / 过渡路径使用,但它不再是常规 host 同步主接口。 - 每个 workspace window 依然持有自己的一份 live `UIEditorWorkspaceController`。 因此: - 不要把当前架构写成“projection-only content controller 已完成”。 ## 5. 窗口类别与内容控制器 当前窗口系统显式区分两类窗口: - `EditorWindowCategory::Workspace` - `EditorWindowCategory::Utility` 两类窗口共享同一个 native host: ```text EditorWindow -> EditorWindowRuntimeController -> D3D12WindowRenderLoop -> EditorWindowContentController ``` ### 5.1 Workspace Window workspace window 的内容控制器是 `EditorWorkspaceWindowContentController`。 它是完整 shell/workspace 容器,用于: - 主窗口 - detached workspace window ### 5.2 Utility Window utility window 的内容控制器是 `EditorUtilityWindowContentController`,内部承载 `EditorUtilityWindowPanel`。 当前 registry / factory 主线是显式 descriptor 驱动: - `EditorUtilityWindowDescriptor` - `EditorUtilityWindowReusePolicy` - `EditorWindowChromePolicy` - `EditorWindowNativeStylePolicy` 当前已注册的 utility window: - `ColorPicker` - `AddComponent` 两者当前都使用 `SingleInstance` 复用策略。 ### 5.3 Capability 校验 窗口内容能力由 `EditorWindowContentCapabilities` 描述,`EditorWindowHostRuntime::CreateEditorWindow(...)` 在创建时做硬校验: - `Workspace` 分类要求 `capabilities.workspace == true` - `Utility` 分类要求 `capabilities.utilityPanel == true` 不要依赖“后续 coordinator 看到空 binding 再兜底”这种旧思路。 ## 6. Frame Request 与每帧主线 `EditorWindowFrameTransferRequests` 当前按两个子域组织: ```text workspace: workspaceMutation beginGlobalTabDrag detachPanel utility: openUtilityWindow ``` 当前事实: - `workspaceMutation` 已经是 frame 内 workspace 变化的显式回传入口。 - `openUtilityWindow` 来自 `EditorContext::RequestOpenUtilityWindow(...)`,由 `EditorWindowFrameOrchestrator` 消费 request state 后写入 frame transfer request。 - queued immediate frame 也按这两个子域分别合并。 steady-state frame 主路径是: ```text Application::Run -> EditorWindowManager::RenderAllWindows -> EditorWindowHostRuntime::RenderAllWindows -> EditorWindowFrameDriver::DriveFrame -> EditorWindowRuntimeController::UpdateAndAppend -> EditorWindowContentController::UpdateAndAppend -> EditorWindowWorkspaceCoordinator::RefreshWindowPresentation -> EditorWindowWorkspaceCoordinator::HandleWindowFrameTransferRequests -> EditorUtilityWindowCoordinator::HandleWindowFrameTransferRequests ``` 另外,`WM_PAINT`、`WM_SIZE`、`WM_DPICHANGED`、`WM_EXITSIZEMOVE` 等消息也会触发 immediate frame,并在 message dispatcher 中 flush queued transfer requests。 ## 7. 修改规范 - 先判断改动属于 framework、app semantics、windowing、Win32 host 还是 rendering host。 - 小改动优先贴近现有模式,不顺手做跨层重构。 - 新增通用 widget 放 `editor/src` / `editor/include/XCEditor`。 - 新增具体 editor 功能放 `editor/app/Features/`,再由 composition 装配。 - 新增 utility window 先补 `EditorUtilityWindowKind`、`EditorUtilityWindowDescriptor`、`CreateEditorUtilityWindowPanel(...)`,不要直接在 Win32 coordinator 里硬编码窗口类型。 - 新增跨窗口语义时,优先增加显式 frame request 或 app/windowing plan builder,不要回退到 Win32 host 直接读写 authority。 - 修改窗口同步逻辑时,区分“当前代码事实”和“长期目标”。当前还存在 live mutable projection,不要按尚未落地的终态直接删接口。 - 不要让 `editor/include/XCEditor/**` 暴露 `App::*` 类型。 - draw append 只负责绘制,不顺手修改 scene / project / authority 状态。 ## 8. 当前架构债务 当前仍然存在的主要债务: - 除 `XCUIEditorLib` 外,app core、windowing、Win32 host、rendering host 还没有真实拆成独立 target。 - `EditorContext` 仍然很重,混合了 shell asset、项目/场景运行时、selection、command focus、utility window request 和状态输出。 - `EditorShellRuntime` 仍然很重,既负责 shell compose / interaction,也负责 hosted panel、viewport request 和 draw append。 - `EditorWorkspaceWindowContentController` 仍持有 live mutable `UIEditorWorkspaceController`,只是 host 常规同步 / presentation 已经切到 projection refresh;projection 和 authority 的边界仍未完全硬化。 - `EditorWindowWorkspaceCoordinator` 仍然过厚,还没有收缩成纯粹的 host executor + native event bridge。 - `EditorWindow::TryGetWorkspaceController()` 仍存在于交互 / 过渡路径,说明 live projection 去状态化还没完成;但常规同步路径已经不再依赖 `ReplaceWorkspaceController()`。 这些都是当前事实,不要在新的规范文档或代码注释里把它们写成“已经解决”。 ## 9. 验证入口 当前 editor 相关验证入口统一在 `tests/UI/Editor`: - `editor_ui_tests` framework 和基础 UI 单元测试。 - `editor_windowing_phase1_tests` 当前窗口 authority / planner / reconcile 规则的 focused unit tests。 - `xcui_editor_app_smoke` editor 启动烟测。 - `tests/UI/Editor/manual_validation` 复杂交互人工验证场景。 条件事实: - `editor_app_feature_tests` 只会在 `XCUIEditorAppLib` 等可选 target 真实存在时创建。 - 不要把它当成当前 checkout 一定存在的测试目标。 涉及窗口系统的改动,优先保持: - `XCUIEditorApp` 可构建 - `editor_windowing_phase1_tests` 不回退 - `xcui_editor_app_smoke` 不回退 ## 10. 推荐阅读入口 开始 editor 相关任务时,优先阅读: - `editor/CMakeLists.txt` - `editor/app/Bootstrap/Application.*` - `editor/app/Composition/EditorContext.*` - `editor/app/Composition/EditorShellRuntime.*` - `editor/app/Windowing/Content/EditorWindowContentController.h` - `editor/app/Windowing/Content/EditorWorkspaceWindowContentController.*` - `editor/app/Windowing/Frame/EditorWindowFrameOrchestrator.*` - `editor/app/Windowing/System/EditorWindowSystem.*` - `editor/app/Platform/Win32/Windowing/EditorWindow.*` - `editor/app/Platform/Win32/Windowing/EditorWindowHostRuntime.*` - `editor/app/Platform/Win32/Windowing/EditorWindowWorkspaceCoordinator.*` - `editor/app/Platform/Win32/Windowing/EditorUtilityWindowCoordinator.*` - `editor/app/UtilityWindows/EditorUtilityWindowRegistry.*` - `tests/UI/Editor/unit/CMakeLists.txt` - `tests/UI/Editor/smoke/CMakeLists.txt`