#include "Dialog.h" Dialog::Dialog(Window& h,std::string text,std::string message, StellarX::MessageBoxType type, bool modal) : Canvas(),message(message), type(type), modal(modal), hWnd(h), titleText(text) { this->id = "Dialog"; show = false; } Dialog::~Dialog() { } void Dialog::draw() { if(!show) { // 如果对话框不可见且需要清理,执行清理 if (pendingCleanup && !isCleaning) { performDelayedCleanup(); } return; } // 如果需要初始化,则执行初始化 if (needsInitialization && show) { initDialogSize(); needsInitialization = false; } if (dirty && show) { // 保存当前绘图状态 saveStyle(); if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage) saveBackground(this->x, this->y, this->width, this->height); Canvas::setBorderColor(this->borderColor); Canvas::setLinewidth(this->BorderWidth); Canvas::setCanvasBkColor(this->backgroundColor); Canvas::setShape(StellarX::ControlShape::ROUND_RECTANGLE); //设置所有控件为脏状态 for(auto& c :this->controls) c->setDirty(true); Canvas::draw(); //绘制消息文本 settextcolor(textStyle.color); //设置字体样式 settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace, textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight, textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut); int ty = y + closeButtonHeight + titleToTextMargin; // 文本起始Y坐标 for (auto line:lines) { int tx = this->x + ((this->width - textwidth(line.c_str())) / 2); // 文本起始X坐标 outtextxy(tx, ty, LPCTSTR(line.c_str())); ty = ty + textheight(LPCTSTR(line.c_str())) + 5; // 每行文本高度加5像素间距 } // 恢复绘图状态 restoreStyle(); dirty = false; } } bool Dialog::handleEvent(const ExMessage& msg) { bool consume = false; if (!show) { if (pendingCleanup && !isCleaning) { performDelayedCleanup(); } return false; } // 如果正在清理或标记为待清理,则不处理事件 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)) { std::cout << "\a" << std::endl; // 模态对话框不允许点击外部区域 return true; } // 将事件传递给子控件处理 if (!consume) consume = Canvas::handleEvent(msg); // 每次事件处理后检查是否需要执行延迟清理 if (pendingCleanup && !isCleaning) performDelayedCleanup(); return consume; } void Dialog::SetTitle(const std::string& title) { this->titleText = title; if (this->title) { this->title->setText(title); } dirty = true; } void Dialog::SetMessage(const std::string& message) { this->message = message; splitMessageLines(); getTextSize(); dirty = true; } void Dialog::SetType(StellarX::MessageBoxType type) { this->type = type; // 重新初始化按钮 initButtons(); dirty = true; } void Dialog::SetModal(bool modal) { this->modal = modal; } void Dialog::SetResult(StellarX::MessageBoxResult result) { this->result = result; } StellarX::MessageBoxResult Dialog::GetResult() const { return this->result; } bool Dialog::model() const { return modal; } void Dialog::Show() { if (pendingCleanup) performDelayedCleanup(); show = true; dirty = true; needsInitialization = true; close = false; shouldClose = false; if (modal) { // 模态对话框需要阻塞当前线程直到对话框关闭 while (show && !close) { // 处理消息 ExMessage msg; if (peekmessage(&msg, EX_MOUSE | EX_KEY)) { handleEvent(msg); // 检查是否需要关闭 if (shouldClose) { Close(); break; } } // 重绘 if (dirty) { requestRepaint(); FlushBatchDraw(); } // 避免CPU占用过高 Sleep(10); } // 模态对话框关闭后执行清理 if (pendingCleanup && !isCleaning) performDelayedCleanup(); } else // 非模态对话框只需标记为可见,由主循环处理 dirty = true; } void Dialog::Close() { if (!show) return; show = false; close = true; dirty = true; pendingCleanup = true; // 只标记需要清理,不立即执行 auto& c = hWnd.getControls(); for(auto& control:c) control->setDirty(true); // 工厂模式下非模态触发回调 返回结果 if (resultCallback&& !modal) resultCallback(this->result); } void Dialog::setInitialization(bool init) { if (init) { initDialogSize(); saveBackground((x - BorderWidth), (y - BorderWidth), (width + 2 * BorderWidth), (height + 2 * BorderWidth)); } } void Dialog::initButtons() { controls.clear(); switch (this->type) { case StellarX::MessageBoxType::OK: // 只有确定按钮 { auto okbutton = createDialogButton((this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin * (buttonNum - 1))) / 2), ((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2), "确定" ); okbutton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::OK); this->Close(); }); okbutton->textStyle = this->textStyle; this->addControl(std::move(okbutton)); } break; case StellarX::MessageBoxType::OKCancel: // 确定和取消按钮 { auto okButton = createDialogButton( (this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin * (buttonNum - 1))) / 2), ((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2), "确定" ); okButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::OK); this->hWnd.dialogClose = true; this->Close(); }); auto cancelButton = createDialogButton( (okButton.get()->getX() + okButton.get()->getButtonWidth() + buttonMargin), okButton.get()->getY(), "取消" ); cancelButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Cancel); this->hWnd.dialogClose = true; this->Close(); }); okButton->textStyle = this->textStyle; cancelButton->textStyle = this->textStyle; this->addControl(std::move(okButton)); this->addControl(std::move(cancelButton)); } break; case StellarX::MessageBoxType::YesNo: // 是和否按钮 { auto yesButton = createDialogButton( (this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin * (buttonNum - 1))) / 2), ((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2), "是" ); yesButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Yes); this->hWnd.dialogClose = true; this->Close(); }); auto noButton = createDialogButton( (yesButton.get()->getX() + yesButton.get()->getButtonWidth() + buttonMargin), yesButton.get()->getY(), "否" ); noButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::No); this->hWnd.dialogClose = true; this->Close(); }); yesButton->textStyle = this->textStyle; noButton->textStyle = this->textStyle; this->addControl(std::move(yesButton)); this->addControl(std::move(noButton)); } break; case StellarX::MessageBoxType::YesNoCancel: // 是、否和取消按钮 { auto yesButton = createDialogButton( (this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin * (buttonNum - 1))) / 2), ((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2), "是" ); yesButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Yes); this->hWnd.dialogClose = true; this->Close(); }); auto noButton = createDialogButton( yesButton.get()->getX() + yesButton.get()->getButtonWidth() + buttonMargin, yesButton.get()->getY(), "否" ); noButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::No); this->hWnd.dialogClose = true; this->Close(); }); auto cancelButton = createDialogButton( noButton.get()->getX() + noButton.get()->getButtonWidth() + buttonMargin, noButton.get()->getY(), "取消" ); cancelButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Cancel); this->hWnd.dialogClose = true; this->Close(); }); yesButton->textStyle = this->textStyle; noButton->textStyle = this->textStyle; cancelButton->textStyle = this->textStyle; this->addControl(std::move(yesButton)); this->addControl(std::move(noButton)); this->addControl(std::move(cancelButton)); } break; case StellarX::MessageBoxType::RetryCancel: // 重试和取消按钮 { auto retryButton = createDialogButton( (this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin * (buttonNum - 1))) / 2), ((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2), "重试" ); retryButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Retry); this->hWnd.dialogClose = true; this->Close(); }); auto cancelButton = createDialogButton( retryButton.get()->getX() + retryButton.get()->getButtonWidth() + buttonMargin, retryButton.get()->getY(), "取消" ); cancelButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Cancel); this->hWnd.dialogClose = true; this->Close(); }); retryButton->textStyle = this->textStyle; cancelButton->textStyle = this->textStyle; this->addControl(std::move(retryButton)); this->addControl(std::move(cancelButton)); } break; case StellarX::MessageBoxType::AbortRetryIgnore: // 中止、重试和忽略按钮 { auto abortButton = createDialogButton( (this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin* (buttonNum-1))) / 2), ((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2), "中止" ); abortButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Abort); this->hWnd.dialogClose = true; this->Close(); }); auto retryButton = createDialogButton( abortButton.get()->getX() + abortButton.get()->getButtonWidth() + buttonMargin, abortButton.get()->getY(), "重试" ); retryButton->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Retry); this->hWnd.dialogClose = true; this->Close(); }); auto ignoreButton = createDialogButton( retryButton.get()->getX() + retryButton.get()->getButtonWidth() + buttonMargin, retryButton.get()->getY(), "忽略" ); ignoreButton.get()->setOnClickListener([this]() { this->SetResult(StellarX::MessageBoxResult::Ignore); this->hWnd.dialogClose = true; this->Close(); }); abortButton->textStyle = this->textStyle; retryButton->textStyle = this->textStyle; ignoreButton->textStyle = this->textStyle; this->addControl(std::move(abortButton)); this->addControl(std::move(retryButton)); this->addControl(std::move(ignoreButton)); } break; } } void Dialog::initCloseButton() { //初始化关闭按钮 auto but = std::make_unique