File indexing completed on 2025-02-23 04:06:48

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2008 Lukáš Tvrdý <lukast.dev@gmail.com>
0004  *  SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include <brushengine/kis_paintop_settings.h>
0009 
0010 #include <QImage>
0011 #include <QColor>
0012 #include <QDomDocument>
0013 #include <QDomElement>
0014 #include <QPainterPath>
0015 #include <QPointer>
0016 
0017 #include <KoPointerEvent.h>
0018 #include <KoColor.h>
0019 #include <KoCompositeOpRegistry.h>
0020 #include <KoViewConverter.h>
0021 
0022 #include "kis_dom_utils.h"
0023 #include "kis_paintop_preset.h"
0024 #include "kis_paint_layer.h"
0025 #include "kis_image.h"
0026 #include "kis_painter.h"
0027 #include "kis_paint_device.h"
0028 #include "kis_paintop_registry.h"
0029 #include "kis_timing_information.h"
0030 #include <brushengine/kis_paint_information.h>
0031 #include "kis_paintop_config_widget.h"
0032 #include <brushengine/kis_paintop_preset.h>
0033 #include "KisPaintOpPresetUpdateProxy.h"
0034 #include <time.h>
0035 #include <kis_types.h>
0036 #include <kis_signals_blocker.h>
0037 
0038 #include <brushengine/kis_locked_properties_server.h>
0039 #include <brushengine/kis_locked_properties_proxy.h>
0040 
0041 #include "KisPaintopSettingsIds.h"
0042 #include "kis_algebra_2d.h"
0043 #include "kis_image_config.h"
0044 #include <KoCanvasResourcesInterface.h>
0045 #include <KoResourceCacheInterface.h>
0046 #include <KoResourceCachePrefixedStorageWrapper.h>
0047 #include <brushengine/KisOptimizedBrushOutline.h>
0048 
0049 #define SANITY_CHECK_CACHE
0050 
0051 #ifdef SANITY_CHECK_CACHE
0052 #include "kis_random_source.h"
0053 #endif
0054 
0055 struct Q_DECL_HIDDEN KisPaintOpSettings::Private {
0056     Private()
0057         : disableDirtyNotifications(false)
0058 #ifdef SANITY_CHECK_CACHE
0059         , versionRandomSource(int(reinterpret_cast<std::intptr_t>(this)))
0060         , versionCookie(versionRandomSource.generate())
0061 #endif
0062     {}
0063 
0064     Private(const Private &rhs)
0065         : settingsWidget(0),
0066           modelName(rhs.modelName),
0067           resourcesInterface(rhs.resourcesInterface),
0068           canvasResourcesInterface(rhs.canvasResourcesInterface),
0069           resourceCacheInterface(rhs.resourceCacheInterface),
0070           disableDirtyNotifications(false)
0071 #ifdef SANITY_CHECK_CACHE
0072         , versionRandomSource(int(reinterpret_cast<std::intptr_t>(this)))
0073         , versionCookie(rhs.versionCookie)
0074 #endif
0075     {
0076         /// NOTE: we don't copy updateListener intentionally, it is
0077         ///       a job of the cloned preset to set the new listener
0078         ///       properly
0079     }
0080 
0081     QPointer<KisPaintOpConfigWidget> settingsWidget;
0082     QString modelName;
0083     UpdateListenerWSP updateListener;
0084     QList<KisUniformPaintOpPropertyWSP> uniformProperties;
0085     KisResourcesInterfaceSP resourcesInterface;
0086     KoCanvasResourcesInterfaceSP canvasResourcesInterface;
0087     KoResourceCacheInterfaceSP resourceCacheInterface;
0088 
0089     bool disableDirtyNotifications;
0090 
0091 #ifdef SANITY_CHECK_CACHE
0092     KisRandomSource versionRandomSource;
0093     quint64 versionCookie;
0094 #endif
0095 
0096     class DirtyNotificationsLocker {
0097     public:
0098         DirtyNotificationsLocker(KisPaintOpSettings::Private *d)
0099             : m_d(d),
0100               m_oldNotificationsState(d->disableDirtyNotifications)
0101         {
0102             m_d->disableDirtyNotifications = true;
0103         }
0104 
0105         ~DirtyNotificationsLocker() {
0106             m_d->disableDirtyNotifications = m_oldNotificationsState;
0107         }
0108 
0109     private:
0110         KisPaintOpSettings::Private *m_d;
0111         bool m_oldNotificationsState;
0112         Q_DISABLE_COPY(DirtyNotificationsLocker)
0113     };
0114 };
0115 
0116 KisPaintOpSettings::UpdateListener::~UpdateListener()
0117 {
0118 }
0119 
0120 KisPaintOpSettings::KisPaintOpSettings(KisResourcesInterfaceSP resourcesInterface)
0121     : d(new Private)
0122 {
0123     d->resourcesInterface = resourcesInterface;
0124 }
0125 
0126 KisPaintOpSettings::~KisPaintOpSettings()
0127 {
0128 }
0129 
0130 KisPaintOpSettings::KisPaintOpSettings(const KisPaintOpSettings &rhs)
0131     : KisPropertiesConfiguration(rhs)
0132     , d(new Private(*rhs.d))
0133 {
0134 }
0135 
0136 void KisPaintOpSettings::setUpdateListener(UpdateListenerWSP listener)
0137 {
0138     d->updateListener = listener;
0139 }
0140 
0141 KisPaintOpSettings::UpdateListenerWSP KisPaintOpSettings::updateListener() const
0142 {
0143     return d->updateListener;
0144 }
0145 
0146 bool KisPaintOpSettings::mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode)
0147 {
0148     Q_UNUSED(modifiers);
0149     Q_UNUSED(currentNode);
0150     setRandomOffset(paintInformation);
0151     return true; // ignore the event by default
0152 }
0153 
0154 bool KisPaintOpSettings::mouseReleaseEvent()
0155 {
0156     return true; // ignore the event by default
0157 }
0158 
0159 void KisPaintOpSettings::setRandomOffset(const KisPaintInformation &paintInformation)
0160 {
0161     bool disableDirtyBefore = d->disableDirtyNotifications;
0162     d->disableDirtyNotifications = true;
0163     if (getBool("Texture/Pattern/Enabled")) {
0164         if (getBool("Texture/Pattern/isRandomOffsetX")) {
0165             setProperty("Texture/Pattern/OffsetX",
0166                         paintInformation.randomSource()->generate(0, KisPropertiesConfiguration::getInt("Texture/Pattern/MaximumOffsetX")));
0167         }
0168         if (getBool("Texture/Pattern/isRandomOffsetY")) {
0169             setProperty("Texture/Pattern/OffsetY",
0170                         paintInformation.randomSource()->generate(0, KisPropertiesConfiguration::getInt("Texture/Pattern/MaximumOffsetY")));
0171 
0172         }
0173     }
0174     d->disableDirtyNotifications = disableDirtyBefore;
0175 }
0176 
0177 bool KisPaintOpSettings::hasMaskingSettings() const
0178 {
0179     return getBool(KisPaintOpUtils::MaskingBrushEnabledTag, false);
0180 }
0181 
0182 KisPaintOpSettingsSP KisPaintOpSettings::createMaskingSettings() const
0183 {
0184     if (!hasMaskingSettings()) return KisPaintOpSettingsSP();
0185 
0186     const KoID pixelBrushId(KisPaintOpUtils::MaskingBrushPaintOpId, QString());
0187 
0188     KisPaintOpSettingsSP maskingSettings = KisPaintOpRegistry::instance()->createSettings(pixelBrushId, resourcesInterface());
0189     maskingSettings->setCanvasResourcesInterface(canvasResourcesInterface());
0190 
0191     this->getPrefixedProperties(KisPaintOpUtils::MaskingBrushPresetPrefix, maskingSettings);
0192 
0193     const bool useMasterSize = this->getBool(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, true);
0194     if (useMasterSize) {
0195         /**
0196          * WARNING: cropping is a workaround for too big brushes due to
0197          * the proportional scaling using shift+drag gesture.
0198          *
0199          * See this bug: https://bugs.kde.org/show_bug.cgi?id=423572
0200          *
0201          * TODO:
0202          *
0203          * 1) Implement a warning notifying the user that his masking
0204          *    brush has been cropped
0205          *
0206          * 2) Make sure that the sliders in KisMaskingBrushOption have
0207          *    correct limits (right now they are limited by usual
0208          *    maximumBrushSize)
0209          */
0210         const qreal maxMaskingBrushSize = KisImageConfig(true).maxMaskingBrushSize();
0211         const qreal masterSizeCoeff = getDouble(KisPaintOpUtils::MaskingBrushMasterSizeCoeffTag, 1.0);
0212         maskingSettings->setPaintOpSize(qMin(maxMaskingBrushSize, masterSizeCoeff * paintOpSize()));
0213     }
0214 
0215     if (d->resourceCacheInterface) {
0216         maskingSettings->setResourceCacheInterface(
0217                     toQShared(new KoResourceCachePrefixedStorageWrapper(
0218                                   KisPaintOpUtils::MaskingBrushPresetPrefix,
0219                                   d->resourceCacheInterface)));
0220     }
0221 
0222     return maskingSettings;
0223 }
0224 
0225 bool KisPaintOpSettings::hasPatternSettings() const
0226 {
0227     return false;
0228 }
0229 
0230 QList<int> KisPaintOpSettings::requiredCanvasResources() const
0231 {
0232     return {};
0233 }
0234 
0235 KoCanvasResourcesInterfaceSP KisPaintOpSettings::canvasResourcesInterface() const
0236 {
0237     return d->canvasResourcesInterface;
0238 }
0239 
0240 void KisPaintOpSettings::setCanvasResourcesInterface(KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0241 {
0242     d->canvasResourcesInterface = canvasResourcesInterface;
0243 }
0244 
0245 void KisPaintOpSettings::setResourceCacheInterface(KoResourceCacheInterfaceSP cacheInterface)
0246 {
0247     d->resourceCacheInterface = cacheInterface;
0248 }
0249 
0250 KoResourceCacheInterfaceSP KisPaintOpSettings::resourceCacheInterface() const
0251 {
0252     return d->resourceCacheInterface;
0253 }
0254 
0255 void KisPaintOpSettings::regenerateResourceCache(KoResourceCacheInterfaceSP cacheInterface)
0256 {
0257     if (hasMaskingSettings()) {
0258         KisPaintOpSettingsSP maskingSettings = createMaskingSettings();
0259 
0260         KoResourceCacheInterfaceSP wrappedCacheInterface =
0261             toQShared(new KoResourceCachePrefixedStorageWrapper(
0262                           KisPaintOpUtils::MaskingBrushPresetPrefix,
0263                           cacheInterface));
0264 
0265         maskingSettings->regenerateResourceCache(wrappedCacheInterface);
0266     }
0267 }
0268 
0269 quint64 KisPaintOpSettings::sanityVersionCookie() const
0270 {
0271 #ifdef SANITY_CHECK_CACHE
0272     return d->versionCookie;
0273 #else
0274     return 0;
0275 #endif
0276 }
0277 
0278 QString KisPaintOpSettings::maskingBrushCompositeOp() const
0279 {
0280     return getString(KisPaintOpUtils::MaskingBrushCompositeOpTag, COMPOSITE_MULT);
0281 }
0282 
0283 KisResourcesInterfaceSP KisPaintOpSettings::resourcesInterface() const
0284 {
0285     return d->resourcesInterface;
0286 }
0287 
0288 void KisPaintOpSettings::setResourcesInterface(KisResourcesInterfaceSP resourcesInterface)
0289 {
0290     d->resourcesInterface = resourcesInterface;
0291 }
0292 
0293 KisPaintOpSettingsSP KisPaintOpSettings::clone() const
0294 {
0295     QString paintopID = getString("paintop");
0296     if (paintopID.isEmpty())
0297         return 0;
0298 
0299     KisPaintOpSettingsSP settings = KisPaintOpRegistry::instance()->createSettings(KoID(paintopID), resourcesInterface());
0300     QMapIterator<QString, QVariant> i(getProperties());
0301     while (i.hasNext()) {
0302         i.next();
0303         settings->setProperty(i.key(), QVariant(i.value()));
0304     }
0305 
0306     settings->setCanvasResourcesInterface(this->canvasResourcesInterface());
0307 
0308 #ifdef SANITY_CHECK_CACHE
0309     settings->d->versionCookie = this->d->versionCookie;
0310 #endif
0311 
0312     return settings;
0313 }
0314 
0315 void KisPaintOpSettings::resetSettings(const QStringList &preserveProperties)
0316 {
0317     QStringList allKeys = preserveProperties;
0318     allKeys << "paintop";
0319 
0320     QHash<QString, QVariant> preserved;
0321     Q_FOREACH (const QString &key, allKeys) {
0322         if (hasProperty(key)) {
0323             preserved[key] = getProperty(key);
0324         }
0325     }
0326 
0327     clearProperties();
0328 
0329     for (auto it = preserved.constBegin(); it != preserved.constEnd(); ++it) {
0330         setProperty(it.key(), it.value());
0331     }
0332 }
0333 
0334 void KisPaintOpSettings::activate()
0335 {
0336 }
0337 
0338 void KisPaintOpSettings::setPaintOpOpacity(qreal value)
0339 {
0340     KisLockedPropertiesProxySP proxy(
0341                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0342 
0343     proxy->setProperty("OpacityValue", value);
0344 }
0345 
0346 void KisPaintOpSettings::setPaintOpFlow(qreal value)
0347 {
0348     KisLockedPropertiesProxySP proxy(
0349                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0350 
0351     proxy->setProperty("FlowValue", value);
0352 }
0353 
0354 void KisPaintOpSettings::setPaintOpFade(qreal value)
0355 {
0356     KisLockedPropertiesProxySP proxy(
0357                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0358 
0359     if (!proxy->hasProperty("brush_definition")) return;
0360 
0361     // Setting the Fade value is a bit more complex.
0362     QDomDocument doc;
0363     doc.setContent(proxy->getString("brush_definition"));
0364 
0365     QDomElement element = doc.documentElement();
0366     QDomElement elementChild = element.elementsByTagName("MaskGenerator").item(0).toElement();
0367 
0368     elementChild.attributeNode("hfade").setValue(KisDomUtils::toString(value));
0369     elementChild.attributeNode("vfade").setValue(KisDomUtils::toString(value));
0370 
0371     proxy->setProperty("brush_definition", doc.toString());
0372 }
0373 
0374 void KisPaintOpSettings::setPaintOpScatter(qreal value)
0375 {
0376     KisLockedPropertiesProxySP proxy(
0377                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0378 
0379     if (!proxy->hasProperty("PressureScatter")) return;
0380 
0381     proxy->setProperty("ScatterValue", value);
0382     proxy->setProperty("PressureScatter", !qFuzzyIsNull(value));
0383 }
0384 
0385 void KisPaintOpSettings::setPaintOpCompositeOp(const QString &value)
0386 {
0387     KisLockedPropertiesProxySP proxy(
0388                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0389 
0390     proxy->setProperty("CompositeOp", value);
0391 }
0392 
0393 qreal KisPaintOpSettings::paintOpOpacity()
0394 {
0395     KisLockedPropertiesProxySP proxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this);
0396 
0397     return proxy->getDouble("OpacityValue", 1.0);
0398 }
0399 
0400 qreal KisPaintOpSettings::paintOpFlow()
0401 {
0402     KisLockedPropertiesProxySP proxy(
0403                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0404 
0405     return proxy->getDouble("FlowValue", 1.0);
0406 }
0407 
0408 qreal KisPaintOpSettings::paintOpFade()
0409 {
0410     KisLockedPropertiesProxySP proxy(
0411         KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0412 
0413     if (!proxy->hasProperty("brush_definition")) return 1.0;
0414 
0415     QDomDocument doc;
0416     doc.setContent(proxy->getString("brush_definition"));
0417 
0418     QDomElement element = doc.documentElement();
0419     QDomElement elementChild = element.elementsByTagName("MaskGenerator").item(0).toElement();
0420 
0421     if (elementChild.attributeNode("hfade").value().toDouble() >= elementChild.attributeNode("vfade").value().toDouble()) {
0422         return elementChild.attributeNode("hfade").value().toDouble();
0423     } else {
0424         return elementChild.attributeNode("vfade").value().toDouble();
0425     }
0426 
0427 }
0428 
0429 qreal KisPaintOpSettings::paintOpScatter()
0430 {
0431     KisLockedPropertiesProxySP proxy(
0432         KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0433 
0434     return proxy->getDouble("ScatterValue", 0.0);
0435 }
0436 
0437 
0438 qreal KisPaintOpSettings::paintOpPatternSize()
0439 {
0440     KisLockedPropertiesProxySP proxy(
0441         KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0442 
0443     return proxy->getDouble("Texture/Pattern/Scale", 0.5);
0444 }
0445 
0446 QString KisPaintOpSettings::paintOpCompositeOp()
0447 {
0448     KisLockedPropertiesProxySP proxy(
0449                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0450 
0451     return proxy->getString("CompositeOp", COMPOSITE_OVER);
0452 }
0453 
0454 void KisPaintOpSettings::setEraserMode(bool value)
0455 {
0456     KisLockedPropertiesProxySP proxy(
0457                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0458 
0459     proxy->setProperty("EraserMode", value);
0460 }
0461 
0462 bool KisPaintOpSettings::eraserMode()
0463 {
0464     KisLockedPropertiesProxySP proxy(
0465                 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
0466 
0467     return proxy->getBool("EraserMode", false);
0468 }
0469 
0470 QString KisPaintOpSettings::effectivePaintOpCompositeOp()
0471 {
0472     return !eraserMode() ? paintOpCompositeOp() : COMPOSITE_ERASE;
0473 }
0474 
0475 qreal KisPaintOpSettings::savedEraserSize() const
0476 {
0477     return getDouble("SavedEraserSize", 0.0);
0478 }
0479 
0480 void KisPaintOpSettings::setSavedEraserSize(qreal value)
0481 {
0482     setProperty("SavedEraserSize", value);
0483     setPropertyNotSaved("SavedEraserSize");
0484 }
0485 
0486 qreal KisPaintOpSettings::savedBrushSize() const
0487 {
0488     return getDouble("SavedBrushSize", 0.0);
0489 }
0490 
0491 void KisPaintOpSettings::setSavedBrushSize(qreal value)
0492 {
0493     setProperty("SavedBrushSize", value);
0494     setPropertyNotSaved("SavedBrushSize");
0495 }
0496 
0497 qreal KisPaintOpSettings::savedEraserOpacity() const
0498 {
0499     return getDouble("SavedEraserOpacity", 0.0);
0500 }
0501 
0502 void KisPaintOpSettings::setSavedEraserOpacity(qreal value)
0503 {
0504     setProperty("SavedEraserOpacity", value);
0505     setPropertyNotSaved("SavedEraserOpacity");
0506 }
0507 
0508 qreal KisPaintOpSettings::savedBrushOpacity() const
0509 {
0510     return getDouble("SavedBrushOpacity", 0.0);
0511 }
0512 
0513 void KisPaintOpSettings::setSavedBrushOpacity(qreal value)
0514 {
0515     setProperty("SavedBrushOpacity", value);
0516     setPropertyNotSaved("SavedBrushOpacity");
0517 }
0518 
0519 QString KisPaintOpSettings::modelName() const
0520 {
0521     return d->modelName;
0522 }
0523 
0524 void KisPaintOpSettings::setModelName(const QString & modelName)
0525 {
0526     d->modelName = modelName;
0527 }
0528 
0529 bool KisPaintOpSettings::isValid() const
0530 {
0531     return true;
0532 }
0533 
0534 QString KisPaintOpSettings::indirectPaintingCompositeOp() const
0535 {
0536     return COMPOSITE_ALPHA_DARKEN;
0537 }
0538 
0539 bool KisPaintOpSettings::isAirbrushing() const
0540 {
0541     return getBool(AIRBRUSH_ENABLED, false);
0542 }
0543 
0544 qreal KisPaintOpSettings::airbrushInterval() const
0545 {
0546     qreal rate = getDouble(AIRBRUSH_RATE, 1.0);
0547     if (rate == 0.0) {
0548         return LONG_TIME;
0549     }
0550     else {
0551         return 1000.0 / rate;
0552     }
0553 }
0554 
0555 bool KisPaintOpSettings::useSpacingUpdates() const
0556 {
0557     return getBool(SPACING_USE_UPDATES, false);
0558 }
0559 
0560 bool KisPaintOpSettings::needsAsynchronousUpdates() const
0561 {
0562     return false;
0563 }
0564 
0565 KisOptimizedBrushOutline KisPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom)
0566 {
0567     KisOptimizedBrushOutline path;
0568     if (mode.isVisible) {
0569         path = ellipseOutline(10, 10, 1.0, 0);
0570 
0571         if (mode.showTiltDecoration) {
0572             path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), 0.0, 2.0));
0573         }
0574 
0575         path.translate(KisAlgebra2D::alignForZoom(info.pos(), alignForZoom));
0576     }
0577 
0578     return path;
0579 }
0580 
0581 KisOptimizedBrushOutline KisPaintOpSettings::ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation)
0582 {
0583     QPainterPath path;
0584     QRectF ellipse(0, 0, width * scale, height * scale);
0585     ellipse.translate(-ellipse.center());
0586     path.addEllipse(ellipse);
0587 
0588     QTransform m;
0589     m.reset();
0590     m.rotate(rotation);
0591     path = m.map(path);
0592     return path;
0593 }
0594 
0595 QPainterPath KisPaintOpSettings::makeTiltIndicator(KisPaintInformation const& info,
0596                                                    QPointF const& start, qreal maxLength, qreal angle)
0597 {
0598     if (maxLength == 0.0) maxLength = 50.0;
0599     maxLength = qMax(maxLength, 50.0);
0600     qreal const length = maxLength * (1 - info.tiltElevation(info, 60.0, 60.0, true));
0601     qreal const baseAngle = 360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0);
0602 
0603     QLineF guideLine = QLineF::fromPolar(length, baseAngle + angle);
0604     guideLine.translate(start);
0605     QPainterPath ret;
0606     ret.moveTo(guideLine.p1());
0607     ret.lineTo(guideLine.p2());
0608     guideLine.setAngle(baseAngle - angle);
0609     ret.lineTo(guideLine.p2());
0610     ret.lineTo(guideLine.p1());
0611     return ret;
0612 }
0613 
0614 void KisPaintOpSettings::setProperty(const QString & name, const QVariant & value)
0615 {
0616     if (value != KisPropertiesConfiguration::getProperty(name) && !d->disableDirtyNotifications) {
0617         UpdateListenerSP updateListener = d->updateListener.toStrongRef();
0618 
0619         if (updateListener) {
0620             updateListener->setDirty(true);
0621         }
0622     }
0623 
0624     KisPropertiesConfiguration::setProperty(name, value);
0625     onPropertyChanged();
0626 }
0627 
0628 
0629 void KisPaintOpSettings::onPropertyChanged()
0630 {
0631     // clear cached data for the resource
0632     d->resourceCacheInterface.clear();
0633 
0634 #ifdef SANITY_CHECK_CACHE
0635     d->versionCookie = d->versionRandomSource.generate();
0636 #endif
0637 
0638     UpdateListenerSP updateListener = d->updateListener.toStrongRef();
0639 
0640     if (updateListener) {
0641         updateListener->notifySettingsChanged();
0642     }
0643 }
0644 
0645 bool KisPaintOpSettings::isLodUserAllowed(const KisPropertiesConfigurationSP config)
0646 {
0647     return config->getBool("lodUserAllowed", true);
0648 }
0649 
0650 void KisPaintOpSettings::setLodUserAllowed(KisPropertiesConfigurationSP config, bool value)
0651 {
0652     config->setProperty("lodUserAllowed", value);
0653 }
0654 
0655 bool KisPaintOpSettings::lodSizeThresholdSupported() const
0656 {
0657     return true;
0658 }
0659 
0660 qreal KisPaintOpSettings::lodSizeThreshold() const
0661 {
0662     return getDouble("lodSizeThreshold", 100.0);
0663 }
0664 
0665 void KisPaintOpSettings::setLodSizeThreshold(qreal value)
0666 {
0667     setProperty("lodSizeThreshold", value);
0668 }
0669 
0670 #include "kis_standard_uniform_properties_factory.h"
0671 
0672 QList<KisUniformPaintOpPropertySP> KisPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings, QPointer<KisPaintOpPresetUpdateProxy> updateProxy)
0673 {
0674     QList<KisUniformPaintOpPropertySP> props =
0675             listWeakToStrong(d->uniformProperties);
0676 
0677 
0678     if (props.isEmpty()) {
0679         using namespace KisStandardUniformPropertiesFactory;
0680 
0681         props.append(createProperty(opacity, settings, updateProxy));
0682         props.append(createProperty(size, settings, updateProxy));
0683         props.append(createProperty(flow, settings, updateProxy));
0684 
0685         d->uniformProperties = listStrongToWeak(props);
0686     }
0687 
0688     return props;
0689 }