Files
XCEngine/docs/api/XCEngine/Editor/UI/DockTabBarChrome/DockTabBarChrome.md
2026-03-29 01:36:53 +08:00

5.1 KiB
Raw Blame History

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::PanelWindowScopeImGui::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_NoTabBarNoWindowMenuButtonNoCloseButton,隐藏 ImGui 原生标签栏。
  • 通过静态 std::unordered_map<ImGuiID, std::vector<ImGuiID>> 维护每个 dock node 的 tab 顺序缓存。
  • 如果当前叶子节点没有显式选中页签,系统会把第一个窗口设为选中页签。
  • 自定义标签条支持:
    • 单击切换选中页签。
    • 左键拖拽改变页签顺序。
    • 满足阈值时将页签从当前 dock 节点拖出,进入 ImGui 原生的 undock 流程。
  • 标签颜色、背景色与分隔线使用 StyleTokens 和 ImGui dock style 的组合结果。
  • 标签宽度当前按文本宽度加固定水平 padding 计算,没有做更复杂的压缩或滚动策略。

这套实现明显不是简单换皮,而是接管了 tab strip 的一部分交互语义。

设计说明

为什么要做这一层,而不是直接接受 ImGui 默认标签栏?

  • 商业编辑器通常会把工作区标签视觉做得更克制、更稳定,以便和工具栏、面板边框形成统一外观。
  • 一旦需要控制页签排序、激活行为、拖出阈值、底部分隔线这些细节,直接用默认样式往往不够。
  • 把这部分逻辑集中在 DockTabBarChrome.h 中,能避免 HierarchySceneConsole 这类面板各自处理 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.hImGuiWindowImGuiDockNode 等内部实现细节,升级 ImGui 时需要重点回归。
  • 当前没有 close button、window menu button也没有更复杂的 tab overflow 处理。
  • tab 顺序缓存是进程内静态状态,不是跨会话布局资产。
  • 这是 Editor 专用 UI 基建,不适合直接当作通用运行时 UI API 使用。

相关文档