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 }