236 lines
8.2 KiB
C++
236 lines
8.2 KiB
C++
#include "dialogs/BlackholeResolveDialog.h"
|
|
|
|
#include <QDialogButtonBox>
|
|
#include <QFrame>
|
|
#include <QLabel>
|
|
#include <QMessageBox>
|
|
#include <QPlainTextEdit>
|
|
#include <QPushButton>
|
|
#include <QRadioButton>
|
|
#include <QStackedWidget>
|
|
#include <QVBoxLayout>
|
|
|
|
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);
|
|
}
|
|
|