File indexing completed on 2024-05-12 15:58:24

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         if(m_mode == STORE) {
0064             m_layerComposition->m_visibilityMap[node->uuid()] = node->visible();
0065             m_layerComposition->m_collapsedMap[node->uuid()] = node->collapsed();
0066         } else {
0067             bool newState = false;
0068             if(m_layerComposition->m_visibilityMap.contains(node->uuid())) {
0069                 newState = m_layerComposition->m_visibilityMap[node->uuid()];
0070             }
0071             if(node->visible() != newState) {
0072                 node->setVisible(m_layerComposition->m_visibilityMap[node->uuid()]);
0073                 node->setDirty();
0074             }
0075             if(m_layerComposition->m_collapsedMap.contains(node->uuid())) {
0076                 node->setCollapsed(m_layerComposition->m_collapsedMap[node->uuid()]);
0077             }
0078         }
0079         
0080         return true;
0081     }
0082 private:
0083     KisLayerComposition* m_layerComposition;
0084     Mode m_mode;
0085 };
0086 
0087 KisLayerComposition::KisLayerComposition(KisImageWSP image, const QString& name)
0088     : m_image(image)
0089     , m_name(name)
0090     , m_exportEnabled(true)
0091 {
0092 
0093 }
0094 
0095 KisLayerComposition::~KisLayerComposition()
0096 {
0097 
0098 }
0099 
0100 KisLayerComposition::KisLayerComposition(const KisLayerComposition &rhs, KisImageWSP otherImage)
0101     : m_image(otherImage ? otherImage : rhs.m_image),
0102       m_name(rhs.m_name),
0103       m_exportEnabled(rhs.m_exportEnabled)
0104 {
0105     {
0106         auto it = rhs.m_visibilityMap.constBegin();
0107         for (; it != rhs.m_visibilityMap.constEnd(); ++it) {
0108             QUuid nodeUuid = it.key();
0109             KisNodeSP node = KisLayerUtils::findNodeByUuid(rhs.m_image->root(), nodeUuid);
0110             if (node) {
0111                 KisNodeQueryPath path = KisNodeQueryPath::absolutePath(node);
0112                 KisNodeSP newNode = path.queryUniqueNode(m_image);
0113                 KIS_ASSERT_RECOVER(newNode) { continue; }
0114 
0115                 m_visibilityMap.insert(newNode->uuid(), it.value());
0116             }
0117         }
0118     }
0119 
0120     {
0121         auto it = rhs.m_collapsedMap.constBegin();
0122         for (; it != rhs.m_collapsedMap.constEnd(); ++it) {
0123             QUuid nodeUuid = it.key();
0124             KisNodeSP node = KisLayerUtils::findNodeByUuid(rhs.m_image->root(), nodeUuid);
0125             if (node) {
0126                 KisNodeQueryPath path = KisNodeQueryPath::absolutePath(node);
0127                 KisNodeSP newNode = path.queryUniqueNode(m_image);
0128                 KIS_ASSERT_RECOVER(newNode) { continue; }
0129 
0130                 m_collapsedMap.insert(newNode->uuid(), it.value());
0131             }
0132         }
0133     }
0134 }
0135 
0136 void KisLayerComposition::setName(const QString& name)
0137 {
0138     m_name = name;
0139 }
0140 
0141 QString KisLayerComposition::name()
0142 {
0143     return m_name;
0144 }
0145 
0146 void KisLayerComposition::store()
0147 {
0148     if(m_image.isNull()) {
0149         return;
0150     }
0151     KisCompositionVisitor visitor(this, KisCompositionVisitor::STORE);
0152     m_image->rootLayer()->accept(visitor);
0153 }
0154 
0155 void KisLayerComposition::apply()
0156 {
0157     if (m_image.isNull()) {
0158         return;
0159     }
0160     KisCompositionVisitor visitor(this, KisCompositionVisitor::APPLY);
0161     m_image->rootLayer()->accept(visitor);
0162 }
0163 
0164 void KisLayerComposition::setExportEnabled ( bool enabled )
0165 {
0166     m_exportEnabled = enabled;
0167 }
0168 
0169 bool KisLayerComposition::isExportEnabled()
0170 {
0171     return m_exportEnabled;
0172 }
0173 
0174 void KisLayerComposition::setVisible(QUuid id, bool visible)
0175 {
0176     m_visibilityMap[id] = visible;
0177 }
0178 
0179 void KisLayerComposition::setCollapsed ( QUuid id, bool collapsed )
0180 {
0181     m_collapsedMap[id] = collapsed;
0182 }
0183 
0184 void KisLayerComposition::save(QDomDocument& doc, QDomElement& element)
0185 {
0186     QDomElement compositionElement = doc.createElement("composition");
0187     compositionElement.setAttribute("name", m_name);
0188     compositionElement.setAttribute("exportEnabled", m_exportEnabled);
0189     QMapIterator<QUuid, bool> iter(m_visibilityMap);
0190     while (iter.hasNext()) {
0191         iter.next();
0192         QDomElement valueElement = doc.createElement("value");
0193         dbgKrita << "uuid" << iter.key().toString() << "visible" <<  iter.value();
0194         valueElement.setAttribute("uuid", iter.key().toString());
0195         valueElement.setAttribute("visible", iter.value());
0196         dbgKrita << "contains" << m_collapsedMap.contains(iter.key());
0197         if (m_collapsedMap.contains(iter.key())) {
0198             dbgKrita << "colapsed :" << m_collapsedMap[iter.key()];
0199             valueElement.setAttribute("collapsed", m_collapsedMap[iter.key()]);
0200         }
0201         compositionElement.appendChild(valueElement);
0202     }
0203     element.appendChild(compositionElement);
0204 }