Files
StellarX-kaifa/开发记录/功能变更/Feature-20260509-0011-布局API使用说明与旧接口覆盖规则.md
T

296 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 功能变更 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 文档中作为调试说明记录。