2026-04-25 17:51:37 +08:00
|
|
|
|
# XCUI Editor Agent Guide
|
|
|
|
|
|
|
|
|
|
|
|
这份文档面向在 `editor/` 下工作的 coding agent / 开发者。它描述当前 editor 的真实工程边界、窗口架构和修改约束,不是产品说明。
|
|
|
|
|
|
|
|
|
|
|
|
如果本文和当前代码、`editor/CMakeLists.txt`、实际目录结构冲突,以当前 checkout 为准,并在本次工作里同步修正文档。
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 当前定位
|
|
|
|
|
|
|
|
|
|
|
|
`editor/` 是当前 editor 应用主线。
|
|
|
|
|
|
|
|
|
|
|
|
当前工程事实:
|
|
|
|
|
|
|
|
|
|
|
|
- 构建目标是 `XCUIEditorApp`。
|
|
|
|
|
|
- 输出名是 `XCEngine`,构建产物为 `XCEngine.exe`。
|
|
|
|
|
|
- `editor/src` 是可复用的 XCEditor UI framework。
|
|
|
|
|
|
- `editor/include/XCEditor` 是 `editor/src` 的公开接口。
|
|
|
|
|
|
- `editor/app` 是具体 XCEngine editor 应用层。
|
|
|
|
|
|
- `editor/resources` 存放 editor 自有图标和 scene viewport shader。
|
|
|
|
|
|
|
|
|
|
|
|
虽然 `editor/CMakeLists.txt` 仍把这些代码编进一个可执行目标,但语义上已经分成 framework、app core、Win32 host 和 D3D12 host 四层。
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 分层边界
|
|
|
|
|
|
|
2026-04-25 18:20:17 +08:00
|
|
|
|
推荐按下面五层理解和修改:
|
2026-04-25 17:51:37 +08:00
|
|
|
|
|
|
|
|
|
|
1. `editor/src` / `editor/include/XCEditor`
|
|
|
|
|
|
XCEditor UI framework。这里应保持通用,不依赖具体项目、场景、Win32 宿主或 D3D12 实现。
|
|
|
|
|
|
|
|
|
|
|
|
2. `editor/app/Composition`、`Features`、`Project`、`Scene`、`State`、`Commands`
|
|
|
|
|
|
Editor app core。这里装配 panel、项目运行时、场景运行时、选择状态、命令路由和 shell frame。
|
|
|
|
|
|
|
2026-04-25 18:20:17 +08:00
|
|
|
|
3. `editor/app/Windowing`
|
|
|
|
|
|
Editor host seam。这里放平台无关的窗口内容 contract、workspace/utility content assembly、frame orchestration 和 host-facing transfer request。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
|
2026-04-25 18:20:17 +08:00
|
|
|
|
4. `editor/app/Platform/Win32`
|
|
|
|
|
|
Win32 host。这里负责原生窗口、消息分发、窗口生命周期、输入收集、title bar / chrome 和 surface/presenter。
|
|
|
|
|
|
|
|
|
|
|
|
5. `editor/app/Rendering`
|
2026-04-25 17:51:37 +08:00
|
|
|
|
Editor rendering host。这里负责 D3D12 UI 渲染、窗口 swapchain、viewport 离屏资源、editor 图标纹理和 scene viewport pass。
|
|
|
|
|
|
|
|
|
|
|
|
依赖方向尽量保持:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
2026-04-25 18:20:17 +08:00
|
|
|
|
app/platform + app/rendering -> app/windowing -> app/core -> XCEditor framework -> engine UI primitives
|
2026-04-25 17:51:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
不要让 `editor/src` 反向依赖 `editor/app`。
|
|
|
|
|
|
|
2026-04-25 18:20:17 +08:00
|
|
|
|
### 2.1 长期目标:把语义分层落成真实模块边界
|
|
|
|
|
|
|
|
|
|
|
|
当前 `editor/` 已经有语义上的四层划分,但还没有真正的编译/依赖边界。窗口相关代码最重要的长期目标,不是继续细拆 `Win32` 目录里的类,而是把下面这条关系变成代码和构建系统都能强制执行的事实:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
XCEditor framework
|
|
|
|
|
|
<- editor app core
|
|
|
|
|
|
<- editor host seam / app/Windowing
|
|
|
|
|
|
<- Win32 host + D3D12 host
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
收敛要求:
|
|
|
|
|
|
|
|
|
|
|
|
- `editor/app/Platform/Win32` 只负责 native window、message pump、input translation、chrome、lifecycle 和 surface/presenter 等宿主职责。
|
|
|
|
|
|
- workspace mutation、utility window routing、shell composition、window content assembly 这类产品语义应逐步收敛到平台无关层,而不是继续堆进 Win32 host。
|
|
|
|
|
|
- `editor/src` / `editor/include/XCEditor` 不允许反向依赖 `editor/app`;公开头文件不应暴露 `App::*` 类型。
|
|
|
|
|
|
- 最终要通过独立 CMake target 和受限 include dirs 落实,而不是只靠目录约定。
|
|
|
|
|
|
|
|
|
|
|
|
后续凡是修改窗口系统,优先朝“缩小 `Platform/Win32` 对 `Composition`、`Features`、`UtilityWindows`、`Rendering` 的直接依赖面”这个方向收敛。如果一个新需求只能通过继续把业务语义塞进 Win32 host 才能完成,应先停下来评估是否缺少平台无关的 host seam。
|
|
|
|
|
|
|
2026-04-25 17:51:37 +08:00
|
|
|
|
## 3. 顶层启动流程
|
|
|
|
|
|
|
|
|
|
|
|
入口:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
app/main.cpp
|
|
|
|
|
|
-> RunXCUIEditorApp
|
|
|
|
|
|
-> Application::Run
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
核心对象关系:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
Application
|
|
|
|
|
|
-> EditorContext
|
|
|
|
|
|
-> EditorWindowManager
|
|
|
|
|
|
-> EditorWindow
|
|
|
|
|
|
-> EditorWindowRuntimeController
|
|
|
|
|
|
-> D3D12WindowRenderer
|
|
|
|
|
|
-> D3D12UiRenderer
|
|
|
|
|
|
-> D3D12WindowRenderLoop
|
|
|
|
|
|
-> EditorWindowContentController
|
|
|
|
|
|
-> EditorWorkspaceWindowContentController
|
|
|
|
|
|
-> EditorUtilityWindowContentController
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`EditorContext` 是全局共享应用状态。每个 workspace window 持有自己的 `UIEditorWorkspaceController` 和 `EditorShellRuntime`。utility window 不持有 workspace controller。
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 显式窗口架构
|
|
|
|
|
|
|
|
|
|
|
|
当前窗口系统已经显式区分两类窗口:
|
|
|
|
|
|
|
|
|
|
|
|
- `EditorWindowCategory::Workspace`
|
|
|
|
|
|
主窗口和由 dock tab / panel 拖出的独立窗口。
|
|
|
|
|
|
- `EditorWindowCategory::Utility`
|
|
|
|
|
|
颜色选择器、Add Component 这类天然工具窗。
|
|
|
|
|
|
|
|
|
|
|
|
两类窗口共享同一个 native host:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
EditorWindow
|
|
|
|
|
|
-> EditorWindowRuntimeController
|
|
|
|
|
|
-> D3D12WindowRenderLoop
|
|
|
|
|
|
-> EditorWindowContentController
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
差异放在 content controller 和 policy 上,而不是靠“有没有 workspace binding”隐式推断。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1 Workspace Window
|
|
|
|
|
|
|
|
|
|
|
|
workspace window 的内容控制器是 `EditorWorkspaceWindowContentController`,内部持有:
|
|
|
|
|
|
|
|
|
|
|
|
- `UIEditorWorkspaceController`
|
|
|
|
|
|
- `EditorShellRuntime`
|
|
|
|
|
|
- `EditorWindowFrameOrchestrator`
|
|
|
|
|
|
|
|
|
|
|
|
这类窗口是完整 shell/workspace 容器。主窗口和 detached workspace window 都属于这一类。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.2 Utility Window
|
|
|
|
|
|
|
|
|
|
|
|
utility window 的内容控制器是 `EditorUtilityWindowContentController`,内部持有:
|
|
|
|
|
|
|
|
|
|
|
|
- `EditorUtilityWindowPanel`
|
|
|
|
|
|
|
|
|
|
|
|
当前 utility 窗口通过 registry/factory 创建,已实现显式 descriptor:
|
|
|
|
|
|
|
|
|
|
|
|
- `EditorUtilityWindowDescriptor`
|
|
|
|
|
|
- `EditorUtilityWindowReusePolicy`
|
|
|
|
|
|
- `EditorWindowChromePolicy`
|
|
|
|
|
|
- `EditorWindowNativeStylePolicy`
|
|
|
|
|
|
|
|
|
|
|
|
当前 `ColorPicker` 和 `AddComponent` 都是单例复用窗口。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 窗口能力与策略
|
|
|
|
|
|
|
|
|
|
|
|
窗口内容能力由 `EditorWindowContentCapabilities` 描述。创建窗口时,host 会校验:
|
|
|
|
|
|
|
|
|
|
|
|
- `Workspace` 分类必须对应具备 workspace capability 的 content controller。
|
|
|
|
|
|
- `Utility` 分类必须对应具备 utility capability 的 content controller。
|
|
|
|
|
|
|
|
|
|
|
|
这一步是硬校验,不再依赖后续 coordinator 通过空 binding 兜底。
|
|
|
|
|
|
|
|
|
|
|
|
窗口外观/宿主策略当前最少包括:
|
|
|
|
|
|
|
|
|
|
|
|
- `EditorWindowChromePolicy`
|
2026-04-25 18:20:17 +08:00
|
|
|
|
当前用于控制 detached title bar tab strip、frame stats,以及 utility window 的 topmost pin 按钮/默认置顶策略。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
- `EditorWindowNativeStylePolicy`
|
|
|
|
|
|
当前用于控制扩展窗口样式和是否复用 host 默认 style。
|
|
|
|
|
|
|
|
|
|
|
|
当前默认规则:
|
|
|
|
|
|
|
|
|
|
|
|
- workspace window 允许 detached title bar tab strip。
|
|
|
|
|
|
- utility window 不允许 detached title bar tab strip。
|
|
|
|
|
|
- utility window 不显示 frame stats。
|
2026-04-25 18:20:17 +08:00
|
|
|
|
- utility window 顶栏显示 topmost pin 按钮,且默认置顶。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
- utility window 使用 `WS_EX_TOOLWINDOW`。
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Workspace / Utility 协调器边界
|
|
|
|
|
|
|
|
|
|
|
|
### 6.1 Workspace Coordinator
|
|
|
|
|
|
|
|
|
|
|
|
`EditorWindowWorkspaceCoordinator` 只处理 `Workspace` 窗口:
|
|
|
|
|
|
|
|
|
|
|
|
- 维护 window workspace set
|
|
|
|
|
|
- 处理 detach panel
|
|
|
|
|
|
- 处理 global tab drag
|
|
|
|
|
|
- 处理 cross-window dock/drop
|
|
|
|
|
|
- 更新 detached workspace title
|
|
|
|
|
|
|
|
|
|
|
|
utility window 不参与:
|
|
|
|
|
|
|
|
|
|
|
|
- workspace set
|
|
|
|
|
|
- dock target hit test
|
|
|
|
|
|
- cross-window drop target
|
|
|
|
|
|
|
|
|
|
|
|
### 6.2 Utility Coordinator
|
|
|
|
|
|
|
|
|
|
|
|
`EditorUtilityWindowCoordinator` 只处理 utility window 请求:
|
|
|
|
|
|
|
|
|
|
|
|
- 根据 `EditorUtilityWindowDescriptor` 创建工具窗
|
|
|
|
|
|
- 按 reuse policy 决定复用还是新建
|
|
|
|
|
|
- 对现有 utility window 做 focus / restore
|
|
|
|
|
|
|
|
|
|
|
|
不要把 utility window 塞进 workspace mutation 流程。
|
|
|
|
|
|
|
|
|
|
|
|
## 7. Frame Request 结构
|
|
|
|
|
|
|
|
|
|
|
|
`EditorWindowFrameTransferRequests` 已拆成两个子域:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
workspace:
|
|
|
|
|
|
beginGlobalTabDrag
|
|
|
|
|
|
detachPanel
|
|
|
|
|
|
|
|
|
|
|
|
utility:
|
|
|
|
|
|
openUtilityWindow
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
规则:
|
|
|
|
|
|
|
|
|
|
|
|
- `EditorWindowWorkspaceCoordinator` 只消费 `transferRequests.workspace`
|
|
|
|
|
|
- `EditorUtilityWindowCoordinator` 只消费 `transferRequests.utility`
|
|
|
|
|
|
- queued immediate frame 也按两个子域分别合并
|
|
|
|
|
|
|
|
|
|
|
|
不要再把 workspace 和 utility 的窗口请求混进同一个平铺字段集合。
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 每帧流程
|
|
|
|
|
|
|
|
|
|
|
|
当前每帧主路径:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
Application::Run
|
|
|
|
|
|
-> EditorWindowManager::RenderAllWindows
|
|
|
|
|
|
-> EditorWindowRuntimeController::BeginFrame
|
|
|
|
|
|
-> EditorWindowRuntimeController::UpdateAndAppend
|
|
|
|
|
|
-> EditorWindowFrameOrchestrator::UpdateAndAppend
|
|
|
|
|
|
-> EditorShellRuntime::Update
|
|
|
|
|
|
-> EditorShellSessionCoordinator::PrepareShellDefinition
|
|
|
|
|
|
-> EditorShellInteractionEngine::Update
|
|
|
|
|
|
-> UpdateUIEditorShellInteraction
|
|
|
|
|
|
-> ViewportHostService::RequestViewport
|
|
|
|
|
|
-> EditorShellSessionCoordinator::FinalizeFrame
|
|
|
|
|
|
-> EditorShellHostedPanelCoordinator::Update
|
|
|
|
|
|
-> EditorShellRuntime::Append
|
|
|
|
|
|
-> EditorWindowRuntimeController::RenderRequestedViewports
|
|
|
|
|
|
-> EditorWindowRuntimeController::Present
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
重要约束:
|
|
|
|
|
|
|
|
|
|
|
|
- viewport 先在 shell layout 阶段通过 `RequestViewport()` 申明尺寸和纹理需求。
|
|
|
|
|
|
- 再在 `RenderRequestedViewports()` 阶段真正渲染。
|
|
|
|
|
|
- 不要打乱这两个阶段的顺序。
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 修改规范
|
|
|
|
|
|
|
2026-04-25 18:20:17 +08:00
|
|
|
|
- 先判断改动属于 framework、app core、windowing seam、Win32 host 还是 rendering host。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
- 小改动优先贴近现有模式,不顺手做跨层重构。
|
|
|
|
|
|
- 新增通用 widget 放 `editor/src` / `editor/include/XCEditor`。
|
|
|
|
|
|
- 新增具体 editor 功能放 `editor/app/Features/<FeatureName>`,再由 composition 装配。
|
2026-04-25 18:20:17 +08:00
|
|
|
|
- 新增 host-facing window content、frame request、content assembly 放 `editor/app/Windowing`。
|
|
|
|
|
|
- 新增 Win32 宿主行为放 `editor/app/Platform/Win32`,通过 seam/controller/policy 与 app core 通信。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
- 新增 viewport 渲染资源或 pass 放 `editor/app/Rendering/Viewport` 或 `editor/resources/shaders/scene-viewport`。
|
|
|
|
|
|
- draw append 只负责绘制,不修改 editor runtime 或 scene/project state。
|
|
|
|
|
|
- D3D12 host、Win32 host、panel 之间避免双向强耦合。
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 当前架构债务
|
|
|
|
|
|
|
|
|
|
|
|
这轮重构完成后,仍有以下债务:
|
|
|
|
|
|
|
2026-04-25 18:20:17 +08:00
|
|
|
|
- `editor/CMakeLists.txt` 还没有把 framework、app core、windowing seam、Win32 host、D3D12 host 拆成独立 target。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
- `EditorContext` 仍然过重,混合了全局状态、service locator、command bridge、session sync 和状态输出。
|
|
|
|
|
|
- `EditorShellRuntime` 仍然过重,既持有 panel,又持有 viewport host、shell frame、draw composer 和 interaction coordinator。
|
|
|
|
|
|
- panel 仍缺少统一 feature 接口,`HierarchyPanel`、`ProjectPanel`、`InspectorPanel` 只是模式相似。
|
2026-04-25 18:20:17 +08:00
|
|
|
|
- `app/Windowing` 目前只是首刀 ownership 调整,workspace / utility window orchestration 仍主要停留在 Win32 coordinator。
|
2026-04-25 17:51:37 +08:00
|
|
|
|
|
|
|
|
|
|
这些债务后续要分步处理,不要一次性重写整个窗口系统。
|
|
|
|
|
|
|
|
|
|
|
|
## 11. 验证基线
|
|
|
|
|
|
|
|
|
|
|
|
当前这轮窗口架构重构的验证状态:
|
|
|
|
|
|
|
|
|
|
|
|
- 用户已完成 GUI 行为验证。
|
|
|
|
|
|
- `cmake --build build --config Debug --target XCUIEditorApp` 已通过。
|
|
|
|
|
|
- `build/editor/Debug/XCEngine.exe` 的 12 秒启动冒烟测试已通过,进程可正常响应关闭请求。
|
|
|
|
|
|
|
|
|
|
|
|
后续涉及窗口架构的改动,至少应维持这条验证基线。
|
|
|
|
|
|
|
|
|
|
|
|
## 12. 推荐阅读入口
|
|
|
|
|
|
|
|
|
|
|
|
开始 editor 相关任务时,优先阅读:
|
|
|
|
|
|
|
|
|
|
|
|
- `editor/CMakeLists.txt`
|
|
|
|
|
|
- `editor/app/Bootstrap/Application.*`
|
|
|
|
|
|
- `editor/app/Composition/EditorContext.*`
|
|
|
|
|
|
- `editor/app/Composition/EditorShellRuntime.*`
|
2026-04-25 18:20:17 +08:00
|
|
|
|
- `editor/app/Windowing/Content/EditorWindowContentController.h`
|
|
|
|
|
|
- `editor/app/Windowing/Frame/EditorWindowFrameOrchestrator.*`
|
2026-04-25 17:51:37 +08:00
|
|
|
|
- `editor/app/Platform/Win32/Windowing/EditorWindow.*`
|
|
|
|
|
|
- `editor/app/Platform/Win32/Windowing/EditorWindowWorkspaceCoordinator.*`
|
|
|
|
|
|
- `editor/app/Platform/Win32/Windowing/EditorUtilityWindowCoordinator.*`
|
|
|
|
|
|
- `editor/app/UtilityWindows/EditorUtilityWindowRegistry.*`
|
|
|
|
|
|
- `editor/include/XCEditor/Workspace/UIEditorWorkspaceController.h`
|
|
|
|
|
|
- `editor/include/XCEditor/Shell/UIEditorShellInteraction.h`
|