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 }