Expose layout API and refresh regression docs

This commit is contained in:
Codex
2026-05-09 19:15:23 +08:00
parent 738cf035bb
commit 2388f22c99
21 changed files with 2491 additions and 367 deletions
@@ -0,0 +1,161 @@
# 新增功能模块 / 模块重构
> 适用场景:新增模块、重大模块重构、核心架构能力演进。
> 不适用场景:小接口或轻量功能变更,请使用“功能变更”模板。
## 基本信息
- 模块 ID`Module-20260410-0002`
- 模块名称: 锚点与布局系统第一阶段重构
- 状态:已验证
- 类型:模块重构
- 所属系统 / 子系统: GUI 框架 / Layout
- 版本 / 分支: 当前工作区 / 下一版本开发中
- 环境: Windows + EasyX
- 负责人: Codex 协作修改
## 背景与目标
- 背景:
- 原有锚点系统仍依赖 `anchor_1 / anchor_2`
- `Window::adaptiveLayout()``Canvas::onWindowResize()` 长期并存两套布局语义
- `Canvas` 布局层存在 `Table` 外部特判
- `TabControl` 外层布局与内部布局耦合较深
- 当前痛点:
- 双锚点表达能力不足,难以覆盖更完整的边集合语义
- 顶层窗口与容器子控件的解算规则不统一,维护成本高
- 特殊控件能力边界没有收回自身语义层
- 缺少针对布局系统的专项回归用例
- 目标:
- 建立统一的布局数据模型与统一解算入口
- 正式区分设计态矩形与运行态矩形
- 保留旧 API 的兼容输入能力
-`Table` 的当前能力边界收回控件自身
- 增加布局专项回归用例 `KEY == 5`
- 非目标:
- 不做字体随控件缩放
- 不做 `Table` 纵向拉伸
- 不重构重绘系统
## 模块边界
- 职责:
- 提供统一的布局规格描述
- 统一顶层窗口与容器子控件的几何解算
- 在保持旧 API 可用的前提下,将内部布局实现迁移到新模型
- 通过控件能力边界约束非法或暂不支持的拉伸组合
- 不负责什么:
- 字体缩放与内容排版自适应
- `Dialog` 内部布局语义重构
- `Table` 纵向拉伸能力
- 外部依赖:
- EasyX 绘制环境
- 现有 `Control / Window / Canvas / TabControl / Table` 控件体系
- 对外能力 / API:
- 继续保留 `setLayoutMode(...)`
- 继续保留 `setAnchor(a1, a2)`
- 当前阶段新增能力主要用于内部统一实现,不额外新增用户层 API
- 关键数据 / 状态:
- `localx / localy / localWidth / localHeight`
- `x / y / width / height`
- `LayoutSpec`
- `LayoutCapability`
- `ResolvedLayoutRect`
## 设计说明
- 核心流程:
- 先在父局部坐标系内按水平轴 / 垂直轴独立解算
- 再将局部矩形映射为世界坐标矩形
- 由控件内部受控路径应用运行态矩形
- 关键对象 / 类关系:
- [`Control`](D:/programming/imGUI-easyX/imGui-easyX/Control.h) 作为统一布局规格与基础解算入口
- [`Window`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp) 负责顶层控件统一收口
- [`Canvas`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp) 负责容器子控件重映射
- [`TabControl`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp) 外层接入统一解算,内部页签栏 / 页面区仍自管
- [`Table`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp) 通过 `LayoutCapability` 显式禁止 `Y` 轴 Stretch
- 生命周期:
- 设计态矩形 `local*` 在普通 resize / 重排过程中不自动回写
- 运行态矩形由统一解算器产出,再通过内部路径应用
- 若确需同步设计基线,只能显式调用 `commitCurrentGeometryAsDesignRect()`
- 事件 / 渲染 / 数据流:
- 事件阶段只改状态,不直接扩散成多套布局公式
- `Window``Canvas` 共用 `resolveLayoutRect()`
- `onWindowResize()` 收口为“快照失效 + 标脏 + 必要传播”,不再承担布局求解
- 关键不变量:
- `local*` 始终表示设计态父局部矩形
- `x / y / width / height` 始终表示运行态绘制矩形
- 旧 API 只作兼容输入层,不再作为内部解算依据
- `Table` 当前阶段只允许 `X` 轴 Stretch
- 降级 / 回退策略:
- 对不满足能力边界的拉伸请求,自然降级为固定尺寸位移
- 旧接口输入通过映射层退回到新模型的有限子集
## 实现与影响
- 关键实现点:
- 引入 `AxisSizePolicy / AxisAlignPolicy / AxisLayoutSpec / LayoutSpec / LayoutCapability / ResolvedLayoutRect`
-`Control` 中增加统一解算与内部受控应用路径
-`Window::adaptiveLayout()` 改为统一解算入口
-`Canvas` 子控件布局从旧比例缩放逻辑切换为统一解算
-`TabControl` 外层接入统一解算,同时保留内部页签系统专用布局
-`Table``Y` 轴固定能力边界收回控件自身
-`z-testDome.cpp` 增加 `KEY == 5` 布局专项回归
- 涉及文件 / 类 / 函数:
- [`CoreTypes.h`](D:/programming/imGUI-easyX/imGui-easyX/CoreTypes.h)
- [`Control.h`](D:/programming/imGUI-easyX/imGui-easyX/Control.h)
- [`Control.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Control.cpp)
- [`Canvas.h`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.h)
- [`Canvas.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp)
- [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp)
- [`TabControl.h`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.h)
- [`TabControl.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp)
- [`Table.h`](D:/programming/imGUI-easyX/imGui-easyX/Table.h)
- [`Table.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp)
- [`z-testDome.cpp`](D:/programming/imGUI-easyX/imGui-easyX/z-testDome.cpp)
- 兼容性影响:
- 向后兼容旧锚点 API
- 当前阶段未删除旧 getter / setter
- 性能影响:
- 无明显新增性能负担
- 主要是布局求解路径从多处分散逻辑收口为统一函数
- 风险点:
- 若某些控件运行态尺寸变化后未明确同步设计基线,后续 resize 仍可能出现“回到旧设计态”的现象
- `TabControl` 的外层统一解算与内部专用布局之间存在边界风险
- `Table` 纵向仍为固定尺寸,后续若扩展能力需单独立项
## 测试与验证
- 测试范围:
- 顶层窗口 resize
- `Canvas` 嵌套布局
- `TabControl` 外层布局接入
- `Table` 横向拉伸与纵向固定
- `KEY == 5` 布局专项回归
- 验证步骤:
1. 编译 `Control.cpp / Canvas.cpp / Table.cpp / TabControl.cpp / Window.cpp`
2. 编译 `z-testDome.cpp /DKEY=2`
3. 编译 `z-testDome.cpp /DKEY=5`
- 验证结果:
- 源码级编译验证通过
- `KEY == 5` 已补齐布局专项回归用例
- GUI 交互仍需用户本机手动确认
- 已知限制 / 遗留问题:
- 本轮不包含字体缩放
- 本轮不包含 `Table` 纵向拉伸
- Tooltip 问题已另外拆分为独立 `BUG / Fix`
## 落地信息
- 关联功能变更 ID[可选]
- 关联 BUG / Fix:
- `BUG-20260410-0004`
- `Fix-BUG-20260410-0004`
- Commit: 当前工作区未提交
- PR[可选]
- 发布版本:[可选]
- 相关文档:
- [`BUG-20260410-0004-按钮Tooltip移出后不消失.md`](D:/programming/imGUI-easyX/imGui-easyX/开发记录/BUG/BUG-20260410-0004-按钮Tooltip移出后不消失.md)
- [`Fix-BUG-20260410-0004-按钮Tooltip移出后不消失.md`](D:/programming/imGUI-easyX/imGui-easyX/开发记录/Fix/Fix-BUG-20260410-0004-按钮Tooltip移出后不消失.md)
@@ -0,0 +1,157 @@
# 新增功能模块 / 模块重构
> 适用场景:新增模块、重大模块重构、核心架构能力演进。
> 不适用场景:小接口或轻量功能变更,请使用“功能变更”模板。
## 基本信息
- 模块 IDModule-20260415-0003
- 模块名称: 布局系统第二阶段收口
- 状态:已完成
- 类型:模块重构
- 所属系统 / 子系统: GUI 框架 / Layout
- 版本 / 分支: 当前工作区 / 下一版本开发中
- 环境: Windows + EasyX
- 负责人: Codex 协作修改
## 背景与目标
- 背景:
- 第一阶段已经完成统一布局链路打通,但几何写入口、内容驱动控件规则、复合控件职责边界仍有残留混用。
- `Label` 曾在 `draw()` 阶段临时决定尺寸,`TabControl``Canvas` 在子树几何映射上也存在职责重叠。
- `WM_MOUSEMOVE` 的容器分发和局部重绘合成,在复杂遮挡场景下容易暴露 hover/tooltip 与 overlay 残留问题。
- 当前痛点:
- 几何语义还不够制度化,后续继续演进布局系统时容易再次混回“draw 阶段改几何”。
- 内容驱动控件和复合控件没有完全落成可解释的边界。
- 局部重绘与上层兄弟补画机制不完整时,会直接破坏遮挡正确性。
- 目标:
- 收口几何写入口语义,明确公开 setter、统一布局应用路径、内容驱动路径、显式设计基线提交。
- 收口 `Label / Table` 的内容驱动规则与设计基线边界。
- 收口 `TabControl / Canvas` 的职责边界,不重写页签系统,但消除页内子控件手工回填。
- 建立轻量级鼠标瞬时状态清理路径和 overlay 补画机制,保证 hover / tooltip / 局部重绘链正确。
- 非目标:[可选]
- 不做字体缩放。
- 不做 `Table` 纵向拉伸。
- 不做 `Dialog` 旧 synthetic move 机制统一。
- 不做 `Table` 内部局部重绘体系。
## 模块边界
- 职责:
- 定义并收口布局系统第二阶段的运行态 / 设计态几何语义。
- 为当前主线控件显式写出能力边界和默认策略。
- 收口局部重绘下的 overlay 补画规则。
- 不负责什么:
- 不扩展新的布局表达能力。
- 不处理字体、图标、DPI 自适应。
- 不把所有控件都改造成内容驱动或局部重绘型复合控件。
- 外部依赖:
- EasyX 绘制环境
- 现有 `Control / Window / Canvas / TabControl / Table / Label / Button` 体系
- 对外能力 / API:
- 保留 `setLayoutMode(...)`
- 保留 `setAnchor(a1, a2)`
- 保留 `commitCurrentGeometryAsDesignRect()`
- `Label::textStyle` 继续保持公开,但要求样式修改后显式 `setDirty(true)`
- 关键数据 / 状态:
- `localx / localy / localWidth / localHeight`
- `x / y / width / height`
- `LayoutSpec / LayoutCapability / ResolvedLayoutRect`
- `eventVisualChanged`
## 设计说明
- 核心流程:
- 先在父局部坐标系内完成统一布局解算。
- 再由内部受控路径把运行态矩形应用到控件。
- 内容驱动控件在自己的受控路径里刷新运行态尺寸。
- 局部重绘提交后,由父容器按实际绘制顺序补画 coverage 上方的 overlay 兄弟。
- 关键对象 / 类关系:
- [`Control`](D:/programming/imGUI-easyX/imGui-easyX/Control.h):几何语义、解算入口、设计基线提交入口。
- [`Label`](D:/programming/imGUI-easyX/imGui-easyX/Label.cpp):内容驱动尺寸,`draw()` 只消费运行态矩形。
- [`Canvas`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp):管理直接子控件的世界坐标映射与局部 overlay 补画。
- [`TabControl`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp):外层接统一解算,内部页签栏 / 页面区继续自管。
- [`Table`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp):当前版本 `X Stretch / Y Fixed`,并保留内部受控结构尺寸基线刷新。
- [`Window`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp):顶层托管重绘收口与 overlay 兄弟补画。
- 生命周期:
- 普通 resize / 父容器重排不自动回写 `local*`
- 显式设计基线提交只通过 `commitCurrentGeometryAsDesignRect()` 或控件内部受控结构刷新点发生。
- 内容驱动尺寸刷新优先发生在 `draw()` 之前。
- 事件 / 渲染 / 数据流:[按模块类型填写]
- `WM_MOUSEMOVE`:第一个命中的兄弟收到真实消息,后续兄弟只清理瞬时鼠标状态。
- 局部重绘:先画本次 dirty 单元,再补画 coverage 上方相交 overlay。
- 运行态几何:统一解算或内容驱动路径写入;设计基线不自动漂移。
- 关键不变量:
- `local*` 始终表示设计态父局部矩形。
- `x / y / width / height` 始终表示运行态绘制矩形。
- `draw()` 不再承担新的几何决策入口。
- `Table` 当前版本 `Y Fixed` 是实现边界,不是永久产品结论。
- 降级 / 回退策略:[可选]
- Stretch 条件不满足时自然降级为固定尺寸位置策略。
- 控件能力边界禁止 Stretch 时,通过日志输出拦截原因。
## 实现与影响
- 关键实现点:
- 在 [`Control.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Control.cpp) 增加布局降级日志、能力边界拦截日志、显式设计基线提交日志。
- 在 [`Label.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Label.cpp) 收口内容驱动尺寸刷新,并显式关闭双轴 Stretch。
- 在 [`Canvas.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp)、[`TabControl.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp)、[`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp) 收口 overlay 补画。
- 在 [`Table.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp) 收口 `Y Fixed`、分页按钮视觉链与页码重绘。
- 涉及文件 / 类 / 函数:
- [`Control.h`](D:/programming/imGUI-easyX/imGui-easyX/Control.h)
- [`Control.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Control.cpp)
- [`Label.h`](D:/programming/imGUI-easyX/imGui-easyX/Label.h)
- [`Label.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Label.cpp)
- [`Canvas.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp)
- [`TabControl.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp)
- [`Table.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp)
- [`TextBox.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TextBox.cpp)
- [`Dialog.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Dialog.cpp)
- [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp)
- 兼容性影响:
- 对旧锚点 API 保持兼容。
- `Label::textStyle` 仍为公开字段,但使用约定更严格。
- 性能影响:
- `WM_MOUSEMOVE` 和 overlay 补画路径增加了必要的状态清理与补画,但避免了整窗级重绘。
- `Table` 分页按钮视觉变化当前仍提升为整表重绘,颗粒度偏粗,但正确性优先。
- 风险点:
- `Dialog` 旧 synthetic move 机制仍与新清理模型并存。
- `Table` 内部局部重绘体系尚未建立,分页区仍偏重。
## 测试与验证
- 测试范围:
- 顶层 resize
- 三层 `Canvas` 嵌套
- `TabControl` 外层 resize 与页内稳定性
- overlay 补画
- `Table` 横向拉伸、分页按钮、页码重绘
- `Label` 文本 / 字体样式变化
- 验证步骤:
1. 编译 `Control.cpp / Label.cpp / Canvas.cpp / TabControl.cpp / Table.cpp / TextBox.cpp / Dialog.cpp`
2. 编译 `z-testDome.cpp /DKEY=5`
3. 手动回归 `KEY5` 的 hover、tooltip、overlay、分页与页码场景
- 验证结果:
- 编译级验证通过。
- 手动 GUI 回归依赖本机继续执行。
- 已知限制 / 遗留问题:[可选]
- `Dialog` 旧 synthetic move 机制暂未统一。
- `Table` 尚未引入内部局部重绘模型。
- 全项目所有控件的能力边界总审计未做。
## 落地信息
- 关联功能变更 ID[可选]
- `Feature-20260415-0008`
- 关联 BUG / Fix[可选]
- `BUG-20260415-0005`
- `Fix-BUG-20260415-0005`
- Commit: 未提交(当前工作区)
- PR[可选]
- 发布版本:[可选]
- 相关文档:[可选]
- [Feature-20260415-0008-KEY5-第二阶段专项回归场景增强.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/功能变更/Feature-20260415-0008-KEY5-第二阶段专项回归场景增强.md)
- [BUG-20260415-0005-局部重绘未补画上层兄弟导致遮挡错误.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/BUG/BUG-20260415-0005-局部重绘未补画上层兄弟导致遮挡错误.md)
- [Fix-BUG-20260415-0005-局部重绘补画上层兄弟修复.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/Fix/Fix-BUG-20260415-0005-局部重绘补画上层兄弟修复.md)
@@ -0,0 +1,177 @@
# 新增功能模块 / 模块重构
> 适用场景:新增模块、重大模块重构、核心架构能力演进。
> 不适用场景:小接口或轻量功能变更,请使用“功能变更”模板。
## 基本信息
- 模块 IDModule-20260415-0004
- 模块名称: 布局系统第二阶段验收与封口
- 状态:已验证
- 类型:模块重构
- 所属系统 / 子系统: GUI 框架 / Layout
- 版本 / 分支: 当前工作区 / 下一版本开发中
- 环境: Windows + EasyX
- 负责人: Codex 协作修改
## 背景与目标
- 背景:
- 第一阶段已完成统一锚点模型和统一解算入口。
- 第二阶段继续围绕“几何所有权收口 + 内容驱动规则收口”推进,实现几何写入口分层、内容驱动控件规则收口、局部重绘与 overlay 补画链修复。
-`KEY1 / KEY5` 回归过程中,又暴露出脏子树提交、coverage 低估、TabControl 层级顺序等一组重绘链问题,需要一并收口后才能视为阶段稳定。
- 当前痛点:
- 缺少一份明确的阶段验收记录,难以区分“本阶段完成项”和“明确延期项”。
- 当前主线 bug 虽已基于测试用例修复,但如果不做封口记录,后续继续推进下一主题时容易重复回头整理。
- 目标:
- 明确第二阶段已经完成的主线改造和已验证的 bug 修复。
- 明确当前接受的边界与明确延期的技术债。
- 为后续“公开布局 API + 旧 demo 迁移”提供稳定起点。
- 非目标:[可选]
- 本记录不新增运行时代码逻辑。
- 本记录不覆盖未来的 Tooltip 智能选位、`Table` 纵向拉伸、`Dialog` synthetic move 统一改造。
## 模块边界
- 职责:
- 汇总布局系统第二阶段的最终语义收口结果。
- 记录本阶段已完成的运行态 / 设计态几何规则、局部重绘提交规则与 overlay 补画规则。
- 明确已知延期项与后续主题边界。
- 不负责什么:
- 不扩展新的布局表达能力。
- 不重写 `Dialog` 旧 synthetic move 机制。
- 不实现 `Table` 内部局部重绘体系。
- 外部依赖:
- `Control / Window / Canvas / TabControl / Table / Label / Button`
- EasyX 绘制与消息循环环境
- 对外能力 / API:
- 保持旧 API`setLayoutMode(...)``setAnchor(...)`
- 保持显式设计基线提交入口:`commitCurrentGeometryAsDesignRect()`
- 保持 `Label::textStyle` 公开,但要求样式修改后手动 `setDirty(true)`
- 关键数据 / 状态:
- `localx / localy / localWidth / localHeight`
- `x / y / width / height`
- `LayoutSpec / LayoutCapability / ResolvedLayoutRect`
- `eventVisualChanged / dirty / coverage / overlay`
## 设计说明
- 核心流程:
- 几何变化先在父局部坐标系内统一解算,再通过内部受控路径应用到运行态矩形。
- 内容驱动控件在自身受控路径中刷新运行态尺寸;设计基线不得在普通布局过程中自动漂移。
- 托管局部重绘按“脏子树提交 -> 直接分支 coverage -> 传递式 overlay 补画”收口,确保嵌套容器、Tooltip、上层兄弟遮挡链闭合。
- 关键对象 / 类关系:
- [`Control.h`](D:/programming/imGUI-easyX/imGui-easyX/Control.h):统一布局解算、设计基线提交、托管重绘底座
- [`Label.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Label.cpp):内容驱动尺寸刷新前移,`draw()` 只消费运行态矩形
- [`Canvas.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp):直接子树映射、脏子树提交、局部 overlay 补画
- [`TabControl.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp):外层统一布局,内部页签栏/页面区自管,绘制顺序与局部提交顺序统一
- [`Table.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp):当前版本 `X Stretch / Y Fixed`、分页按钮视觉与页码重绘修复
- [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp):顶层托管重绘、传递式 overlay 补画、顶层 coverage 收口
- 生命周期:
- 普通 resize / 重排不自动回写 `local*`
- 公开 setter 只写运行态,不隐式提交设计基线
- 显式设计基线提交只通过 `commitCurrentGeometryAsDesignRect()` 或控件内部受控结构刷新触发
- 事件 / 渲染 / 数据流:[按模块类型填写]
- `WM_MOUSEMOVE`:真实命中分支处理事件,后续兄弟仅清理鼠标瞬时状态
- 托管局部重绘:先提交 dirty root / dirty branch,再按 coverage 传递式补画 overlay
- Tooltip / 扩展绘制 coverage:通过 `getManagedRepaintCoverageRect()` 纳入托管 coverage 计算
- 关键不变量:
- `local*` 只表示设计态父局部矩形
- `x / y / width / height` 只表示运行态绘制矩形
- `draw()` 不再承担新的几何决策入口
- `Table` 当前版本 `Y Fixed` 是实现边界,不是永久产品结论
- 降级 / 回退策略:[可选]
- Stretch 不满足条件时降级为固定尺寸位移策略,并输出最小必要日志
- 控件能力边界拦截 Stretch 请求时,通过日志说明被拦截的轴和原因
## 实现与影响
- 关键实现点:
- 收口公开 setter、统一布局应用路径、内容驱动路径、显式设计基线提交四类几何写入口
- 修复 `WM_MOUSEMOVE` 短路后 hover / tooltip 无法及时清理的问题
- 修复局部重绘只认直接 dirty child、不认 dirty descendant 的链路缺口
- 修复 coverage 低估导致 Tooltip / overlay 漏补画的问题
- 修复 Tab 页签按钮与页面绘制顺序不一致导致 Tooltip 被页面覆盖的问题
- 修复重复激活已激活页签时的残影 / 快照链扰动问题
- 涉及文件 / 类 / 函数:
- [`Control.h`](D:/programming/imGUI-easyX/imGui-easyX/Control.h)
- [`Control.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Control.cpp)
- [`Label.h`](D:/programming/imGUI-easyX/imGui-easyX/Label.h)
- [`Label.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Label.cpp)
- [`Button.h`](D:/programming/imGUI-easyX/imGui-easyX/Button.h)
- [`Button.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Button.cpp)
- [`Canvas.h`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.h)
- [`Canvas.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Canvas.cpp)
- [`TabControl.h`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.h)
- [`TabControl.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TabControl.cpp)
- [`Table.h`](D:/programming/imGUI-easyX/imGui-easyX/Table.h)
- [`Table.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Table.cpp)
- [`TextBox.h`](D:/programming/imGUI-easyX/imGui-easyX/TextBox.h)
- [`TextBox.cpp`](D:/programming/imGUI-easyX/imGui-easyX/TextBox.cpp)
- [`Dialog.h`](D:/programming/imGUI-easyX/imGui-easyX/Dialog.h)
- [`Dialog.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Dialog.cpp)
- [`Window.h`](D:/programming/imGUI-easyX/imGui-easyX/Window.h)
- [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp)
- [`MessageBox.h`](D:/programming/imGUI-easyX/imGui-easyX/MessageBox.h)
- [`z-testDome.cpp`](D:/programming/imGUI-easyX/imGui-easyX/z-testDome.cpp)
- 兼容性影响:
- 旧锚点 API 仍可用,内部实现已完全转到新布局模型
- `Label::textStyle` 仍为公开字段,但要求样式修改后显式 `setDirty(true)`
- `TabControl::setActiveIndex()``Button::setButtonClick()` 对重复同状态调用新增短路,不再重复触发链路
- 性能影响:
- 局部重绘 coverage 和 overlay 补画会更保守,补画次数可能略增
- 相比整窗 / 整容器强制重绘,这仍是更合理的正确性与性能折中
- `Table` 分页按钮视觉变化当前仍提升为整张 `Table` 重绘,颗粒度偏粗但正确性优先
- 风险点:
- `Dialog` 旧 synthetic move 机制仍与新清理模型并存
- `Table` 尚未拥有自己的内部局部重绘体系
- 公开 `AxisSizePolicy / AxisAlignPolicy` API 仍未开放,旧 demo 仍受旧入口表达能力限制
## 测试与验证
- 测试范围:
- `KEY1`:页签重复激活、表格超出页范围残影回归
- `KEY5`:三层 `Canvas` 嵌套、跨容器 hover / tooltip、overlay 补画、`TabControl``Table`、页码与分页按钮
- 核心源码编译级验证:布局主线、重绘主线、Tab / Table / Label / TextBox / Dialog 主线
- 验证步骤:
1. 编译 `Control.cpp / Button.cpp / Label.cpp / Canvas.cpp / TabControl.cpp / Table.cpp / TextBox.cpp / Dialog.cpp / Window.cpp`
2. 编译 `z-testDome.cpp /DKEY=1`
3. 编译 `z-testDome.cpp /DKEY=5`
4. 手动回归 `KEY1 / KEY5` 中的 tooltip、overlay、页签、分页、三层嵌套和跨容器按钮场景
- 验证结果:
- 编译级验证通过
- 基于当前 `KEY1 / KEY5` 用例回归,已知 bug 已修复
- GUI 手动回归依赖本机继续确认,当前结论基于现有测试反馈成立
- 已知限制 / 遗留问题:[可选]
- `Dialog` 旧 synthetic `WM_MOUSEMOVE` 机制尚未统一到新模型
- `Table` 内部局部重绘体系尚未实现
- Tooltip 智能选位明确后置
- 公开 `AxisSizePolicy / AxisAlignPolicy` API 尚未开放,`KEY2` 等旧场景仍受旧 anchor 语义限制
## 落地信息
- 关联功能变更 ID[可选]
- `Feature-20260415-0008`
- 关联 BUG / Fix[可选]
- `BUG-20260415-0005`
- `Fix-BUG-20260415-0005`
- `BUG-20260415-0006`
- `Fix-BUG-20260415-0006`
- `BUG-20260415-0007`
- `Fix-BUG-20260415-0007`
- `BUG-20260415-0008`
- `Fix-BUG-20260415-0008`
- Commit: 未提交(当前工作区)
- PR[可选]
- 发布版本:[可选]
- 相关文档:[可选]
- [Module-20260415-0003-布局系统第二阶段收口.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/模块/Module-20260415-0003-布局系统第二阶段收口.md)
- [Feature-20260415-0008-KEY5-第二阶段专项回归场景增强.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/功能变更/Feature-20260415-0008-KEY5-第二阶段专项回归场景增强.md)
- [BUG-20260415-0006-托管局部重绘未正确提交脏子树导致嵌套Canvas按钮状态不刷新.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/BUG/BUG-20260415-0006-托管局部重绘未正确提交脏子树导致嵌套Canvas按钮状态不刷新.md)
- [Fix-BUG-20260415-0006-托管局部重绘脏子树提交链修复.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/Fix/Fix-BUG-20260415-0006-托管局部重绘脏子树提交链修复.md)
- [BUG-20260415-0007-实际绘制coverage低估导致Tooltip与overlay补画漏算.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/BUG/BUG-20260415-0007-实际绘制coverage低估导致Tooltip与overlay补画漏算.md)
- [Fix-BUG-20260415-0007-实际绘制coverage与overlay补画链修复.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/Fix/Fix-BUG-20260415-0007-实际绘制coverage与overlay补画链修复.md)
- [BUG-20260415-0008-TabControl页签层级与重复激活链路导致Tooltip和残影异常.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/BUG/BUG-20260415-0008-TabControl页签层级与重复激活链路导致Tooltip和残影异常.md)
- [Fix-BUG-20260415-0008-TabControl页签层级与重复激活链路修复.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/Fix/Fix-BUG-20260415-0008-TabControl页签层级与重复激活链路修复.md)
@@ -0,0 +1,146 @@
# 新增功能模块 / 模块重构
> 适用场景:新增模块、重大模块重构、核心架构能力演进。
> 不适用场景:小接口或轻量功能变更,请使用“功能变更”模板。
## 基本信息
- 模块 IDModule-20260416-0005
- 模块名称: 布局策略公开 API 落地
- 状态:开发中
- 类型:架构演进
- 所属系统 / 子系统: GUI 框架 / Layout API
- 版本 / 分支: 当前工作区 / 下一开发阶段
- 环境: Windows + EasyX
- 负责人: Codex 协作修改
## 背景与目标
- 背景:
- 第一阶段与第二阶段已经把内部布局模型收口到 `LayoutSpec / LayoutCapability / AxisSizePolicy / AxisAlignPolicy`
- 外部调用层仍主要依赖 `setLayoutMode(...)``setAnchor(...)`,无法直接表达“固定尺寸 + 比例位移”“固定尺寸 + 居中”这类语义。
- `KEY2` 顶部位选择区就是典型例子:旧双锚点语义不足,导致按钮与标签 resize 后错位,且难以继续扩展。
- 当前痛点:
- 外部用户无法直接设置 `AxisSizePolicy / AxisAlignPolicy`
- 旧 demo 继续依赖旧锚点入口,验证成本高,迁移路径不清晰。
- 新旧 API 混用规则若不写清,后续容易再次回到“旧 anchor 硬凑新布局”的状态。
- 目标:
- 将当前内部布局策略正式开放为公开 API。
- 明确新旧 API 混用规则与对外可见语义。
-`KEY2` 作为新布局 API 的首个迁移样例。
- 非目标:[可选]
- 不统一 `Dialog` 旧 synthetic `WM_MOUSEMOVE` 机制。
- 不实现 `Table` 内部局部重绘体系。
- 不实现 Tooltip 智能选位。
- 不扩展 `Table` 纵向拉伸和字体缩放。
## 模块边界
- 职责:
- 对外开放按轴设置布局规格的最小 API。
- 固化新旧 API 的混用规则与默认行为。
- 提供首个迁移样例,验证新 API 可表达旧场景中“旧 anchor 无法清晰表达”的布局。
- 不负责什么:
- 不开放 `LayoutCapability` 的通用外部修改接口。
- 不改变控件内部硬能力边界。
- 不把所有旧 demo 一次性全部迁完。
- 外部依赖:
- `Control / Canvas / TabControl / Table / Label / TextBox`
- `z-testDome.cpp`
- 对外能力 / API:
- `setHorizontalLayoutSpec(...)`
- `setVerticalLayoutSpec(...)`
- `setHorizontalAnchors(...)`
- `setVerticalAnchors(...)`
- `setHorizontalSizePolicy(...)`
- `setVerticalSizePolicy(...)`
- `setHorizontalAlignPolicy(...)`
- `setVerticalAlignPolicy(...)`
- `getHorizontalLayoutSpec()`
- `getVerticalLayoutSpec()`
- 关键数据 / 状态:
- `layoutSpec`
- `layoutMode`
- `layoutCapability`
- `localx / localy / localWidth / localHeight`
- `x / y / width / height`
## 设计说明
- 核心流程:
- 外部通过新 API 直接写入水平轴 / 垂直轴布局规格。
- 新 API 被调用后,控件自动切到 `AnchorToEdges` 布局模式。
- 运行时统一解算继续以 `layoutSpec` 为唯一依据。
- 关键对象 / 类关系:
- [`Control.h`](D:/programming/imGUI-easyX/imGui-easyX/Control.h):公开布局策略 API 的对外入口。
- [`Control.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Control.cpp):新 API 的实现、新旧 API 映射共存规则。
- [`z-testDome.cpp`](D:/programming/imGUI-easyX/imGui-easyX/z-testDome.cpp)`KEY2` 迁移示例与验证入口。
- 生命周期:
- 新 API 只影响运行态布局策略,不自动提交设计基线。
- 设计基线仍由显式提交路径或控件内部受控路径维护。
- 事件 / 渲染 / 数据流:[按模块类型填写]
- 新 API 不改变事件分发与局部重绘主链。
- 只是改变布局规格输入层与解算参数来源。
- 关键不变量:
- 新旧 API 混用时,后调用者生效。
- 旧 API 仍保留兼容,但只覆盖新模型的有限子集。
- 公开布局 API 不得自动回写 `local*`
- 降级 / 回退策略:[可选]
- 非法组合继续沿用现有降级规则,并输出最小必要日志。
- 若后续回退,只需回退 `Control` 中新增 API 与 `KEY2` 迁移代码,不影响第二阶段主线。
## 实现与影响
- 关键实现点:
-`Control` 层开放最小够用的布局策略 API。
- 新 API 调用后自动切换到 `AnchorToEdges`
- 保留 `setAnchor(...)` 与旧 getter,不破坏兼容路径。
-`KEY2` 位选择区、功能区、显示区和配置区作为迁移样例,验证新 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)
- 兼容性影响:
- 兼容旧 `setAnchor(...)` 调用。
- 新 API 为新增能力,不影响现有二进制接口使用方式。
- 混用时以最后一次设置为准。
- 性能影响:
- 布局解算主逻辑不变,性能影响可忽略。
- `KEY2` 迁移后控件层次变多,但仍处于测试用例范围。
- 风险点:
- `KEY2` 迁移后可能暴露旧 demo 中原本被旧锚点语义掩盖的布局问题。
- 若后续没有补使用说明,外部调用仍可能继续滥用旧锚点入口。
## 测试与验证
- 测试范围:
- `Control` 新公开布局 API 编译级验证
- `KEY2` 迁移后的布局与显示联动
- `KEY5` 回归,确认新 API 未破坏第二阶段主线
- 验证步骤:
1. 编译 `Control.cpp`
2. 编译 `z-testDome.cpp /DKEY=2`
3. 编译 `z-testDome.cpp /DKEY=5`
4. 手动回归 `KEY2` 位选择区、功能区、显示区与配置区的 resize 和联动行为
- 验证结果:
- 编译级验证通过。
- GUI 手动回归待本机继续确认。
- 已知限制 / 遗留问题:[可选]
- `Dialog` 旧 synthetic `WM_MOUSEMOVE` 机制暂未统一。
- `Table` 内部局部重绘体系暂未实现。
- resize 过程中若开启高频 console 日志,可能出现一帧视觉延迟;当前判断属于调试态 I/O 现象,不作为 bug 处理,后续可在官网或 API 文档中注明。
## 落地信息
- 关联功能变更 ID[可选]
- `Feature-20260416-0009`
- 关联 BUG / Fix[可选]
- [Module-20260415-0004-布局系统第二阶段验收与封口.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/模块/Module-20260415-0004-布局系统第二阶段验收与封口.md)
- Commit:
- PR[可选]
- 发布版本:[可选]
- 相关文档:[可选]
- [Module-20260410-0002-锚点与布局系统第一阶段重构.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/模块/Module-20260410-0002-锚点与布局系统第一阶段重构.md)
- [Module-20260415-0004-布局系统第二阶段验收与封口.md](D:/programming/imGUI-easyX/imGui-easyX/开发记录/模块/Module-20260415-0004-布局系统第二阶段验收与封口.md)