diff --git a/kylin-theme-builder.pro b/kylin-theme-builder.pro index f21cfba..da8d508 100644 --- a/kylin-theme-builder.pro +++ b/kylin-theme-builder.pro @@ -1,10 +1,15 @@ -QT += core gui svg KWindowSystem multimedia multimediawidgets concurrent +QT += core gui svg KWindowSystem multimedia multimediawidgets concurrent dbus printsupport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 link_pkgconfig -PKGCONFIG += kysdk-qtwidgets kysdk-waylandhelper kysdk-sysinfo kysdk-datacollect gsettings-qt +KF5 += i18n doctools guiaddons widgetsaddons kio xmlgui textwidgets jobwidgets + +PKGCONFIG += kysdk-qtwidgets kysdk-waylandhelper kysdk-sysinfo kysdk-datacollect gsettings-qt kylin-ai-base jsoncpp json-glib-1.0 + +INCLUDEPATH += /usr/include/KF5 +INCLUDEPATH += /usr/include/KF5/KI18n # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings @@ -50,7 +55,8 @@ SOURCES += \ src/module/plymouththemefeature.cpp \ src/module/plymouththemewidget.cpp \ src/module/savepathdialog.cpp \ - src/titlebar.cpp + src/titlebar.cpp \ + src/aithemebar.cpp HEADERS += \ src/build/build.h \ @@ -84,7 +90,8 @@ HEADERS += \ src/module/plymouththemefeature.h \ src/module/plymouththemewidget.h \ src/module/savepathdialog.h \ - src/titlebar.h + src/titlebar.h \ + src/aithemebar.h RESOURCES += \ resource.qrc @@ -103,4 +110,5 @@ appdesktop.files += kylin-theme-builder.desktop appdesktop.path = /usr/share/applications/ INSTALLS +=target qm_files appdesktop -LIBS += -lukui-log4qt + +LIBS += -lukui-log4qt -L/usr/lib/x86_64-linux-gnu -lKF5I18n diff --git a/src/aithemebar.cpp b/src/aithemebar.cpp new file mode 100644 index 0000000..cc4e278 --- /dev/null +++ b/src/aithemebar.cpp @@ -0,0 +1,1242 @@ +/* + Copyright (c) 2003-2007 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "aithemebar.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int configVersion = 2; //AI作图基础版本和高级版本的分别 + +aithemebar::aithemebar(QWidget *parent) + : QWidget (parent) +{ + setAcceptDrops (false); + + AiSettings = nullptr; + //取消登录界面绘画 + /* + if(!getConfigStatus()) + loginConfigurationPage(); + else + */ + + m_AiMode = new AIModeDataThread(); + if(m_AiMode->setSessionStatus()) + { + mSession = m_AiMode->getVisionSession(); + } + + initUI(); + + setFixedWidth(250); +} + +aithemebar::~aithemebar() +{ + if (AiSettings) + delete AiSettings; + if (m_AiMode) + delete m_AiMode; +} + +/** + * @brief aithemebar::getConfigStatus + * 获取AI画图秘钥是否配置 + * @return 是否配置 + */ +bool aithemebar::getConfigStatus() +{ + bool res = false; + if (QGSettings::isSchemaInstalled(AI_GSETTINGS)){ + AiSettings = new QGSettings(AI_GSETTINGS); + connect(AiSettings, &QGSettings::changed, this, &aithemebar::onConfigSettingsChange); + res = AiSettings->get(AI_KEY).toBool(); + } + + return res; +} + +/** + * @brief aithemebar::onConfigSettingsChange + * 配置反馈回调函数 + * @param key + */ +void aithemebar::onConfigSettingsChange(const QString &key) +{ + qDebug()<<"key == "<get("isVisionSetup").toBool()){ + if (configWidget) { + delete configWidget; + initUI(); + } + } + } +} + +/** + * @brief aithemebar::loginConfigurationPage + * 登录配置界面函数 + */ +void aithemebar::loginConfigurationPage() +{ + configWidget = new QWidget(this); + QVBoxLayout* layout = new QVBoxLayout(configWidget); + + QLabel* label_logo = new QLabel(this); + label_logo->setPixmap(QPixmap(DRAWING_IMAGE)); + label_logo->setScaledContents(true); + label_logo->setFixedSize(54,52); + + QLabel* label_slogo = new QLabel(this); + label_slogo->setPixmap(QPixmap(SLOGO_IMAGE)); + label_slogo->setScaledContents(true); + label_slogo->setFixedSize(168,24); + + QLabel* label_config = new QLabel(this); + label_config->setText(i18n("Please configure the AI model account before you can use the mapping function.")); + label_config->setFixedSize(218,52); + label_config->setAlignment(Qt::AlignCenter); + label_config->setWordWrap(true); + label_config->setStyleSheet("color: #B8B8B8;"); + + QPushButton* button_config = new QPushButton(i18n("Configure now"),this); + button_config->setFixedSize(112,36); + button_config->setStyleSheet("QPushButton" + "{ background-color: #3790FA; " + "color: white; " + "border: none;" + "border-radius: 5px; }"); + + QLabel* label_bg = new QLabel(this); + label_bg->setFixedSize(250, 160); + label_bg->setPixmap(QPixmap(BG_IMAGE)); + label_bg->setScaledContents(true); + + layout->addStretch(25); + layout->addWidget(label_logo, 0, Qt::AlignCenter); + layout->addStretch(1); + layout->addWidget(label_slogo, 1, Qt::AlignCenter); + layout->addStretch(1); + layout->addWidget(label_config, 2, Qt::AlignCenter); + layout->addStretch(1); + layout->addSpacing(15); + layout->addWidget(button_config, 3, Qt::AlignCenter); + layout->addStretch(25); + layout->addWidget(label_bg, 4); + + connect(button_config, &QPushButton::clicked, this, &aithemebar::onConfigButtonClicked); + configWidget->setLayout(layout); + // setWidget(configWidget); + +} + +/** + * @brief aithemebar::onConfigButtonClicked + * 登录配置按钮回调函数,调用秘钥配置界面 + */ +void aithemebar::onConfigButtonClicked() +{ + QDBusInterface *m_dbusInterface = new QDBusInterface(KYLIN_AI_DBUS, + KYLIN_AI_PATH, + KYLIN_AI_DBUS, + QDBusConnection::sessionBus(), + this); + if(m_dbusInterface->isValid()){ + m_dbusInterface->call("setModel"); + } + delete m_dbusInterface; +} + + +/** + * @brief aithemebar::getconfigVersionData + * 获取AI作图调用的模型是基础版本还是高级版本 + */ +void aithemebar::getconfigVersionData() +{ + QString jsonFilePath = QDir::homePath() + "/.config/model_manager.json"; + + qDebug()<setMinimumSize(250,620); + centralWidget->setMaximumWidth(250); + centralWidget->setBackgroundRole(QPalette::Base); + centralWidget->setAutoFillBackground(true); + + textBox = QString("A cute cat pilot wearing goggles is soaring through the blue sky, cartoon style, HD"); + + colorfulButtonStyle = "QPushButton " + "{ background: qlineargradient(" + "x1: 0, y1: 0, x2: 1, y2: 0," + "stop: 0 #3790FA, " + "stop: 1 #E85CFF);" + "color: white; " + "border: none;" + "border-radius: 5px; }"; + + colorGrayButtonStyle = "QPushButton" + "{ background-color: #E6E6E6; " + "color: #2626268C; " + "border: none;" + "border-radius: 5px; }"; + // 获取基础版本/高级版本 +// getconfigVersionData(); + +// if (configVersion == 2) + AIImageSize = QSize(512, 512); +// else if (configVersion == 1) +// AIImageSize = QSize(1536, 1024); + + /* 图像描述布局 */ + auto *label = new QLabel(i18n("Image description")); + label->setAlignment(Qt::AlignLeft | Qt::AlignTop); + label->setFixedSize(224,30); + + QTextEdit *inputBox = new QTextEdit(); + inputBox->setPlaceholderText(i18n(textBox.toLocal8Bit().data())); + inputBox->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + inputBox->setFixedSize(224,100); + + /* 图像风格布局 */ + auto *styleLabel = new QLabel(i18n("Image style")); + styleLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); + styleLabel->setFixedSize(180, 30); + + styleGrid = new QGridLayout(); + addStyleWidget(); + + /* 图像分辨率 */ + auto *resolutionLabel = new QLabel(i18n("Image resolution")); + resolutionLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); + resolutionLabel->setFixedSize(180, 30); + + resolutionComboBox = new QComboBox(this); + addResolutionComboBox(); + + /* 生成数量布局 */ + QLabel *quantityLabel = new QLabel(i18n("Generated quantity")); + quantityLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); + quantityLabel->setFixedSize(180, 30); + + quantityComboBox = new QComboBox(this); + addQuantityComboBox(); + + /* 立即生成按钮 */ + buildButton = new QPushButton(i18n("Generate now"), this); + buildButton->setFixedSize(224,36); + buildButton->setStyleSheet(colorGrayButtonStyle); + buildButton->setEnabled(false); + buildButtonFlag = false; + + /* 分页功能 */ + stackedWidget = new QStackedWidget(centralWidget); + + /* 生成结果布局 */ + resultGrid = new QHBoxLayout(this); + resultLabel = new QLabel(i18n("result")); + QPushButton *previousButton = new QPushButton(this); + pageLabel = new QLabel(tr("1")); + QPushButton *nextButton = new QPushButton(this); + deleteButton = new QPushButton(this); + resultLabel->setFixedSize(80,30); + + previousButton->setIcon(QIcon::fromTheme("ukui-start-symbolic")); + previousButton->setFixedSize(20,20); + previousButton->setStyleSheet("QPushButton { background-color: transparent; }"); + + pageLabel->setFixedSize(50,30); + pageLabel->setAlignment(Qt::AlignCenter); + + nextButton->setFixedSize(20,20); + nextButton->setIcon(QIcon::fromTheme("ukui-end-symbolic")); + nextButton->setStyleSheet("QPushButton { background-color: transparent; }"); + + deleteButton->setIcon(QIcon::fromTheme("edit-delete-symbolic")); + deleteButton->setFixedSize(24,24); + deleteButton->setStyleSheet("QPushButton { background-color: transparent; }"); + + resultGrid->addWidget(resultLabel); + resultGrid->addStretch(); + resultGrid->addWidget(previousButton); + resultGrid->addWidget(pageLabel); + resultGrid->addWidget(nextButton); + resultGrid->addWidget(deleteButton); + resultGrid->setAlignment(pageLabel, Qt::AlignRight); + + /* 创建一个容器小部件来包含 resultGrid */ + QWidget *resultWidget = new QWidget(this); + resultWidget->setLayout(resultGrid); + + /* 设置整体布局 */ + vbox = new QVBoxLayout(centralWidget); + vbox->setMargin (2); + vbox->setSpacing (5); + vbox->setAlignment(Qt::AlignTop); + vbox->setSizeConstraint(QLayout::SetMinAndMaxSize); // 设置布局大小约束 + + vbox->addWidget(label); + vbox->addWidget(inputBox); + vbox->addSpacing(15); + vbox->addWidget(styleLabel); + vbox->addLayout(styleGrid); + vbox->addSpacing(15); + vbox->addWidget(resolutionLabel); + vbox->addWidget(resolutionComboBox); + vbox->addSpacing(15); + vbox->addWidget(quantityLabel); + vbox->addWidget(quantityComboBox); + vbox->addSpacing(15); + vbox->addWidget(buildButton); + vbox->addSpacing(15); + vbox->addWidget(resultWidget); + vbox->addWidget(stackedWidget); + + vbox->setContentsMargins(5,5,15,5); + // 隐藏resultGrid中的所有子控件 + for (int i = 0; i < resultGrid->count(); ++i) + { + QLayoutItem *item = resultGrid->itemAt(i); + if (item && item->widget()) + item->widget()->setVisible(false); + } + + connect(buildButton, &QPushButton::clicked, this, &aithemebar::onGenerateButtonClicked); + connect(inputBox,&QTextEdit::textChanged, this, &aithemebar::handleInputTextChanged); + connect(previousButton, &QPushButton::clicked, this, &aithemebar::showPreviousPage); + connect(nextButton, &QPushButton::clicked, this, &aithemebar::showNextPage); + connect(deleteButton, &QPushButton::clicked, this, &aithemebar::deleteCurrentPage); + connect(m_AiMode, &AIModeDataThread::finishedSignal, this, &aithemebar::onThreadFinished); + + centralWidget->setFixedWidth(240); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(centralWidget); + mainLayout->setContentsMargins(0, 0, 0, 0); + setLayout(mainLayout); +} + +/** + * @brief aithemebar::addStyleGrid + * 添加风格布局 + * @param widget + * @param line + */ +void aithemebar::addStyleGrid(QWidget *widget, int line) +{ + styleGrid->addWidget(widget, line / 3, line % 3); +} + +/** + * @brief aithemebar::addStyleWidget + * 添加风格窗口 + */ +void aithemebar::addStyleWidget() +{ + QString path = "/usr/share/kolourpaint/pics/style/%1"; + QStringList styleList = {"style-ancient", "style-anime", + "style-realistic","style-ukiyoe"}; + + QStringList styleMoreList ={ "style-futurism", "style-pixel", "style-conceptual", "style-cyberpunk", + "style-baroque", "style-surrealism", "style-watercolour", //头部删除"style-lolita" + "style-vaporwave", "style-oil-painting","style-cartoon"}; + + + + moreButton = new QPushButton(); + moreButton->setText(i18n("more")); + moreButton->setFixedSize(72, 40); + moreButton->setFont(QFont("Arial", 8)); + moreButton->setProperty("useButtonPalette", true); + + QWidget *widget_all = addAllStyleLabel(path.arg("style-all@2x.png"), "style-all", 0); + widget_low_poly = addStyleLabel(path.arg("style-low-poly@2x.png"), "style-low-poly", 5); + + styleGrid->addWidget(widget_all, 0, 0, Qt::AlignTop); + for (int i = 0; i < styleList.size(); ++i) + { + QString iconPath = path.arg(styleList[i]) + "@2x.png"; + QString labelText = styleList[i]; + QWidget *widget = addStyleLabel(iconPath, labelText, i+1); + addStyleGrid(widget, i+1); + } + styleGrid->addWidget(moreButton, 1, 2,Qt::AlignTop); + for (int i = 0; i < styleMoreList.size(); ++i) + { + QString iconPath = path.arg(styleMoreList[i]) + "@2x.png"; + QString labelText = styleMoreList[i]; + QWidget *widget = addStyleLabel(iconPath, labelText, i + 6); + addStyleGrid(widget, i + 6); + } + + for (int i = 6; i < styleGrid->count(); ++i) + { + styleGrid->itemAt(i)->widget()->setVisible(false); + } + + styleFlag = true; + + connect(moreButton,&QPushButton::clicked, this, &aithemebar::onStyleMoreButtonClick); + +} + +/** + * @brief aithemebar::onStyleMoreButtonClick + * 风格点击回调事件 + */ +void aithemebar::onStyleMoreButtonClick() +{ + if (styleFlag) { + for (int i = 0; i < styleGrid->count(); ++i) + { + styleGrid->itemAt(i)->widget()->setVisible(styleFlag); + } + + moreButton->setText(i18n("Pack up")); + + styleGrid->removeWidget(moreButton); + + addStyleGrid(widget_low_poly, 5); + styleGrid->addWidget(moreButton, 5, 1,Qt::AlignTop); + } else { + for (int i = 5; i < styleGrid->count()-1; ++i) + { + styleGrid->itemAt(i)->widget()->setVisible(styleFlag); + } + + moreButton->setText(i18n("more")); + + styleGrid->removeWidget(moreButton); + styleGrid->removeWidget(widget_low_poly); + + addStyleGrid(widget_low_poly, 16); + styleGrid->addWidget(moreButton, 1, 2, Qt::AlignTop); + } + + styleFlag = !styleFlag; +} + +/** + * @brief aithemebar::addAllStyleLabel + * 添加探索无限风格函数 + * @param iconPath + * @param labelText + * @param line + * @return + */ +QWidget *aithemebar::addAllStyleLabel(QString iconPath, QString labelText, int line) +{ + QWidget *widget = new QWidget(); + QVBoxLayout *styleVBox = new QVBoxLayout(widget); + + QLabel *iconLabel = new QLabel(this); + iconLabel->setObjectName("iconLabel"); + iconLabel->setFixedSize(72,42); + iconLabel->setPixmap(QPixmap(iconPath).scaled(112,64, Qt::KeepAspectRatio,Qt::SmoothTransformation)); + iconLabel->setScaledContents(true); + iconLabel->setAlignment(Qt::AlignCenter); + + QLabel *textLabel = new QLabel(i18n(labelText.toLocal8Bit().data()), this); + textLabel->setObjectName("textLabel"); + textLabel->setFixedSize(72,16); + textLabel->setFont(QFont("Arial", 8)); + textLabel->setAlignment(Qt::AlignCenter); + textLabel->setProperty("labelStyle", line); + + iconLabel->setStyleSheet("border: 2px solid #3790FA; border-radius: 5px;"); + textLabel->setStyleSheet("color: #3790FA;"); + selectedIconLabel = iconLabel; + selectedTextLabel = textLabel; + + styleVBox->setMargin (0); + styleVBox->setSpacing (2); + styleVBox->addWidget(iconLabel); + styleVBox->addWidget(textLabel); + + widget->setFixedSize(72,58); + + widget->installEventFilter(this); + + return widget; +} + +/** + * @brief aithemebar::addStyleLabel + * 添加风格布局函数 + * @param iconPath + * @param labelText + * @param line + * @return + */ +QWidget *aithemebar::addStyleLabel(QString iconPath, QString labelText, int line) +{ + QWidget *widget = new QWidget(); + QVBoxLayout *styleVBox = new QVBoxLayout(widget); + + QLabel *iconLabel = new QLabel(this); + iconLabel->setObjectName("iconLabel"); + iconLabel->setFixedSize(72,42); + iconLabel->setPixmap(QPixmap(iconPath).scaled(112,64, Qt::KeepAspectRatio,Qt::SmoothTransformation)); + iconLabel->setScaledContents(true); + iconLabel->setAlignment(Qt::AlignCenter); + + QLabel *textLabel = new QLabel(i18n(labelText.toLocal8Bit().data()), this); + textLabel->setObjectName("textLabel"); + textLabel->setFixedSize(72,16); + textLabel->setFont(QFont("Arial", 8)); + textLabel->setAlignment(Qt::AlignCenter); + textLabel->setProperty("labelStyle", line); + + styleVBox->setMargin (0); + styleVBox->setSpacing (2); + styleVBox->addWidget(iconLabel); + styleVBox->addWidget(textLabel); + widget->setFixedSize(72,58); + + widget->installEventFilter(this); + + return widget; +} + +/** + * @brief aithemebar::eventFilter + * 事件重载回调函数 + * @param obj + * @param event + * @return + */ +bool aithemebar::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::MouseButtonPress) + { + handleLabelClicked(obj); + return true; + } + return QObject::eventFilter(obj, event); +} + +/** + * @brief aithemebar::handleLabelClicked + * 新增的槽函数,处理风格部分的点击事件 + * @param clickedObject + */ +void aithemebar::handleLabelClicked(QObject *clickedObject) +{ + QWidget *clickedWidget = qobject_cast(clickedObject); + + if (!clickedWidget){ + qDebug()<<"clickedWidget is null"; + return; + } + + QLabel *iconLabel = clickedWidget->findChild("iconLabel"); + QLabel *textLabel = clickedWidget->findChild("textLabel"); + + if (!iconLabel || !textLabel){ + qDebug()<<"clickedLable is null"; + return; + } + + if(!selectedIconLabel || !selectedTextLabel){ + qDebug()<<"selectedIconLabel/selectedTextLabel is null"; + return; + } + + if (selectedIconLabel != iconLabel) { + selectedIconLabel->setStyleSheet(""); + selectedTextLabel->setStyleSheet(""); + selectedIconLabel = nullptr; + selectedTextLabel = nullptr; + } + iconLabel->setStyleSheet("border: 2px solid #3790FA; border-radius: 5px;"); + textLabel->setStyleSheet("color: #3790FA;"); + selectedIconLabel = iconLabel; + selectedTextLabel = textLabel; + int identifier = textLabel->property("labelStyle").toInt(); + if (identifier > 9){ + identifier += 1; + } + ImageStyle = (VisionImageStyle)identifier; +} + +QJsonArray aithemebar::readResolutionsFromJson(QString key) +{ + if (!mSession) + return QJsonArray(); + + QString jsonString = QString(vision_get_prompt2image_supported_params(mSession)); + + qDebug()<<"jsonString === "<addItem("512x512"); + return; + } + + for (const QJsonValue &value : resolutions) { + QString resolution = value.toString(); + resolutionComboBox->addItem(resolution); + } + + connect(resolutionComboBox, QOverload::of(&QComboBox::currentIndexChanged), + [=](int index) { + QString selectedResolution = resolutionComboBox->currentText(); + // 解析为QSize(这里假设分辨率总是"WxH"格式) + int widthPos = selectedResolution.indexOf('x'); + qDebug()<<"index = "<addItem("1张"); + } + else if (num == 6){ + quantityComboBox->addItem("1张"); + quantityComboBox->addItem("2张"); + quantityComboBox->addItem("6张"); + } + else if (num == 8){ + for (int i = 1; i <= num; i *= 2) { + quantityComboBox->addItem(QString("%1张").arg(i)); + } + } + else { + quantityComboBox->addItem("1张"); + qDebug()<<"读取生成数量不是常用数量, num = "<::of(&QComboBox::currentIndexChanged), + [=](int index) { + QString selectedResolution = quantityComboBox->currentText(); + QString numberString = selectedResolution.remove(QRegExp("[^\\d]")); + quantityNum = numberString.toInt(); + qDebug()<<"生成数量quantityNum = "<(findChild())->toPlainText(); + if(!resultText.isEmpty()) + textBox = resultText; + + qDebug() << "输入文字为:" << textBox; + + buildButton->setEnabled(false); + buildButton->setText(i18n("In formation...")); + buildButton->setStyleSheet(colorGrayButtonStyle); + buildButtonFlag = true; + if(!deleteButton->isEnabled()) + deleteButton->setEnabled(true); + + // 更新结果显示 + updateResultGrid(); + + // 更新图像 + updateImageGrid(); +} + +/** + * @brief aithemebar::handleInputTextChanged + * 文字输入回调函数 + */ +void aithemebar::handleInputTextChanged() +{ + //考虑添加生成中判断 + QString userText = static_cast(findChild())->toPlainText().trimmed(); + bool enableButton = !userText.isEmpty(); + if (enableButton && !buildButton->isEnabled() && !buildButtonFlag) { + qDebug()<<"buildButton set true"; + buildButton->setEnabled(enableButton); + buildButton->setStyleSheet(colorfulButtonStyle); + } + else if (!enableButton && buildButton->isEnabled()) { + buildButton->setEnabled(enableButton); + buildButton->setStyleSheet(colorGrayButtonStyle); + } +} + +/** + * @brief aithemebar::addPageAndStoreImages + * 添加AI生成后的图片及页 + */ +void aithemebar::addPageAndStoreImages() +{ + // Create a new page + QWidget *newPage = new QWidget(); + + // Get the current set of images + QVector currentImages = imagesVector.last(); + + QGridLayout *pageLayout = new QGridLayout(newPage); + pageLayout->setMargin (2); + pageLayout->setSpacing (5); + if(show_quantityNum == 1){ + pageLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft); + } + else { + pageLayout->setAlignment(Qt::AlignTop | Qt::AlignCenter); + } + + for (int i = 0; i < currentImages.size(); ++i) { + QPixmap pixmap = currentImages[i]; + setAiPixmap(pixmap, i, pageLayout); + } + stackedWidget->addWidget(newPage); + stackedWidget->setCurrentIndex(stackedWidget->count() - 1); + updatePageLabel(); +} + +/** + * @brief aithemebar::createPixmapWithText + * 生成图片报错处理 + * @param text + * @return + */ +QPixmap aithemebar::createPixmapWithText(const QString &text) +{ + QSize size; + size = getImageLabelSize(); + + QPixmap pixmap(size); + pixmap.fill(QColor("#E6E6E6")); + + QColor color("#B8B8B8"); + QPainter painter(&pixmap); + + // 设置字体和字体大小,这里假设使用默认字体,根据实际需求可自定义 + QFont font = painter.font(); + font.setPointSize(12); + // 若需要调整字体大小以适应换行,请在此处设置,例如:font.setPointSize(10); + + QRect textRect = pixmap.rect().adjusted(8, 8, -8, -8); + // 计算文本在给定宽度下的自动换行字符串 + QString wrappedText = fontMetrics().elidedText(i18n(text.toLocal8Bit().data()), Qt::ElideNone, textRect.width(), Qt::TextWordWrap); + + painter.setFont(font); + painter.setPen(color); + painter.drawText(textRect, Qt::AlignCenter | Qt::TextWordWrap, wrappedText); + painter.end(); + + qDebug()<<"Error message:"<setEnabled(true); + return; + } + if (imageIndex == 0){ + imagesVector.append(QVector()); + } + if (errorCode != 0) + map = AIGeneratesErrorHandling(errorCode); + else + map = pixmap; + + if (imagesVector.size() > 0 ){ + imagesVector.last().append(map); + } + qDebug()<<"onThreadFinished: imageIndex = "<setStyleSheet(colorfulButtonStyle);//设置立即生成按钮为立即生成 + buildButtonFlag = false; + addPageAndStoreImages(); + } +} + + +AIModeDataThread::AIModeDataThread() +{ + +} + +AIModeDataThread::~AIModeDataThread() +{ + vision_destroy_session(session); +} + +bool AIModeDataThread::setSessionStatus() +{ + if (m_sessionFlag) + return true; + + session = nullptr; + VisionResult ret = vision_create_session(&session); + if (ret != VISION_SUCCESS) { + qDebug()<<"创建失败VisionResult="<textBox; + if(imageData.index == 0) + emit AIMode->finishedSignal(false, map, imageData.index, imageData.total, imageData.error_code); + emit AIMode->finishedSignal(true, map, imageData.index, imageData.total, imageData.error_code); +} + +/** + * @brief AIModeDataThread::someFunctionInThread + * AI服务调用函数 + * @return + */ +bool AIModeDataThread::someFunctionInThread() +{ + int width = AIImageSize.width(); + int height = AIImageSize.height(); + + vision_set_prompt2image_number(session, quantityNum); + vision_set_prompt2image_size(session, width, height); + vision_set_prompt2image_callback(session, generateImageCallback, this); + vision_set_prompt2image_style(session, ImageStyle); + + VisionResult imageRet = vision_prompt2image_async(session, textBox.toLocal8Bit().data()); + + qDebug()<<"ImageStyle == "<(showAIImageSize.width()) / static_cast(108); + int height = showAIImageSize.height() / ratio; + + if (height != 0) + labelSize = QSize(108, height); + + qDebug()<<"getImageLabelSize labelSize = "<setPixmap(scalePix); + + imageLabel->setFixedSize(labelSize); + pageLayout->addWidget(imageLabel, imageIndex / imageColumn, imageIndex % imageColumn); + connect(imageLabel, &imageClickableLabel::labelClicked, this, &aithemebar::handleLabelClick); +} + +/** + * @brief aithemebar::deleteImageGridWidget + * 清空上一次生成的图像函数,主要是等待转圈参数 + */ +void aithemebar::deleteImageGridWidget() +{ + // 清空之前的图像 + if(stackedWidget->count() > 0 ){ + QWidget *w = stackedWidget->widget(stackedWidget->count() - 1); + stackedWidget->removeWidget(w); + w->deleteLater(); + } + updatePageLabel(); +} + +/** + * @brief aithemebar::updatePageLabel + * 更新换页页码函数 + */ +void aithemebar::updatePageLabel() +{ + currentPageIndx = stackedWidget->currentIndex(); + pageLabel->setText(QString("%1/%2").arg(currentPageIndx + 1).arg(stackedWidget->count())); +} + +/** + * @brief aithemebar::showPreviousPage + * 上一页回调函数 + */ +void aithemebar::showPreviousPage() +{ + if (stackedWidget->count() > 1 && currentPageIndx > 0) { + currentPageIndx--; + stackedWidget->setCurrentIndex(currentPageIndx); + updatePageLabel(); + } + else if (stackedWidget->count() > 1 && currentPageIndx == 0) { + currentPageIndx = stackedWidget->count() - 1; + stackedWidget->setCurrentIndex(currentPageIndx); + updatePageLabel(); + } + setEnabledDeleteButton(); + qDebug()<<"stackedWidget->count() = "<count()<<"currentPageIndx="<count() > 1 && currentPageIndx < stackedWidget->count() - 1) { + currentPageIndx++; + stackedWidget->setCurrentIndex(currentPageIndx); + updatePageLabel(); + } + else if (stackedWidget->count() > 1 && currentPageIndx == stackedWidget->count() - 1) { + currentPageIndx = 0; + stackedWidget->setCurrentIndex(currentPageIndx); + updatePageLabel(); + } + setEnabledDeleteButton(); + qDebug()<<"stackedWidget->count() = "<count()<<"currentPageIndx="<removeWidget(stackedWidget->currentWidget()); + updatePageLabel(); + if(stackedWidget->count() <= 1){ + updateResultGrid(); + if (currentPageIndx == -1) + deleteButton->setEnabled(false); + else + setEnabledDeleteButton(); + } + else { + setEnabledDeleteButton(); + } +} + +void aithemebar::setEnabledDeleteButton() +{ + qDebug()<<"currentPageIndx == "<count() - 1){ + deleteButton->setEnabled(false); + } + else { + deleteButton->setEnabled(true); + } +} +void aithemebar::updateResultGrid() +{ + qDebug()<<"updateResultGrid: stackedWidget->count() === "<count(); + // 显示resultGrid中的所有子控件 + for (int i = 0; i < resultGrid->count(); ++i) + { + QLayoutItem *item = resultGrid->itemAt(i);; + if (stackedWidget->count() < 1 && (i == 2 || i == 3 || i ==4)){ + if (item && item->widget()){ + item->widget()->setVisible(false); + } + continue; + } + if (item && item->widget()){ + item->widget()->setVisible(true); + } + } +} + +/** + * @brief aithemebar::updateImageGrid + * 更新、等待QLabel相关界面,并开启线程运行 + */ +void aithemebar::updateImageGrid() +{ + show_quantityNum = quantityNum; + showAIImageSize = AIImageSize; + + QSize labelSize = getImageLabelSize(); + + QWidget *newWidget = new QWidget(); + QGridLayout *pageLayout = new QGridLayout(newWidget); + + pageLayout->setMargin (2); + pageLayout->setSpacing (5); + if(show_quantityNum == 1){ + pageLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft); + } + else { + pageLayout->setAlignment(Qt::AlignTop | Qt::AlignCenter); + } + + for(int i = 0; i < quantityNum; i++){ + QLabel *label = new QLabel(); + movie = new QMovie(LOADING_IMAGE); + if (quantityNum == 1) + movie->setScaledSize(QSize(50,50)); + else + movie->setScaledSize(QSize(30,30)); + label->setMovie(movie); + movie->start(); + label->setStyleSheet("QLabel {" + "background-color: #E6E6E6;" + "border-radius: 5px;}"); + + label->setFixedSize(labelSize); + label->setAlignment(Qt::AlignCenter); + pageLayout->addWidget(label, i / imageColumn, i % imageColumn, Qt::AlignTop); + } + + stackedWidget->addWidget(newWidget); + stackedWidget->setCurrentIndex(stackedWidget->count() - 1); + + qDebug()<<"updateImageGrid : currentPageIndx = "<count(); + updatePageLabel(); + + deleteButtonFlag = false; + deleteButton->setEnabled(false); + + qDebug()< + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_AI_DRAWINGBAR_H +#define KP_AI_DRAWINGBAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOADING_IMAGE "/usr/share/kolourpaint/pics/loading.gif" +#define BG_IMAGE "/usr/share/kolourpaint/pics/bg@2x.png" +#define SLOGO_IMAGE "/usr/share/kolourpaint/pics/slogo-Drawing.svg" +#define DRAWING_IMAGE "/usr/share/kolourpaint/pics/AI-Drawing@2x.png" +#define KYLIN_AI_DBUS "com.kylin.aiassistant" +#define KYLIN_AI_PATH "/com/kylin/aiassistant" +#define AI_GSETTINGS "org.kylin.aiassistant.settings" +#define AI_KEY "isVisionSetup" + + +/** + * @brief The AIModeDataThread class + * 线程类,用于跑AI的服务 + */ +class AIModeDataThread : public QObject +{ + Q_OBJECT + +public: + AIModeDataThread(); + ~AIModeDataThread(); + + bool setSessionStatus(); + VisionSession getVisionSession(){ + return session; + } + bool someFunctionInThread(); + + void setAIData (QString str, QSize size, int quantity, VisionImageStyle Style){ + textBox = str; + AIImageSize = size; + quantityNum = quantity; + ImageStyle = Style; + } + +signals: + void finishedSignal(bool flag, QPixmap pixmap, int imageIndex, int imageSum, int errorCode); + +private: + void sendErrorSignal(int ret){ + emit finishedSignal(false, QPixmap(), 0, 1, ret); + for(int i = 0; i < quantityNum; i++) + emit finishedSignal(true, QPixmap(), i, quantityNum, ret); + } + static void generateImageCallback(VisionImageData imageData, void* userData); + +private: + QPixmap pixmap; + int quantityNum = 1; //数量按钮 + QSize AIImageSize; + QString textBox; + VisionImageStyle ImageStyle; + bool m_sessionFlag = false; + VisionSession session; +}; + +/** + * @brief The imageClickableLabel class + * QLabel点击事件类,用于对图片做处理传输 + */ +class imageClickableLabel : public QLabel +{ + Q_OBJECT + +signals: + void labelClicked(const QPixmap &pixmap); + +public: + imageClickableLabel(const QPixmap &pixmap, QWidget *parent = nullptr) : QLabel(parent), pixmap(pixmap){} + +protected: + void mousePressEvent(QMouseEvent *event) override + { + Q_UNUSED(event); + emit labelClicked(pixmap); + } + +private: + QPixmap pixmap; +}; + + +class aithemebar : public QWidget +{ + Q_OBJECT + +signals: + void imageClicked(const QPixmap &pixmap); + +public: + aithemebar(QWidget *parent); + ~aithemebar(); + +public: + void initUI(); + bool getConfigStatus(); + void getconfigVersionData(); + void loginConfigurationPage(); + void setAiPixmap(QPixmap pixmap,int imageIndex, QGridLayout *pageLayout); + void updatePageLabel(); + + QSize getImageLabelSize(); + + bool eventFilter(QObject *watched, QEvent *event); + void handleLabelClicked(QObject *clickedObject); + + QPixmap createPixmapWithText(const QString &text); + QPixmap AIGeneratesErrorHandling(int errorCode); + +private slots: + void onConfigButtonClicked(); //配置按钮回调函数 + void onConfigSettingsChange(const QString &key); //AI配置成功后回调 + void onGenerateButtonClicked(); //生成按钮回调函数 + void handleInputTextChanged(); //文字变化回调函数 + + void showPreviousPage(); //显示上一页 + void showNextPage(); //显示下一页 + void deleteCurrentPage(); + void setEnabledDeleteButton(); + void handleLabelClick(const QPixmap &pixmap); + + void addPageAndStoreImages(); + void onStyleMoreButtonClick(); + + void startThread() { + if (m_AiMode->setSessionStatus()){ + m_AiMode->setAIData(textBox, AIImageSize, quantityNum, ImageStyle); + m_AiMode->someFunctionInThread(); + } + } + void onThreadFinished(bool flag, QPixmap pixmap, int imageIndex, int imageSum, int errorCode); + +private: + void updateImageGrid(); + void updateResultGrid(); + void deleteImageGridWidget(); + + void addResolutionComboBox(); + void addQuantityComboBox(); + + QJsonArray readResolutionsFromJson(QString key); + int readNumFromJson(QString key); + QWidget *addAllStyleLabel(QString iconPath, QString labelText, int line); + QWidget *addStyleLabel(QString iconPath, QString labelText, int line); + + void addStyleWidget(); + void addStyleGrid(QWidget *widget, int line); + +private: + int imageColumn = 2;//显示列表列数 + int quantityNum = 1; //数量按钮 + int show_quantityNum = 1; //数量按钮 + int currentPageIndx = -1;//切换页第几页 + + bool styleFlag; //风格标志位,用于判断按下哪一个风格 + bool deleteButtonFlag = true; + bool buildButtonFlag; + + QGSettings *AiSettings; //监听配置信息 + QSize AIImageSize; //图片大小 + QSize showAIImageSize; + QMovie *movie = nullptr;//生成等待图标 + QLabel *resultLabel; //生成结果 label + QLabel *pageLabel; //第几页面label + + QLabel *selectedIconLabel;//风格图片选择Label + QLabel *selectedTextLabel;//风格文字选择Label + + QWidget *configWidget; //立即配置页面 + QWidget *widget_low_poly; //多边形风格 + + QString textBox; //图像描述文字 + QString colorfulButtonStyle; //立即生成按钮渐变色 + QString colorGrayButtonStyle;//立即生成按钮置灰 + + QBoxLayout *vbox; //页面布局 + QHBoxLayout *resultGrid; //生成结果布局 + QGridLayout *styleGrid; //风格布局 + QPushButton *moreButton; //更多按钮 + + QScrollArea *scrollArea; //滚动窗口 + QPushButton *buildButton; //立即生成按钮 + QPushButton *deleteButton; //删除按钮 + + QComboBox *resolutionComboBox; //图像分辨率 + QComboBox *quantityComboBox; //生成数量 + + QStackedWidget *stackedWidget; //生成结果的换页窗口 + QVector> imagesVector; //生成图像数据集成 + + VisionSession mSession = nullptr; + VisionImageStyle ImageStyle; //风格样式 + AIModeDataThread *m_AiMode; //AI生成程序 + +}; +#endif diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c1854aa..ddca990 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -153,8 +153,8 @@ void MainWindow::initUI() // this->setPalette(palette); this->setBackgroundRole(QPalette::Base); this->setAutoFillBackground(true); - - this->setMinimumSize(1280, 720); + // this->setMinimumSize(1280, 720); + this->setMinimumSize(1600, 900); m_maininterface = new MainInterface(); m_entrywidget = new QWidget(); diff --git a/src/module/grubthemewidget.cpp b/src/module/grubthemewidget.cpp index 4102720..0d93fe8 100644 --- a/src/module/grubthemewidget.cpp +++ b/src/module/grubthemewidget.cpp @@ -20,6 +20,8 @@ #include "grubthemewidget.h" #include "../fileProcess/filecheck.h" #include +#include "../aithemebar.h" +#include bool GrubThemeWidget::g_themeChange; /** @@ -33,20 +35,34 @@ GrubThemeWidget::GrubThemeWidget(QWidget *parent) : QWidget(parent) { initPreviewWidget(); initRightWidget(); - QHBoxLayout *grubthemelayout = new QHBoxLayout(); - QPushButton *line = new QPushButton(); - line->setDisabled(true); - line->setFixedWidth(1); - line->setFixedHeight(2000); - grubthemelayout->addWidget(m_previewwidget); - grubthemelayout->addWidget(line); - grubthemelayout->addWidget(m_rightwidget); + m_grubthemelayout = new QHBoxLayout(); + // grubthemelayout->setSizeConstraint(QLayout::SetMinimumSize); + + QPushButton *line1 = new QPushButton(); + line1->setDisabled(true); + line1->setFixedWidth(1); + line1->setFixedHeight(2000); - grubthemelayout->setContentsMargins(0,0,0,0); - grubthemelayout->setSpacing(0); + QPushButton *line2 = new QPushButton(); + line2->setDisabled(true); + line2->setFixedWidth(1); + line2->setFixedHeight(2000); - this->setLayout(grubthemelayout); + // 主布局添加控件 + // m_grubthemelayout->addStretch(1); + m_grubthemelayout->addWidget(m_previewwidget); + m_grubthemelayout->addWidget(line1); // 分割线 + m_grubthemelayout->addWidget(m_rightwidget); + m_grubthemelayout->addWidget(line2); // 分割线 + initAithemeBar(); + // m_grubthemelayout->addWidget(m_aithemebar); + // m_grubthemelayout->addStretch(1); + + m_grubthemelayout->setContentsMargins(0,0,0,0); + m_grubthemelayout->setSpacing(0); + + this->setLayout(m_grubthemelayout); } /** @@ -73,6 +89,34 @@ void GrubThemeWidget::initPreviewWidget() m_previewwidget->setLayout(m_previewlayout); } +/** + * @brief 初始化Ai生图小部件 + * 创建一个新的 QWidget,设置固定高度,并添加到grub布局。 + * 连接 label 的 clicked 信号,当点击按钮时,传递图片到预览窗口。 + */ +void GrubThemeWidget::initAithemeBar() +{ + // 创建 aithemebar 实例 + m_aithemebar = new aithemebar(this); + m_aithemebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + + // 设置最小和最大宽度 + m_aithemebar->setMinimumSize(250, 620); + m_aithemebar->setMaximumWidth(250); + m_aithemebar->setBackgroundRole(QPalette::Base); + m_aithemebar->setAutoFillBackground(true); + + // 设置 aithemebar 的固定宽度 + m_aithemebar->setFixedWidth(250); + + // 在布局中为 aithemebar 分配足够的空间 + QSpacerItem *spacer = new QSpacerItem(15, 0, QSizePolicy::Fixed, QSizePolicy::Minimum); + m_grubthemelayout->addItem(spacer); + m_grubthemelayout->addWidget(m_aithemebar); +} + + /** * @brief 初始化右侧小部件 * @@ -134,7 +178,7 @@ void GrubThemeWidget::initEditWidget() grubAddPicWidget *a = new grubAddPicWidget(); QHBoxLayout *importlayout = new QHBoxLayout(); - importlayout->addStretch(1); + importlayout->addStretch(1); importlayout->addWidget(m_showBtn); importlayout->addStretch(1); importlayout->addWidget(a); @@ -229,6 +273,14 @@ void GrubThemeWidget::refresh() m_showBtn->setIconSize(QSize(178,122)); } +void GrubThemeWidget::updateAIImage() +{ + m_preview->updateBackground(resourceGrubPath); + QPixmap pixmap(resourceGrubPath); + m_showBtn->setIcon(QIcon(pixmap)); + m_showBtn->setIconSize(QSize(178,122)); +} + void GrubThemeWidget::useMaximumScale() { m_preview->maxscale(); @@ -250,15 +302,5 @@ void GrubThemeWidget::setBuildBtnText(bool isglobal) void GrubThemeWidget::addspaceritem() { - QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding); - QSpacerItem *spacer2 = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding); - spacer->changeSize(m_previewwidget->width(), 155, QSizePolicy::Maximum, QSizePolicy::Maximum); - spacer2->changeSize(m_previewwidget->width(), 159, QSizePolicy::Maximum, QSizePolicy::Maximum); - -// m_previewlayout->addItem(spacer); m_previewlayout->addWidget(m_preview); -// m_previewlayout->addItem(spacer2); } - - - diff --git a/src/module/grubthemewidget.h b/src/module/grubthemewidget.h index a5665ca..704ce43 100644 --- a/src/module/grubthemewidget.h +++ b/src/module/grubthemewidget.h @@ -23,6 +23,7 @@ #include "grubthemefeature.h" #include "historywidget.h" #include "basewidget.h" +#include "../aithemebar.h" #include #include @@ -39,12 +40,14 @@ public: explicit GrubThemeWidget(QWidget *parent = nullptr); void initPreviewWidget(); void initRightWidget(); + void initAithemeBar(); void addspaceritem(); - void initEditWidget(); + void initEditWidget(); void initBuildWidget(); static bool g_themeChange; void eidtInitWidget(const HistoryInfo &InfoData); void refresh(); + void updateAIImage(); void useMaximumScale(); void useRestoreScale(); void setBuildBtnText(bool isglobal); @@ -56,8 +59,10 @@ private: BasePreviewWidget *m_previewwidget; GrubImageWidget *m_preview; QWidget *m_rightwidget; + QHBoxLayout *m_grubthemelayout; QWidget *m_grubwidget; QWidget *m_buildwidget; + aithemebar *m_aithemebar; QVBoxLayout *m_previewlayout; GrubEditButton *m_showBtn; QPushButton *m_buildButton;