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

5.4 KiB
Raw Blame History

HierarchyPanel

命名空间: XCEngine::Editor

类型: class

源文件: editor/src/panels/HierarchyPanel.h

描述: 编辑器场景层级面板,负责绘制根实体树、处理选择与重命名事件,并把上下文菜单与拖放操作路由给 Action 层。

概述

HierarchyPanel 是当前编辑器里最典型的“视图层面板”:它自己拥有 UI 状态,但不直接承担场景编辑命令实现。它的主要任务是把当前场景对象以树形方式呈现出来,并把用户交互转换成选择、重命名、右键菜单和拖放请求。

按当前实现,这个面板主要负责:

  • 订阅选择变化与外部重命名请求事件。
  • 读取 ISceneManager 提供的根实体列表。
  • 基于 UI::TreeView 递归绘制场景对象树。
  • 维护内联重命名状态。
  • 将选择、右键菜单、拖放等行为委托给 Actions::HierarchyActionRouter 一侧的 helper。

这和商业引擎编辑器的分层很一致Hierarchy 面板负责“看见和触发”,而不是直接“改数据和执行业务命令”。

当前实现行为

editor/src/panels/HierarchyPanel.cpp 的实现:

  • OnAttach() 会订阅:
    • SelectionChangedEvent
    • EntityRenameRequestedEvent
  • OnDetach() 会正确取消订阅并清零 handler id。
  • Render() 会:
    • 应用 HierarchyInspectorPanelBackgroundColor()
    • 通过 PanelWindowScope / PanelContentScope 建立标准面板外壳。
    • 调用 Actions::ObserveFocusedActionRoute(...) 将当前焦点路由标记为 Hierarchy
    • ISceneManager 读取根实体并逐个递归渲染。
    • 在树绘制完成后处理背景点击、背景右键菜单、实体右键菜单和根级 drop target。

节点绘制模型

当前的节点绘制已经不再是旧版本那种局部自定义树,而是完全建立在 UI::TreeView 之上:

  • 每个实体节点都会构造一个 UI::TreeNodeDefinition
  • selected 状态来自 ISelectionManager::IsSelected(...)
  • leaf 状态来自 gameObject->GetChildCount() == 0
  • persistenceKey 使用 gameObject->GetUUID() 转成字符串,保证展开状态在同一面板实例中稳定。
  • style 使用 UI::HierarchyTreeStyle()
  • prefix 使用 UI::NavigationTreePrefixWidth()UI::DrawAssetIcon(..., AssetIconKind::GameObject) 绘制对象图标。

这意味着当前 Hierarchy 的视觉和交互行为已经被统一纳入 Editor UI 基础设施,而不是面板自己手工维护整套树渲染细节。

交互行为

当前节点交互通过 TreeNodeCallbacks 接入:

  • 单击左键:调用 Actions::HandleHierarchySelectionClick(...),支持结合 Ctrl 执行多选。
  • 右键:调用 Actions::HandleHierarchyItemContextRequest(...) 打开目标实体上下文菜单。
  • 双击:调用 BeginRename(...) 进入内联重命名。
  • 节点额外渲染阶段:调用 Actions::BeginHierarchyEntityDrag(...)Actions::AcceptHierarchyEntityDrop(...) 接入拖放。

因此 HierarchyPanel 自己不直接执行“重排父子关系”之类操作,它只负责在正确的节点生命周期里提供 drop source / target 入口。

重命名模型

HierarchyPanel 当前用 UI::InlineTextEditState<uint64_t, 256> 保存重命名状态。

当前行为是:

  • 外部若派发 EntityRenameRequestedEvent,面板会在 OnRenameRequested(...) 中找到实体并进入重命名。
  • 若用户双击树节点,也会进入重命名。
  • 编辑过程中:
    • Enter 提交。
    • Escape 取消。
    • 输入框失焦且用户左键点击其他位置时提交。
  • CommitRename() 最终通过 Actions::CommitEntityRename(...) 把改名请求发往动作层。

这类实现很像商业编辑器中的“inline rename controller”面板持有输入框状态但真正的实体改名仍然走统一命令路径。

生命周期与线程语义

  • 该面板依赖有效的 IEditorContext 才能 attach、订阅事件并绘制。
  • 事件订阅和 UI 绘制都应视为编辑器主线程行为。
  • m_treeStatem_renameState 都属于面板实例私有状态,不会自动跨会话持久化。

设计说明

当前实现的一个正确方向是Hierarchy 面板只负责“把场景对象转成 Editor UI 语义”,而不是把所有业务都塞进面板里。

这样做的收益是:

  • 树视图风格、图标前缀、展开行为可以和 ProjectPanel 共享。
  • 选择、重命名、上下文菜单、拖放都能被 Actions 层集中治理。
  • 面板本身更容易继续重构,比如后续加入搜索、过滤、批量操作时,不必推翻底层树控件。

当前限制

  • 当前没有搜索、过滤、排序或大场景虚拟化能力。
  • 展开状态只保存在 UI::TreeViewState 的内存态中,不会自动写入布局文件。
  • 重命名输入框是替换式绘制,不是“树节点原位嵌入子控件”的更复杂实现。
  • 目前只为每个节点提供统一的 GameObject 图标前缀,没有按组件类型做更细粒度图标区分。

相关文档