Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_base_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_base_node.h"
8#include <klocalizedstring.h>
9
10#include <kis_image.h>
11#include <kis_icon.h>
12#include <KoProperties.h>
14#include <KoColorSpace.h>
16
17#include "kis_pointer_utils.h"
18
19#include "kis_paint_device.h"
22
24
25struct Q_DECL_HIDDEN KisBaseNode::Private
26{
27 QString compositeOp;
30 QUuid id;
31 QMap<QString, KisKeyframeChannel*> keyframeChannels;
33
34 bool collapsed {false};
35 bool supportsLodMoves {false};
36 bool animated {false};
37 bool pinnedToTimeline {false};
40
42 : id(QUuid::createUuid())
43 , opacityProperty(new KisDefaultBounds(p_image), &properties, OPACITY_OPAQUE_U8)
44 , image(p_image)
45 {
46 }
47
48 Private(const Private &rhs)
49 : compositeOp(rhs.compositeOp),
50 id(QUuid::createUuid()),
51 opacityProperty(new KisDefaultBounds(rhs.image), &properties, OPACITY_OPAQUE_U8),
52 collapsed(rhs.collapsed),
53 supportsLodMoves(rhs.supportsLodMoves),
54 animated(rhs.animated),
55 pinnedToTimeline(rhs.pinnedToTimeline),
56 image(rhs.image)
57 {
58 QMapIterator<QString, QVariant> iter = rhs.properties.propertyIterator();
59 while (iter.hasNext()) {
60 iter.next();
61 properties.setProperty(iter.key(), iter.value());
62 }
63 }
64};
65
67 : m_d(new Private(image))
68{
78 setVisible(true, true);
79 setUserLocked(false);
80 setCollapsed(false);
82
83 m_d->compositeOp = COMPOSITE_OVER;
84
85 connect(&m_d->opacityProperty, SIGNAL(changed(quint8)), this, SIGNAL(opacityChanged(quint8)));
86}
87
88
90 : QObject()
91 , KisShared()
92 , m_d(new Private(*rhs.m_d))
93{
94 if (rhs.m_d->opacityProperty.hasChannel()) {
95 m_d->opacityProperty.transferKeyframeData(rhs.m_d->opacityProperty);
96 m_d->keyframeChannels.insert(m_d->opacityProperty.channel()->id(), m_d->opacityProperty.channel());
97 }
98
99 connect(&m_d->opacityProperty, SIGNAL(changed(quint8)), this, SIGNAL(opacityChanged(quint8)));
100}
101
103{
104 delete m_d;
105}
106
111
113{
114 return m_d->opacityProperty.get();
115}
116
118{
119 m_d->opacityProperty.set(val);
121}
122
124{
125 return int(float(opacity() * 100) / 255 + 0.5);
126}
127
129{
130 setOpacity(int(float(val * 255) / 100 + 0.5));
131}
132
133const QString& KisBaseNode::compositeOpId() const
134{
135 return m_d->compositeOp;
136}
137
138void KisBaseNode::setCompositeOpId(const QString& compositeOp)
139{
140 if (m_d->compositeOp == compositeOp) return;
141
142 m_d->compositeOp = compositeOp;
145}
146
154
156{
157 setVisible(properties.at(0).state.toBool());
158 m_d->hack_visible = properties.at(0);
159 setUserLocked(properties.at(1).state.toBool());
160}
161
163{
164 return m_d->properties;
165}
166
167void KisBaseNode::setNodeProperty(const QString & name, const QVariant & value)
168{
169 m_d->properties.setProperty(name, value);
171}
172
174{
175 QMapIterator<QString, QVariant> iter = properties.propertyIterator();
176 while (iter.hasNext()) {
177 iter.next();
178 m_d->properties.setProperty(iter.key(), iter.value());
179 }
182}
183
184bool KisBaseNode::check(const KoProperties & properties) const
185{
186 QMapIterator<QString, QVariant> iter = properties.propertyIterator();
187 while (iter.hasNext()) {
188 iter.next();
189 if (m_d->properties.contains(iter.key())) {
190 if (m_d->properties.value(iter.key()) != iter.value())
191 return false;
192 }
193 }
194 return true;
195}
196
197
198QImage KisBaseNode::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode, KisThumbnailBoundsMode boundsMode)
199{
200 Q_UNUSED(aspectRatioMode);
201 Q_UNUSED(boundsMode);
202
203 try {
204 QImage image(w, h, QImage::Format_ARGB32);
205 image.fill(0);
206 return image;
207 } catch (const std::bad_alloc&) {
208 return QImage();
209 }
210
211}
212
213QImage KisBaseNode::createPreferredThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
214{
215 return createThumbnail(w, h, aspectRatioMode, m_d->thumbnailBoundsMode);
216}
217
219{
220 return m_d->thumbnailBoundsMode;
221}
222
227
229{
230 return -1;
231}
232
233QImage KisBaseNode::createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode, KisThumbnailBoundsMode boundsMode)
234{
235 Q_UNUSED(time);
236 return createThumbnail(w, h, aspectRatioMode, boundsMode);
237}
238
239QImage KisBaseNode::createPreferredThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode)
240{
241 return createThumbnailForFrame(w, h, time, aspectRatioMode, m_d->thumbnailBoundsMode);
242}
243
244bool KisBaseNode::visible(bool recursive) const
245{
246 bool isVisible = m_d->properties.boolProperty(KisLayerPropertiesIcons::visible.id(), true);
247 KisBaseNodeSP parentNode = parentCallback();
248
249 return recursive && isVisible && parentNode ?
250 parentNode->visible(recursive) : isVisible;
251}
252
253void KisBaseNode::setVisible(bool visible, bool loading)
254{
255 const bool isVisible = m_d->properties.boolProperty(KisLayerPropertiesIcons::visible.id(), true);
256 if (!loading && isVisible == visible) return;
257
258 m_d->properties.setProperty(KisLayerPropertiesIcons::visible.id(), visible);
260
261 if (!loading) {
264 }
265}
266
268{
269 return m_d->properties.boolProperty(KisLayerPropertiesIcons::locked.id(), false);
270}
271
273{
274 if (!m_d->image) {
275 return false;
276 }
277
278 const KisBaseNode* element = this;
279
280 while (element) {
281 if (element->isIsolatedRoot()) {
282 return true;
283 } else {
284 element = element->parentCallback().data();
285 }
286 }
287
288 return false;
289}
290
292{
293 if (!m_d->image) {
294 return false;
295 }
296
297 const KisBaseNode* isolatedRoot = m_d->image->isolationRootNode().data();
298
299 return (this == isolatedRoot);
300}
301
303{
304 const bool isLocked = m_d->properties.boolProperty(KisLayerPropertiesIcons::locked.id(), true);
305 if (isLocked == locked) return;
306
307 m_d->properties.setProperty(KisLayerPropertiesIcons::locked.id(), locked);
309}
310
311bool KisBaseNode::isEditable(bool checkVisibility) const
312{
313 bool editable = true;
314 if (checkVisibility) {
315 editable = ((visible(false) || belongsToIsolatedGroup()) && !userLocked());
316 }
317 else {
318 editable = (!userLocked());
319 }
320
321 if (editable) {
322 KisBaseNodeSP parentNode = parentCallback();
323 if (parentNode && parentNode != this) {
324 editable = parentNode->isEditable(checkVisibility);
325 }
326 }
327 return editable;
328}
329
331{
332 return paintDevice() && isEditable();
333}
334
335void KisBaseNode::setCollapsed(bool collapsed)
336{
337 const bool oldCollapsed = m_d->collapsed;
338
339 m_d->collapsed = collapsed;
340
341 if (oldCollapsed != collapsed) {
343 }
344}
345
346bool KisBaseNode::collapsed() const
347{
348 return m_d->collapsed;
349}
350
352{
353 const int currentLabel = colorLabelIndex();
354
355 if (currentLabel == index) return;
356
357 m_d->properties.setProperty(KisLayerPropertiesIcons::colorLabelIndex.id(), index);
359}
360
362{
363 return m_d->properties.intProperty(KisLayerPropertiesIcons::colorLabelIndex.id(), 0);
364}
365
366QUuid KisBaseNode::uuid() const
367{
368 return m_d->id;
369}
370
371void KisBaseNode::setUuid(const QUuid& id)
372{
373 m_d->id = id;
375}
376
378{
379 return m_d->supportsLodMoves;
380}
381
383{
384 return true;
385}
386
388{
389 m_d->image = image;
390 m_d->opacityProperty.updateDefaultBounds(new KisDefaultBounds(image));
391}
392
394{
395 return m_d->image;
396}
397
399{
400 return false;
401}
402
404{
405 m_d->supportsLodMoves = value;
406}
407
408
409QMap<QString, KisKeyframeChannel*> KisBaseNode::keyframeChannels() const
410{
411 return m_d->keyframeChannels;
412}
413
415{
416 QMap<QString, KisKeyframeChannel*>::const_iterator i = m_d->keyframeChannels.constFind(id);
417 if (i == m_d->keyframeChannels.constEnd()) {
418 return 0;
419 }
420 return i.value();
421}
422
424{
425 return m_d->pinnedToTimeline;
426}
427
429{
430 if (pinned == m_d->pinnedToTimeline) return;
431
432 m_d->pinnedToTimeline = pinned;
434}
435
437{
439
440 if (!channel && create) {
441 channel = requestKeyframeChannel(id);
442
443 if (channel) {
444 addKeyframeChannel(channel);
445 }
446 }
447
448 return channel;
449}
450
452{
453 return m_d->animated;
454}
455
457{
458 m_d->animated = true;
460}
461
463{
464 m_d->keyframeChannels.insert(channel->id(), channel);
465 Q_EMIT keyframeChannelAdded(channel);
466}
467
469{
470 if (id == KisKeyframeChannel::Opacity.id()) {
471 Q_ASSERT(!m_d->opacityProperty.hasChannel());
472
473 KisPaintDeviceSP device = original();
474 KisNode* node = dynamic_cast<KisNode*>(this);
475
476 if (device && node) {
477 m_d->opacityProperty.makeAnimated(node);
478 return m_d->opacityProperty.channel();
479 }
480 }
481
482 return 0;
483}
484
486{
487 if (id == KisKeyframeChannel::Opacity.id() && original()) {
488 return true;
489 }
490
491 return false;
492}
493
494QDebug operator<<(QDebug dbg, const KisBaseNode::Property &prop)
495{
496 dbg.nospace() << "Property(" << prop.id << ", " << prop.state;
497
498 if (prop.isInStasis) {
499 dbg.nospace() << ", in-stasis";
500 }
501
502 dbg.nospace() << ")";
503
504 return dbg.space();
505}
float value(const T *src, size_t ch)
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
static const KoID Opacity
static KisBaseNode::Property getProperty(const KoID &id, bool state)
QMapIterator< QString, QVariant > propertyIterator() const
void setProperty(const QString &name, const QVariant &value)
QDebug operator<<(QDebug dbg, const KisBaseNode::Property &prop)
KisThumbnailBoundsMode
Definition kis_types.h:336
void setPinnedToTimeline(bool pinned)
void setNodeProperty(const QString &name, const QVariant &value)
void setSupportsLodMoves(bool value)
virtual bool supportsLodPainting() const
QMap< QString, KisKeyframeChannel * > keyframeChannels
quint8 percentOpacity() const
virtual KisPaintDeviceSP colorSampleSourceDevice() const
virtual void setUserLocked(bool l)
bool isIsolatedRoot() const
QUuid uuid() const
virtual void baseNodeInvalidateAllFramesCallback()
virtual KisPaintDeviceSP projection() const =0
const QString & compositeOpId() const
virtual void baseNodeCollapsedChangedCallback()
virtual QImage createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio, KisThumbnailBoundsMode boundsMode=KisThumbnailBoundsMode::Precise)
bool isEditable(bool checkVisibility=true) const
virtual void baseNodeChangedCallback()
KisBaseNode(KisImageWSP image)
void setOpacity(quint8 val)
virtual void setVisible(bool visible, bool loading=false)
bool isPinnedToTimeline() const
KisKeyframeChannel * getKeyframeChannel(const QString &id, bool create)
void mergeNodeProperties(const KoProperties &properties)
QImage createPreferredThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio)
virtual void setImage(KisImageWSP image)
virtual KisKeyframeChannel * requestKeyframeChannel(const QString &id)
bool belongsToIsolatedGroup() const
const KoProperties & nodeProperties() const
virtual KisPaintDeviceSP original() const =0
KisAnimatedOpacityProperty opacityProperty
virtual void notifyParentVisibilityChanged(bool value)
void setUuid(const QUuid &id)
KisThumbnailBoundsMode preferredThumbnailBoundsMode() const
KoProperties properties
void setColorLabelIndex(int index)
KisBaseNode::Property hack_visible
~KisBaseNode() override
Private(KisImageWSP p_image)
Private *const m_d
void setCollapsed(bool collapsed)
virtual int thumbnailSeqNo() const
void keyframeChannelAdded(KisKeyframeChannel *channel)
QString compositeOp
KisImageWSP image
int colorLabelIndex() const
void opacityChanged(quint8 value)
bool userLocked() const
bool isAnimated() const
void setPercentOpacity(quint8 val)
virtual QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio, KisThumbnailBoundsMode boundsMode=KisThumbnailBoundsMode::Precise)
virtual KisPaintDeviceSP paintDevice() const =0
virtual PropertyList sectionModelProperties() const
QString name() const
void setPreferredThumbnailBoundsMode(KisThumbnailBoundsMode value) const
void setCompositeOpId(const QString &compositeOpId)
Private(const Private &rhs)
virtual void addKeyframeChannel(KisKeyframeChannel *channel)
virtual bool isFakeNode() const
quint8 opacity() const
bool check(const KoProperties &properties) const
virtual bool visible(bool recursive=false) const
virtual KisBaseNodeSP parentCallback() const
bool hasEditablePaintDevice() const
void enableAnimation()
virtual bool supportsKeyframeChannel(const QString &id)
virtual void setSectionModelProperties(const PropertyList &properties)
QImage createPreferredThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio)