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
+83 -1
View File
@@ -432,6 +432,8 @@ bool Button::handleEvent(const ExMessage& msg)
// 事件吞噬规则:
// - 鼠标移动:只有“当前命中按钮”时才吞掉,避免前一个按钮在清 hover 时截断消息,
// 导致后一个真正命中的按钮收不到 WM_MOUSEMOVE。
// 这里的前提是:父容器会保证“没有拿到真实消息的后续兄弟”还能走一遍
// clearTransientMouseState(),从而清掉旧 hover / tooltip。
// - 鼠标按下/抬起:命中按钮区域时吞掉,避免点击穿透到底层控件。
if (msg.message == WM_MOUSEMOVE)
{
@@ -451,6 +453,79 @@ bool Button::handleEvent(const ExMessage& msg)
return consume;
}
bool Button::clearTransientMouseState()
{
if (!show)
return false;
bool hoverChanged = false;
bool normalClickChanged = false;
bool bodyVisualChanged = false;
bool tooltipChanged = false;
if (hover)
{
hover = false;
hoverChanged = true;
bodyVisualChanged = true;
}
// NORMAL 模式下的按下态只属于一次鼠标交互过程;
// 如果本次 WM_MOUSEMOVE 已经被同层更上层的兄弟控件消费,
// 当前按钮就不应继续保留这笔临时按下视觉。
if (mode == StellarX::ButtonMode::NORMAL && click)
{
click = false;
normalClickChanged = true;
bodyVisualChanged = true;
}
if (tipVisible)
{
hideTooltip();
tooltipChanged = true;
}
const bool stateChanged = bodyVisualChanged || tooltipChanged;
if (!stateChanged)
return false;
SX_LOG_TRACE("Event")
<< SX_T("清理按钮鼠标临时状态:id=", "clear button transient mouse state: id=")
<< id
<< SX_T(" hover=", " hover=") << (hoverChanged ? 1 : 0)
<< SX_T(" tooltip=", " tooltip=") << (tooltipChanged ? 1 : 0)
<< SX_T(" normalClick=", " normalClick=") << (normalClickChanged ? 1 : 0);
markEventVisualChanged(true);
// 只有按钮本体视觉真正变化时,才请求按钮自身区域重绘;
// 若只是 Tooltip 消失,hideTooltip() 已经通过回贴快照清掉了悬浮层区域,
// 不再额外重绘按钮本体,避免高频鼠标移动时的无意义重画。
if (bodyVisualChanged)
{
dirty = true;
requestRepaint(parent);
}
return true;
}
RECT Button::getManagedRepaintCoverageRect() const
{
RECT coverage = getBoundsRect();
if (!tipEnabled || !tipVisible)
return coverage;
const RECT tipRect = tipLabel.getManagedRepaintCoverageRect();
coverage.left = (std::min)(coverage.left, tipRect.left);
coverage.top = (std::min)(coverage.top, tipRect.top);
coverage.right = (std::max)(coverage.right, tipRect.right);
coverage.bottom = (std::max)(coverage.bottom, tipRect.bottom);
return coverage;
}
void Button::setOnClickListener(std::function<void()> callback)
{
this->onClickCallback = std::move(callback);
@@ -558,7 +633,14 @@ void Button::setButtonShape(StellarX::ControlShape shape)
//允许通过外部函数修改按钮的点击状态,并执行相应的回调函数
void Button::setButtonClick(BOOL click)
{
this->click = click;
const bool targetClick = (click != FALSE);
// TOGGLE 状态若没有发生变化,就不应重复触发 onToggleOn/OffCallback。
// 否则像 TabControl 这种“外部再次激活已激活页签”的场景,
// 会把页面显示/隐藏、快照失效、重绘链整条重复执行一遍,最终破坏可见页的背景恢复语义。
if (mode == StellarX::ButtonMode::TOGGLE && this->click == targetClick)
return;
this->click = targetClick;
if (mode == StellarX::ButtonMode::NORMAL && click)
{