Tighten new editor shell chrome and add dock convergence plan

This commit is contained in:
2026-04-10 21:05:07 +08:00
parent 503e6408ed
commit 87ad489bfd
13 changed files with 549 additions and 179 deletions

View File

@@ -0,0 +1,364 @@
# XCEditor Dock统一与Tab拖拽停靠收口计划
日期:`2026-04-10`
## 1. 文档定位
这份计划只解决 `XCEditor` 当前 dock 基础层的两个核心问题:
1. `Hierarchy / Inspector``Scene / Game / Console / Project` 顶部 chrome 不是同一套。
2. tab 不能像旧 `editor/` 的 ImGui docking 那样拖拽重排与调整停靠位置。
这两个问题本质上是同一个根问题:当前 `DockHost` 的叶子语义和渲染路径没有统一,导致视觉、命中、交互、布局变更都被拆成两套,后续再堆业务面板只会继续在错误基础上加复杂度。
本计划属于 `Editor` 基础层收口,不属于业务面板重建计划。
在这份计划完成前,不继续推进 `new_editor``Project / Hierarchy / Inspector / Console` 业务重建。
## 2. 当前问题与根因
## 2.1 当前现象
- `Hierarchy / Inspector` 的 header 仍然走 standalone panel 外壳。
- `Scene / Game / Console / Project` 走 tab stack 外壳。
- 用户看到的直接结果是tab 高度、内边距、标题区结构、可交互区域都不一致。
- 用户尝试拖 tab 时,没有任何重排、合并、分裂停靠反馈。
## 2.2 当前真实根因
当前实现里同时存在两种叶子形态:
- `Panel`
- `TabStack`
这使得 `DockHost` 的整条链路都被拆成两套:
- 布局输出分叉
- 绘制分叉
- hit test 分叉
- 交互分叉
- 未来的 docking mutation 也无从统一落点
当前代码里的直接证据:
- `new_editor/app/Shell/ProductShellAsset.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorDockHost.h`
- `new_editor/src/Shell/UIEditorDockHost.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorDockHostInteraction.h`
- `new_editor/src/Shell/UIEditorDockHostInteraction.cpp`
- `new_editor/include/XCEditor/Collections/UIEditorTabStripInteraction.h`
- `new_editor/src/Collections/UIEditorTabStripInteraction.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceController.h`
- `new_editor/src/Shell/UIEditorWorkspaceController.cpp`
- `new_editor/src/Shell/UIEditorWorkspaceLayoutPersistence.cpp`
当前控制器层只具备:
- `OpenPanel`
- `ClosePanel`
- `ShowPanel`
- `HidePanel`
- `ActivatePanel`
- `ResetWorkspace`
- `SetSplitRatio`
还没有真正支撑 docking 的命令与树变更能力:
- `ReorderTab`
- `MoveTabToStack`
- `DockTabRelative`
- `ExtractTab`
- `MergeTabStack`
## 3. 改造目标
本轮收口后的目标状态如下:
1. 运行态叶子节点只保留一种语义:`TabStack`
2. 单面板也被视为“只有一个 tab 的 tab stack”。
3. `DockHost` 只保留一套统一的 `DockHeader / TabWell / ContentBody` 视觉结构。
4. `Hierarchy / Inspector``Scene / Game / Console / Project` 必须走同一套 header/tab primitive。
5. tab 至少支持:
- 同 stack 重排
- 跨 stack 合并
- 向目标 leaf 的 `left/right/top/bottom/center` 停靠
6. 拖拽过程中必须有明确 preview不允许“拖了但没有反馈”。
7. workspace 布局持久化必须覆盖新结构,并兼容旧布局升级。
8.`tests/UI/Editor` 中补齐单元测试与集成测试后,才允许继续推进业务面板。
## 4. 范围边界
## 4.1 本轮必须做
- `XCEditor` 的 dock 叶子语义统一
- dock chrome 统一
- tab 拖拽状态机
- docking drop target 与 preview overlay
- workspace tree surgery
- layout persistence 升级
- `tests/UI/Editor` 的回归补齐
## 4.2 本轮明确不做
- 多原生窗口 detached docking
- 浮动窗口系统
- 业务面板内部复杂逻辑重建
- `Runtime UI` 相关能力
-`Editor` 再做一套资源化主题体系
`Editor` 当前继续采用固定代码样式,不走 UI 资源那套。
## 5. 目标结构
## 5.1 统一后的 workspace 叶子模型
运行态只保留:
- `SplitNode`
- `TabStackNode`
其中 `TabStackNode` 内部包含:
- `tabs`
- `selectedTabId`
- `activePanelId`
不再保留“裸 `Panel` 叶子节点”这种视觉语义。
## 5.2 统一后的 dock 布局输出
`DockHost` 最终应面向统一 leaf 输出:
- `tabWellRect`
- `contentBodyRect`
- `selectedPanelId`
- `tabItems`
- `dropPreview`
不再分成:
- `panelLayouts`
- `tabStackLayouts`
两套平行分支。
## 5.3 统一后的交互分层
交互链路收口为:
1. `UIEditorTabStripInteraction`
- 负责 tab press / armed / drag / release / cancel
2. `UIEditorDockHostInteraction`
- 负责把 tab 拖拽映射为 docking preview 与 docking command
3. `UIEditorWorkspaceController`
- 负责真正修改 workspace tree
4. `UIEditorWorkspaceLayoutPersistence`
- 负责新旧布局读写与升级
## 6. 分阶段执行计划
## Phase A统一叶子语义
### 目标
把 workspace 运行态的叶子语义统一到 `TabStackNode`,彻底消除 standalone panel 叶子。
### 任务
- 调整 `UIEditorWorkspaceModel`,明确叶子节点只允许 `TabStackNode`
- 调整 `ProductShellAsset` 与默认 workspace 构建逻辑,让单面板默认也生成单-tab stack。
- 调整 `UIEditorWorkspaceSession`,保证 active/selected 状态都围绕 tab stack 工作。
- 调整 `UIEditorWorkspaceLayoutPersistence`,读旧格式时自动升级为统一 leaf 结构。
- 增加 degenerate tree cleanup
- 空 stack 删除
- 单子 split 折叠
- 非法 selectedTab 修正
### 完成标准
- 运行态 workspace 中不再出现 standalone panel 叶子。
- 旧布局能被自动升级并正常显示。
## Phase B统一 dock chrome 与布局输出
### 目标
让所有 panel 顶部都走同一套 dock header / tab well primitive。
### 任务
- 重构 `UIEditorDockHost` 的 layout 输出结构,改为统一 leaf 布局。
- 删除 standalone panel 与 tab stack 的渲染分叉。
- `UIEditorPanelFrame` 缩回“边框与 body 外壳”职责,不再自带独立 header 风格。
- `UIEditorTabStrip` 成为唯一 tab/header 渲染入口。
- `UIEditorPanelContentHost` 只根据统一 leaf layout 定位 panel body。
- 统一 hit target 语义,保证 header/tab/body 命中都来自同一套结构。
### 完成标准
- `Hierarchy / Inspector / Scene / Game / Console / Project` 顶部结构完全统一。
- tab 高度、padding、命中区域、激活态样式只由一套 metric/palette 控制。
## Phase C同 stack tab 拖拽重排
### 目标
先把最小闭环做稳:同一个 stack 内 tab 可拖拽重排。
### 任务
-`UIEditorTabStripInteraction` 增加拖拽状态机:
- `pressed`
- `armed`
- `dragging`
- `cancelled`
- `committed`
- 增加 drag threshold、pointer capture、Esc cancel、release commit。
- 在同 stack 内计算插入位置与 preview insertion marker。
-`UIEditorWorkspaceController` 增加 `ReorderTab(...)`
- 保证 selected/active/focus 状态在重排后仍然正确。
### 完成标准
- 同一 tab strip 内可拖拽重排。
- 有明确插入线 preview。
- 无闪烁、无丢焦、无错误激活。
## Phase D跨 stack 合并与 split docking
### 目标
把 tab 从“只能在本组重排”扩展到“可跨组移动并形成新停靠布局”。
### 任务
-`DockHostInteraction` 中引入 drop target 解析:
- `center`
- `left`
- `right`
- `top`
- `bottom`
- `root empty area`
- 增加 preview overlay
- center merge 预览
- edge split 高亮预览
- 同 stack reorder 线性预览
-`WorkspaceController` 中增加:
- `MoveTabToStack(...)`
- `DockTabRelative(...)`
- `ExtractTab(...)`
- `MergeTabStack(...)`
- 增加 tree surgery
- 从源 stack 抽 tab
- 插入目标 stack
- 围绕目标 leaf 生成 split
- 空 stack 清理
- 单子 split 折叠
### 完成标准
- tab 可从一个 stack 拖到另一个 stack。
- 可通过 `left/right/top/bottom/center` 形成新布局。
- 交互有实时 preview。
## Phase E持久化、回归与测试体系补齐
### 目标
把新 docking 结构正式纳入 `tests/UI/Editor` 的标准回归。
### 任务
- 更新 layout serialization稳定写回统一 leaf 结构。
- 旧布局读取时自动升级。
- 补齐 `tests/UI/Editor/unit`
- 旧布局升级
- 同 stack reorder
- 跨 stack merge
- split docking
- cleanup collapse
- active/selected 同步
- persistence round-trip
- 补齐 `tests/UI/Editor/integration`
- `shell/dock_header_unified`
- `shell/dock_tab_reorder_same_stack`
- `shell/dock_tab_move_between_stacks`
- `shell/dock_tab_split_targets`
- `state/dock_layout_persistence`
- 每个集成测试 exe 顶部写清楚当前验证目标,不再只写模糊状态文本。
### 完成标准
- `tests/UI/Editor` 对新 docking 具备完整回归入口。
- 后续业务面板接入时,不需要再倒回头修基础 docking 架构。
## 7. 代码落点
本轮预计主要改动路径:
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceModel.h`
- `new_editor/src/Shell/UIEditorWorkspaceModel.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceController.h`
- `new_editor/src/Shell/UIEditorWorkspaceController.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceLayoutPersistence.h`
- `new_editor/src/Shell/UIEditorWorkspaceLayoutPersistence.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceSession.h`
- `new_editor/src/Shell/UIEditorWorkspaceSession.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorDockHost.h`
- `new_editor/src/Shell/UIEditorDockHost.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorDockHostInteraction.h`
- `new_editor/src/Shell/UIEditorDockHostInteraction.cpp`
- `new_editor/include/XCEditor/Collections/UIEditorTabStripInteraction.h`
- `new_editor/src/Collections/UIEditorTabStripInteraction.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorPanelFrame.h`
- `new_editor/src/Shell/UIEditorPanelFrame.cpp`
- `new_editor/include/XCEditor/Shell/UIEditorPanelContentHost.h`
- `new_editor/src/Shell/UIEditorPanelContentHost.cpp`
- `new_editor/app/Shell/ProductShellAsset.cpp`
- `tests/UI/Editor/unit/*dock*`
- `tests/UI/Editor/unit/*workspace*`
- `tests/UI/Editor/integration/shell/*dock*`
- `tests/UI/Editor/integration/state/layout_persistence/*`
## 8. 并行拆分建议
这轮改造可以拆成 4 条可并行子线,但必须按主从顺序集成:
1. `WorkspaceModel / Controller / Persistence`
2. `DockHost layout / render / hit-test 统一`
3. `TabStripInteraction / DockHostInteraction` 拖拽状态机
4. `tests/UI/Editor` 单元与集成回归补齐
并行原则:
- 先以 `Phase A` 的统一 leaf 语义为总前提。
- `Phase B``Phase C` 可以在统一模型落定后并行推进。
- `Phase E` 可以在 `Phase C / D` 功能接口稳定后并行补齐。
## 9. 风险与控制
## 9.1 最大风险
- 旧布局兼容被打断
- 统一叶子后现有 panel body 定位错位
- 拖拽状态机与 focus/capture 冲突
- split tree surgery 产生退化树或悬空 active panel
## 9.2 控制方式
- 先做模型统一,再做交互,不反过来堆补丁
- 每个 mutation 先补 `unit` 再补 `integration`
- 任何旧布局兼容问题都在 persistence 层处理,不在渲染层写兼容分叉
- 任何单面板特殊视觉都回收为单-tab stack不再恢复 standalone panel 路径
## 10. 收口判定
只有同时满足以下条件,才算这轮 dock 基础层真正收口:
1. 所有 dock 叶子统一为 `TabStackNode`
2. `Hierarchy / Inspector``Scene / Game / Console / Project` 头部视觉完全统一。
3. tab 可同组重排、跨组合并、左右上下停靠。
4. 拖拽过程有稳定 preview释放后结果正确。
5. 布局可持久化,旧布局可升级。
6. `tests/UI/Editor/unit + integration` 已覆盖关键回归。
在这 6 条完成前,不进入下一轮业务面板重建。