4.6 KiB
4.6 KiB
PropertyLayout
命名空间: XCEngine::Editor::UI
类型: header-helper + struct
源文件: editor/src/UI/PropertyLayout.h
描述: 为 Inspector 属性行提供统一的标签列 / 控件列几何计算,并把具体控件绘制委托给回调。
概述
PropertyLayout.h 是当前 Inspector 体验能否“像一个成熟编辑器”而不是“像一堆临时摆放的 ImGui 控件”的关键基础设施。
它不直接定义浮点框、复选框或向量输入框,而是先回答一个更底层的问题:
- 标签列从哪里开始?
- 控件列从哪里开始?
- 当前行有多高?
- 控件应该拿到多宽的可用空间?
把这层几何计算独立出来以后,ScalarControls、VectorControls、PropertyGrid 这些上层 helper 就可以共享同一套 Inspector 排版规则,而不需要每种控件都重复手算列宽和光标位置。
公开 API
| 成员 | 说明 |
|---|---|
PropertyLayoutSpec |
描述标签缩进、控件列起点、标签和控件间距、控件右侧留白。 |
PropertyLayoutMetrics |
保存一行属性被计算出的实际几何结果。 |
MakePropertyLayout() |
生成使用默认 token 的 PropertyLayoutSpec。 |
PushPropertyLayoutStyles() |
推入当前属性行需要的样式变量。 |
GetPropertyControlWidth(...) |
根据布局结果返回控件区域宽度。 |
SetNextPropertyControlWidth(...) |
用布局结果直接设置下一个控件的宽度。 |
AlignPropertyControlToRight(...) |
让较窄控件在属性列中右对齐。 |
DrawPropertyRow(...) |
绘制一整行属性,并把具体控件绘制委托给回调。 |
当前实现行为
按 editor/src/UI/PropertyLayout.h 的实现:
PropertyLayoutSpec的默认值直接来自StyleTokens.h,例如InspectorPropertyControlColumnStart()与InspectorPropertyLabelInset()。PushPropertyLayoutStyles()当前只推入ImGuiStyleVar_FramePadding,并不负责整套 Inspector 样式。DrawPropertyRow(...)会:- 以
label为PushID的依据。 - 读取当前内容区宽度并计算一整行的 label / control 几何。
- 直接用
ImDrawList::AddText(...)绘制标签文本,而不是创建一个独立的 ImGui label item。 - 把光标移动到控件列起点,再调用外部回调绘制真正的控件。
- 最后用
Dummy(...)吃掉这一行占用的高度,确保后续布局连续。
- 以
这说明它是一层“布局执行器”,不是单纯的常量集合。
设计说明
商业引擎编辑器通常会把 Inspector 的“字段布局规则”和“字段编辑控件”拆开,这一点和 Unity Inspector 的使用体验很像:
- 左边是稳定的属性标签列。
- 右边是不同类型字段共享的一列编辑区域。
- 上层组件编辑器只描述“这里是一条 Position / Rotation / Scale”,而不是自己计算每个字段的横向坐标。
这样拆分的收益非常直接:
- 所有组件编辑器天然保持一致的列对齐。
- 以后如果想统一调整 Inspector 视觉密度,只需要修改 token 或布局层。
PropertyGrid可以专注在“属性语义 + 撤销接线”,而不必再重复几何计算。
使用模式
更推荐的使用方式不是直接手算坐标,而是把控件包进 DrawPropertyRow(...) 的回调:
const UI::PropertyLayoutSpec layout = UI::MakePropertyLayout();
UI::DrawPropertyRow("Mass", layout, [&](const UI::PropertyLayoutMetrics& metrics) {
UI::SetNextPropertyControlWidth(metrics);
return ImGui::DragFloat("##value", &mass, 0.1f, 0.0f, 1000.0f, "%.2f");
});
如果只是常见属性类型,实际工程里更常见的入口是:
ScalarControls.hVectorControls.hPropertyGrid.h
它们已经把 PropertyLayout 作为底层依赖封装好了。
线程语义
- 这一层完全依赖当前帧的 ImGui 上下文和当前窗口布局状态,只能在 UI 线程、ImGui 绘制阶段调用。
- 它不维护后台状态,也不适合离线计算布局。
当前限制
PushID(label)意味着同一作用域里若有重复标签,调用方应额外PushID以避免冲突。- 标签是直接画到 draw list 上的,因此不是可交互的独立 ImGui item。
- 当前布局仍然是固定列起点模型,不是响应式表单系统。
PushPropertyLayoutStyles()目前只做最小样式压栈,离完整的属性主题系统还有距离。