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