File indexing completed on 2024-05-19 04:26:19

0001 /*
0002  *  SPDX-FileCopyrightText: 2012 Sven Langkamp <sven.langkamp@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_layer_composition.h"
0008 #include "kis_node_visitor.h"
0009 #include "kis_group_layer.h"
0010 #include "kis_adjustment_layer.h"
0011 #include "kis_external_layer_iface.h"
0012 #include "kis_paint_layer.h"
0013 #include "generator/kis_generator_layer.h"
0014 #include "kis_clone_layer.h"
0015 #include "kis_filter_mask.h"
0016 #include "kis_transform_mask.h"
0017 #include "kis_transparency_mask.h"
0018 #include "kis_selection_mask.h"
0019 #include "lazybrush/kis_colorize_mask.h"
0020 #include "kis_layer_utils.h"
0021 #include "kis_node_query_path.h"
0022 
0023 #include <QDomDocument>
0024 
0025 class KisCompositionVisitor : public KisNodeVisitor {
0026 public:
0027     enum Mode {
0028         STORE,
0029         APPLY
0030     };
0031     
0032     KisCompositionVisitor(KisLayerComposition* layerComposition, Mode mode)
0033         : m_layerComposition(layerComposition)
0034         , m_mode(mode)
0035     {        
0036     }
0037 
0038     bool visit(KisNode* node) override { return process(node); }
0039     bool visit(KisGroupLayer* layer) override
0040     { 
0041         bool result = visitAll(layer);
0042         if(layer == layer->image()->rootLayer()) {
0043             return result;
0044         }        
0045         return result && process(layer);
0046     }
0047     bool visit(KisAdjustmentLayer* layer) override { return process(layer); }
0048     bool visit(KisPaintLayer* layer) override { return process(layer); }
0049     bool visit(KisExternalLayer* layer) override { return process(layer); }
0050     bool visit(KisGeneratorLayer* layer) override { return process(layer); }
0051     bool visit(KisCloneLayer* layer) override { return process(layer); }
0052     bool visit(KisFilterMask* mask) override { return process(mask); }
0053     bool visit(KisTransformMask* mask) override { return process(mask); }
0054     bool visit(KisTransparencyMask* mask) override { return process(mask); }
0055     bool visit(KisSelectionMask* mask) override { return process(mask); }
0056     bool visit(KisColorizeMask* mask) override { return process(mask); }
0057 
0058     bool process(KisNode* node) {
0059         if (node->isFakeNode()) {
0060             dbgKrita << "Compositions: Skipping over Fake Node" << node->uuid() << node->name();
0061             return true;
0062         }
0063 
0064         bool result = visitAll(node);
0065 
0066         if(m_mode == STORE) {
0067             m_layerComposition->m_visibilityMap[node->uuid()] = node->visible();
0068             m_layerComposition->m_collapsedMap[node->uuid()] = node->collapsed();
0069         } else {
0070             bool newState = false;
0071             if(m_layerComposition->m_visibilityMap.contains(node->uuid())) {
0072                 newState = m_layerComposition->m_visibilityMap[node->uuid()];
0073             }
0074             if(node->visible() != newState) {
0075                 node->setVisible(m_layerComposition->m_visibilityMap[node->uuid()]);
0076                 node->setDirty();
0077             }
0078             if(m_layerComposition->m_collapsedMap.contains(node->uuid())) {
0079                 node->setCollapsed(m_layerComposition->m_collapsedMap[node->uuid()]);
0080             }
0081         }
0082         
0083         return result;
0084     }
0085 private:
0086     KisLayerComposition* m_layerComposition;
0087     Mode m_mode;
0088 };
0089 
0090 KisLayerComposition::KisLayerComposition(KisImageWSP image, const QString& name)
0091     : m_image(image)
0092     , m_name(name)
0093     , m_exportEnabled(true)
0094 {
0095 
0096 }
0097 
0098 KisLayerComposition::~KisLayerComposition()
0099 {
0100 
0101 }
0102 
0103 KisLayerComposition::KisLayerComposition(const KisLayerComposition &rhs, KisImageWSP otherImage)
0104     : m_image(otherImage ? otherImage : rhs.m_image),
0105       m_name(rhs.m_name),
0106       m_exportEnabled(rhs.m_exportEnabled)
0107 {
0108     {
0109         auto it = rhs.m_visibilityMap.constBegin();
0110         for (; it != rhs.m_visibilityMap.constEnd(); ++it) {
0111             QUuid nodeUuid = it.key();
0112             KisNodeSP node = KisLayerUtils::findNodeByUuid(rhs.m_image->root(), nodeUuid);
0113             if (node) {
0114                 KisNodeQueryPath path = KisNodeQueryPath::absolutePath(node);
0115                 KisNodeSP newNode = path.queryUniqueNode(m_image);
0116                 KIS_ASSERT_RECOVER(newNode) { continue; }
0117 
0118                 m_visibilityMap.insert(newNode->uuid(), it.value());
0119             }
0120         }
0121     }
0122 
0123     {
0124         auto it = rhs.m_collapsedMap.constBegin();
0125         for (; it != rhs.m_collapsedMap.constEnd(); ++it) {
0126             QUuid nodeUuid = it.key();
0127             KisNodeSP node = KisLayerUtils::findNodeByUuid(rhs.m_image->root(), nodeUuid);
0128             if (node) {
0129                 KisNodeQueryPath path = KisNodeQueryPath::absolutePath(node);
0130                 KisNodeSP newNode = path.queryUniqueNode(m_image);
0131                 KIS_ASSERT_RECOVER(newNode) { continue; }
0132 
0133                 m_collapsedMap.insert(newNode->uuid(), it.value());
0134             }
0135         }
0136     }
0137 }
0138 
0139 void KisLayerComposition::setName(const QString& name)
0140 {
0141     m_name = name;
0142 }
0143 
0144 QString KisLayerComposition::name()
0145 {
0146     return m_name;
0147 }
0148 
0149 void KisLayerComposition::store()
0150 {
0151     if(m_image.isNull()) {
0152         return;
0153     }
0154     KisCompositionVisitor visitor(this, KisCompositionVisitor::STORE);
0155     m_image->rootLayer()->accept(visitor);
0156 }
0157 
0158 void KisLayerComposition::apply()
0159 {
0160     if (m_image.isNull()) {
0161         return;
0162     }
0163     KisCompositionVisitor visitor(this, KisCompositionVisitor::APPLY);
0164     m_image->rootLayer()->accept(visitor);
0165 }
0166 
0167 void KisLayerComposition::setExportEnabled ( bool enabled )
0168 {
0169     m_exportEnabled = enabled;
0170 }
0171 
0172 bool KisLayerComposition::isExportEnabled()
0173 {
0174     return m_exportEnabled;
0175 }
0176 
0177 void KisLayerComposition::setVisible(QUuid id, bool visible)
0178 {
0179     m_visibilityMap[id] = visible;
0180 }
0181 
0182 void KisLayerComposition::setCollapsed ( QUuid id, bool collapsed )
0183 {
0184     m_collapsedMap[id] = collapsed;
0185 }
0186 
0187 void KisLayerComposition::save(QDomDocument& doc, QDomElement& element)
0188 {
0189     QDomElement compositionElement = doc.createElement("composition");
0190     compositionElement.setAttribute("name", m_name);
0191     compositionElement.setAttribute("exportEnabled", m_exportEnabled);
0192     QMapIterator<QUuid, bool> iter(m_visibilityMap);
0193     while (iter.hasNext()) {
0194         iter.next();
0195         QDomElement valueElement = doc.createElement("value");
0196         dbgKrita << "uuid" << iter.key().toString() << "visible" <<  iter.value();
0197         valueElement.setAttribute("uuid", iter.key().toString());
0198         valueElement.setAttribute("visible", iter.value());
0199         dbgKrita << "contains" << m_collapsedMap.contains(iter.key());
0200         if (m_collapsedMap.contains(iter.key())) {
0201             dbgKrita << "collapsed :" << m_collapsedMap[iter.key()];
0202             valueElement.setAttribute("collapsed", m_collapsedMap[iter.key()]);
0203         }
0204         compositionElement.appendChild(valueElement);
0205     }
0206     element.appendChild(compositionElement);
0207 }