296 lines
10 KiB
Markdown
296 lines
10 KiB
Markdown
# 功能变更 ID: Feature-20260509-0011
|
||
|
||
> 适用场景:记录小到中等规模的功能、接口、行为、默认值或配置变化。
|
||
> 不适用场景:新增核心模块、重大模块重构、架构级设计,请使用“新增功能模块”模板。
|
||
|
||
## 基本信息
|
||
|
||
- ID: Feature-20260509-0011
|
||
- 标题: 布局 API 使用说明与旧接口覆盖规则
|
||
- 状态:已验证
|
||
- 类型:新增
|
||
- 级别:L2 中等
|
||
- 模块: Layout API / Control
|
||
- 版本 / 分支: 当前工作区
|
||
- 环境: Windows + EasyX
|
||
- 负责人: Codex 协作修改
|
||
|
||
## 变更背景
|
||
|
||
- 背景:
|
||
- 当前布局系统内部已经以 `LayoutSpec` 为统一解算依据。
|
||
- 旧接口 `setLayoutMode(...)` / `setAnchor(...)` 仍然保留,但只能表达有限的双锚点语义。
|
||
- 新增公开布局 API 后,需要明确用户应如何设置轴向锚点、尺寸策略和固定尺寸位移策略。
|
||
- 目标:
|
||
- 说明新布局 API 的职责和使用方式。
|
||
- 明确新旧接口混用时的覆盖规则。
|
||
- 给出常见布局组合和 `KEY2` 迁移场景中的推荐写法。
|
||
- 不做什么:[可选]
|
||
- 不开放 `LayoutCapability` 的普通外部写入接口。
|
||
- 不修改 `Table` 当前版本 `Y Fixed` 的能力边界。
|
||
- 不处理 Tooltip 智能选位、`Table` 内部局部重绘、`Dialog` synthetic move 统一等后置项。
|
||
|
||
## 变更内容
|
||
|
||
- 变更摘要:
|
||
- 增加布局 API 使用说明文档。
|
||
- 明确新接口与旧接口的覆盖关系。
|
||
- 汇总常见布局模式的代码写法。
|
||
- 新增项:[可选]
|
||
- 新公开接口说明
|
||
- 旧接口映射说明
|
||
- 混用覆盖规则
|
||
- 常见写法示例
|
||
- 调试态日志说明
|
||
- 修改项:[可选]
|
||
- 无运行时代码修改,本文件只记录使用说明。
|
||
- 删除 / 废弃项:[可选]
|
||
- 无
|
||
- 受影响的文件 / 类 / 函数:
|
||
- [`Control.h`](D:/programming/imGUI-easyX/imGui-easyX/Control.h)
|
||
- [`Control.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Control.cpp)
|
||
- [`z-testDome.cpp`](D:/programming/imGUI-easyX/imGui-easyX/z-testDome.cpp)
|
||
- 对外 API / 属性变化:[可选]
|
||
- `setHorizontalLayoutSpec(...)`
|
||
- `setVerticalLayoutSpec(...)`
|
||
- `setHorizontalAnchors(...)`
|
||
- `setVerticalAnchors(...)`
|
||
- `setHorizontalSizePolicy(...)`
|
||
- `setVerticalSizePolicy(...)`
|
||
- `setHorizontalAlignPolicy(...)`
|
||
- `setVerticalAlignPolicy(...)`
|
||
- `getHorizontalLayoutSpec()`
|
||
- `getVerticalLayoutSpec()`
|
||
|
||
## 行为对照
|
||
|
||
- 变更前:
|
||
- 用户主要通过 `setLayoutMode(...)` 与 `setAnchor(...)` 设置布局。
|
||
- 固定尺寸 + 居中、固定尺寸 + 比例位移等组合无法通过旧接口清晰表达。
|
||
- 旧双锚点在某些测试场景中会被迫承担 Stretch 语义,导致固定按钮和内容驱动标签在 resize 后错位。
|
||
- 变更后:
|
||
- 用户可按水平轴 / 垂直轴分别设置锚点集合、尺寸策略和固定尺寸位移策略。
|
||
- 旧接口仍可用,但只作为兼容输入层。
|
||
- 新旧接口混用时,最后调用的接口覆盖对应轴的布局规格。
|
||
- 兼容性说明:兼容
|
||
- 迁移说明:[可选]
|
||
- 新代码建议优先使用新布局 API。
|
||
- 旧代码可以继续使用 `setAnchor(...)`,但复杂布局应逐步迁移到新接口。
|
||
|
||
## 验证与落地
|
||
|
||
- 验证方式:
|
||
- 编译 `Control.cpp`
|
||
- 编译 `z-testDome.cpp /DKEY=2`
|
||
- 编译 `z-testDome.cpp /DKEY=5`
|
||
- 手测 `KEY1 / KEY2 / KEY5`
|
||
- 验证结果:
|
||
- 编译级验证通过。
|
||
- 用户手测当前暂未发现问题。
|
||
- 关联 BUG / Fix:[可选]
|
||
- [Feature-20260416-0009-KEY2-使用新布局API重构与联动刷新.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/功能变更/Feature-20260416-0009-KEY2-使用新布局API重构与联动刷新.md)
|
||
- [Feature-20260418-0010-当前阶段测试用例矩阵与定位.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/功能变更/Feature-20260418-0010-当前阶段测试用例矩阵与定位.md)
|
||
- Commit:
|
||
- PR:[可选]
|
||
- 发布版本:[可选]
|
||
- 备注:[可选]
|
||
- resize 收口阶段若开启高频 console 日志,可能出现一帧视觉延迟;当前按调试态 I/O 现象记录,不作为 bug 处理。
|
||
|
||
## API 总览
|
||
|
||
### 完整轴向规格接口
|
||
|
||
```cpp
|
||
void setHorizontalLayoutSpec(const StellarX::AxisLayoutSpec& spec);
|
||
void setVerticalLayoutSpec(const StellarX::AxisLayoutSpec& spec);
|
||
```
|
||
|
||
- 直接覆盖对应轴的完整布局规格。
|
||
- 调用后自动切换到 `StellarX::LayoutMode::AnchorToEdges`。
|
||
- 适合调用方已经准备好完整 `AxisLayoutSpec` 的场景。
|
||
|
||
### 锚点集合接口
|
||
|
||
```cpp
|
||
void setHorizontalAnchors(bool left, bool right);
|
||
void setVerticalAnchors(bool top, bool bottom);
|
||
```
|
||
|
||
- 水平轴对应 `left / right`。
|
||
- 垂直轴对应 `top / bottom`。
|
||
- 只修改对应轴的锚点集合,不主动改变尺寸策略或位移策略。
|
||
|
||
### 尺寸策略接口
|
||
|
||
```cpp
|
||
void setHorizontalSizePolicy(StellarX::AxisSizePolicy policy);
|
||
void setVerticalSizePolicy(StellarX::AxisSizePolicy policy);
|
||
```
|
||
|
||
- `Stretch`:允许该轴尺寸随父容器变化。
|
||
- `FixedSize`:该轴尺寸保持设计态尺寸。
|
||
- 控件能力边界仍然生效。例如 `Table` 当前版本不允许 `Y Stretch`,即使用户设置垂直 `Stretch`,也会被能力边界降级。
|
||
|
||
### 固定尺寸位移策略接口
|
||
|
||
```cpp
|
||
void setHorizontalAlignPolicy(StellarX::AxisAlignPolicy policy);
|
||
void setVerticalAlignPolicy(StellarX::AxisAlignPolicy policy);
|
||
```
|
||
|
||
- 只在 `FixedSize` 语义下决定位置。
|
||
- 不负责改变尺寸。
|
||
- 常用值:
|
||
- `Start`:保持起边关系,例如左固定、上固定。
|
||
- `End`:保持终边关系,例如右固定、下固定。
|
||
- `Center`:保持居中关系。
|
||
- `Proportional`:保持设计态相对位置比例,适合固定尺寸控件在可变宽容器中按比例移动。
|
||
|
||
### 读取接口
|
||
|
||
```cpp
|
||
StellarX::AxisLayoutSpec getHorizontalLayoutSpec() const;
|
||
StellarX::AxisLayoutSpec getVerticalLayoutSpec() const;
|
||
```
|
||
|
||
- 返回当前生效的新模型轴向规格。
|
||
- 不保证能完整逆映射回旧 `anchor_1 / anchor_2` 语义。
|
||
|
||
## 新旧接口覆盖规则
|
||
|
||
### 旧接口仍然保留
|
||
|
||
```cpp
|
||
void setLayoutMode(StellarX::LayoutMode layoutMode);
|
||
void setAnchor(StellarX::Anchor anchor1, StellarX::Anchor anchor2);
|
||
```
|
||
|
||
- 旧接口是兼容入口。
|
||
- `setAnchor(...)` 内部会把旧双锚点映射到新的 `layoutSpec.horizontal` 与 `layoutSpec.vertical`。
|
||
- 旧接口无法表达所有新模型状态,例如固定尺寸 + 比例位移、固定尺寸 + 居中等。
|
||
|
||
### 后调用者生效
|
||
|
||
规则:
|
||
|
||
- 先调用 `setAnchor(...)`,再调用新 API,则新 API 覆盖对应轴规格。
|
||
- 先调用新 API,再调用 `setAnchor(...)`,则旧接口重新覆盖水平轴和垂直轴规格。
|
||
- 新 API 只覆盖自己负责的轴或字段。例如 `setHorizontalSizePolicy(...)` 只修改水平轴尺寸策略,不修改垂直轴。
|
||
|
||
示例:
|
||
|
||
```cpp
|
||
button->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
|
||
button->setAnchor(StellarX::Anchor::Left, StellarX::Anchor::Right);
|
||
|
||
// 覆盖水平轴:改为固定尺寸 + 居中,不再沿用旧接口映射出的 Stretch。
|
||
button->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
|
||
button->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Center);
|
||
```
|
||
|
||
### 新 API 自动切换布局模式
|
||
|
||
所有新布局 setter 都会自动将 `layoutMode` 切换为 `AnchorToEdges`。
|
||
因此新代码通常不需要再额外写:
|
||
|
||
```cpp
|
||
control->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
|
||
```
|
||
|
||
## 常见布局写法
|
||
|
||
### 左固定
|
||
|
||
```cpp
|
||
control->setHorizontalAnchors(true, false);
|
||
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
|
||
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Start);
|
||
```
|
||
|
||
### 右固定
|
||
|
||
```cpp
|
||
control->setHorizontalAnchors(false, true);
|
||
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
|
||
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::End);
|
||
```
|
||
|
||
### 水平拉伸
|
||
|
||
```cpp
|
||
control->setHorizontalAnchors(true, true);
|
||
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::Stretch);
|
||
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Start);
|
||
```
|
||
|
||
### 固定尺寸居中
|
||
|
||
```cpp
|
||
control->setHorizontalAnchors(true, true);
|
||
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
|
||
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Center);
|
||
```
|
||
|
||
### 固定尺寸比例位移
|
||
|
||
```cpp
|
||
control->setHorizontalAnchors(true, true);
|
||
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
|
||
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Proportional);
|
||
```
|
||
|
||
适用场景:
|
||
|
||
- 一组固定尺寸按钮需要随着父容器变宽按比例展开。
|
||
- `KEY2` 中每个 bit 单元就是该策略的典型使用方式。
|
||
|
||
## KEY2 迁移要点
|
||
|
||
`KEY2` 原问题不是单纯参数错误,而是布局单元拆分不合理:
|
||
|
||
- 位号 `Label` 是内容驱动尺寸。
|
||
- 位按钮是固定尺寸。
|
||
- 二者分别使用比例位移时,因为自身尺寸不同,resize 后会出现错位。
|
||
|
||
当前迁移方式:
|
||
|
||
- 每一位创建一个小 `Canvas` 单元。
|
||
- 单元内部固定放置位号 `Label` 与位按钮。
|
||
- 单元自身使用 `FixedSize + Proportional`。
|
||
- 这样移动的是整个 bit 单元,而不是标签和按钮分别移动。
|
||
|
||
示意写法:
|
||
|
||
```cpp
|
||
auto cell = std::make_unique<Canvas>(cellX, 0, 32, 50);
|
||
cell->setHorizontalAnchors(true, true);
|
||
cell->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
|
||
cell->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Proportional);
|
||
```
|
||
|
||
## 能力边界说明
|
||
|
||
布局 API 表达的是“调用方希望如何布局”,但控件能力边界仍然优先。
|
||
|
||
当前关键边界:
|
||
|
||
- `Canvas`:`X / Y` 均允许 Stretch。
|
||
- `TabControl`:外层允许 Stretch,内部页签栏 / 页面区仍由自身管理。
|
||
- `Table`:当前版本 `X Stretch / Y Fixed`,这是当前实现边界,不是永久产品结论。
|
||
- `TextBox`:默认更适合 `X Stretch / Y FixedSize`。
|
||
- `Label`:默认固定或内容驱动刷新运行态尺寸,不建议做双轴 Stretch。
|
||
- `Dialog`:只居中,不参与父级拉伸。
|
||
|
||
如果用户设置的策略超出控件能力边界,统一解算层会按现有降级规则处理,并保留必要日志。
|
||
|
||
## 调试态说明
|
||
|
||
resize / 最大化 / 还原过程中,如果开启大量 console 日志,可能出现一帧视觉延迟或短暂残影。
|
||
当前判断原因是日志系统同步写控制台且默认逐行 flush,导致主线程 resize 收口绘制被 I/O 拖慢。
|
||
|
||
处理建议:
|
||
|
||
- 常规手测可关闭 console 日志。
|
||
- 需要日志时可优先输出到文件。
|
||
- 当前不作为布局或重绘 bug 处理,后续可在官网/API 文档中作为调试说明记录。
|