1 /*
2 * Copyright (C) 2006 Boudewijn Rempt <boud@valdyas.org>
3 * Copyright (c) 2020 L. E. Segovia <amy@amyspark.me>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "kis_layer_manager.h"
21
22 #include <QRect>
23 #include <QApplication>
24 #include <QCursor>
25 #include <QString>
26 #include <QDialog>
27 #include <QVBoxLayout>
28 #include <QFileInfo>
29 #include <QStandardPaths>
30
31 #include <kactioncollection.h>
32 #include <klocalizedstring.h>
33 #include <QMessageBox>
34 #include <QUrl>
35
36 #include <kis_file_name_requester.h>
37 #include <kis_icon.h>
38 #include <KisImportExportManager.h>
39 #include <KisDocument.h>
40 #include <KoColorSpace.h>
41 #include <KoCompositeOpRegistry.h>
42 #include <KoPointerEvent.h>
43 #include <KoColorProfile.h>
44 #include <KoSelection.h>
45 #include <KisPart.h>
46 #include <KisMainWindow.h>
47
48 #include <filter/kis_filter_configuration.h>
49 #include <filter/kis_filter.h>
50 #include <kis_filter_strategy.h>
51 #include <generator/kis_generator_layer.h>
52 #include <kis_file_layer.h>
53 #include <kis_adjustment_layer.h>
54 #include <kis_mask.h>
55 #include <kis_clone_layer.h>
56 #include <kis_group_layer.h>
57 #include <kis_image.h>
58 #include <kis_layer.h>
59 #include <kis_paint_device.h>
60 #include <kis_selection.h>
61 #include <flake/kis_shape_layer.h>
62 #include <kis_undo_adapter.h>
63 #include <kis_painter.h>
64 #include <kis_meta_data_store.h>
65 #include <kis_meta_data_merge_strategy_registry.h>
66 #include <kis_psd_layer_style.h>
67 #include <KisMimeDatabase.h>
68
69 #include "kis_config.h"
70 #include "kis_cursor.h"
71 #include "dialogs/kis_dlg_adj_layer_props.h"
72 #include "dialogs/kis_dlg_adjustment_layer.h"
73 #include "dialogs/kis_dlg_layer_properties.h"
74 #include "dialogs/kis_dlg_generator_layer.h"
75 #include "dialogs/kis_dlg_file_layer.h"
76 #include "dialogs/kis_dlg_layer_style.h"
77 #include "dialogs/KisDlgChangeCloneSource.h"
78 #include "kis_filter_manager.h"
79 #include "kis_node_visitor.h"
80 #include "kis_paint_layer.h"
81 #include "commands/kis_image_commands.h"
82 #include "commands/kis_node_commands.h"
83 #include "kis_change_file_layer_command.h"
84 #include "kis_canvas_resource_provider.h"
85 #include "kis_selection_manager.h"
86 #include "kis_statusbar.h"
87 #include "KisViewManager.h"
88 #include "kis_zoom_manager.h"
89 #include "canvas/kis_canvas2.h"
90 #include "widgets/kis_meta_data_merge_strategy_chooser_widget.h"
91 #include "widgets/kis_wdg_generator.h"
92 #include "kis_progress_widget.h"
93 #include "kis_node_commands_adapter.h"
94 #include "kis_node_manager.h"
95 #include "kis_action.h"
96 #include "kis_action_manager.h"
97 #include "kis_raster_keyframe_channel.h"
98 #include "kis_signal_compressor_with_param.h"
99 #include "kis_abstract_projection_plane.h"
100 #include "commands_new/kis_set_layer_style_command.h"
101 #include "kis_post_execution_undo_adapter.h"
102 #include "kis_selection_mask.h"
103 #include "kis_layer_utils.h"
104 #include "lazybrush/kis_colorize_mask.h"
105 #include "kis_processing_applicator.h"
106 #include "kis_projection_leaf.h"
107
108 #include "KisSaveGroupVisitor.h"
109
KisLayerManager(KisViewManager * view)110 KisLayerManager::KisLayerManager(KisViewManager * view)
111 : m_view(view)
112 , m_commandsAdapter(new KisNodeCommandsAdapter(m_view))
113
114 {
115 }
116
~KisLayerManager()117 KisLayerManager::~KisLayerManager()
118 {
119 delete m_commandsAdapter;
120 }
121
setView(QPointer<KisView> view)122 void KisLayerManager::setView(QPointer<KisView>view)
123 {
124 m_imageView = view;
125 }
126
activeLayer()127 KisLayerSP KisLayerManager::activeLayer()
128 {
129 if (m_imageView) {
130 return m_imageView->currentLayer();
131 }
132 return 0;
133 }
134
activeDevice()135 KisPaintDeviceSP KisLayerManager::activeDevice()
136 {
137 if (activeLayer()) {
138 return activeLayer()->paintDevice();
139 }
140 return 0;
141 }
142
activateLayer(KisLayerSP layer)143 void KisLayerManager::activateLayer(KisLayerSP layer)
144 {
145 if (m_imageView) {
146 layersUpdated();
147 if (layer) {
148 m_view->canvasResourceProvider()->slotNodeActivated(layer.data());
149 }
150 }
151 }
152
153
setup(KisActionManager * actionManager)154 void KisLayerManager::setup(KisActionManager* actionManager)
155 {
156 m_imageFlatten = actionManager->createAction("flatten_image");
157 connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage()));
158
159 m_imageMergeLayer = actionManager->createAction("merge_layer");
160 connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer()));
161
162 m_flattenLayer = actionManager->createAction("flatten_layer");
163 connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer()));
164
165 m_rasterizeLayer = actionManager->createAction("rasterize_layer");
166 connect(m_rasterizeLayer, SIGNAL(triggered()), this, SLOT(rasterizeLayer()));
167
168 m_groupLayersSave = actionManager->createAction("save_groups_as_images");
169 connect(m_groupLayersSave, SIGNAL(triggered()), this, SLOT(saveGroupLayers()));
170
171 m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated");
172 connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated()));
173
174 m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer");
175 connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer()));
176
177 KisAction *action = actionManager->createAction("trim_to_image");
178 connect(action, SIGNAL(triggered()), this, SLOT(trimToImage()));
179
180 m_layerStyle = actionManager->createAction("layer_style");
181 connect(m_layerStyle, SIGNAL(triggered()), this, SLOT(layerStyle()));
182
183 }
184
updateGUI()185 void KisLayerManager::updateGUI()
186 {
187 KisImageSP image = m_view->image();
188 KisLayerSP layer = activeLayer();
189
190 const bool isGroupLayer = layer && layer->inherits("KisGroupLayer");
191
192 m_imageMergeLayer->setText(
193 isGroupLayer ?
194 i18nc("@action:inmenu", "Merge Group") :
195 i18nc("@action:inmenu", "Merge with Layer Below"));
196 m_flattenLayer->setVisible(!isGroupLayer);
197
198 if (m_view->statusBar())
199 m_view->statusBar()->setProfile(image);
200 }
201
imageResizeToActiveLayer()202 void KisLayerManager::imageResizeToActiveLayer()
203 {
204 KisLayerSP layer;
205 KisImageWSP image = m_view->image();
206
207 if (image && (layer = activeLayer())) {
208 QRect cropRect = layer->projection()->nonDefaultPixelArea();
209 if (!cropRect.isEmpty()) {
210 image->cropImage(cropRect);
211 } else {
212 m_view->showFloatingMessage(
213 i18nc("floating message in layer manager",
214 "Layer is empty "),
215 QIcon(), 2000, KisFloatingMessage::Low);
216 }
217 }
218 }
219
trimToImage()220 void KisLayerManager::trimToImage()
221 {
222 KisImageWSP image = m_view->image();
223 if (image) {
224 image->cropImage(image->bounds());
225 }
226 }
227
layerProperties()228 void KisLayerManager::layerProperties()
229 {
230 if (!m_view) return;
231 if (!m_view->document()) return;
232
233 KisLayerSP layer = activeLayer();
234 if (!layer) return;
235
236 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
237 const bool multipleLayersSelected = selectedNodes.size() > 1;
238
239 if (!m_view->nodeManager()->canModifyLayers(selectedNodes)) return;
240
241 KisAdjustmentLayerSP adjustmentLayer = KisAdjustmentLayerSP(dynamic_cast<KisAdjustmentLayer*>(layer.data()));
242 KisGeneratorLayerSP generatorLayer = KisGeneratorLayerSP(dynamic_cast<KisGeneratorLayer*>(layer.data()));
243 KisFileLayerSP fileLayer = KisFileLayerSP(dynamic_cast<KisFileLayer*>(layer.data()));
244
245 if (adjustmentLayer && !multipleLayersSelected) {
246
247 KisPaintDeviceSP dev = adjustmentLayer->projection();
248
249 KisDlgAdjLayerProps dlg(adjustmentLayer, adjustmentLayer.data(), dev, m_view, adjustmentLayer->filter().data(), adjustmentLayer->name(), i18n("Filter Layer Properties"), m_view->mainWindow(), "dlgadjlayerprops");
250 dlg.resize(dlg.minimumSizeHint());
251
252
253 KisFilterConfigurationSP configBefore(adjustmentLayer->filter());
254 KIS_ASSERT_RECOVER_RETURN(configBefore);
255 QString xmlBefore = configBefore->toXML();
256
257
258 if (dlg.exec() == QDialog::Accepted) {
259
260 adjustmentLayer->setName(dlg.layerName());
261
262 KisFilterConfigurationSP configAfter(dlg.filterConfiguration());
263 Q_ASSERT(configAfter);
264 QString xmlAfter = configAfter->toXML();
265
266 if(xmlBefore != xmlAfter) {
267 KisChangeFilterCmd *cmd
268 = new KisChangeFilterCmd(adjustmentLayer,
269 configBefore->name(),
270 xmlBefore,
271 configAfter->name(),
272 xmlAfter,
273 false);
274 // FIXME: check whether is needed
275 cmd->redo();
276 m_view->undoAdapter()->addCommand(cmd);
277 m_view->document()->setModified(true);
278 }
279 }
280 else {
281 KisFilterConfigurationSP configAfter(dlg.filterConfiguration());
282 Q_ASSERT(configAfter);
283 QString xmlAfter = configAfter->toXML();
284
285 if(xmlBefore != xmlAfter) {
286 adjustmentLayer->setFilter(KisFilterRegistry::instance()->cloneConfiguration(configBefore.data()));
287 adjustmentLayer->setDirty();
288 }
289 }
290 }
291 else if (generatorLayer && !multipleLayersSelected) {
292 KisFilterConfigurationSP configBefore(generatorLayer->filter());
293 Q_ASSERT(configBefore);
294 QString xmlBefore = configBefore->toXML();
295
296 KisDlgGeneratorLayer *dlg = new KisDlgGeneratorLayer(generatorLayer->name(), m_view, m_view->mainWindow(), generatorLayer, configBefore, KisStrokeId());
297 dlg->setWindowTitle(i18n("Fill Layer Properties"));
298 dlg->setAttribute(Qt::WA_DeleteOnClose);
299
300 dlg->setConfiguration(configBefore.data());
301
302 Qt::WindowFlags flags = dlg->windowFlags();
303 dlg->setWindowFlags(flags | Qt::Tool | Qt::Dialog);
304 dlg->show();
305
306 }
307 else if (fileLayer && !multipleLayersSelected){
308 QString basePath = QFileInfo(m_view->document()->url().toLocalFile()).absolutePath();
309 QString fileNameOld = fileLayer->fileName();
310 KisFileLayer::ScalingMethod scalingMethodOld = fileLayer->scalingMethod();
311 KisDlgFileLayer dlg(basePath, fileLayer->name(), m_view->mainWindow());
312 dlg.setCaption(i18n("File Layer Properties"));
313 dlg.setFileName(fileNameOld);
314 dlg.setScalingMethod(scalingMethodOld);
315
316 if (dlg.exec() == QDialog::Accepted) {
317 const QString fileNameNew = dlg.fileName();
318 KisFileLayer::ScalingMethod scalingMethodNew = dlg.scaleToImageResolution();
319
320 if(fileNameNew.isEmpty()){
321 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified"));
322 return;
323 }
324 fileLayer->setName(dlg.layerName());
325
326 if (fileNameOld!= fileNameNew || scalingMethodOld != scalingMethodNew) {
327 KisChangeFileLayerCmd *cmd
328 = new KisChangeFileLayerCmd(fileLayer,
329 basePath,
330 fileNameOld,
331 scalingMethodOld,
332 basePath,
333 fileNameNew,
334 scalingMethodNew);
335 m_view->undoAdapter()->addCommand(cmd);
336 }
337 }
338 } else { // If layer == normal painting layer, vector layer, or group layer
339 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
340
341 KisDlgLayerProperties *dialog = new KisDlgLayerProperties(selectedNodes, m_view);
342 dialog->resize(dialog->minimumSizeHint());
343 dialog->setAttribute(Qt::WA_DeleteOnClose);
344 Qt::WindowFlags flags = dialog->windowFlags();
345 #ifdef Q_OS_ANDROID
346 // a Qt::Tool window seems incapable of receiving keyboard focus
347 dialog->setWindowFlags(flags | Qt::Dialog);
348 #else
349 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog);
350 #endif
351 dialog->show();
352
353 }
354 }
355
changeCloneSource()356 void KisLayerManager::changeCloneSource()
357 {
358 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
359 if (selectedNodes.isEmpty()) {
360 return;
361 }
362
363 QList<KisCloneLayerSP> cloneLayers;
364 KisNodeSP node;
365 Q_FOREACH (node, selectedNodes) {
366 KisCloneLayerSP cloneLayer(qobject_cast<KisCloneLayer *>(node.data()));
367 if (cloneLayer) {
368 cloneLayers << cloneLayer;
369 }
370 }
371
372 if (cloneLayers.isEmpty()) {
373 return;
374 }
375
376 if (!m_view->nodeManager()->canModifyLayers(implicitCastList<KisNodeSP>(cloneLayers))) return;
377
378 KisDlgChangeCloneSource *dialog = new KisDlgChangeCloneSource(cloneLayers, m_view);
379 dialog->setCaption(i18n("Change Clone Layer"));
380 dialog->resize(dialog->minimumSizeHint());
381 dialog->setAttribute(Qt::WA_DeleteOnClose);
382 Qt::WindowFlags flags = dialog->windowFlags();
383 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog);
384 dialog->show();
385 }
386
convertNodeToPaintLayer(KisNodeSP source)387 void KisLayerManager::convertNodeToPaintLayer(KisNodeSP source)
388 {
389 KisImageWSP image = m_view->image();
390 if (!image) return;
391
392 // this precondition must be checked at higher level
393 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false));
394
395 KisLayer *srcLayer = qobject_cast<KisLayer*>(source.data());
396 if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) {
397 image->flattenLayer(srcLayer);
398 return;
399 }
400
401 KisPaintDeviceSP srcDevice =
402 source->paintDevice() ? source->projection() : source->original();
403
404 bool putBehind = false;
405
406 QString newCompositeOp =
407 source->projectionLeaf()->isLayer() ?
408 source->compositeOpId() : COMPOSITE_OVER;
409
410 KisColorizeMask *colorizeMask = dynamic_cast<KisColorizeMask*>(source.data());
411 if (colorizeMask) {
412 srcDevice = colorizeMask->coloringProjection();
413 putBehind = colorizeMask->compositeOpId() == COMPOSITE_BEHIND;
414 if (putBehind) {
415 newCompositeOp = COMPOSITE_OVER;
416 }
417 }
418
419 if (!srcDevice) return;
420
421 KisPaintDeviceSP clone;
422
423 if (*srcDevice->colorSpace() !=
424 *srcDevice->compositionSourceColorSpace()) {
425
426 clone = new KisPaintDevice(srcDevice->compositionSourceColorSpace());
427 clone->setDefaultPixel(
428 srcDevice->defaultPixel().convertedTo(
429 srcDevice->compositionSourceColorSpace()));
430
431 QRect rc(srcDevice->extent());
432 KisPainter::copyAreaOptimized(rc.topLeft(), srcDevice, clone, rc);
433 } else {
434 clone = new KisPaintDevice(*srcDevice);
435 }
436
437 KisLayerSP layer = new KisPaintLayer(image,
438 source->name(),
439 source->opacity(),
440 clone);
441
442 if (srcDevice->framesInterface()) {
443 KisKeyframeChannel *cloneKeyChannel = layer->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
444 layer->enableAnimation();
445 KisKeyframeChannel *sourceKeyChannel = srcDevice->keyframeChannel();
446
447 foreach (const int &index, sourceKeyChannel->allKeyframeIds()) {
448 cloneKeyChannel->copyExternalKeyframe(sourceKeyChannel, index, index);
449 }
450 }
451
452 layer->setCompositeOpId(newCompositeOp);
453
454 KisNodeSP parent = source->parent();
455 KisNodeSP above = source->prevSibling();
456
457 while (parent && !parent->allowAsChild(layer)) {
458 above = above ? above->parent() : source->parent();
459 parent = above ? above->parent() : 0;
460 }
461
462 if (putBehind && above == source->parent()) {
463 above = above->prevSibling();
464 }
465
466 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a Paint Layer"));
467 m_commandsAdapter->removeNode(source);
468 m_commandsAdapter->addNode(layer, parent, above);
469 m_commandsAdapter->endMacro();
470 }
471
convertGroupToAnimated()472 void KisLayerManager::convertGroupToAnimated()
473 {
474 KisGroupLayerSP group = dynamic_cast<KisGroupLayer*>(activeLayer().data());
475 if (group.isNull()) return;
476
477 if (!m_view->nodeManager()->canModifyLayer(group)) return;
478
479 KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), group->name(), OPACITY_OPAQUE_U8);
480 animatedLayer->enableAnimation();
481 KisRasterKeyframeChannel *contentChannel = dynamic_cast<KisRasterKeyframeChannel*>(
482 animatedLayer->getKeyframeChannel(KisKeyframeChannel::Content.id(), true));
483 KIS_ASSERT_RECOVER_RETURN(contentChannel);
484
485 KisNodeSP child = group->firstChild();
486 int time = 0;
487 while (child) {
488 contentChannel->importFrame(time, child->projection(), NULL);
489 time++;
490
491 child = child->nextSibling();
492 }
493
494 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to an animated layer"));
495 m_commandsAdapter->addNode(animatedLayer, group->parent(), group);
496 m_commandsAdapter->removeNode(group);
497 m_commandsAdapter->endMacro();
498 }
499
convertLayerToFileLayer(KisNodeSP source)500 void KisLayerManager::convertLayerToFileLayer(KisNodeSP source)
501 {
502 KisImageSP image = m_view->image();
503 if (!image) return;
504
505 // this precondition must be checked at higher level
506 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false));
507
508 QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export);
509
510 KoDialog dlg;
511 QWidget *page = new QWidget(&dlg);
512 dlg.setMainWidget(page);
513 QBoxLayout *layout = new QVBoxLayout(page);
514 dlg.setWindowTitle(i18n("Save layers to..."));
515 QLabel *lbl = new QLabel(i18n("Choose the location where the layer will be saved to. The new file layer will then reference this location."));
516 lbl->setWordWrap(true);
517 layout->addWidget(lbl);
518 KisFileNameRequester *urlRequester = new KisFileNameRequester(page);
519 urlRequester->setMode(KoFileDialog::SaveFile);
520 urlRequester->setMimeTypeFilters(listMimeFilter);
521 urlRequester->setFileName(m_view->document()->url().toLocalFile());
522 if (m_view->document()->url().isLocalFile()) {
523 QFileInfo location = QFileInfo(m_view->document()->url().toLocalFile()).completeBaseName();
524 location.setFile(location.dir(), location.completeBaseName() + "_" + source->name() + ".png");
525 urlRequester->setFileName(location.absoluteFilePath());
526 }
527 else {
528 const QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
529 const QString proposedFileName = QDir(location.absoluteFilePath()).absoluteFilePath(source->name() + ".png");
530 urlRequester->setFileName(proposedFileName);
531 }
532
533 layout->addWidget(urlRequester);
534 if (!dlg.exec()) return;
535
536 QString path = urlRequester->fileName();
537
538 if (path.isEmpty()) return;
539
540 QFileInfo f(path);
541
542 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName());
543 if (mimeType.isEmpty()) {
544 mimeType = "image/png";
545 }
546 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
547
548 QRect bounds = source->exactBounds();
549 if (bounds.isEmpty()) {
550 bounds = image->bounds();
551 }
552 KisImageSP dst = new KisImage(doc->createUndoStore(),
553 image->width(),
554 image->height(),
555 image->projection()->compositionSourceColorSpace(),
556 source->name());
557 dst->setResolution(image->xRes(), image->yRes());
558 doc->setFileBatchMode(false);
559 doc->setCurrentImage(dst);
560 KisNodeSP node = source->clone();
561 dst->addNode(node);
562 dst->initialRefreshGraph();
563 dst->cropImage(bounds);
564 dst->waitForDone();
565
566 bool r = doc->exportDocumentSync(QUrl::fromLocalFile(path), mimeType.toLatin1());
567 if (!r) {
568
569 qWarning() << "Converting layer to file layer. path:"<< path << "gave errors" << doc->errorMessage();
570 } else {
571 QString basePath = QFileInfo(m_view->document()->url().toLocalFile()).absolutePath();
572 QString relativePath = QDir(basePath).relativeFilePath(path);
573 KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, source->name(), OPACITY_OPAQUE_U8);
574 fileLayer->setX(bounds.x());
575 fileLayer->setY(bounds.y());
576 KisNodeSP dstParent = source->parent();
577 KisNodeSP dstAboveThis = source->prevSibling();
578 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a file layer"));
579 m_commandsAdapter->removeNode(source);
580 m_commandsAdapter->addNode(fileLayer, dstParent, dstAboveThis);
581 m_commandsAdapter->endMacro();
582 }
583 doc->closeUrl(false);
584 }
585
adjustLayerPosition(KisNodeSP node,KisNodeSP activeNode,KisNodeSP & parent,KisNodeSP & above)586 void KisLayerManager::adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above)
587 {
588 Q_ASSERT(activeNode);
589
590 parent = activeNode;
591 above = parent->lastChild();
592
593 if (parent->inherits("KisGroupLayer") && parent->collapsed()) {
594 above = parent;
595 parent = parent->parent();
596 return;
597 }
598
599 while (parent &&
600 (!parent->allowAsChild(node) || !parent->isEditable(false))) {
601
602 above = parent;
603 parent = parent->parent();
604 }
605
606 if (!parent) {
607 warnKrita << "KisLayerManager::adjustLayerPosition:"
608 << "No node accepted newly created node";
609
610 parent = m_view->image()->root();
611 above = parent->lastChild();
612 }
613 }
614
addLayerCommon(KisNodeSP activeNode,KisNodeSP layer,bool updateImage,KisProcessingApplicator * applicator)615 void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisNodeSP layer, bool updateImage, KisProcessingApplicator *applicator)
616 {
617 KisNodeSP parent;
618 KisNodeSP above;
619 adjustLayerPosition(layer, activeNode, parent, above);
620
621 KisGroupLayer *group = dynamic_cast<KisGroupLayer*>(parent.data());
622 const bool parentForceUpdate = group && !group->projectionIsValid();
623 updateImage |= parentForceUpdate;
624
625 m_commandsAdapter->addNodeAsync(layer, parent, above, updateImage, updateImage, applicator);
626 }
627
addPaintLayer(KisNodeSP activeNode)628 KisLayerSP KisLayerManager::addPaintLayer(KisNodeSP activeNode)
629 {
630 KisImageWSP image = m_view->image();
631 KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName( i18n("Paint Layer") ), OPACITY_OPAQUE_U8, image->colorSpace());
632
633 addLayerCommon(activeNode, layer, false, 0);
634
635 return layer;
636 }
637
addGroupLayer(KisNodeSP activeNode)638 KisNodeSP KisLayerManager::addGroupLayer(KisNodeSP activeNode)
639 {
640 KisImageWSP image = m_view->image();
641 KisGroupLayerSP group = new KisGroupLayer(image.data(), image->nextLayerName( i18n("Group") ), OPACITY_OPAQUE_U8);
642 addLayerCommon(activeNode, group, false, 0);
643 return group;
644 }
645
addCloneLayer(KisNodeList nodes)646 KisNodeSP KisLayerManager::addCloneLayer(KisNodeList nodes)
647 {
648 KisImageWSP image = m_view->image();
649
650 KisNodeList filteredNodes = KisLayerUtils::sortAndFilterMergableInternalNodes(nodes, false);
651 if (filteredNodes.isEmpty()) return KisNodeSP();
652
653 KisNodeSP newAbove = filteredNodes.last();
654
655 KisNodeSP node, lastClonedNode;
656 Q_FOREACH (node, filteredNodes) {
657 lastClonedNode = new KisCloneLayer(qobject_cast<KisLayer*>(node.data()), image.data(), image->nextLayerName( i18n("Clone Layer") ), OPACITY_OPAQUE_U8);
658 addLayerCommon(newAbove, lastClonedNode, true, 0 );
659 }
660
661 return lastClonedNode;
662 }
663
addShapeLayer(KisNodeSP activeNode)664 KisNodeSP KisLayerManager::addShapeLayer(KisNodeSP activeNode)
665 {
666 if (!m_view) return 0;
667 if (!m_view->document()) return 0;
668
669 KisImageWSP image = m_view->image();
670 KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(i18n("Vector Layer")), OPACITY_OPAQUE_U8);
671
672 addLayerCommon(activeNode, layer, false, 0);
673
674 return layer;
675 }
676
addAdjustmentLayer(KisNodeSP activeNode)677 KisNodeSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode)
678 {
679 KisImageWSP image = m_view->image();
680
681 KisSelectionSP selection = m_view->selection();
682
683 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE,
684 KisImageSignalVector() << ModifiedSignal,
685 kundo2_i18n("Add Layer"));
686
687
688 KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection, &applicator);
689
690 KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original());
691
692 KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(i18n("Filter Layer")), i18n("New Filter Layer"), m_view, qApp->activeWindow());
693 dlg.resize(dlg.minimumSizeHint());
694
695 // ensure that the device may be free'd by the dialog
696 // when it is not needed anymore
697 previewDevice = 0;
698
699 if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) {
700 // XXX: add messagebox warning if there's no filter set!
701 applicator.cancel();
702 } else {
703 adjl->setName(dlg.layerName());
704 applicator.end();
705 }
706
707 return adjl;
708 }
709
addAdjustmentLayer(KisNodeSP activeNode,const QString & name,KisFilterConfigurationSP filter,KisSelectionSP selection,KisProcessingApplicator * applicator)710 KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode, const QString & name,
711 KisFilterConfigurationSP filter,
712 KisSelectionSP selection,
713 KisProcessingApplicator *applicator)
714 {
715 KisImageWSP image = m_view->image();
716 KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter, selection);
717 addLayerCommon(activeNode, layer, true, applicator);
718
719 return layer;
720 }
721
addGeneratorLayer(KisNodeSP activeNode,const QString & name,KisFilterConfigurationSP filter,KisSelectionSP selection,KisProcessingApplicator * applicator)722 KisGeneratorLayerSP KisLayerManager::addGeneratorLayer(KisNodeSP activeNode, const QString &name, KisFilterConfigurationSP filter, KisSelectionSP selection, KisProcessingApplicator *applicator)
723 {
724 KisImageWSP image = m_view->image();
725 auto layer = new KisGeneratorLayer(image, name, filter, selection);
726 addLayerCommon(activeNode, layer, true, applicator);
727
728 return layer;
729 }
730
addGeneratorLayer(KisNodeSP activeNode)731 KisNodeSP KisLayerManager::addGeneratorLayer(KisNodeSP activeNode)
732 {
733 KisImageWSP image = m_view->image();
734 KisSelectionSP selection = m_view->selection();
735 QColor currentForeground = m_view->canvasResourceProvider()->fgColor().toQColor();
736
737 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Add Layer"));
738
739 KisGeneratorLayerSP node = addGeneratorLayer(activeNode, QString(), nullptr, selection, &applicator);
740
741 KisDlgGeneratorLayer dlg(image->nextLayerName(i18n("Fill Layer")), m_view, m_view->mainWindow(), node, nullptr, applicator.getStroke());
742 KisFilterConfigurationSP defaultConfig = dlg.configuration();
743 defaultConfig->setProperty("color", currentForeground);
744 dlg.setConfiguration(defaultConfig);
745
746 if (dlg.exec() == QDialog::Accepted) {
747 node->setName(dlg.layerName());
748 applicator.end();
749 return node;
750 }
751 else {
752 applicator.cancel();
753 return nullptr;
754 }
755 }
756
flattenImage()757 void KisLayerManager::flattenImage()
758 {
759 KisImageSP image = m_view->image();
760
761 if (!m_view->blockUntilOperationsFinished(image)) return;
762
763 if (image) {
764 bool doIt = true;
765
766 if (image->nHiddenLayers() > 0) {
767 int answer = QMessageBox::warning(m_view->mainWindow(),
768 i18nc("@title:window", "Flatten Image"),
769 i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"),
770 QMessageBox::Yes | QMessageBox::No,
771 QMessageBox::No);
772
773 if (answer != QMessageBox::Yes) {
774 doIt = false;
775 }
776 }
777
778 if (doIt) {
779 image->flatten(m_view->activeNode());
780 }
781 }
782 }
783
isSelectionMask(KisNodeSP node)784 inline bool isSelectionMask(KisNodeSP node) {
785 return dynamic_cast<KisSelectionMask*>(node.data());
786 }
787
tryMergeSelectionMasks(KisNodeSP currentNode,KisImageSP image)788 bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image)
789 {
790 bool result = false;
791
792 KisNodeSP prevNode = currentNode->prevSibling();
793 if (isSelectionMask(currentNode) &&
794 prevNode && isSelectionMask(prevNode)) {
795
796 QList<KisNodeSP> mergedNodes;
797 mergedNodes.append(currentNode);
798 mergedNodes.append(prevNode);
799
800 image->mergeMultipleLayers(mergedNodes, currentNode);
801
802 result = true;
803 }
804
805 return result;
806 }
807
tryFlattenGroupLayer(KisNodeSP currentNode,KisImageSP image)808 bool tryFlattenGroupLayer(KisNodeSP currentNode, KisImageSP image)
809 {
810 bool result = false;
811
812 if (currentNode->inherits("KisGroupLayer")) {
813 KisGroupLayer *layer = qobject_cast<KisGroupLayer*>(currentNode.data());
814 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(layer, false);
815
816 image->flattenLayer(layer);
817 result = true;
818 }
819
820 return result;
821 }
822
mergeLayer()823 void KisLayerManager::mergeLayer()
824 {
825 KisImageSP image = m_view->image();
826 if (!image) return;
827
828 KisLayerSP layer = activeLayer();
829 if (!layer) return;
830
831 if (!m_view->blockUntilOperationsFinished(image)) return;
832
833 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
834
835 // check if all the layers are a part of a locked group
836 bool hasEditableLayer = false;
837 Q_FOREACH (KisNodeSP node, selectedNodes) {
838 if (node->isEditable(false)) {
839 hasEditableLayer = true;
840 break;
841 }
842 }
843
844 if (!hasEditableLayer) {
845 m_view->showFloatingMessage(
846 i18ncp("floating message in layer manager",
847 "Layer is locked ", "Layers are locked", selectedNodes.size()),
848 QIcon(), 2000, KisFloatingMessage::Low);
849 return;
850 }
851
852 if (selectedNodes.size() > 1) {
853 image->mergeMultipleLayers(selectedNodes, m_view->activeNode());
854 }
855
856 else if (tryMergeSelectionMasks(m_view->activeNode(), image)) {
857 // already done!
858 } else if (tryFlattenGroupLayer(m_view->activeNode(), image)) {
859 // already done!
860 } else {
861
862 if (!layer->prevSibling()) return;
863 KisLayer *prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
864 if (!prevLayer) return;
865 if (prevLayer->userLocked()) {
866 m_view->showFloatingMessage(
867 i18nc("floating message in layer manager",
868 "Layer is locked "),
869 QIcon(), 2000, KisFloatingMessage::Low);
870 }
871
872 else if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) {
873 image->mergeDown(layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
874 }
875 else {
876 const KisMetaData::MergeStrategy* strategy = KisMetaDataMergeStrategyChooserWidget::showDialog(m_view->mainWindow());
877 if (!strategy) return;
878 image->mergeDown(layer, strategy);
879 }
880 }
881
882 m_view->updateGUI();
883 }
884
flattenLayer()885 void KisLayerManager::flattenLayer()
886 {
887 KisImageSP image = m_view->image();
888 if (!image) return;
889
890 KisLayerSP layer = activeLayer();
891 if (!layer) return;
892
893 if (!m_view->blockUntilOperationsFinished(image)) return;
894 if (!m_view->nodeManager()->canModifyLayer(layer)) return;
895
896 convertNodeToPaintLayer(layer);
897 m_view->updateGUI();
898 }
899
rasterizeLayer()900 void KisLayerManager::rasterizeLayer()
901 {
902 KisImageSP image = m_view->image();
903 if (!image) return;
904
905 KisLayerSP layer = activeLayer();
906 if (!layer) return;
907
908 if (!m_view->blockUntilOperationsFinished(image)) return;
909 if (!m_view->nodeManager()->canModifyLayer(layer)) return;
910
911 KisPaintLayerSP paintLayer = new KisPaintLayer(image, layer->name(), layer->opacity());
912 KisPainter gc(paintLayer->paintDevice());
913 QRect rc = layer->projection()->exactBounds();
914 gc.bitBlt(rc.topLeft(), layer->projection(), rc);
915
916 m_commandsAdapter->beginMacro(kundo2_i18n("Rasterize Layer"));
917 m_commandsAdapter->addNode(paintLayer.data(), layer->parent().data(), layer.data());
918
919 int childCount = layer->childCount();
920 for (int i = 0; i < childCount; i++) {
921 m_commandsAdapter->moveNode(layer->firstChild(), paintLayer, paintLayer->lastChild());
922 }
923 m_commandsAdapter->removeNode(layer);
924 m_commandsAdapter->endMacro();
925 updateGUI();
926 }
927
928
layersUpdated()929 void KisLayerManager::layersUpdated()
930 {
931 KisLayerSP layer = activeLayer();
932 if (!layer) return;
933
934 m_view->updateGUI();
935 }
936
saveGroupLayers()937 void KisLayerManager::saveGroupLayers()
938 {
939 QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export);
940
941 KoDialog dlg;
942 QWidget *page = new QWidget(&dlg);
943 dlg.setMainWidget(page);
944 QBoxLayout *layout = new QVBoxLayout(page);
945
946 KisFileNameRequester *urlRequester = new KisFileNameRequester(page);
947 urlRequester->setMode(KoFileDialog::SaveFile);
948 if (m_view->document()->url().isLocalFile()) {
949 urlRequester->setStartDir(QFileInfo(m_view->document()->url().toLocalFile()).absolutePath());
950 }
951 urlRequester->setMimeTypeFilters(listMimeFilter);
952 urlRequester->setFileName(m_view->document()->url().toLocalFile());
953 layout->addWidget(urlRequester);
954
955 QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page);
956 chkInvisible->setChecked(false);
957 layout->addWidget(chkInvisible);
958 QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page);
959 chkDepth->setChecked(true);
960 layout->addWidget(chkDepth);
961
962 if (!dlg.exec()) return;
963
964 QString path = urlRequester->fileName();
965
966 if (path.isEmpty()) return;
967
968 QFileInfo f(path);
969
970 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName(), false);
971 if (mimeType.isEmpty()) {
972 mimeType = "image/png";
973 }
974 QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first();
975 QString basename = f.completeBaseName();
976
977 KisImageSP image = m_view->image();
978 if (!image) return;
979
980 KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType);
981 image->rootLayer()->accept(v);
982
983 }
984
activeLayerHasSelection()985 bool KisLayerManager::activeLayerHasSelection()
986 {
987 return (activeLayer()->selection() != 0);
988 }
989
addFileLayer(KisNodeSP activeNode)990 KisNodeSP KisLayerManager::addFileLayer(KisNodeSP activeNode)
991 {
992 QString basePath;
993 QUrl url = m_view->document()->url();
994 if (url.isLocalFile()) {
995 basePath = QFileInfo(url.toLocalFile()).absolutePath();
996 }
997 KisImageWSP image = m_view->image();
998
999 KisDlgFileLayer dlg(basePath, image->nextLayerName(i18n("File Layer")), m_view->mainWindow());
1000 dlg.resize(dlg.minimumSizeHint());
1001
1002 if (dlg.exec() == QDialog::Accepted) {
1003 QString name = dlg.layerName();
1004 QString fileName = dlg.fileName();
1005
1006 if(fileName.isEmpty()){
1007 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified"));
1008 return 0;
1009 }
1010
1011 KisFileLayer::ScalingMethod scalingMethod = dlg.scaleToImageResolution();
1012 KisNodeSP node = new KisFileLayer(image, basePath, fileName, scalingMethod, name, OPACITY_OPAQUE_U8);
1013 addLayerCommon(activeNode, node, true, 0);
1014 return node;
1015 }
1016 return 0;
1017 }
1018
updateLayerStyles(KisLayerSP layer,KisDlgLayerStyle * dlg)1019 void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg)
1020 {
1021 KisSetLayerStyleCommand::updateLayerStyle(layer, dlg->style()->clone());
1022 }
1023
layerStyle()1024 void KisLayerManager::layerStyle()
1025 {
1026 KisImageWSP image = m_view->image();
1027 if (!image) return;
1028
1029 KisLayerSP layer = activeLayer();
1030 if (!layer) return;
1031
1032 if (!m_view->blockUntilOperationsFinished(image)) return;
1033 if (!m_view->nodeManager()->canModifyLayer(layer)) return;
1034
1035 KisPSDLayerStyleSP oldStyle;
1036 if (layer->layerStyle()) {
1037 oldStyle = layer->layerStyle()->clone();
1038 }
1039 else {
1040 oldStyle = toQShared(new KisPSDLayerStyle());
1041 }
1042
1043 KisDlgLayerStyle dlg(oldStyle->clone(), m_view->canvasResourceProvider());
1044
1045 std::function<void ()> updateCall(std::bind(updateLayerStyles, layer, &dlg));
1046 SignalToFunctionProxy proxy(updateCall);
1047 connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start()));
1048
1049 if (dlg.exec() == QDialog::Accepted) {
1050 KisPSDLayerStyleSP newStyle = dlg.style();
1051
1052 KUndo2CommandSP command = toQShared(
1053 new KisSetLayerStyleCommand(layer, oldStyle, newStyle));
1054
1055 image->postExecutionUndoAdapter()->addCommand(command);
1056 }
1057 }
1058
1059