# 新增功能模块 / 模块重构 > 适用场景:新增模块、重大模块重构、核心架构能力演进。 > 不适用场景:小接口或轻量功能变更,请使用“功能变更”模板。 ## 基本信息 - 模块 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)