# Widgets **命名空间**: `XCEngine::Editor::UI` **类型**: `header-helper` **源文件**: `editor/src/UI/Widgets.h` **描述**: 面向编辑器业务语义的高层 ImGui helper 集合,覆盖菜单、搜索框、行内重命名、面包屑、资产卡片、Inspector section、弹窗和日志行等可复用交互单元。 ## 概述 `Widgets.h` 不是底层绘图原语集合,而是“已经带编辑器语义”的复用控件层。 它的定位介于: - `Core.h`、`StyleTokens.h` 这类基础 UI 封装 - 具体面板文件里的业务流程 之间。 当前多个关键面板都直接依赖它: - `ProjectPanel` - `HierarchyPanel` - `InspectorPanel` - `ConsolePanel` 所以这份 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 内部直接改业务对象。 例如: - `AssetTileResult` - `InlineRenameFieldResult` - `ComponentSectionResult` 这种做法对 ImGui 风格 editor 很关键,因为调用方通常需要: - 先绘制 - 再统一在循环外处理选择、打开、导航、提交重命名 `ProjectPanel` 当前就是典型例子。它先批量收集 `clicked` / `openRequested`,再在循环末统一处理 selection 和 open 行为,避免在遍历过程中破坏当前容器或导航状态。 ## 关键 helper 行为 ### 搜索框 `ToolbarSearchField(...)` 当前除了调用 `InputTextWithHint(...)`,还会: - 应用统一的工具栏输入框样式 - 按 `trailingWidth` 自动计算可用宽度 - 在输入框左侧手动画搜索图标 这意味着 Project 等工具栏的搜索控件已经有统一视觉和布局语义,而不是普通裸 `InputText`。 ### 行内重命名 `DrawInlineRenameField(...)` 和 `DrawInlineRenameFieldAt(...)` 当前返回: - `submitted` - `cancelRequested` - `deactivated` - `active` 这几个状态组合非常实用,因为编辑器行内重命名通常既要响应: - Enter 提交 - Escape 取消 - 失焦提交或结束 又要允许调用方控制焦点请求和屏幕定位。 ### 面包屑 `DrawToolbarBreadcrumbs(...)` 当前把 root label、路径段数量、名称回调和导航回调解耦开来。 它的行为是: - 当前段不可点击 - 非当前段点击后回调 `navigateToSegment(index)` - 相邻段之间统一插入 `>` 分隔符 `ProjectPanel` 正是靠它把 `Assets -> ... -> CurrentFolder` 渲染成稳定的导航条。 ### 资产卡片 `DrawAssetTile(...)` 是当前 Project Browser 最核心的共享 widget 之一。 它会统一处理: - 空闲边框与填充 - 选中态高亮 - 拖拽中的 dim overlay - 图标居中布局 - 标签区域裁剪 - 单击和双击判断 并返回: - `clicked` - `openRequested` - `hovered` - `labelMin / 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` 不只是“视觉控件库”,也承担了一部分复杂交互协议的收口工作。 ## 真实调用方式 当前几个典型使用点是: - `ProjectPanel` - `ToolbarSearchField(...)` - `DrawToolbarBreadcrumbs(...)` - `DrawAssetTile(...)` - `DrawInlineRenameFieldAt(...)` - `InspectorPanel` - `BeginComponentSection(...)` - `InspectorActionButton(...)` - `DrawHintText(...)` - `DrawEmptyState(...)` - `HierarchyActionRouter` - `DrawMenuCommands(...)` - `DrawPopupSubmenuScope(...)` - `ConsolePanel` - `DrawConsoleLogRow(...)` ## 设计说明 当前 `Widgets.h` 的设计取向很明确: - 保持 header-only,降低调用成本 - 通过小结果结构承载交互状态 - 让多个面板共享一致的 UI 语义 这是一种很典型的 Dear ImGui 编辑器写法。它未必“面向通用 GUI 框架”,但对当前项目这种单体 editor 非常高效。 ## 当前限制 - 仍然是 inline helper 集合,不是独立 widget framework。 - 某些 helper 明显服务于当前视觉风格和业务模型,通用性有限。 - 目前没有虚拟列表、树过滤高亮、多列资产表等更重型控件。 - `Create` 子菜单相关 trace 直接写日志通道,后续若日志层细化,可能需要单独的 debug 开关。 ## 相关文档 - [UI](../UI.md) - [Core](../Core/Core.md) - [ProjectPanel](../../panels/ProjectPanel/ProjectPanel.md) - [InspectorPanel](../../panels/InspectorPanel/InspectorPanel.md) - [HierarchyActionRouter](../../Actions/HierarchyActionRouter/HierarchyActionRouter.md)