Finalize layout stage 2 fixes and refresh regression scenes

This commit is contained in:
Codex
2026-04-16 11:40:39 +08:00
parent b7ad960518
commit 738cf035bb
20 changed files with 1470 additions and 308 deletions
+72
View File
@@ -133,6 +133,35 @@ namespace
result.pos = childDesignPos;
return result;
}
const char* SxAxisName(bool horizontal)
{
return horizontal ? "X" : "Y";
}
void LogAxisDowngradeIfNeeded(const std::string& id, bool horizontal,
const StellarX::AxisLayoutSpec& spec, bool allowStretch)
{
if (spec.sizePolicy != StellarX::AxisSizePolicy::Stretch)
return;
if (!spec.anchorStart || !spec.anchorEnd)
{
SX_LOGD("Layout")
<< SX_T("布局降级:id=", "layout downgrade: id=") << id
<< SX_T(" axis=", " axis=") << SxAxisName(horizontal)
<< SX_T(" 原因=Stretch 但未同时锚定起止边", " reason=stretch without dual anchors");
return;
}
if (!allowStretch)
{
SX_LOGD("Layout")
<< SX_T("能力边界拦截:id=", "layout capability intercept: id=") << id
<< SX_T(" axis=", " axis=") << SxAxisName(horizontal)
<< SX_T(" 原因=当前控件禁止该轴 Stretch", " reason=stretch disabled by capability");
}
}
}
StellarX::ControlText& StellarX::ControlText::operator=(const ControlText& text)
@@ -270,15 +299,31 @@ void Control::setHeight(int height)
dirty = true;
}
bool Control::clearTransientMouseState()
{
// 基类默认没有 hover / tooltip / 临时按下态等鼠标瞬时状态。
// 具体控件若需要在“未收到本次 WM_MOUSEMOVE”时做清理,重写此接口即可。
return false;
}
void Control::commitCurrentGeometryAsDesignRect()
{
// 该接口是“显式提交新的设计基线”的唯一入口之一。
// 普通布局解算、父容器重排、窗口 resize 均不得自动回写 local*
// 否则会导致设计基线漂移,后续解算越来越不稳定。
SX_LOGD("Layout")
<< SX_T("提交设计基线:id=", "commit design rect: id=") << id
<< SX_T(" world=(", " world=(") << x << "," << y << "," << width << "," << height << ")"
<< SX_T(" parentLocalBefore=(", " parentLocalBefore=(")
<< localx << "," << localy << "," << localWidth << "," << localHeight << ")";
localx = parent ? (x - parent->getX()) : x;
localy = parent ? (y - parent->getY()) : y;
localWidth = width;
localHeight = height;
SX_LOGD("Layout")
<< SX_T("提交设计基线完成:id=", "commit design rect done: id=") << id
<< SX_T(" parentLocalAfter=(", " parentLocalAfter=(")
<< localx << "," << localy << "," << localWidth << "," << localHeight << ")";
}
StellarX::ResolvedLayoutRect Control::resolveLayoutRect(int parentDesignW, int parentDesignH,
@@ -299,6 +344,8 @@ StellarX::ResolvedLayoutRect Control::resolveLayoutRect(int parentDesignW, int p
}
// 第 1 层:先在父局部坐标系内分别解算水平轴和垂直轴。
LogAxisDowngradeIfNeeded(id, true, layoutSpec.horizontal, layoutCapability.allowStretchX);
LogAxisDowngradeIfNeeded(id, false, layoutSpec.vertical, layoutCapability.allowStretchY);
const LayoutAxisResult horizontal = ResolveAxis(parentDesignW, parentCurrentW, localx, localWidth,
layoutSpec.horizontal, layoutCapability.allowStretchX);
const LayoutAxisResult vertical = ResolveAxis(parentDesignH, parentCurrentH, localy, localHeight,
@@ -436,6 +483,17 @@ Control* Control::getManagedRepaintRoot()
return root;
}
Control* Control::getManagedRepaintDirectBranch(Control* root)
{
if (!root)
return nullptr;
Control* branch = this;
while (branch->parent && branch->parent != root)
branch = branch->parent;
return branch;
}
RECT Control::getBoundsRect() const
{
RECT rc{};
@@ -446,6 +504,13 @@ RECT Control::getBoundsRect() const
return rc;
}
RECT Control::getManagedRepaintCoverageRect() const
{
// 基类默认认为“实际绘制 coverage == 控件本体矩形”。
// 复合控件或带浮层的控件会 override,把附加绘制区域一并并入。
return getBoundsRect();
}
bool Control::canCommitManagedPartialRepaint() const
{
// 基类默认不承诺自己能安全做局部提交;
@@ -453,6 +518,13 @@ bool Control::canCommitManagedPartialRepaint() const
return false;
}
bool Control::hasManagedDirtySubtree() const
{
// 基类只感知自身是否为脏;
// 容器类会 override 为“自身或其受管理子树是否有脏内容”。
return dirty;
}
void Control::commitManagedRepaint()
{
if (!show)