Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:mrbadguy:gimp-unstable
gmic2
krita5.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File krita5.patch of Package gmic2
From c4b6796080d5c0f76b64fee06a38d285ab462a75 Mon Sep 17 00:00:00 2001 From: Christophe Marin <christophe@krop.fr> Date: Fri, 28 Jun 2024 09:46:58 +0200 Subject: [PATCH] Krita 5 plugin support Origin: https://github.com/amyspark/gmic Rebased for gmic 3.4.0 --- gmic-qt/CMakeLists.txt | 68 ++++- gmic-qt/gmic_krita_qt.desktop | 9 + gmic-qt/src/DialogSettings.cpp | 33 ++- .../src/FilterParameters/BoolParameter.cpp | 2 + .../src/FilterParameters/FloatParameter.cpp | 3 +- gmic-qt/src/FilterParameters/IntParameter.cpp | 2 + .../src/FilterParameters/NoteParameter.cpp | 2 + .../FilterParameters/SeparatorParameter.cpp | 2 + .../src/FilterSelector/FiltersPresenter.cpp | 2 +- gmic-qt/src/Globals.h | 19 ++ gmic-qt/src/GmicProcessor.cpp | 5 + gmic-qt/src/GmicProcessor.h | 1 + gmic-qt/src/GmicQt.cpp | 6 +- gmic-qt/src/HeadlessProcessor.cpp | 5 +- .../src/Host/KritaPlugin/gmicqttoolplugin.cpp | 233 ++++++++++++++++++ .../src/Host/KritaPlugin/gmicqttoolplugin.h | 55 +++++ .../Host/KritaPlugin/gmicqttoolplugin.json | 9 + gmic-qt/src/Host/KritaPlugin/host.cpp | 195 +++++++++++++++ gmic-qt/src/Host/None/JpegQualityDialog.cpp | 6 +- gmic-qt/src/LanguageSettings.cpp | 9 +- gmic-qt/src/MainWindow.cpp | 52 +++- gmic-qt/src/MainWindow.h | 2 + gmic-qt/src/Settings.cpp | 10 +- gmic-qt/src/Tags.cpp | 6 +- gmic-qt/src/Widgets/InOutPanel.cpp | 2 + gmic-qt/src/Widgets/InOutPanel.h | 2 + gmic-qt/src/Widgets/ProgressInfoWindow.cpp | 4 + gmic-qt/src/Widgets/ProgressInfoWindow.h | 2 + gmic-qt/ui/dialogsettings.ui | 2 +- 29 files changed, 716 insertions(+), 32 deletions(-) create mode 100644 gmic-qt/gmic_krita_qt.desktop create mode 100644 gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.cpp create mode 100644 gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.h create mode 100644 gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.json create mode 100644 gmic-qt/src/Host/KritaPlugin/host.cpp diff --git a/gmic-qt/CMakeLists.txt b/gmic-qt/CMakeLists.txt index 47face8..0641f4c 100644 --- a/gmic-qt/CMakeLists.txt +++ b/gmic-qt/CMakeLists.txt @@ -30,7 +30,7 @@ endif() message("Build type is " ${CMAKE_BUILD_TYPE}) -set (GMIC_QT_HOST "gimp" CACHE STRING "Define for which host gmic-qt will be built: gimp, gimp3 (experimental), none, paintdotnet or 8bf.") +set (GMIC_QT_HOST "gimp" CACHE STRING "Define for which host gmic-qt will be built: gimp, gimp3 (experimental), krita-plugin, none, paintdotnet or 8bf.") if (${GMIC_QT_HOST} STREQUAL "none") message("Building standalone version.") else() @@ -701,6 +701,70 @@ if (${GMIC_QT_HOST} STREQUAL "gimp" OR ${GMIC_QT_HOST} STREQUAL "gimp3") ) install(TARGETS gmic_gimp_qt RUNTIME DESTINATION "${GIMP_PKGLIBDIR}/plug-ins/gmic_gimp_qt") +elseif (${GMIC_QT_HOST} STREQUAL "krita-plugin") + set(MIN_FRAMEWORKS_VERSION 5.44.0) + + find_package(ECM 5.22 REQUIRED NOMODULE) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) + + include(KDEInstallDirs) + include(KDECMakeSettings) + + if (ANDROID) + set (KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}) + else() + set (KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}/kritaplugins) + endif() + + find_package(KF5 ${MIN_FRAMEWORKS_VERSION} REQUIRED COMPONENTS + CoreAddons + ) + + message(STATUS "Looking for Krita QMic libraries in: ${CMAKE_PREFIX_PATH}") + + find_library(KIS_IMAGE_INTERFACE_LIBRARY + NAMES kritaqmicinterface + REQUIRED) + + find_path(KIS_IMAGE_INTERFACE_DIR + NAMES kis_qmic_plugin_interface.h + REQUIRED) + + set_package_properties(kritaqmicinterface PROPERTIES + URL "http://www.krita.org" + DESCRIPTION "Krita GMic core library" + ) + + set (gmic_qt_SRCS ${gmic_qt_SRCS} src/Host/KritaPlugin/host.cpp src/Host/KritaPlugin/gmicqttoolplugin.cpp) + set (gmic_qt_SRCS ${gmic_qt_SRCS} ) + qt5_wrap_ui(gmic_qt_SRCS ${gmic_qt_FORMS}) + add_definitions(-DGMIC_HOST=krita-plugin) + add_definitions(-D_GMIC_QT_DISABLE_THEMING_) + add_definitions(-D_GMIC_QT_CONSENT_TO_UPDATE_FIRST_) + add_definitions(-D_GMIC_QT_DISABLE_TRANSLATION_) + add_definitions(-D_GMIC_USE_HOSTED_SETTINGS_) + add_library(krita_gmic_qt MODULE ${gmic_qt_SRCS} ${gmic_qt_QRC} ${qmic_qt_QM}) + target_include_directories( + krita_gmic_qt + PUBLIC + ${KIS_IMAGE_INTERFACE_DIR} + ) + target_link_libraries( + krita_gmic_qt + PRIVATE + ${gmic_qt_LIBRARIES} + ${KIS_IMAGE_INTERFACE_LIBRARY} + KF5::CoreAddons + ) + if (ANDROID) + target_link_libraries( + krita_gmic_qt + PRIVATE + log + ) + endif() + install(TARGETS krita_gmic_qt DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) # plugin + elseif (${GMIC_QT_HOST} STREQUAL "none") set (gmic_qt_SRCS ${gmic_qt_SRCS} @@ -783,7 +847,7 @@ elseif (${GMIC_QT_HOST} STREQUAL "8bf") else() - message(FATAL_ERROR "GMIC_QT_HOST is not defined as gimp, gimp3, none, paintdotnet or 8bf") + message(FATAL_ERROR "GMIC_QT_HOST is not defined as gimp, gimp3, krita-plugin, none, paintdotnet or 8bf") endif() diff --git a/gmic-qt/gmic_krita_qt.desktop b/gmic-qt/gmic_krita_qt.desktop new file mode 100644 index 0000000..579d427 --- /dev/null +++ b/gmic-qt/gmic_krita_qt.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=gmic_krita_qt +Exec=gmic_krita_qt +GenericName=G'Mic plugin for Krita +Comment=G'Mic plugin for Krita +Type=Application +Icon=gmic_krita_qt +Categories=Qt;KDE;Graphics; +StartupNotify=false diff --git a/gmic-qt/src/DialogSettings.cpp b/gmic-qt/src/DialogSettings.cpp index 6c1e6b9..29328c4 100644 --- a/gmic-qt/src/DialogSettings.cpp +++ b/gmic-qt/src/DialogSettings.cpp @@ -56,11 +56,7 @@ DialogSettings::DialogSettings(QWidget * parent) : QDialog(parent), ui(new Ui::D #ifdef _GMIC_QT_DEBUG_ ui->cbUpdatePeriodicity->addItem(tr("At launch (debug)"), QVariant(0)); #endif - for (int i = 0; i < ui->cbUpdatePeriodicity->count(); ++i) { - if (Settings::updatePeriodicity() == ui->cbUpdatePeriodicity->itemData(i).toInt()) { - ui->cbUpdatePeriodicity->setCurrentIndex(i); - } - } + ui->cbUpdatePeriodicity->setCurrentIndex(ui->cbUpdatePeriodicity->findData(Settings::updatePeriodicity())); ui->outputMessages->setToolTip(tr("Output messages")); ui->outputMessages->addItem(tr("Quiet (default)"), (int)OutputMessageMode::Quiet); @@ -81,9 +77,12 @@ DialogSettings::DialogSettings(QWidget * parent) : QDialog(parent), ui(new Ui::D ui->rbLeftPreview->setChecked(Settings::previewPosition() == MainWindow::PreviewPosition::Left); ui->rbRightPreview->setChecked(Settings::previewPosition() == MainWindow::PreviewPosition::Right); - const bool savedDarkTheme = QSettings().value(DARK_THEME_KEY, GmicQtHost::DarkThemeIsDefault).toBool(); + const bool savedDarkTheme = GMIC_SETTINGS_INLINE.value(DARK_THEME_KEY, GmicQtHost::DarkThemeIsDefault).toBool(); ui->rbDarkTheme->setChecked(savedDarkTheme); ui->rbDefaultTheme->setChecked(!savedDarkTheme); +#ifdef _GMIC_QT_DISABLE_THEMING_ + ui->groupBoxTheme->setEnabled(false); +#endif ui->cbNativeColorDialogs->setChecked(Settings::nativeColorDialogs()); ui->cbNativeColorDialogs->setToolTip(tr("Check to use Native/OS color dialog, uncheck to use Qt's")); ui->cbNativeFileDialogs->setChecked(Settings::nativeFileDialogs()); @@ -95,19 +94,33 @@ DialogSettings::DialogSettings(QWidget * parent) : QDialog(parent), ui(new Ui::D connect(ui->pbOk, &QPushButton::clicked, this, &DialogSettings::onOk); connect(ui->rbLeftPreview, &QRadioButton::toggled, this, &DialogSettings::onRadioLeftPreviewToggled); +#ifdef _GMIC_QT_DISABLE_UPDATES_ + ui->pbUpdate->setEnabled(false); +#else connect(ui->pbUpdate, &QPushButton::clicked, this, &DialogSettings::onUpdateClicked); +#endif +#ifdef _GMIC_QT_DISABLE_UPDATES_ + ui->cbUpdatePeriodicity->setEnabled(false); +#else connect(ui->cbUpdatePeriodicity, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DialogSettings::onUpdatePeriodicityChanged); +#endif connect(ui->labelPreviewLeft, &ClickableLabel::clicked, ui->rbLeftPreview, &QRadioButton::click); connect(ui->labelPreviewRight, &ClickableLabel::clicked, ui->rbRightPreview, &QRadioButton::click); connect(ui->cbNativeColorDialogs, &QCheckBox::toggled, this, &DialogSettings::onColorDialogsToggled); connect(ui->cbNativeFileDialogs, &QCheckBox::toggled, this, &DialogSettings::onFileDialogsToggled); connect(Updater::getInstance(), &Updater::updateIsDone, this, &DialogSettings::enableUpdateButton); +#ifndef _GMIC_QT_DISABLE_THEMING_ connect(ui->rbDarkTheme, &QRadioButton::toggled, this, &DialogSettings::onDarkThemeToggled); +#endif connect(ui->cbShowLogos, &QCheckBox::toggled, this, &DialogSettings::onVisibleLogosToggled); connect(ui->cbPreviewZoom, &QCheckBox::toggled, this, &DialogSettings::onPreviewZoomToggled); connect(ui->sbPreviewTimeout, QOverload<int>::of(&QSpinBox::valueChanged), this, &DialogSettings::onPreviewTimeoutChange); connect(ui->outputMessages, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DialogSettings::onOutputMessageModeChanged); +#ifdef _GMIC_QT_DISABLE_UPDATES_ + ui->cbNotifyFailedUpdate->setEnabled(false); +#else connect(ui->cbNotifyFailedUpdate, &QCheckBox::toggled, this, &DialogSettings::onNotifyStartupUpdateFailedToggle); +#endif #if QT_VERSION_GTE(6, 0, 0) ui->cbHighDPI->hide(); @@ -117,9 +130,14 @@ DialogSettings::DialogSettings(QWidget * parent) : QDialog(parent), ui(new Ui::D connect(ui->cbHighDPI, &QCheckBox::toggled, this, &DialogSettings::onHighDPIToggled); #endif +#ifdef _GMIC_QT_DISABLE_TRANSLATION_ + ui->languageSelector->setEnabled(false); +#else ui->languageSelector->selectLanguage(Settings::languageCode()); ui->languageSelector->enableFilterTranslation(Settings::filterTranslationEnabled()); +#endif +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { QPalette p = ui->cbNativeColorDialogs->palette(); p.setColor(QPalette::Text, Settings::CheckBoxTextColor); @@ -136,6 +154,7 @@ DialogSettings::DialogSettings(QWidget * parent) : QDialog(parent), ui(new Ui::D ui->cbNotifyFailedUpdate->setPalette(p); ui->cbHighDPI->setPalette(p); } +#endif ui->pbOk->setFocus(); ui->tabWidget->setCurrentIndex(0); } @@ -157,7 +176,7 @@ void DialogSettings::onOk() void DialogSettings::done(int r) { - QSettings settings; + GMIC_SETTINGS(settings); ui->sources->saveSettings(); Settings::save(settings); QDialog::done(r); diff --git a/gmic-qt/src/FilterParameters/BoolParameter.cpp b/gmic-qt/src/FilterParameters/BoolParameter.cpp index ffa324e..a9dfb04 100644 --- a/gmic-qt/src/FilterParameters/BoolParameter.cpp +++ b/gmic-qt/src/FilterParameters/BoolParameter.cpp @@ -64,12 +64,14 @@ bool BoolParameter::addTo(QWidget * widget, int row) _checkBox = new QCheckBox(widget); _checkBox->setChecked(_value); _label = new QLabel(_name, widget); +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { QPalette p = _checkBox->palette(); p.setColor(QPalette::Text, Settings::CheckBoxTextColor); p.setColor(QPalette::Base, Settings::CheckBoxBaseColor); _checkBox->setPalette(p); } +#endif _grid->addWidget(_label, row, 0, 1, 1); _grid->addWidget(_checkBox, row, 1, 1, 2); connectCheckBox(); diff --git a/gmic-qt/src/FilterParameters/FloatParameter.cpp b/gmic-qt/src/FilterParameters/FloatParameter.cpp index fb271f0..c8aa32b 100644 --- a/gmic-qt/src/FilterParameters/FloatParameter.cpp +++ b/gmic-qt/src/FilterParameters/FloatParameter.cpp @@ -73,13 +73,14 @@ bool FloatParameter::addTo(QWidget * widget, int row) _slider->setMinimumWidth(SLIDER_MIN_WIDTH); _slider->setRange(0, SLIDER_MAX_RANGE); _slider->setValue(static_cast<int>(SLIDER_MAX_RANGE * (_value - _min) / (_max - _min))); +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { QPalette p = _slider->palette(); p.setColor(QPalette::Button, QColor(100, 100, 100)); p.setColor(QPalette::Highlight, QColor(130, 130, 130)); _slider->setPalette(p); } - +#endif _spinBox = new CustomDoubleSpinBox(widget, _min, _max); _spinBox->setSingleStep(double(_max - _min) / 100.0); _spinBox->setValue((double)_value); diff --git a/gmic-qt/src/FilterParameters/IntParameter.cpp b/gmic-qt/src/FilterParameters/IntParameter.cpp index 2af87cb..bc0f77c 100644 --- a/gmic-qt/src/FilterParameters/IntParameter.cpp +++ b/gmic-qt/src/FilterParameters/IntParameter.cpp @@ -81,12 +81,14 @@ bool IntParameter::addTo(QWidget * widget, int row) _spinBox = new CustomSpinBox(widget, _min, _max); _spinBox->setValue(_value); +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { QPalette p = _slider->palette(); p.setColor(QPalette::Button, QColor(100, 100, 100)); p.setColor(QPalette::Highlight, QColor(130, 130, 130)); _slider->setPalette(p); } +#endif _grid->addWidget(_label = new QLabel(_name, widget), row, 0, 1, 1); setTextSelectable(_label); _grid->addWidget(_slider, row, 1, 1, 1); diff --git a/gmic-qt/src/FilterParameters/NoteParameter.cpp b/gmic-qt/src/FilterParameters/NoteParameter.cpp index e576b0f..be469de 100644 --- a/gmic-qt/src/FilterParameters/NoteParameter.cpp +++ b/gmic-qt/src/FilterParameters/NoteParameter.cpp @@ -88,12 +88,14 @@ bool NoteParameter::initFromText(const QString & /* filterName */, const char * _text.remove(QRegularExpression("^\"")).remove(QRegularExpression("\"$")).replace(QString("\\\""), "\""); _text.replace(QString("\\n"), "<br/>"); +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { _text.replace(QRegularExpression("color\\s*=\\s*\"purple\""), QString("color=\"#ff00ff\"")); _text.replace(QRegularExpression("foreground\\s*=\\s*\"purple\""), QString("foreground=\"#ff00ff\"")); _text.replace(QRegularExpression("color\\s*=\\s*\"blue\""), QString("color=\"#9b9bff\"")); _text.replace(QRegularExpression("foreground\\s*=\\s*\"blue\""), QString("foreground=\"#9b9bff\"")); } +#endif _text.replace(QRegularExpression("color\\s*=\\s*\""), QString("style=\"color:")); _text.replace(QRegularExpression("foreground\\s*=\\s*\""), QString("style=\"color:")); diff --git a/gmic-qt/src/FilterParameters/SeparatorParameter.cpp b/gmic-qt/src/FilterParameters/SeparatorParameter.cpp index fad7b0a..7f6d317 100644 --- a/gmic-qt/src/FilterParameters/SeparatorParameter.cpp +++ b/gmic-qt/src/FilterParameters/SeparatorParameter.cpp @@ -58,9 +58,11 @@ bool SeparatorParameter::addTo(QWidget * widget, int row) _frame->setSizePolicy(sizePolicy); _frame->setFrameShape(QFrame::HLine); _frame->setFrameShadow(QFrame::Sunken); +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { _frame->setStyleSheet("QFrame{ border-top: 0px none #a0a0a0; border-bottom: 2px solid rgb(160,160,160);}"); } +#endif _grid->addWidget(_frame, row, 0, 1, 3); return true; } diff --git a/gmic-qt/src/FilterSelector/FiltersPresenter.cpp b/gmic-qt/src/FilterSelector/FiltersPresenter.cpp index 3d2991c..3df386d 100644 --- a/gmic-qt/src/FilterSelector/FiltersPresenter.cpp +++ b/gmic-qt/src/FilterSelector/FiltersPresenter.cpp @@ -431,7 +431,7 @@ void FiltersPresenter::expandFaveFolder() void FiltersPresenter::expandPreviousSessionExpandedFolders() { if (_filtersView) { - QList<QString> expandedFolderPaths = QSettings().value("Config/ExpandedFolders", QStringList()).toStringList(); + QList<QString> expandedFolderPaths = GMIC_SETTINGS_INLINE.value("Config/ExpandedFolders", QStringList()).toStringList(); _filtersView->expandFolders(expandedFolderPaths); } } diff --git a/gmic-qt/src/Globals.h b/gmic-qt/src/Globals.h index b19a38d..9ab3e3b 100644 --- a/gmic-qt/src/Globals.h +++ b/gmic-qt/src/Globals.h @@ -59,7 +59,13 @@ const char WarningPrefix = '!'; #define ONE_WEEK_HOURS (7 * 24) #define TWO_WEEKS_HOURS (14 * 24) #define ONE_MONTH_HOURS (30 * 24) +#ifdef _GMIC_QT_CONSENT_TO_UPDATE_FIRST_ +#define INTERNET_DEFAULT_PERIODICITY INTERNET_NEVER_UPDATE_PERIODICITY +#define INTERNET_DEFAULT_REFRESH_UPDATE 0 +#else #define INTERNET_DEFAULT_PERIODICITY ONE_MONTH_HOURS +#define INTERNET_DEFAULT_REFRESH_UPDATE 1 +#endif #define PREVIEW_MAX_ZOOM_FACTOR 40.0 @@ -68,4 +74,17 @@ const char WarningPrefix = '!'; #define KEYPOINTS_INTERACTIVE_MIDDLE_DELAY_MS ((KEYPOINTS_INTERACTIVE_LOWER_DELAY_MS + KEYPOINTS_INTERACTIVE_UPPER_DELAY_MS) / 2) #define KEYPOINTS_INTERACTIVE_AVERAGING_COUNT 6 +#ifdef _GMIC_USE_HOSTED_SETTINGS_ +#ifdef Q_OS_MACOS +#define GMIC_SETTINGS(x) QSettings x(GMIC_QT_ORGANISATION_DOMAIN, GMIC_QT_APPLICATION_NAME) +#define GMIC_SETTINGS_INLINE QSettings(GMIC_QT_ORGANISATION_DOMAIN, GMIC_QT_APPLICATION_NAME) +#else +#define GMIC_SETTINGS(x) QSettings x(GMIC_QT_ORGANISATION_NAME, GMIC_QT_APPLICATION_NAME) +#define GMIC_SETTINGS_INLINE QSettings(GMIC_QT_ORGANISATION_NAME, GMIC_QT_APPLICATION_NAME) +#endif +#else +#define GMIC_SETTINGS(x) QSettings x +#define GMIC_SETTINGS_INLINE QSettings() +#endif + #endif // GMIC_QT_GLOBALS_H diff --git a/gmic-qt/src/GmicProcessor.cpp b/gmic-qt/src/GmicProcessor.cpp index 80c93c1..0019a1f 100644 --- a/gmic-qt/src/GmicProcessor.cpp +++ b/gmic-qt/src/GmicProcessor.cpp @@ -209,6 +209,11 @@ bool GmicProcessor::isIdle() const return !_filterThread; } +bool GmicProcessor::isInputImagesEmpty() const +{ + return _gmicImages->is_empty(); +} + int GmicProcessor::duration() const { if (_filterThread) { diff --git a/gmic-qt/src/GmicProcessor.h b/gmic-qt/src/GmicProcessor.h index cecdd1a..e85cb57 100644 --- a/gmic-qt/src/GmicProcessor.h +++ b/gmic-qt/src/GmicProcessor.h @@ -94,6 +94,7 @@ public: bool isProcessingFullImage() const; bool isProcessing() const; bool isIdle() const; + bool isInputImagesEmpty() const; bool hasUnfinishedAbortedThreads() const; const gmic_library::gmic_image<float> & previewImage() const; diff --git a/gmic-qt/src/GmicQt.cpp b/gmic-qt/src/GmicQt.cpp index 3af90b3..17b98c3 100644 --- a/gmic-qt/src/GmicQt.cpp +++ b/gmic-qt/src/GmicQt.cpp @@ -87,7 +87,7 @@ RunParameters lastAppliedFilterRunParameters(ReturnedRunParametersFlag flag) { configureApplication(); RunParameters parameters; - QSettings settings; + GMIC_SETTINGS(settings); const QString path = settings.value(QString("LastExecution/host_%1/FilterPath").arg(GmicQtHost::ApplicationShortname)).toString(); parameters.filterPath = path.toStdString(); QString args = settings.value(QString("LastExecution/host_%1/Arguments").arg(GmicQtHost::ApplicationShortname)).toString(); @@ -197,7 +197,7 @@ int run(UserInterfaceMode interfaceMode, // LanguageSettings::installTranslators(); MainWindow mainWindow; mainWindow.setPluginParameters(parameters); - if (QSettings().value("Config/MainWindowMaximized", false).toBool()) { + if (GMIC_SETTINGS_INLINE.value("Config/MainWindowMaximized", false).toBool()) { mainWindow.showMaximized(); } else { mainWindow.show(); @@ -545,9 +545,11 @@ namespace void configureApplication() { +#ifndef _GMIC_USE_HOSTED_SETTINGS_ QCoreApplication::setOrganizationName(GMIC_QT_ORGANISATION_NAME); QCoreApplication::setOrganizationDomain(GMIC_QT_ORGANISATION_DOMAIN); QCoreApplication::setApplicationName(GMIC_QT_APPLICATION_NAME); +#endif QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar); #if !QT_VERSION_GTE(6, 0, 0) if (QSettings().value(HIGHDPI_KEY, false).toBool()) { diff --git a/gmic-qt/src/HeadlessProcessor.cpp b/gmic-qt/src/HeadlessProcessor.cpp index f10efc3..a595ec1 100644 --- a/gmic-qt/src/HeadlessProcessor.cpp +++ b/gmic-qt/src/HeadlessProcessor.cpp @@ -27,6 +27,7 @@ #include <QMessageBox> #include <QSettings> #include <QStringList> +#include "Globals.h" #include "Common.h" #include "FilterParameters/FilterParametersWidget.h" #include "FilterSelector/FiltersPresenter.h" @@ -234,7 +235,7 @@ void HeadlessProcessor::onProcessingFinished() GmicQtHost::outputImages(images, _filterThread->imageNames(), _outputMode); _processingCompletedProperly = true; } - QSettings settings; + GMIC_SETTINGS(settings); if (!status.isEmpty() && !_hash.isEmpty()) { ParametersCache::setValues(_hash, status); ParametersCache::save(); @@ -267,7 +268,9 @@ void HeadlessProcessor::endApplication(const QString & errorMessage) if (!errorMessage.isEmpty()) { Logger::error(errorMessage); } +#ifndef _GMIC_USE_HOSTED_SETTINGS_ QCoreApplication::exit(!errorMessage.isEmpty()); +#endif } } // namespace GmicQt diff --git a/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.cpp b/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.cpp new file mode 100644 index 0000000..849ca44 --- /dev/null +++ b/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.cpp @@ -0,0 +1,233 @@ +/* + * This file is part of G'MIC-Qt, a generic plug-in for raster graphics + * editors, offering hundreds of filters thanks to the underlying G'MIC + * image processing framework. + * + * Copyright (C) 2020-2022 L. E. Segovia <amy@amyspark.me> + * + * Description: Krita painting suite plugin for G'Mic-Qt. + * + * G'MIC-Qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * G'MIC-Qt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <QApplication> +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QEventLoop> +#include <QPointer> +#include <QSettings> +#include <QTranslator> +#include <list> + +#ifdef Q_OS_ANDROID +#include <android/log.h> +#include <array> +#include <iostream> +#include <thread> +#include <unistd.h> +#endif + +#include "Settings.h" +#include "GmicQt.h" +#include "Globals.h" +#include "HeadlessProcessor.h" +#include "Host/GmicQtHost.h" +#include "LanguageSettings.h" +#include "Logger.h" +#include "MainWindow.h" +#include "Widgets/InOutPanel.h" +#include "Widgets/ProgressInfoWindow.h" +#include "Utils.h" +#include "gmicqttoolplugin.h" + +#include "kpluginfactory.h" + +K_PLUGIN_FACTORY_WITH_JSON(KritaGmicPluginFactory, + "gmicqttoolplugin.json", + registerPlugin<KritaGmicPlugin>();) + +KritaGmicPlugin::KritaGmicPlugin(QObject *parent, const QVariantList &) + : QObject(parent) +{ +#ifdef Q_OS_WIN + // Workaround for deploying basic CLUTs + // See https://krita-artists.org/t/unknown-filename-gmic-qt/37813 + { + const auto srcPath = QDir(QCoreApplication::applicationDirPath().append(QStringLiteral("/../share/gmic/"))).absolutePath(); + const auto dstPath = GmicQt::gmicConfigPath(true); + const std::list<QString> files = {"/gmic_cluts.gmz", "/gmic_denoise_cnn.gmz"}; + + for (const auto file: files) { + const auto src = srcPath + file; + const auto dst = dstPath + file; + if (QFileInfo(src).exists() && !QFileInfo(dst).exists()) { + qWarning() << src << dst; + QFile::copy(src, dst); + } + } + + if (!qEnvironmentVariableIsSet("GMIC_SYSTEM_PATH")) { + qputenv("GMIC_SYSTEM_PATH", QString(srcPath).replace(L'/', L'\\').toLocal8Bit()); + } + } +#endif +} + +int KritaGmicPlugin::launch(std::shared_ptr<KisImageInterface> i, bool headless) +{ +#ifdef Q_OS_ANDROID + /* Since on Android stdout and stderr redirect to null, un-redirect them */ + /* based on https://stackoverflow.com/a/gmic-qt/31777050 */ + + std::array<int, 2> oldFd; + std::array<int, 2> newStdout, newStderr; + + auto redir_worker = [](std::array<int, 2> &fd, android_LogPriority lvl) { + ssize_t rdsz; + std::array<char, 1024> buf{}; + while ((rdsz = read(fd[0], buf.data(), buf.size() - 1)) > 0) { + if (buf[rdsz - 1] == '\n') + --rdsz; + buf[rdsz] = 0; /* add null-terminator */ + __android_log_write( + lvl, qPrintable(GmicQtHost::ApplicationName), buf.data()); + } + }; + + /* make stdout line-buffered and stderr unbuffered */ + setvbuf(stdout, 0, _IOLBF, 0); + setvbuf(stderr, 0, _IOLBF, 0); + + /* create the pipe and redirect stdout and stderr */ + dup2(1, oldFd[0]); + dup2(2, oldFd[1]); + pipe(newStdout.data()); + pipe(newStderr.data()); + dup2(newStdout[1], 1); + dup2(newStderr[1], 2); + + /* spawn the logging thread */ + auto newStdoutRedir = + std::thread(redir_worker, std::ref(newStdout), ANDROID_LOG_DEBUG); + auto newStderrRedir = + std::thread(redir_worker, std::ref(newStderr), ANDROID_LOG_WARN); + newStdoutRedir.detach(); + newStderrRedir.detach(); +#endif + + using namespace GmicQt; + + std::list<GmicQt::InputMode> disabledInputModes; + disabledInputModes.push_back(GmicQt::InputMode::NoInput); + // disabledInputModes.push_back(GmicQt::Active); + // disabledInputModes.push_back(GmicQt::All); + // disabledInputModes.push_back(GmicQt::ActiveAndBelow); + // disabledInputModes.push_back(GmicQt::ActiveAndAbove); + disabledInputModes.push_back(GmicQt::InputMode::AllVisible); + disabledInputModes.push_back(GmicQt::InputMode::AllInvisible); + + std::list<GmicQt::OutputMode> disabledOutputModes; + // disabledOutputModes.push_back(GmicQt::OutputMode::InPlace); + disabledOutputModes.push_back(GmicQt::OutputMode::NewImage); + disabledOutputModes.push_back(GmicQt::OutputMode::NewLayers); + disabledOutputModes.push_back(GmicQt::OutputMode::NewActiveLayers); + + int status = 0; + GmicQtHost::iface = i; + if (headless) { + GmicQt::RunParameters parameters = GmicQt::lastAppliedFilterRunParameters( + GmicQt::ReturnedRunParametersFlag::AfterFilterExecution); + { + for (const GmicQt::InputMode & mode : disabledInputModes) { + GmicQt::InOutPanel::disableInputMode(mode); + } + for (const GmicQt::OutputMode & mode : disabledOutputModes) { + GmicQt::InOutPanel::disableOutputMode(mode); + } + } + Settings::load(GmicQt::UserInterfaceMode::ProgressDialog); + Logger::setMode(Settings::outputMessageMode()); + LanguageSettings::installTranslators(); + + HeadlessProcessor processor(nullptr); + if (!processor.setPluginParameters(parameters)) { + Logger::error(processor.error()); + return 1; + } + + QPointer<ProgressInfoWindow> progressWindow(new ProgressInfoWindow(&processor)); + // We want a non modal dialog here. + progressWindow->setWindowFlags(Qt::Tool | Qt::Dialog); + progressWindow->setWindowModality(Qt::ApplicationModal); + // Make it destroy itself on close (signaling the event loop) + progressWindow->setAttribute(Qt::WA_DeleteOnClose); + + processor.startProcessing(); + + QEventLoop loop; + connect(progressWindow, SIGNAL(destroyed()), &loop, SLOT(quit())); + status = loop.exec(); + } else { + GmicQt::RunParameters parameters = GmicQt::lastAppliedFilterRunParameters( + GmicQt::ReturnedRunParametersFlag::AfterFilterExecution); + { + for (const GmicQt::InputMode & mode : disabledInputModes) { + GmicQt::InOutPanel::disableInputMode(mode); + } + for (const GmicQt::OutputMode & mode : disabledOutputModes) { + GmicQt::InOutPanel::disableOutputMode(mode); + } + } + Settings::load(GmicQt::UserInterfaceMode::Full); + Logger::setMode(Settings::outputMessageMode()); + LanguageSettings::installTranslators(); + + QPointer<MainWindow> mainWindow(new MainWindow(qApp->activeWindow())); + mainWindow->setPluginParameters(parameters); +#ifdef Q_OS_MACOS + mainWindow->setWindowFlags(Qt::Tool | Qt::Dialog); +#else + mainWindow->setWindowFlags(Qt::Dialog); +#endif + mainWindow->setWindowModality(Qt::ApplicationModal); + // Make it destroy itself on close (signaling the event loop) + mainWindow->setAttribute(Qt::WA_DeleteOnClose); + + if (GMIC_SETTINGS_INLINE.value("Config/MainWindowMaximized", false).toBool()) { + mainWindow->showMaximized(); + } else { + mainWindow->show(); + } + + // Wait than main widget is closed. + QEventLoop loop; + connect(mainWindow, SIGNAL(destroyed()), &loop, SLOT(quit())); + status = loop.exec(); + } + + GmicQtHost::sharedMemorySegments.clear(); + GmicQtHost::iface.reset(); + +#ifdef Q_OS_ANDROID + /* un-redirect stdout and stderr */ + dup2(oldFd[0], 1); + dup2(oldFd[1], 2); +#endif + + return status; +} + +#include "gmicqttoolplugin.moc" diff --git a/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.h b/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.h new file mode 100644 index 0000000..bea9056 --- /dev/null +++ b/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.h @@ -0,0 +1,55 @@ +/* + * This file is part of G'MIC-Qt, a generic plug-in for raster graphics + * editors, offering hundreds of filters thanks to the underlying G'MIC + * image processing framework. + * + * Copyright (C) 2020-2021 L. E. Segovia <amy@amyspark.me> + * + * Description: Krita painting suite plugin for G'Mic-Qt. + * + * G'MIC-Qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * G'MIC-Qt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef GMICQT_TOOL_PLUGIN_H +#define GMICQT_TOOL_PLUGIN_H + +#include <QObject> +#include <QSharedMemory> +#include <QVector> +#include <QtPlugin> +#include <memory> + +#include <kis_qmic_interface.h> +#include <kis_qmic_plugin_interface.h> + +namespace GmicQtHost +{ +extern QVector<KisQMicImageSP> sharedMemorySegments; +extern std::shared_ptr<KisImageInterface> iface; +} // namespace GmicQtHost + +class KritaGmicPlugin : public QObject, public KisQmicPluginInterface +{ + Q_OBJECT + Q_INTERFACES(KisQmicPluginInterface) + +public: + KritaGmicPlugin(QObject *parent, const QVariantList &); + + int launch(std::shared_ptr<KisImageInterface> iface, + bool headless = false) override; +}; + +#endif diff --git a/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.json b/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.json new file mode 100644 index 0000000..4639d5e --- /dev/null +++ b/gmic-qt/src/Host/KritaPlugin/gmicqttoolplugin.json @@ -0,0 +1,9 @@ +{ + "Id": "GMic-Qt Krita Plugin", + "Type": "Service", + "X-KDE-Library": "gmic_krita_qt", + "X-KDE-ServiceTypes": [ + "Krita/GMic" + ], + "X-Krita-Version": "28" +} diff --git a/gmic-qt/src/Host/KritaPlugin/host.cpp b/gmic-qt/src/Host/KritaPlugin/host.cpp new file mode 100644 index 0000000..fcfa12b --- /dev/null +++ b/gmic-qt/src/Host/KritaPlugin/host.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 Boudewijn Rempt <boud@valdyas.org> + * Copyright (C) 2020-2022 L. E. Segovia <amy@amyspark.me> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <QByteArray> +#include <QDebug> +#include <QDesktopWidget> +#include <QFileDialog> +#include <QFileInfo> +#include <QSharedMemory> +#include <QStandardPaths> +#include <QStringLiteral> +#include <QUuid> +#include <QVector> +#include <algorithm> +#include <memory> + +#include "GmicQt.h" +#include "Host/GmicQtHost.h" +#ifndef gmic_core +#include "CImg.h" +#endif +#include "gmic.h" +#include "kis_qmic_interface.h" + +/* + * No messages are sent in the plugin version of GMic. + * Instead, a list of KisQMicImageSP (shared pointers to KisQMic instances) + * are sent. These have: + * + * layer name + * shared pointer to data + * width + * height + * a mutex to control access. + * + * For the sake of debuggability, the overall control flow has been maintained. + */ + +namespace GmicQtHost +{ +const QString ApplicationName = QStringLiteral("Krita"); +const char *const ApplicationShortname = GMIC_QT_XSTRINGIFY(GMIC_HOST); +const bool DarkThemeIsDefault = false; + +QVector<KisQMicImageSP> sharedMemorySegments; +std::shared_ptr<KisImageInterface> iface; + +void getLayersExtent(int *width, int *height, GmicQt::InputMode mode) +{ +#if defined(KRITA_QMIC_INTERFACE_VERSION) && KRITA_QMIC_INTERFACE_VERSION >= 0x05010001 + const auto size = iface->gmic_qt_get_image_size(static_cast<int>(mode)); +#else + const auto size = iface->gmic_qt_get_image_size(); +#endif + *width = size.width(); + *height = size.height(); + + // qDebug() << "gmic-qt: layers extent:" << *width << *height; +} + +void getCroppedImages(gmic_list<float> &images, + gmic_list<char> &imageNames, + double x, + double y, + double width, + double height, + GmicQt::InputMode mode) +{ + // qDebug() << "gmic-qt: get_cropped_images:" << x << y << width << height; + + const bool entireImage = x < 0 && y < 0 && width < 0 && height < 0; + if (entireImage) { + x = 0.0; + y = 0.0; + width = 1.0; + height = 1.0; + } + + // Create a message for Krita + QRectF cropRect = {x, y, width, height}; + auto imagesList = + iface->gmic_qt_get_cropped_images(static_cast<int>(mode), cropRect); + + if (imagesList.isEmpty()) { + qWarning() << "\tgmic-qt: empty answer!"; + return; + } + + // qDebug() << "\tgmic-qt: " << answer; + + images.assign(imagesList.size()); + imageNames.assign(imagesList.size()); + + // qDebug() << "\tgmic-qt: imagelist size" << imagesList.size(); + + // Get the layers as prepared by Krita in G'Mic format + for (int i = 0; i < imagesList.length(); ++i) { + const auto &layer = imagesList[i]; + const auto ba = layer->m_layerName.toUtf8(); + gmic_image<char>::string(ba.data()).move_to(imageNames[i]); + + // Fill images from the shared memory areas + + { + QMutexLocker lock(&layer->m_mutex); + + // qDebug() << "Memory segment" << (quintptr)image.data() << image->size() + // << (quintptr)&image->m_data << (quintptr)image->m_data.get(); + + // convert the data to the list of float + gmic_image<float> gimg; + gimg.assign(layer->m_width, layer->m_height, 1, 4); + const size_t length = + layer->m_width * layer->m_height * 4U * sizeof(float); + std::memcpy(gimg._data, layer->constData(), length); + gimg.move_to(images[i]); + } + } + + iface->gmic_qt_detach(); + + // qDebug() << "\tgmic-qt: Images size" << images.size() << ", names size" << + // imageNames.size(); +} + +void outputImages(gmic_list<float> &images, + const gmic_list<char> &imageNames, + GmicQt::OutputMode mode) +{ + // qDebug() << "qmic-qt-output-images"; + + sharedMemorySegments.clear(); + + // qDebug() << "\tqmic-qt: shared memory" << sharedMemorySegments.count(); + + // Create qsharedmemory segments for each image + // Create a message for Krita based on mode, the keys of the qsharedmemory + // segments and the imageNames + QVector<KisQMicImageSP> layers; + + for (uint i = 0; i < images.size(); ++i) { + // qDebug() << "\tgmic-qt: image number" << i; + + gmic_image<float> gimg = images.at(i); + + const auto layerName = QString::fromUtf8(imageNames[i].data()); + + KisQMicImageSP m = KisQMicImageSP::create( + layerName, gimg._width, gimg._height, gimg._spectrum); + sharedMemorySegments << m; + + { + QMutexLocker lock(&m->m_mutex); + + const auto slice = gimg.get_slice(0); + + const auto length = slice._width * slice._height * slice._spectrum * sizeof(float); + std::memcpy(m->m_data, slice._data, length); + } + + layers << m; + } + + iface->gmic_qt_output_images(static_cast<int>(mode), layers); +} + +void showMessage(const char *) +{ + // May be left empty for Krita. + // Only used by launchPluginHeadless(), called in the non-interactive + // script mode of GIMP. +} + +void applyColorProfile(cimg_library::CImg<gmic_pixel_type> &) +{ +} + +} // namespace GmicQtHost diff --git a/gmic-qt/src/Host/None/JpegQualityDialog.cpp b/gmic-qt/src/Host/None/JpegQualityDialog.cpp index 69635c6..00a7f95 100644 --- a/gmic-qt/src/Host/None/JpegQualityDialog.cpp +++ b/gmic-qt/src/Host/None/JpegQualityDialog.cpp @@ -2,6 +2,8 @@ #include <QSettings> #include "Settings.h" #include "ui_jpegqualitydialog.h" +#include "Globals.h" + int JpegQualityDialog::_permanentQuality = -1; int JpegQualityDialog::_selectedQuality = -1; @@ -15,7 +17,7 @@ JpegQualityDialog::JpegQualityDialog(QWidget * parent) : QDialog(parent), ui(new ui->spinBox->setRange(0, 100); if (_selectedQuality == -1) { - _selectedQuality = QSettings().value(JPEG_QUALITY_KEY, 85).toInt(); + _selectedQuality = GMIC_SETTINGS_INLINE.value(JPEG_QUALITY_KEY, 85).toInt(); } ui->slider->setValue(_selectedQuality); @@ -25,7 +27,7 @@ JpegQualityDialog::JpegQualityDialog(QWidget * parent) : QDialog(parent), ui(new connect(ui->spinBox, QOverload<int>::of(&QSpinBox::valueChanged), ui->slider, &QSlider::setValue); connect(ui->pbOk, &QPushButton::clicked, [this]() { _selectedQuality = ui->spinBox->value(); - QSettings().setValue(JPEG_QUALITY_KEY, _selectedQuality); + GMIC_SETTINGS_INLINE.setValue(JPEG_QUALITY_KEY, _selectedQuality); }); connect(ui->pbOk, &QPushButton::clicked, this, &QDialog::accept); connect(ui->pbCancel, &QPushButton::clicked, this, &QDialog::reject); diff --git a/gmic-qt/src/LanguageSettings.cpp b/gmic-qt/src/LanguageSettings.cpp index 7e74667..0c92a47 100644 --- a/gmic-qt/src/LanguageSettings.cpp +++ b/gmic-qt/src/LanguageSettings.cpp @@ -23,6 +23,7 @@ * */ +#include "Globals.h" #include "LanguageSettings.h" #include <QApplication> #include <QDebug> @@ -66,7 +67,11 @@ const QMap<QString, QString> & LanguageSettings::availableLanguages() QString LanguageSettings::configuredTranslator() { - QString code = QSettings().value(LANGUAGE_CODE_KEY, QString()).toString(); +#ifndef _GMIC_QT_DISABLE_TRANSLATION_ + QString code = GMIC_SETTINGS_INLINE.value(LANGUAGE_CODE_KEY, QString()).toString(); +#else + QString code; +#endif if (code.isEmpty()) { code = systemDefaultAndAvailableLanguageCode(); if (code.isEmpty()) { @@ -105,7 +110,7 @@ void LanguageSettings::installTranslators() if (!lang.isEmpty() && (lang != "en")) { installQtTranslator(lang); installTranslator(QString(":/translations/%1.qm").arg(lang)); - if (QSettings().value(ENABLE_FILTER_TRANSLATION, false).toBool()) { + if (GMIC_SETTINGS_INLINE.value(ENABLE_FILTER_TRANSLATION, false).toBool()) { installTranslator(QString(":/translations/filters/%1.qm").arg(lang)); } } diff --git a/gmic-qt/src/MainWindow.cpp b/gmic-qt/src/MainWindow.cpp index d48e095..008d955 100644 --- a/gmic-qt/src/MainWindow.cpp +++ b/gmic-qt/src/MainWindow.cpp @@ -187,8 +187,12 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent), ui(new Ui::MainW updateShortcutF5->setContext(Qt::ApplicationShortcut); QShortcut * updateShortcutCtrlR = new QShortcut(QKeySequence("Ctrl+R"), this); updateShortcutCtrlR->setContext(Qt::ApplicationShortcut); +#ifdef _GMIC_QT_DISABLE_UPDATES_ + ui->tbUpdateFilters->setEnabled(false); +#else connect(updateShortcutF5, &QShortcut::activated, [this]() { ui->tbUpdateFilters->animateClick(); }); connect(updateShortcutCtrlR, &QShortcut::activated, [this]() { ui->tbUpdateFilters->animateClick(); }); +#endif ui->tbUpdateFilters->setToolTip(updateText); } @@ -275,6 +279,7 @@ void MainWindow::setIcons() ui->tbExpandCollapse->setIcon(_expandIcon); } +#ifndef _GMIC_QT_DISABLE_THEMING_ void MainWindow::setDarkTheme() { // SHOW(QStyleFactory::keys()); @@ -328,6 +333,7 @@ void MainWindow::setDarkTheme() ui->vSplitterLine->setStyleSheet("QFrame{ border-top: 0px none #a0a0a0; border-bottom: 1px solid rgb(160,160,160);}"); Settings::UnselectedFilterTextColor = Settings::UnselectedFilterTextColor.darker(150); } +#endif void MainWindow::setPluginParameters(const RunParameters & parameters) { @@ -363,7 +369,9 @@ void MainWindow::onUpdateDownloadsFinished(int status) showMessage(tr("No download was needed."), 3000); } +#ifndef _GMIC_QT_DISABLE_UPDATES_ ui->tbUpdateFilters->setEnabled(true); +#endif if (_filtersPresenter->currentFilter().hash.isEmpty()) { setNoFilter(); } else { @@ -385,7 +393,7 @@ void MainWindow::buildFiltersTree() _filtersPresenter->importGmicGTKFaves(); _filtersPresenter->saveFaves(); _gtkFavesShouldBeImported = false; - QSettings().setValue(FAVES_IMPORT_KEY, true); + GMIC_SETTINGS_INLINE.setValue(FAVES_IMPORT_KEY, true); } _filtersPresenter->toggleSelectionMode(withVisibility); } @@ -493,7 +501,7 @@ void MainWindow::onStartupFiltersUpdateFinished(int status) } else if (status == (int)Updater::UpdateStatus::NotNecessary) { } - if (QSettings().value(FAVES_IMPORT_KEY, false).toBool() || !FavesModelReader::gmicGTKFaveFileAvailable()) { + if (GMIC_SETTINGS_INLINE.value(FAVES_IMPORT_KEY, false).toBool() || !FavesModelReader::gmicGTKFaveFileAvailable()) { _gtkFavesShouldBeImported = false; } else { _gtkFavesShouldBeImported = askUserForGTKFavesImport(); @@ -511,7 +519,7 @@ void MainWindow::onStartupFiltersUpdateFinished(int status) } // Retrieve and select previously selected filter - QString hash = QSettings().value("SelectedFilter", QString()).toString(); + QString hash = GMIC_SETTINGS_INLINE.value("SelectedFilter", QString()).toString(); if (_newSession || !_lastExecutionOK) { hash.clear(); } @@ -576,7 +584,9 @@ void MainWindow::onEscapeKeyPressed() } else { _processor.cancel(); ui->previewWidget->displayOriginalImage(); +#ifndef _GMIC_QT_DISABLE_UPDATES_ ui->tbUpdateFilters->setEnabled(true); +#endif } } } @@ -696,7 +706,9 @@ void MainWindow::onPreviewUpdateRequested(bool synchronous, bool randomized) ui->previewWidget->invalidateSavedPreview(); return; } +#ifndef _GMIC_QT_DISABLE_UPDATES_ ui->tbUpdateFilters->setEnabled(false); +#endif _processor.init(); GmicProcessor::FilterContext context; if (!ui->cbPreview->isChecked()) { @@ -764,7 +776,9 @@ void MainWindow::onPreviewImageAvailable() } ui->previewWidget->setPreviewImage(_processor.previewImage()); ui->previewWidget->enableRightClick(); +#ifndef _GMIC_QT_DISABLE_UPDATES_ ui->tbUpdateFilters->setEnabled(true); +#endif } void MainWindow::onGUIDynamismRunDone() @@ -779,9 +793,19 @@ void MainWindow::onGUIDynamismRunDone() void MainWindow::onPreviewError(const QString & message) { + // if Krita is too busy generating the images, restart the + // the preview process + if (_processor.isInputImagesEmpty()) { + CroppedImageListProxy::clear(); + QTimer::singleShot(1000, ui->previewWidget, SLOT(sendUpdateRequest())); + return; + } + ui->previewWidget->setPreviewErrorMessage(message); ui->previewWidget->enableRightClick(); +#ifndef _GMIC_QT_DISABLE_UPDATES_ ui->tbUpdateFilters->setEnabled(true); +#endif } void MainWindow::onParametersChanged() @@ -864,12 +888,16 @@ void MainWindow::onVeryFirstShowEvent() Updater::setOutputMessageMode(Settings::outputMessageMode()); int ageLimit; { - QSettings settings; + GMIC_SETTINGS(settings); ageLimit = settings.value(INTERNET_UPDATE_PERIODICITY_KEY, INTERNET_DEFAULT_PERIODICITY).toInt(); } +#ifndef _GMIC_QT_DISABLE_UPDATES_ const bool useNetwork = (ageLimit != INTERNET_NEVER_UPDATE_PERIODICITY); +#else + const bool useNetwork = false; +#endif ui->progressInfoWidget->startFiltersUpdateAnimationAndShow(); - Updater::getInstance()->startUpdate(ageLimit, 4, useNetwork); + Updater::getInstance()->startUpdate(ageLimit, 60, useNetwork); } void MainWindow::setZoomConstraint() @@ -1019,7 +1047,7 @@ void MainWindow::saveCurrentParameters() void MainWindow::saveSettings() { - QSettings settings; + GMIC_SETTINGS(settings); _filtersPresenter->saveSettings(settings); @@ -1061,7 +1089,7 @@ void MainWindow::saveSettings() void MainWindow::loadSettings() { - QSettings settings; + GMIC_SETTINGS(settings); _filtersPresenter->loadSettings(settings); _lastExecutionOK = settings.value("LastExecution/ExitedNormally", true).toBool(); _newSession = host_app_pid() != settings.value("LastExecution/HostApplicationID", 0).toUInt(); @@ -1076,9 +1104,11 @@ void MainWindow::loadSettings() if (settings.value("Config/PreviewPosition", "Left").toString() == "Left") { setPreviewPosition(PreviewPosition::Left); } +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { setDarkTheme(); } +#endif if (!Settings::visibleLogos()) { ui->logosLabel->hide(); } @@ -1122,7 +1152,7 @@ void MainWindow::loadSettings() ui->splitter->setSizes(sizes); } - ui->cbInternetUpdate->setChecked(settings.value("Config/RefreshInternetUpdate", true).toBool()); + ui->cbInternetUpdate->setChecked(settings.value(REFRESH_USING_INTERNET_KEY, INTERNET_DEFAULT_REFRESH_UPDATE).toBool()); } void MainWindow::setPreviewPosition(MainWindow::PreviewPosition position) @@ -1184,7 +1214,7 @@ void MainWindow::setPreviewPosition(MainWindow::PreviewPosition position) void MainWindow::adjustVerticalSplitter() { QList<int> sizes; - QSettings settings; + GMIC_SETTINGS(settings); sizes.push_back(settings.value(QString("Config/ParamsVerticalSplitterSizeTop"), -1).toInt()); sizes.push_back(settings.value(QString("Config/ParamsVerticalSplitterSizeBottom"), -1).toInt()); const int splitterHeight = ui->verticalSplitter->height(); @@ -1315,17 +1345,19 @@ bool MainWindow::askUserForGTKFavesImport() QMessageBox::Yes | QMessageBox::No, this); messageBox.setDefaultButton(QMessageBox::Yes); QCheckBox * cb = new QCheckBox(tr("Don't ask again")); +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { QPalette p = cb->palette(); p.setColor(QPalette::Text, Settings::CheckBoxTextColor); p.setColor(QPalette::Base, Settings::CheckBoxBaseColor); cb->setPalette(p); } +#endif messageBox.setCheckBox(cb); int choice = messageBox.exec(); if (choice != QMessageBox::Yes) { if (cb->isChecked()) { - QSettings().setValue(FAVES_IMPORT_KEY, true); + GMIC_SETTINGS_INLINE.setValue(FAVES_IMPORT_KEY, true); } return false; } diff --git a/gmic-qt/src/MainWindow.h b/gmic-qt/src/MainWindow.h index e7ed69d..ea16e23 100644 --- a/gmic-qt/src/MainWindow.h +++ b/gmic-qt/src/MainWindow.h @@ -70,7 +70,9 @@ public: explicit MainWindow(QWidget * parent = nullptr); ~MainWindow() override; void updateFiltersFromSources(int ageLimit, bool useNetwork); +#ifndef _GMIC_QT_DISABLE_THEMING_ void setDarkTheme(); +#endif void setPluginParameters(const RunParameters & parameters); public slots: diff --git a/gmic-qt/src/Settings.cpp b/gmic-qt/src/Settings.cpp index 4764218..6e91e78 100644 --- a/gmic-qt/src/Settings.cpp +++ b/gmic-qt/src/Settings.cpp @@ -77,7 +77,7 @@ QString Settings::NegativeSign('-'); void Settings::load(UserInterfaceMode userInterfaceMode) { - QSettings settings; + GMIC_SETTINGS(settings); _visibleLogos = settings.value("LogosAreVisible", true).toBool(); _darkThemeEnabled = settings.value(DARK_THEME_KEY, GmicQtHost::DarkThemeIsDefault).toBool(); _languageCode = settings.value(LANGUAGE_CODE_KEY, QString()).toString(); @@ -131,7 +131,11 @@ void Settings::setVisibleLogos(bool on) bool Settings::darkThemeEnabled() { - return _darkThemeEnabled; +#ifdef _GMIC_QT_DISABLE_THEMING_ + return GmicQtHost::DarkThemeIsDefault; +#else + return _darkThemeEnabled; +#endif } void Settings::setDarkThemeEnabled(bool on) @@ -273,8 +277,10 @@ void Settings::save(QSettings & settings) { removeObsoleteKeys(settings); settings.setValue("LogosAreVisible", _visibleLogos); +#ifndef _GMIC_QT_DISABLE_TRANSLATION_ settings.setValue(LANGUAGE_CODE_KEY, _languageCode); settings.setValue(ENABLE_FILTER_TRANSLATION, _filterTranslationEnabled); +#endif settings.setValue("Config/PreviewPosition", (_previewPosition == MainWindow::PreviewPosition::Left) ? "Left" : "Right"); settings.setValue("Config/NativeColorDialogs", _nativeColorDialogs); diff --git a/gmic-qt/src/Tags.cpp b/gmic-qt/src/Tags.cpp index fae4d99..d3140e0 100644 --- a/gmic-qt/src/Tags.cpp +++ b/gmic-qt/src/Tags.cpp @@ -26,6 +26,7 @@ #include <QAction> #include <QBuffer> #include <QByteArray> +#include <QCoreApplication> #include <QDebug> #include <QIcon> #include <QImage> @@ -148,7 +149,10 @@ QAction * TagAssets::action(QObject * parent, TagColor color, IconMark mark) if ((color == TagColor::None) || (color == TagColor::Count)) { return nullptr; } - return new QAction(menuIcon(color, mark), QObject::tr("%1 Tag").arg(colorName(color)), parent); + QAction *action = new QAction(menuIcon(color, mark), QObject::tr("%1 Tag").arg(colorName(color)), parent); + if (qApp->testAttribute(Qt::AA_DontShowIconsInMenus)) + action->setIconVisibleInMenu(true); + return action; } QString TagAssets::colorName(TagColor color) diff --git a/gmic-qt/src/Widgets/InOutPanel.cpp b/gmic-qt/src/Widgets/InOutPanel.cpp index 2a30f99..535ba84 100644 --- a/gmic-qt/src/Widgets/InOutPanel.cpp +++ b/gmic-qt/src/Widgets/InOutPanel.cpp @@ -157,10 +157,12 @@ void InOutPanel::onResetButtonClicked() setState(InputOutputState::Default, true); } +#ifndef _GMIC_QT_DISABLE_THEMING_ void InOutPanel::setDarkTheme() { ui->tbReset->setIcon(IconLoader::load("view-refresh")); } +#endif void InOutPanel::setDefaultInputMode() { diff --git a/gmic-qt/src/Widgets/InOutPanel.h b/gmic-qt/src/Widgets/InOutPanel.h index 381bc64..7939d3a 100644 --- a/gmic-qt/src/Widgets/InOutPanel.h +++ b/gmic-qt/src/Widgets/InOutPanel.h @@ -79,7 +79,9 @@ public slots: void onInputModeSelected(int); void onOutputModeSelected(int); void onResetButtonClicked(); +#ifndef _GMIC_QT_DISABLE_THEMING_ void setDarkTheme(); +#endif private: static void setDefaultInputMode(); diff --git a/gmic-qt/src/Widgets/ProgressInfoWindow.cpp b/gmic-qt/src/Widgets/ProgressInfoWindow.cpp index 533d257..604cf47 100644 --- a/gmic-qt/src/Widgets/ProgressInfoWindow.cpp +++ b/gmic-qt/src/Widgets/ProgressInfoWindow.cpp @@ -59,9 +59,11 @@ ProgressInfoWindow::ProgressInfoWindow(HeadlessProcessor * processor) : QMainWin connect(processor, &HeadlessProcessor::done, this, &ProgressInfoWindow::onProcessingFinished); _isShown = false; +#ifndef _GMIC_QT_DISABLE_THEMING_ if (Settings::darkThemeEnabled()) { setDarkTheme(); } +#endif } ProgressInfoWindow::~ProgressInfoWindow() @@ -85,6 +87,7 @@ void ProgressInfoWindow::closeEvent(QCloseEvent * event) event->accept(); } +#ifndef _GMIC_QT_DISABLE_THEMING_ void ProgressInfoWindow::setDarkTheme() { qApp->setStyle(QStyleFactory::create("Fusion")); @@ -107,6 +110,7 @@ void ProgressInfoWindow::setDarkTheme() p.setColor(QPalette::Disabled, QPalette::WindowText, QColor(110, 110, 110)); qApp->setPalette(p); } +#endif void ProgressInfoWindow::onCancelClicked(bool) { diff --git a/gmic-qt/src/Widgets/ProgressInfoWindow.h b/gmic-qt/src/Widgets/ProgressInfoWindow.h index 615dd16..9db9a1a 100644 --- a/gmic-qt/src/Widgets/ProgressInfoWindow.h +++ b/gmic-qt/src/Widgets/ProgressInfoWindow.h @@ -57,7 +57,9 @@ public: protected: void showEvent(QShowEvent *) override; void closeEvent(QCloseEvent *) override; +#ifndef _GMIC_QT_DISABLE_THEMING_ void setDarkTheme(); +#endif public slots: void onCancelClicked(bool); diff --git a/gmic-qt/ui/dialogsettings.ui b/gmic-qt/ui/dialogsettings.ui index 10b7ec8..f03ef4c 100644 --- a/gmic-qt/ui/dialogsettings.ui +++ b/gmic-qt/ui/dialogsettings.ui @@ -108,7 +108,7 @@ </widget> </item> <item row="0" column="1"> - <widget class="QGroupBox" name="groupBox_3"> + <widget class="QGroupBox" name="groupBoxTheme"> <property name="title"> <string>Theme</string> </property> -- 2.45.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor