Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_node.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_node.h"
8
9#include <QList>
10#include <QReadWriteLock>
11#include <QReadLocker>
12#include <QWriteLocker>
13#include <QPainterPath>
14#include <QRect>
15#include <QCoreApplication>
16
17#include <KoProperties.h>
18
19#include "kis_global.h"
21#include "kis_node_visitor.h"
26
27#include "kis_clone_layer.h"
28
29#include "kis_time_span.h"
30
31#include "kis_safe_read_list.h"
33
35#include "kis_projection_leaf.h"
36#include "kis_undo_adapter.h"
38#include "kis_image.h"
39#include "kis_layer_utils.h"
40#include "KisRegion.h"
42
49 qRegisterMetaType<KisNodeSP>("KisNodeSP");
50 qRegisterMetaType<KisNodeList>("KisNodeList");
51 qRegisterMetaType<KisNodeAdditionFlags>("KisNodeAdditionFlags");
52}
53
54
75struct Q_DECL_HIDDEN KisNode::Private
76{
77public:
79 : graphListener(0)
80 , nodeProgressProxy(0)
81 , busyProgressIndicator(0)
82 , projectionLeaf(new KisProjectionLeaf(node))
83 {
84 }
85
91 QReadWriteLock nodeSubgraphLock;
92
94
95 const KisNode* findSymmetricClone(const KisNode *srcRoot,
96 const KisNode *dstRoot,
97 const KisNode *srcTarget);
98 void processDuplicatedClones(const KisNode *srcDuplicationRoot,
99 const KisNode *dstDuplicationRoot,
100 KisNode *node);
101
102 std::optional<KisFrameChangeUpdateRecipe> frameRemovalUpdateRecipe;
104};
105
110const KisNode* KisNode::Private::findSymmetricClone(const KisNode *srcRoot,
111 const KisNode *dstRoot,
112 const KisNode *srcTarget)
113{
114 if (srcRoot == srcTarget) return dstRoot;
115
116 KisSafeReadNodeList::const_iterator srcIter = srcRoot->m_d->nodes.constBegin();
117 KisSafeReadNodeList::const_iterator dstIter = dstRoot->m_d->nodes.constBegin();
118
119 for (; srcIter != srcRoot->m_d->nodes.constEnd(); srcIter++, dstIter++) {
120
121 KIS_ASSERT_RECOVER_RETURN_VALUE((srcIter != srcRoot->m_d->nodes.constEnd()) ==
122 (dstIter != dstRoot->m_d->nodes.constEnd()), 0);
123
124 const KisNode *node = findSymmetricClone(srcIter->data(), dstIter->data(), srcTarget);
125 if (node) return node;
126
127 }
128
129 return 0;
130}
131
142void KisNode::Private::processDuplicatedClones(const KisNode *srcDuplicationRoot,
143 const KisNode *dstDuplicationRoot,
144 KisNode *node)
145{
146 if (KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node)) {
147 KIS_ASSERT_RECOVER_RETURN(clone->copyFrom());
148 const KisNode *newCopyFrom = findSymmetricClone(srcDuplicationRoot,
149 dstDuplicationRoot,
150 clone->copyFrom());
151
152 if (newCopyFrom) {
153 KisLayer *newCopyFromLayer = qobject_cast<KisLayer*>(const_cast<KisNode*>(newCopyFrom));
154 KIS_ASSERT_RECOVER_RETURN(newCopyFromLayer);
155
156 clone->setCopyFrom(newCopyFromLayer);
157 }
158 }
159
160 KisSafeReadNodeList::const_iterator iter;
161 FOREACH_SAFE(iter, node->m_d->nodes) {
162 KisNode *child = const_cast<KisNode*>((*iter).data());
163 processDuplicatedClones(srcDuplicationRoot, dstDuplicationRoot, child);
164 }
165}
166
168 : KisBaseNode(image),
169 m_d(new Private(this))
170{
171 m_d->parent = 0;
172 m_d->graphListener = 0;
173 moveToThread(qApp->thread());
174}
175
177 : KisBaseNode(rhs)
178 , m_d(new Private(this))
179{
180 m_d->parent = 0;
181 m_d->graphListener = 0;
182 moveToThread(qApp->thread());
183
184 // NOTE: the nodes are not supposed to be added/removed while
185 // creation of another node, so we do *no* locking here!
186
187 KisSafeReadNodeList::const_iterator iter;
188 FOREACH_SAFE(iter, rhs.m_d->nodes) {
189 KisNodeSP child = (*iter)->clone();
191 m_d->nodes.append(child);
192 child->setParent(this);
193 }
194
195 m_d->processDuplicatedClones(&rhs, this, this);
196}
197
199{
200 if (m_d->busyProgressIndicator) {
201 m_d->busyProgressIndicator->prepareDestroying();
202 m_d->busyProgressIndicator->deleteLater();
203 }
204
205 if (m_d->nodeProgressProxy) {
206 m_d->nodeProgressProxy->prepareDestroying();
207 m_d->nodeProgressProxy->deleteLater();
208 }
209
210 {
211 QWriteLocker l(&m_d->nodeSubgraphLock);
212 m_d->nodes.clear();
213 }
214
215 delete m_d;
216}
217
218QRect KisNode::needRect(const QRect &rect, PositionToFilthy pos) const
219{
220 Q_UNUSED(pos);
221 return rect;
222}
223
224QRect KisNode::changeRect(const QRect &rect, PositionToFilthy pos) const
225{
226 Q_UNUSED(pos);
227 return rect;
228}
229
230QRect KisNode::accessRect(const QRect &rect, PositionToFilthy pos) const
231{
232 Q_UNUSED(pos);
233 return rect;
234}
235
236void KisNode::childNodeChanged(KisNodeSP /*changedChildNode*/)
237{
238}
239
241{
242 KIS_ASSERT_RECOVER_NOOP(0 && "KisNode::projectionPlane() is not defined!");
243 static KisAbstractProjectionPlaneSP plane =
245
246 return plane;
247}
248
250{
251 return m_d->projectionLeaf;
252}
253
255{
256 KisBaseNode::setImage(newImage);
257
258 KisNodeSP node = firstChild();
259 while (node) {
261 [newImage] (KisNodeSP node) {
262 node->setImage(newImage);
263 });
264
265 node = node->nextSibling();
266 }
267}
268
270{
271 return v.visit(this);
272}
273
275{
276 visitor.visit(this, undoAdapter);
277}
278
280{
281 return m_d->graphListener ? m_d->graphListener->graphSequenceNumber() : -1;
282}
283
285{
286 return m_d->graphListener;
287}
288
290{
291 m_d->graphListener = graphListener;
292
293 QReadLocker l(&m_d->nodeSubgraphLock);
294 KisSafeReadNodeList::const_iterator iter;
295 FOREACH_SAFE(iter, m_d->nodes) {
296 KisNodeSP child = (*iter);
298 }
299}
300
302{
303 QWriteLocker l(&m_d->nodeSubgraphLock);
304 m_d->parent = parent;
305}
306
308{
309 QReadLocker l(&m_d->nodeSubgraphLock);
310 return m_d->parent.isValid() ? KisNodeSP(m_d->parent) : KisNodeSP();
311}
312
314{
315 return parent();
316}
317
319{
320 QReadLocker l(&m_d->nodeSubgraphLock);
321
322 KisSafeReadNodeList::const_iterator iter;
323 FOREACH_SAFE(iter, m_d->nodes) {
324 KisNodeSP child = (*iter);
326 }
327}
328
330{
331 if(m_d->graphListener) {
332 m_d->graphListener->nodeChanged(this);
333 Q_EMIT sigNodeChangedInternal();
334 }
335}
336
338{
339 if(m_d->graphListener) {
340 m_d->graphListener->invalidateAllFrames();
341 }
342}
343
345{
346 if(m_d->graphListener) {
347 m_d->graphListener->nodeCollapsedChanged(this);
348 }
349}
350
352{
353 channel->setNode(this);
355
356 if (m_d->graphListener) {
357 m_d->graphListener->keyframeChannelHasBeenAdded(this, channel);
358 }
359}
360
362{
363 QReadLocker l(&m_d->nodeSubgraphLock);
364 return !m_d->nodes.isEmpty() ? m_d->nodes.first() : 0;
365}
366
368{
369 QReadLocker l(&m_d->nodeSubgraphLock);
370 return !m_d->nodes.isEmpty() ? m_d->nodes.last() : 0;
371}
372
374{
385 QReadLocker l(&m_d->nodeSubgraphLock);
386
387 int i = m_d->nodes.indexOf(child) - 1;
388 return i >= 0 ? m_d->nodes.at(i) : 0;
389}
390
392{
396 QReadLocker l(&m_d->nodeSubgraphLock);
397
398 int i = m_d->nodes.indexOf(child) + 1;
399 return i > 0 && i < m_d->nodes.size() ? m_d->nodes.at(i) : 0;
400}
401
403{
404 KisNodeSP parentNode = parent();
405 return parentNode ? parentNode->prevChildImpl(const_cast<KisNode*>(this)) : 0;
406}
407
409{
410 KisNodeSP parentNode = parent();
411 return parentNode ? parentNode->nextChildImpl(const_cast<KisNode*>(this)) : 0;
412}
413
414quint32 KisNode::childCount() const
415{
416 QReadLocker l(&m_d->nodeSubgraphLock);
417 return m_d->nodes.size();
418}
419
420
421KisNodeSP KisNode::at(quint32 index) const
422{
423 QReadLocker l(&m_d->nodeSubgraphLock);
424
425 if (!m_d->nodes.isEmpty() && index < (quint32)m_d->nodes.size()) {
426 return m_d->nodes.at(index);
427 }
428
429 return 0;
430}
431
432int KisNode::index(const KisNodeSP node) const
433{
434 QReadLocker l(&m_d->nodeSubgraphLock);
435
436 return m_d->nodes.indexOf(node);
437}
438
439QList<KisNodeSP> KisNode::childNodes(const QStringList & nodeTypes, const KoProperties & properties) const
440{
441 QReadLocker l(&m_d->nodeSubgraphLock);
442
444
445 KisSafeReadNodeList::const_iterator iter;
446 FOREACH_SAFE(iter, m_d->nodes) {
447 if (*iter) {
448 if (properties.isEmpty() || (*iter)->check(properties)) {
449 bool rightType = true;
450
451 if(!nodeTypes.isEmpty()) {
452 rightType = false;
453 Q_FOREACH (const QString &nodeType, nodeTypes) {
454 if ((*iter)->inherits(nodeType.toLatin1())) {
455 rightType = true;
456 break;
457 }
458 }
459 }
460 if (rightType) {
461 nodes.append(*iter);
462 }
463 }
464 }
465 }
466 return nodes;
467}
468
469bool KisNode::add(KisNodeSP newNode, KisNodeSP aboveThis, KisNodeAdditionFlags flags)
470{
472 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!aboveThis || aboveThis->parent().data() == this, false);
475 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(index(newNode) < 0, false);
476
477 int idx = aboveThis ? this->index(aboveThis) + 1 : 0;
478
479 // theoretical race condition may happen here ('idx' may become
480 // deprecated until the write lock will be held). But we ignore
481 // it, because it is not supported to add/remove nodes from two
482 // concurrent threads simultaneously
483
484 if (m_d->graphListener) {
485 m_d->graphListener->aboutToAddANode(this, idx);
486 }
487
488 {
489 QWriteLocker l(&m_d->nodeSubgraphLock);
490
491 newNode->createNodeProgressProxy();
492
493 m_d->nodes.insert(idx, newNode);
494
495 newNode->setParent(this);
496 newNode->setGraphListener(m_d->graphListener);
497 }
498
499 newNode->setImage(image());
500
501 if (m_d->graphListener) {
502 m_d->graphListener->nodeHasBeenAdded(this, idx, flags);
503 }
504
505 childNodeChanged(newNode);
506
507 return true;
508}
509
510bool KisNode::remove(quint32 index)
511{
512 if (index < childCount()) {
513 KisNodeSP removedNode = at(index);
514
515 if (m_d->graphListener) {
516 m_d->graphListener->aboutToRemoveANode(this, index);
517 }
518
519 removedNode->setImage(0);
520
521 {
522 QWriteLocker l(&m_d->nodeSubgraphLock);
523
524 removedNode->setGraphListener(0);
525
526 removedNode->setParent(0); // after calling aboutToRemoveANode or then the model get broken according to TT's modeltest
527 m_d->nodes.removeAt(index);
528 }
529
530 if (m_d->graphListener) {
531 m_d->graphListener->nodeHasBeenRemoved(this, index);
532 }
533
534 childNodeChanged(removedNode);
535
536 return true;
537 }
538 return false;
539}
540
542{
543 return node->parent().data() == this ? remove(index(node)) : false;
544}
545
547{
548 if (m_d->nodeProgressProxy) {
549 return m_d->nodeProgressProxy;
550 } else if (parent()) {
551 return parent()->nodeProgressProxy();
552 }
553 return 0;
554}
555
557{
558 if (m_d->busyProgressIndicator) {
559 return m_d->busyProgressIndicator;
560 } else if (parent()) {
561 return parent()->busyProgressIndicator();
562 }
563 return 0;
564}
565
567{
568 if (!m_d->nodeProgressProxy) {
569 m_d->nodeProgressProxy = new KisNodeProgressProxy(this);
570 m_d->busyProgressIndicator = new KisBusyProgressIndicator(m_d->nodeProgressProxy);
571
572 m_d->nodeProgressProxy->moveToThread(this->thread());
573 m_d->busyProgressIndicator->moveToThread(this->thread());
574 }
575}
576
578{
579 setDirty(extent());
580}
581
583{
584 if(m_d->graphListener) {
585 m_d->graphListener->requestProjectionUpdate(this, rects, KisProjectionUpdateFlag::None);
586 }
587}
588
589void KisNode::setDirty(const KisRegion &region)
590{
591 setDirty(region.rects());
592}
593
594void KisNode::setDirty(const QRect & rect)
595{
597}
598
603
608
610{
611 if(m_d->graphListener) {
612 m_d->graphListener->requestProjectionUpdate(this, rects, KisProjectionUpdateFlag::DontInvalidateFrames);
613 }
614}
615
616void KisNode::invalidateFrames(const KisTimeSpan &range, const QRect &rect)
617{
618 if(m_d->graphListener) {
619 m_d->graphListener->invalidateFrames(range, rect);
620 }
621}
622
624KisNode::Private::handleKeyframeChannelUpdateImpl(const KisKeyframeChannel *channel, int time)
625{
627
628 recipe.affectedRange = channel->affectedFrames(time);
629 recipe.affectedRect = channel->affectedRect(time);
630
631 if (parent->image()) {
632 KisDefaultBoundsSP bounds(new KisDefaultBounds(parent->image()));
633
634 if (recipe.affectedRange.contains(bounds->currentTime())) {
635 recipe.totalDirtyRect = recipe.affectedRect;
636 }
637 }
638
639 return recipe;
640}
641
643{
644 m_d->handleKeyframeChannelUpdateImpl(channel, time).notify(this);
645}
646
648{
649 m_d->handleKeyframeChannelUpdateImpl(channel, time).notify(this);
650}
651
653{
654 return m_d->handleKeyframeChannelUpdateImpl(channel, time);
655}
656
658{
659 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->frameRemovalUpdateRecipe);
660 m_d->frameRemovalUpdateRecipe = handleKeyframeChannelFrameAboutToBeRemovedImpl(channel, time);
661}
662
664{
665 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->frameRemovalUpdateRecipe);
666 m_d->frameRemovalUpdateRecipe->notify(this);
667 m_d->frameRemovalUpdateRecipe = std::nullopt;
668}
669
671{
672 if(m_d->graphListener) {
673 m_d->graphListener->requestTimeSwitch(time);
674 }
675}
676
678{
679 // noop. everything is done by getLodCapableDevices()
680}
681
683{
685
686 KisPaintDeviceSP device = paintDevice();
687 if (device) {
688 list << device;
689 }
690
691 KisPaintDeviceSP originalDevice = original();
692 if (originalDevice && originalDevice != device) {
693 list << originalDevice;
694 }
695
696 list << projectionPlane()->getLodCapableDevices();
697
698 return list;
699}
float value(const T *src, size_t ch)
qreal v
char nodeType(const KoPathPoint *point)
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
virtual KisTimeSpan affectedFrames(int time) const
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
void setNode(KisNodeWSP node)
virtual QRect affectedRect(int time) const =0
virtual void visit(KisNode *node, KisUndoAdapter *undoAdapter)=0
QVector< QRect > rects() const
bool contains(int time) const
bool isEmpty() const
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define bounds(x, a, b)
qRegisterMetaType< KisNodeAdditionFlags >("KisNodeAdditionFlags")
KIS_DECLARE_STATIC_INITIALIZER
Definition kis_node.cpp:48
qRegisterMetaType< KisNodeList >("KisNodeList")
KisSafeReadList< KisNodeSP > KisSafeReadNodeList
Definition kis_node.cpp:32
QSharedPointer< T > toQShared(T *ptr)
#define FOREACH_SAFE(_iter, _container)
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
void recursiveApplyNodes(NodePointer node, Functor func)
virtual void setImage(KisImageWSP image)
virtual KisPaintDeviceSP original() const =0
KoProperties properties
KisImageWSP image
virtual QRect extent() const
virtual KisPaintDeviceSP paintDevice() const =0
virtual void addKeyframeChannel(KisKeyframeChannel *channel)
void baseNodeInvalidateAllFramesCallback() override
Definition kis_node.cpp:337
void notifyParentVisibilityChanged(bool value) override
Definition kis_node.cpp:318
virtual void handleKeyframeChannelFrameAdded(const KisKeyframeChannel *channel, int time)
Definition kis_node.cpp:647
void setParent(KisNodeWSP parent)
Definition kis_node.cpp:301
void setDirtyDontResetAnimationCache()
Definition kis_node.cpp:599
KisNodeSP prevSibling() const
Definition kis_node.cpp:402
KisNode(KisImageWSP image)
Definition kis_node.cpp:167
KisNodeSP nextChildImpl(KisNodeSP child)
Definition kis_node.cpp:391
Private(KisNode *node)
Definition kis_node.cpp:78
bool remove(quint32 index)
Definition kis_node.cpp:510
void baseNodeCollapsedChangedCallback() override
Definition kis_node.cpp:344
void baseNodeChangedCallback() override
Definition kis_node.cpp:329
const KisNode * findSymmetricClone(const KisNode *srcRoot, const KisNode *dstRoot, const KisNode *srcTarget)
virtual KisPaintDeviceList getLodCapableDevices() const
Definition kis_node.cpp:682
KisNodeSP firstChild() const
Definition kis_node.cpp:361
QList< KisNodeSP > childNodes(const QStringList &nodeTypes, const KoProperties &properties) const
Definition kis_node.cpp:439
void handleKeyframeChannelFrameHasBeenRemoved(const KisKeyframeChannel *channel, int time)
Definition kis_node.cpp:663
KisBusyProgressIndicator * busyProgressIndicator
Definition kis_node.cpp:90
KisSafeReadNodeList nodes
Definition kis_node.cpp:88
void handleKeyframeChannelFrameAboutToBeRemoved(const KisKeyframeChannel *channel, int time)
Definition kis_node.cpp:657
void setImage(KisImageWSP newImage) override
Definition kis_node.cpp:254
virtual KisAbstractProjectionPlaneSP projectionPlane() const
Definition kis_node.cpp:240
KisProjectionLeafSP projectionLeaf
Definition kis_node.cpp:93
KisBaseNodeSP parentCallback() const override
Definition kis_node.cpp:313
~KisNode() override
Definition kis_node.cpp:198
KisNodeSP prevChildImpl(KisNodeSP child)
Definition kis_node.cpp:373
int index(const KisNodeSP node) const
Definition kis_node.cpp:432
virtual QRect changeRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const
Definition kis_node.cpp:224
void processDuplicatedClones(const KisNode *srcDuplicationRoot, const KisNode *dstDuplicationRoot, KisNode *node)
KisNodeProgressProxy * nodeProgressProxy
Definition kis_node.cpp:89
virtual QRect needRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const
Definition kis_node.cpp:218
int graphSequenceNumber() const
Definition kis_node.cpp:279
bool accept(KisNodeVisitor &v) override
Definition kis_node.cpp:269
virtual KisNodeSP clone() const =0
PositionToFilthy
Definition kis_node.h:58
quint32 childCount() const
Definition kis_node.cpp:414
void invalidateFrames(const KisTimeSpan &range, const QRect &rect)
Definition kis_node.cpp:616
virtual void syncLodCache()
Definition kis_node.cpp:677
void addKeyframeChannel(KisKeyframeChannel *channel) override
Definition kis_node.cpp:351
void createNodeProgressProxy()
Definition kis_node.cpp:566
virtual QRect accessRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const
Definition kis_node.cpp:230
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP lastChild() const
Definition kis_node.cpp:367
bool add(KisNodeSP newNode, KisNodeSP aboveThis, KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
Definition kis_node.cpp:469
void setGraphListener(KisNodeGraphListener *graphListener)
Definition kis_node.cpp:289
KisNodeSP at(quint32 index) const
Definition kis_node.cpp:421
Private *const m_d
Definition kis_node.h:415
KisNodeSP nextSibling() const
Definition kis_node.cpp:408
void sigNodeChangedInternal()
void requestTimeSwitch(int time)
Definition kis_node.cpp:670
virtual KisFrameChangeUpdateRecipe handleKeyframeChannelFrameAboutToBeRemovedImpl(const KisKeyframeChannel *channel, int time)
Definition kis_node.cpp:652
KisNodeGraphListener * graphListener
Definition kis_node.cpp:87
std::optional< KisFrameChangeUpdateRecipe > frameRemovalUpdateRecipe
Definition kis_node.cpp:102
virtual void childNodeChanged(KisNodeSP changedChildNode)
Definition kis_node.cpp:236
KisFrameChangeUpdateRecipe handleKeyframeChannelUpdateImpl(const KisKeyframeChannel *channel, int time)
QReadWriteLock nodeSubgraphLock
Definition kis_node.cpp:91
virtual void handleKeyframeChannelFrameChange(const KisKeyframeChannel *channel, int time)
Definition kis_node.cpp:642
virtual void setDirty()
Definition kis_node.cpp:577
virtual bool allowAsChild(KisNodeSP) const =0