Files
Genarrative/docs/technical/【技术方案】UI编辑器Godot容器布局模型-2026-08-18.md
k88936 f9e1e5d2a7
Project CI / Backend tests (push) Successful in 7m35s
Project CI / Repository checks (push) Successful in 3m2s
Project CI / Frontend tests (push) Successful in 3m24s
Project CI / Native shell tests (push) Successful in 18m52s
Fix/修复ui editor选择逻辑 (#270)
close #266
当前实现: 按下就重新选择

实际上应该: 松开而且没有发生拖动才重新选择

before:
![shotmd-1788407266-compressed.webp](/attachments/251eccf6-ae02-4ae6-b9d2-4eb1fbf67df3)

after:
![shotmd-1788418953-compressed.webp](/attachments/5c05b506-ae08-4cb1-83c8-8da8e1590a7f)

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/270
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-09-04 16:30:43 +08:00

3.2 KiB
Raw Permalink Blame History

UI 编辑器 Godot 容器布局模型

更新时间:2026-09-03

范围

UI 编辑器节点统一采用 Godot 4.x Control 风格布局数据。Rust 负责持久化和参数校验;UI Editor 前端将该数据单向生成 Preview CSS。CSS 只是预览后端,不是领域模型,也不需要与 Godot 项目或运行时对接。

本次是破坏性 UI 设计 schema 变更:旧 Node.transform 改为 Node.layout.transform,不提供迁移。

数据模型

每个 Node 保留:

layout: {
  transform,                    // anchors + offsets
  custom_minimum_size: [x, y],
  size_flags_horizontal: 0|1|2|3|4|8,
  size_flags_vertical: 0|1|2|3|4|8,
  size_flags_stretch_ratio,
  container: None | HBox | VBox | Grid | Margin | Center
}

flags 使用 Godot 数值:ShrinkBegin=0Fill=1Expand=2ExpandFill=3ShrinkCenter=4ShrinkEnd=8。默认最小尺寸为 [0, 0]flags 为 Fillstretch ratio 为 1

Container 专属数据是互斥 tagged unionHBox/VBox 存 alignment + separationGrid 存 columns + h_separation + v_separationMargin 存四边 marginCenter 存 use_top_left

语义

  • 普通 Controlchildren 继续按自己的 Transform 绝对定位。
  • 父为 Container:父忽略 direct child 的 Transform,使用 child minimum size、flags 与 stretch ratioTransform 不删除,离开 Container 后继续可用。
  • children_display_mode 仍是独立的 Stack/Exclusive 可见性规则;不可见 child 不参与 Container。
  • 不支持 Flex/Flow wrapGrid 按行优先排列。
  • Margin 的 children 填满内侧矩形;Center 的 children 居中并可重叠。
  • v1 minimum size 只使用 custom_minimum_size。TODO:为文本、图片等组件提供 minimum-size,再与 custom minimum 逐轴取最大值。
  • ImageType::Tiled.fill_center=false 当前暂不支持,前端预览与 Rust HTML 生成均保持整块 repeat fallback;如需实现仅铺边框,必须先补充 CSS 输出与既有项目迁移契约。

编辑器交互

布局只在 Inspector 编辑。Preview 不为 Container 管理的 child 提供拖拽或缩放手柄;Inspector 会提示其 Transform 被父 Container 忽略。普通 Control 仍保留原 Transform 编辑和自由预览操作。

Preview 的节点选择采用“松开确认”语义:节点或调整手柄按下时只建立指针手势,不立即改变选择;沿用现有 2px 屏幕位移阈值(达到阈值即视为拖动),未达到阈值且在预览区域内松开时才选择按下命中的节点,发生拖动、取消、失焦或在区域外松开均不选择。发生拖动时,Transform 更新作用于按下前已选中的节点;没有当前选择时才回退到按下节点。拖动外层节点时,嵌套 child 产生的后续 click 也不得重新选择;未发生拖动时,嵌套 child 仍按实际命中节点选择。

取消、失焦、树切换或无效几何导致的手势终止会同时清理下一次 click 抑制状态;只有正常 pointerup 才会根据拖动结果抑制后续 click。

预览节点层禁止浏览器原生文字选择;拖动手势开始时阻止默认行为,避免 pointer drag 被浏览器解释为文本选取。