Krita Source Code Documentation
Loading...
Searching...
No Matches
KisLayerUtils Namespace Reference

Namespaces

namespace  Private
 

Classes

struct  ActivateSelectionMask
 
struct  AddNewFrame
 
struct  CleanUpNodes
 
struct  ConvertToPaintLayerInfo
 
struct  CreateMergedLayer
 
struct  CreateMergedLayerMultiple
 
struct  DisableColorizeKeyStrokes
 
struct  DisableExtraCompositing
 
struct  DisableOnionSkins
 
struct  DisablePassThroughForHeadsOnly
 
struct  EphemeralCommandsWrapper
 
struct  FillSelectionMasks
 
struct  InitSplitAlphaSelectionMask
 
struct  InsertNode
 
struct  KeepMergedNodesSelected
 
class  KeepNodesSelectedCommand
 
class  KisSimpleUpdateCommand
 
struct  MergeDownInfo
 
struct  MergeDownInfoBase
 
struct  MergeLayers
 
struct  MergeLayersMultiple
 
struct  MergeMetaData
 
struct  MergeMultipleInfo
 
struct  MergeSelectionMasks
 
struct  RefreshDelayedUpdateLayers
 
struct  RefreshHiddenAreas
 
class  RemoveNodeHelper
 
struct  SelectGlobalSelectionMask
 
struct  SimpleAddNode
 
struct  SimpleRemoveLayers
 
struct  SplitAlphaCommand
 
struct  SplitAlphaToMaskInfo
 
struct  SwitchFrameCommand
 The SwitchFrameCommand struct Switches to frame with undo/redo support. More...
 
struct  UndoEphemeralCommands
 
struct  UploadProjectionToFrameCommand
 

Typedefs

typedef QSharedPointer< ConvertToPaintLayerInfoConvertToPaintLayerInfoSP
 
typedef QMap< int, QSet< KisNodeSP > > FrameJobs
 
typedef QSharedPointer< MergeDownInfoBaseMergeDownInfoBaseSP
 
typedef QSharedPointer< MergeDownInfoMergeDownInfoSP
 
typedef QSharedPointer< MergeMultipleInfoMergeMultipleInfoSP
 
typedef QSharedPointer< SplitAlphaToMaskInfoSplitAlphaToMaskInfoSP
 

Enumerations

enum  MergeFlag { None , SkipMergingFrames = 0x1 }
 

Functions

void addCopyOfNameTag (KisNodeSP node)
 
bool canChangeImageProfileInvisibly (KisImageSP image)
 
void changeImageDefaultProjectionColor (KisImageSP image, const KoColor &color)
 
bool checkIsChildOf (KisNodeSP node, const KisNodeList &parents)
 
bool checkIsCloneOf (KisNodeSP node, const KisNodeList &nodes)
 
template<typename T >
bool checkNodesDiffer (KisNodeList nodes, std::function< T(KisNodeSP)> checkerFunc)
 
std::future< KisNodeSPconvertToPaintLayer (KisImageSP image, KisNodeSP src)
 
int fetchLayerActiveRasterFrameID (KisNodeSP node)
 
KisTimeSpan fetchLayerActiveRasterFrameSpan (KisNodeSP node, const int time)
 
int fetchLayerActiveRasterFrameTime (KisNodeSP node)
 
QSet< int > fetchLayerFrames (KisNodeSP node)
 
QSet< int > fetchLayerFramesRecursive (KisNodeSP rootNode)
 
QSet< int > fetchLayerIdenticalRasterFrameTimes (KisNodeSP node, const int &frameTime)
 
QSet< int > fetchLayerRasterFrameTimesMatchingID (KisNodeSP node, const int frameID)
 
QSet< int > fetchLayerRasterIDsAtTimes (KisNodeSP node, const QSet< int > &times)
 
QSet< int > fetchLayerUniqueRasterTimesMatchingIDs (KisNodeSP node, QSet< int > &frameIDs)
 
void fetchSelectionMasks (KisNodeList mergedNodes, QVector< KisSelectionMaskSP > &selectionMasks)
 
QSet< int > fetchUniqueFrameTimes (KisNodeSP node, QSet< int > selectedTimes, bool filterActiveFrameID)
 
KisNodeList filterInvisibleNodes (const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter)
 
void filterMergeableNodes (KisNodeList &nodes, bool allowMasks)
 
QSet< int > filterTimesForOnlyRasterKeyedTimes (KisNodeSP node, const QSet< int > &times)
 
void filterUnlockedNodes (KisNodeList &nodes)
 
KisImageSP findImageByHierarchy (KisNodeSP node)
 
KisNodeSP findNodeByName (KisNodeSP root, const QString &name)
 
template<class T >
T * findNodeByType (KisNodeSP root)
 
KisNodeSP findNodeByUuid (KisNodeSP root, const QUuid &uuid)
 
QList< KisNodeSPfindNodesByName (KisNodeSP root, const QString &name, bool recursive, bool partialMatch)
 
KisNodeList findNodesWithProps (KisNodeSP root, const KoProperties &props, bool excludeRoot)
 
KisNodeSP findRoot (KisNodeSP node)
 
void flattenImage (KisImageSP image, KisNodeSP activeNode, MergeFlags flags)
 
void flattenLayer (KisImageSP image, KisLayerSP layer, MergeFlags flags)
 
void forceAllDelayedNodesUpdate (KisNodeSP root)
 
void forceAllHiddenOriginalsUpdate (KisNodeSP root)
 
bool hasDelayedNodeWithUpdates (KisNodeSP root)
 
void mergeDown (KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy *strategy, MergeFlags flags)
 
void mergeMultipleLayers (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, MergeFlags flags)
 
void mergeMultipleLayersImpl (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, bool flattenSingleLayer, const KUndo2MagicString &actionName, bool cleanupNodes=true, const QString layerName=QString(), MergeFlags flags=None)
 
void mergeMultipleNodes (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, MergeFlags flags)
 
void newLayerFromVisible (KisImageSP image, KisNodeSP putAfter, MergeFlags flags)
 
template<typename NodePointer , typename Functor >
void recursiveApplyNodes (NodePointer node, Functor func)
 
KisNodeSP recursiveFindNode (KisNodeSP node, std::function< bool(KisNodeSP)> func)
 
QRect recursiveTightNodeVisibleBounds (KisNodeSP rootNode)
 
void refreshHiddenAreaAsync (KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea)
 
KisNodeList sortAndFilterAnyMergeableNodesSafe (const KisNodeList &nodes, KisImageSP image)
 
KisNodeList sortAndFilterMergeableInternalNodes (KisNodeList nodes, bool allowMasks)
 
KisNodeList sortMergeableInternalNodes (KisNodeList nodes)
 
void sortMergeableNodes (KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes)
 
KisNodeList sortMergeableNodes (KisNodeSP root, KisNodeList nodes)
 
KRITAIMAGE_EXPORT void sortMergeableNodes (KisNodeSP root, QList< KisNodeSP > &inputNodes, QList< KisNodeSP > &outputNodes)
 
void splitAlphaToMask (KisImageSP image, KisNodeSP node, const QString &maskName)
 
void splitNonRemovableNodes (KisNodeList &nodesToRemove, KisNodeList &_nodesToHide)
 
bool tryMergeSelectionMasks (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter)
 
void updateFrameJobs (FrameJobs *jobs, KisNodeSP node)
 
void updateFrameJobsRecursive (FrameJobs *jobs, KisNodeSP rootNode)
 

Typedef Documentation

◆ ConvertToPaintLayerInfoSP

◆ FrameJobs

typedef QMap<int, QSet<KisNodeSP> > KisLayerUtils::FrameJobs

Definition at line 94 of file kis_layer_utils.h.

◆ MergeDownInfoBaseSP

◆ MergeDownInfoSP

◆ MergeMultipleInfoSP

◆ SplitAlphaToMaskInfoSP

Enumeration Type Documentation

◆ MergeFlag

Enumerator
None 
SkipMergingFrames 

Definition at line 31 of file kis_layer_utils.h.

31 {
32 None,
34 };

Function Documentation

◆ addCopyOfNameTag()

KRITAIMAGE_EXPORT void KisLayerUtils::addCopyOfNameTag ( KisNodeSP node)

Definition at line 1709 of file kis_layer_utils.cpp.

1710 {
1711 if (!KisImageConfig(true).renameDuplicatedLayers()) { return; }
1712
1713 const QString prefix = i18n("Copy of");
1714 QString newName = node->name();
1715 if (!newName.startsWith(prefix)) {
1716 newName = QString("%1 %2").arg(prefix).arg(newName);
1717 node->setName(newName);
1718 }
1719 }
void setName(const QString &name)
QString name() const

References KisBaseNode::name(), and KisBaseNode::setName().

◆ canChangeImageProfileInvisibly()

KRITAIMAGE_EXPORT bool KisLayerUtils::canChangeImageProfileInvisibly ( KisImageSP image)

Definition at line 2341 of file kis_layer_utils.cpp.

2342 {
2343 int numLayers = 0;
2344 bool hasNonNormalLayers = false;
2345 bool hasTransparentLayer = false;
2346
2347
2348 recursiveApplyNodes(image->root(),
2349 [&numLayers, &hasNonNormalLayers, &hasTransparentLayer, image] (KisNodeSP node) {
2350 if (!node->inherits("KisLayer")) return;
2351
2352 numLayers++;
2353
2354 if (node->exactBounds().isEmpty()) return;
2355
2356 // this is only an approximation! it is not exact!
2357 if (!hasTransparentLayer &&
2358 node->exactBounds() != image->bounds()) {
2359
2360 hasTransparentLayer = true;
2361 }
2362
2363 if (!hasNonNormalLayers &&
2364 node->compositeOpId() != COMPOSITE_OVER) {
2365
2366 hasNonNormalLayers = true;
2367 }
2368 });
2369
2370 return numLayers == 1 || (!hasNonNormalLayers && !hasTransparentLayer);
2371 }
const QString COMPOSITE_OVER
void recursiveApplyNodes(NodePointer node, Functor func)
const QString & compositeOpId() const

References COMPOSITE_OVER, KisBaseNode::compositeOpId(), recursiveApplyNodes(), and KisNodeFacade::root.

◆ changeImageDefaultProjectionColor()

KRITAIMAGE_EXPORT void KisLayerUtils::changeImageDefaultProjectionColor ( KisImageSP image,
const KoColor & color )

◆ checkIsChildOf()

KRITAIMAGE_EXPORT bool KisLayerUtils::checkIsChildOf ( KisNodeSP node,
const KisNodeList & parents )

Definition at line 1545 of file kis_layer_utils.cpp.

1546 {
1547 KisNodeList nodeParents;
1548
1549 KisNodeSP parent = node->parent();
1550 while (parent) {
1551 nodeParents << parent;
1552 parent = parent->parent();
1553 }
1554
1555 foreach(KisNodeSP perspectiveParent, parents) {
1556 if (nodeParents.contains(perspectiveParent)) {
1557 return true;
1558 }
1559 }
1560
1561 return false;
1562 }
KisNodeWSP parent
Definition kis_node.cpp:86

References KisNode::parent.

◆ checkIsCloneOf()

KRITAIMAGE_EXPORT bool KisLayerUtils::checkIsCloneOf ( KisNodeSP node,
const KisNodeList & nodes )

Returns true if: o node is a clone of some layer in nodes o node is a clone any child layer of any layer in nodes o node is a clone of a clone of a ..., that in the end points to any layer in nodes of their children.

Definition at line 1564 of file kis_layer_utils.cpp.

1565 {
1566 bool result = false;
1567
1568 KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
1569 if (clone) {
1570 KisNodeSP cloneSource = KisNodeSP(clone->copyFrom());
1571
1572 Q_FOREACH(KisNodeSP subtree, nodes) {
1573 result =
1574 recursiveFindNode(subtree,
1575 [cloneSource](KisNodeSP node) -> bool
1576 {
1577 return node == cloneSource;
1578 });
1579
1580 if (!result) {
1581 result = checkIsCloneOf(cloneSource, nodes);
1582 }
1583
1584 if (result) {
1585 break;
1586 }
1587 }
1588 }
1589
1590 return result;
1591 }
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
KisNodeSP recursiveFindNode(KisNodeSP node, std::function< bool(KisNodeSP)> func)
KisLayerSP copyFrom

References checkIsCloneOf(), KisCloneLayer::copyFrom, KisSharedPtr< T >::data(), and recursiveFindNode().

◆ checkNodesDiffer()

template<typename T >
bool KisLayerUtils::checkNodesDiffer ( KisNodeList nodes,
std::function< T(KisNodeSP)> checkerFunc )

Definition at line 214 of file kis_layer_utils.h.

215 {
216 bool valueDiffers = false;
217 bool initialized = false;
218 T currentValue = T();
219 Q_FOREACH (KisNodeSP node, nodes) {
220 if (!initialized) {
221 currentValue = checkerFunc(node);
222 initialized = true;
223 } else if (currentValue != checkerFunc(node)) {
224 valueDiffers = true;
225 break;
226 }
227 }
228 return valueDiffers;
229 }

◆ convertToPaintLayer()

KRITAIMAGE_EXPORT std::future< KisNodeSP > KisLayerUtils::convertToPaintLayer ( KisImageSP image,
KisNodeSP src )

Definition at line 2398 of file kis_layer_utils.cpp.

2399 {
2400 //Initialize all operation dependencies.
2401 ConvertToPaintLayerInfoSP info( new ConvertToPaintLayerInfo(image, src) );
2402
2403 if (!info->hasTargetNode())
2405
2406 KisImageSignalVector emitSignals;
2407 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Convert to a Paint Layer"));
2408
2409 applicator.applyCommand(new SimpleAddNode(info->image(), info->targetNode(), info->insertionParent(), info->insertionPutAfter()), KisStrokeJobData::BARRIER);
2410
2411 if (info->frames().count() > 0) {
2412 Q_FOREACH(const int& frame, info->frames()) {
2413 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, false, info->storage));
2414 applicator.applyCommand(new RefreshDelayedUpdateLayers(info->sourceNodes()), KisStrokeJobData::BARRIER);
2415 applicator.applyCommand(new RefreshHiddenAreas(info->image(), info->sourceNode()), KisStrokeJobData::BARRIER);
2416 applicator.applyCommand(new AddNewFrame(info->targetNode(), frame, info->sourceNode()), KisStrokeJobData::BARRIER);
2417 applicator.applyCommand(new UploadProjectionToFrameCommand(info->sourceNode(), info->targetNode(), frame));
2418 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, true, info->storage));
2419 }
2420 }
2421
2422 applicator.applyCommand(new SimpleRemoveLayers(info->toRemove(), info->image()));
2423
2424 applicator.end();
2425
2426 return kismpl::then(applicator.successfullyCompletedFuture(),
2427 [node = info->targetNode()] (std::future<bool> completed) {
2428 return completed.get() ? node : KisNodeSP();
2429 });
2430 }
auto then(std::future< T > &&future, Function &&func) -> std::future< decltype(func(std::move(future)))>
std::future< void > make_ready_future()
The SwitchFrameCommand struct Switches to frame with undo/redo support.

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisProcessingApplicator::end(), kundo2_i18n(), kismpl::make_ready_future(), KisProcessingApplicator::NONE, KisProcessingApplicator::successfullyCompletedFuture(), and kismpl::then().

◆ fetchLayerActiveRasterFrameID()

int KisLayerUtils::fetchLayerActiveRasterFrameID ( KisNodeSP node)

Definition at line 2434 of file kis_layer_utils.cpp.

2435 {
2437 KisPaintDeviceSP paintDevice = node->paintDevice();
2438 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2439
2440 if (!paintDevice->keyframeChannel()) {
2441 return -1;
2442 }
2443
2444 const int activeTime = paintDevice->keyframeChannel()->activeKeyframeTime();
2445 KisRasterKeyframeSP keyframe = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(activeTime);
2447
2448 return keyframe->frameID();
2449 }
KisKeyframeSP activeKeyframeAt(int time) const
int activeKeyframeTime(int time) const
Get the time of the active keyframe. Useful for snapping any time to that of the most recent keyframe...
KisRasterKeyframeChannel * keyframeChannel() const
The KisRasterKeyframe class is a concrete subclass of KisKeyframe that wraps a physical raster image ...
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
virtual KisPaintDeviceSP paintDevice() const =0

References KisKeyframeChannel::activeKeyframeAt(), KisKeyframeChannel::activeKeyframeTime(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerActiveRasterFrameSpan()

KRITAIMAGE_EXPORT KisTimeSpan KisLayerUtils::fetchLayerActiveRasterFrameSpan ( KisNodeSP node,
const int time )

Definition at line 2464 of file kis_layer_utils.cpp.

2465 {
2467 KisPaintDeviceSP paintDevice = node->paintDevice();
2469 if (!paintDevice->keyframeChannel()) {
2470 return KisTimeSpan::infinite(0);
2471 }
2472
2473 return paintDevice->keyframeChannel()->affectedFrames(time);
2474 }
virtual KisTimeSpan affectedFrames(int time) const
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
static KisTimeSpan infinite(int start)

References KisKeyframeChannel::affectedFrames(), KisTimeSpan::infinite(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerActiveRasterFrameTime()

KRITAIMAGE_EXPORT int KisLayerUtils::fetchLayerActiveRasterFrameTime ( KisNodeSP node)

Definition at line 2451 of file kis_layer_utils.cpp.

2452 {
2454 KisPaintDeviceSP paintDevice = node->paintDevice();
2455 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2456
2457 if (!paintDevice->keyframeChannel()) {
2458 return -1;
2459 }
2460
2461 return paintDevice->keyframeChannel()->activeKeyframeTime();
2462 }

References KisKeyframeChannel::activeKeyframeTime(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerFrames()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchLayerFrames ( KisNodeSP node)

Definition at line 1344 of file kis_layer_utils.cpp.

1344 {
1345 QSet<int> frames;
1346 Q_FOREACH(KisKeyframeChannel *channel, node->keyframeChannels()) {
1347 if (!channel) {
1348 continue;
1349 }
1350
1351 KisRasterKeyframeChannel *rasterChan = dynamic_cast<KisRasterKeyframeChannel*>(channel);
1352 if (rasterChan) {
1353 frames.unite(rasterChan->allKeyframeTimes());
1354 continue;
1355 }
1356
1357 KisScalarKeyframeChannel *scalarChan = dynamic_cast<KisScalarKeyframeChannel*>(channel);
1358 if (scalarChan) {
1359 const int initialKeyframe = scalarChan->firstKeyframeTime();
1360
1361 if (initialKeyframe == -1) {
1362 continue;
1363 }
1364
1365 const int lastKeyframe = scalarChan->lastKeyframeTime();
1366 KisTimeSpan currentSpan = scalarChan->identicalFrames(initialKeyframe);
1367 while (!currentSpan.isInfinite() && currentSpan.isValid() && currentSpan.start() < lastKeyframe) {
1368 frames.insert(currentSpan.start());
1369 currentSpan = scalarChan->identicalFrames(currentSpan.end() + 1);
1370 }
1371
1372 frames.insert(lastKeyframe);
1373 }
1374
1375 }
1376
1377 return frames;
1378 }
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisSca...
virtual KisTimeSpan identicalFrames(int time) const override
Get a span of times for which the channel gives identical results compared to frame at a given time....
int start() const
bool isInfinite() const
int end() const
bool isValid() const
QMap< QString, KisKeyframeChannel * > keyframeChannels

References KisKeyframeChannel::allKeyframeTimes(), KisTimeSpan::end(), KisKeyframeChannel::firstKeyframeTime(), KisScalarKeyframeChannel::identicalFrames(), KisTimeSpan::isInfinite(), KisTimeSpan::isValid(), KisBaseNode::keyframeChannels, KisKeyframeChannel::lastKeyframeTime(), and KisTimeSpan::start().

◆ fetchLayerFramesRecursive()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchLayerFramesRecursive ( KisNodeSP rootNode)

Definition at line 1380 of file kis_layer_utils.cpp.

1380 {
1381 if (!rootNode->visible()) return QSet<int>();
1382
1383 QSet<int> frames = fetchLayerFrames(rootNode);
1384
1385 KisNodeSP node = rootNode->firstChild();
1386 while(node) {
1387 frames |= fetchLayerFramesRecursive(node);
1388 node = node->nextSibling();
1389 }
1390
1391 return frames;
1392 }
QSet< int > fetchLayerFrames(KisNodeSP node)
QSet< int > fetchLayerFramesRecursive(KisNodeSP rootNode)
virtual bool visible(bool recursive=false) const
KisNodeSP firstChild() const
Definition kis_node.cpp:361
KisNodeSP nextSibling() const
Definition kis_node.cpp:408

References fetchLayerFrames(), fetchLayerFramesRecursive(), KisNode::firstChild(), KisNode::nextSibling(), and KisBaseNode::visible().

◆ fetchLayerIdenticalRasterFrameTimes()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchLayerIdenticalRasterFrameTimes ( KisNodeSP node,
const int & frameTime )

Definition at line 2476 of file kis_layer_utils.cpp.

2477 {
2478 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2479 KisPaintDeviceSP paintDevice = node->paintDevice();
2480 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2481 if (!paintDevice->keyframeChannel()) {
2482 return QSet<int>();
2483 }
2484
2485 return paintDevice->keyframeChannel()->clonesOf(node.data(), frameTime);
2486 }

References KisRasterKeyframeChannel::clonesOf(), KisSharedPtr< T >::data(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerRasterFrameTimesMatchingID()

QSet< int > KisLayerUtils::fetchLayerRasterFrameTimesMatchingID ( KisNodeSP node,
const int frameID )

Definition at line 2489 of file kis_layer_utils.cpp.

2489 {
2490 KIS_ASSERT(node);
2491 KisRasterKeyframeChannel* rasterChannel = dynamic_cast<KisRasterKeyframeChannel*>(node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false));
2492
2493 if (!rasterChannel) {
2494 return QSet<int>();
2495 }
2496
2497 return rasterChannel->timesForFrameID(frameID);
2498 }
static const KoID Raster
QSet< int > timesForFrameID(int frameID) const
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
KisKeyframeChannel * getKeyframeChannel(const QString &id, bool create)

References KisBaseNode::getKeyframeChannel(), KIS_ASSERT, KisKeyframeChannel::Raster, and KisRasterKeyframeChannel::timesForFrameID().

◆ fetchLayerRasterIDsAtTimes()

QSet< int > KisLayerUtils::fetchLayerRasterIDsAtTimes ( KisNodeSP node,
const QSet< int > & times )

Definition at line 2500 of file kis_layer_utils.cpp.

2501 {
2502 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2503 KisPaintDeviceSP paintDevice = node->paintDevice();
2504 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2505 if (!paintDevice->keyframeChannel()) {
2506 return QSet<int>();
2507 }
2508
2509 QSet<int> frameIDs;
2510
2511 Q_FOREACH( const int& frame, times ) {
2513 frameIDs << raster->frameID();
2514 }
2515
2516 return frameIDs;
2517 }

References KisKeyframeChannel::activeKeyframeAt(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerUniqueRasterTimesMatchingIDs()

QSet< int > KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs ( KisNodeSP node,
QSet< int > & frameIDs )

Definition at line 2531 of file kis_layer_utils.cpp.

2532 {
2533 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2534 KisPaintDeviceSP paintDevice = node->paintDevice();
2535 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2536 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice->framesInterface(), QSet<int>());
2537
2538 QSet<int> uniqueTimes;
2539
2540 Q_FOREACH( const int& id, frameIDs) {
2541 QSet<int> times = fetchLayerRasterFrameTimesMatchingID(node, id);
2542 if (times.count() > 0) {
2543 uniqueTimes.insert(*times.begin());
2544 }
2545 }
2546
2547 return uniqueTimes;
2548 }
KisPaintDeviceFramesInterface * framesInterface()
QSet< int > fetchLayerRasterFrameTimesMatchingID(KisNodeSP node, const int frameID)

References fetchLayerRasterFrameTimesMatchingID(), KisPaintDevice::framesInterface(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchSelectionMasks()

void KisLayerUtils::fetchSelectionMasks ( KisNodeList mergedNodes,
QVector< KisSelectionMaskSP > & selectionMasks )

Definition at line 66 of file kis_layer_utils.cpp.

67 {
68 foreach (KisNodeSP node, mergedNodes) {
69
70 Q_FOREACH(KisNodeSP child, node->childNodes(QStringList("KisSelectionMask"), KoProperties())) {
71
72 KisSelectionMaskSP mask = qobject_cast<KisSelectionMask*>(child.data());
73 if (mask) {
74 selectionMasks.append(mask);
75 }
76 }
77 }
78 }
QList< KisNodeSP > childNodes(const QStringList &nodeTypes, const KoProperties &properties) const
Definition kis_node.cpp:439

References KisNode::childNodes(), and KisSharedPtr< T >::data().

◆ fetchUniqueFrameTimes()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchUniqueFrameTimes ( KisNodeSP node,
QSet< int > selectedTimes,
bool filterActiveFrameID )

Definition at line 2550 of file kis_layer_utils.cpp.

2551 {
2552 if (selectedTimes.isEmpty() || !node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id()))
2553 return selectedTimes;
2554
2555 // Convert a set of selected keyframe times into set of selected "frameIDs"...
2556 QSet<int> selectedFrameIDs = KisLayerUtils::fetchLayerRasterIDsAtTimes(node, selectedTimes);
2557
2558 if (filterActiveFrameID) {
2559 // Current frame was already filtered e.g. during filter preview in `KisFilterManager::apply`...
2560 // So let's remove it...
2561 const int currentActiveFrameID = KisLayerUtils::fetchLayerActiveRasterFrameID(node);
2562 selectedFrameIDs.remove(currentActiveFrameID);
2563 }
2564
2565 // Convert frameIDs to any arbitrary frame time associated with the frameID...
2566 QSet<int> uniqueFrameTimes = node->paintDevice()->framesInterface() ? KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs(node, selectedFrameIDs) : QSet<int>();
2567
2568 return uniqueFrameTimes;
2569 }
QString id() const
Definition KoID.cpp:63
int fetchLayerActiveRasterFrameID(KisNodeSP node)
QSet< int > fetchLayerUniqueRasterTimesMatchingIDs(KisNodeSP node, QSet< int > &frameIDs)
QSet< int > fetchLayerRasterIDsAtTimes(KisNodeSP node, const QSet< int > &times)
virtual bool supportsKeyframeChannel(const QString &id)

References fetchLayerActiveRasterFrameID(), fetchLayerRasterIDsAtTimes(), fetchLayerUniqueRasterTimesMatchingIDs(), KisPaintDevice::framesInterface(), KoID::id(), KisBaseNode::paintDevice(), KisKeyframeChannel::Raster, and KisBaseNode::supportsKeyframeChannel().

◆ filterInvisibleNodes()

KisNodeList KisLayerUtils::filterInvisibleNodes ( const KisNodeList & nodes,
KisNodeList * invisibleNodes,
KisNodeSP * putAfter )

When a layer is invisible and user-locked we should just skip it and do neither merge nor remove it.

Definition at line 1738 of file kis_layer_utils.cpp.

1739 {
1740 KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; }
1741 KIS_ASSERT_RECOVER(putAfter) { return nodes; }
1742
1743 KisNodeList visibleNodes;
1744 int putAfterIndex = -1;
1745
1746 Q_FOREACH(KisNodeSP node, nodes) {
1747 if (node->visible()) {
1748 visibleNodes << node;
1749 } else if (node->userLocked()) {
1754 } else {
1755 *invisibleNodes << node;
1756
1757 if (node == *putAfter) {
1758 putAfterIndex = visibleNodes.size() - 1;
1759 }
1760 }
1761 }
1762
1763 if (!visibleNodes.isEmpty() && putAfterIndex >= 0) {
1764 putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1);
1765 *putAfter = visibleNodes[putAfterIndex];
1766 }
1767
1768 return visibleNodes;
1769 }
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
bool userLocked() const

References KIS_ASSERT_RECOVER, KisBaseNode::userLocked(), and KisBaseNode::visible().

◆ filterMergeableNodes()

KRITAIMAGE_EXPORT void KisLayerUtils::filterMergeableNodes ( KisNodeList & nodes,
bool allowMasks )

Definition at line 1593 of file kis_layer_utils.cpp.

1594 {
1595 KisNodeList::iterator it = nodes.begin();
1596
1597 while (it != nodes.end()) {
1598 if ((!allowMasks && !qobject_cast<KisLayer*>(it->data())) ||
1599 checkIsChildOf(*it, nodes)) {
1600 //qDebug() << "Skipping node" << ppVar((*it)->name());
1601 it = nodes.erase(it);
1602 } else {
1603 ++it;
1604 }
1605 }
1606 }
bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents)

References checkIsChildOf().

◆ filterTimesForOnlyRasterKeyedTimes()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::filterTimesForOnlyRasterKeyedTimes ( KisNodeSP node,
const QSet< int > & times )

Definition at line 2519 of file kis_layer_utils.cpp.

2520 {
2522 KisPaintDeviceSP paintDevice = node->paintDevice();
2523 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, times);
2524 if (!paintDevice->keyframeChannel()) {
2525 return times;
2526 }
2527
2528 return paintDevice->keyframeChannel()->allKeyframeTimes().intersect(times);
2529 }

References KisKeyframeChannel::allKeyframeTimes(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ filterUnlockedNodes()

KRITAIMAGE_EXPORT void KisLayerUtils::filterUnlockedNodes ( KisNodeList & nodes)

Definition at line 1771 of file kis_layer_utils.cpp.

1772 {
1773 KisNodeList::iterator it = nodes.begin();
1774
1775 while (it != nodes.end()) {
1776 if ((*it)->userLocked()) {
1777 it = nodes.erase(it);
1778 } else {
1779 ++it;
1780 }
1781 }
1782 }

◆ findImageByHierarchy()

KRITAIMAGE_EXPORT KisImageSP KisLayerUtils::findImageByHierarchy ( KisNodeSP node)

Definition at line 2263 of file kis_layer_utils.cpp.

2264 {
2265 while (node) {
2266 const KisLayer *layer = dynamic_cast<const KisLayer*>(node.data());
2267 if (layer) {
2268 return layer->image();
2269 }
2270
2271 node = node->parent();
2272 }
2273
2274 return 0;
2275 }
KisImageWSP image

References KisSharedPtr< T >::data(), KisBaseNode::image, and KisNode::parent.

◆ findNodeByName()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findNodeByName ( KisNodeSP root,
const QString & name )

Definition at line 2220 of file kis_layer_utils.cpp.

2221 {
2222 return recursiveFindNode(root,
2223 [name] (KisNodeSP node) {
2224 return node->name() == name;
2225 });
2226 }

References KisBaseNode::name(), and recursiveFindNode().

◆ findNodeByType()

template<class T >
T * KisLayerUtils::findNodeByType ( KisNodeSP root)

Definition at line 267 of file kis_layer_utils.h.

267 {
268 return dynamic_cast<T*>(recursiveFindNode(root, [] (KisNodeSP node) {
269 return bool(dynamic_cast<T*>(node.data()));
270 }).data());
271 }

References KisSharedPtr< T >::data(), and recursiveFindNode().

◆ findNodeByUuid()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findNodeByUuid ( KisNodeSP root,
const QUuid & uuid )

Recursively searches for a node with specified Uuid

Definition at line 2194 of file kis_layer_utils.cpp.

2195 {
2196 return recursiveFindNode(root,
2197 [uuid] (KisNodeSP node) {
2198 return node->uuid() == uuid;
2199 });
2200 }
QUuid uuid() const

References recursiveFindNode(), and KisBaseNode::uuid().

◆ findNodesByName()

KRITAIMAGE_EXPORT QList< KisNodeSP > KisLayerUtils::findNodesByName ( KisNodeSP root,
const QString & name,
bool recursive,
bool partialMatch )

Definition at line 2202 of file kis_layer_utils.cpp.

2203 {
2204 KisNodeList nodeList;
2205 KisNodeSP child = root->firstChild();
2206
2207 while (child) {
2208 if (name.isEmpty() || (!partialMatch && child->name() == name) || (partialMatch && child->name().contains(name, Qt::CaseInsensitive))) {
2209 nodeList << child;
2210 }
2211 if (recursive && child->childCount() > 0) {
2212 nodeList << findNodesByName(child, name, recursive, partialMatch);
2213 }
2214 child = child->nextSibling();
2215 }
2216
2217 return nodeList;
2218 }
quint32 childCount() const
Definition kis_node.cpp:414

References KisNode::childCount(), findNodesByName(), KisNode::firstChild(), KisBaseNode::name(), and KisNode::nextSibling().

◆ findNodesWithProps()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::findNodesWithProps ( KisNodeSP root,
const KoProperties & props,
bool excludeRoot )

Definition at line 1721 of file kis_layer_utils.cpp.

1722 {
1723 KisNodeList nodes;
1724
1725 if ((!excludeRoot || root->parent()) && root->check(props)) {
1726 nodes << root;
1727 }
1728
1729 KisNodeSP node = root->firstChild();
1730 while (node) {
1731 nodes += findNodesWithProps(node, props, excludeRoot);
1732 node = node->nextSibling();
1733 }
1734
1735 return nodes;
1736 }
bool check(const KoProperties &properties) const

References KisBaseNode::check(), findNodesWithProps(), KisNode::firstChild(), KisNode::nextSibling(), and KisNode::parent.

◆ findRoot()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findRoot ( KisNodeSP node)

Definition at line 2331 of file kis_layer_utils.cpp.

2332 {
2333 if (!node) return node;
2334
2335 while (node->parent()) {
2336 node = node->parent();
2337 }
2338 return node;
2339 }

References KisNode::parent.

◆ flattenImage()

KRITAIMAGE_EXPORT void KisLayerUtils::flattenImage ( KisImageSP image,
KisNodeSP activeNode,
MergeFlags flags )

Definition at line 2144 of file kis_layer_utils.cpp.

2145 {
2146 if (!activeNode) {
2147 activeNode = image->root()->lastChild();
2148 }
2149
2150
2151 KisNodeList mergedNodes;
2152 mergedNodes << image->root();
2153
2154 mergeMultipleLayersImpl(image, mergedNodes, activeNode,
2155 true, kundo2_i18n("Flatten Image"),
2156 true, QString(),
2157 flags);
2158 }
KisNodeSP lastChild() const
Definition kis_node.cpp:367

References kundo2_i18n(), KisNode::lastChild(), mergeMultipleLayersImpl(), and KisNodeFacade::root.

◆ flattenLayer()

KRITAIMAGE_EXPORT void KisLayerUtils::flattenLayer ( KisImageSP image,
KisLayerSP layer,
MergeFlags flags )

Definition at line 2130 of file kis_layer_utils.cpp.

2131 {
2132 if (!layer->childCount() && !layer->layerStyle())
2133 return;
2134
2135 KisNodeList mergedNodes;
2136 mergedNodes << layer;
2137
2138 mergeMultipleLayersImpl(image, mergedNodes, layer,
2139 true, kundo2_i18n("Flatten Layer"),
2140 true, QString(),
2141 flags);
2142 }
void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, bool flattenSingleLayer, const KUndo2MagicString &actionName, bool cleanupNodes=true, const QString layerName=QString(), MergeFlags flags=None)
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171

References KisNode::childCount(), kundo2_i18n(), KisLayer::layerStyle, and mergeMultipleLayersImpl().

◆ forceAllDelayedNodesUpdate()

KRITAIMAGE_EXPORT void KisLayerUtils::forceAllDelayedNodesUpdate ( KisNodeSP root)

Definition at line 2228 of file kis_layer_utils.cpp.

2229 {
2231 [] (KisNodeSP node) {
2232 KisDelayedUpdateNodeInterface *delayedUpdate =
2233 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2234 if (delayedUpdate) {
2235 delayedUpdate->forceUpdateTimedNode();
2236 }
2237 });
2238 }
The KisDelayedUpdateNodeInterface class is an interface for nodes that delay their real updates with ...
virtual void forceUpdateTimedNode()=0
forceUpdateTimedNode forces the node to regenerate its project. The update might be asynchronous,...

References KisSharedPtr< T >::data(), KisDelayedUpdateNodeInterface::forceUpdateTimedNode(), and recursiveApplyNodes().

◆ forceAllHiddenOriginalsUpdate()

KRITAIMAGE_EXPORT void KisLayerUtils::forceAllHiddenOriginalsUpdate ( KisNodeSP root)

Definition at line 2251 of file kis_layer_utils.cpp.

2252 {
2254 [] (KisNodeSP node) {
2255 KisCroppedOriginalLayerInterface *croppedUpdate =
2256 dynamic_cast<KisCroppedOriginalLayerInterface*>(node.data());
2257 if (croppedUpdate) {
2258 croppedUpdate->forceUpdateHiddenAreaOnOriginal();
2259 }
2260 });
2261 }
virtual void forceUpdateHiddenAreaOnOriginal()=0

References KisSharedPtr< T >::data(), KisCroppedOriginalLayerInterface::forceUpdateHiddenAreaOnOriginal(), and recursiveApplyNodes().

◆ hasDelayedNodeWithUpdates()

KRITAIMAGE_EXPORT bool KisLayerUtils::hasDelayedNodeWithUpdates ( KisNodeSP root)

Definition at line 2240 of file kis_layer_utils.cpp.

2241 {
2242 return recursiveFindNode(root,
2243 [] (KisNodeSP node) {
2244 KisDelayedUpdateNodeInterface *delayedUpdate =
2245 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2246
2247 return delayedUpdate ? delayedUpdate->hasPendingTimedUpdates() : false;
2248 });
2249 }
virtual bool hasPendingTimedUpdates() const =0

References KisSharedPtr< T >::data(), KisDelayedUpdateNodeInterface::hasPendingTimedUpdates(), and recursiveFindNode().

◆ mergeDown()

KRITAIMAGE_EXPORT void KisLayerUtils::mergeDown ( KisImageSP image,
KisLayerSP layer,
const KisMetaData::MergeStrategy * strategy,
MergeFlags flags )
See also
a comment in mergeMultipleLayersImpl()

Save the original time before we start switching is with asynchronous SwitchFrameCommand.

When switching frames we need to update the entire image, not only the new extent of the layer, hence we pass refresh_entire_image to the command to make sure that the entire image bounds rect is added to the update rect

If source layer is not animated, then just merge that into the current frame to avoid unintentional destruction of the animation on the layer below. To merge the source into all the frames, just make the source animated.

See https://bugs.kde.org/show_bug.cgi?id=475550

Definition at line 1420 of file kis_layer_utils.cpp.

1421 {
1422 if (!layer->prevSibling()) return;
1423
1424 // XXX: this breaks if we allow free mixing of masks and layers
1425 KisLayerSP prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
1426
1427 while (prevLayer && prevLayer->isFakeNode()) {
1428 prevLayer = qobject_cast<KisLayer*>(prevLayer->prevSibling().data());
1429 }
1430
1431 if (!prevLayer) return;
1432
1433 if (!layer->visible() && !prevLayer->visible()) {
1434 return;
1435 }
1436
1437 KisImageSignalVector emitSignals;
1438 KisProcessingApplicator applicator(image, 0,
1440 emitSignals,
1441 kundo2_i18n("Merge Down"));
1442
1443 if (layer->visible() && prevLayer->visible()) {
1444 MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer, flags));
1445
1446 // disable key strokes on all colorize masks, all onion skins on
1447 // paint layers and wait until update is finished with a barrier
1448 applicator.applyCommand(new DisableColorizeKeyStrokes(info));
1449 applicator.applyCommand(new DisableOnionSkins(info));
1450 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1451
1452 applicator.applyCommand(new KeepMergedNodesSelected(info, false));
1453 applicator.applyCommand(new FillSelectionMasks(info));
1454 applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER);
1455
1456 // NOTE: shape layer may have emitted spontaneous jobs during layer creation,
1457 // wait for them to complete!
1458 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1459 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1460
1461 // in two-layer mode we disable pass through only when the destination layer
1462 // is not a group layer
1463 applicator.applyCommand(new DisablePassThroughForHeadsOnly(info, true));
1464 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1465
1466 if (info->frames.size() > 0) {
1471 const int currentTimeOnStart = info->image->animationInterface()->currentTime();
1472
1473 foreach (int frame, info->frames) {
1474 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1475
1476 applicator.applyCommand(new AddNewFrame(info, frame));
1483 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1484 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1485
1494 const bool skipMergingSourceLayer = !layer->isAnimated() &&
1495 frame != currentTimeOnStart;
1496
1497 applicator.applyCommand(new MergeLayers(info, skipMergingSourceLayer), KisStrokeJobData::BARRIER);
1498
1499 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage), KisStrokeJobData::BARRIER);
1500 }
1501 } else {
1502 applicator.applyCommand(new RefreshHiddenAreas(info));
1503 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1504 applicator.applyCommand(new MergeLayers(info, false), KisStrokeJobData::BARRIER);
1505 }
1506
1507 applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1508 applicator.applyCommand(new CleanUpNodes(info, layer),
1511 applicator.applyCommand(new KeepMergedNodesSelected(info, true));
1512 } else if (layer->visible()) {
1513 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1514 layer, KisNodeSP(),
1515 image, false));
1516
1517 applicator.applyCommand(
1518 new SimpleRemoveLayers(KisNodeList() << prevLayer,
1519 image),
1522
1523 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1524 KisNodeSP(), layer,
1525 image, true));
1526 } else if (prevLayer->visible()) {
1527 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1528 layer, KisNodeSP(),
1529 image, false));
1530
1531 applicator.applyCommand(
1532 new SimpleRemoveLayers(KisNodeList() << layer,
1533 image),
1536
1537 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1538 KisNodeSP(), prevLayer,
1539 image, true));
1540 }
1541
1542 applicator.end();
1543 }
QList< KisNodeSP > KisNodeList
Definition kis_types.h:264
QSharedPointer< MergeDownInfo > MergeDownInfoSP
bool isAnimated() const
virtual bool isFakeNode() const
KisNodeSP prevSibling() const
Definition kis_node.cpp:402

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisSharedPtr< T >::data(), KisProcessingApplicator::end(), KisStrokeJobData::EXCLUSIVE, KisBaseNode::isAnimated(), KisBaseNode::isFakeNode(), kundo2_i18n(), KisProcessingApplicator::NONE, KisNode::prevSibling(), KisLayerUtils::RefreshHiddenAreas::refresh_entire_image, KisStrokeJobData::SEQUENTIAL, and KisBaseNode::visible().

◆ mergeMultipleLayers()

KRITAIMAGE_EXPORT void KisLayerUtils::mergeMultipleLayers ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter,
MergeFlags flags )

Definition at line 2014 of file kis_layer_utils.cpp.

2015 {
2016 mergeMultipleLayersImpl(image, mergedNodes, putAfter,
2017 false, kundo2_i18n("Merge Selected Nodes"),
2018 true, QString(),
2019 flags);
2020 }

References kundo2_i18n(), and mergeMultipleLayersImpl().

◆ mergeMultipleLayersImpl()

void KisLayerUtils::mergeMultipleLayersImpl ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter,
bool flattenSingleLayer,
const KUndo2MagicString & actionName,
bool cleanupNodes = true,
const QString layerName = QString(),
MergeFlags flags = None )

There might be two approaches for merging multiple layers:

1) Consider the selected nodes as a distinct "group" and merge them as if they were isolated from the rest of the image. The key point of this approach is that the look of the image will change, when merging "weird" layers, like adjustment layers or layers with non-normal blending mode.

2) Merge layers in a way to keep the look of the image as unchanged as possible. With this approach one uses a few heuristics:

  • when merging multiple layers with non-normal (but equal) blending mode, first merge these layers together using Normal blending mode, then set blending mode of the result to the original blending mode
  • when merging multiple layers with different blending modes or layer styles, they are first rasterized, and then laid over each other with their own composite op. The blending mode of the final layer is set to Normal, so the user could clearly see that he should choose the correct blending mode.

Krita uses the second approach: after merge operation, the image should look as if nothing has happened (if it is technically possible).

We have reached the root of the layer hierarchy and didn't manage to find a node that was editable enough for putting our merged result into it. That shouldn't happen in normal circumstances, unless the user chose to make the root layer visible and lock it manually.

When switching frames we need to update the entire image, not only the new extent of the layer, hence we pass refresh_entire_image to the command to make sure that the entire image bounds rect is added to the update rect

Definition at line 1871 of file kis_layer_utils.cpp.

1875 {
1876 if (!putAfter) {
1877 putAfter = mergedNodes.first();
1878 }
1879
1880 filterMergeableNodes(mergedNodes);
1881 {
1882 KisNodeList tempNodes;
1883 std::swap(mergedNodes, tempNodes);
1884 sortMergeableNodes(image->root(), tempNodes, mergedNodes);
1885 }
1886
1887 if (mergedNodes.size() <= 1 &&
1888 (!flattenSingleLayer && mergedNodes.size() == 1)) return;
1889
1890 KisImageSignalVector emitSignals;
1891 emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes);
1892
1893
1894
1895 KisNodeList originalNodes = mergedNodes;
1896 KisNodeList invisibleNodes;
1897 mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter);
1898
1899 if (mergedNodes.isEmpty()) return;
1900
1901
1902 // make sure we don't add the new layer into a locked group
1904 while (putAfter->parent() && !putAfter->parent()->isEditable()) {
1905 putAfter = putAfter->parent();
1906 }
1907
1915 if (!putAfter->parent()) {
1916 return;
1917 }
1918
1919 KisProcessingApplicator applicator(image, 0,
1921 emitSignals,
1922 actionName);
1923
1924
1925 if (!invisibleNodes.isEmpty() && cleanupNodes) {
1926
1927 /* If the putAfter node is invisible,
1928 * we should instead pick one of the nodes
1929 * to be merged to avoid a null putAfter
1930 * after we remove all invisible layers from
1931 * the image.
1932 * (The assumption is that putAfter is among
1933 * the layers to merge, so if it's invisible,
1934 * it's going to be removed)
1935 */
1936 if (!putAfter->visible()){
1937 putAfter = mergedNodes.first();
1938 }
1939
1940 applicator.applyCommand(
1941 new SimpleRemoveLayers(invisibleNodes,
1942 image),
1945 }
1946
1947 if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) {
1948 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes, flags));
1949
1950 // disable key strokes on all colorize masks, all onion skins on
1951 // paint layers and wait until update is finished with a barrier
1952 //
1953 // when doing "new layer from visible" we should undo these changes
1954 // before the action stops, because the source layers are **not**
1955 // removed as a result of this action
1956 applicator.applyCommand(
1957 new EphemeralCommandsWrapper(info,
1958 {
1959 new DisableColorizeKeyStrokes(info),
1960 new DisableOnionSkins(info),
1961 new DisablePassThroughForHeadsOnly(info)
1962 },
1963 cleanupNodes));
1964 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1965
1966 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false));
1967 applicator.applyCommand(new FillSelectionMasks(info));
1968 applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER);
1969 applicator.applyCommand(new EphemeralCommandsWrapper(info, { new DisableExtraCompositing(info) } , cleanupNodes));
1970 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1971
1972 if (!info->frames.isEmpty()) {
1973 foreach (int frame, info->frames) {
1974 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1975
1976 applicator.applyCommand(new AddNewFrame(info, frame));
1983 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1984 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1985 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
1986
1987 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
1988 }
1989 } else {
1990 applicator.applyCommand(new RefreshHiddenAreas(info));
1991 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1992 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
1993 }
1994
1995 //applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1996 if (cleanupNodes){
1997 applicator.applyCommand(new CleanUpNodes(info, putAfter, flattenSingleLayer),
2000 } else {
2001 applicator.applyCommand(new UndoEphemeralCommands(info));
2002 applicator.applyCommand(new InsertNode(info, putAfter),
2005 }
2006
2007 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true));
2008 }
2009
2010 applicator.end();
2011
2012 }
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
KisNodeList filterInvisibleNodes(const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter)
QSharedPointer< MergeMultipleInfo > MergeMultipleInfoSP
bool isEditable(bool checkVisibility=true) const

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisProcessingApplicator::end(), KisStrokeJobData::EXCLUSIVE, filterInvisibleNodes(), filterMergeableNodes(), KisBaseNode::isEditable(), KIS_SAFE_ASSERT_RECOVER_RETURN, KisProcessingApplicator::NONE, KisNode::parent, KisLayerUtils::RefreshHiddenAreas::refresh_entire_image, KisNodeFacade::root, KisStrokeJobData::SEQUENTIAL, sortMergeableNodes(), and KisBaseNode::visible().

◆ mergeMultipleNodes()

KRITAIMAGE_EXPORT void KisLayerUtils::mergeMultipleNodes ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter,
MergeFlags flags = None )

Same as mergeMultipleLayers() but tries to merge masks with tryMergeSelectionMasks() first.

Definition at line 2022 of file kis_layer_utils.cpp.

2023 {
2024 if (!tryMergeSelectionMasks(image, mergedNodes, putAfter)) {
2025 mergeMultipleLayers(image, mergedNodes, putAfter, flags);
2026 }
2027 }
bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image)
void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, MergeFlags flags)

References mergeMultipleLayers(), and tryMergeSelectionMasks().

◆ newLayerFromVisible()

KRITAIMAGE_EXPORT void KisLayerUtils::newLayerFromVisible ( KisImageSP image,
KisNodeSP putAfter,
MergeFlags flags )

Definition at line 2029 of file kis_layer_utils.cpp.

2030 {
2031 KisNodeList mergedNodes;
2032 mergedNodes << image->root();
2033
2034 mergeMultipleLayersImpl(image, mergedNodes, putAfter,
2035 true, kundo2_i18n("New From Visible"),
2036 false, i18nc("New layer created from all the visible layers", "Visible"),
2037 flags);
2038 }

References kundo2_i18n(), mergeMultipleLayersImpl(), and KisNodeFacade::root.

◆ recursiveApplyNodes()

template<typename NodePointer , typename Functor >
void KisLayerUtils::recursiveApplyNodes ( NodePointer node,
Functor func )

Applies func to node and all its children recursively

Definition at line 235 of file kis_layer_utils.h.

236 {
237 func(node);
238
239 node = node->firstChild();
240 while (node) {
241 recursiveApplyNodes(node, func);
242 node = node->nextSibling();
243 }
244 }

References recursiveApplyNodes().

◆ recursiveFindNode()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::recursiveFindNode ( KisNodeSP node,
std::function< bool(KisNodeSP)> func )

Walks through node and all its children recursively until func returns true. When func returns true, the node is considered to be found, the search is stopped and the found node is returned to the caller.

Definition at line 2176 of file kis_layer_utils.cpp.

2177 {
2178 if (func(node)) {
2179 return node;
2180 }
2181
2182 node = node->firstChild();
2183 while (node) {
2184 KisNodeSP resultNode = recursiveFindNode(node, func);
2185 if (resultNode) {
2186 return resultNode;
2187 }
2188 node = node->nextSibling();
2189 }
2190
2191 return 0;
2192 }

References KisNode::firstChild(), KisNode::nextSibling(), and recursiveFindNode().

◆ recursiveTightNodeVisibleBounds()

KRITAIMAGE_EXPORT QRect KisLayerUtils::recursiveTightNodeVisibleBounds ( KisNodeSP rootNode)

Definition at line 2322 of file kis_layer_utils.cpp.

2323 {
2324 QRect exactBounds;
2325 recursiveApplyNodes(rootNode, [&exactBounds] (KisNodeSP node) {
2326 exactBounds |= node->projectionPlane()->tightUserVisibleBounds();
2327 });
2328 return exactBounds;
2329 }
virtual KisAbstractProjectionPlaneSP projectionPlane() const
Definition kis_node.cpp:240

References KisNode::projectionPlane(), and recursiveApplyNodes().

◆ refreshHiddenAreaAsync()

KRITAIMAGE_EXPORT void KisLayerUtils::refreshHiddenAreaAsync ( KisImageSP image,
KisNodeSP rootNode,
const QRect & preparedArea )

Definition at line 2318 of file kis_layer_utils.cpp.

2318 {
2319 Private::refreshHiddenAreaAsync(image, rootNode, preparedArea, QRect());
2320 }

References KisLayerUtils::Private::refreshHiddenAreaAsync().

◆ sortAndFilterAnyMergeableNodesSafe()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortAndFilterAnyMergeableNodesSafe ( const KisNodeList & nodes,
KisImageSP image )

Definition at line 1685 of file kis_layer_utils.cpp.

1685 {
1686 KisNodeList filteredNodes = nodes;
1687 KisNodeList sortedNodes;
1688
1689 KisLayerUtils::filterMergeableNodes(filteredNodes, true);
1690
1691 bool haveExternalNodes = false;
1692 Q_FOREACH (KisNodeSP node, nodes) {
1693 if (node->graphListener() != image->root()->graphListener()) {
1694 haveExternalNodes = true;
1695 break;
1696 }
1697 }
1698
1699 if (!haveExternalNodes) {
1700 KisLayerUtils::sortMergeableNodes(image->root(), filteredNodes, sortedNodes);
1701 } else {
1702 sortedNodes = filteredNodes;
1703 }
1704
1705 return sortedNodes;
1706 }
void sortMergeableNodes(KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes)
void filterMergeableNodes(KisNodeList &nodes, bool allowMasks)
KisNodeGraphListener * graphListener
Definition kis_node.cpp:87

References filterMergeableNodes(), KisNode::graphListener, KisNodeFacade::root, and sortMergeableNodes().

◆ sortAndFilterMergeableInternalNodes()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortAndFilterMergeableInternalNodes ( KisNodeList nodes,
bool allowMasks )

Definition at line 1640 of file kis_layer_utils.cpp.

1641 {
1642 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1643
1644 KisNodeSP root;
1645 Q_FOREACH(KisNodeSP node, nodes) {
1646 KisNodeSP localRoot = node;
1647 while (localRoot->parent()) {
1648 localRoot = localRoot->parent();
1649 }
1650
1651 if (!root) {
1652 root = localRoot;
1653 }
1654 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1655 }
1656
1657 KisNodeList result;
1658 sortMergeableNodes(root, nodes, result);
1659 filterMergeableNodes(result, allowMasks);
1660 return result;
1661 }
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126

References filterMergeableNodes(), KIS_SAFE_ASSERT_RECOVER, KisNode::parent, and sortMergeableNodes().

◆ sortMergeableInternalNodes()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortMergeableInternalNodes ( KisNodeList nodes)

Definition at line 1663 of file kis_layer_utils.cpp.

1664 {
1665 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1666
1667 KisNodeSP root;
1668 Q_FOREACH(KisNodeSP node, nodes) {
1669 KisNodeSP localRoot = node;
1670 while (localRoot->parent()) {
1671 localRoot = localRoot->parent();
1672 }
1673
1674 if (!root) {
1675 root = localRoot;
1676 }
1677 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1678 }
1679
1680 KisNodeList result;
1681 sortMergeableNodes(root, nodes, result);
1682 return result;
1683 }

References KIS_SAFE_ASSERT_RECOVER, KisNode::parent, and sortMergeableNodes().

◆ sortMergeableNodes() [1/3]

void KisLayerUtils::sortMergeableNodes ( KisNodeSP root,
KisNodeList & inputNodes,
KisNodeList & outputNodes )

By the end of recursion inputNodes must be empty

Definition at line 1608 of file kis_layer_utils.cpp.

1609 {
1610 KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root);
1611
1612 if (it != inputNodes.end()) {
1613 outputNodes << *it;
1614 inputNodes.erase(it);
1615 }
1616
1617 if (inputNodes.isEmpty()) {
1618 return;
1619 }
1620
1621 KisNodeSP child = root->firstChild();
1622 while (child) {
1623 sortMergeableNodes(child, inputNodes, outputNodes);
1624 child = child->nextSibling();
1625 }
1626
1630 KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty());
1631 }
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
KisNodeListSP inputNodes(KisImageSP image, InputLayerMode inputMode, KisNodeSP currentNode)

References KisNode::firstChild(), KIS_ASSERT_RECOVER_NOOP, KisNode::nextSibling(), KisNode::parent, and sortMergeableNodes().

◆ sortMergeableNodes() [2/3]

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortMergeableNodes ( KisNodeSP root,
KisNodeList nodes )

Definition at line 1633 of file kis_layer_utils.cpp.

1634 {
1635 KisNodeList result;
1636 sortMergeableNodes(root, nodes, result);
1637 return result;
1638 }

References sortMergeableNodes().

◆ sortMergeableNodes() [3/3]

KRITAIMAGE_EXPORT void KisLayerUtils::sortMergeableNodes ( KisNodeSP root,
QList< KisNodeSP > & inputNodes,
QList< KisNodeSP > & outputNodes )

◆ splitAlphaToMask()

KRITAIMAGE_EXPORT void KisLayerUtils::splitAlphaToMask ( KisImageSP image,
KisNodeSP node,
const QString & maskName )

Definition at line 2373 of file kis_layer_utils.cpp.

2374 {
2375 SplitAlphaToMaskInfoSP info( new SplitAlphaToMaskInfo(node->image(), node, maskName) );
2376
2377 KisImageSignalVector emitSignals;
2378 KisProcessingApplicator applicator(image, 0,
2380 emitSignals,
2381 kundo2_i18n("Split Alpha into a Mask"));
2382
2383 applicator.applyCommand(new SimpleAddNode(info->image, info->getMask(), info->node), KisStrokeJobData::BARRIER);
2384 applicator.applyCommand(new InitSplitAlphaSelectionMask(info));
2385 if (info->frames.count() > 0) {
2386 Q_FOREACH(const int& frame, info->frames) {
2387 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
2388 applicator.applyCommand(new AddNewFrame(info->getMask(), frame, info->node));
2389 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2390 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
2391 }
2392 } else {
2393 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2394 }
2395 applicator.end();
2396 }

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisProcessingApplicator::end(), KisBaseNode::image, kundo2_i18n(), and KisProcessingApplicator::NONE.

◆ splitNonRemovableNodes()

void KisLayerUtils::splitNonRemovableNodes ( KisNodeList & nodesToRemove,
KisNodeList & _nodesToHide )

Definition at line 1111 of file kis_layer_utils.cpp.

1112 {
1113 QSet<KisNodeSP> nodesToHide;
1114 QSet<KisNodeSP> extraNodesToRemove;
1115
1116 for (auto it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) {
1117 KisNodeSP root = *it;
1119
1120 if (!root->isEditable(false)) {
1121 nodesToHide.insert(root);
1122 } else {
1123 bool rootNeedsCarefulRemoval = false;
1124
1125 recursiveApplyNodes(root,
1126 [root, &nodesToHide, &rootNeedsCarefulRemoval] (KisNodeSP node) {
1127 if (!node->isEditable(false)) {
1128 while (node != root) {
1129 nodesToHide.insert(node);
1130 node = node->parent();
1131 KIS_SAFE_ASSERT_RECOVER_BREAK(node);
1132 }
1133 nodesToHide.insert(root);
1134 rootNeedsCarefulRemoval = true;
1135 }
1136 });
1137
1138 if (rootNeedsCarefulRemoval) {
1140 [&extraNodesToRemove] (KisNodeSP node) {
1141 extraNodesToRemove.insert(node);
1142 });
1143 }
1144 }
1145 }
1146 nodesToRemove += KisNodeList(extraNodesToRemove.begin(), extraNodesToRemove.end());
1147 KritaUtils::filterContainer<KisNodeList>(nodesToRemove,
1148 [nodesToHide](KisNodeSP node) {
1149 return !nodesToHide.contains(node);
1150 });
1151 _nodesToHide = KisNodeList(nodesToHide.begin(), nodesToHide.end());
1152 }
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KisBaseNode::isEditable(), KIS_SAFE_ASSERT_RECOVER_NOOP, recursiveApplyNodes(), and KisBaseNode::visible().

◆ tryMergeSelectionMasks()

KRITAIMAGE_EXPORT bool KisLayerUtils::tryMergeSelectionMasks ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter )

Definition at line 2091 of file kis_layer_utils.cpp.

2092 {
2093 QList<KisSelectionMaskSP> selectionMasks;
2094
2095 for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) {
2096 KisSelectionMaskSP mask = dynamic_cast<KisSelectionMask*>(it->data());
2097 if (!mask) {
2098 it = mergedNodes.erase(it);
2099 } else {
2100 selectionMasks.append(mask);
2101 ++it;
2102 }
2103 }
2104
2105 if (mergedNodes.isEmpty()) return false;
2106
2107 KisLayerSP parentLayer = qobject_cast<KisLayer*>(selectionMasks.first()->parent().data());
2108 KIS_ASSERT_RECOVER(parentLayer) { return 0; }
2109
2110 KisImageSignalVector emitSignals;
2111
2112 KisProcessingApplicator applicator(image, 0,
2114 emitSignals,
2115 kundo2_i18n("Merge Selection Masks"));
2116
2117 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes, None));
2118
2119
2120 applicator.applyCommand(new MergeSelectionMasks(info, putAfter));
2121 applicator.applyCommand(new CleanUpNodes(info, putAfter),
2124 applicator.applyCommand(new ActivateSelectionMask(info));
2125 applicator.end();
2126
2127 return true;
2128 }

References KisProcessingApplicator::applyCommand(), KisProcessingApplicator::end(), KisStrokeJobData::EXCLUSIVE, KIS_ASSERT_RECOVER, kundo2_i18n(), None, KisProcessingApplicator::NONE, and KisStrokeJobData::SEQUENTIAL.

◆ updateFrameJobs()

void KisLayerUtils::updateFrameJobs ( FrameJobs * jobs,
KisNodeSP node )

Definition at line 1394 of file kis_layer_utils.cpp.

1394 {
1395 QSet<int> frames = fetchLayerFrames(node);
1396 frames = fetchUniqueFrameTimes(node, frames, false);
1397
1398 if (frames.isEmpty()) {
1399 (*jobs)[0].insert(node);
1400 } else {
1401 foreach (int frame, frames) {
1402 (*jobs)[frame].insert(node);
1403 }
1404 }
1405 }
QSet< int > fetchUniqueFrameTimes(KisNodeSP node, QSet< int > selectedTimes, bool filterActiveFrameID)

References fetchLayerFrames(), and fetchUniqueFrameTimes().

◆ updateFrameJobsRecursive()

void KisLayerUtils::updateFrameJobsRecursive ( FrameJobs * jobs,
KisNodeSP rootNode )

Definition at line 1407 of file kis_layer_utils.cpp.

1407 {
1408 updateFrameJobs(jobs, rootNode);
1409
1410 KisNodeSP node = rootNode->firstChild();
1411 while(node) {
1412 updateFrameJobsRecursive(jobs, node);
1413 node = node->nextSibling();
1414 }
1415 }
void updateFrameJobs(FrameJobs *jobs, KisNodeSP node)
void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode)

References KisNode::firstChild(), KisNode::nextSibling(), updateFrameJobs(), and updateFrameJobsRecursive().