Save pre-batched-redraw snapshot

This commit is contained in:
Codex
2026-04-07 16:23:40 +08:00
parent 7f8431a18c
commit b07a4ec370
8 changed files with 142 additions and 54 deletions
+53 -25
View File
@@ -44,12 +44,15 @@ void Dialog::draw()
//绘制消息文本
settextcolor(textStyle.color);
setbkmode(TRANSPARENT);
//设置字体样式
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
outtextxy(x + 5, y + 5, LPCTSTR(titleText.c_str()));
int ty = y + closeButtonHeight + titleToTextMargin; // 文本起始Y坐标
for (auto& line : lines)
{
@@ -68,6 +71,7 @@ void Dialog::draw()
bool Dialog::handleEvent(const ExMessage& msg)
{
bool consume = false;
resetEventVisualChanged();
if (!show)
{
if (pendingCleanup && !isCleaning)
@@ -80,12 +84,20 @@ bool Dialog::handleEvent(const ExMessage& msg)
// 如果正在清理或标记为待清理,则不处理事件
if (pendingCleanup || isCleaning)
return false;
// 模态对话框不允许点击外部区域
// 模态对话框:点击对话框外部区域时,发出提示音(\a)并吞噬该事件,不允许操作背景内容。
if (modal && msg.message == WM_LBUTTONUP &&
(msg.x < x || msg.x > x + width || msg.y < y || msg.y > y + height))
const bool isMouseMessage =
msg.message == WM_MOUSEMOVE ||
msg.message == WM_LBUTTONDOWN ||
msg.message == WM_LBUTTONUP;
const bool insideDialog =
msg.x >= x && msg.x <= x + width &&
msg.y >= y && msg.y <= y + height;
// 模态对话框区域外鼠标事件不允许落到底层背景。
if (modal && isMouseMessage && !insideDialog)
{
std::cout << "\a" << std::endl;
if (msg.message == WM_LBUTTONUP)
std::cout << "\a" << std::endl;
return true;
}
@@ -93,6 +105,10 @@ bool Dialog::handleEvent(const ExMessage& msg)
if (!consume)
consume = Canvas::handleEvent(msg);
// 对话框矩形范围内的鼠标事件一律由对话框吞掉,避免穿透到底层控件。
if (isMouseMessage && insideDialog)
consume = true;
// 每次事件处理后检查是否需要执行延迟清理
if (pendingCleanup && !isCleaning)
performDelayedCleanup();
@@ -182,9 +198,8 @@ void Dialog::Show()
// 立即统一收口:父窗重绘 背景+普通控件(不会画到这只模态)
hWnd.pumpResizeIfNeeded();
// 这只模态在新尺寸下重建布局 / 重抓背景 → 本帧要画自己
setInitialization(true);
setDirty(true);
// 这只模态只重新居中,不参与拉伸;背景快照需要在新位置重抓。
recenterInHostWindow();
}
// ② 处理这只对话框的鼠标/键盘(沿用原来 EX_MOUSE | EX_KEY
@@ -257,10 +272,30 @@ void Dialog::setInitialization(bool init)
}
}
void Dialog::recenterInHostWindow()
{
if (!show)
return;
// 尚未完成首次初始化时,保持“延迟初始化”语义,由首次 draw 统一创建子控件。
if (needsInitialization || width <= 0 || height <= 0)
{
dirty = true;
return;
}
const int newX = (hWnd.getWidth() - width) / 2;
const int newY = (hWnd.getHeight() - height) / 2;
invalidateBackgroundSnapshot();
x = newX;
y = newY;
rebuildChrome();
dirty = true;
}
void Dialog::initButtons()
{
controls.clear();
switch (this->type)
{
case StellarX::MessageBoxType::OK: // 只有确定按钮
@@ -489,16 +524,6 @@ void Dialog::initCloseButton()
this->addControl(std::move(but));
}
void Dialog::initTitle()
{
auto titleLabel = std::make_unique<Label>(this->x + 5, this->y + 5, titleText, textStyle.color);
titleLabel->setTextdisap(true);
titleLabel->textStyle = this->textStyle;
this->title = titleLabel.get();
this->addControl(std::move(titleLabel));
}
void Dialog::splitMessageLines()
{
lines.clear(); // 先清空现有的行
@@ -570,6 +595,13 @@ void Dialog::invalidateLayout(bool clearChildren)
this->dirty = true;
}
void Dialog::rebuildChrome()
{
clearControls();
initButtons();
initCloseButton();
}
// 计算逻辑:对话框宽度取【文本区域最大宽度】和【按钮区域总宽度】中的较大值。
// 对话框高度 = 标题栏 + 文本区 + 按钮区 + 各种间距。
void Dialog::initDialogSize()
@@ -626,9 +658,7 @@ void Dialog::initDialogSize()
this->x = (hWnd.getWidth() - this->width) / 2;
this->y = (hWnd.getHeight() - this->height) / 2;
initButtons(); // 初始化按钮
initTitle(); // 初始化标题标签
initCloseButton(); // 初始化关闭按钮
rebuildChrome();
}
void Dialog::addControl(std::unique_ptr<Control> control)
@@ -655,7 +685,6 @@ void Dialog::performDelayedCleanup()
// 重置指针
closeButton = nullptr;
title = nullptr;
// 释放背景图像资源
if (saveBkImage && hasSnap)
{
@@ -709,7 +738,6 @@ void Dialog::clearControls()
controls.clear();
// 重置按钮指针
closeButton = nullptr;
title = nullptr; // 释放标题资源
}
std::unique_ptr<Button> Dialog::createDialogButton(int x, int y, const std::string& text)