Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_paintop_settings.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2008 Lukáš Tvrdý <lukast.dev@gmail.com>
4 * SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9
10#include <QColor>
11#include <QDomDocument>
12#include <QDomElement>
13#include <QPainterPath>
14#include <QPointer>
15
16#include <KoPointerEvent.h>
17#include <KoColor.h>
19#include <KoViewConverter.h>
20
21#include "kis_dom_utils.h"
22#include "kis_paintop_preset.h"
23#include "kis_paint_layer.h"
24#include "kis_image.h"
25#include "kis_painter.h"
26#include "kis_paint_device.h"
33#include <time.h>
34#include <kis_types.h>
35#include <kis_signals_blocker.h>
36
39
41#include "kis_algebra_2d.h"
42#include "kis_image_config.h"
47
48#define SANITY_CHECK_CACHE
49
50#ifdef SANITY_CHECK_CACHE
51#include "kis_random_source.h"
52#endif
53
54struct Q_DECL_HIDDEN KisPaintOpSettings::Private {
56 : settingsWidget(0)
58 , versionRandomSource(int(reinterpret_cast<std::intptr_t>(this)))
59 , versionCookie(versionRandomSource.generate())
60#endif
61 {}
62
63 Private(const Private &rhs)
64 : settingsWidget(0),
65 modelName(rhs.modelName),
66 resourcesInterface(rhs.resourcesInterface),
67 canvasResourcesInterface(rhs.canvasResourcesInterface),
68 resourceCacheInterface(rhs.resourceCacheInterface)
70 , versionRandomSource(int(reinterpret_cast<std::intptr_t>(this)))
71 , versionCookie(rhs.versionCookie)
72#endif
73 {
77 }
78
80 QString modelName;
86
87#ifdef SANITY_CHECK_CACHE
90#endif
91
92};
93
97
103
107
113
115{
116 d->updateListener = listener;
117}
118
120{
121 return d->updateListener;
122}
123
124bool KisPaintOpSettings::mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode)
125{
126 Q_UNUSED(modifiers);
127 Q_UNUSED(currentNode);
128 return true; // ignore the event by default
129}
130
132{
133 return true; // ignore the event by default
134}
135
140
142{
144
145 const KoID pixelBrushId(KisPaintOpUtils::MaskingBrushPaintOpId, QString());
146
148 maskingSettings->setCanvasResourcesInterface(canvasResourcesInterface());
149
151
152 const bool useMasterSize = this->getBool(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, true);
153 if (useMasterSize) {
169 const qreal maxMaskingBrushSize = KisImageConfig(true).maxMaskingBrushSize();
170 const qreal masterSizeCoeff = getDouble(KisPaintOpUtils::MaskingBrushMasterSizeCoeffTag, 1.0);
171 maskingSettings->setPaintOpSize(qMin(maxMaskingBrushSize, masterSizeCoeff * paintOpSize()));
172 }
173
174 if (d->resourceCacheInterface) {
175 maskingSettings->setResourceCacheInterface(
178 d->resourceCacheInterface)));
179 }
180
181 return maskingSettings;
182}
183
185{
186 return false;
187}
188
190{
191 return {};
192}
193
195{
196 return d->canvasResourcesInterface;
197}
198
200{
201 d->canvasResourcesInterface = canvasResourcesInterface;
202}
203
205{
206 d->resourceCacheInterface = cacheInterface;
207}
208
210{
211 return d->resourceCacheInterface;
212}
213
215{
216 if (hasMaskingSettings()) {
218
219 KoResourceCacheInterfaceSP wrappedCacheInterface =
222 cacheInterface));
223
224 maskingSettings->regenerateResourceCache(wrappedCacheInterface);
225 }
226}
227
229{
230#ifdef SANITY_CHECK_CACHE
231 return d->versionCookie;
232#else
233 return 0;
234#endif
235}
236
241
243{
244 return d->resourcesInterface;
245}
246
248{
249 d->resourcesInterface = resourcesInterface;
250}
251
253{
254 QString paintopID = getString("paintop");
255 if (paintopID.isEmpty())
256 return 0;
257
259 QMapIterator<QString, QVariant> i(getProperties());
260 while (i.hasNext()) {
261 i.next();
262 settings->setProperty(i.key(), QVariant(i.value()));
263 }
264
265 settings->setCanvasResourcesInterface(this->canvasResourcesInterface());
266
267#ifdef SANITY_CHECK_CACHE
268 settings->d->versionCookie = this->d->versionCookie;
269#endif
270
271 return settings;
272}
273
274void KisPaintOpSettings::resetSettings(const QStringList &preserveProperties)
275{
276 QStringList allKeys = preserveProperties;
277 allKeys << "paintop";
278
279 QHash<QString, QVariant> preserved;
280 Q_FOREACH (const QString &key, allKeys) {
281 if (hasProperty(key)) {
282 preserved[key] = getProperty(key);
283 }
284 }
285
287
288 for (auto it = preserved.constBegin(); it != preserved.constEnd(); ++it) {
289 setProperty(it.key(), it.value());
290 }
291}
292
296
298{
300 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
301
302 proxy->setProperty("OpacityValue", value);
303}
304
306{
308 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
309
310 proxy->setProperty("FlowValue", value);
311}
312
314{
316 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
317
318 if (!proxy->hasProperty("brush_definition")) return;
319
320 // Setting the Fade value is a bit more complex.
321 QDomDocument doc;
322 doc.setContent(proxy->getString("brush_definition"));
323
324 QDomElement element = doc.documentElement();
325 QDomElement elementChild = element.elementsByTagName("MaskGenerator").item(0).toElement();
326
327 elementChild.attributeNode("hfade").setValue(KisDomUtils::toString(value));
328 elementChild.attributeNode("vfade").setValue(KisDomUtils::toString(value));
329
330 proxy->setProperty("brush_definition", doc.toString());
331}
332
334{
336 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
337
338 if (!proxy->hasProperty("PressureScatter")) return;
339
340 proxy->setProperty("ScatterValue", value);
341 proxy->setProperty("PressureScatter", !qFuzzyIsNull(value));
342}
343
345{
347 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
348
349 proxy->setProperty("CompositeOp", value);
350}
351
353{
355
356 return proxy->getDouble("OpacityValue", 1.0);
357}
358
360{
362 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
363
364 return proxy->getDouble("FlowValue", 1.0);
365}
366
368{
370 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
371
372 if (!proxy->hasProperty("brush_definition")) return 1.0;
373
374 QDomDocument doc;
375 doc.setContent(proxy->getString("brush_definition"));
376
377 QDomElement element = doc.documentElement();
378 QDomElement elementChild = element.elementsByTagName("MaskGenerator").item(0).toElement();
379
380 if (elementChild.attributeNode("hfade").value().toDouble() >= elementChild.attributeNode("vfade").value().toDouble()) {
381 return elementChild.attributeNode("hfade").value().toDouble();
382 } else {
383 return elementChild.attributeNode("vfade").value().toDouble();
384 }
385
386}
387
389{
391 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
392
393 return proxy->getDouble("ScatterValue", 0.0);
394}
395
396
398{
400 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
401
402 return proxy->getDouble("Texture/Pattern/Scale", 0.5);
403}
404
406{
408 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
409
410 return proxy->getString("CompositeOp", COMPOSITE_OVER);
411}
412
414{
416 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
417
418 proxy->setProperty("EraserMode", value);
419}
420
422{
424 KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
425
426 return proxy->getBool("EraserMode", false);
427}
428
433
435{
436 return getDouble("SavedEraserSize", 0.0);
437}
438
440{
441 setProperty("SavedEraserSize", value);
442 setPropertyNotSaved("SavedEraserSize");
443}
444
446{
447 return getDouble("SavedBrushSize", 0.0);
448}
449
451{
452 setProperty("SavedBrushSize", value);
453 setPropertyNotSaved("SavedBrushSize");
454}
455
457{
458 return getDouble("SavedEraserOpacity", 0.0);
459}
460
462{
463 setProperty("SavedEraserOpacity", value);
464 setPropertyNotSaved("SavedEraserOpacity");
465}
466
468{
469 return getDouble("SavedBrushOpacity", 0.0);
470}
471
473{
474 setProperty("SavedBrushOpacity", value);
475 setPropertyNotSaved("SavedBrushOpacity");
476}
477
478QString KisPaintOpSettings::modelName() const
479{
480 return d->modelName;
481}
482
483void KisPaintOpSettings::setModelName(const QString & modelName)
484{
485 d->modelName = modelName;
486}
487
489{
490 return true;
491}
492
497
499{
500 return getBool(AIRBRUSH_ENABLED, false);
501}
502
504{
505 qreal rate = getDouble(AIRBRUSH_RATE, 1.0);
506 if (rate == 0.0) {
507 return LONG_TIME;
508 }
509 else {
510 return 1000.0 / rate;
511 }
512}
513
515{
516 return getBool(SPACING_USE_UPDATES, false);
517}
518
520{
521 return false;
522}
523
525{
527 if (mode.isVisible) {
528 path = ellipseOutline(10, 10, 1.0, 0);
529
530 if (mode.showTiltDecoration) {
531 path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), 0.0, 2.0));
532 }
533
534 path.translate(KisAlgebra2D::alignForZoom(info.pos(), alignForZoom));
535 }
536
537 return path;
538}
539
540KisOptimizedBrushOutline KisPaintOpSettings::ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation)
541{
542 QPainterPath path;
543 QRectF ellipse(0, 0, width * scale, height * scale);
544 ellipse.translate(-ellipse.center());
545 path.addEllipse(ellipse);
546
547 QTransform m;
548 m.reset();
549 m.rotate(rotation);
550 path = m.map(path);
551 return path;
552}
553
555 QPointF const& start, qreal maxLength, qreal angle)
556{
557 if (maxLength == 0.0) maxLength = 50.0;
558 maxLength = qMax(maxLength, 50.0);
559 qreal const length = maxLength * (1 - info.tiltElevation(info, 60.0, 60.0, true));
560 qreal const baseAngle = 360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0);
561
562 QLineF guideLine = QLineF::fromPolar(length, baseAngle + angle);
563 guideLine.translate(start);
564 QPainterPath ret;
565 ret.moveTo(guideLine.p1());
566 ret.lineTo(guideLine.p2());
567 guideLine.setAngle(baseAngle - angle);
568 ret.lineTo(guideLine.p2());
569 ret.lineTo(guideLine.p1());
570 return ret;
571}
572
573void KisPaintOpSettings::setProperty(const QString & name, const QVariant & value)
574{
576 UpdateListenerSP updateListener = d->updateListener.toStrongRef();
577
578 if (updateListener) {
579 updateListener->setDirty(true);
580 }
581 }
582
585}
586
587
589{
590 // clear cached data for the resource
591 d->resourceCacheInterface.clear();
592
593#ifdef SANITY_CHECK_CACHE
594 d->versionCookie = d->versionRandomSource.generate();
595#endif
596
597 UpdateListenerSP updateListener = d->updateListener.toStrongRef();
598
599 if (updateListener) {
600 updateListener->notifySettingsChanged();
601 }
602}
603
605{
606 return config->getBool("lodUserAllowed", true);
607}
608
610{
611 config->setProperty("lodUserAllowed", value);
612}
613
615{
616 return true;
617}
618
620{
621 return getDouble("lodSizeThreshold", 100.0);
622}
623
625{
626 setProperty("lodSizeThreshold", value);
627}
628
630
632{
634 listWeakToStrong(d->uniformProperties);
635
636
637 if (props.isEmpty()) {
639
640 props.append(createProperty(opacity, settings, updateProxy));
641 props.append(createProperty(size, settings, updateProxy));
642 props.append(createProperty(flow, settings, updateProxy));
643
644 d->uniformProperties = listStrongToWeak(props);
645 }
646
647 return props;
648}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
const QString COMPOSITE_OVER
const QString COMPOSITE_MULT
const QString COMPOSITE_ERASE
const QString COMPOSITE_ALPHA_DARKEN
int maxMaskingBrushSize() const
static KisLockedPropertiesServer * instance()
KisLockedPropertiesProxySP createLockedPropertiesProxy(KisPropertiesConfiguration *settings)
const QPointF & pos() const
static qreal tiltDirection(const KisPaintInformation &info, bool normalize=true)
static qreal tiltElevation(const KisPaintInformation &info, qreal maxTiltX=60.0, qreal maxTiltY=60.0, bool normalize=true)
static KisPaintOpRegistry * instance()
KisPaintOpSettingsSP createSettings(const KoID &id, KisResourcesInterfaceSP resourcesInterface) const
Definition KoID.h:30
static bool qFuzzyIsNull(half h)
#define SANITY_CHECK_CACHE
const QString AIRBRUSH_ENABLED
const QString AIRBRUSH_RATE
const QString SPACING_USE_UPDATES
QSharedPointer< T > toQShared(T *ptr)
Container< QSharedPointer< T > > listWeakToStrong(const Container< QWeakPointer< T > > &container, bool allOrNothing=true)
Container< QWeakPointer< T > > listStrongToWeak(const Container< QSharedPointer< T > > &container)
const qreal LONG_TIME
KisPinnedSharedPtr< KisPaintOpSettings > KisPaintOpSettingsSP
Definition kis_types.h:242
QPointF alignForZoom(const QPointF &pt, qreal zoom)
QString toString(const QString &value)
const char MaskingBrushEnabledTag[]
const char MaskingBrushUseMasterSizeTag[]
const char MaskingBrushPaintOpId[]
const char MaskingBrushMasterSizeCoeffTag[]
const char MaskingBrushPresetPrefix[]
const char MaskingBrushCompositeOpTag[]
virtual void regenerateResourceCache(KoResourceCacheInterfaceSP cacheInterface)
void setSavedEraserSize(qreal value)
static QPainterPath makeTiltIndicator(KisPaintInformation const &info, QPointF const &start, qreal lengthScale, qreal angle)
virtual bool isValid() const
virtual QString indirectPaintingCompositeOp() const
quint64 sanityVersionCookie() const
static void setLodUserAllowed(KisPropertiesConfigurationSP config, bool value)
KisRandomSource versionRandomSource
static bool isLodUserAllowed(const KisPropertiesConfigurationSP config)
virtual bool needsAsynchronousUpdates() const
void setSavedBrushSize(qreal value)
virtual bool hasPatternSettings() const
KisResourcesInterfaceSP resourcesInterface
static KisOptimizedBrushOutline ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation)
void setCanvasResourcesInterface(KoCanvasResourcesInterfaceSP canvasResourcesInterface)
KisPaintOpSettings(KisResourcesInterfaceSP resourcesInterface)
virtual qreal paintOpSize() const =0
void setPaintOpCompositeOp(const QString &value)
QPointer< KisPaintOpConfigWidget > settingsWidget
void setPaintOpFlow(qreal value)
virtual KisOptimizedBrushOutline brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom)
virtual KisPaintOpSettingsSP clone() const
virtual qreal airbrushInterval() const
virtual bool lodSizeThresholdSupported() const
void setModelName(const QString &modelName)
virtual void resetSettings(const QStringList &preserveProperties=QStringList())
void setProperty(const QString &name, const QVariant &value) override
virtual void setPaintOpOpacity(qreal value)
virtual qreal paintOpPatternSize()
void setEraserMode(bool value)
void setPaintOpFade(qreal value)
void setResourcesInterface(KisResourcesInterfaceSP resourcesInterface)
virtual void setResourceCacheInterface(KoResourceCacheInterfaceSP cacheInterface)
virtual bool isAirbrushing() const
void setSavedBrushOpacity(qreal value)
void setSavedEraserOpacity(qreal value)
const QScopedPointer< Private > d
virtual bool mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode)
KisPaintOpSettingsSP createMaskingSettings() const
KoCanvasResourcesInterfaceSP canvasResourcesInterface
QList< KisUniformPaintOpPropertyWSP > uniformProperties
void setLodSizeThreshold(qreal value)
UpdateListenerWSP updateListener
void setPaintOpScatter(qreal value)
QString maskingBrushCompositeOp() const
void setUpdateListener(UpdateListenerWSP listener)
virtual bool useSpacingUpdates() const
KoResourceCacheInterfaceSP resourceCacheInterface
virtual QList< int > requiredCanvasResources() const
Private(const Private &rhs)
void setPropertyNotSaved(const QString &name)
Marks a property that should not be saved by toXML.
QString getString(const QString &name, const QString &def=QString()) const
void clearProperties()
Clear the map of properties.
virtual bool hasProperty(const QString &name) const
virtual void setProperty(const QString &name, const QVariant &value)
bool getBool(const QString &name, bool def=false) const
double getDouble(const QString &name, double def=0.0) const
void getPrefixedProperties(const QString &prefix, KisPropertiesConfiguration *config) const
virtual bool getProperty(const QString &name, QVariant &value) const
virtual QMap< QString, QVariant > getProperties() const