File indexing completed on 2024-05-19 04:26:21
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_layer_utils.h" 0008 0009 #include <algorithm> 0010 0011 #include <QUuid> 0012 #include <KoColorSpaceConstants.h> 0013 #include <KoProperties.h> 0014 0015 #include "kis_painter.h" 0016 #include "kis_image.h" 0017 #include "kis_node.h" 0018 #include "kis_layer.h" 0019 #include "kis_paint_layer.h" 0020 #include "kis_clone_layer.h" 0021 #include "kis_group_layer.h" 0022 #include "kis_selection.h" 0023 #include "kis_selection_mask.h" 0024 #include "kis_meta_data_merge_strategy.h" 0025 #include <kundo2command.h> 0026 #include "commands/kis_image_layer_add_command.h" 0027 #include "commands/kis_image_layer_remove_command.h" 0028 #include "commands/kis_image_layer_move_command.h" 0029 #include "commands/kis_image_change_layers_command.h" 0030 #include "commands_new/kis_activate_selection_mask_command.h" 0031 #include "commands/kis_image_change_visibility_command.h" 0032 #include "kis_abstract_projection_plane.h" 0033 #include "kis_processing_applicator.h" 0034 #include "kis_image_animation_interface.h" 0035 #include "kis_keyframe_channel.h" 0036 #include "kis_raster_keyframe_channel.h" 0037 #include "kis_projection_leaf.h" 0038 #include "kis_scalar_keyframe_channel.h" 0039 #include "kis_time_span.h" 0040 #include "kis_command_utils.h" 0041 #include "commands_new/kis_change_projection_color_command.h" 0042 #include "kis_layer_properties_icons.h" 0043 #include "lazybrush/kis_colorize_mask.h" 0044 #include "commands/kis_node_property_list_command.h" 0045 #include "commands/kis_node_compositeop_command.h" 0046 #include <KisDelayedUpdateNodeInterface.h> 0047 #include <KisCroppedOriginalLayerInterface.h> 0048 #include "krita_utils.h" 0049 #include "kis_image_signal_router.h" 0050 #include "kis_sequential_iterator.h" 0051 #include "kis_transparency_mask.h" 0052 #include "kis_paint_device_frames_interface.h" 0053 #include "kis_command_ids.h" 0054 #include "kis_image_config.h" 0055 #include "KisFutureUtils.h" 0056 0057 0058 namespace KisLayerUtils { 0059 0060 namespace Private { 0061 void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea, const QRect &extraUpdateRect); 0062 } 0063 0064 void fetchSelectionMasks(KisNodeList mergedNodes, QVector<KisSelectionMaskSP> &selectionMasks) 0065 { 0066 foreach (KisNodeSP node, mergedNodes) { 0067 0068 Q_FOREACH(KisNodeSP child, node->childNodes(QStringList("KisSelectionMask"), KoProperties())) { 0069 0070 KisSelectionMaskSP mask = qobject_cast<KisSelectionMask*>(child.data()); 0071 if (mask) { 0072 selectionMasks.append(mask); 0073 } 0074 } 0075 } 0076 } 0077 0078 struct MergeDownInfoBase { 0079 MergeDownInfoBase(KisImageSP _image) 0080 : image(_image), 0081 storage(new SwitchFrameCommand::SharedStorage()) 0082 { 0083 } 0084 0085 virtual ~MergeDownInfoBase() {} 0086 0087 KisImageWSP image; 0088 0089 QVector<KisSelectionMaskSP> selectionMasks; 0090 0091 KisNodeSP dstNode; 0092 0093 SwitchFrameCommand::SharedStorageSP storage; 0094 QSet<int> frames; 0095 bool pinnedToTimeline = false; 0096 bool enableOnionSkins = false; 0097 0098 virtual KisNodeList allSrcNodes() = 0; 0099 0100 KisLayerSP dstLayer() { 0101 return qobject_cast<KisLayer*>(dstNode.data()); 0102 } 0103 }; 0104 0105 struct SplitAlphaToMaskInfo { 0106 SplitAlphaToMaskInfo(KisImageSP _image, KisNodeSP _node, const QString& maskName) 0107 : image(_image) 0108 , node(_node) 0109 , storage(new SwitchFrameCommand::SharedStorage()) 0110 { 0111 frames = fetchLayerFramesRecursive(_node); 0112 mask = new KisTransparencyMask(image, maskName); 0113 } 0114 0115 KisImageWSP image; 0116 KisNodeSP node; 0117 SwitchFrameCommand::SharedStorageSP storage; 0118 QSet<int> frames; 0119 0120 KisPaintDeviceSP getMaskDevice() { 0121 return mask->paintDevice(); 0122 } 0123 0124 KisMaskSP getMask() { 0125 return mask; 0126 } 0127 0128 KisLayerSP getLayer() { 0129 return qobject_cast<KisLayer*>(node.data()); 0130 } 0131 0132 private: 0133 KisTransparencyMaskSP mask; 0134 0135 }; 0136 0137 struct MergeDownInfo : public MergeDownInfoBase { 0138 MergeDownInfo(KisImageSP _image, 0139 KisLayerSP _prevLayer, 0140 KisLayerSP _currLayer) 0141 : MergeDownInfoBase(_image), 0142 prevLayer(_prevLayer), 0143 currLayer(_currLayer) 0144 { 0145 frames = fetchLayerFramesRecursive(prevLayer) | 0146 fetchLayerFramesRecursive(currLayer); 0147 0148 /** 0149 * If source layer is not animated, then just merge that into the current frame 0150 * only. See the other part of this feature in mergeDown() itself 0151 * 0152 * See https://bugs.kde.org/show_bug.cgi?id=475550 0153 */ 0154 if (!frames.isEmpty() && !currLayer->isAnimated()) { 0155 frames.insert(image->animationInterface()->currentTime()); 0156 } 0157 0158 pinnedToTimeline = prevLayer->isPinnedToTimeline() || currLayer->isPinnedToTimeline(); 0159 0160 const KisPaintLayer *paintLayer = qobject_cast<KisPaintLayer*>(currLayer.data()); 0161 if (paintLayer) enableOnionSkins |= paintLayer->onionSkinEnabled(); 0162 0163 paintLayer = qobject_cast<KisPaintLayer*>(prevLayer.data()); 0164 if (paintLayer) enableOnionSkins |= paintLayer->onionSkinEnabled(); 0165 } 0166 0167 KisLayerSP prevLayer; 0168 KisLayerSP currLayer; 0169 0170 KisNodeList allSrcNodes() override { 0171 KisNodeList mergedNodes; 0172 mergedNodes << prevLayer; 0173 mergedNodes << currLayer; 0174 return mergedNodes; 0175 } 0176 }; 0177 0178 struct ConvertToPaintLayerInfo { 0179 ConvertToPaintLayerInfo(KisImageSP image, KisNodeSP node) 0180 : storage(new SwitchFrameCommand::SharedStorage()) 0181 , m_sourceNode(node) 0182 , m_image(image) 0183 , m_pinnedToTimeline(false) 0184 { 0185 m_frames = fetchLayerFramesRecursive(node); 0186 0187 m_pinnedToTimeline = node->isPinnedToTimeline(); 0188 0189 m_sourcePaintDevice = 0190 m_sourceNode->paintDevice() ? m_sourceNode->projection() : m_sourceNode->original(); 0191 0192 m_compositeOp = m_sourceNode->projectionLeaf()->isLayer() ? m_sourceNode->compositeOpId() : COMPOSITE_OVER; 0193 0194 KisColorizeMask *colorizeMask = dynamic_cast<KisColorizeMask*>(m_sourceNode.data()); 0195 if (colorizeMask) { 0196 m_sourcePaintDevice = colorizeMask->coloringProjection(); 0197 const bool putBehind = colorizeMask->compositeOpId() == COMPOSITE_BEHIND; 0198 if (putBehind) { 0199 m_compositeOp = COMPOSITE_OVER; 0200 } 0201 0202 m_insertionParent = m_sourceNode->parent()->parent(); 0203 m_insertionPutAfter = putBehind ? m_sourceNode->parent()->prevSibling() : m_sourceNode->parent(); 0204 0205 } else if (dynamic_cast<KisMask*>(m_sourceNode.data())) { 0206 m_insertionParent = m_sourceNode->parent()->parent(); 0207 m_insertionPutAfter = m_sourceNode->parent()->prevSibling(); 0208 } else { 0209 m_insertionParent = m_sourceNode->parent(); 0210 m_insertionPutAfter = m_sourceNode; 0211 } 0212 0213 KisCloneLayer *cloneLayer = dynamic_cast<KisCloneLayer*>(m_sourceNode.data()); 0214 if (cloneLayer) { 0215 m_targetNode = cloneLayer->reincarnateAsPaintLayer(); 0216 } else if (m_sourcePaintDevice) { 0217 KisPaintDeviceSP clone; 0218 0219 if (*m_sourcePaintDevice->colorSpace() != 0220 *m_sourcePaintDevice->compositionSourceColorSpace()) { 0221 0222 clone = new KisPaintDevice(m_sourcePaintDevice->compositionSourceColorSpace()); 0223 clone->setDefaultPixel( 0224 m_sourcePaintDevice->defaultPixel().convertedTo( 0225 m_sourcePaintDevice->compositionSourceColorSpace())); 0226 0227 QRect rc(m_sourcePaintDevice->extent()); 0228 KisPainter::copyAreaOptimized(rc.topLeft(), m_sourcePaintDevice, clone, rc); 0229 } else { 0230 clone = new KisPaintDevice(*m_sourcePaintDevice); 0231 } 0232 0233 m_targetNode = new KisPaintLayer(m_image, 0234 m_sourceNode->name(), 0235 m_sourceNode->opacity(), 0236 clone); 0237 0238 m_targetNode->setCompositeOpId(m_compositeOp); 0239 0240 if (sourceLayer() && targetLayer()) { 0241 targetLayer()->disableAlphaChannel(sourceLayer()->alphaChannelDisabled()); 0242 } 0243 0244 if (sourcePaintLayer() && targetPaintLayer()) { 0245 targetPaintLayer()->setAlphaLocked(sourcePaintLayer()->alphaLocked()); 0246 } 0247 } 0248 } 0249 0250 QSet<int> frames() { 0251 return m_frames; 0252 } 0253 0254 KisNodeSP sourceNode() { 0255 return m_sourceNode; 0256 } 0257 0258 KisLayerSP sourceLayer() { 0259 return qobject_cast<KisLayer*>(m_sourceNode.data()); 0260 } 0261 0262 KisNodeList sourceNodes() { 0263 KisNodeList list; 0264 list << m_sourceNode; 0265 return list; 0266 } 0267 0268 KisPaintLayerSP sourcePaintLayer() { 0269 return qobject_cast<KisPaintLayer*>(m_sourceNode.data()); 0270 } 0271 0272 bool hasTargetNode() { 0273 return m_targetNode != nullptr; 0274 } 0275 0276 KisNodeSP targetNode() { 0277 return m_targetNode; 0278 } 0279 0280 KisLayerSP targetLayer() { 0281 return qobject_cast<KisLayer*>(m_targetNode.data()); 0282 } 0283 0284 KisPaintLayerSP targetPaintLayer() { 0285 return qobject_cast<KisPaintLayer*>(m_targetNode.data()); 0286 } 0287 0288 0289 KisImageSP image() { 0290 return m_image; 0291 } 0292 0293 KisPaintDeviceSP paintDevice() { 0294 return m_sourcePaintDevice; 0295 } 0296 0297 KisNodeList toRemove() { 0298 KisNodeList lst; 0299 lst << m_sourceNode; 0300 return lst; 0301 } 0302 0303 KisNodeSP insertionPutAfter() const { 0304 return m_insertionPutAfter; 0305 } 0306 0307 KisNodeSP insertionParent() const { 0308 return m_insertionParent; 0309 } 0310 0311 SwitchFrameCommand::SharedStorageSP storage; 0312 0313 private: 0314 KisNodeSP m_sourceNode; 0315 KisNodeSP m_targetNode; 0316 KisImageWSP m_image; 0317 KisPaintDeviceSP m_sourcePaintDevice; 0318 QSet<int> m_frames; 0319 QString m_compositeOp; 0320 bool m_pinnedToTimeline; 0321 0322 KisNodeSP m_insertionParent; 0323 KisNodeSP m_insertionPutAfter; 0324 }; 0325 0326 struct MergeMultipleInfo : public MergeDownInfoBase { 0327 MergeMultipleInfo(KisImageSP _image, 0328 KisNodeList _mergedNodes) 0329 : MergeDownInfoBase(_image), 0330 mergedNodes(_mergedNodes) 0331 { 0332 foreach (KisNodeSP node, mergedNodes) { 0333 frames |= fetchLayerFramesRecursive(node); 0334 pinnedToTimeline |= node->isPinnedToTimeline(); 0335 0336 const KisPaintLayer *paintLayer = qobject_cast<KisPaintLayer*>(node.data()); 0337 if (paintLayer) { 0338 enableOnionSkins |= paintLayer->onionSkinEnabled(); 0339 } 0340 } 0341 } 0342 0343 QScopedPointer<KisSurrogateUndoStore> ephemeralCommandsStore; 0344 KisNodeList mergedNodes; 0345 bool nodesCompositingVaries = false; 0346 0347 KisNodeList allSrcNodes() override { 0348 return mergedNodes; 0349 } 0350 }; 0351 0352 typedef QSharedPointer<MergeDownInfoBase> MergeDownInfoBaseSP; 0353 typedef QSharedPointer<MergeDownInfo> MergeDownInfoSP; 0354 typedef QSharedPointer<MergeMultipleInfo> MergeMultipleInfoSP; 0355 typedef QSharedPointer<SplitAlphaToMaskInfo> SplitAlphaToMaskInfoSP; 0356 typedef QSharedPointer<ConvertToPaintLayerInfo> ConvertToPaintLayerInfoSP; 0357 0358 struct FillSelectionMasks : public KUndo2Command { 0359 FillSelectionMasks(MergeDownInfoBaseSP info) : m_info(info) {} 0360 0361 void redo() override { 0362 fetchSelectionMasks(m_info->allSrcNodes(), m_info->selectionMasks); 0363 } 0364 0365 private: 0366 MergeDownInfoBaseSP m_info; 0367 }; 0368 0369 struct DisableColorizeKeyStrokes : public KisCommandUtils::AggregateCommand { 0370 DisableColorizeKeyStrokes(MergeDownInfoBaseSP info) : m_info(info) {} 0371 0372 void populateChildCommands() override { 0373 Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) { 0374 recursiveApplyNodes(node, 0375 [this] (KisNodeSP node) { 0376 if (dynamic_cast<KisColorizeMask*>(node.data()) && 0377 KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool()) { 0378 0379 KisBaseNode::PropertyList props = node->sectionModelProperties(); 0380 KisLayerPropertiesIcons::setNodeProperty(&props, 0381 KisLayerPropertiesIcons::colorizeEditKeyStrokes, 0382 false); 0383 0384 addCommand(new KisNodePropertyListCommand(node, props)); 0385 } 0386 }); 0387 } 0388 } 0389 0390 private: 0391 MergeDownInfoBaseSP m_info; 0392 }; 0393 0394 struct DisableOnionSkins : public KisCommandUtils::AggregateCommand { 0395 DisableOnionSkins(MergeDownInfoBaseSP info) : m_info(info) {} 0396 0397 void populateChildCommands() override { 0398 Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) { 0399 recursiveApplyNodes(node, 0400 [this] (KisNodeSP node) { 0401 if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::onionSkins, false).toBool()) { 0402 0403 KisBaseNode::PropertyList props = node->sectionModelProperties(); 0404 KisLayerPropertiesIcons::setNodeProperty(&props, 0405 KisLayerPropertiesIcons::onionSkins, 0406 false); 0407 0408 addCommand(new KisNodePropertyListCommand(node, props)); 0409 } 0410 }); 0411 } 0412 } 0413 0414 private: 0415 MergeDownInfoBaseSP m_info; 0416 }; 0417 0418 struct DisableExtraCompositing : public KisCommandUtils::AggregateCommand { 0419 DisableExtraCompositing(MergeMultipleInfoSP info) : m_info(info) {} 0420 0421 void populateChildCommands() override { 0422 /** 0423 * We disable extra compositing only in case all the layers have 0424 * the same compositing properties, therefore, we can just sum them using 0425 * Normal blend mode 0426 */ 0427 if (m_info->nodesCompositingVaries) return; 0428 0429 // we should disable dirty requests on **redo only**, otherwise 0430 // the state of the layers will not be recovered on undo 0431 m_info->image->disableDirtyRequests(); 0432 0433 Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) { 0434 if (node->compositeOpId() != COMPOSITE_OVER) { 0435 addCommand(new KisNodeCompositeOpCommand(node, COMPOSITE_OVER)); 0436 } 0437 0438 if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::inheritAlpha, false).toBool()) { 0439 0440 KisBaseNode::PropertyList props = node->sectionModelProperties(); 0441 KisLayerPropertiesIcons::setNodeProperty(&props, 0442 KisLayerPropertiesIcons::inheritAlpha, 0443 false); 0444 0445 addCommand(new KisNodePropertyListCommand(node, props)); 0446 } 0447 } 0448 0449 m_info->image->enableDirtyRequests(); 0450 } 0451 0452 private: 0453 MergeMultipleInfoSP m_info; 0454 }; 0455 0456 struct DisablePassThroughForHeadsOnly : public KisCommandUtils::AggregateCommand { 0457 DisablePassThroughForHeadsOnly(MergeDownInfoBaseSP info, bool skipIfDstIsGroup = false) 0458 : m_info(info), 0459 m_skipIfDstIsGroup(skipIfDstIsGroup) 0460 { 0461 } 0462 0463 void populateChildCommands() override { 0464 if (m_skipIfDstIsGroup && 0465 m_info->dstLayer() && 0466 m_info->dstLayer()->inherits("KisGroupLayer")) { 0467 0468 return; 0469 } 0470 0471 0472 Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) { 0473 if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::passThrough, false).toBool()) { 0474 0475 KisBaseNode::PropertyList props = node->sectionModelProperties(); 0476 KisLayerPropertiesIcons::setNodeProperty(&props, 0477 KisLayerPropertiesIcons::passThrough, 0478 false); 0479 0480 addCommand(new KisNodePropertyListCommand(node, props)); 0481 } 0482 } 0483 } 0484 0485 private: 0486 MergeDownInfoBaseSP m_info; 0487 bool m_skipIfDstIsGroup; 0488 }; 0489 0490 struct RefreshHiddenAreas : public KisCommandUtils::AggregateCommand { 0491 struct refresh_entire_image_t {}; 0492 static constexpr refresh_entire_image_t refresh_entire_image{}; 0493 0494 RefreshHiddenAreas(MergeDownInfoBaseSP info) : m_image(info->image), m_nodes(info->allSrcNodes()) {} 0495 RefreshHiddenAreas(MergeDownInfoBaseSP info, refresh_entire_image_t) : m_image(info->image), m_nodes(info->allSrcNodes()), m_extraUpdateRect(info->image->bounds()) {} 0496 RefreshHiddenAreas(KisImageSP image, KisNodeSP node) : m_image(image), m_nodes() { 0497 m_nodes << node; 0498 } 0499 0500 void populateChildCommands() override { 0501 KisImageAnimationInterface *interface = m_image->animationInterface(); 0502 const QRect preparedRect = !interface->externalFrameActive() ? 0503 m_image->bounds() : QRect(); 0504 0505 foreach (KisNodeSP node, m_nodes) { 0506 Private::refreshHiddenAreaAsync(m_image, node, preparedRect, m_extraUpdateRect); 0507 } 0508 } 0509 0510 private: 0511 KisImageWSP m_image; 0512 KisNodeList m_nodes; 0513 QRect m_extraUpdateRect; 0514 }; 0515 0516 struct RefreshDelayedUpdateLayers : public KUndo2Command { 0517 RefreshDelayedUpdateLayers(MergeDownInfoBaseSP info) 0518 : m_nodes(info->allSrcNodes()) {} 0519 0520 RefreshDelayedUpdateLayers(KisNodeList nodes){ 0521 m_nodes << nodes; 0522 } 0523 0524 void redo() override { 0525 if (m_info) { 0526 m_nodes << m_info->allSrcNodes(); 0527 } 0528 0529 foreach (KisNodeSP node, m_nodes) { 0530 forceAllDelayedNodesUpdate(node); 0531 } 0532 } 0533 0534 private: 0535 KisNodeList m_nodes; 0536 MergeDownInfoBaseSP m_info; 0537 }; 0538 0539 struct KeepMergedNodesSelected : public KisCommandUtils::AggregateCommand { 0540 KeepMergedNodesSelected(MergeDownInfoSP info, bool finalizing) 0541 : m_singleInfo(info), 0542 m_finalizing(finalizing) {} 0543 0544 KeepMergedNodesSelected(MergeMultipleInfoSP info, KisNodeSP putAfter, bool finalizing) 0545 : m_multipleInfo(info), 0546 m_finalizing(finalizing), 0547 m_putAfter(putAfter) {} 0548 0549 void populateChildCommands() override { 0550 KisNodeSP prevNode; 0551 KisNodeSP nextNode; 0552 KisNodeList prevSelection; 0553 KisNodeList nextSelection; 0554 KisImageSP image; 0555 0556 if (m_singleInfo) { 0557 prevNode = m_singleInfo->currLayer; 0558 nextNode = m_singleInfo->dstNode; 0559 image = m_singleInfo->image; 0560 } else if (m_multipleInfo) { 0561 prevNode = m_putAfter; 0562 nextNode = m_multipleInfo->dstNode; 0563 prevSelection = m_multipleInfo->allSrcNodes(); 0564 image = m_multipleInfo->image; 0565 } 0566 0567 if (!m_finalizing) { 0568 addCommand(new KeepNodesSelectedCommand(prevSelection, KisNodeList(), 0569 prevNode, KisNodeSP(), 0570 image, false)); 0571 } else { 0572 addCommand(new KeepNodesSelectedCommand(KisNodeList(), nextSelection, 0573 KisNodeSP(), nextNode, 0574 image, true)); 0575 } 0576 } 0577 0578 private: 0579 MergeDownInfoSP m_singleInfo; 0580 MergeMultipleInfoSP m_multipleInfo; 0581 bool m_finalizing; 0582 KisNodeSP m_putAfter; 0583 }; 0584 0585 struct CreateMergedLayer : public KisCommandUtils::AggregateCommand { 0586 CreateMergedLayer(MergeDownInfoSP info) : m_info(info) {} 0587 0588 void populateChildCommands() override { 0589 // actual merging done by KisLayer::createMergedLayer (or specialized descendant) 0590 m_info->dstNode = m_info->currLayer->createMergedLayerTemplate(m_info->prevLayer); 0591 0592 if (m_info->frames.size() > 0) { 0593 m_info->dstNode->enableAnimation(); 0594 m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true); 0595 } 0596 0597 m_info->dstNode->setPinnedToTimeline(m_info->pinnedToTimeline); 0598 m_info->dstNode->setColorLabelIndex(m_info->allSrcNodes().first()->colorLabelIndex()); 0599 0600 KisPaintLayer *dstPaintLayer = qobject_cast<KisPaintLayer*>(m_info->dstNode.data()); 0601 if (dstPaintLayer) { 0602 dstPaintLayer->setOnionSkinEnabled(m_info->enableOnionSkins); 0603 } 0604 } 0605 0606 private: 0607 MergeDownInfoSP m_info; 0608 }; 0609 0610 struct CreateMergedLayerMultiple : public KisCommandUtils::AggregateCommand { 0611 CreateMergedLayerMultiple(MergeMultipleInfoSP info, const QString name = QString() ) 0612 : m_info(info), 0613 m_name(name) {} 0614 0615 void populateChildCommands() override { 0616 QString mergedLayerName; 0617 if (m_name.isEmpty()){ 0618 const QString mergedLayerSuffix = i18n("Merged"); 0619 mergedLayerName = m_info->mergedNodes.first()->name(); 0620 0621 if (KisImageConfig(true).renameMergedLayers() && !mergedLayerName.endsWith(mergedLayerSuffix)) { 0622 mergedLayerName = QString("%1 %2") 0623 .arg(mergedLayerName).arg(mergedLayerSuffix); 0624 } 0625 } else { 0626 mergedLayerName = m_name; 0627 } 0628 0629 KisPaintLayer *dstPaintLayer = new KisPaintLayer(m_info->image, mergedLayerName, OPACITY_OPAQUE_U8); 0630 m_info->dstNode = dstPaintLayer; 0631 0632 if (m_info->frames.size() > 0) { 0633 m_info->dstNode->enableAnimation(); 0634 m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true); 0635 } 0636 0637 0638 auto channelFlagsLazy = [](KisNodeSP node) { 0639 KisLayer *layer = dynamic_cast<KisLayer*>(node.data()); 0640 return layer ? layer->channelFlags() : QBitArray(); 0641 }; 0642 0643 QString compositeOpId; 0644 QBitArray channelFlags; 0645 bool compositionVaries = false; 0646 bool isFirstCycle = true; 0647 0648 foreach (KisNodeSP node, m_info->allSrcNodes()) { 0649 if (isFirstCycle) { 0650 compositeOpId = node->compositeOpId(); 0651 channelFlags = channelFlagsLazy(node); 0652 isFirstCycle = false; 0653 } else if (compositeOpId != node->compositeOpId() || 0654 channelFlags != channelFlagsLazy(node)) { 0655 compositionVaries = true; 0656 break; 0657 } 0658 0659 KisLayerSP layer = qobject_cast<KisLayer*>(node.data()); 0660 if (layer && layer->layerStyle()) { 0661 compositionVaries = true; 0662 break; 0663 } 0664 } 0665 0666 if (!compositionVaries) { 0667 if (!compositeOpId.isEmpty()) { 0668 m_info->dstNode->setCompositeOpId(compositeOpId); 0669 } 0670 if (m_info->dstLayer() && !channelFlags.isEmpty()) { 0671 m_info->dstLayer()->setChannelFlags(channelFlags); 0672 } 0673 } 0674 0675 m_info->nodesCompositingVaries = compositionVaries; 0676 0677 m_info->dstNode->setPinnedToTimeline(m_info->pinnedToTimeline); 0678 m_info->dstNode->setColorLabelIndex(m_info->allSrcNodes().first()->colorLabelIndex()); 0679 0680 dstPaintLayer->setOnionSkinEnabled(m_info->enableOnionSkins); 0681 } 0682 0683 private: 0684 MergeMultipleInfoSP m_info; 0685 QString m_name; 0686 }; 0687 0688 struct MergeLayers : public KisCommandUtils::AggregateCommand { 0689 MergeLayers(MergeDownInfoSP info, bool skipMergingSourceLayer) 0690 : m_info(info), m_skipMergingSourceLayer(skipMergingSourceLayer) {} 0691 0692 void populateChildCommands() override { 0693 // actual merging done by KisLayer::createMergedLayer (or specialized descendant) 0694 m_info->currLayer->fillMergedLayerTemplate(m_info->dstLayer(), m_info->prevLayer, m_skipMergingSourceLayer); 0695 } 0696 0697 private: 0698 MergeDownInfoSP m_info; 0699 bool m_skipMergingSourceLayer {false}; 0700 }; 0701 0702 struct MergeLayersMultiple : public KisCommandUtils::AggregateCommand { 0703 MergeLayersMultiple(MergeMultipleInfoSP info) : m_info(info) {} 0704 0705 void populateChildCommands() override { 0706 KisPainter gc(m_info->dstNode->paintDevice()); 0707 0708 foreach (KisNodeSP node, m_info->allSrcNodes()) { 0709 QRect rc = node->exactBounds() | m_info->image->bounds(); 0710 node->projectionPlane()->apply(&gc, rc); 0711 } 0712 } 0713 0714 private: 0715 MergeMultipleInfoSP m_info; 0716 }; 0717 0718 struct MergeMetaData : public KUndo2Command { 0719 MergeMetaData(MergeDownInfoSP info, const KisMetaData::MergeStrategy* strategy) 0720 : m_info(info), 0721 m_strategy(strategy) {} 0722 0723 void redo() override { 0724 QRect layerProjectionExtent = m_info->currLayer->projection()->extent(); 0725 QRect prevLayerProjectionExtent = m_info->prevLayer->projection()->extent(); 0726 int prevLayerArea = prevLayerProjectionExtent.width() * prevLayerProjectionExtent.height(); 0727 int layerArea = layerProjectionExtent.width() * layerProjectionExtent.height(); 0728 0729 QList<double> scores; 0730 double norm = qMax(prevLayerArea, layerArea); 0731 scores.append(prevLayerArea / norm); 0732 scores.append(layerArea / norm); 0733 0734 QList<const KisMetaData::Store*> srcs; 0735 srcs.append(m_info->prevLayer->metaData()); 0736 srcs.append(m_info->currLayer->metaData()); 0737 m_strategy->merge(m_info->dstLayer()->metaData(), srcs, scores); 0738 } 0739 0740 private: 0741 MergeDownInfoSP m_info; 0742 const KisMetaData::MergeStrategy *m_strategy; 0743 }; 0744 0745 struct InitSplitAlphaSelectionMask : public KisCommandUtils::AggregateCommand { 0746 InitSplitAlphaSelectionMask(SplitAlphaToMaskInfoSP info) 0747 : m_info(info) {} 0748 0749 void populateChildCommands() override { 0750 m_info->getMask()->initSelection(m_info->getLayer()); 0751 } 0752 0753 private: 0754 SplitAlphaToMaskInfoSP m_info; 0755 }; 0756 0757 struct SplitAlphaCommand : public KUndo2Command { 0758 SplitAlphaCommand(SplitAlphaToMaskInfoSP info) 0759 : m_info(info) { 0760 m_cached = new KisPaintDevice(*m_info->node->paintDevice(), KritaUtils::CopyAllFrames); 0761 } 0762 0763 void redo() override { 0764 KisPaintDeviceSP srcDevice = m_info->node->paintDevice(); 0765 const KoColorSpace *srcCS = srcDevice->colorSpace(); 0766 const QRect processRect = 0767 srcDevice->exactBounds() | 0768 srcDevice->defaultBounds()->bounds(); 0769 0770 KisSequentialIterator srcIt(srcDevice, processRect); 0771 KisSequentialIterator dstIt(m_info->getMaskDevice(), processRect); 0772 0773 while (srcIt.nextPixel() && dstIt.nextPixel()) { 0774 quint8 *srcPtr = srcIt.rawData(); 0775 quint8 *alpha8Ptr = dstIt.rawData(); 0776 0777 *alpha8Ptr = srcCS->opacityU8(srcPtr); 0778 srcCS->setOpacity(srcPtr, OPACITY_OPAQUE_U8, 1); 0779 } 0780 } 0781 0782 void undo() override { 0783 KisPaintDeviceSP srcDevice = m_info->node->paintDevice(); 0784 0785 if (srcDevice->framesInterface()) { //Swap contents of all frames to reflect the pre-operation state. 0786 KisPaintDeviceSP tempPD = new KisPaintDevice(*m_cached, KritaUtils::CopySnapshot); 0787 Q_FOREACH(const int& frame, srcDevice->framesInterface()->frames() ) { 0788 if (m_cached->framesInterface()->frames().contains(frame)) { 0789 m_cached->framesInterface()->writeFrameToDevice(frame, tempPD); 0790 srcDevice->framesInterface()->uploadFrame(frame, tempPD); 0791 } 0792 } 0793 } else { 0794 const QRect processRect = 0795 srcDevice->exactBounds() | 0796 srcDevice->defaultBounds()->bounds(); 0797 0798 const KoColorSpace *srcCS = srcDevice->colorSpace(); 0799 KisSequentialIterator srcIt(m_cached, processRect); 0800 KisSequentialIterator dstIt(srcDevice, processRect); 0801 0802 while (srcIt.nextPixel() && dstIt.nextPixel()) { 0803 quint8 *srcPtr = srcIt.rawData(); 0804 quint8 *dstPtr = dstIt.rawData(); 0805 srcCS->setOpacity(dstPtr, srcCS->opacityU8(srcPtr), 1); 0806 } 0807 } 0808 } 0809 0810 private: 0811 SplitAlphaToMaskInfoSP m_info; 0812 KisPaintDeviceSP m_cached; 0813 }; 0814 0815 struct UploadProjectionToFrameCommand : public KisCommandUtils::AggregateCommand { 0816 UploadProjectionToFrameCommand(KisNodeSP src, KisNodeSP target, int frame) 0817 : m_source(src) 0818 , m_target(target) 0819 , m_frame(frame) 0820 {} 0821 0822 void populateChildCommands() override { 0823 KisRasterKeyframeChannel* channel = dynamic_cast<KisRasterKeyframeChannel*>(m_target->getKeyframeChannel(KisKeyframeChannel::Raster.id())); 0824 if (!channel) 0825 return; 0826 0827 0828 KisPaintDeviceSP clone = new KisPaintDevice(*m_source->projection()); 0829 KisRasterKeyframeSP key = channel->keyframeAt<KisRasterKeyframe>(m_frame); 0830 m_target->paintDevice()->framesInterface()->uploadFrame(key->frameID(), clone); 0831 } 0832 0833 private: 0834 KisNodeSP m_source; 0835 KisNodeSP m_target; 0836 int m_frame; 0837 }; 0838 0839 KeepNodesSelectedCommand::KeepNodesSelectedCommand(const KisNodeList &selectedBefore, 0840 const KisNodeList &selectedAfter, 0841 KisNodeSP activeBefore, 0842 KisNodeSP activeAfter, 0843 KisImageSP image, 0844 bool finalize, KUndo2Command *parent) 0845 : FlipFlopCommand(finalize, parent), 0846 m_selectedBefore(selectedBefore), 0847 m_selectedAfter(selectedAfter), 0848 m_activeBefore(activeBefore), 0849 m_activeAfter(activeAfter), 0850 m_image(image) 0851 { 0852 } 0853 0854 void KeepNodesSelectedCommand::partB() { 0855 KisImageSignalType type; 0856 if (getState() == State::FINALIZING) { 0857 type = ComplexNodeReselectionSignal(m_activeAfter, m_selectedAfter); 0858 } else { 0859 type = ComplexNodeReselectionSignal(m_activeBefore, m_selectedBefore); 0860 } 0861 m_image->signalRouter()->emitNotification(type); 0862 } 0863 0864 SelectGlobalSelectionMask::SelectGlobalSelectionMask(KisImageSP image) 0865 : m_image(image) 0866 { 0867 } 0868 0869 SelectGlobalSelectionMask::~SelectGlobalSelectionMask() 0870 { 0871 } 0872 0873 void SelectGlobalSelectionMask::redo() { 0874 0875 KisImageSignalType type = 0876 ComplexNodeReselectionSignal(m_image->rootLayer()->selectionMask(), KisNodeList()); 0877 m_image->signalRouter()->emitNotification(type); 0878 0879 } 0880 0881 RemoveNodeHelper::~RemoveNodeHelper() 0882 { 0883 } 0884 0885 /** 0886 * The removal of two nodes in one go may be a bit tricky, because one 0887 * of them may be the clone of another. If we remove the source of a 0888 * clone layer, it will reincarnate into a paint layer. In this case 0889 * the pointer to the second layer will be lost. 0890 * 0891 * That's why we need to care about the order of the nodes removal: 0892 * the clone --- first, the source --- last. 0893 */ 0894 void RemoveNodeHelper::safeRemoveMultipleNodes(KisNodeList nodes, KisImageSP image) { 0895 const bool lastLayer = scanForLastLayer(image, nodes); 0896 0897 auto isNodeWeird = [] (KisNodeSP node) { 0898 const bool normalCompositeMode = node->compositeOpId() == COMPOSITE_OVER; 0899 0900 KisLayer *layer = dynamic_cast<KisLayer*>(node.data()); 0901 const bool hasInheritAlpha = layer && layer->alphaChannelDisabled(); 0902 return !normalCompositeMode && !hasInheritAlpha; 0903 }; 0904 0905 while (!nodes.isEmpty()) { 0906 KisNodeList::iterator it = nodes.begin(); 0907 0908 while (it != nodes.end()) { 0909 if (!checkIsSourceForClone(*it, nodes)) { 0910 KisNodeSP node = *it; 0911 0912 addCommandImpl(new KisImageLayerRemoveCommand(image, node, !isNodeWeird(node), true)); 0913 it = nodes.erase(it); 0914 } else { 0915 ++it; 0916 } 0917 } 0918 } 0919 0920 if (lastLayer) { 0921 KisLayerSP newLayer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace()); 0922 addCommandImpl(new KisImageLayerAddCommand(image, newLayer, 0923 image->root(), 0924 KisNodeSP(), 0925 false, false)); 0926 } 0927 } 0928 0929 bool RemoveNodeHelper::checkIsSourceForClone(KisNodeSP src, const KisNodeList &nodes) { 0930 foreach (KisNodeSP node, nodes) { 0931 if (node == src) continue; 0932 0933 KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data()); 0934 0935 if (clone && KisNodeSP(clone->copyFrom()) == src) { 0936 return true; 0937 } 0938 } 0939 0940 return false; 0941 } 0942 0943 bool RemoveNodeHelper::scanForLastLayer(KisImageWSP image, KisNodeList nodesToRemove) { 0944 bool removeLayers = false; 0945 Q_FOREACH(KisNodeSP nodeToRemove, nodesToRemove) { 0946 if (qobject_cast<KisLayer*>(nodeToRemove.data())) { 0947 removeLayers = true; 0948 break; 0949 } 0950 } 0951 if (!removeLayers) return false; 0952 0953 bool lastLayer = true; 0954 KisNodeSP node = image->root()->firstChild(); 0955 while (node) { 0956 if (!nodesToRemove.contains(node) && 0957 qobject_cast<KisLayer*>(node.data()) && 0958 !node->isFakeNode()) { 0959 0960 lastLayer = false; 0961 break; 0962 } 0963 node = node->nextSibling(); 0964 } 0965 0966 return lastLayer; 0967 } 0968 0969 SimpleRemoveLayers::SimpleRemoveLayers(const KisNodeList &nodes, 0970 KisImageSP image) 0971 : m_nodes(nodes), 0972 m_image(image) 0973 { 0974 } 0975 0976 void SimpleRemoveLayers::populateChildCommands() { 0977 if (m_nodes.isEmpty()) return; 0978 safeRemoveMultipleNodes(m_nodes, m_image); 0979 } 0980 0981 void SimpleRemoveLayers::addCommandImpl(KUndo2Command *cmd) { 0982 addCommand(cmd); 0983 } 0984 0985 struct InsertNode : public KisCommandUtils::AggregateCommand { 0986 InsertNode(MergeDownInfoBaseSP info, KisNodeSP putAfter) 0987 : m_info(info), m_putAfter(putAfter) {} 0988 0989 void populateChildCommands() override { 0990 addCommand(new KisImageLayerAddCommand(m_info->image, 0991 m_info->dstNode, 0992 m_putAfter->parent(), 0993 m_putAfter, 0994 true, false)); 0995 0996 } 0997 0998 private: 0999 virtual void addCommandImpl(KUndo2Command *cmd) { 1000 addCommand(cmd); 1001 } 1002 1003 MergeDownInfoBaseSP m_info; 1004 KisNodeSP m_putAfter; 1005 }; 1006 1007 struct SimpleAddNode : public KisCommandUtils::AggregateCommand { 1008 SimpleAddNode(KisImageSP image, KisNodeSP toAdd, KisNodeSP parent = 0, KisNodeSP putAfter = 0) 1009 : m_image(image) 1010 , m_toAdd(toAdd) 1011 , m_parent(parent) 1012 , m_putAfter(putAfter) 1013 { 1014 while (m_parent && !m_parent->allowAsChild(m_toAdd)) { 1015 m_putAfter = m_putAfter ? m_putAfter->parent() : m_parent; 1016 m_parent = m_putAfter ? m_putAfter->parent() : 0; 1017 } 1018 1019 if (!m_parent) { 1020 m_parent = m_image->root(); 1021 } 1022 } 1023 1024 1025 void populateChildCommands() override { 1026 addCommand(new KisImageLayerAddCommand(m_image, 1027 m_toAdd, 1028 m_parent, 1029 m_putAfter, 1030 true, false)); 1031 } 1032 1033 private: 1034 virtual void addCommandImpl(KUndo2Command *cmd) { 1035 addCommand(cmd); 1036 } 1037 1038 KisImageWSP m_image; 1039 KisNodeSP m_toAdd; 1040 KisNodeSP m_parent; 1041 KisNodeSP m_putAfter; 1042 1043 }; 1044 1045 1046 void splitNonRemovableNodes(KisNodeList &nodesToRemove, KisNodeList &_nodesToHide) 1047 { 1048 QSet<KisNodeSP> nodesToHide; 1049 QSet<KisNodeSP> extraNodesToRemove; 1050 1051 for (auto it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) { 1052 KisNodeSP root = *it; 1053 KIS_SAFE_ASSERT_RECOVER_NOOP(root->visible()); 1054 1055 if (!root->isEditable(false)) { 1056 nodesToHide.insert(root); 1057 } else { 1058 bool rootNeedsCarefulRemoval = false; 1059 1060 recursiveApplyNodes(root, 1061 [root, &nodesToHide, &rootNeedsCarefulRemoval] (KisNodeSP node) { 1062 if (!node->isEditable(false)) { 1063 while (node != root) { 1064 nodesToHide.insert(node); 1065 node = node->parent(); 1066 KIS_SAFE_ASSERT_RECOVER_BREAK(node); 1067 } 1068 nodesToHide.insert(root); 1069 rootNeedsCarefulRemoval = true; 1070 } 1071 }); 1072 1073 if (rootNeedsCarefulRemoval) { 1074 recursiveApplyNodes(root, 1075 [&extraNodesToRemove] (KisNodeSP node) { 1076 extraNodesToRemove.insert(node); 1077 }); 1078 } 1079 } 1080 } 1081 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0) 1082 nodesToRemove += KisNodeList(extraNodesToRemove.begin(), extraNodesToRemove.end()); 1083 #else 1084 nodesToRemove += extraNodesToRemove.toList(); 1085 #endif 1086 KritaUtils::filterContainer<KisNodeList>(nodesToRemove, 1087 [nodesToHide](KisNodeSP node) { 1088 return !nodesToHide.contains(node); 1089 }); 1090 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0) 1091 _nodesToHide = KisNodeList(nodesToHide.begin(), nodesToHide.end()); 1092 #else 1093 _nodesToHide = nodesToHide.toList(); 1094 #endif 1095 } 1096 1097 struct CleanUpNodes : private RemoveNodeHelper, public KisCommandUtils::AggregateCommand { 1098 CleanUpNodes(MergeDownInfoBaseSP info, KisNodeSP putAfter) 1099 : m_info(info), m_putAfter(putAfter) {} 1100 1101 static void findPerfectParent(KisNodeList nodesToDelete, KisNodeSP &putAfter, KisNodeSP &parent) { 1102 if (!putAfter) { 1103 putAfter = nodesToDelete.last(); 1104 } 1105 1106 // Add the new merged node on top of the active node 1107 // -- checking all parents if they are included in nodesToDelete 1108 // Not every descendant is included in nodesToDelete even if in fact 1109 // they are going to be deleted, so we need to check it. 1110 // If we consider the path from root to the putAfter node, 1111 // if there are any nodes marked for deletion, any node afterwards 1112 // is going to be deleted, too. 1113 // example: root . . . . . ! ! . . ! ! ! ! . . . . putAfter 1114 // it should be: root . . . . . ! ! ! ! ! ! ! ! ! ! ! ! !putAfter 1115 // and here: root . . . . X ! ! . . ! ! ! ! . . . . putAfter 1116 // you can see which node is "the perfect ancestor" 1117 // (marked X; called "parent" in the function arguments). 1118 // and here: root . . . . . O ! . . ! ! ! ! . . . . putAfter 1119 // you can see which node is "the topmost deleted ancestor" (marked 'O') 1120 1121 KisNodeSP node = putAfter->parent(); 1122 bool foundDeletedAncestor = false; 1123 KisNodeSP topmostAncestorToDelete = nullptr; 1124 1125 while (node) { 1126 1127 if (nodesToDelete.contains(node) 1128 && !nodesToDelete.contains(node->parent())) { 1129 foundDeletedAncestor = true; 1130 topmostAncestorToDelete = node; 1131 // Here node is to be deleted and its parent is not, 1132 // so its parent is the one of the first not deleted (="perfect") ancestors. 1133 // We need the one that is closest to the top (root) 1134 } 1135 1136 node = node->parent(); 1137 } 1138 1139 if (foundDeletedAncestor) { 1140 parent = topmostAncestorToDelete->parent(); 1141 putAfter = topmostAncestorToDelete; 1142 } 1143 else { 1144 parent = putAfter->parent(); // putAfter (and none of its ancestors) is to be deleted, so its parent is the first not deleted ancestor 1145 } 1146 1147 } 1148 1149 void populateChildCommands() override { 1150 KisNodeList nodesToDelete = m_info->allSrcNodes(); 1151 1152 KisNodeSP parent; 1153 findPerfectParent(nodesToDelete, m_putAfter, parent); 1154 1155 if (!parent) { 1156 KisNodeSP oldRoot = m_info->image->root(); 1157 KisNodeSP newRoot(new KisGroupLayer(m_info->image, "root", OPACITY_OPAQUE_U8)); 1158 1159 // copy all fake nodes into the new image 1160 KisLayerUtils::recursiveApplyNodes(oldRoot, [this, oldRoot, newRoot] (KisNodeSP node) { 1161 if (node->isFakeNode() && node->parent() == oldRoot) { 1162 addCommand(new KisImageLayerAddCommand(m_info->image, 1163 node->clone(), 1164 newRoot, 1165 KisNodeSP(), 1166 false, false)); 1167 1168 } 1169 }); 1170 1171 addCommand(new KisImageLayerAddCommand(m_info->image, 1172 m_info->dstNode, 1173 newRoot, 1174 KisNodeSP(), 1175 true, false)); 1176 addCommand(new KisImageChangeLayersCommand(m_info->image, oldRoot, newRoot)); 1177 1178 } 1179 else { 1180 addCommand(new KisImageLayerAddCommand(m_info->image, 1181 m_info->dstNode, 1182 parent, 1183 m_putAfter, 1184 true, false)); 1185 1186 1187 /** 1188 * We can merge selection masks, in this case dstLayer is not defined! 1189 */ 1190 if (m_info->dstLayer()) { 1191 reparentSelectionMasks(m_info->image, 1192 m_info->dstLayer(), 1193 m_info->selectionMasks); 1194 } 1195 1196 KisNodeList safeNodesToDelete = m_info->allSrcNodes(); 1197 KisNodeList safeNodesToHide; 1198 1199 splitNonRemovableNodes(safeNodesToDelete, safeNodesToHide); 1200 1201 Q_FOREACH(KisNodeSP node, safeNodesToHide) { 1202 addCommand(new KisImageChangeVisibilityCommand(false, node)); 1203 } 1204 1205 safeRemoveMultipleNodes(safeNodesToDelete, m_info->image); 1206 } 1207 1208 1209 } 1210 1211 private: 1212 void addCommandImpl(KUndo2Command *cmd) override { 1213 addCommand(cmd); 1214 } 1215 1216 void reparentSelectionMasks(KisImageSP image, 1217 KisLayerSP newLayer, 1218 const QVector<KisSelectionMaskSP> &selectionMasks) { 1219 1220 KIS_SAFE_ASSERT_RECOVER_RETURN(newLayer); 1221 1222 foreach (KisSelectionMaskSP mask, selectionMasks) { 1223 addCommand(new KisImageLayerMoveCommand(image, mask, newLayer, newLayer->lastChild())); 1224 addCommand(new KisActivateSelectionMaskCommand(mask, false)); 1225 } 1226 } 1227 private: 1228 MergeDownInfoBaseSP m_info; 1229 KisNodeSP m_putAfter; 1230 }; 1231 1232 SwitchFrameCommand::SharedStorage::~SharedStorage() { 1233 } 1234 1235 SwitchFrameCommand::SwitchFrameCommand(KisImageSP image, int time, bool finalize, SharedStorageSP storage) 1236 : FlipFlopCommand(finalize), 1237 m_image(image), 1238 m_newTime(time), 1239 m_storage(storage) {} 1240 1241 SwitchFrameCommand::~SwitchFrameCommand() {} 1242 1243 void SwitchFrameCommand::partA() { 1244 KisImageAnimationInterface *interface = m_image->animationInterface(); 1245 const int currentTime = interface->currentTime(); 1246 if (currentTime == m_newTime) { 1247 m_storage->value = m_newTime; 1248 return; 1249 } 1250 1251 interface->image()->disableUIUpdates(); 1252 interface->saveAndResetCurrentTime(m_newTime, &m_storage->value); 1253 } 1254 1255 void SwitchFrameCommand::partB() { 1256 KisImageAnimationInterface *interface = m_image->animationInterface(); 1257 const int currentTime = interface->currentTime(); 1258 if (currentTime == m_storage->value) { 1259 return; 1260 } 1261 1262 interface->restoreCurrentTime(&m_storage->value); 1263 interface->image()->enableUIUpdates(); 1264 } 1265 1266 struct AddNewFrame : public KisCommandUtils::AggregateCommand { 1267 AddNewFrame(KisNodeSP node, int frame) : m_node(node), m_frame(frame) {} 1268 AddNewFrame(KisNodeSP node, int frame, KisNodeList sampleNodes) : m_node(node), m_frame(frame), m_sampledNodes(sampleNodes) {} 1269 AddNewFrame(KisNodeSP node, int frame, KisNodeSP source) : m_node(node), m_frame(frame) { m_sampledNodes << source; } 1270 AddNewFrame(MergeDownInfoBaseSP info, int frame) : m_frame(frame), m_sampledNodes(info->allSrcNodes()), m_mergeInfo(info) {} 1271 1272 void populateChildCommands() override { 1273 KUndo2Command *cmd = new KUndo2Command; 1274 KisNodeSP node = m_node ? m_node : m_mergeInfo->dstNode; 1275 KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true); 1276 channel->addKeyframe(m_frame, cmd); 1277 1278 if (m_sampledNodes.count() > 0) { 1279 applyKeyframeColorLabel(channel->keyframeAt(m_frame), m_sampledNodes); 1280 } 1281 1282 addCommand(cmd); 1283 } 1284 1285 void applyKeyframeColorLabel(KisKeyframeSP dstKeyframe, KisNodeList srcNodes) { 1286 Q_FOREACH(KisNodeSP srcNode, srcNodes) { 1287 Q_FOREACH(KisKeyframeChannel *channel, srcNode->keyframeChannels().values()) { 1288 KisKeyframeSP keyframe = channel->keyframeAt(m_frame); 1289 if (!keyframe.isNull() && keyframe->colorLabel() != 0) { 1290 dstKeyframe->setColorLabel(keyframe->colorLabel()); 1291 return; 1292 } 1293 } 1294 } 1295 1296 dstKeyframe->setColorLabel(0); 1297 } 1298 1299 private: 1300 KisNodeSP m_node; 1301 int m_frame; 1302 KisNodeList m_sampledNodes; 1303 MergeDownInfoBaseSP m_mergeInfo; 1304 }; 1305 1306 QSet<int> fetchLayerFrames(KisNodeSP node) { 1307 QSet<int> frames; 1308 Q_FOREACH(KisKeyframeChannel *channel, node->keyframeChannels()) { 1309 if (!channel) { 1310 continue; 1311 } 1312 1313 KisRasterKeyframeChannel *rasterChan = dynamic_cast<KisRasterKeyframeChannel*>(channel); 1314 if (rasterChan) { 1315 frames.unite(rasterChan->allKeyframeTimes()); 1316 continue; 1317 } 1318 1319 KisScalarKeyframeChannel *scalarChan = dynamic_cast<KisScalarKeyframeChannel*>(channel); 1320 if (scalarChan) { 1321 const int initialKeyframe = scalarChan->firstKeyframeTime(); 1322 1323 if (initialKeyframe == -1) { 1324 continue; 1325 } 1326 1327 const int lastKeyframe = scalarChan->lastKeyframeTime(); 1328 KisTimeSpan currentSpan = scalarChan->identicalFrames(initialKeyframe); 1329 while (!currentSpan.isInfinite() && currentSpan.isValid() && currentSpan.start() < lastKeyframe) { 1330 frames.insert(currentSpan.start()); 1331 currentSpan = scalarChan->identicalFrames(currentSpan.end() + 1); 1332 } 1333 1334 frames.insert(lastKeyframe); 1335 } 1336 1337 } 1338 1339 return frames; 1340 } 1341 1342 QSet<int> fetchLayerFramesRecursive(KisNodeSP rootNode) { 1343 if (!rootNode->visible()) return QSet<int>(); 1344 1345 QSet<int> frames = fetchLayerFrames(rootNode); 1346 1347 KisNodeSP node = rootNode->firstChild(); 1348 while(node) { 1349 frames |= fetchLayerFramesRecursive(node); 1350 node = node->nextSibling(); 1351 } 1352 1353 return frames; 1354 } 1355 1356 void updateFrameJobs(FrameJobs *jobs, KisNodeSP node) { 1357 QSet<int> frames = fetchLayerFrames(node); 1358 frames = fetchUniqueFrameTimes(node, frames, false); 1359 1360 if (frames.isEmpty()) { 1361 (*jobs)[0].insert(node); 1362 } else { 1363 foreach (int frame, frames) { 1364 (*jobs)[frame].insert(node); 1365 } 1366 } 1367 } 1368 1369 void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode) { 1370 updateFrameJobs(jobs, rootNode); 1371 1372 KisNodeSP node = rootNode->firstChild(); 1373 while(node) { 1374 updateFrameJobsRecursive(jobs, node); 1375 node = node->nextSibling(); 1376 } 1377 } 1378 1379 /** 1380 * \see a comment in mergeMultipleLayersImpl() 1381 */ 1382 void mergeDown(KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy* strategy) 1383 { 1384 if (!layer->prevSibling()) return; 1385 1386 // XXX: this breaks if we allow free mixing of masks and layers 1387 KisLayerSP prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data()); 1388 if (!prevLayer) return; 1389 1390 if (!layer->visible() && !prevLayer->visible()) { 1391 return; 1392 } 1393 1394 KisImageSignalVector emitSignals; 1395 KisProcessingApplicator applicator(image, 0, 1396 KisProcessingApplicator::NONE, 1397 emitSignals, 1398 kundo2_i18n("Merge Down")); 1399 1400 if (layer->visible() && prevLayer->visible()) { 1401 MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer)); 1402 1403 // disable key strokes on all colorize masks, all onion skins on 1404 // paint layers and wait until update is finished with a barrier 1405 applicator.applyCommand(new DisableColorizeKeyStrokes(info)); 1406 applicator.applyCommand(new DisableOnionSkins(info)); 1407 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); 1408 1409 applicator.applyCommand(new KeepMergedNodesSelected(info, false)); 1410 applicator.applyCommand(new FillSelectionMasks(info)); 1411 applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER); 1412 1413 // NOTE: shape layer may have emitted spontaneous jobs during layer creation, 1414 // wait for them to complete! 1415 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER); 1416 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); 1417 1418 // in two-layer mode we disable pass through only when the destination layer 1419 // is not a group layer 1420 applicator.applyCommand(new DisablePassThroughForHeadsOnly(info, true)); 1421 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); 1422 1423 if (info->frames.size() > 0) { 1424 /** 1425 * Save the original time before we start switching is with 1426 * asynchronous SwitchFrameCommand. 1427 */ 1428 const int currentTimeOnStart = info->image->animationInterface()->currentTime(); 1429 1430 foreach (int frame, info->frames) { 1431 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage)); 1432 1433 applicator.applyCommand(new AddNewFrame(info, frame)); 1434 /** 1435 * When switching frames we need to update the entire image, not 1436 * only the **new** extent of the layer, hence we pass `refresh_entire_image` 1437 * to the command to make sure that the entire image bounds rect is added 1438 * to the update rect 1439 */ 1440 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image)); 1441 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER); 1442 1443 /** 1444 * If source layer is **not** animated, then just merge that into the 1445 * current frame to avoid unintentional destruction of the animation 1446 * on the layer below. To merge the source into all the frames, just 1447 * make the source animated. 1448 * 1449 * See https://bugs.kde.org/show_bug.cgi?id=475550 1450 */ 1451 const bool skipMergingSourceLayer = !layer->isAnimated() && 1452 frame != currentTimeOnStart; 1453 1454 applicator.applyCommand(new MergeLayers(info, skipMergingSourceLayer), KisStrokeJobData::BARRIER); 1455 1456 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage), KisStrokeJobData::BARRIER); 1457 } 1458 } else { 1459 applicator.applyCommand(new RefreshHiddenAreas(info)); 1460 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER); 1461 applicator.applyCommand(new MergeLayers(info, false), KisStrokeJobData::BARRIER); 1462 } 1463 1464 applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER); 1465 applicator.applyCommand(new CleanUpNodes(info, layer), 1466 KisStrokeJobData::SEQUENTIAL, 1467 KisStrokeJobData::EXCLUSIVE); 1468 applicator.applyCommand(new KeepMergedNodesSelected(info, true)); 1469 } else if (layer->visible()) { 1470 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), 1471 layer, KisNodeSP(), 1472 image, false)); 1473 1474 applicator.applyCommand( 1475 new SimpleRemoveLayers(KisNodeList() << prevLayer, 1476 image), 1477 KisStrokeJobData::SEQUENTIAL, 1478 KisStrokeJobData::EXCLUSIVE); 1479 1480 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), 1481 KisNodeSP(), layer, 1482 image, true)); 1483 } else if (prevLayer->visible()) { 1484 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), 1485 layer, KisNodeSP(), 1486 image, false)); 1487 1488 applicator.applyCommand( 1489 new SimpleRemoveLayers(KisNodeList() << layer, 1490 image), 1491 KisStrokeJobData::SEQUENTIAL, 1492 KisStrokeJobData::EXCLUSIVE); 1493 1494 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), 1495 KisNodeSP(), prevLayer, 1496 image, true)); 1497 } 1498 1499 applicator.end(); 1500 } 1501 1502 bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents) 1503 { 1504 KisNodeList nodeParents; 1505 1506 KisNodeSP parent = node->parent(); 1507 while (parent) { 1508 nodeParents << parent; 1509 parent = parent->parent(); 1510 } 1511 1512 foreach(KisNodeSP perspectiveParent, parents) { 1513 if (nodeParents.contains(perspectiveParent)) { 1514 return true; 1515 } 1516 } 1517 1518 return false; 1519 } 1520 1521 bool checkIsCloneOf(KisNodeSP node, const KisNodeList &nodes) 1522 { 1523 bool result = false; 1524 1525 KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data()); 1526 if (clone) { 1527 KisNodeSP cloneSource = KisNodeSP(clone->copyFrom()); 1528 1529 Q_FOREACH(KisNodeSP subtree, nodes) { 1530 result = 1531 recursiveFindNode(subtree, 1532 [cloneSource](KisNodeSP node) -> bool 1533 { 1534 return node == cloneSource; 1535 }); 1536 1537 if (!result) { 1538 result = checkIsCloneOf(cloneSource, nodes); 1539 } 1540 1541 if (result) { 1542 break; 1543 } 1544 } 1545 } 1546 1547 return result; 1548 } 1549 1550 void filterMergeableNodes(KisNodeList &nodes, bool allowMasks) 1551 { 1552 KisNodeList::iterator it = nodes.begin(); 1553 1554 while (it != nodes.end()) { 1555 if ((!allowMasks && !qobject_cast<KisLayer*>(it->data())) || 1556 checkIsChildOf(*it, nodes)) { 1557 //qDebug() << "Skipping node" << ppVar((*it)->name()); 1558 it = nodes.erase(it); 1559 } else { 1560 ++it; 1561 } 1562 } 1563 } 1564 1565 void sortMergeableNodes(KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes) 1566 { 1567 KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root); 1568 1569 if (it != inputNodes.end()) { 1570 outputNodes << *it; 1571 inputNodes.erase(it); 1572 } 1573 1574 if (inputNodes.isEmpty()) { 1575 return; 1576 } 1577 1578 KisNodeSP child = root->firstChild(); 1579 while (child) { 1580 sortMergeableNodes(child, inputNodes, outputNodes); 1581 child = child->nextSibling(); 1582 } 1583 1584 /** 1585 * By the end of recursion \p inputNodes must be empty 1586 */ 1587 KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty()); 1588 } 1589 1590 KisNodeList sortMergeableNodes(KisNodeSP root, KisNodeList nodes) 1591 { 1592 KisNodeList result; 1593 sortMergeableNodes(root, nodes, result); 1594 return result; 1595 } 1596 1597 KisNodeList sortAndFilterMergeableInternalNodes(KisNodeList nodes, bool allowMasks) 1598 { 1599 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; } 1600 1601 KisNodeSP root; 1602 Q_FOREACH(KisNodeSP node, nodes) { 1603 KisNodeSP localRoot = node; 1604 while (localRoot->parent()) { 1605 localRoot = localRoot->parent(); 1606 } 1607 1608 if (!root) { 1609 root = localRoot; 1610 } 1611 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; } 1612 } 1613 1614 KisNodeList result; 1615 sortMergeableNodes(root, nodes, result); 1616 filterMergeableNodes(result, allowMasks); 1617 return result; 1618 } 1619 1620 KisNodeList sortAndFilterAnyMergeableNodesSafe(const KisNodeList &nodes, KisImageSP image) { 1621 KisNodeList filteredNodes = nodes; 1622 KisNodeList sortedNodes; 1623 1624 KisLayerUtils::filterMergeableNodes(filteredNodes, true); 1625 1626 bool haveExternalNodes = false; 1627 Q_FOREACH (KisNodeSP node, nodes) { 1628 if (node->graphListener() != image->root()->graphListener()) { 1629 haveExternalNodes = true; 1630 break; 1631 } 1632 } 1633 1634 if (!haveExternalNodes) { 1635 KisLayerUtils::sortMergeableNodes(image->root(), filteredNodes, sortedNodes); 1636 } else { 1637 sortedNodes = filteredNodes; 1638 } 1639 1640 return sortedNodes; 1641 } 1642 1643 1644 void addCopyOfNameTag(KisNodeSP node) 1645 { 1646 const QString prefix = i18n("Copy of"); 1647 QString newName = node->name(); 1648 if (!newName.startsWith(prefix)) { 1649 newName = QString("%1 %2").arg(prefix).arg(newName); 1650 node->setName(newName); 1651 } 1652 } 1653 1654 KisNodeList findNodesWithProps(KisNodeSP root, const KoProperties &props, bool excludeRoot) 1655 { 1656 KisNodeList nodes; 1657 1658 if ((!excludeRoot || root->parent()) && root->check(props)) { 1659 nodes << root; 1660 } 1661 1662 KisNodeSP node = root->firstChild(); 1663 while (node) { 1664 nodes += findNodesWithProps(node, props, excludeRoot); 1665 node = node->nextSibling(); 1666 } 1667 1668 return nodes; 1669 } 1670 1671 KisNodeList filterInvisibleNodes(const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter) 1672 { 1673 KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; } 1674 KIS_ASSERT_RECOVER(putAfter) { return nodes; } 1675 1676 KisNodeList visibleNodes; 1677 int putAfterIndex = -1; 1678 1679 Q_FOREACH(KisNodeSP node, nodes) { 1680 if (node->visible() || node->userLocked()) { 1681 visibleNodes << node; 1682 } else { 1683 *invisibleNodes << node; 1684 1685 if (node == *putAfter) { 1686 putAfterIndex = visibleNodes.size() - 1; 1687 } 1688 } 1689 } 1690 1691 if (!visibleNodes.isEmpty() && putAfterIndex >= 0) { 1692 putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1); 1693 *putAfter = visibleNodes[putAfterIndex]; 1694 } 1695 1696 return visibleNodes; 1697 } 1698 1699 void filterUnlockedNodes(KisNodeList &nodes) 1700 { 1701 KisNodeList::iterator it = nodes.begin(); 1702 1703 while (it != nodes.end()) { 1704 if ((*it)->userLocked()) { 1705 it = nodes.erase(it); 1706 } else { 1707 ++it; 1708 } 1709 } 1710 } 1711 1712 void changeImageDefaultProjectionColor(KisImageSP image, const KoColor &color) 1713 { 1714 KisImageSignalVector emitSignals; 1715 KisProcessingApplicator applicator(image, 1716 image->root(), 1717 KisProcessingApplicator::RECURSIVE, 1718 emitSignals, 1719 kundo2_i18n("Change projection color"), 1720 0, 1721 KisCommandUtils::ChangeProjectionColorCommand); 1722 applicator.applyCommand(new KisChangeProjectionColorCommand(image, color), KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE); 1723 applicator.end(); 1724 } 1725 1726 struct EphemeralCommandsWrapper : KisCommandUtils::AggregateCommand 1727 { 1728 EphemeralCommandsWrapper(MergeMultipleInfoSP info, QVector<KUndo2Command*> commands, bool cleanupNodes) 1729 : m_info(info) 1730 , m_commands(commands) 1731 , m_cleanupNodes(cleanupNodes) 1732 { 1733 } 1734 1735 void populateChildCommands() { 1736 if (!m_cleanupNodes && !m_info->ephemeralCommandsStore) { 1737 m_info->ephemeralCommandsStore.reset(new KisSurrogateUndoStore()); 1738 } 1739 1740 Q_FOREACH (KUndo2Command *cmd, m_commands) { 1741 if (m_cleanupNodes) { 1742 addCommand(cmd); 1743 } else { 1744 m_info->ephemeralCommandsStore->addCommand(cmd); 1745 } 1746 } 1747 m_commands.clear(); 1748 m_info.reset(); 1749 } 1750 1751 private: 1752 MergeMultipleInfoSP m_info; 1753 QVector<KUndo2Command*> m_commands; 1754 bool m_cleanupNodes {true}; 1755 }; 1756 1757 struct UndoEphemeralCommands : KisCommandUtils::AggregateCommand 1758 { 1759 UndoEphemeralCommands(MergeMultipleInfoSP info) 1760 : m_info(info) 1761 { 1762 } 1763 1764 void populateChildCommands() { 1765 KIS_SAFE_ASSERT_RECOVER_RETURN(m_info->ephemeralCommandsStore); 1766 m_info->ephemeralCommandsStore->undoAll(); 1767 1768 } 1769 1770 private: 1771 MergeMultipleInfoSP m_info; 1772 }; 1773 1774 /** 1775 * There might be two approaches for merging multiple layers: 1776 * 1777 * 1) Consider the selected nodes as a distinct "group" and merge them 1778 * as if they were isolated from the rest of the image. The key point 1779 * of this approach is that the look of the image will change, when 1780 * merging "weird" layers, like adjustment layers or layers with 1781 * non-normal blending mode. 1782 * 1783 * 2) Merge layers in a way to keep the look of the image as unchanged as 1784 * possible. With this approach one uses a few heuristics: 1785 * 1786 * * when merging multiple layers with non-normal (but equal) blending 1787 * mode, first merge these layers together using Normal blending mode, 1788 * then set blending mode of the result to the original blending mode 1789 * 1790 * * when merging multiple layers with different blending modes or 1791 * layer styles, they are first rasterized, and then laid over each 1792 * other with their own composite op. The blending mode of the final 1793 * layer is set to Normal, so the user could clearly see that he should 1794 * choose the correct blending mode. 1795 * 1796 * Krita uses the second approach: after merge operation, the image should look 1797 * as if nothing has happened (if it is technically possible). 1798 */ 1799 void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, 1800 bool flattenSingleLayer, const KUndo2MagicString &actionName, 1801 bool cleanupNodes = true, const QString layerName = QString()) 1802 { 1803 if (!putAfter) { 1804 putAfter = mergedNodes.first(); 1805 } 1806 1807 filterMergeableNodes(mergedNodes); 1808 { 1809 KisNodeList tempNodes; 1810 std::swap(mergedNodes, tempNodes); 1811 sortMergeableNodes(image->root(), tempNodes, mergedNodes); 1812 } 1813 1814 if (mergedNodes.size() <= 1 && 1815 (!flattenSingleLayer && mergedNodes.size() == 1)) return; 1816 1817 KisImageSignalVector emitSignals; 1818 emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes); 1819 1820 1821 1822 KisNodeList originalNodes = mergedNodes; 1823 KisNodeList invisibleNodes; 1824 mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter); 1825 1826 if (mergedNodes.isEmpty()) return; 1827 1828 1829 // make sure we don't add the new layer into a locked group 1830 KIS_SAFE_ASSERT_RECOVER_RETURN(putAfter->parent()); 1831 while (putAfter->parent() && !putAfter->parent()->isEditable()) { 1832 putAfter = putAfter->parent(); 1833 } 1834 1835 /** 1836 * We have reached the root of the layer hierarchy and didn't manage 1837 * to find a node that was editable enough for putting our merged 1838 * result into it. That shouldn't happen in normal circumstances, 1839 * unless the user chose to make the root layer visible and lock 1840 * it manually. 1841 */ 1842 if (!putAfter->parent()) { 1843 return; 1844 } 1845 1846 KisProcessingApplicator applicator(image, 0, 1847 KisProcessingApplicator::NONE, 1848 emitSignals, 1849 actionName); 1850 1851 1852 if (!invisibleNodes.isEmpty() && cleanupNodes) { 1853 1854 /* If the putAfter node is invisible, 1855 * we should instead pick one of the nodes 1856 * to be merged to avoid a null putAfter 1857 * after we remove all invisible layers from 1858 * the image. 1859 * (The assumption is that putAfter is among 1860 * the layers to merge, so if it's invisible, 1861 * it's going to be removed) 1862 */ 1863 if (!putAfter->visible()){ 1864 putAfter = mergedNodes.first(); 1865 } 1866 1867 applicator.applyCommand( 1868 new SimpleRemoveLayers(invisibleNodes, 1869 image), 1870 KisStrokeJobData::SEQUENTIAL, 1871 KisStrokeJobData::EXCLUSIVE); 1872 } 1873 1874 if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) { 1875 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes)); 1876 1877 // disable key strokes on all colorize masks, all onion skins on 1878 // paint layers and wait until update is finished with a barrier 1879 // 1880 // when doing "new layer from visible" we should undo these changes 1881 // before the action stops, because the source layers are **not** 1882 // removed as a result of this action 1883 applicator.applyCommand( 1884 new EphemeralCommandsWrapper(info, 1885 { 1886 new DisableColorizeKeyStrokes(info), 1887 new DisableOnionSkins(info), 1888 new DisablePassThroughForHeadsOnly(info) 1889 }, 1890 cleanupNodes)); 1891 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); 1892 1893 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false)); 1894 applicator.applyCommand(new FillSelectionMasks(info)); 1895 applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER); 1896 applicator.applyCommand(new EphemeralCommandsWrapper(info, { new DisableExtraCompositing(info) } , cleanupNodes)); 1897 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); 1898 1899 if (!info->frames.isEmpty()) { 1900 foreach (int frame, info->frames) { 1901 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage)); 1902 1903 applicator.applyCommand(new AddNewFrame(info, frame)); 1904 /** 1905 * When switching frames we need to update the entire image, not 1906 * only the **new** extent of the layer, hence we pass `refresh_entire_image` 1907 * to the command to make sure that the entire image bounds rect is added 1908 * to the update rect 1909 */ 1910 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image)); 1911 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER); 1912 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER); 1913 1914 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage)); 1915 } 1916 } else { 1917 applicator.applyCommand(new RefreshHiddenAreas(info)); 1918 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER); 1919 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER); 1920 } 1921 1922 //applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER); 1923 if (cleanupNodes){ 1924 applicator.applyCommand(new CleanUpNodes(info, putAfter), 1925 KisStrokeJobData::SEQUENTIAL, 1926 KisStrokeJobData::EXCLUSIVE); 1927 } else { 1928 applicator.applyCommand(new UndoEphemeralCommands(info)); 1929 applicator.applyCommand(new InsertNode(info, putAfter), 1930 KisStrokeJobData::SEQUENTIAL, 1931 KisStrokeJobData::EXCLUSIVE); 1932 } 1933 1934 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true)); 1935 } 1936 1937 applicator.end(); 1938 1939 } 1940 1941 void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter) 1942 { 1943 mergeMultipleLayersImpl(image, mergedNodes, putAfter, false, kundo2_i18n("Merge Selected Nodes")); 1944 } 1945 1946 void newLayerFromVisible(KisImageSP image, KisNodeSP putAfter) 1947 { 1948 KisNodeList mergedNodes; 1949 mergedNodes << image->root(); 1950 1951 mergeMultipleLayersImpl(image, mergedNodes, putAfter, true, kundo2_i18n("New From Visible"), false, i18nc("New layer created from all the visible layers", "Visible")); 1952 } 1953 1954 struct MergeSelectionMasks : public KisCommandUtils::AggregateCommand { 1955 MergeSelectionMasks(MergeDownInfoBaseSP info, KisNodeSP putAfter) 1956 : m_info(info), 1957 m_putAfter(putAfter){} 1958 1959 void populateChildCommands() override { 1960 KisNodeSP parent; 1961 CleanUpNodes::findPerfectParent(m_info->allSrcNodes(), m_putAfter, parent); 1962 1963 KisLayerSP parentLayer; 1964 do { 1965 parentLayer = qobject_cast<KisLayer*>(parent.data()); 1966 1967 parent = parent->parent(); 1968 } while(!parentLayer && parent); 1969 1970 KisSelectionSP selection = new KisSelection(); 1971 1972 foreach (KisNodeSP node, m_info->allSrcNodes()) { 1973 KisMaskSP mask = dynamic_cast<KisMask*>(node.data()); 1974 if (!mask) continue; 1975 1976 selection->pixelSelection()->applySelection( 1977 mask->selection()->pixelSelection(), SELECTION_ADD); 1978 } 1979 1980 KisSelectionMaskSP mergedMask = new KisSelectionMask(m_info->image, i18n("Selection Mask")); 1981 mergedMask->initSelection(parentLayer); 1982 mergedMask->setSelection(selection); 1983 1984 m_info->dstNode = mergedMask; 1985 } 1986 1987 private: 1988 MergeDownInfoBaseSP m_info; 1989 KisNodeSP m_putAfter; 1990 }; 1991 1992 struct ActivateSelectionMask : public KisCommandUtils::AggregateCommand { 1993 ActivateSelectionMask(MergeDownInfoBaseSP info) 1994 : m_info(info) {} 1995 1996 void populateChildCommands() override { 1997 KisSelectionMaskSP mergedMask = dynamic_cast<KisSelectionMask*>(m_info->dstNode.data()); 1998 addCommand(new KisActivateSelectionMaskCommand(mergedMask, true)); 1999 } 2000 2001 private: 2002 MergeDownInfoBaseSP m_info; 2003 }; 2004 2005 bool tryMergeSelectionMasks(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter) 2006 { 2007 QList<KisSelectionMaskSP> selectionMasks; 2008 2009 for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) { 2010 KisSelectionMaskSP mask = dynamic_cast<KisSelectionMask*>(it->data()); 2011 if (!mask) { 2012 it = mergedNodes.erase(it); 2013 } else { 2014 selectionMasks.append(mask); 2015 ++it; 2016 } 2017 } 2018 2019 if (mergedNodes.isEmpty()) return false; 2020 2021 KisLayerSP parentLayer = qobject_cast<KisLayer*>(selectionMasks.first()->parent().data()); 2022 KIS_ASSERT_RECOVER(parentLayer) { return 0; } 2023 2024 KisImageSignalVector emitSignals; 2025 2026 KisProcessingApplicator applicator(image, 0, 2027 KisProcessingApplicator::NONE, 2028 emitSignals, 2029 kundo2_i18n("Merge Selection Masks")); 2030 2031 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes)); 2032 2033 2034 applicator.applyCommand(new MergeSelectionMasks(info, putAfter)); 2035 applicator.applyCommand(new CleanUpNodes(info, putAfter), 2036 KisStrokeJobData::SEQUENTIAL, 2037 KisStrokeJobData::EXCLUSIVE); 2038 applicator.applyCommand(new ActivateSelectionMask(info)); 2039 applicator.end(); 2040 2041 return true; 2042 } 2043 2044 void flattenLayer(KisImageSP image, KisLayerSP layer) 2045 { 2046 if (!layer->childCount() && !layer->layerStyle()) 2047 return; 2048 2049 KisNodeList mergedNodes; 2050 mergedNodes << layer; 2051 2052 mergeMultipleLayersImpl(image, mergedNodes, layer, true, kundo2_i18n("Flatten Layer")); 2053 } 2054 2055 void flattenImage(KisImageSP image, KisNodeSP activeNode) 2056 { 2057 if (!activeNode) { 2058 activeNode = image->root()->lastChild(); 2059 } 2060 2061 2062 KisNodeList mergedNodes; 2063 mergedNodes << image->root(); 2064 2065 mergeMultipleLayersImpl(image, mergedNodes, activeNode, true, kundo2_i18n("Flatten Image")); 2066 } 2067 2068 KisSimpleUpdateCommand::KisSimpleUpdateCommand(KisNodeList nodes, bool finalize, KUndo2Command *parent) 2069 : FlipFlopCommand(finalize, parent), 2070 m_nodes(nodes) 2071 { 2072 } 2073 void KisSimpleUpdateCommand::partB() 2074 { 2075 updateNodes(m_nodes); 2076 } 2077 void KisSimpleUpdateCommand::updateNodes(const KisNodeList &nodes) 2078 { 2079 Q_FOREACH(KisNodeSP node, nodes) { 2080 node->setDirty(node->extent()); 2081 } 2082 } 2083 2084 KisNodeSP recursiveFindNode(KisNodeSP node, std::function<bool(KisNodeSP)> func) 2085 { 2086 if (func(node)) { 2087 return node; 2088 } 2089 2090 node = node->firstChild(); 2091 while (node) { 2092 KisNodeSP resultNode = recursiveFindNode(node, func); 2093 if (resultNode) { 2094 return resultNode; 2095 } 2096 node = node->nextSibling(); 2097 } 2098 2099 return 0; 2100 } 2101 2102 KisNodeSP findNodeByUuid(KisNodeSP root, const QUuid &uuid) 2103 { 2104 return recursiveFindNode(root, 2105 [uuid] (KisNodeSP node) { 2106 return node->uuid() == uuid; 2107 }); 2108 } 2109 2110 QList<KisNodeSP> findNodesByName(KisNodeSP root, const QString &name, bool recursive, bool partialMatch) 2111 { 2112 KisNodeList nodeList; 2113 KisNodeSP child = root->firstChild(); 2114 2115 while (child) { 2116 if (name.isEmpty() || (!partialMatch && child->name() == name) || (partialMatch && child->name().contains(name, Qt::CaseInsensitive))) { 2117 nodeList << child; 2118 } 2119 if (recursive && child->childCount() > 0) { 2120 nodeList << findNodesByName(child, name, recursive, partialMatch); 2121 } 2122 child = child->nextSibling(); 2123 } 2124 2125 return nodeList; 2126 } 2127 2128 KisNodeSP findNodeByName(KisNodeSP root, const QString &name) 2129 { 2130 return recursiveFindNode(root, 2131 [name] (KisNodeSP node) { 2132 return node->name() == name; 2133 }); 2134 } 2135 2136 void forceAllDelayedNodesUpdate(KisNodeSP root) 2137 { 2138 KisLayerUtils::recursiveApplyNodes(root, 2139 [] (KisNodeSP node) { 2140 KisDelayedUpdateNodeInterface *delayedUpdate = 2141 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data()); 2142 if (delayedUpdate) { 2143 delayedUpdate->forceUpdateTimedNode(); 2144 } 2145 }); 2146 } 2147 2148 bool hasDelayedNodeWithUpdates(KisNodeSP root) 2149 { 2150 return recursiveFindNode(root, 2151 [] (KisNodeSP node) { 2152 KisDelayedUpdateNodeInterface *delayedUpdate = 2153 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data()); 2154 2155 return delayedUpdate ? delayedUpdate->hasPendingTimedUpdates() : false; 2156 }); 2157 } 2158 2159 void forceAllHiddenOriginalsUpdate(KisNodeSP root) 2160 { 2161 KisLayerUtils::recursiveApplyNodes(root, 2162 [] (KisNodeSP node) { 2163 KisCroppedOriginalLayerInterface *croppedUpdate = 2164 dynamic_cast<KisCroppedOriginalLayerInterface*>(node.data()); 2165 if (croppedUpdate) { 2166 croppedUpdate->forceUpdateHiddenAreaOnOriginal(); 2167 } 2168 }); 2169 } 2170 2171 KisImageSP findImageByHierarchy(KisNodeSP node) 2172 { 2173 while (node) { 2174 const KisLayer *layer = dynamic_cast<const KisLayer*>(node.data()); 2175 if (layer) { 2176 return layer->image(); 2177 } 2178 2179 node = node->parent(); 2180 } 2181 2182 return 0; 2183 } 2184 2185 namespace Private { 2186 QRect realNodeChangeRect(KisNodeSP rootNode, QRect currentRect = QRect()) { 2187 KisNodeSP node = rootNode->firstChild(); 2188 2189 while(node) { 2190 currentRect |= realNodeChangeRect(node, currentRect); 2191 node = node->nextSibling(); 2192 } 2193 2194 if (!rootNode->isFakeNode() && !rootNode->projectionLeaf()->isMask()) { 2195 // TODO: it would be better to count up changeRect inside 2196 // node's extent() method 2197 // 2198 // NOTE: when flattening a group layer, we should take the change rect of the 2199 // all the child layers as the source of the change. We are calculating 2200 // the change rect **before** the update itself, therefore rootNode->exactBounds() 2201 // is not yet prepared, hence its exact bounds still contail old values. 2202 currentRect |= rootNode->projectionPlane()->changeRect(rootNode->exactBounds() | currentRect); 2203 } 2204 2205 return currentRect; 2206 } 2207 } 2208 2209 namespace Private { 2210 void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea, const QRect &extraUpdateRect) { 2211 QRect realNodeRect = Private::realNodeChangeRect(rootNode) | extraUpdateRect; 2212 if (!preparedArea.contains(realNodeRect)) { 2213 2214 QRegion dirtyRegion = realNodeRect; 2215 dirtyRegion -= preparedArea; 2216 2217 auto rc = dirtyRegion.begin(); 2218 while (rc != dirtyRegion.end()) { 2219 image->refreshGraphAsync(rootNode, *rc, realNodeRect); 2220 rc++; 2221 } 2222 } 2223 } 2224 } // namespace Private 2225 2226 void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea) { 2227 Private::refreshHiddenAreaAsync(image, rootNode, preparedArea, QRect()); 2228 } 2229 2230 QRect recursiveTightNodeVisibleBounds(KisNodeSP rootNode) 2231 { 2232 QRect exactBounds; 2233 recursiveApplyNodes(rootNode, [&exactBounds] (KisNodeSP node) { 2234 exactBounds |= node->projectionPlane()->tightUserVisibleBounds(); 2235 }); 2236 return exactBounds; 2237 } 2238 2239 KisNodeSP findRoot(KisNodeSP node) 2240 { 2241 if (!node) return node; 2242 2243 while (node->parent()) { 2244 node = node->parent(); 2245 } 2246 return node; 2247 } 2248 2249 bool canChangeImageProfileInvisibly(KisImageSP image) 2250 { 2251 int numLayers = 0; 2252 bool hasNonNormalLayers = false; 2253 bool hasTransparentLayer = false; 2254 2255 2256 recursiveApplyNodes(image->root(), 2257 [&numLayers, &hasNonNormalLayers, &hasTransparentLayer, image] (KisNodeSP node) { 2258 if (!node->inherits("KisLayer")) return; 2259 2260 numLayers++; 2261 2262 if (node->exactBounds().isEmpty()) return; 2263 2264 // this is only an approximation! it is not exact! 2265 if (!hasTransparentLayer && 2266 node->exactBounds() != image->bounds()) { 2267 2268 hasTransparentLayer = true; 2269 } 2270 2271 if (!hasNonNormalLayers && 2272 node->compositeOpId() != COMPOSITE_OVER) { 2273 2274 hasNonNormalLayers = true; 2275 } 2276 }); 2277 2278 return numLayers == 1 || (!hasNonNormalLayers && !hasTransparentLayer); 2279 } 2280 2281 void splitAlphaToMask(KisImageSP image, KisNodeSP node, const QString& maskName) 2282 { 2283 SplitAlphaToMaskInfoSP info( new SplitAlphaToMaskInfo(node->image(), node, maskName) ); 2284 2285 KisImageSignalVector emitSignals; 2286 KisProcessingApplicator applicator(image, 0, 2287 KisProcessingApplicator::NONE, 2288 emitSignals, 2289 kundo2_i18n("Split Alpha into a Mask")); 2290 2291 applicator.applyCommand(new SimpleAddNode(info->image, info->getMask(), info->node), KisStrokeJobData::BARRIER); 2292 applicator.applyCommand(new InitSplitAlphaSelectionMask(info)); 2293 if (info->frames.count() > 0) { 2294 Q_FOREACH(const int& frame, info->frames) { 2295 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage)); 2296 applicator.applyCommand(new AddNewFrame(info->getMask(), frame, info->node)); 2297 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER); 2298 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage)); 2299 } 2300 } else { 2301 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER); 2302 } 2303 applicator.end(); 2304 } 2305 2306 std::future<KisNodeSP> convertToPaintLayer(KisImageSP image, KisNodeSP src) 2307 { 2308 //Initialize all operation dependencies. 2309 ConvertToPaintLayerInfoSP info( new ConvertToPaintLayerInfo(image, src) ); 2310 2311 if (!info->hasTargetNode()) 2312 return kismpl::make_ready_future(KisNodeSP()); 2313 2314 KisImageSignalVector emitSignals; 2315 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Convert to a Paint Layer")); 2316 2317 applicator.applyCommand(new SimpleAddNode(info->image(), info->targetNode(), info->insertionParent(), info->insertionPutAfter()), KisStrokeJobData::BARRIER); 2318 2319 if (info->frames().count() > 0) { 2320 Q_FOREACH(const int& frame, info->frames()) { 2321 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, false, info->storage)); 2322 applicator.applyCommand(new RefreshDelayedUpdateLayers(info->sourceNodes()), KisStrokeJobData::BARRIER); 2323 applicator.applyCommand(new RefreshHiddenAreas(info->image(), info->sourceNode()), KisStrokeJobData::BARRIER); 2324 applicator.applyCommand(new AddNewFrame(info->targetNode(), frame, info->sourceNode()), KisStrokeJobData::BARRIER); 2325 applicator.applyCommand(new UploadProjectionToFrameCommand(info->sourceNode(), info->targetNode(), frame)); 2326 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, true, info->storage)); 2327 } 2328 } 2329 2330 applicator.applyCommand(new SimpleRemoveLayers(info->toRemove(), info->image())); 2331 2332 applicator.end(); 2333 2334 return kismpl::then(applicator.successfullyCompletedFuture(), 2335 [node = info->targetNode()] (std::future<bool> completed) { 2336 return completed.get() ? node : KisNodeSP(); 2337 }); 2338 } 2339 2340 //=========================================================== 2341 2342 int fetchLayerActiveRasterFrameID(KisNodeSP node) 2343 { 2344 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, -1); 2345 KisPaintDeviceSP paintDevice = node->paintDevice(); 2346 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1); 2347 2348 if (!paintDevice->keyframeChannel()) { 2349 return -1; 2350 } 2351 2352 const int activeTime = paintDevice->keyframeChannel()->activeKeyframeTime(); 2353 KisRasterKeyframeSP keyframe = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(activeTime); 2354 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(keyframe, -1); 2355 2356 return keyframe->frameID(); 2357 } 2358 2359 int fetchLayerActiveRasterFrameTime(KisNodeSP node) 2360 { 2361 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, -1); 2362 KisPaintDeviceSP paintDevice = node->paintDevice(); 2363 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1); 2364 2365 if (!paintDevice->keyframeChannel()) { 2366 return -1; 2367 } 2368 2369 return paintDevice->keyframeChannel()->activeKeyframeTime(); 2370 } 2371 2372 KisTimeSpan fetchLayerActiveRasterFrameSpan(KisNodeSP node, const int time) 2373 { 2374 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, KisTimeSpan::infinite(0)); 2375 KisPaintDeviceSP paintDevice = node->paintDevice(); 2376 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, KisTimeSpan::infinite(0)); 2377 if (!paintDevice->keyframeChannel()) { 2378 return KisTimeSpan::infinite(0); 2379 } 2380 2381 return paintDevice->keyframeChannel()->affectedFrames(time); 2382 } 2383 2384 QSet<int> fetchLayerIdenticalRasterFrameTimes(KisNodeSP node, const int &frameTime) 2385 { 2386 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>()); 2387 KisPaintDeviceSP paintDevice = node->paintDevice(); 2388 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>()); 2389 if (!paintDevice->keyframeChannel()) { 2390 return QSet<int>(); 2391 } 2392 2393 return paintDevice->keyframeChannel()->clonesOf(node.data(), frameTime); 2394 } 2395 2396 /* Finds all frames matching a specific frame ID. useful to filter out duplicate frames. */ 2397 QSet<int> fetchLayerRasterFrameTimesMatchingID(KisNodeSP node, const int frameID) { 2398 KIS_ASSERT(node); 2399 KisRasterKeyframeChannel* rasterChannel = dynamic_cast<KisRasterKeyframeChannel*>(node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false)); 2400 2401 if (!rasterChannel) { 2402 return QSet<int>(); 2403 } 2404 2405 return rasterChannel->timesForFrameID(frameID); 2406 } 2407 2408 QSet<int> fetchLayerRasterIDsAtTimes(KisNodeSP node, const QSet<int> ×) 2409 { 2410 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>()); 2411 KisPaintDeviceSP paintDevice = node->paintDevice(); 2412 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>()); 2413 if (!paintDevice->keyframeChannel()) { 2414 return QSet<int>(); 2415 } 2416 2417 QSet<int> frameIDs; 2418 2419 Q_FOREACH( const int& frame, times ) { 2420 KisRasterKeyframeSP raster = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(frame); 2421 frameIDs << raster->frameID(); 2422 } 2423 2424 return frameIDs; 2425 } 2426 2427 QSet<int> filterTimesForOnlyRasterKeyedTimes(KisNodeSP node, const QSet<int> ×) 2428 { 2429 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, times); 2430 KisPaintDeviceSP paintDevice = node->paintDevice(); 2431 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, times); 2432 if (!paintDevice->keyframeChannel()) { 2433 return times; 2434 } 2435 2436 return paintDevice->keyframeChannel()->allKeyframeTimes().intersect(times); 2437 } 2438 2439 QSet<int> fetchLayerUniqueRasterTimesMatchingIDs(KisNodeSP node, QSet<int>& frameIDs) 2440 { 2441 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>()); 2442 KisPaintDeviceSP paintDevice = node->paintDevice(); 2443 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>()); 2444 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice->framesInterface(), QSet<int>()); 2445 2446 QSet<int> uniqueTimes; 2447 2448 Q_FOREACH( const int& id, frameIDs) { 2449 QSet<int> times = fetchLayerRasterFrameTimesMatchingID(node, id); 2450 if (times.count() > 0) { 2451 uniqueTimes.insert(*times.begin()); 2452 } 2453 } 2454 2455 return uniqueTimes; 2456 } 2457 2458 QSet<int> fetchUniqueFrameTimes(KisNodeSP node, QSet<int> selectedTimes, bool filterActiveFrameID) 2459 { 2460 if (selectedTimes.isEmpty() || !node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id())) 2461 return selectedTimes; 2462 2463 // Convert a set of selected keyframe times into set of selected "frameIDs"... 2464 QSet<int> selectedFrameIDs = KisLayerUtils::fetchLayerRasterIDsAtTimes(node, selectedTimes); 2465 2466 if (filterActiveFrameID) { 2467 // Current frame was already filtered e.g. during filter preview in `KisFilterManager::apply`... 2468 // So let's remove it... 2469 const int currentActiveFrameID = KisLayerUtils::fetchLayerActiveRasterFrameID(node); 2470 selectedFrameIDs.remove(currentActiveFrameID); 2471 } 2472 2473 // Convert frameIDs to any arbitrary frame time associated with the frameID... 2474 QSet<int> uniqueFrameTimes = node->paintDevice()->framesInterface() ? KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs(node, selectedFrameIDs) : QSet<int>(); 2475 2476 return uniqueFrameTimes; 2477 } 2478 2479 }