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 }