10#include <QCoreApplication>
140 , m_d(new
Private(this, image))
147 &
m_d->dirtyParentUpdateCompressor, SLOT(start()));
153 connect(&
m_d->prefilterRecalculationCompressor,
158 m_d->updateCompressor.moveToThread(qApp->thread());
167 m_d(new
Private(*rhs.m_d, this))
174 &
m_d->dirtyParentUpdateCompressor, SLOT(start()));
180 m_d->updateCompressor.moveToThread(qApp->thread());
186 if (!parentLayer || !parentLayer->
original())
return;
191 const qreal samplePortion = 0.1;
192 const qreal alphaPortion =
202 return m_d->fakePaintDevice->colorSpace();
208 KoColorConversionTransformation::ConversionFlags conversionFlags,
220 for (
int i = 0; i <
m_list->size(); i++) {
239 for (
int i = 0; i <
m_list->size(); i++) {
262 m_d->coloringProjection->setProfile(profile, parentCommand);
264 for (
auto & stroke :
m_d->keyStrokes) {
265 stroke.color.setProfile(profile);
271 KoColorConversionTransformation::ConversionFlags conversionFlags,
278 m_d->fakePaintDevice->convertTo(dstColorSpace, renderingIntent, conversionFlags, composite, progressUpdater);
279 m_d->coloringProjection->convertTo(dstColorSpace, renderingIntent, conversionFlags, composite, progressUpdater);
283 dstColorSpace, renderingIntent, conversionFlags,
285 strokesConversionCommand->
redo();
294 return m_d->needsUpdate;
299 m_d->setNeedsUpdateImpl(
value,
true);
308 if (!
value && requestedByUser) {
319 const bool filteredSourceValid =
m_d->filteredSourceValid(src);
320 m_d->originalSequenceNumber = src->sequenceNumber();
321 m_d->filteringDirty =
false;
323 if (!prefilterOnly) {
324 m_d->coloringProjection->clear();
328 if (!parentLayer)
return;
332 m_d->updateIsRunning =
true;
336 if (
m_d->limitToDeviceBounds) {
337 fillBounds |= src->exactBounds();
346 m_d->filteredDeviceBounds = fillBounds;
350 m_d->coloringProjection,
368 m_d->extentBeforeUpdateStart.push(
extent());
391 if (!
m_d->filteredSourceValid(src)) {
392 const QRect &oldExtent =
extent();
394 m_d->setNeedsUpdateImpl(
true,
false);
395 m_d->filteringDirty =
true;
408 m_d->updateIsRunning =
false;
410 if (!prefilterOnly) {
411 m_d->setNeedsUpdateImpl(
false,
false);
416 if (!
m_d->extentBeforeUpdateStart.isEmpty()) {
417 oldExtent =
m_d->extentBeforeUpdateStart.pop();
428 m_d->setNeedsUpdateImpl(
true,
false);
447 if (
m_d->needsUpdate &&
m_d->needsUpdate != property.
state.toBool()) {
452 if (
m_d->showKeyStrokes != property.
state.toBool()) {
457 if (
m_d->showColoring != property.
state.toBool()) {
471 return m_d->coloringProjection;
477 m_d->shouldShowColoring() && !
m_d->coloringProjection->
extent().isEmpty() ?
489 return v.visit(
this);
494 return visitor.
visit(
this, undoAdapter);
499 return !updateIsRunning &&
503 !filteredSource->extent().isEmpty();
508 return !updateIsRunning &&
517 KisRenderPassFlags flags)
const
525 if (!
m_d->filteringDirty) {
536 if (
m_d->shouldShowFilteredSource()) {
537 const QRect drawRect =
m_d->limitToDeviceBounds ?
rect &
m_d->filteredDeviceBounds :
rect;
540 gc.
bitBlt(drawRect.topLeft(),
m_d->filteredSource, drawRect);
546 if (
m_d->shouldShowColoring()) {
555 if (
m_d->showKeyStrokes) {
573 if (
m_d->currentKeyStrokeDevice &&
574 m_d->needAddCurrentKeyStroke &&
575 !isTemporaryTargetErasing) {
577 extendedStrokes <<
KeyStroke(
m_d->currentKeyStrokeDevice,
m_d->currentColor);
580 Q_FOREACH (
const KeyStroke &stroke, extendedStrokes) {
584 if (stroke.
color ==
m_d->currentColor ||
585 (isTemporaryTargetErasing &&
618template <
class DeviceMetricPolicy>
623 if (
m_d->shouldShowFilteredSource()) {
624 rc |= boundsPolicy(
m_d->filteredSource);
627 if (
m_d->shouldShowColoring()) {
628 rc |= boundsPolicy(
m_d->coloringProjection);
631 if (
m_d->showKeyStrokes) {
633 rc |= boundsPolicy(stroke.
dev);
639 if (temporaryTarget) {
667 auto it =
m_d->keyStrokes.begin();
668 for(; it !=
m_d->keyStrokes.end(); ++it) {
669 it->dev->setDefaultBounds(
bounds);
672 m_d->coloringProjection->setDefaultBounds(
bounds);
673 m_d->fakePaintDevice->setDefaultBounds(
bounds);
674 m_d->filteredSource->setDefaultBounds(
bounds);
684 m_d->setNeedsUpdateImpl(
true,
false);
687 std::find_if(
m_d->keyStrokes.constBegin(),
688 m_d->keyStrokes.constEnd(),
692 bool newKeyStroke =
false;
694 if (it ==
m_d->keyStrokes.constEnd()) {
700 activeDevice = it->dev;
703 m_d->currentColor = color;
704 m_d->currentKeyStrokeDevice = activeDevice;
705 m_d->needAddCurrentKeyStroke = newKeyStroke;
713 m_index(
index), m_stroke(stroke),
714 m_list(list), m_node(node) {}
717 m_list->insert(m_index, m_stroke);
718 m_node->setNeedsUpdate(
true);
719 Q_EMIT m_node->sigKeyStrokesListChanged();
724 m_list->removeAt(m_index);
725 m_node->setNeedsUpdate(
true);
726 Q_EMIT m_node->sigKeyStrokesListChanged();
765 if (
m_d->needAddCurrentKeyStroke && !isTemporaryTargetErasing) {
777 if (!isTemporaryTargetErasing) {
778 mergeToLayerImpl(
m_d->currentKeyStrokeDevice, parentCommand, transactionText, timedID,
false, sharedWriteLock, &jobs);
781 if (temporaryExtent.intersects(stroke.
dev->
extent())) {
782 mergeToLayerImpl(stroke.
dev, parentCommand, transactionText, timedID,
false, sharedWriteLock, &jobs);
787 mergeToLayerImpl(
m_d->fakePaintDevice, parentCommand, transactionText, timedID,
false, sharedWriteLock, &jobs);
797 fakeExecutor.
addRunnableJobs(implicitCastList<KisRunnableStrokeJobDataBase*>(jobs));
799 m_d->currentKeyStrokeDevice = 0;
806 if (isTemporaryTargetErasing) {
827 painter->
bitBlt(rc.topLeft(), src, rc);
833 painter->
bitBlt(rc.topLeft(), tempSelection, rc);
844 return m_d->showColoring;
857 if (!savedExtent.isEmpty()) {
864 return m_d->showKeyStrokes;
870 if (
m_d->showKeyStrokes && !
value) {
877 if (!savedExtent.isEmpty()) {
889 for (
int i = 0; i <
m_d->keyStrokes.size(); i++) {
890 colors.
colors <<
m_d->keyStrokes[i].color;
892 if (
m_d->keyStrokes[i].isTransparent) {
902 : m_newList(newList),
910 m_node->setNeedsUpdate(
true);
911 Q_EMIT m_node->sigKeyStrokesListChanged();
918 m_node->setNeedsUpdate(
true);
919 Q_EMIT m_node->sigKeyStrokesListChanged();
936 for (
int i = 0; i < newList.size(); i++) {
937 newList[i].color = colors.
colors[i];
959 std::find_if(
m_d->keyStrokes.begin(),
960 m_d->keyStrokes.end(),
965 const int index = it -
m_d->keyStrokes.begin();
984 devices << stroke.
dev;
987 devices <<
m_d->coloringProjection;
988 devices <<
m_d->fakePaintDevice;
995 m_d->filteredSource->clear();
996 m_d->originalSequenceNumber = -1;
997 m_d->filteringDirty =
true;
1005 m_d->filteringOptions.useEdgeDetection =
value;
1006 m_d->filteringDirty =
true;
1012 return m_d->filteringOptions.useEdgeDetection;
1017 m_d->filteringOptions.edgeDetectionSize =
value;
1018 m_d->filteringDirty =
true;
1024 return m_d->filteringOptions.edgeDetectionSize;
1029 m_d->filteringOptions.fuzzyRadius =
value;
1030 m_d->filteringDirty =
true;
1036 return m_d->filteringOptions.fuzzyRadius;
1041 m_d->filteringOptions.cleanUpAmount =
value;
1047 return m_d->filteringOptions.cleanUpAmount;
1053 m_d->filteringDirty =
true;
1059 return m_d->limitToDeviceBounds;
1064 m_d->fakePaintDevice->clear();
1081 m_d->keyStrokes <<
KeyStroke(dev, color, isTransparent);
1087 m_d->updateIsRunning =
false;
1092 return m_d->filteredSource;
1097 return m_d->keyStrokes;
1102 m_d->keyStrokes = strokes;
1104 for (
auto it =
m_d->keyStrokes.begin(); it !=
m_d->keyStrokes.end(); ++it) {
1105 it->dev->setParentNode(
this);
1114 return m_d->offset.x();
1119 return m_d->offset.y();
1124 const QPoint oldOffset =
m_d->offset;
1125 m_d->offset.rx() =
x;
1131 const QPoint oldOffset =
m_d->offset;
1132 m_d->offset.ry() =
y;
1140 auto it =
m_d->keyStrokes.begin();
1141 for(; it !=
m_d->keyStrokes.end(); ++it) {
1145 list <<
m_d->coloringProjection;
1146 list <<
m_d->fakePaintDevice;
1147 list <<
m_d->filteredSource;
1159 if (!
m_d->filteredSourceValid(src)) {
float value(const T *src, size_t ch)
QVector< KisImageSignalType > KisImageSignalVector
const QString COMPOSITE_MULT
const QString COMPOSITE_ERASE
const QString COMPOSITE_BEHIND
PythonPluginManager * instance
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void slotRegenerationCancelled()
KisBaseNode::PropertyList sectionModelProperties() const override
bool limitToDeviceBounds() const
void setShowColoring(bool value)
friend struct SetKeyStrokesColorSpaceCommand
bool showColoring() const
void mergeToLayerThreaded(KisNodeSP layer, KUndo2Command *parentCommand, const KUndo2MagicString &transactionText, int timedID, QVector< KisRunnableStrokeJobData * > *jobs) override
qreal cleanUpAmount() const
QIcon icon() const override
QRect nonDependentExtent() const override
friend struct SetKeyStrokeColorsCommand
void setKeyStrokesDirect(const QList< KisLazyFillTools::KeyStroke > &strokes)
void setEdgeDetectionSize(qreal value)
void setLimitToDeviceBounds(bool value)
KisPaintDeviceList getLodCapableDevices() const override
KisColorizeMask(KisImageWSP image, const QString &name)
friend struct KeyStrokeAddRemoveCommand
const KoColorSpace * colorSpace() const override
void moveAllInternalDevices(const QPoint &diff)
void setSectionModelProperties(const KisBaseNode::PropertyList &properties) override
void setProfile(const KoColorProfile *profile, KUndo2Command *parentCommand)
void setUseEdgeDetection(bool value)
void setKeyStrokesColors(KeyStrokeColors colors)
void regeneratePrefilteredDeviceIfNeeded()
const QScopedPointer< Private > m_d
QRect extent() const override
qreal fuzzyRadius() const
qint32 y() const override
void initializeCompositeOp()
void setCurrentColor(const KoColor &color) override
void slotRegenerationFinished(bool prefilterOnly)
QRect decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst, const QRect &rc, PositionToFilthy maskPos, KisRenderPassFlags flags) const override
~KisColorizeMask() override
bool accept(KisNodeVisitor &v) override
KisPaintDeviceSP testingFilteredSource() const
KisPaintDeviceSP coloringProjection() const
void slotUpdateRegenerateFilling(bool prefilterOnly=false)
void setFuzzyRadius(qreal value)
KisPaintDeviceSP colorSampleSourceDevice() const override
void setShowKeyStrokes(bool value)
QVector< KisPaintDeviceSP > allPaintDevices() const
void mergeToLayerUnthreaded(KisNodeSP layer, KUndo2Command *parentCommand, const KUndo2MagicString &transactionText, int timedID)
bool useEdgeDetection() const
void slotUpdateOnDirtyParent()
void setImage(KisImageWSP image) override
bool showKeyStrokes() const
void removeKeyStroke(const KoColor &color)
void slotRecalculatePrefilteredImage()
void rerenderFakePaintDevice()
KisPaintDeviceSP paintDevice() const override
void writeMergeData(KisPainter *painter, KisPaintDeviceSP src, const QRect &rc) override
KUndo2Command * setColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KoUpdater *progressUpdater=nullptr)
void testingAddKeyStroke(KisPaintDeviceSP dev, const KoColor &color, bool isTransparent=false)
bool supportsNonIndirectPainting() const override
void sigUpdateOnDirtyParent() const
KeyStrokeColors keyStrokesColors() const
void setNeedsUpdate(bool value)
QList< KisLazyFillTools::KeyStroke > fetchKeyStrokesDirect() const
void setCleanUpAmount(qreal value)
qreal edgeDetectionSize() const
void setY(qint32 y) override
QRect exactBounds() const override
void forceRegenerateMask()
QRect calculateMaskBounds(DeviceMetricPolicy policy) const
void setX(qint32 x) override
void sigKeyStrokesListChanged()
qint32 x() const override
void setFilteringOptions(const KisLazyFillTools::FilteringOptions &value)
void addKeyStroke(KisPaintDeviceSP dev, const KoColor &color)
void addRunnableJobs(const QVector< KisRunnableStrokeJobDataBase * > &list) override
void fillSelection(const QRect &rc, const KoColor &color)
KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override
QRect bounds() const override
void endStroke(KisStrokeId id) override
static const KoID colorizeEditKeyStrokes
static const KoID colorizeShowColoring
static KisBaseNode::Property getProperty(const KoID &id, bool state)
static const KoID colorizeNeedsUpdate
void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
int sequenceNumber() const
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
QRect exactBounds() const
const KoColorSpace * colorSpace() const
void setParentNode(KisNodeWSP parent)
void moveTo(qint32 x, qint32 y)
void setSelection(KisSelectionSP selection)
void setOpacityF(qreal opacity)
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void setOpacityU8(quint8 opacity)
Set the opacity which is used in painting (like filling polygons)
void setCompositeOpId(const KoCompositeOp *op)
void applyCommand(KUndo2Command *command, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
virtual void visit(KisNode *node, KisUndoAdapter *undoAdapter)=0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
static KoColor createTransparent(const KoColorSpace *cs)
const KoColorSpace * colorSpace() const
return the current colorSpace
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
KisSharedPtr< KisDefaultBoundsBase > KisDefaultBoundsBaseSP
KisSharedPtr< KisPaintDevice > KisPaintDeviceSP
KisSharedPtr< KisNode > KisNodeSP
KUndo2MagicString kundo2_i18n(const char *text)
QIcon loadIcon(const QString &name)
void addJobSequential(QVector< Job * > &jobs, Func func)
qreal estimatePortionOfTransparentPixels(KisPaintDeviceSP dev, const QRect &rect, qreal samplePortion)
auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value)
mem_equal_to is an unary functor that compares a member of the object to a given value
QList< KeyStroke > * m_list
KeyStrokeAddRemoveCommand(bool add, int index, KeyStroke stroke, QList< KeyStroke > *list, KisColorizeMaskSP node, KUndo2Command *parentCommand=nullptr)
const QString & compositeOpId() const
virtual KisPaintDeviceSP original() const =0
virtual PropertyList sectionModelProperties() const
void setCompositeOpId(const QString &compositeOpId)
virtual void setSectionModelProperties(const PropertyList &properties)
QVector< KoColor > colors
QStack< QRect > extentBeforeUpdateStart
KisCachedSelection cachedSelection
KisThreadSafeSignalCompressor prefilterRecalculationCompressor
bool shouldShowFilteredSource() const
void setNeedsUpdateImpl(bool value, bool requestedByUser)
bool shouldShowColoring() const
KisPaintDeviceSP filteredSource
bool filteredSourceValid(KisPaintDeviceSP parentDevice)
QList< KeyStroke > keyStrokes
bool needAddCurrentKeyStroke
int originalSequenceNumber
FilteringOptions filteringOptions
Private(const Private &rhs, KisColorizeMask *_q)
KisThreadSafeSignalCompressor dirtyParentUpdateCompressor
Private(KisColorizeMask *_q, KisImageWSP image)
KisPaintDeviceSP coloringProjection
KisPaintDeviceSP currentKeyStrokeDevice
KisPaintDeviceSP fakePaintDevice
QRect filteredDeviceBounds
KisThreadSafeSignalCompressor updateCompressor
void addCommand(KUndo2Command *cmd)
void setupTemporaryPainter(KisPainter *painter) const
KisPaintDeviceSP temporaryTarget
void mergeToLayerImpl(KisPaintDeviceSP dst, KUndo2Command *parentCommand, const KUndo2MagicString &transactionText, int timedID, bool cleanResources, WriteLockerSP sharedWriteLock, QVector< KisRunnableStrokeJobData * > *jobs)
QString temporaryCompositeOp() const
KisPaintDeviceSP original() const override=0
KisPaintDeviceSP projection() const override
void baseNodeChangedCallback() override
int index(const KisNodeSP node) const
bool add(KisNodeSP newNode, KisNodeSP aboveThis, KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
void copyAlphaFrom(KisPaintDeviceSP src, const QRect &processRect)
QRect selectedRect() const
KisPixelSelectionSP pixelSelection
static KoColorSpaceRegistry * instance()
const KoColorSpace * alpha8()
QList< KeyStroke > * m_list
QList< KeyStroke > m_newList
QList< KeyStroke > m_oldList
SetKeyStrokeColorsCommand(const QList< KeyStroke > newList, QList< KeyStroke > *list, KisColorizeMaskSP node)
const KoColorSpace * m_dstCS
KoColorConversionTransformation::Intent m_renderingIntent
SetKeyStrokesColorSpaceCommand(const KoColorSpace *dstCS, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, QList< KeyStroke > *list, KisColorizeMaskSP node)
QList< KeyStroke > * m_list
KoColorConversionTransformation::ConversionFlags m_conversionFlags
QVector< KoColor > m_newColors
QVector< KoColor > m_oldColors