#include "dialogs/BlackholeResolveDialog.h" #include #include #include #include #include #include #include #include #include namespace { const QString kDefaultFluxInpaintPrompt = QStringLiteral( "这是一幅中国山水画的一部分,mask是被我去除的一个人物,现在需要在原来的位置填充与周围画布连贯的背景"); QPushButton* makeAlgoButton(const QString& title, QWidget* parent) { auto* btn = new QPushButton(parent); btn->setCheckable(false); btn->setCursor(Qt::PointingHandCursor); btn->setMinimumHeight(48); btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); btn->setText(title); btn->setStyleSheet( "QPushButton { text-align: left; padding: 10px 12px; border: 1px solid palette(mid); border-radius: 8px; }" "QPushButton:hover { border-color: palette(highlight); }"); return btn; } } // namespace BlackholeResolveDialog::BlackholeResolveDialog(const QString& blackholeName, QWidget* parent) : QDialog(parent), m_blackholeName(blackholeName) { setModal(true); setMinimumSize(400, 320); setWindowTitle(QStringLiteral("修复 · %1").arg(m_blackholeName)); auto* root = new QVBoxLayout(this); m_pages = new QStackedWidget(this); root->addWidget(m_pages, 1); buildSelectPage(); buildDetailPage(); m_pages->setCurrentWidget(m_pageSelect); } QString BlackholeResolveDialog::inpaintModelKey() const { if (m_radioFlux && m_radioFlux->isChecked()) { return QStringLiteral("flux_fill"); } return QStringLiteral("lama"); } QString BlackholeResolveDialog::promptText() const { return m_promptEdit ? m_promptEdit->toPlainText().trimmed() : QString(); } void BlackholeResolveDialog::buildSelectPage() { m_pageSelect = new QWidget(this); auto* layout = new QVBoxLayout(m_pageSelect); layout->setContentsMargins(8, 8, 8, 8); layout->setSpacing(12); auto* title = new QLabel(QStringLiteral("方式"), m_pageSelect); title->setStyleSheet("font-size: 16px; font-weight: 600;"); layout->addWidget(title); auto* btnCopy = makeAlgoButton(QStringLiteral("复制背景"), m_pageSelect); auto* btnOriginal = makeAlgoButton(QStringLiteral("原始背景"), m_pageSelect); auto* btnModel = makeAlgoButton(QStringLiteral("模型补全"), m_pageSelect); layout->addWidget(btnCopy); layout->addWidget(btnOriginal); layout->addWidget(btnModel); layout->addStretch(1); auto* btns = new QDialogButtonBox(QDialogButtonBox::Cancel, m_pageSelect); connect(btns, &QDialogButtonBox::rejected, this, &QDialog::reject); layout->addWidget(btns); connect(btnCopy, &QPushButton::clicked, this, [this]() { enterAlgorithmPage(Algorithm::CopyBackgroundRegion); }); connect(btnOriginal, &QPushButton::clicked, this, [this]() { enterAlgorithmPage(Algorithm::UseOriginalBackground); }); connect(btnModel, &QPushButton::clicked, this, [this]() { enterAlgorithmPage(Algorithm::ModelInpaint); }); m_pages->addWidget(m_pageSelect); } void BlackholeResolveDialog::buildDetailPage() { m_pageDetail = new QWidget(this); auto* layout = new QVBoxLayout(m_pageDetail); layout->setContentsMargins(8, 8, 8, 8); layout->setSpacing(10); m_detailTitle = new QLabel(m_pageDetail); m_detailTitle->setStyleSheet("font-size: 15px; font-weight: 600;"); layout->addWidget(m_detailTitle); m_algoDetails = new QStackedWidget(m_pageDetail); // 详情页 A:复制背景其他区域(交互布局) m_copyDetail = new QWidget(m_algoDetails); { auto* cLay = new QVBoxLayout(m_copyDetail); cLay->setSpacing(8); auto* panel = new QFrame(m_copyDetail); panel->setFrameShape(QFrame::StyledPanel); auto* pLay = new QVBoxLayout(panel); pLay->setSpacing(8); auto* tip = new QLabel(QStringLiteral("在画布拖动取样。"), panel); tip->setStyleSheet("color: palette(mid);"); pLay->addWidget(tip); cLay->addWidget(panel); cLay->addStretch(1); } // 详情页 B:使用原始背景(确认布局) m_originalDetail = new QWidget(m_algoDetails); { auto* oLay = new QVBoxLayout(m_originalDetail); oLay->setSpacing(8); auto* desc = new QLabel(QStringLiteral("不修改背景原图。"), m_originalDetail); desc->setWordWrap(true); oLay->addWidget(desc); oLay->addStretch(1); } // 详情页 C:模型补全 m_modelDetail = new QWidget(m_algoDetails); { auto* mLay = new QVBoxLayout(m_modelDetail); mLay->setSpacing(8); auto* panel = new QFrame(m_modelDetail); panel->setFrameShape(QFrame::StyledPanel); auto* pLay = new QVBoxLayout(panel); pLay->setSpacing(8); m_radioLama = new QRadioButton(QStringLiteral("LaMa"), panel); m_radioFlux = new QRadioButton(QStringLiteral("FLUX Fill"), panel); m_radioLama->setChecked(true); pLay->addWidget(m_radioLama); pLay->addWidget(m_radioFlux); m_promptLabel = new QLabel(QStringLiteral("提示词"), panel); pLay->addWidget(m_promptLabel); m_promptEdit = new QPlainTextEdit(panel); m_promptEdit->setMinimumHeight(72); m_promptLabel->setVisible(false); m_promptEdit->setVisible(false); pLay->addWidget(m_promptEdit); auto syncPromptUi = [this]() { if (!m_promptEdit || !m_promptLabel) { return; } const bool flux = m_radioFlux && m_radioFlux->isChecked(); m_promptLabel->setVisible(flux); m_promptEdit->setVisible(flux); if (flux) { m_promptEdit->setEnabled(true); if (m_promptEdit->toPlainText().trimmed().isEmpty()) { m_promptEdit->setPlainText(kDefaultFluxInpaintPrompt); } } else { m_promptEdit->setEnabled(false); } }; connect(m_radioLama, &QRadioButton::toggled, this, [syncPromptUi](bool on) { if (on) { syncPromptUi(); } }); connect(m_radioFlux, &QRadioButton::toggled, this, [syncPromptUi](bool on) { if (on) { syncPromptUi(); } }); syncPromptUi(); mLay->addWidget(panel); mLay->addStretch(1); } m_algoDetails->addWidget(m_copyDetail); m_algoDetails->addWidget(m_originalDetail); m_algoDetails->addWidget(m_modelDetail); layout->addWidget(m_algoDetails, 1); auto* btns = new QDialogButtonBox(m_pageDetail); auto* btnBack = btns->addButton(QStringLiteral("返回"), QDialogButtonBox::ActionRole); auto* btnApply = btns->addButton(QStringLiteral("确定"), QDialogButtonBox::AcceptRole); auto* btnCancel = btns->addButton(QDialogButtonBox::Cancel); connect(btnBack, &QPushButton::clicked, this, [this]() { m_pages->setCurrentWidget(m_pageSelect); }); connect(btnApply, &QPushButton::clicked, this, [this]() { if (m_selectedAlgorithm == Algorithm::ModelInpaint && m_radioFlux && m_radioFlux->isChecked() && promptText().isEmpty()) { QMessageBox::warning(this, QStringLiteral("模型补全"), QStringLiteral("请填写提示词。")); return; } accept(); }); connect(btnCancel, &QPushButton::clicked, this, &QDialog::reject); layout->addWidget(btns); m_pages->addWidget(m_pageDetail); } void BlackholeResolveDialog::enterAlgorithmPage(Algorithm algo) { m_selectedAlgorithm = algo; if (algo == Algorithm::CopyBackgroundRegion) { m_detailTitle->setText(QStringLiteral("复制背景")); m_algoDetails->setCurrentWidget(m_copyDetail); } else if (algo == Algorithm::UseOriginalBackground) { m_detailTitle->setText(QStringLiteral("原始背景")); m_algoDetails->setCurrentWidget(m_originalDetail); } else { m_detailTitle->setText(QStringLiteral("模型补全")); m_algoDetails->setCurrentWidget(m_modelDetail); } m_pages->setCurrentWidget(m_pageDetail); }