diff --git a/krita/data/gamutmasks/Atmosphere_With_Accent.kgm b/krita/data/gamutmasks/Atmosphere_With_Accent.kgm new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/pics/svg/dark_gamut-mask-on.svg b/krita/pics/svg/dark_gamut-mask-on.svg new file mode 100644 --- /dev/null +++ b/krita/pics/svg/dark_gamut-mask-on.svg @@ -0,0 +1,1535 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/pics/svg/light_gamut-mask-off.svg b/krita/pics/svg/light_gamut-mask-off.svg new file mode 100644 --- /dev/null +++ b/krita/pics/svg/light_gamut-mask-off.svg @@ -0,0 +1,1563 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/pics/svg/light_gamut-mask-on.svg b/krita/pics/svg/light_gamut-mask-on.svg new file mode 100644 --- /dev/null +++ b/krita/pics/svg/light_gamut-mask-on.svg @@ -0,0 +1,1535 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/pics/svg/svg-icons.qrc b/krita/pics/svg/svg-icons.qrc --- a/krita/pics/svg/svg-icons.qrc +++ b/krita/pics/svg/svg-icons.qrc @@ -147,5 +147,9 @@ dark_wheel-sectors.svg dark_infinity.svg light_infinity.svg + dark_gamut-mask-on.svg + dark_gamut-mask-off.svg + light_gamut-mask-off.svg + light_gamut-mask-on.svg diff --git a/libs/flake/KisGamutMaskViewConverter.h b/libs/flake/KisGamutMaskViewConverter.h --- a/libs/flake/KisGamutMaskViewConverter.h +++ b/libs/flake/KisGamutMaskViewConverter.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef KISGAMUTMASKVIEWCONVERTER_H #define KISGAMUTMASKVIEWCONVERTER_H @@ -11,7 +28,7 @@ class QRectF; /** - * @brief view convertor for gamut mask calculations and painting; 0,0 in the center + * @brief view convertor for gamut mask calculations and painting */ class KRITAFLAKE_EXPORT KisGamutMaskViewConverter : public KoViewConverter { diff --git a/libs/flake/KisGamutMaskViewConverter.cpp b/libs/flake/KisGamutMaskViewConverter.cpp --- a/libs/flake/KisGamutMaskViewConverter.cpp +++ b/libs/flake/KisGamutMaskViewConverter.cpp @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include "KisGamutMaskViewConverter.h" #include diff --git a/libs/flake/resources/KoGamutMask.h b/libs/flake/resources/KoGamutMask.h --- a/libs/flake/resources/KoGamutMask.h +++ b/libs/flake/resources/KoGamutMask.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef KOGAMUTMASK_H #define KOGAMUTMASK_H @@ -24,6 +41,7 @@ bool coordIsClear(const QPointF& coord, const KoViewConverter& viewConverter) const; QPainterPath outline(); void paint(QPainter &painter, const KoViewConverter& viewConverter); + void paintStroke(QPainter &painter, const KoViewConverter& viewConverter); KoShape* koShape(); private: @@ -40,19 +58,8 @@ Q_OBJECT public: - /** - * @brief load a gamut mask from given file - * @param filename - */ KoGamutMask(const QString &filename); - - /** - * @brief create KoGamutMask from polygons - * @param polygons - */ KoGamutMask(); - - // TODO: copy constructor, for duplicating masks KoGamutMask(KoGamutMask *rhs); bool coordIsClear(const QPointF& coord, KoViewConverter& viewConverter, bool preview); @@ -63,6 +70,7 @@ bool saveToDevice(QIODevice* dev) const override; void paint(QPainter &painter, KoViewConverter& viewConverter, bool preview); + void paintStroke(QPainter &painter, KoViewConverter& viewConverter, bool preview); QString title(); void setTitle(QString title); @@ -74,13 +82,14 @@ void setMaskShapes(QList shapes); void setPreviewMaskShapes(QList shapes); - void setMaskShapesToVector(QList shapes, QVector& targetVector); QList koShapes() const; - // switch back to loaded shapes when ending mask preview void clearPreview(); + private: + void setMaskShapesToVector(QList shapes, QVector& targetVector); + struct Private; Private* const d; }; diff --git a/libs/flake/resources/KoGamutMask.cpp b/libs/flake/resources/KoGamutMask.cpp --- a/libs/flake/resources/KoGamutMask.cpp +++ b/libs/flake/resources/KoGamutMask.cpp @@ -1,4 +1,21 @@ -#include "KoGamutMask.h" +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "KoGamutMask.h" #include @@ -54,28 +71,37 @@ painter.restore(); } +void KoGamutMaskShape::paintStroke(QPainter &painter, const KoViewConverter &viewConverter) +{ + painter.save(); + painter.setTransform(m_maskShape->absoluteTransformation(&viewConverter) * painter.transform()); + m_maskShape->paintStroke(painter, viewConverter, m_shapePaintingContext); + painter.restore(); + +} struct Q_DECL_HIDDEN KoGamutMask::Private { QString name; QString title; QString description; QByteArray data; QVector maskShapes; QVector previewShapes; - QSizeF maskSize; // at 100DPI + QSizeF maskSize; }; KoGamutMask::KoGamutMask(const QString& filename) : KoResource(filename) , d(new Private()) { - + d->maskSize = QSizeF(144.0,144.0); } KoGamutMask::KoGamutMask() : KoResource(QString()) , d(new Private()) { + d->maskSize = QSizeF(144.0,144.0); } KoGamutMask::KoGamutMask(KoGamutMask* rhs) @@ -89,9 +115,8 @@ d->maskSize = rhs->d->maskSize; QList newShapes; - for(KoGamutMaskShape* sh: d->maskShapes) { - KoShape* shape = sh->koShape(); - newShapes.append(shape); + for(KoShape* sh: rhs->koShapes()) { + newShapes.append(sh->cloneShape()); } setMaskShapes(newShapes); @@ -134,6 +159,21 @@ } } +void KoGamutMask::paintStroke(QPainter &painter, KoViewConverter &viewConverter, bool preview) +{ + QVector* shapeVector; + + if (preview && !d->previewShapes.isEmpty()) { + shapeVector = &d->previewShapes; + } else { + shapeVector = &d->maskShapes; + } + + for(KoGamutMaskShape* shape: *shapeVector) { + shape->paintStroke(painter, viewConverter); + } +} + bool KoGamutMask::load() { QFile file(filename()); @@ -143,7 +183,6 @@ return false; } bool res = loadFromDevice(&file); - setValid(res); file.close(); return res; } @@ -154,7 +193,8 @@ d->data = dev->readAll(); - Q_ASSERT(d->data.size() != 0); + // TODO: test + KIS_ASSERT_RECOVER_RETURN_VALUE(d->data.size() != 0, false); if (filename().isNull()) { warnFlake << "Cannot load gamut mask" << name() << "there is no filename set"; @@ -190,7 +230,7 @@ KoXmlDocument xmlDocument; QString errorMsg; int errorLine = 0; - int errorColumn; + int errorColumn = 0; bool ok = xmlDocument.setContent(ba, false, &errorMsg, &errorLine, &errorColumn); if (!ok) { @@ -233,6 +273,8 @@ buf.close(); + setValid(true); + return true; } @@ -327,7 +369,6 @@ return d->maskSize; } -// TODO: rethink preview void KoGamutMask::setPreviewMaskShapes(QList shapes) { setMaskShapesToVector(shapes, d->previewShapes); diff --git a/libs/ui/KisResourceBundle.h b/libs/ui/KisResourceBundle.h --- a/libs/ui/KisResourceBundle.h +++ b/libs/ui/KisResourceBundle.h @@ -152,6 +152,7 @@ QList m_palettesMd5Installed; QList m_workspacesMd5Installed; QList m_presetsMd5Installed; + QList m_gamutMasksMd5Installed; QString m_bundleVersion; }; diff --git a/libs/ui/KisResourceBundle.cpp b/libs/ui/KisResourceBundle.cpp --- a/libs/ui/KisResourceBundle.cpp +++ b/libs/ui/KisResourceBundle.cpp @@ -383,6 +383,21 @@ } } } + else if (resType == "ko_gamutmasks") { + KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); + Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { + KoResource *res = gamutMaskServer->resourceByMD5(ref.md5sum); + if (!res) res = gamutMaskServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); + if (!saveResourceToStore(res, store.data(), "gamutmasks")) { + if (res) { + warnKrita << "Could not save resource" << resType << res->name(); + } + else { + warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); + } + } + } + } } if (!m_thumbnail.isNull()) { @@ -700,6 +715,51 @@ } } + else if (resType == "gamutmasks") { + KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); + Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { + + if (resourceStore->isOpen()) resourceStore->close(); + + dbgResources << "\tInstalling" << ref.resourcePath; + KoGamutMask *res = gamutMaskServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); + + if (!res) { + warnKrita << "Could not create resource for" << ref.resourcePath; + continue; + } + if (!resourceStore->open(ref.resourcePath)) { + warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); + continue; + } + if (!res->loadFromDevice(resourceStore->device())) { + warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); + continue; + } + dbgResources << "\t\tresource:" << res->name(); + + //find the resource on the server + KoGamutMask *res2 = gamutMaskServer->resourceByName(res->name()); + if (!res2) {//if it doesn't exist... + gamutMaskServer->addResource(res, false);//add it! + + if (!m_gamutMasksMd5Installed.contains(res->md5())) { + m_gamutMasksMd5Installed.append(res->md5()); + } + if (ref.md5sum!=res->md5()) { + md5Mismatch.append(res->name()); + } + + Q_FOREACH (const QString &tag, ref.tagList) { + gamutMaskServer->addTag(res, tag); + } + //gamutMaskServer->addTag(res, name()); + } + else { + //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; + } + } + } } m_installed = true; if(!md5Mismatch.isEmpty()){ @@ -777,13 +837,23 @@ } } + KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); + //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("gamutmasks")) { + Q_FOREACH (const QByteArray md5, m_gamutMasksMd5Installed) { + KoGamutMask *res = gamutMaskServer->resourceByMD5(md5); + if (res) { + gamutMaskServer->removeResourceFromServer(res); + } + } + Q_FOREACH(const QString &tag, tags) { paintoppresetServer->tagCategoryRemoved(tag); workspaceServer->tagCategoryRemoved(tag); paletteServer->tagCategoryRemoved(tag); brushServer->tagCategoryRemoved(tag); patternServer->tagCategoryRemoved(tag); gradientServer->tagCategoryRemoved(tag); + gamutMaskServer->tagCategoryRemoved(tag); } @@ -863,6 +933,11 @@ KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum); if (res) ret << res.data(); } + else if (resType == "gamutmasks") { + KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); + KoResource *res = gamutMaskServer->resourceByMD5(ref.md5sum); + if (res) ret << res; + } } return ret; } diff --git a/libs/ui/KisResourceBundleManifest.cpp b/libs/ui/KisResourceBundleManifest.cpp --- a/libs/ui/KisResourceBundleManifest.cpp +++ b/libs/ui/KisResourceBundleManifest.cpp @@ -47,7 +47,7 @@ } QString manifestTypeToResourceType(const QString &type) { - if (type == "patterns" || type == "gradients" || type == "palettes") { + if (type == "patterns" || type == "gradients" || type == "palettes" || type == "gamutmasks") { return "ko_" + type; } else { diff --git a/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp b/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp --- a/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp +++ b/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp @@ -62,5 +62,8 @@ if (cbRemovePattern->isChecked()) { KoResourceServerProvider::instance()->patternServer()->removeBlackListedFiles(); } + if (cbRemoveGamutMasks->isChecked()) { + KoResourceServerProvider::instance()->gamutMaskServer()->removeBlackListedFiles(); + } } diff --git a/libs/ui/forms/wdgdlgblacklistcleanup.ui b/libs/ui/forms/wdgdlgblacklistcleanup.ui --- a/libs/ui/forms/wdgdlgblacklistcleanup.ui +++ b/libs/ui/forms/wdgdlgblacklistcleanup.ui @@ -117,6 +117,16 @@ + + + + Gamut Masks + + + true + + + diff --git a/plugins/dockers/artisticcolorselector/CMakeLists.txt b/plugins/dockers/artisticcolorselector/CMakeLists.txt --- a/plugins/dockers/artisticcolorselector/CMakeLists.txt +++ b/plugins/dockers/artisticcolorselector/CMakeLists.txt @@ -12,5 +12,5 @@ ) add_library(kritaartisticcolorselector MODULE ${kritaartisticcolorselector_SOURCES}) -target_link_libraries(kritaartisticcolorselector kritalibkis kritaui) +target_link_libraries(kritaartisticcolorselector kritaui) install(TARGETS kritaartisticcolorselector DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) diff --git a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h --- a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h +++ b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h @@ -28,7 +28,6 @@ #include #include #include -//#include #include #include @@ -55,18 +54,14 @@ void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; -//Q_SIGNALS: -// void sigGamutMaskChanged(); - private Q_SLOTS: void slotCanvasResourceChanged(int key, const QVariant& value); void slotFgColorChanged(const KisColor& color); void slotBgColorChanged(const KisColor& color); void slotColorSpaceSelected(int type); + void slotSetGamma(qreal gamma); void slotPreferenceChanged(); - void slotResetRingPositions(); void slotResetDefaultSettings(); - void slotLightModeChanged(bool setToAbsolute); void slotGamutMaskToggle(bool value); void slotGamutMaskActivatePreview(bool value); void slotGamutMaskSet(KoGamutMask* mask); @@ -81,9 +76,10 @@ WheelPreferencesPopupUI* m_wheelPrefsUI; KoGamutMask* m_selectedMask; - QPixmap m_infinityPixmap; + QIcon m_iconMaskOff; + QIcon m_iconMaskOn; - void updateWheelInfoStrip(); + QPixmap m_infinityPixmap; }; diff --git a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp --- a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp +++ b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp @@ -91,26 +91,19 @@ QPixmap valueScaleStepsPixmap = KisIconUtils::loadIcon("wheel-light").pixmap(16,16); QIcon infinityIcon = KisIconUtils::loadIcon("infinity"); m_infinityPixmap = infinityIcon.pixmap(16,16); + m_iconMaskOff = KisIconUtils::loadIcon("gamut-mask-off"); + m_iconMaskOn = KisIconUtils::loadIcon("gamut-mask-on"); m_selectorUI->colorSelector->loadSettings(); + m_selectorUI->bnWheelPrefs->setIcon(KisIconUtils::loadIcon("wheel-sectors")); m_selectorUI->bnWheelPrefs->setPopupWidget(m_wheelPrefsUI); - // TODO: make it into separate window m_selectorUI->bnDockerPrefs->setPopupWidget(m_preferencesUI); m_selectorUI->bnDockerPrefs->setIcon(KisIconUtils::loadIcon("configure")); m_selectorUI->bnToggleMask->setChecked(false); - m_selectorUI->bnToggleMask->setIcon(KisIconUtils::loadIcon("novisible")); - m_selectorUI->labelMaskToolbar->setPixmap(KisIconUtils::loadIcon("media-playback-stop").pixmap(16,16)); - - m_selectorUI->labelHueStepsIcon->setPixmap(hueStepsPixmap); - m_selectorUI->labelSaturationStepsIcon->setPixmap(saturationStepsPixmap); - m_selectorUI->labelValueScaleStepsIcon->setPixmap(valueScaleStepsPixmap); - - m_selectorUI->labelHueSteps->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); - m_selectorUI->labelSaturationSteps->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); - m_selectorUI->labelValueScaleSteps->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); + m_selectorUI->bnToggleMask->setIcon(m_iconMaskOff); //preferences m_hsxButtons->addButton(m_preferencesUI->bnHsy, KisColor::HSY); @@ -167,28 +160,34 @@ m_preferencesUI->showColorBlip->setChecked(m_selectorUI->colorSelector->getShowColorBlip()); m_preferencesUI->showBgColor->setChecked(m_selectorUI->colorSelector->getShowBgColor()); m_preferencesUI->showValueScaleNumbers->setChecked(m_selectorUI->colorSelector->getShowValueScaleNumbers()); - m_preferencesUI->bnAbsLight->setChecked(m_selectorUI->colorSelector->islightRelative()); m_preferencesUI->enforceGamutMask->setChecked(m_selectorUI->colorSelector->enforceGamutMask()); m_preferencesUI->permissiveGamutMask->setChecked(!m_selectorUI->colorSelector->enforceGamutMask()); m_preferencesUI->showMaskPreview->setChecked(m_selectorUI->colorSelector->maskPreviewActive()); + m_preferencesUI->valueScaleGamma->setValue(m_selectorUI->colorSelector->gamma()); + switch(m_selectorUI->colorSelector->getColorSpace()) { case KisColor::HSV: { m_preferencesUI->bnHsv->setChecked(true); } break; case KisColor::HSI: { m_preferencesUI->bnHsi->setChecked(true); } break; case KisColor::HSL: { m_preferencesUI->bnHsl->setChecked(true); } break; case KisColor::HSY: { m_preferencesUI->bnHsy->setChecked(true); } break; } + if (m_selectorUI->colorSelector->getColorSpace() == KisColor::HSY) { + m_preferencesUI->valueScaleGammaBox->show(); + } else { + m_preferencesUI->valueScaleGammaBox->hide(); + } + connect(m_wheelPrefsUI->numValueScaleSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->numHueSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->numSaturationSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnInverseSat , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnInfHueSteps , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnInfValueScaleSteps, SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnDefault , SIGNAL(clicked(bool)) , SLOT(slotResetDefaultSettings())); - connect(m_wheelPrefsUI->bnResetPosition , SIGNAL(clicked(bool)) , SLOT(slotResetRingPositions())); connect(m_preferencesUI->defaultHueSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->defaultSaturationSteps, SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); @@ -200,8 +199,8 @@ connect(m_preferencesUI->showBgColor , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->showValueScaleNumbers, SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->enforceGamutMask , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged())); - connect(m_preferencesUI->bnAbsLight , SIGNAL(toggled(bool)) , SLOT(slotLightModeChanged(bool))); connect(m_preferencesUI->showMaskPreview , SIGNAL(toggled(bool)), SLOT(slotGamutMaskActivatePreview(bool))); + connect(m_preferencesUI->valueScaleGamma , SIGNAL(valueChanged(qreal)), SLOT(slotSetGamma(qreal))); connect(m_selectorUI->colorSelector , SIGNAL(sigFgColorChanged(const KisColor&)) , SLOT(slotFgColorChanged(const KisColor&))); connect(m_selectorUI->colorSelector , SIGNAL(sigBgColorChanged(const KisColor&)) , SLOT(slotBgColorChanged(const KisColor&))); @@ -211,8 +210,6 @@ connect(m_hsxButtons , SIGNAL(buttonClicked(int)) , SLOT(slotColorSpaceSelected(int))); - updateWheelInfoStrip(); - setWidget(m_selectorUI); } @@ -267,12 +264,23 @@ void ArtisticColorSelectorDock::slotColorSpaceSelected(int type) { - m_selectorUI->colorSelector->setColorSpace(static_cast(type)); + m_selectorUI->colorSelector->setColorSpace(static_cast(type), m_preferencesUI->valueScaleGamma->value()); + + if (m_selectorUI->colorSelector->getColorSpace() == KisColor::HSY) { + m_preferencesUI->valueScaleGammaBox->show(); + } else { + m_preferencesUI->valueScaleGammaBox->hide(); + } +} + +void ArtisticColorSelectorDock::slotSetGamma(qreal gamma) +{ + m_selectorUI->colorSelector->setGamma(gamma); } void ArtisticColorSelectorDock::slotPreferenceChanged() { - int hueSteps; + int hueSteps = DEFAULT_HUE_STEPS; if (m_wheelPrefsUI->bnInfHueSteps->isChecked()) { m_wheelPrefsUI->numHueSteps->setEnabled(false); hueSteps = 1; @@ -332,12 +340,6 @@ m_selectorUI->colorSelector->setInverseSaturation(false); } - updateWheelInfoStrip(); -} - -void ArtisticColorSelectorDock::slotResetRingPositions() -{ - m_selectorUI->colorSelector->resetRings(); } void ArtisticColorSelectorDock::slotResetDefaultSettings() @@ -376,32 +378,6 @@ m_wheelPrefsUI->numValueScaleSteps->setEnabled(true); m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(false); } - - updateWheelInfoStrip(); -} - -void ArtisticColorSelectorDock::slotLightModeChanged(bool setToAbsolute) -{ - m_selectorUI->colorSelector->setLight(m_selectorUI->colorSelector->getLight(), setToAbsolute); -} - -void ArtisticColorSelectorDock::updateWheelInfoStrip() -{ - int hueSteps = m_selectorUI->colorSelector->getNumPieces(); - if (hueSteps == 1) { - m_selectorUI->labelHueSteps->setPixmap(m_infinityPixmap); - } else { - m_selectorUI->labelHueSteps->setNum(hueSteps); - } - - m_selectorUI->labelSaturationSteps->setNum(m_wheelPrefsUI->numSaturationSteps->value()); - - int valueScaleSteps = m_selectorUI->colorSelector->getNumLightPieces(); - if (valueScaleSteps == 1) { - m_selectorUI->labelValueScaleSteps->setPixmap(m_infinityPixmap); - } else { - m_selectorUI->labelValueScaleSteps->setNum(valueScaleSteps); - } } void ArtisticColorSelectorDock::slotGamutMaskActivatePreview(bool value) @@ -427,9 +403,9 @@ if (b == true) { m_selectorUI->colorSelector->setGamutMask(m_selectedMask); - m_selectorUI->bnToggleMask->setIcon(KisIconUtils::loadIcon("visible")); + m_selectorUI->bnToggleMask->setIcon(m_iconMaskOn); } else { - m_selectorUI->bnToggleMask->setIcon(KisIconUtils::loadIcon("novisible")); + m_selectorUI->bnToggleMask->setIcon(m_iconMaskOff); } m_selectorUI->colorSelector->setGamutMaskOn(b); @@ -460,6 +436,10 @@ void ArtisticColorSelectorDock::slotGamutMaskSet(KoGamutMask *mask) { + if (!mask) { + return; + } + m_selectedMask = mask; if (m_selectedMask) { diff --git a/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui b/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui --- a/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui +++ b/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui @@ -7,7 +7,7 @@ 0 0 358 - 520 + 472 @@ -34,7 +34,7 @@ - Show lightness numbers on the value scale + Show numbered value scale @@ -95,10 +95,51 @@ - - - Use HSV saturation component + + + QFrame::NoFrame + + + + + Value Scale Gamma + + + + + + + 1 + + + 0.100000000000000 + + + 50.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + diff --git a/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui b/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui --- a/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui +++ b/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui @@ -6,103 +6,55 @@ 0 0 - 360 - 279 + 334 + 284 100 100 - + - - - - 1 - 0 - - - - V - - - - - - - - 2 - 0 - - - - QFrame::StyledPanel + + + Toggle gamut mask - 0 - - - - - - - - 1 - 0 - + - - H + + true - + - - 2 + + 0 0 - - QFrame::StyledPanel - - 0 - - - - - - - - 1 - 0 - + Select a mask in "Gamut Masks" docker - - S + + true - - - - 2 - 0 - + + + QFrame::Sunken - - QFrame::StyledPanel - - - 0 + + Qt::Vertical @@ -116,12 +68,15 @@ - 20 + 16777215 16777215 + + Color wheel preferences + - Text-align:left + @@ -131,19 +86,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -158,6 +100,9 @@ 0 + + Docker settings + @@ -178,43 +123,6 @@ - - - - - - M - - - - - - - - - - true - - - - - - - - 0 - 0 - - - - Select a mask in "Gamut Masks" docker - - - true - - - - - diff --git a/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui b/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui --- a/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui +++ b/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui @@ -132,17 +132,7 @@ - Reset Steps - - - false - - - - - - - Reset Rings + Reset to default false diff --git a/plugins/dockers/artisticcolorselector/kis_arcs_constants.h b/plugins/dockers/artisticcolorselector/kis_arcs_constants.h --- a/plugins/dockers/artisticcolorselector/kis_arcs_constants.h +++ b/plugins/dockers/artisticcolorselector/kis_arcs_constants.h @@ -1,7 +1,25 @@ +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef KIS_ARCS_CONSTANTS_H #define KIS_ARCS_CONSTANTS_H #include +#include static const int MIN_NUM_HUE_PIECES = 1; static const int MIN_NUM_UI_HUE_PIECES = 2; @@ -16,6 +34,16 @@ static const int DEFAULT_SATURATION_STEPS = 7; static const int DEFAULT_VALUE_SCALE_STEPS = 11; -static const QString UTF_INF_CHAR = "\u221E"; +// color scheme for the selector +static const QColor COLOR_MIDDLE_GRAY = QColor(128,128,128,255); +static const QColor COLOR_DARK = QColor(20,20,20,255); +static const QColor COLOR_LIGHT = QColor(232,232,232,255); +static const QColor COLOR_ACCENT = QColor(255,60,60,255); + +static const QColor COLOR_MASK_FILL = COLOR_MIDDLE_GRAY; +static const QColor COLOR_MASK_OUTLINE = COLOR_LIGHT; +static const QColor COLOR_MASK_CLEAR = COLOR_LIGHT; +static const QColor COLOR_SELECTED = COLOR_ACCENT; +static const QColor COLOR_NORMAL_OUTLINE = COLOR_MIDDLE_GRAY; #endif // KIS_ARCS_CONSTANTS_H diff --git a/plugins/dockers/artisticcolorselector/kis_color.h b/plugins/dockers/artisticcolorselector/kis_color.h --- a/plugins/dockers/artisticcolorselector/kis_color.h +++ b/plugins/dockers/artisticcolorselector/kis_color.h @@ -62,36 +62,26 @@ inline float getB() const { return core()->rgb(2); } inline float getH() const { return core()->hsx(0); } inline float getS() const { return core()->hsx(1); } - inline float getX() const { return core()->hsx(2); } + inline float getX(float gamma=1.0f) const { return pow(core()->hsx(2), 1/gamma); } inline float getA() const { return core()->hsx(3); } inline void setR(float v) { setRGB(v, core()->rgb(1), core()->rgb(2), core()->hsx(3)); } inline void setG(float v) { setRGB(core()->rgb(0), v, core()->rgb(2), core()->hsx(3)); } inline void setB(float v) { setRGB(core()->rgb(0), core()->rgb(1), v, core()->hsx(3)); } inline void setH(float v) { setHSX(v, core()->hsx(1), core()->hsx(2), core()->hsx(3)); } inline void setS(float v) { setHSX(core()->hsx(0), v, core()->hsx(2), core()->hsx(3)); } - inline void setX(float v) { setHSX(core()->hsx(0), core()->hsx(1), v, core()->hsx(3)); } + inline void setX(float v, float gamma=1.0f) { + setHSX(core()->hsx(0), core()->hsx(1), v, core()->hsx(3), gamma); + } inline void setA(float v) { core()->hsx(3) = qBound(0.0f, v, 1.0f); } inline QColor getQColor() const { return QColor(getR()*255, getG()*255, getB()*255, getA()*255); } - inline const VecHSXA& getHSX () const { return core()->hsx; } - inline const VecRGB& getRGB () const { return core()->rgb; } inline void setRGB(float r, float g, float b, float a=1.0f) { core()->setRGB(r, g, b, a); } - inline void setHSX(float h, float s, float x, float a=1.0f) { core()->setHSX(h, s, x, a); } - - inline void setRGB(const VecRGB& rgb) { - core()->rgb = rgb; - core()->updateHSX(); - } - - inline void setHSX(const VecHSXA& hsx) { - core()->hsx = hsx; - core()->updateRGB(); + inline void setHSX(float h, float s, float x, float a=1.0f, float gamma=1.0f) { + core()->setHSX(h, s, pow(x, gamma), a); } - - void setRGBfromHue(float hue, float alpha=1.0f); - + KisColor& operator = (const KisColor& color); friend KisColor operator - (const KisColor& a, const KisColor& b) { @@ -116,7 +106,6 @@ KisColor result; result.core()->hsx = a.core()->hsx * b; result.core()->updateRGB(); -// result.setH(a.getH()); return result; } diff --git a/plugins/dockers/artisticcolorselector/kis_color.cpp b/plugins/dockers/artisticcolorselector/kis_color.cpp --- a/plugins/dockers/artisticcolorselector/kis_color.cpp +++ b/plugins/dockers/artisticcolorselector/kis_color.cpp @@ -76,7 +76,7 @@ KisColor::KisColor(Type type) { - initRGB(type, 0.0f, 0.0f, 0.0f, 0.0f); + initRGB(type, 0.0f, 0.0f, 0.0f, 1.0f); } KisColor::KisColor(float hue, float a, Type type) @@ -160,15 +160,6 @@ core()->setHSX(h, s, x, a); } -void KisColor::setRGBfromHue(float hue, float alpha) -{ - float r = 0; - float g = 0; - float b = 0; - ::getRGB(r, g, b, hue); - core()->setRGB(r, g, b, alpha); -} - KisColor& KisColor::operator=(const KisColor& color) { initHSX(color.getType(), color.getH(), color.getS(), color.getX(), color.getA()); diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.h b/plugins/dockers/artisticcolorselector/kis_color_selector.h --- a/plugins/dockers/artisticcolorselector/kis_color_selector.h +++ b/plugins/dockers/artisticcolorselector/kis_color_selector.h @@ -43,20 +43,12 @@ struct ColorRing { - ColorRing(): angle(0) { } + ColorRing() + : saturation(0) + , outerRadius(0) + , innerRadius(0) + { } - Radian getPieceAngle() const { return RAD_360 / float(pieced.size()); } - Radian getShift () const { return angle % getPieceAngle(); } - Radian getMovedAngel() const { return angle - tmpAngle; } - - void setTemporaries(const KisColor& color) { - tmpAngle = angle; - tmpColor = color; - } - - KisColor tmpColor; - Radian tmpAngle; - Radian angle; float saturation; float outerRadius; float innerRadius; @@ -66,14 +58,16 @@ public: KisColorSelector(QWidget* parent, KisColor::Type type=KisColor::HSL); - void setColorSpace(KisColor::Type type); + void setColorSpace(KisColor::Type type, float valueScaleGamma); void setNumPieces(int num); void setNumLightPieces(int num) __attribute__((optimize(0))); void setNumRings(int num); - void resetRings(); - void resetSelectedRing(); - void resetLight(); - void setLight(float light=0.0f, bool relative=true); + + void setLight(float light=0.0f); + + float gamma() const { return m_gamma; } + void setGamma(float gamma); + void setInverseSaturation(bool inverse); void selectColor(const KisColor& color); void setFgColor(const KisColor& fgColor); @@ -103,9 +97,7 @@ qint32 getNumRings () const { return m_colorRings.size(); } qint32 getNumPieces () const { return m_numPieces; } qint32 getNumLightPieces () const { return m_numLightPieces; } - qreal getLight () const { return m_light; } bool isSaturationInverted() const { return m_inverseSaturation; } - bool islightRelative () const { return m_relativeLight; } quint32 getDefaultHueSteps () const { return m_defaultHueSteps; } quint32 getDefaultSaturationSteps () const { return m_defaultSaturationSteps; } @@ -135,27 +127,26 @@ void recalculateRings(quint8 numRings, quint8 numPieces); void createRing(ColorRing& wheel, quint8 numPieces, qreal innerRadius, qreal outerRadius); - void drawRing(QPainter& painter, int ringIndex, ColorRing& wheel, const QRect& rect); + void drawRing(QPainter& painter, ColorRing& wheel, const QRect& rect); void drawOutline(QPainter& painter, const QRect& rect); void drawBlip(QPainter& painter, const QRect& rect); void drawLightStrip(QPainter& painter, const QRect& rect); void drawGamutMaskShape(QPainter& painter, const QRect& rect); - qint8 getHueIndex(Radian hue, Radian shift=0.0f) const; + qint8 getHueIndex(Radian hue) const; qreal getHue(int hueIdx, Radian shift=0.0f) const; qint8 getLightIndex(const QPointF& pt) const; qint8 getLightIndex(qreal light) const; - qreal getLight(qreal light, qreal hue, bool relative) const; qreal getLight(const QPointF& pt) const; qint8 getSaturationIndex(const QPointF& pt) const; qint8 getSaturationIndex(qreal saturation) const; qreal getSaturation(int saturationIdx) const; -// QPointF mapCoord(const QPointF& pt, const QRectF& rect) const; - QPointF mapCoordToView(const QPointF& pt, const QRectF& viewRect) const; QPointF mapCoordToUnit(const QPointF& pt, const QRectF& viewRect) const; QPointF mapColorToUnit(const KisColor& color, bool invertSaturation = true) const; + Radian mapCoordToAngle(qreal x, qreal y) const; + QPointF mapHueToAngle(float hue) const; public: // This is a private interface for signal compressor, don't use it. @@ -167,8 +158,7 @@ quint8 m_numPieces; quint8 m_numLightPieces; bool m_inverseSaturation; - bool m_relativeLight; - float m_light; + float m_gamma; qint8 m_selectedRing; qint8 m_selectedPiece; qint8 m_selectedLightPiece; @@ -180,13 +170,10 @@ QRect m_renderArea; QRect m_lightStripArea; bool m_mouseMoved; - Acs::ColorRole m_selectedColorRole; QPointF m_clickPos; qint8 m_clickedRing; QVector m_colorRings; Qt::MouseButtons m_pressedButtons; - const QColor m_grayColor; - const QColor m_gamutMaskColor; // docker settings quint8 m_defaultHueSteps; diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp --- a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp +++ b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp @@ -36,36 +36,40 @@ #include "kis_color_selector.h" +//#define DEBUG_ARC_SELECTOR + KisColorSelector::KisColorSelector(QWidget* parent, KisColor::Type type) : QWidget(parent) , m_colorSpace(type) , m_inverseSaturation(false) - , m_relativeLight(true) - , m_light(0.5f) - , m_selectedColorRole(Acs::Foreground) + , m_gamma(1.0f) , m_clickedRing(-1) , m_gamutMaskOn(false) - , m_widgetUpdatesSelf(false) - , m_grayColor(QColor(128,128,128,255)) - , m_gamutMaskColor(QColor(128,128,128,255)) , m_currentGamutMask(nullptr) , m_maskPreviewActive(true) -{ + , m_widgetUpdatesSelf(false) +{ m_viewConverter = new KisGamutMaskViewConverter(); - recalculateRings(9, 12); - recalculateAreas(9); + recalculateRings(DEFAULT_SATURATION_STEPS, DEFAULT_HUE_STEPS); + recalculateAreas(DEFAULT_VALUE_SCALE_STEPS); selectColor(KisColor(Qt::red, KisColor::HSY)); using namespace std::placeholders; // For _1 placeholder auto function = std::bind(&KisColorSelector::slotUpdateColorAndPreview, this, _1); m_updateColorCompressor.reset(new ColorCompressorType(20 /* ms */, function)); } -void KisColorSelector::setColorSpace(KisColor::Type type) +void KisColorSelector::setColorSpace(KisColor::Type type, float valueScaleGamma) { m_colorSpace = type; + setGamma(valueScaleGamma); m_selectedColor = KisColor(m_selectedColor, m_colorSpace); + +#ifdef DEBUG_ARC_SELECTOR + dbgPlugins << "KisColorSelector::setColorSpace: set to:" << m_colorSpace; +#endif + update(); } @@ -76,7 +80,7 @@ recalculateAreas(quint8(num)); if (m_selectedLightPiece >= 0) - m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); + m_selectedLightPiece = getLightIndex(m_selectedColor.getX(m_gamma)); update(); } @@ -110,74 +114,63 @@ m_selectedColor = KisColor(color, m_colorSpace); m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2); m_selectedRing = getSaturationIndex(m_selectedColor.getS()); - m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); + m_selectedLightPiece = getLightIndex(m_selectedColor.getX(m_gamma)); update(); } void KisColorSelector::setFgColor(const KisColor& fgColor) { if (!m_widgetUpdatesSelf) { m_fgColor = KisColor(fgColor, m_colorSpace); + m_selectedColor = KisColor(fgColor, m_colorSpace); + +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::setFgColor: m_fgColor set to:" << "H:" << m_fgColor.getH() << "S:" << m_fgColor.getS() - << "X:" << m_fgColor.getX(); + << "X:" << m_fgColor.getX(m_gamma); - m_selectedColor = KisColor(fgColor, m_colorSpace); dbgPlugins << "KisColorSelector::setFgColor: m_selectedColor set to:" << "H:" << m_selectedColor.getH() << "S:" << m_selectedColor.getS() - << "X:" << m_selectedColor.getX(); + << "X:" << m_selectedColor.getX(m_gamma); +#endif update(); - } else { - dbgPlugins << "KisColorSelector::setFgColor: m_widgetUpdatesSelf == true, not updating color"; } } void KisColorSelector::setBgColor(const KisColor& bgColor) { if (!m_widgetUpdatesSelf) { m_bgColor = KisColor(bgColor, m_colorSpace); +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::setBgColor: m_bgColor set to:" << "H:" << m_bgColor.getH() << "S:" << m_bgColor.getS() - << "X:" << m_bgColor.getX(); + << "X:" << m_bgColor.getX(m_gamma); +#endif update(); - } else { - dbgPlugins << "KisColorSelector::setBgColor: m_widgetUpdatesSelf == true, not updating color"; } } -void KisColorSelector::resetRings() +void KisColorSelector::setLight(float light) { - for(int i=0; i= 0) { - m_colorRings[m_selectedRing].angle = 0.0f; - update(); +void KisColorSelector::setGamma(float gamma) { + if (m_colorSpace == KisColor::HSY) { + m_gamma = gamma; + } else { + m_gamma = 1.0f; } -} -void KisColorSelector::setLight(float light, bool relative) -{ - m_light = qBound(0.0f, light, 1.0f); +#ifdef DEBUG_ARC_SELECTOR + dbgPlugins << "KisColorSelector::setGamma: set to:" << m_gamma; +#endif - m_selectedColor.setX(getLight(m_light, m_selectedColor.getH(), relative)); - m_relativeLight = relative; - m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); update(); } @@ -226,7 +219,6 @@ void KisColorSelector::setGamutMaskOn(bool gamutMaskOn) { - // do not allow the mask on, if it is a nullptr if (m_currentGamutMask) { m_gamutMaskOn = gamutMaskOn; update(); @@ -261,17 +253,39 @@ QPointF KisColorSelector::mapColorToUnit(const KisColor& color, bool invertSaturation) const { - qreal angle = color.getH() * 2.0 * M_PI; - qreal radius; if (invertSaturation && m_inverseSaturation) { radius = 1.0 - color.getS(); } else { radius = color.getS(); } - qreal x = std::cos(angle)*radius; - qreal y = std::sin(-angle)*radius; + QPointF hueCoord = mapHueToAngle(color.getH()); + qreal x = hueCoord.x()*radius; + qreal y = hueCoord.y()*radius; + + return QPointF(x,y); +} + +KisColorSelector::Radian KisColorSelector::mapCoordToAngle(qreal x, qreal y) const +{ + float angle = std::atan2(-y, -x); + +#ifdef DEBUG_ARC_SELECTOR + dbgPlugins << "KisColorSelector::mapCoordToAngle: " + << "X:" << x + << "Y:" << y + << "angle:" << angle; +#endif + + return angle; +} + +QPointF KisColorSelector::mapHueToAngle(float hue) const +{ + float angle = hue * 2.0 * M_PI - M_PI; + float x = std::cos(angle); + float y = std::sin(angle); return QPointF(x,y); } @@ -295,18 +309,6 @@ return qint8(qRound(light * (getNumLightPieces()-1))); } -qreal KisColorSelector::getLight(qreal light, qreal hue, bool relative) const -{ - if (relative) { - KisColor color(hue, 1.0f, m_colorSpace); - qreal cl = color.getX(); - light = (light * 2.0f) - 1.0f; - return (light < 0.0f) ? (cl + cl*light) : (cl + (1.0f-cl)*light); - } - - return light; -} - qreal KisColorSelector::getLight(const QPointF& pt) const { qint8 clickedLightPiece = getLightIndex(pt); @@ -321,9 +323,8 @@ return qreal(0); } -qint8 KisColorSelector::getHueIndex(Radian hue, Radian shift) const +qint8 KisColorSelector::getHueIndex(Radian hue) const { - hue -= shift; qreal partSize = 1.0 / qreal(getNumPieces()); return qint8(qRound(hue.scaled(0.0f, 1.0f) / partSize) % getNumPieces()); } @@ -362,7 +363,11 @@ void KisColorSelector::recalculateAreas(quint8 numLightPieces) { - const qreal LIGHT_STRIP_RATIO = 0.075; + + qreal LIGHT_STRIP_RATIO = 0.075; + if (m_showValueScaleNumbers) { + LIGHT_STRIP_RATIO = 0.25; + } int width = QWidget::width(); int height = QWidget::height(); @@ -451,11 +456,12 @@ void KisColorSelector::requestUpdateColorAndPreview(const KisColor &color, Acs::ColorRole role) { +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::requestUpdateColorAndPreview: requesting update to: " << "H:" << color.getH() << "S:" << color.getS() - << "X:" << color.getX(); - + << "X:" << color.getX(m_gamma); +#endif m_updateColorCompressor->start(qMakePair(color, role)); } @@ -466,52 +472,52 @@ if (selectAsFgColor) { m_fgColor = color.first; } else { m_bgColor = color.first; } - m_selectedColor = color.first; - m_selectedColorRole = color.second; + m_selectedColor = color.first; +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::slotUpdateColorAndPreview: m_selectedColor set to:" << "H:" << m_selectedColor.getH() << "S:" << m_selectedColor.getS() - << "X:" << m_selectedColor.getX() - << "role:" << m_selectedColorRole; - + << "X:" << m_selectedColor.getX(m_gamma); +#endif if (selectAsFgColor) { emit sigFgColorChanged(m_selectedColor); } else { emit sigBgColorChanged(m_selectedColor); } } -void KisColorSelector::drawRing(QPainter& painter, int ringIndex, KisColorSelector::ColorRing& ring, const QRect& rect) +void KisColorSelector::drawRing(QPainter& painter, KisColorSelector::ColorRing& ring, const QRect& rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.width()/2, rect.height()/2); if (ring.pieced.size() > 1) { - painter.rotate(-ring.getShift().degrees()); + QTransform mirror; + mirror.rotate(180, Qt::YAxis); + painter.setTransform(mirror, true); painter.scale(rect.width()/2, rect.height()/2); -// painter.setPen(Qt::NoPen); - QPen normalPen = QPen(QBrush(m_grayColor), 0.005); - QPen clearMaskPen = QPen(QBrush(Qt::white), 0.005); + QPen normalPen = QPen(QBrush(COLOR_NORMAL_OUTLINE), 0.005); + QPen clearMaskPen = QPen(QBrush(COLOR_MASK_CLEAR), 0.005); QBrush brush(Qt::SolidPattern); for(int i=0; i= 1.0f) ? (hue - 1.0f) : hue; hue = (hue < 0.0f) ? (hue + 1.0f) : hue; KisColor color(hue, 1.0f, m_colorSpace); color.setS(ring.saturation); - color.setX(getLight(m_light, hue, m_relativeLight)); + color.setX(m_selectedColor.getX(m_gamma), m_gamma); if(m_gamutMaskOn && m_enforceGamutMask && colorIsClear(color)) { painter.setPen(clearMaskPen); } else { painter.setPen(normalPen); } if ((m_enforceGamutMask) && (!colorIsClear(color))) { - brush.setColor(m_gamutMaskColor); + brush.setColor(COLOR_MASK_FILL); } else { brush.setColor(color.getQColor()); } @@ -522,29 +528,28 @@ } else { KisColor colors[7] = { - KisColor(Qt::red , m_colorSpace), - KisColor(Qt::yellow , m_colorSpace), - KisColor(Qt::green , m_colorSpace), KisColor(Qt::cyan , m_colorSpace), - KisColor(Qt::blue , m_colorSpace), + KisColor(Qt::green , m_colorSpace), + KisColor(Qt::yellow , m_colorSpace), + KisColor(Qt::red , m_colorSpace), KisColor(Qt::magenta, m_colorSpace), - KisColor(Qt::red , m_colorSpace) + KisColor(Qt::blue , m_colorSpace), + KisColor(Qt::cyan , m_colorSpace) }; QConicalGradient gradient(0, 0, 0); for(int i=0; i<=6; ++i) { qreal hue = float(i) / 6.0f; colors[i].setS(ring.saturation); - colors[i].setX(getLight(m_light, hue, m_relativeLight)); + colors[i].setX(m_selectedColor.getX(m_gamma), m_gamma); gradient.setColorAt(hue, colors[i].getQColor()); } painter.scale(rect.width()/2, rect.height()/2); painter.fillPath(ring.pieced[0], QBrush(gradient)); } -// painter.resetTransform(); painter.restore(); } @@ -555,26 +560,18 @@ painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); painter.scale(rect.width()/2, rect.height()/2); - QPen normalPen = QPen(QBrush(m_grayColor), 0.005); - QPen selectedPen = QPen(QBrush(Qt::red), 0.01); + QPen normalPen = QPen(QBrush(COLOR_NORMAL_OUTLINE), 0.005); + QPen selectedPen = QPen(QBrush(COLOR_SELECTED), 0.01); painter.setPen(normalPen); if (getNumPieces() > 1) { -// for(int i=0; i= 0 && m_selectedPiece >= 0) { painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); - painter.rotate(-m_colorRings[m_selectedRing].getShift().degrees()); + QTransform mirror; + mirror.rotate(180, Qt::YAxis); + painter.setTransform(mirror, true); painter.scale(rect.width()/2, rect.height()/2); painter.setPen(selectedPen); @@ -595,86 +592,124 @@ painter.drawEllipse(QRectF(-iRad, -iRad, iRad*2.0, iRad*2.0)); painter.drawEllipse(QRectF(-oRad, -oRad, oRad*2.0, oRad*2.0)); - float c = std::cos(-m_selectedColor.getH() * PI2); - float s = std::sin(-m_selectedColor.getH() * PI2); - painter.drawLine(QPointF(c*iRad, s*iRad), QPointF(c*oRad, s*oRad)); + QPointF lineCoords = mapHueToAngle(m_selectedColor.getH()); + painter.drawLine(QPointF(lineCoords.x()*iRad, lineCoords.y()*iRad), QPointF(lineCoords.x()*oRad, lineCoords.y()*oRad)); } } } void KisColorSelector::drawLightStrip(QPainter& painter, const QRect& rect) { - bool isVertical = true; qreal penSize = qreal(qMin(QWidget::width(), QWidget::height())) / 200.0; - KisColor color(m_fgColor); + KisColor valueScaleColor(m_selectedColor); + KisColor grayScaleColor(Qt::gray, m_colorSpace); + int rectSize = rect.height(); painter.resetTransform(); + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); - if (getNumLightPieces() > 1) { - painter.setRenderHint(QPainter::Antialiasing, true); - painter.setPen(QPen(QBrush(Qt::red), penSize)); + QTransform matrix; + matrix.translate(rect.x(), rect.y()); + matrix.scale(rect.width(), rect.height()); - QTransform matrix; - matrix.translate(rect.x(), rect.y()); - matrix.scale(rect.width(), rect.height()); + qreal rectColorLeftX; + qreal rectColorWidth; + if (m_showValueScaleNumbers) { + rectColorLeftX = 0.6; + rectColorWidth = 0.4; + } else { + rectColorLeftX = 0.0; + rectColorWidth = 1.0; + } + + if (getNumLightPieces() > 1) { for(int i=0; i coord X:" << fgColorPos.x() << " Y:" << fgColorPos.y(); +#endif - - painter.setPen(QPen(QBrush(Qt::white), 0.01)); + painter.setPen(QPen(QBrush(COLOR_LIGHT), 0.01)); painter.drawEllipse(fgColorPos, 0.05, 0.05); - painter.setPen(QPen(QBrush(Qt::black), 0.01)); + painter.setPen(QPen(QBrush(COLOR_DARK), 0.01)); painter.setBrush(m_fgColor.getQColor()); painter.drawEllipse(fgColorPos, 0.04, 0.04); } @@ -709,16 +745,18 @@ painter.scale(rect.width()/2, rect.height()/2); painter.setPen(Qt::NoPen); - painter.setBrush(m_gamutMaskColor); + painter.setBrush(COLOR_MASK_FILL); painter.drawEllipse(QPointF(0,0), 1.0, 1.0); painter.resetTransform(); -// painter.setCompositionMode(QPainter::CompositionMode_Xor); - painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); m_currentGamutMask->paint(painter, *m_viewConverter, m_maskPreviewActive); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + m_currentGamutMask->paintStroke(painter, *m_viewConverter, m_maskPreviewActive); + painter.restore(); } @@ -762,11 +800,10 @@ wdgPainter.restore(); for(int i=0; ilocalPos(), m_renderArea); m_mouseMoved = false; m_pressedButtons = event->buttons(); m_clickedRing = getSaturationIndex(m_clickPos); + Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); qint8 clickedLightPiece = getLightIndex(event->localPos()); if (clickedLightPiece >= 0) { - setLight(getLight(event->localPos()), m_relativeLight); + setLight(getLight(event->localPos())); m_selectedLightPiece = clickedLightPiece; - requestUpdateColorAndPreview(m_selectedColor, Acs::buttonsToRole(Qt::NoButton, m_pressedButtons)); + requestUpdateColorAndPreview(m_selectedColor, colorRole); m_mouseMoved = true; } else if (m_clickedRing >= 0) { - if (getNumPieces() > 1) { - for(int i=0; ilocalPos(), m_renderArea); qint8 clickedLightPiece = getLightIndex(event->localPos()); + Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); if (clickedLightPiece >= 0) { - setLight(getLight(event->localPos()), m_relativeLight); + setLight(getLight(event->localPos())); m_selectedLightPiece = clickedLightPiece; - requestUpdateColorAndPreview(m_selectedColor, m_selectedColorRole); + requestUpdateColorAndPreview(m_selectedColor, colorRole); } if (m_clickedRing < 0) return; - if (getNumPieces() > 1) { - float angle = std::atan2(dragPos.x(), dragPos.y()) - std::atan2(m_clickPos.x(), m_clickPos.y()); - float dist = std::sqrt(dragPos.x()*dragPos.x() + dragPos.y()*dragPos.y()) * 0.80f; - float threshold = 5.0f * (1.0f-(dist*dist)); - - if (qAbs(angle * TO_DEG) >= threshold || m_mouseMoved) { - bool selectedRingMoved = true; - - if (m_pressedButtons & Qt::RightButton) { - selectedRingMoved = m_clickedRing == m_selectedRing; - m_colorRings[m_clickedRing].angle = m_colorRings[m_clickedRing].tmpAngle + angle; - } - else for(int i=0; i= 0) { - Radian angle = std::atan2(m_clickPos.x(), m_clickPos.y()) - RAD_90; - KisColor color; + Radian angle = mapCoordToAngle(m_clickPos.x(), m_clickPos.y()); + KisColor color(m_colorSpace); - qint8 hueIndex = getHueIndex(angle, m_colorRings[m_clickedRing].getShift()); + qint8 hueIndex = getHueIndex(angle); if (getNumPieces() > 1) { - color.setH(getHue(hueIndex, m_colorRings[m_clickedRing].getShift())); + color.setH(getHue(hueIndex)); } else { color.setH(angle.scaled(0.0f, 1.0f)); } color.setS(getSaturation(m_clickedRing)); - color.setX(getLight(m_light, color.getH(), m_relativeLight)); + color.setX(m_selectedColor.getX(m_gamma), m_gamma); if ((!m_enforceGamutMask) || colorIsClear(color)) { - m_selectedColor.setHSX(color.getH(), color.getS(), color.getX()); + m_selectedColor.setHSX(color.getH(), color.getS(), color.getX(m_gamma), color.getA(), m_gamma); m_selectedPiece = hueIndex; m_selectedRing = m_clickedRing; - requestUpdateColorAndPreview(m_selectedColor, Acs::buttonsToRole(Qt::NoButton, m_pressedButtons)); + requestUpdateColorAndPreview(m_selectedColor, colorRole); } } else if (m_mouseMoved) - requestUpdateColorAndPreview(m_selectedColor, m_selectedColorRole); + requestUpdateColorAndPreview(m_selectedColor, colorRole); m_clickedRing = -1; m_widgetUpdatesSelf = false; +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::ReleasePressEvent: m_widgetUpdatesSelf = false"; +#endif update(); } @@ -934,7 +958,9 @@ void KisColorSelector::leaveEvent(QEvent* /*e*/) { m_widgetUpdatesSelf = false; +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::leaveEvent: m_widgetUpdatesSelf = false"; +#endif } void KisColorSelector::saveSettings() @@ -946,67 +972,60 @@ cfg.writeEntry("ArtColorSel.LightPieces", qint32(m_numLightPieces)); cfg.writeEntry("ArtColorSel.InversedSaturation", m_inverseSaturation); - cfg.writeEntry("ArtColorSel.RelativeLight" , m_relativeLight); - cfg.writeEntry("ArtColorSel.Light" , m_light); + cfg.writeEntry("ArtColorSel.Light" , m_selectedColor.getX(m_gamma)); cfg.writeEntry("ArtColorSel.SelColorH", m_selectedColor.getH()); cfg.writeEntry("ArtColorSel.SelColorS", m_selectedColor.getS()); - cfg.writeEntry("ArtColorSel.SelColorX", m_selectedColor.getX()); + cfg.writeEntry("ArtColorSel.SelColorX", m_selectedColor.getX(m_gamma)); cfg.writeEntry("ArtColorSel.SelColorA", m_selectedColor.getA()); cfg.writeEntry("ArtColorSel.defaultHueSteps", quint32(m_defaultHueSteps)); cfg.writeEntry("ArtColorSel.defaultSaturationSteps", quint32(m_defaultSaturationSteps)); cfg.writeEntry("ArtColorSel.defaultValueScaleSteps", quint32(m_defaultValueScaleSteps)); cfg.writeEntry("ArtColorSel.showBgColor", m_showBgColor); cfg.writeEntry("ArtColorSel.showColorBlip", m_showColorBlip); - cfg.writeEntry("ArtColorSel.showValueScaleNumber", m_showValueScaleNumbers); + cfg.writeEntry("ArtColorSel.showValueScale", m_showValueScaleNumbers); cfg.writeEntry("ArtColorSel.enforceGamutMask", m_enforceGamutMask); cfg.writeEntry("ArtColorSel.maskPreviewActive", m_maskPreviewActive); - - QList angles; - - for(int i=0; i("ArtColorSel.ColorSpace" , KisColor::HSY))); m_defaultHueSteps = cfg.readEntry("ArtColorSel.defaultHueSteps", DEFAULT_HUE_STEPS); m_defaultSaturationSteps = cfg.readEntry("ArtColorSel.defaultSaturationSteps", DEFAULT_SATURATION_STEPS); m_defaultValueScaleSteps = cfg.readEntry("ArtColorSel.defaultValueScaleSteps", DEFAULT_VALUE_SCALE_STEPS); setNumLightPieces(cfg.readEntry("ArtColorSel.LightPieces", DEFAULT_VALUE_SCALE_STEPS)); + KisColor::Type colorSpace = KisColor::Type(cfg.readEntry("ArtColorSel.ColorSpace" , KisColor::HSY)); + float valueScaleGamma = cfg.readEntry("ArtColorSel.valueScaleGamma", 2.2f); + if (colorSpace == KisColor::HSY) { + setGamma(valueScaleGamma); + + } + + setColorSpace(colorSpace, valueScaleGamma); + m_selectedColor.setH(cfg.readEntry("ArtColorSel.SelColorH", 0.0f)); m_selectedColor.setS(cfg.readEntry("ArtColorSel.SelColorS", 0.0f)); - m_selectedColor.setX(cfg.readEntry("ArtColorSel.SelColorX", 0.0f)); + m_selectedColor.setX(cfg.readEntry("ArtColorSel.SelColorX", 0.0f), m_gamma); m_selectedColor.setA(1.0f); setInverseSaturation(cfg.readEntry("ArtColorSel.InversedSaturation", false)); - setLight(cfg.readEntry("ArtColorSel.Light", 0.5f), cfg.readEntry("ArtColorSel.RelativeLight", true)); + setLight(cfg.readEntry("ArtColorSel.Light", 0.5f)); - setNumRings(cfg.readEntry("ArtColorSel.NumRings" , DEFAULT_SATURATION_STEPS)); + setNumRings(cfg.readEntry("ArtColorSel.NumRings", DEFAULT_SATURATION_STEPS)); setNumPieces(cfg.readEntry("ArtColorSel.RingPieces", DEFAULT_HUE_STEPS)); - QList angles = cfg.readList("ArtColorSel.RingAngles"); - - for (int i = 0; i < m_colorRings.size(); ++i) { - if (i < angles.size() && i < m_colorRings.size()) { - m_colorRings[i].angle = angles[i]; - } - } - m_showBgColor = cfg.readEntry("ArtColorSel.showBgColor", true); m_showColorBlip = cfg.readEntry("ArtColorSel.showColorBlip", true); - m_showValueScaleNumbers = cfg.readEntry("ArtColorSel.showValueScaleNumber", false); - m_enforceGamutMask = cfg.readEntry("ArtColorSel.enforceGamutMask", true); + m_showValueScaleNumbers = cfg.readEntry("ArtColorSel.showValueScale", false); + m_enforceGamutMask = cfg.readEntry("ArtColorSel.enforceGamutMask", false); m_maskPreviewActive = cfg.readEntry("ArtColorSel.maskPreviewActive", true); @@ -1046,6 +1065,7 @@ void KisColorSelector::setShowValueScaleNumbers(bool value) { m_showValueScaleNumbers = value; + recalculateAreas(quint8(getNumLightPieces())); update(); } diff --git a/plugins/dockers/gamutmask/KisGamutMaskChooser.h b/plugins/dockers/gamutmask/KisGamutMaskChooser.h --- a/plugins/dockers/gamutmask/KisGamutMaskChooser.h +++ b/plugins/dockers/gamutmask/KisGamutMaskChooser.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef KISGAMUTMASKCHOOSER_H #define KISGAMUTMASKCHOOSER_H @@ -14,6 +31,8 @@ explicit KisGamutMaskChooser(QWidget *parent = nullptr); ~KisGamutMaskChooser() override; + void setCurrentResource(KoResource* resource); + Q_SIGNALS: void sigGamutMaskSelected(KoGamutMask* mask); diff --git a/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp b/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp --- a/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp +++ b/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2018 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include "KisGamutMaskChooser.h" #include @@ -64,6 +81,8 @@ QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0,0,0,0); + // TODO: menu for view mode change + layout->addWidget(m_itemChooser); setLayout(layout); @@ -75,6 +94,11 @@ } +void KisGamutMaskChooser::setCurrentResource(KoResource *resource) +{ + m_itemChooser->setCurrentResource(resource); +} + void KisGamutMaskChooser::resourceSelected(KoResource* resource) { emit sigGamutMaskSelected(static_cast(resource)); diff --git a/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui b/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui --- a/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui +++ b/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui @@ -6,8 +6,8 @@ 0 0 - 358 - 336 + 363 + 322 @@ -22,51 +22,81 @@ - - - - - - 0 - 0 - - - - Select a mask - - - - - - - Apply To Selector - - - - - - - - - - Edit - - - - - - - - - - Delete - - - - - - - + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Create new mask + + + + + + + + + + Edit selected mask + + + + + + + + + + Duplicate selected mask + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete selected mask + + + + + + + + @@ -184,16 +214,6 @@ - - - - Save As New - - - - - - diff --git a/plugins/dockers/gamutmask/gamutmask_dock.h b/plugins/dockers/gamutmask/gamutmask_dock.h --- a/plugins/dockers/gamutmask/gamutmask_dock.h +++ b/plugins/dockers/gamutmask/gamutmask_dock.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -35,7 +36,6 @@ #include class KisCanvasResourceProvider; -class KisColor; class QButtonGroup; class QMenu; @@ -55,7 +55,7 @@ public: // KoResourceServerObserver void unsetResourceServer() override; - void resourceAdded(KoGamutMask* resource) override {} + void resourceAdded(KoGamutMask* /*resource*/) override {}; void removingResource(KoGamutMask* resource) override; void resourceChanged(KoGamutMask* resource) override; void syncTaggedResourceView() override {} @@ -74,29 +74,42 @@ void slotGamutMaskCancelEdit(); void slotGamutMaskSelected(KoGamutMask* mask); void slotGamutMaskPreview(); - void slotGamutMaskSaveNew(); + void slotGamutMaskCreateNew(); + void slotGamutMaskDuplicate(); void slotGamutMaskDelete(); - void slotGamutMaskSet(); void slotDocumentRemoved(QString filename); + void slotViewChanged(); + void slotDocumentSaved(); private: - KisCanvasResourceProvider* m_resourceProvider; - void closeMaskDocument(); void openMaskEditor(); void cancelMaskEdit(); - void saveSelectedMaskResource(); - void finalizeMaskSave(); + void selectMask(KoGamutMask* mask, bool notifyItemChooser = true); + bool saveSelectedMaskResource(); + void deleteMask(); + int getUserFeedback(QString message + , QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No + , QMessageBox::StandardButton defaultButton = QMessageBox::Yes); + + int saveOrCancel(QMessageBox::StandardButton defaultAction = QMessageBox::Save); - bool m_selfClosingMaskFile; + KoGamutMask* createMaskResource(KoGamutMask* sourceMask, QString newTitle); - KoGamutMask *addDuplicateResource(QString newTitle); QPair resolveMaskTitle(QString suggestedTitle); QList getShapesFromLayer(); KisShapeLayerSP getShapeLayer(); + KisCanvasResourceProvider* m_resourceProvider; + + bool m_selfClosingTemplate; + bool m_externalTemplateClose; + bool m_creatingNewMask; + bool m_templatePrevSaved; + bool m_selfSelectingMask; + GamutMaskChooserUI* m_dockerUI; KoResourceItemChooser* m_maskChooser; diff --git a/plugins/dockers/gamutmask/gamutmask_dock.cpp b/plugins/dockers/gamutmask/gamutmask_dock.cpp --- a/plugins/dockers/gamutmask/gamutmask_dock.cpp +++ b/plugins/dockers/gamutmask/gamutmask_dock.cpp @@ -46,6 +46,10 @@ #include "gamutmask_dock.h" #include #include +#include +#include + +#include #include "ui_wdgGamutMaskChooser.h" @@ -62,23 +66,28 @@ GamutMaskDock::GamutMaskDock() : QDockWidget(i18n("Gamut Masks")) , m_resourceProvider(0) + , m_selfClosingTemplate(false) + , m_externalTemplateClose(false) + , m_creatingNewMask(false) + , m_templatePrevSaved(false) + , m_selfSelectingMask(false) + , m_selectedMask(nullptr) , m_maskDocument(nullptr) , m_view(nullptr) - , m_selectedMask(nullptr) { m_dockerUI = new GamutMaskChooserUI(); m_dockerUI->bnMaskEditor->setIcon(KisIconUtils::loadIcon("dirty-preset")); - m_dockerUI->bnMaskSet->setIcon(KisIconUtils::loadIcon("dialog-ok")); m_dockerUI->bnMaskDelete->setIcon(KisIconUtils::loadIcon("deletelayer")); - m_dockerUI->maskPropertiesBox->setVisible(false); + m_dockerUI->bnMaskNew->setIcon(KisIconUtils::loadIcon("list-add")); + m_dockerUI->bnMaskDuplicate->setIcon(KisIconUtils::loadIcon("duplicatelayer")); - m_dockerUI->bnSaveMaskNew->setIcon(KisIconUtils::loadIcon("list-add")); + m_dockerUI->maskPropertiesBox->setVisible(false); m_dockerUI->bnSaveMask->setIcon(KisIconUtils::loadIcon("document-save")); m_dockerUI->bnCancelMaskEdit->setIcon(KisIconUtils::loadIcon("dialog-cancel")); m_dockerUI->bnPreviewMask->setIcon(KisIconUtils::loadIcon("visible")); - QRegularExpression maskTitleRegex("^[-_\\sA-Za-z0-9]+$"); + QRegularExpression maskTitleRegex("^[-_\\(\\)\\sA-Za-z0-9]+$"); QRegularExpressionValidator* m_maskTitleValidator = new QRegularExpressionValidator(maskTitleRegex, this); m_dockerUI->maskTitleEdit->setValidator(m_maskTitleValidator); @@ -92,9 +101,9 @@ connect(m_dockerUI->bnMaskEditor , SIGNAL(clicked()) , SLOT(slotGamutMaskEdit())); connect(m_dockerUI->maskChooser, SIGNAL(sigGamutMaskSelected(KoGamutMask*)), SLOT(slotGamutMaskSelected(KoGamutMask*))); - connect(m_dockerUI->bnSaveMaskNew , SIGNAL(clicked()) , SLOT(slotGamutMaskSaveNew())); - connect(m_dockerUI->bnMaskSet , SIGNAL(clicked()) , SLOT(slotGamutMaskSet())); + connect(m_dockerUI->bnMaskNew , SIGNAL(clicked()) , SLOT(slotGamutMaskCreateNew())); connect(m_dockerUI->bnMaskDelete , SIGNAL(clicked()) , SLOT(slotGamutMaskDelete())); + connect(m_dockerUI->bnMaskDuplicate , SIGNAL(clicked()) , SLOT(slotGamutMaskDuplicate())); setWidget(m_dockerUI); } @@ -109,7 +118,7 @@ { m_resourceProvider = kisview->resourceProvider(); - m_selectedMask = m_resourceProvider->currentGamutMask(); + selectMask(m_resourceProvider->currentGamutMask()); connect(this, SIGNAL(sigGamutMaskSet(KoGamutMask*)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); connect(this, SIGNAL(sigGamutMaskChanged(KoGamutMask*)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); @@ -128,93 +137,207 @@ void GamutMaskDock::openMaskEditor() { - m_dockerUI->maskPropertiesBox->setVisible(true); - - //shouldnt be nullptr here if (!m_selectedMask) { return; } + m_dockerUI->maskPropertiesBox->setVisible(true); + m_dockerUI->maskPropertiesBox->setEnabled(true); + m_dockerUI->editControlsBox->setEnabled(false); + m_dockerUI->editControlsBox->setVisible(false); + m_dockerUI->maskTitleEdit->setText(m_selectedMask->title()); m_dockerUI->maskDescriptionEdit->setPlainText(m_selectedMask->description()); // open gamut mask template in the application QString maskTemplateFile = KoResourcePaths::findResource("data", "gamutmasks/GamutMaskTemplate.kra"); - dbgPlugins << "GamutMaskDock::slotGamutMaskEdit: maskTemplateFile" - << maskTemplateFile; - // open template document m_maskDocument = KisPart::instance()->createDocument(); KisPart::instance()->addDocument(m_maskDocument); m_maskDocument->openUrl(QUrl::fromLocalFile(maskTemplateFile), KisDocument::DontAddToRecent); - m_maskDocument->resetURL(); + + // template document needs a proper autogenerated filename, + // to avoid collision with other documents, + // otherwise bugs happen when slotDocumentRemoved is called + // (e.g. user closes another view, the template stays open, but the edit operation is canceled) + m_maskDocument->setInfiniteAutoSaveInterval(); + QString maskPath = QString("%1%2%3_%4.kra") + .arg(QDir::tempPath()) + .arg(QDir::separator()) + .arg("GamutMaskTemplate") + .arg(std::time(nullptr)); + m_maskDocument->setUrl(QUrl::fromLocalFile(maskPath)); + m_maskDocument->setLocalFilePath(maskPath); KisShapeLayerSP shapeLayer = getShapeLayer(); // pass only copies of shapes to the layer, // so the originals don't disappear from the mask later for (KoShape *shape: m_selectedMask->koShapes()) { - shapeLayer->addShape(shape->cloneShape()); + KoShape* newShape = shape->cloneShape(); + newShape->setStroke(KoShapeStrokeModelSP()); + newShape->setBackground(QSharedPointer(new KoColorBackground(QColor(255,255,255)))); + shapeLayer->addShape(newShape); } m_maskDocument->setPreActivatedNode(shapeLayer); // set document as active KisMainWindow* mainWindow = KisPart::instance()->currentMainwindow(); - Q_ASSERT(mainWindow); + KIS_ASSERT(mainWindow); m_view = mainWindow->addViewAndNotifyLoadingCompleted(m_maskDocument); - Q_ASSERT(m_view); + KIS_ASSERT(m_view); for(KisView *view: KisPart::instance()->views()) { if (view->document() == m_maskDocument) { view->activateWindow(); break; } } + + connect(m_view->viewManager(), SIGNAL(viewChanged()), this, SLOT(slotViewChanged())); + connect(m_maskDocument, SIGNAL(completed()), this, SLOT(slotDocumentSaved())); } void GamutMaskDock::cancelMaskEdit() { + if (m_creatingNewMask) { + deleteMask(); + } + if (m_selectedMask) { m_selectedMask->clearPreview(); - m_dockerUI->maskPropertiesBox->setVisible(false); - if (m_resourceProvider->currentGamutMask() == m_selectedMask) { emit sigGamutMaskChanged(m_selectedMask); } } + + closeMaskDocument(); } -void GamutMaskDock::saveSelectedMaskResource() +void GamutMaskDock::selectMask(KoGamutMask *mask, bool notifyItemChooser) { + if (!mask) { + return; + } + + m_selectedMask = mask; + + if (notifyItemChooser) { + m_selfSelectingMask = true; + m_dockerUI->maskChooser->setCurrentResource(m_selectedMask); + m_selfSelectingMask = false; + } + + emit sigGamutMaskSet(m_selectedMask); +} + +bool GamutMaskDock::saveSelectedMaskResource() +{ + if (!m_selectedMask || !m_maskDocument) { + return false; + } + + bool maskSaved = false; + if (m_selectedMask) { - m_selectedMask->setDescription(m_dockerUI->maskDescriptionEdit->toPlainText()); + QList shapes = getShapesFromLayer(); - m_selectedMask->setMaskShapes(getShapesFromLayer()); + if (shapes.count() > 0) { + m_selectedMask->setMaskShapes(shapes); - m_selectedMask->setImage( - m_maskDocument->image()->convertToQImage(m_maskDocument->image()->bounds() - , m_maskDocument->image()->profile() - ) - ); + m_selectedMask->setImage( + m_maskDocument->image()->convertToQImage(m_maskDocument->image()->bounds() + , m_maskDocument->image()->profile() + ) + ); - m_selectedMask->clearPreview(); - m_selectedMask->save(); + m_selectedMask->setDescription(m_dockerUI->maskDescriptionEdit->toPlainText()); + + m_selectedMask->clearPreview(); + m_selectedMask->save(); + maskSaved = true; + } else { + getUserFeedback(i18n("

Saving of gamut mask '%1' was aborted.

" + "

The mask template is invalid.

" + "

Please check that:" + "

    " + "
  • your template contains a vector layer named 'maskShapesLayer'
  • " + "
  • there are one or more vector shapes on the 'maskShapesLayer'
  • " + "

" + , m_selectedMask->title()), + QMessageBox::Ok, QMessageBox::Ok); + } } + + return maskSaved; } -void GamutMaskDock::finalizeMaskSave() +void GamutMaskDock::deleteMask() { - closeMaskDocument(); - m_dockerUI->maskPropertiesBox->setVisible(false); + KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); + rServer->removeResourceAndBlacklist(m_selectedMask); + m_selectedMask = nullptr; } -KoGamutMask* GamutMaskDock::addDuplicateResource(QString newTitle) +int GamutMaskDock::getUserFeedback(QString message, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - // construct a copy - KoGamutMask* newMask = new KoGamutMask(m_selectedMask); + int res = QMessageBox::warning(this, + i18nc("@title:window", "Krita"), + message, + buttons, defaultButton); + + return res; +} + +int GamutMaskDock::saveOrCancel(QMessageBox::StandardButton defaultAction) +{ + int response = 0; + + if (m_maskDocument->isModified()) { + response = getUserFeedback(i18n("

Gamut mask '%1' has been modified.

Do you want to save it?

" + , m_selectedMask->title()), + QMessageBox::Cancel | QMessageBox::Close | QMessageBox::Save, defaultAction); + + } else if (m_templatePrevSaved && defaultAction != QMessageBox::Close) { + response = QMessageBox::Save; + + } else if (!m_templatePrevSaved) { + response = QMessageBox::Close; + + } else { + response = defaultAction; + } + + switch (response) { + case QMessageBox::Save : { + slotGamutMaskSave(); + break; + } + case QMessageBox::Close : { + cancelMaskEdit(); + break; + } + } + + return response; +} + +KoGamutMask *GamutMaskDock::createMaskResource(KoGamutMask* sourceMask, QString newTitle) +{ + m_creatingNewMask = true; + + KoGamutMask* newMask = nullptr; + if (sourceMask) { + newMask = new KoGamutMask(sourceMask); + newMask->setImage(sourceMask->image()); + } else { + newMask = new KoGamutMask(); + QString defaultPreviewPath = KoResourcePaths::findResource("data", "gamutmasks/empty_mask_preview.png"); + newMask->setImage(QImage(defaultPreviewPath, "PNG")); + } QPair maskFile = resolveMaskTitle(newTitle); QString maskTitle = maskFile.first; @@ -226,64 +349,68 @@ newMask->setValid(true); KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); + rServer->removeFromBlacklist(newMask); rServer->addResource(newMask, false); - - return newMask; } QPair GamutMaskDock::resolveMaskTitle(QString suggestedTitle) { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); QString saveLocation = rServer->saveLocation(); - QString processedTitle = suggestedTitle.trimmed(); - QString newFilename = saveLocation + processedTitle.replace(QRegularExpression("\\s+"), "_") + ".kgm"; - - QFileInfo fileInfo(newFilename); - QStringList resourceBlacklist = rServer->blackListedFiles(); - - int i = 1; - int lastIndex = 0; - while (fileInfo.exists()) { - if (resourceBlacklist.contains(fileInfo.filePath())) { - // allow to overwrite blacklisted masks - break; - } else { - fileInfo.setFile(saveLocation + processedTitle + QString("%1").arg(i) + ".kgm"); - lastIndex = i; - i++; - } + QString resourceName = processedTitle; + while (rServer->resourceByName(resourceName)) { + resourceName = resourceName + QString(" (Copy)"); } - QString maskTitle = (lastIndex > 0) ? (processedTitle + QString("%1").arg(lastIndex)) : processedTitle; + QString maskTitle = resourceName; + QString maskFile = maskTitle + ".kgm"; + QString path = saveLocation + maskFile.replace(QRegularExpression("\\s+"), "_"); + QFileInfo fileInfo(path); return QPair(maskTitle, fileInfo); } void GamutMaskDock::closeMaskDocument() { - if (m_maskDocument) { - // HACK: set the document to not modified to bypass confirmation dialog - // the close is already confirmed - m_maskDocument->setModified(false); + if (!m_externalTemplateClose) { + if (m_maskDocument) { + // set the document to not modified to bypass confirmation dialog + // the close is already confirmed + m_maskDocument->setModified(false); + + m_maskDocument->closeUrl(); + m_view->closeView(); + m_view->deleteLater(); + + // set a flag that we are doing it ourselves, so the docker does not react to + // removing signal from KisPart + m_selfClosingTemplate = true; + KisPart::instance()->removeView(m_view); + KisPart::instance()->removeDocument(m_maskDocument); + m_selfClosingTemplate = false; + } + } - m_maskDocument->closeUrl(); - m_view->closeView(); - m_view->deleteLater(); + m_dockerUI->maskPropertiesBox->setVisible(false); + m_dockerUI->editControlsBox->setVisible(true); + m_dockerUI->editControlsBox->setEnabled(true); - // HACK: set a flag that we are doing it ourselves, so the docker does not react to - // removing signal from KisPart - m_selfClosingMaskFile = true; - KisPart::instance()->removeView(m_view); - KisPart::instance()->removeDocument(m_maskDocument); - m_selfClosingMaskFile = false; + disconnect(m_view->viewManager(), SIGNAL(viewChanged()), this, SLOT(slotViewChanged())); + disconnect(m_maskDocument, SIGNAL(completed()), this, SLOT(slotDocumentSaved())); - m_maskDocument = nullptr; - m_view = nullptr; + // the template file is meant as temporary, if the user saved it, delete now + if (QFile::exists(m_maskDocument->localFilePath())) { + QFile::remove(m_maskDocument->localFilePath()); } + + m_maskDocument = nullptr; + m_view = nullptr; + m_creatingNewMask = false; + m_templatePrevSaved = false; } QList GamutMaskDock::getShapesFromLayer() @@ -293,9 +420,15 @@ // create a deep copy of the shapes to save in the mask, // otherwise they vanish when the template closes QList newShapes; - for (KoShape* sh: shapeLayer->shapes()) { - KoShape* newShape = sh->cloneShape(); - newShapes.append(newShape); + + if (shapeLayer) { + for (KoShape* sh: shapeLayer->shapes()) { + KoShape* newShape = sh->cloneShape(); + KoShapeStrokeSP border(new KoShapeStroke(0.5f, Qt::white)); + newShape->setStroke(border); + newShape->setBackground(QSharedPointer(new KoColorBackground(QColor(255,255,255,0)))); + newShapes.append(newShape); + } } return newShapes; @@ -309,29 +442,25 @@ void GamutMaskDock::slotGamutMaskSave() { + if (!m_selectedMask || !m_maskDocument) { + return; + } + QString newTitle = m_dockerUI->maskTitleEdit->text(); - // was this mask previously set to selectors? - bool setToSelectors = (m_resourceProvider->currentGamutMask() == m_selectedMask); if (m_selectedMask->title() != newTitle) { // title has changed, rename - if (!m_selectedMask) { - return; - } - - // construct a copy - KoGamutMask* newMask = addDuplicateResource(newTitle); + KoGamutMask* newMask = createMaskResource(m_selectedMask, newTitle); // delete old mask and select new - slotGamutMaskDelete(); - m_selectedMask = newMask; + deleteMask(); + selectMask(newMask); } - saveSelectedMaskResource(); - finalizeMaskSave(); - - if (setToSelectors) { + bool maskSaved = saveSelectedMaskResource(); + if (maskSaved) { emit sigGamutMaskSet(m_selectedMask); + closeMaskDocument(); } } @@ -341,32 +470,7 @@ return; } - bool cancelApproved = false; - if (m_maskDocument->isModified()) { - int res = QMessageBox::warning(this, - i18nc("@title:window", "Krita"), - i18n("

Gamut mask '%1' has been modified.

Discard changes?

" - , m_selectedMask->title()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - - switch (res) { - case QMessageBox::Yes : { - cancelApproved = true; - break; - } - case QMessageBox::No : { - cancelApproved = false; - break; - } - } - } else { - cancelApproved = true; - } - - if (cancelApproved) { - cancelMaskEdit(); - closeMaskDocument(); - } + saveOrCancel(QMessageBox::Close); } void GamutMaskDock::slotGamutMaskPreview() @@ -381,12 +485,15 @@ void GamutMaskDock::slotGamutMaskSelected(KoGamutMask *mask) { - m_selectedMask = mask; + if (!m_selfSelectingMask) { + if (m_maskDocument) { + int res = saveOrCancel(); + if (res == QMessageBox::Cancel) { + return; + } + } - if (m_selectedMask) { - m_dockerUI->labelMaskName->setText(m_selectedMask->title()); - } else { - m_dockerUI->labelMaskName->setText(i18n("Select a mask")); + selectMask(mask, false); } } @@ -413,77 +520,84 @@ if (resource == m_resourceProvider->currentGamutMask()) { emit sigGamutMaskUnset(); m_selectedMask = nullptr; - m_dockerUI->labelMaskName->setText(i18n("Select a mask")); } } void GamutMaskDock::resourceChanged(KoGamutMask *resource) { // if currently set mask has been changed, notify selectors - // TODO: is m_resourceProvider->currentGamutMask() == m_selectedMask? if (resource == m_resourceProvider->currentGamutMask()) { - m_selectedMask = resource; - emit sigGamutMaskChanged(resource); + selectMask(resource); } } -void GamutMaskDock::slotGamutMaskSaveNew() +void GamutMaskDock::slotGamutMaskCreateNew() +{ + KoGamutMask* newMask = createMaskResource(nullptr, "new mask"); + selectMask(newMask); + openMaskEditor(); +} + +void GamutMaskDock::slotGamutMaskDuplicate() { if (!m_selectedMask) { return; } - KoGamutMask* newMask = addDuplicateResource(m_dockerUI->maskTitleEdit->text()); - m_selectedMask = newMask; - - saveSelectedMaskResource(); - finalizeMaskSave(); + KoGamutMask* newMask = createMaskResource(m_selectedMask, m_selectedMask->title()); + selectMask(newMask); + openMaskEditor(); } void GamutMaskDock::slotGamutMaskDelete() { if (!m_selectedMask) { return; } - int res = QMessageBox::warning(this, - i18nc("@title:window", "Krita"), - i18n("Are you sure you want to delete mask '%1'?" - , m_selectedMask->title()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + int res = getUserFeedback(i18n("Are you sure you want to delete mask '%1'?" + , m_selectedMask->title())); - // delete only if user confirms if (res == QMessageBox::Yes) { - KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); - // TODO: other resources do it this way, but the files stay on disk - rServer->removeResourceAndBlacklist(m_selectedMask); - - m_selectedMask = nullptr; - m_dockerUI->labelMaskName->setText(i18n("Select a mask")); + deleteMask(); } } -void GamutMaskDock::slotGamutMaskSet() -{ - if (!m_selectedMask) { - return; - } - - emit sigGamutMaskSet(m_selectedMask); -} - void GamutMaskDock::slotDocumentRemoved(QString filename) { if (!m_maskDocument) { return; } - // HACK: we do not want to run this if it is we who close the file - if (!m_selfClosingMaskFile) { + m_externalTemplateClose = true; + + // we do not want to run this if it is we who close the file + if (!m_selfClosingTemplate) { // KisPart called, that a document will be removed // if it's ours, cancel the mask edit operation if (m_maskDocument->url().toLocalFile() == filename) { - cancelMaskEdit(); + m_maskDocument->waitForSavingToComplete(); + saveOrCancel(); } } + + m_externalTemplateClose = false; +} + +void GamutMaskDock::slotViewChanged() +{ + if (!m_maskDocument || !m_view) { + return; + } + + if (m_view->viewManager()->document() == m_maskDocument) { + m_dockerUI->maskPropertiesBox->setEnabled(true); + } else { + m_dockerUI->maskPropertiesBox->setEnabled(false); + } +} + +void GamutMaskDock::slotDocumentSaved() +{ + m_templatePrevSaved = true; } diff --git a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp --- a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp +++ b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp @@ -295,6 +295,10 @@ else if (resType == "paintoppresets") { toplevel->setText(0, i18n("Brush Presets")); } + else if (resType == "gamutmasks") { + toplevel->setText(0, i18n("Gamut Masks")); + } + m_ui->listBundleContents->addTopLevelItem(toplevel); diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.h b/plugins/extensions/resourcemanager/dlg_create_bundle.h --- a/plugins/extensions/resourcemanager/dlg_create_bundle.h +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.h @@ -51,6 +51,7 @@ QStringList selectedPatterns() const { return m_selectedPatterns; } QStringList selectedPalettes() const { return m_selectedPalettes; } QStringList selectedWorkspaces() const { return m_selectedWorkspaces; } + QStringList selectedGamutMasks() const { return m_selectedGamutMasks; } private Q_SLOTS: @@ -72,6 +73,7 @@ QStringList m_selectedPatterns; QStringList m_selectedPalettes; QStringList m_selectedWorkspaces; + QStringList m_selectedGamutMasks; QString m_previewImage; diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp --- a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp @@ -126,6 +126,13 @@ } } } + else if (resType == "gamutmasks") { + Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + if (res) { + m_selectedGamutMasks << res->shortFilename(); + } + } + } } } else { @@ -150,6 +157,7 @@ m_ui->cmbResourceTypes->addItem(i18n("Brushes"), QString("brushes")); m_ui->cmbResourceTypes->addItem(i18n("Brush Presets"), QString("presets")); m_ui->cmbResourceTypes->addItem(i18n("Gradients"), QString("gradients")); + m_ui->cmbResourceTypes->addItem(i18n("Gamut Masks"), QString("gamutmasks")); m_ui->cmbResourceTypes->addItem(i18n("Patterns"), QString("patterns")); m_ui->cmbResourceTypes->addItem(i18n("Palettes"), QString("palettes")); m_ui->cmbResourceTypes->addItem(i18n("Workspaces"), QString("workspaces")); @@ -277,6 +285,9 @@ else if (resourceType == "workspaces") { m_selectedWorkspaces.append(item->data(Qt::UserRole).toString()); } + else if (resourceType == "gamutmasks") { + m_selectedGamutMasks.append(item->data(Qt::UserRole).toString()); + } } m_ui->tableAvailable->setCurrentRow(row); @@ -308,6 +319,9 @@ else if (resourceType == "workspaces") { m_selectedWorkspaces.removeAll(item->data(Qt::UserRole).toString()); } + else if (resourceType == "gamutmasks") { + m_selectedGamutMasks.removeAll(item->data(Qt::UserRole).toString()); + } } m_ui->tableSelected->setCurrentRow(row); @@ -420,6 +434,21 @@ } } } + else if (resourceType == "gamutmasks") { + KoResourceServer* server = KoResourceServerProvider::instance()->gamutMaskServer(); + Q_FOREACH (KoResource *res, server->resources()) { + QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); + item->setData(Qt::UserRole, res->shortFilename()); + + if (m_selectedGamutMasks.contains(res->shortFilename())) { + m_ui->tableSelected->addItem(item); + } + else { + m_ui->tableAvailable->addItem(item); + } + } + } + } void DlgCreateBundle::getPreviewImage() diff --git a/plugins/extensions/resourcemanager/resourcemanager.cpp b/plugins/extensions/resourcemanager/resourcemanager.cpp --- a/plugins/extensions/resourcemanager/resourcemanager.cpp +++ b/plugins/extensions/resourcemanager/resourcemanager.cpp @@ -63,15 +63,16 @@ patternServer = KoResourceServerProvider::instance()->patternServer(); paletteServer = KoResourceServerProvider::instance()->paletteServer(); workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); + gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); } KisBrushResourceServer* brushServer; KisPaintOpPresetResourceServer * paintopServer; KoResourceServer* gradientServer; KoResourceServer *patternServer; KoResourceServer* paletteServer; KoResourceServer* workspaceServer; - + KoResourceServer* gamutMaskServer; }; K_PLUGIN_FACTORY_WITH_JSON(ResourceManagerFactory, "kritaresourcemanager.json", registerPlugin();) @@ -196,6 +197,12 @@ newBundle->addResource("kis_workspaces", res->filename(), d->workspaceServer->assignedTagsList(res), res->md5()); } + res = dlgCreateBundle.selectedGamutMasks(); + Q_FOREACH (const QString &r, res) { + KoResource *res = d->gamutMaskServer->resourceByFilename(r); + newBundle->addResource("ko_gamutmasks", res->filename(), d->gamutMaskServer->assignedTagsList(res), res->md5()); + } + newBundle->addMeta("fileName", bundlePath); newBundle->addMeta("created", QDate::currentDate().toString("dd/MM/yyyy"));