5.1 KiB
5.1 KiB
DockTabBarChrome
命名空间: XCEngine::Editor::UI
类型: header-helper
源文件: editor/src/UI/DockTabBarChrome.h
描述: 基于 ImGui Docking 内部节点实现自定义停靠标签栏外观、选中逻辑、拖拽排序与拖出浮动行为。
概述
DockTabBarChrome.h 是当前 Editor UI 里技术耦合度最高的一层 helper 之一。它的职责不是创建 dockspace,而是在 ImGui 已经提供 docking 能力的前提下,把默认标签栏替换成一套更像商业编辑器的自定义标签栏。
当前这套方案由两部分组成:
ConfigureDockTabBarChrome(...)递归配置 dock node,关闭原生 tab bar,并确保叶子节点处于可绘制的稳定状态。DrawDockedWindowTabStrip()在具体面板窗口内部补画自定义标签条。
从调用关系上看:
DockLayoutController::RenderDockspace()负责每帧配置 dockspace 节点。PanelChrome::PanelWindowScope在ImGui::Begin(...)成功后调用DrawDockedWindowTabStrip()。
也就是说,这一层本质上是“布局层 + 面板 chrome 层”的协作产物,而不是某一个面板自己的私有实现。
建议视为公开入口的函数
虽然头文件里存在很多 inline helper,但从设计意图上,真正应该被其他模块直接依赖的入口主要只有下面三个:
| 成员 | 说明 |
|---|---|
ConfigureDockTabBarChrome(ImGuiDockNode* node) |
对指定 dock node 递归应用自定义 tab bar 策略。 |
ConfigureDockTabBarChrome(ImGuiID dockspaceId) |
通过 dockspace id 找到 root node 并应用同样策略。 |
DrawDockedWindowTabStrip() |
在当前面板窗口顶部绘制自定义标签条。 |
其他诸如 DockTabOrderCache()、ReorderDockTab(...)、BeginCustomDockTabUndock(...) 之类的函数,虽然在头文件可见,但更适合作为当前实现细节理解,而不是稳定的上层调用契约。
当前实现行为
按 editor/src/UI/DockTabBarChrome.h 的实现,当前版本具备以下行为:
- 对叶子
ImGuiDockNode会强制设置ImGuiDockNodeFlags_NoTabBar、NoWindowMenuButton、NoCloseButton,隐藏 ImGui 原生标签栏。 - 通过静态
std::unordered_map<ImGuiID, std::vector<ImGuiID>>维护每个 dock node 的 tab 顺序缓存。 - 如果当前叶子节点没有显式选中页签,系统会把第一个窗口设为选中页签。
- 自定义标签条支持:
- 单击切换选中页签。
- 左键拖拽改变页签顺序。
- 满足阈值时将页签从当前 dock 节点拖出,进入 ImGui 原生的 undock 流程。
- 标签颜色、背景色与分隔线使用
StyleTokens和 ImGui dock style 的组合结果。 - 标签宽度当前按文本宽度加固定水平 padding 计算,没有做更复杂的压缩或滚动策略。
这套实现明显不是简单换皮,而是接管了 tab strip 的一部分交互语义。
设计说明
为什么要做这一层,而不是直接接受 ImGui 默认标签栏?
- 商业编辑器通常会把工作区标签视觉做得更克制、更稳定,以便和工具栏、面板边框形成统一外观。
- 一旦需要控制页签排序、激活行为、拖出阈值、底部分隔线这些细节,直接用默认样式往往不够。
- 把这部分逻辑集中在
DockTabBarChrome.h中,能避免Hierarchy、Scene、Console这类面板各自处理 dock 标签外观。
如果和 Unity 的使用体验类比,这层更像“编辑器工作区标签栏的定制实现”,而不是某个单独窗口组件。
前置条件与线程语义
- 只能在启用了 ImGui Docking 的编辑器 UI 帧里使用。
ConfigureDockTabBarChrome(...)应在 dockspace 建立后、面板开始绘制前调用;当前由DockLayoutController统一负责。DrawDockedWindowTabStrip()需要当前窗口已经Begin(...)成功且窗口处于 docked 状态;当前由PanelWindowScope自动调用。- 这一层依赖
imgui_internal.h暴露的内部结构,应视为 UI 主线程专用逻辑,不具备线程安全保证。
典型用法
const ImGuiID dockspaceId = ImGui::GetID("MainDockspace.Root");
UI::ConfigureDockTabBarChrome(dockspaceId);
{
UI::DockHostStyleScope dockHostStyle;
ImGui::DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockFlags);
}
面板窗口不需要自己手写标签条调用,使用 PanelWindowScope 时会自动进入:
UI::PanelWindowScope panel("Hierarchy");
当前限制
- 强依赖
imgui_internal.h、ImGuiWindow、ImGuiDockNode等内部实现细节,升级 ImGui 时需要重点回归。 - 当前没有 close button、window menu button,也没有更复杂的 tab overflow 处理。
- tab 顺序缓存是进程内静态状态,不是跨会话布局资产。
- 这是 Editor 专用 UI 基建,不适合直接当作通用运行时 UI API 使用。