Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_qmic_synchronize_layers_command.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2013 Lukáš Tvrdý <lukast.dev@gmail.com>
3 * SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
4 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
10
11#include <tuple>
12#include <utility>
13
14#include <KisDocument.h>
15#include <KisMainWindow.h>
16#include <KisPart.h>
17#include <KisViewManager.h>
20#include <kis_command_utils.h>
21#include <kis_image.h>
22#include <kis_layer_utils.h>
23#include <kis_node_manager.h>
25#include <kis_paint_layer.h>
26#include <kis_selection.h>
28#include <kis_transaction.h>
29#include <kis_types.h>
30
32
36 KisImageWSP image,
37 const QRect &dstRect,
38 KisSelectionSP selection)
39 : m_nodes(std::move(nodes))
40 , m_newNodes(new KisNodeList())
41 , m_images(std::move(images))
42 , m_image(image)
43 , m_dstRect(dstRect)
44 , m_selection(selection)
45 {
46 }
47
49 {
50 qDeleteAll(m_imageCommands);
51 m_imageCommands.clear();
52 }
53
58 QRect m_dstRect;
63};
64
66 KisNodeListSP nodes,
68 KisImageWSP image,
69 const QRect &dstRect,
70 KisSelectionSP selection)
71 : KisCommandUtils::CompositeCommand()
72 , d(new Private{std::move(nodes),
73 std::move(images),
74 image,
75 dstRect,
76 selection})
77{
78 dbgPlugins << "KisQmicSynchronizeLayersCommand";
79}
80
85
87{
88 dbgPlugins << "KisQmicSynchronizeLayersCommand::Redo";
89
90 const auto pickAboveThis = [&]() {
91 if (!d->m_newNodes->isEmpty()) {
92 return d->m_newNodes->last()->prevSibling();
93 } else {
94 return d->m_nodes->last()->prevSibling();
95 }
96 };
97
98 const auto getNode = [&](int i) {
99 if (i >= d->m_nodes->size()) {
100 return d->m_newNodes->at(i - d->m_nodes->size());
101 } else {
102 return d->m_nodes->at(i);
103 }
104 };
105
106 KisNodeManager *nodeManager = [&]() -> KisNodeManager * {
108 if (!mainWin)
109 return nullptr;
110 KisViewManager *viewManager = mainWin->viewManager();
111 if (!viewManager)
112 return nullptr;
113 if (viewManager->document()->image() != d->m_image)
114 return nullptr;
115 return viewManager->nodeManager();
116 }();
117
118 if (!nodeManager)
119 return;
120
121 auto *selectOldLayer = new KisLayerUtils::KeepNodesSelectedCommand(
122 nodeManager->selectedNodes(),
123 nodeManager->selectedNodes(),
124 nodeManager->activeNode(),
125 nodeManager->activeNode(),
126 d->m_image,
127 false);
128
129 selectOldLayer->redo();
130
132
133 // if gmic produces more layers
134 if (d->m_nodes->size() < d->m_images.size()) {
135 if (d->m_image) {
136 const QPoint origin = [&]() -> QPoint {
137 if (d->m_selection) {
138 return d->m_selection->selectedExactRect().topLeft();
139 } else if (!d->m_nodes->isEmpty()) {
140 const auto root = d->m_nodes->at(0);
141 return {root->x(), root->y()};
142 } else {
143 return {};
144 }
145 }();
146 const int nodesCount = d->m_nodes->size();
147 for (int i = nodesCount; i < d->m_images.size(); i++) {
148 KisPaintDeviceSP device = new KisPaintDevice(d->m_image->colorSpace());
149 KisLayerSP paintLayer = new KisPaintLayer(d->m_image, QString("New layer %1 from gmic filter").arg(i), OPACITY_OPAQUE_U8, device);
150 paintLayer->setX(origin.x());
151 paintLayer->setY(origin.y());
152
154 *d->m_images[i].data(),
155 device,
156 d->m_selection,
157 d->m_dstRect);
158
159 KisNodeSP aboveThis(nullptr);
160 KisNodeSP parent(nullptr);
161
162 if (nodesCount > 0) {
163 // This node is a copy made by GMic of an existing node;
164 // give it its name back (the existing node will be reused
165 // by KisImportQmicProcessingVisitor)
166 paintLayer->setName(getNode(i - nodesCount)->name());
167 aboveThis = pickAboveThis();
168 parent = d->m_nodes->at(0)->parent();
169
170 dbgPlugins << "Adding paint layer" << (i - nodesCount + 1) << paintLayer << "to parent" << parent->name() << "above" << aboveThis;
171 }
172
173 auto *layerNameCmd =
175 paintLayer.data(),
176 d->m_selection);
177 layerNameCmd->redo();
178
180
181 auto *addLayerCmd = new KisImageLayerAddCommand(d->m_image, paintLayer, parent, aboveThis, true, true);
182
183 addLayerCmd->redo();
185 d->m_newNodes->append(paintLayer);
186 }
187 } else // small preview
188 {
189 Q_ASSERT(!d->m_nodes->empty());
190 for (int i = d->m_nodes->size(); i < d->m_images.size(); i++) {
191 KisPaintDeviceSP device = new KisPaintDevice(d->m_nodes->at(0)->colorSpace());
192 KisLayerSP paintLayer = new KisPaintLayer(nullptr, "New layer from gmic filter", OPACITY_OPAQUE_U8, device);
193 d->m_newNodes->append(paintLayer);
194 }
195 }
196 } else if (d->m_nodes->size() > d->m_images.size()) {
197 // if gmic produces less layers, we are going to drop some
198
199 const KisNodeList extraNodes = [&]() {
200 KisNodeList result;
201 const auto minIndex = d->m_images.size();
202 for (auto i = minIndex; i < d->m_nodes->size(); i++) {
203 result.append(d->m_nodes->at(i));
204 }
205 return result;
206 }();
207
208 auto *removeLayerCmd = new KisLayerUtils::SimpleRemoveLayers(extraNodes, d->m_image);
209 removeLayerCmd->redo();
211 }
212
213 const int boundary = std::min(d->m_nodes->size(), d->m_images.size());
214
215 for (int index = 0; index < boundary; index++) {
216 KisNodeSP node = d->m_nodes->at(index);
217
218 const KisQMicImageSP &gimg = d->m_images.at(index);
219 dbgPlugins << "Importing layer index" << index
220 << "Size: " << gimg->m_width << "x" << gimg->m_height
221 << "colorchannels: " << gimg->m_spectrum;
222
223 KisPaintDeviceSP dst = node->paintDevice();
224
225 const auto *layer = dynamic_cast<const KisLayer *>(node.data());
226 const KisSelectionSP selection =
227 layer ? layer->selection() : d->m_selection;
228
229 KisTransaction transaction(dst);
231 dst,
232 selection,
233 d->m_dstRect);
234 auto *layerNameCmd =
236 node.data(),
237 selection);
238 layerNameCmd->redo();
239
241
242 transaction.commit(&d->m_undoAdapter);
243 node->setDirty(d->m_dstRect);
244 }
245
246 KisNodeSP currentNode = [&]() -> KisNodeSP {
247 if (!d->m_nodes->empty()) {
248 return d->m_nodes->first();
249 } else if (!d->m_newNodes->empty()) {
250 return d->m_newNodes->first();
251 }
252 return {};
253 }();
254
255 if (!currentNode)
256 return;
257
258 auto *selectNewLayer = new KisLayerUtils::KeepNodesSelectedCommand(
259 nodeManager->selectedNodes(),
260 {currentNode},
261 nodeManager->activeNode(),
262 currentNode,
263 d->m_image,
264 true);
265
266 selectNewLayer->redo();
267
269
270 dbgPlugins << "Set selected node to" << currentNode->name();
271}
272
274{
276 d->m_undoAdapter.undoAll();
277 d->m_newNodes->clear();
278}
const quint8 OPACITY_OPAQUE_U8
KisImageSP image
The command for adding a layer.
Main window for Krita.
KisViewManager * viewManager
KisNodeSP activeNode()
Convenience function to get the active layer or mask.
KisNodeList selectedNodes()
static KisPart * instance()
Definition KisPart.cpp:131
KisMainWindow * currentMainwindow() const
Definition KisPart.cpp:483
void commit(KisUndoAdapter *undoAdapter)
KisDocument * document() const
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.
#define dbgPlugins
Definition kis_debug.h:51
KUndo2Command * applyLayerNameChanges(const KisQMicImage &srcGmicImage, KisNode *node, KisSelectionSP selection)
void gmicImageToPaintDevice(const KisQMicImage &srcGmicImage, KisPaintDeviceSP dst, KisSelectionSP selection, const QRect &dstRect)
void setName(const QString &name)
virtual KisPaintDeviceSP paintDevice() const =0
QString name() const
void setX(qint32 x) override
Definition kis_layer.cc:983
void setY(qint32 y) override
Definition kis_layer.cc:989
virtual void setDirty()
Definition kis_node.cpp:577
Private(KisNodeListSP nodes, QVector< KisQMicImageSP > images, KisImageWSP image, const QRect &dstRect, KisSelectionSP selection)
KisQmicSynchronizeLayersCommand(KisNodeListSP nodes, QVector< KisQMicImageSP > images, KisImageWSP image, const QRect &dstRect=QRect(), KisSelectionSP selection=nullptr)