Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_group_layer.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
3 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
4 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kis_group_layer.h"
10
11#include <KoIcon.h>
12#include <kis_icon.h>
14#include <KoColorSpace.h>
15#include <KoColor.h>
16
17
18#include "kis_node_visitor.h"
20#include "kis_debug.h"
21#include "kis_image.h"
22#include "kis_paint_device.h"
23#include "kis_default_bounds.h"
24#include "kis_clone_layer.h"
25#include "kis_selection_mask.h"
26#include "kis_psd_layer_style.h"
28#include <kis_projection_leaf.h>
30
31
32struct Q_DECL_HIDDEN KisGroupLayer::Private
33{
34public:
36 : paintDevice(0)
37 , x(0)
38 , y(0)
39 , passThroughMode(false)
40 {
41 }
42
44 qint32 x;
45 qint32 y;
47
48 std::tuple<KisPaintDeviceSP, bool> originalImpl() const;
49};
50
51KisGroupLayer::KisGroupLayer(KisImageWSP image, const QString &name, quint8 opacity, const KoColorSpace * colorSpace) :
52 KisLayer(image, name, opacity),
53 m_d(new Private())
54{
56}
57
59 KisLayer(rhs),
60 m_d(new Private())
61{
62 m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data());
63 m_d->x = rhs.m_d->x;
64 m_d->y = rhs.m_d->y;
65 m_d->paintDevice->setDefaultPixel(const_cast<KisGroupLayer*>(&rhs)->m_d->paintDevice->defaultPixel());
66 m_d->paintDevice->setProjectionDevice(true);
67 m_d->passThroughMode = rhs.passThroughMode();
68}
69
74
76{
77 KisNodeSP source = clone->copyFrom();
78 if (source) {
79 if(!allowAsChild(source)) return false;
80
81 if (source->inherits("KisGroupLayer")) {
82 KisNodeSP newParent = const_cast<KisGroupLayer*>(this);
83 while (newParent) {
84 if (newParent == source) {
85 return false;
86 }
87 newParent = newParent->parent();
88 }
89 }
90 }
91
92 return true;
93}
94
96{
97 KisCloneLayerSP cloneLayer = dynamic_cast<KisCloneLayer*>(node.data());
98 if(cloneLayer) {
99 return checkCloneLayer(cloneLayer);
100 }
101 else if (node->inherits("KisGroupLayer")) {
102 KisNodeSP child = node->firstChild();
103 while (child) {
104 if (!checkNodeRecursively(child)) {
105 return false;
106 }
107 child = child->nextSibling();
108 }
109 }
110
111 return true;
112}
113
115{
116 if (!checkNodeRecursively(node)) return false;
117
118 if (!parent()) {
119 // We are the root layer, so we need to check
120 // whether the node that's going to be added is
121 // a selection mask; that is only allowed if
122 // there isn't a global selection. See
123 // BUG:294905
124
125 if (node->inherits("KisSelectionMask")) {
126 return !qobject_cast<KisSelectionMask*>(node.data())->active() || !selectionMask();
127 }
128
129 KisImageSP image = this->image();
130
131 if (!image || !image->allowMasksOnRootNode()) {
132 if (node->inherits("KisMask")) {
133 return false;
134 }
135 }
136 }
137
138 return checkNodeRecursively(node);
139
140}
141
143{
144 return m_d->paintDevice->colorSpace();
145}
146
148{
149 return KisIconUtils::loadIcon("groupLayer");
150}
151
153{
154 m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image));
156}
157
159{
160 KisGroupLayer *prevGroup = dynamic_cast<KisGroupLayer*>(prevLayer.data());
161
162 if (prevGroup && canMergeAndKeepBlendOptions(prevLayer)) {
163 KisSharedPtr<KisGroupLayer> merged(new KisGroupLayer(*prevGroup));
164
165 KisNodeSP child, cloned;
166
167 for (child = firstChild(); child; child = child->nextSibling()) {
168 cloned = child->clone();
169 image()->addNode(cloned, merged);
170 }
171
172 if (!merged->passThroughMode()) {
173 image()->refreshGraphAsync(merged);
174 }
175
176 return merged;
177 } else
178 return KisLayer::createMergedLayerTemplate(prevLayer);
179}
180
181void KisGroupLayer::fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer, bool skipPaintingThisLayer)
182{
183 if (!dynamic_cast<KisGroupLayer*>(dstLayer.data())) {
184 KisLayer::fillMergedLayerTemplate(dstLayer, prevLayer, skipPaintingThisLayer);
185 }
186}
187
189{
190 if (!colorSpace)
192
193 Q_ASSERT(colorSpace);
194
195 if (!m_d->paintDevice) {
196
198 dev->setX(this->x());
199 dev->setY(this->y());
200 m_d->paintDevice = dev;
201 m_d->paintDevice->setProjectionDevice(true);
202 }
203 else if(*m_d->paintDevice->colorSpace() != *colorSpace) {
204
205 m_d->paintDevice->clear();
206 m_d->paintDevice->convertTo(colorSpace);
207
208 } else {
209
210 m_d->paintDevice->clear();
211 }
212}
213
215{
216 KisNode *child = firstChild().data();
217 KisLayer *onlyLayer = 0;
218
219 while (child) {
220 KisLayer *layer = qobject_cast<KisLayer*>(child);
221 if (layer && !layer->isFakeNode()) {
222 if (onlyLayer) return 0;
223 onlyLayer = layer;
224 }
225 child = child->nextSibling().data();
226 }
227
228 return onlyLayer;
229}
230
232{
233 KisLayer *child = onlyMeaningfulChild();
234
235 if (child) {
237 if (child->channelFlags().isEmpty() &&
238 projection &&
239 child->visible() &&
240 (child->compositeOpId() == COMPOSITE_OVER ||
242 child->compositeOpId() == COMPOSITE_COPY) &&
243 child->opacity() == OPACITY_OPAQUE_U8 &&
244 *projection->colorSpace() == *colorSpace() &&
245 !child->layerStyle()) {
246
247 quint8 defaultOpacity =
248 m_d->paintDevice->defaultPixel().opacityU8();
249
250 if(defaultOpacity == OPACITY_TRANSPARENT_U8) {
251 return projection;
252 }
253 }
254 }
255
256 return 0;
257}
258
259std::tuple<KisPaintDeviceSP, bool> KisGroupLayer::originalImpl() const
260{
266 KisPaintDeviceSP realOriginal = tryObligeChild();
267 bool ownsOriginal = false;
268
269 if (!realOriginal) {
270 if (!childCount() && !m_d->paintDevice->extent().isEmpty()) {
271 m_d->paintDevice->clear();
272 }
273 realOriginal = m_d->paintDevice;
274 ownsOriginal = true;
275 }
276
277 return std::make_tuple(realOriginal, ownsOriginal);
278}
279
281{
282 return std::get<0>(originalImpl());
283}
284
286{
287 KisPaintDeviceSP originalDev;
288 bool ownsOriginal = false;
289 std::tie(originalDev, ownsOriginal) = originalImpl();
290
291 return ownsOriginal ? originalDev : nullptr;
292}
293
295{
296 return hasEffectMasks() ? projection()->exactBoundsAmortized() : m_d->paintDevice->exactBoundsAmortized();
297}
298
300{
301 return 0;
302}
303
305{
306 return !tryObligeChild();
307}
308
310{
311 m_d->paintDevice->setDefaultPixel(color);
312}
313
315{
316 KoColor color(m_d->paintDevice->defaultPixel(), m_d->paintDevice->colorSpace());
317 return color;
318}
319
321{
322 return m_d->passThroughMode;
323}
324
326{
327 if (m_d->passThroughMode == value) return;
328
329 m_d->passThroughMode = value;
330 if (m_d->passThroughMode) {
332 }
336}
337
346
348{
349 Q_FOREACH (const KisBaseNode::Property &property, properties) {
350 if (property.name == i18n("Pass Through")) {
351 setPassThroughMode(property.state.toBool());
352 }
353 }
354
356}
357
359{
360 return v.visit(this);
361}
362
364{
365 return visitor.visit(this, undoAdapter);
366}
367
368qint32 KisGroupLayer::x() const
369{
370 return m_d->paintDevice ? m_d->paintDevice->x() : m_d->x;
371}
372
373qint32 KisGroupLayer::y() const
374{
375 return m_d->paintDevice ? m_d->paintDevice->y() : m_d->y;
376}
377
379{
380 m_d->x = x;
381 if(m_d->paintDevice) {
382 m_d->paintDevice->setX(x);
383 }
384}
385
387{
388 m_d->y = y;
389 if(m_d->paintDevice) {
390 m_d->paintDevice->setY(y);
391 }
392}
393
395{
396 inline QRect operator() (const KisNode *node) {
397 return node->projectionPlane()->looseUserVisibleBounds();
398 }
399};
400
402{
403 inline QRect operator() (const KisNode *node) {
404 return node->projectionPlane()->tightUserVisibleBounds();
405 }
406};
407
408template <class MetricPolicy>
409QRect collectRects(const KisNode *node, MetricPolicy policy)
410{
411 QRect accumulator;
412
413 const KisNode *child = node->firstChild();
414 while (child) {
415 if (child->projectionLeaf()->isLayer() &&
416 child->projectionLeaf()->visible()) {
417
418 accumulator |= policy(child);
419 }
420 child = child->nextSibling();
421 }
422
423 return accumulator;
424}
425
427{
428 return m_d->passThroughMode ?
431}
432
434{
435 return m_d->passThroughMode ?
438}
439
444
float value(const T *src, size_t ch)
qreal v
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
const quint8 OPACITY_TRANSPARENT_U8
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
const QString COMPOSITE_ALPHA_DARKEN
void refreshGraphAsync(KisNodeSP root, const QVector< QRect > &rects, const QRect &cropRect, KisProjectionUpdateFlags flags=KisProjectionUpdateFlag::None) override
const KoColorSpace * colorSpace() const
bool allowMasksOnRootNode() const
static KisBaseNode::Property getProperty(const KoID &id, bool state)
void setX(qint32 x)
const KoColorSpace * colorSpace() const
QRect exactBoundsAmortized() const
void setY(qint32 y)
virtual void visit(KisNode *node, KisUndoAdapter *undoAdapter)=0
QRect collectRects(const KisNode *node, MetricPolicy policy)
QIcon loadIcon(const QString &name)
QRect operator()(const KisNode *node)
QRect operator()(const KisNode *node)
const QString & compositeOpId() const
KoProperties properties
KisImageWSP image
virtual bool isFakeNode() const
quint8 opacity() const
virtual bool visible(bool recursive=false) const
KisNodeSP clone() const override
void setDefaultProjectionColor(KoColor color)
bool checkNodeRecursively(KisNodeSP node) const
QIcon icon() const override
void setSectionModelProperties(const KisBaseNode::PropertyList &properties) override
bool checkCloneLayer(KisCloneLayerSP clone) const
void fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer, bool skipPaintingThisLayer) override
QRect extent() const override
KisBaseNode::PropertyList sectionModelProperties() const override
bool allowAsChild(KisNodeSP) const override
KisLayer * onlyMeaningfulChild() const
bool projectionIsValid() const
Private *const m_d
const KoColorSpace * colorSpace() const override
std::tuple< KisPaintDeviceSP, bool > originalImpl() const
QRect calculateChildrenTightUserVisibleBounds() const
KisPaintDeviceSP lazyDestinationForSubtreeComposition() const
KisLayerSP createMergedLayerTemplate(KisLayerSP prevLayer) override
bool accept(KisNodeVisitor &v) override
void setImage(KisImageWSP image) override
KisPaintDeviceSP tryObligeChild() const
void setX(qint32 x) override
KisPaintDeviceSP original() const override
void setPassThroughMode(bool value)
QRect calculateChildrenLooseUserVisibleBounds() const
void resetCache(const KoColorSpace *colorSpace)
void setY(qint32 y) override
QRect exactBounds() const override
KoColor defaultProjectionColor() const
QRect amortizedProjectionRectForCleanupInChangePass() const override
KisPaintDeviceSP paintDevice
KisGroupLayer(KisImageWSP image, const QString &name, quint8 opacity, const KoColorSpace *colorSpace=0)
~KisGroupLayer() override
KisPaintDeviceSP projection() const override
Definition kis_layer.cc:820
void setImage(KisImageWSP image) override
Definition kis_layer.cc:378
virtual void fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer, bool skipPaintingThisLayer=false)
Definition kis_layer.cc:416
virtual KisLayerSP createMergedLayerTemplate(KisLayerSP prevLayer)
Definition kis_layer.cc:401
bool canMergeAndKeepBlendOptions(KisLayerSP otherLayer)
Definition kis_layer.cc:390
bool hasEffectMasks() const
Definition kis_layer.cc:562
QRect exactBounds() const override
QBitArray channelFlags
Definition kis_layer.cc:167
virtual KisSelectionMaskSP selectionMask() const
Definition kis_layer.cc:498
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171
QRect extent() const override
void notifyChildMaskChanged()
Definition kis_layer.cc:493
void setSectionModelProperties(const KisBaseNode::PropertyList &properties) override
Definition kis_layer.cc:297
KisBaseNode::PropertyList sectionModelProperties() const override
Definition kis_layer.cc:272
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
void baseNodeInvalidateAllFramesCallback() override
Definition kis_node.cpp:337
void baseNodeChangedCallback() override
Definition kis_node.cpp:329
KisNodeSP firstChild() const
Definition kis_node.cpp:361
virtual KisAbstractProjectionPlaneSP projectionPlane() const
Definition kis_node.cpp:240
KisProjectionLeafSP projectionLeaf
Definition kis_node.cpp:93
virtual KisNodeSP clone() const =0
quint32 childCount() const
Definition kis_node.cpp:414
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP nextSibling() const
Definition kis_node.cpp:408