6.8 KiB
Widgets
命名空间: XCEngine::Editor::UI
类型: header-helper
源文件: editor/src/UI/Widgets.h
描述: 面向编辑器业务语义的高层 ImGui helper 集合,覆盖菜单、搜索框、行内重命名、面包屑、资产卡片、Inspector section、弹窗和日志行等可复用交互单元。
概述
Widgets.h 不是底层绘图原语集合,而是“已经带编辑器语义”的复用控件层。
它的定位介于:
Core.h、StyleTokens.h这类基础 UI 封装- 具体面板文件里的业务流程
之间。
当前多个关键面板都直接依赖它:
ProjectPanelHierarchyPanelInspectorPanelConsolePanel
所以这份 header 的核心价值,不是减少几行 ImGui 代码,而是统一整个 editor 的交互语言。
当前覆盖的 widget 类别
| 类别 | 代表 API | 主要使用场景 |
|---|---|---|
| 菜单与子菜单 | DrawMenuScope、DrawMenuCommand、DrawMenuCommands、DrawPopupSubmenuScope |
MenuBar、Hierarchy / Project 上下文菜单 |
| 工具栏与搜索 | ToolbarSearchField、DrawToolbarLabel、ToolbarToggleButton |
Project / Console / 顶部工具栏 |
| 行内编辑 | DrawInlineRenameField、DrawInlineRenameFieldAt |
Project 资源网格重命名、Hierarchy 行内重命名 |
| 路径导航 | DrawToolbarBreadcrumbs、DrawBreadcrumbSegment |
Project 面包屑 |
| 资产浏览 | ComputeAssetTileSize、DrawAssetTile、AssetTileOptions |
Project 浏览区 |
| Inspector section | BeginComponentSection、EndComponentSection、InspectorActionButton |
Inspector 组件区块、材质资源区块 |
| 弹窗与对话框 | BeginTitledPopup、DrawDialogActionRow |
选择器、确认弹窗 |
| 提示与日志 | BeginTitledTooltip、DrawConsoleLogRow、DrawEmptyState、DrawHintText |
Console、空状态、悬浮提示 |
为什么这一层很重要
即时模式 UI 最容易出现的问题,不是“没法画出来”,而是:
- 同一种交互在不同面板里长得不一样
- 每个面板都自己实现一份重命名输入框
- 上下文菜单、面包屑、资产卡片的行为逐渐漂移
Widgets.h 当前就是专门用来压住这类分叉的。
它把“编辑器里反复出现的交互模式”抽成统一 helper,使面板层可以更专注于:
- 当前数据来自哪里
- 当前用户动作应该触发什么命令
而不是反复造相同的 UI 小轮子。
结果结构而不是直接副作用
当前文件一个很重要的风格,是尽量用结果结构返回交互状态,而不是在 helper 内部直接改业务对象。
例如:
AssetTileResultInlineRenameFieldResultComponentSectionResult
这种做法对 ImGui 风格 editor 很关键,因为调用方通常需要:
- 先绘制
- 再统一在循环外处理选择、打开、导航、提交重命名
ProjectPanel 当前就是典型例子。它先批量收集 clicked / openRequested,再在循环末统一处理 selection 和 open 行为,避免在遍历过程中破坏当前容器或导航状态。
关键 helper 行为
搜索框
ToolbarSearchField(...) 当前除了调用 InputTextWithHint(...),还会:
- 应用统一的工具栏输入框样式
- 按
trailingWidth自动计算可用宽度 - 在输入框左侧手动画搜索图标
这意味着 Project 等工具栏的搜索控件已经有统一视觉和布局语义,而不是普通裸 InputText。
行内重命名
DrawInlineRenameField(...) 和 DrawInlineRenameFieldAt(...) 当前返回:
submittedcancelRequesteddeactivatedactive
这几个状态组合非常实用,因为编辑器行内重命名通常既要响应:
- Enter 提交
- Escape 取消
- 失焦提交或结束
又要允许调用方控制焦点请求和屏幕定位。
面包屑
DrawToolbarBreadcrumbs(...) 当前把 root label、路径段数量、名称回调和导航回调解耦开来。
它的行为是:
- 当前段不可点击
- 非当前段点击后回调
navigateToSegment(index) - 相邻段之间统一插入
>分隔符
ProjectPanel 正是靠它把 Assets -> ... -> CurrentFolder 渲染成稳定的导航条。
资产卡片
DrawAssetTile(...) 是当前 Project Browser 最核心的共享 widget 之一。
它会统一处理:
- 空闲边框与填充
- 选中态高亮
- 拖拽中的 dim overlay
- 图标居中布局
- 标签区域裁剪
- 单击和双击判断
并返回:
clickedopenRequestedhoveredlabelMin / labelMax
其中 labelMin / labelMax 会被 ProjectPanel 继续拿去覆盖行内重命名输入框位置。
Inspector section
BeginComponentSection(...) 当前做的不只是画一个标题行。它还负责:
- 用 ImGui state storage 按
id保存展开状态 - 绘制 disclosure arrow
- 统一 header 背景、边框和文字布局
- 返回内容缩进量
这让 InspectorPanel 和材质资源 inspector 可以在完全共享的 section 语义上继续叠加各自内容。
Popup 子菜单
DrawPopupSubmenuScope(...) 是当前比较有“编辑器修 bug 痕迹”的 helper。
它除了处理 popup 子菜单的 hover-open / click-open / auto-close 之外,还会对标签为 Create 的子菜单写调试日志,用来定位 Hierarchy 创建子菜单 popup 状态错乱问题。
这说明 Widgets.h 不只是“视觉控件库”,也承担了一部分复杂交互协议的收口工作。
真实调用方式
当前几个典型使用点是:
ProjectPanelToolbarSearchField(...)DrawToolbarBreadcrumbs(...)DrawAssetTile(...)DrawInlineRenameFieldAt(...)
InspectorPanelBeginComponentSection(...)InspectorActionButton(...)DrawHintText(...)DrawEmptyState(...)
HierarchyActionRouterDrawMenuCommands(...)DrawPopupSubmenuScope(...)
ConsolePanelDrawConsoleLogRow(...)
设计说明
当前 Widgets.h 的设计取向很明确:
- 保持 header-only,降低调用成本
- 通过小结果结构承载交互状态
- 让多个面板共享一致的 UI 语义
这是一种很典型的 Dear ImGui 编辑器写法。它未必“面向通用 GUI 框架”,但对当前项目这种单体 editor 非常高效。
当前限制
- 仍然是 inline helper 集合,不是独立 widget framework。
- 某些 helper 明显服务于当前视觉风格和业务模型,通用性有限。
- 目前没有虚拟列表、树过滤高亮、多列资产表等更重型控件。
Create子菜单相关 trace 直接写日志通道,后续若日志层细化,可能需要单独的 debug 开关。