Save pre-batched-redraw snapshot
This commit is contained in:
+53
-25
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user