Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_layer_manager.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "kis_layer_manager.h"
9
10#include <QRect>
11#include <QApplication>
12#include <QCursor>
13#include <QString>
14#include <QDialog>
15#include <QVBoxLayout>
16#include <QFileInfo>
17#include <QStandardPaths>
18#include <QClipboard>
19#include <QMimeData>
20
21#include <kactioncollection.h>
22#include <klocalizedstring.h>
23#include <QMessageBox>
24#include <QUrl>
25
27#include <kis_icon.h>
29#include <KisDocument.h>
30#include <KoColorSpace.h>
32#include <KoPointerEvent.h>
33#include <KoColorProfile.h>
34#include <KoSelection.h>
35#include <KisPart.h>
36#include <KisMainWindow.h>
37
39#include <filter/kis_filter.h>
40#include <kis_filter_strategy.h>
42#include <kis_file_layer.h>
44#include <kis_mask.h>
45#include <kis_clone_layer.h>
46#include <kis_group_layer.h>
47#include <kis_image.h>
48#include <kis_layer.h>
49#include <kis_paint_device.h>
50#include <kis_selection.h>
52#include <kis_undo_adapter.h>
53#include <kis_painter.h>
54#include <kis_meta_data_store.h>
56#include <kis_psd_layer_style.h>
57#include <KisMimeDatabase.h>
58#include <kis_clipboard.h>
59
60#include "kis_config.h"
61#include "kis_cursor.h"
69#include "kis_filter_manager.h"
70#include "kis_node_visitor.h"
71#include "kis_paint_layer.h"
78#include "kis_statusbar.h"
79#include "KisViewManager.h"
80#include "kis_zoom_manager.h"
81#include "canvas/kis_canvas2.h"
84#include "kis_progress_widget.h"
86#include "kis_node_manager.h"
87#include "kis_action.h"
88#include "kis_action_manager.h"
94#include "kis_selection_mask.h"
95#include "kis_layer_utils.h"
98#include "kis_projection_leaf.h"
100
101#include "KisSaveGroupVisitor.h"
103
104
106 : m_view(view)
107 , m_commandsAdapter(new KisNodeCommandsAdapter(m_view))
108
109{
110}
111
116
121
123{
124 if (m_imageView) {
125 return m_imageView->currentLayer();
126 }
127 return 0;
128}
129
131{
132 if (activeLayer()) {
133 return activeLayer()->paintDevice();
134 }
135 return 0;
136}
137
139{
140 if (m_imageView) {
142 if (layer) {
144 }
145 }
146}
147
148
150{
151 m_imageFlatten = actionManager->createAction("flatten_image");
152 connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage()));
153
154 m_imageMergeLayer = actionManager->createAction("merge_layer");
155 connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer()));
156
157 m_flattenLayer = actionManager->createAction("flatten_layer");
158 connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer()));
159
160 m_groupLayersSave = actionManager->createAction("save_groups_as_images");
161 connect(m_groupLayersSave, SIGNAL(triggered()), this, SLOT(saveGroupLayers()));
162
163 m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated");
164 connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated()));
165
166 m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer");
167 connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer()));
168
169 KisAction *action = actionManager->createAction("trim_to_image");
170 connect(action, SIGNAL(triggered()), this, SLOT(trimToImage()));
171
172 action = actionManager->createAction("purge_unused_image_data");
173 connect(action, SIGNAL(triggered()), this, SLOT(purgeUnusedImageData()));
174
175 m_layerStyle = actionManager->createAction("layer_style");
176 connect(m_layerStyle, SIGNAL(triggered()), this, SLOT(layerStyle()));
177
178 m_copyLayerStyle = actionManager->createAction("copy_layer_style");
179 connect(m_copyLayerStyle, SIGNAL(triggered()), this, SLOT(copyLayerStyle()));
180
181 m_pasteLayerStyle = actionManager->createAction("paste_layer_style");
182 connect(m_pasteLayerStyle, SIGNAL(triggered()), this, SLOT(pasteLayerStyle()));
183}
184
186{
187 KisImageSP image = m_view->image();
188 KisLayerSP layer = activeLayer();
189
190 const bool isGroupLayer = layer && layer->inherits("KisGroupLayer");
191
192 QString mergeLayerText;
193 if (m_view->nodeManager()->selectedNodes().size() > 1) {
194 mergeLayerText = i18nc("@action:inmenu", "Merge Selected Layers");
195 } else if (isGroupLayer) {
196 mergeLayerText = i18nc("@action:inmenu", "Merge Group");
197 } else {
198 mergeLayerText = i18nc("@action:inmenu", "Merge with Layer Below");
199 }
200 m_imageMergeLayer->setText(mergeLayerText);
201
202 m_flattenLayer->setVisible(!isGroupLayer);
203
204 if (m_view->statusBar())
205 m_view->statusBar()->setProfile(image);
206}
207
209{
210 KisLayerSP layer;
211 KisImageWSP image = m_view->image();
212
213 if (image && (layer = activeLayer())) {
214 QRect cropRect = layer->projection()->nonDefaultPixelArea();
215 if (!cropRect.isEmpty()) {
216 image->cropImage(cropRect);
217 } else {
219 i18nc("floating message in layer manager",
220 "Layer is empty "),
221 QIcon(), 2000, KisFloatingMessage::Low);
222 }
223 }
224}
225
227{
228 KisImageWSP image = m_view->image();
229 if (image) {
230 image->cropImage(image->bounds());
231 }
232}
233
235{
236 KisImageWSP image = m_view->image();
237 if (image) {
238 image->purgeUnusedData(false);
239 }
240}
241
243{
244 if (!m_view) return;
245 if (!m_view->document()) return;
246
247 // For non-modal dialogs, only allow one instance of the dialog to exist.
248 // Modal dialogs won't set this.
250
251 KisLayerSP layer = activeLayer();
252 if (!layer) return;
253
254 const QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
255 const bool multipleLayersSelected = selectedNodes.size() > 1;
256
257 if (!m_view->nodeManager()->canModifyLayers(selectedNodes)) return;
258
259 KisAdjustmentLayerSP adjustmentLayer = KisAdjustmentLayerSP(dynamic_cast<KisAdjustmentLayer*>(layer.data()));
260 KisGeneratorLayerSP generatorLayer = KisGeneratorLayerSP(dynamic_cast<KisGeneratorLayer*>(layer.data()));
261 KisFileLayerSP fileLayer = KisFileLayerSP(dynamic_cast<KisFileLayer*>(layer.data()));
262
263 if (adjustmentLayer && !multipleLayersSelected) {
264 KisPaintDeviceSP dev = adjustmentLayer->projection();
265
266 KisDlgAdjLayerProps dlg(adjustmentLayer, adjustmentLayer.data(), dev, m_view, adjustmentLayer->filter().data(), adjustmentLayer->name(), i18n("Filter Layer Properties"), m_view->mainWindow(), "dlgadjlayerprops");
267 dlg.resize(dlg.minimumSizeHint());
268
269 KisFilterConfigurationSP configBefore(adjustmentLayer->filter());
270 KIS_ASSERT_RECOVER_RETURN(configBefore);
271 QString xmlBefore = configBefore->toXML();
272
273 if (dlg.exec() == QDialog::Accepted) {
274 KUndo2Command *cmd = nullptr;
275
277 Q_ASSERT(configAfter);
278 QString xmlAfter = configAfter->toXML();
279
280 if(xmlBefore != xmlAfter) {
282 new KisChangeFilterCmd(adjustmentLayer,
283 configBefore->cloneWithResourcesSnapshot(),
284 configAfter->cloneWithResourcesSnapshot()));
285 }
286
287 if (adjustmentLayer->name() != dlg.layerName()) {
289 new KisNodeRenameCommand(adjustmentLayer,
290 adjustmentLayer->name(),
291 dlg.layerName()));
292 }
293
294 if (cmd) {
296 }
297 }
298 else {
300 Q_ASSERT(configAfter);
301 QString xmlAfter = configAfter->toXML();
302
303 if(xmlBefore != xmlAfter) {
304 adjustmentLayer->setFilter(configBefore->cloneWithResourcesSnapshot());
305 adjustmentLayer->setDirty();
306 }
307 }
308 }
309 else if (fileLayer && !multipleLayersSelected){
310 QString basePath = QFileInfo(m_view->document()->path()).absolutePath();
311 QString fileNameOld = fileLayer->fileName();
312 KisFileLayer::ScalingMethod scalingMethodOld = fileLayer->scalingMethod();
313 QString scalingFilterOld = fileLayer->scalingFilter();
314 KisDlgFileLayer dlg(basePath, fileLayer->name(), m_view->mainWindow());
315 dlg.setCaption(i18n("File Layer Properties"));
316 dlg.setFileName(fileNameOld);
317 dlg.setScalingMethod(scalingMethodOld);
318 dlg.setScalingFilter(scalingFilterOld);
319
320 if (dlg.exec() == QDialog::Accepted) {
321 const QString fileNameNew = dlg.fileName();
323 QString scalingFilterNew = dlg.scalingFilter();
324
325 if(fileNameNew.isEmpty()){
326 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified"));
327 return;
328 }
329
330 KUndo2Command *cmd = nullptr;
331
332 if (fileNameOld != fileNameNew || scalingMethodOld != scalingMethodNew
333 || scalingFilterOld != scalingFilterNew) {
334
336 new KisChangeFileLayerCmd(fileLayer,
337 basePath,
338 fileNameOld,
339 scalingMethodOld,
340 scalingFilterOld,
341 basePath,
342 fileNameNew,
343 scalingMethodNew,
344 scalingFilterNew));
345 }
346
347 if (fileLayer->name() != dlg.layerName()) {
349 new KisNodeRenameCommand(fileLayer, fileLayer->name(), dlg.layerName()));
350 }
351
352 if (cmd) {
354 }
355 }
356 } else {
357 QDialog* dlg = nullptr;
358
359 if (generatorLayer && !multipleLayersSelected) {
360 KisFilterConfigurationSP configBefore(generatorLayer->filter());
361 Q_ASSERT(configBefore);
362
363 auto* genDlg = new KisDlgGeneratorLayer(generatorLayer->name(), m_view, m_view->canvas(), generatorLayer, configBefore, KisStrokeId());
364 genDlg->setWindowTitle(i18n("Fill Layer Properties"));
365 genDlg->setConfiguration(configBefore.data());
366
367 dlg = genDlg;
368 }
369
370 // Handle these layer(s) as normal painting layer, vector layer, or group layer
371 if (!dlg) {
372 dlg = new KisDlgLayerProperties(selectedNodes, m_view, m_view->canvas());
373 }
374
375 dlg->resize(dlg->minimumSizeHint());
376 dlg->setAttribute(Qt::WA_DeleteOnClose);
377
378 const Qt::WindowFlags flags = dlg->windowFlags();
379#ifdef Q_OS_ANDROID
380 // a Qt::Tool window seems incapable of receiving keyboard focus
381 dlg->setWindowFlags(flags | Qt::Dialog);
382#else
383 dlg->setWindowFlags(flags | Qt::Tool | Qt::Dialog);
384#endif
385 connect(dlg, SIGNAL(destroyed()), this, SLOT(layerPropertiesDialogClosed()));
387
388 dlg->show();
389 dlg->activateWindow();
390 }
391}
392
397
399{
400 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
401 if (selectedNodes.isEmpty()) {
402 return;
403 }
404
405 QList<KisCloneLayerSP> cloneLayers;
406 KisNodeSP node;
407 Q_FOREACH (node, selectedNodes) {
408 KisCloneLayerSP cloneLayer(qobject_cast<KisCloneLayer *>(node.data()));
409 if (cloneLayer) {
410 cloneLayers << cloneLayer;
411 }
412 }
413
414 if (cloneLayers.isEmpty()) {
415 return;
416 }
417
418 if (!m_view->nodeManager()->canModifyLayers(implicitCastList<KisNodeSP>(cloneLayers))) return;
419
420 KisDlgChangeCloneSource *dialog = new KisDlgChangeCloneSource(cloneLayers, m_view);
421 dialog->setCaption(i18n("Change Clone Layer"));
422 dialog->resize(dialog->minimumSizeHint());
423 dialog->setAttribute(Qt::WA_DeleteOnClose);
424 Qt::WindowFlags flags = dialog->windowFlags();
425 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog);
426 dialog->show();
427 dialog->activateWindow();
428}
429
431{
432 KisImageSP image = m_view->image();
433 if (!image) return;
434
435 KisLayerSP layer = activeLayer();
436 if (!layer) return;
437
439 if (!layerStyle) return;
440
443 QString psdxml = serializer.formPsdXmlDocument().toString();
444
445 if (!psdxml.isEmpty()) {
446 QMimeData *mimeData = new QMimeData;
447
448 mimeData->setText(psdxml);
449 mimeData->setData("application/x-krita-layer-style", psdxml.toUtf8());
450
451 QGuiApplication::clipboard()->setMimeData(mimeData);
452 }
453}
454
456{
457 KisImageSP image = m_view->image();
458 if (!image) return;
459
460 KisLayerSP layer = activeLayer();
461 if (!layer) return;
462
463 QString aslXml;
464
465 if (KisClipboard::instance()->hasLayerStyles()) {
466 aslXml = QString::fromUtf8(QGuiApplication::clipboard()->mimeData()->data("application/x-krita-layer-style"));
467 } else {
468 aslXml = QGuiApplication::clipboard()->text();
469 }
470
471 if (aslXml.isEmpty()) return;
472
473 QDomDocument aslDoc;
474 if (!aslDoc.setContent(aslXml)) return;
475
477 serializer.registerPSDPattern(aslDoc);
478 serializer.readFromPSDXML(aslDoc);
479
480 if (serializer.styles().size() != 1) return;
481
482 KisPSDLayerStyleSP newStyle = serializer.styles().first()->cloneWithResourcesSnapshot(
484 m_view->canvasBase()->resourceManager()->canvasResourcesInterface());
485 KUndo2Command *cmd = new KisSetLayerStyleCommand(layer, layer->layerStyle(), newStyle);
486
488 image->waitForDone();
489}
490
492{
493 KisImageWSP image = m_view->image();
494 if (!image) return;
495
496 // this precondition must be checked at higher level
497 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false));
498
499 KisLayer *srcLayer = qobject_cast<KisLayer*>(source.data());
500 if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) {
501 image->flattenLayer(srcLayer);
502 return;
503 }
504
506}
507
509{
510 KisGroupLayerSP targetGroup = dynamic_cast<KisGroupLayer*>(activeLayer().data());
511 if (targetGroup.isNull()) {
512 // Try containing group, if it exists...
513 KisNodeSP parent = activeLayer()->parent();
514 if (!parent->parent()) return; // watch out for the root node!
515 targetGroup = dynamic_cast<KisGroupLayer*>(parent.data());
516 }
517
518 if (targetGroup.isNull()) return;
519 if (!m_view->nodeManager()->canModifyLayer(targetGroup)) return;
520
521 KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), targetGroup->name(), OPACITY_OPAQUE_U8);
522 animatedLayer->enableAnimation();
523 KisRasterKeyframeChannel *keyframeChannel = dynamic_cast<KisRasterKeyframeChannel*>(
524 animatedLayer->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true));
525 KIS_ASSERT_RECOVER_RETURN(keyframeChannel);
526
527 KisNodeSP childNode = targetGroup->firstChild();
528 int time = 0;
529 while (childNode) {
530 keyframeChannel->importFrame(time, childNode->projection(), NULL);
531 time++;
532
533 childNode = childNode->nextSibling();
534 }
535
536 m_commandsAdapter->beginMacro(kundo2_i18n("Convert Group to Animated Layer"));
537 m_commandsAdapter->addNode(animatedLayer, targetGroup->parent(), targetGroup);
538 m_commandsAdapter->removeNode(targetGroup);
540}
541
543{
544 KisImageSP image = m_view->image();
545 if (!image) return;
546
547 // this precondition must be checked at higher level
548 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false));
549
551
552 KoDialog dlg;
553 QWidget *page = new QWidget(&dlg);
554 dlg.setMainWidget(page);
555 QBoxLayout *layout = new QVBoxLayout(page);
556 dlg.setWindowTitle(i18n("Save layers to..."));
557 QLabel *lbl = new QLabel(i18n("Choose the location where the layer will be saved to. The new file layer will then reference this location."));
558 lbl->setWordWrap(true);
559 layout->addWidget(lbl);
560 KisFileNameRequester *urlRequester = new KisFileNameRequester(page);
561 urlRequester->setMode(KoFileDialog::SaveFile);
562 urlRequester->setMimeTypeFilters(listMimeFilter);
563 urlRequester->setFileName(m_view->document()->path());
564 if (!m_view->document()->path().isEmpty()) {
565 QFileInfo location = QFileInfo(m_view->document()->path());
566 location.setFile(location.dir(), location.completeBaseName() + "_" + source->name() + ".png");
567 urlRequester->setFileName(location.absoluteFilePath());
568 }
569 else {
570 const QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
571 const QString proposedFileName = QDir(location.absoluteFilePath()).absoluteFilePath(source->name() + ".png");
572 urlRequester->setFileName(proposedFileName);
573 }
574
575 layout->addWidget(urlRequester);
576 if (!dlg.exec()) return;
577
578 QString path = urlRequester->fileName();
579
580 if (path.isEmpty()) return;
581
582 QFileInfo f(path);
583
584 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName());
585 if (mimeType.isEmpty()) {
586 mimeType = "image/png";
587 }
588 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
589
590 QRect bounds = source->exactBounds();
591 if (bounds.isEmpty()) {
592 bounds = image->bounds();
593 }
594 KisImageSP dst = new KisImage(doc->createUndoStore(),
595 image->width(),
596 image->height(),
598 source->name());
599 dst->setResolution(image->xRes(), image->yRes());
600 doc->setFileBatchMode(false);
601 doc->setCurrentImage(dst);
602 KisNodeSP node = source->clone();
603 dst->addNode(node);
604 dst->initialRefreshGraph();
605 dst->cropImage(bounds);
606 dst->waitForDone();
607
608 bool r = doc->exportDocumentSync(path, mimeType.toLatin1());
609 if (!r) {
610
611 qWarning() << "Converting layer to file layer. path:"<< path << "gave errors" << doc->errorMessage();
612 } else {
613 QString basePath = QFileInfo(m_view->document()->path()).absolutePath();
614 QString relativePath = QDir(basePath).relativeFilePath(path);
615 KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, "Bicubic", source->name(), OPACITY_OPAQUE_U8);
616 fileLayer->setX(bounds.x());
617 fileLayer->setY(bounds.y());
618 KisNodeSP dstParent = source->parent();
619 KisNodeSP dstAboveThis = source->prevSibling();
620 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a file layer"));
622 m_commandsAdapter->addNode(fileLayer, dstParent, dstAboveThis);
624 }
625 doc->closePath(false);
626}
627
629{
630 Q_ASSERT(activeNode);
631
632 parent = activeNode;
633 above = parent->lastChild();
634
635 if (parent->inherits("KisGroupLayer") && parent->collapsed()) {
636 above = parent;
637 parent = parent->parent();
638 return;
639 }
640
641 while (parent &&
642 (!parent->allowAsChild(node) || !parent->isEditable(false))) {
643
644 above = parent;
645 parent = parent->parent();
646 }
647
648 if (!parent) {
649 warnKrita << "KisLayerManager::adjustLayerPosition:"
650 << "No node accepted newly created node";
651
652 parent = m_view->image()->root();
653 above = parent->lastChild();
654 }
655}
656
657void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisNodeSP layer, bool updateImage, KisProcessingApplicator *applicator)
658{
659 KisNodeSP parent;
660 KisNodeSP above;
661 adjustLayerPosition(layer, activeNode, parent, above);
662
663 KisGroupLayer *group = dynamic_cast<KisGroupLayer*>(parent.data());
664
665 if (layer->inherits("KisGroupLayer") || layer->inherits("KisPaintLayer")) {
666 const KoColorSpace *colorSpace = group->colorSpace();
667
668 if (layer->inherits("KisGroupLayer")) {
669 KisGroupLayer *newLayer = dynamic_cast<KisGroupLayer*>(layer.data());
670 newLayer->resetCache(colorSpace);
671 } else {
672 KisPaintLayer *newLayer = qobject_cast<KisPaintLayer *>(layer.data());
673 newLayer->paintDevice()->convertTo(colorSpace);
674 }
675 }
676
677 const bool parentForceUpdate = group && !group->projectionIsValid();
678 updateImage |= parentForceUpdate;
679
680 m_commandsAdapter->addNodeAsync(layer, parent, above, updateImage, updateImage, applicator);
681}
682
684{
685 KisImageWSP image = m_view->image();
686 KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName( i18n("Paint Layer") ), OPACITY_OPAQUE_U8, image->colorSpace());
687
688 KisConfig cfg(true);
690
691 addLayerCommon(activeNode, layer, false, 0);
692
693 return layer;
694}
695
697{
698 KisImageWSP image = m_view->image();
699 KisGroupLayerSP group = new KisGroupLayer(image.data(), image->nextLayerName( i18nc("A group of layers", "Group") ), OPACITY_OPAQUE_U8);
700 addLayerCommon(activeNode, group, false, 0);
701 return group;
702}
703
705{
706 KisImageWSP image = m_view->image();
707
709 if (filteredNodes.isEmpty()) return KisNodeSP();
710
711 KisNodeSP newAbove = filteredNodes.last();
712
713 KisNodeSP node, lastClonedNode;
714 Q_FOREACH (node, filteredNodes) {
715 lastClonedNode = new KisCloneLayer(qobject_cast<KisLayer*>(node.data()), image.data(), image->nextLayerName( i18n("Clone Layer") ), OPACITY_OPAQUE_U8);
716 addLayerCommon(newAbove, lastClonedNode, true, 0 );
717 }
718
719 return lastClonedNode;
720}
721
723{
724 if (!m_view) return 0;
725 if (!m_view->document()) return 0;
726
727 KisImageWSP image = m_view->image();
728 KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(i18n("Vector Layer")), OPACITY_OPAQUE_U8);
729
730 addLayerCommon(activeNode, layer, false, 0);
731
732 return layer;
733}
734
736{
737 KisImageWSP image = m_view->image();
738
739 KisSelectionSP selection = m_view->selection();
740
743 kundo2_i18n("Add Layer"));
744
745
746 KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection, &applicator);
747 applicator.end();
748 image->waitForDone(); // So that previewDevice doesn't end up empty and result in empty histograms
749
750 KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original());
751
752 KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(i18n("Filter Layer")), i18n("New Filter Layer"), m_view, qApp->activeWindow());
753 dlg.resize(dlg.minimumSizeHint());
754
755 // ensure that the device may be free'd by the dialog
756 // when it is not needed anymore
757 previewDevice = 0;
758
759 if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) {
760 // XXX: add messagebox warning if there's no filter set!
762 } else {
763 adjl->setName(dlg.layerName());
764 }
765
766 return adjl;
767}
768
771 KisSelectionSP selection,
772 KisProcessingApplicator *applicator)
773{
774 KisImageWSP image = m_view->image();
775 KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter ? filter->cloneWithResourcesSnapshot() : 0, selection);
776 addLayerCommon(activeNode, layer, true, applicator);
777
778 return layer;
779}
780
782{
783 KisImageWSP image = m_view->image();
784 auto layer = new KisGeneratorLayer(image, name, filter, selection);
785 addLayerCommon(activeNode, layer, true, applicator);
786
787 return layer;
788}
789
791{
792 KisImageWSP image = m_view->image();
793 KisSelectionSP selection = m_view->selection();
794 QColor currentForeground = m_view->canvasResourceProvider()->fgColor().toQColor();
795
797
798 KisGeneratorLayerSP node = addGeneratorLayer(activeNode, QString(), nullptr, selection, &applicator);
799
800 KisDlgGeneratorLayer dlg(image->nextLayerName(i18n("Fill Layer")), m_view, m_view->mainWindow(), node, nullptr, applicator.getStroke());
801 KisFilterConfigurationSP defaultConfig = dlg.configuration();
802 defaultConfig->setProperty("color", currentForeground);
803 dlg.setConfiguration(defaultConfig);
804
805 if (dlg.exec() == QDialog::Accepted) {
806 applicator.applyCommand(new KisNodeRenameCommand(node, node->name(), dlg.layerName()));
807 applicator.end();
808 return node;
809 }
810 else {
811 applicator.cancel();
812 return nullptr;
813 }
814}
815
817{
818 KisImageSP image = m_view->image();
819
820 if (!m_view->blockUntilOperationsFinished(image)) return;
821
822 if (image) {
823 bool doIt = true;
824
825 if (image->nHiddenLayers() > 0) {
826 int answer = QMessageBox::warning(m_view->mainWindow(),
827 i18nc("@title:window", "Flatten Image"),
828 i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"),
829 QMessageBox::Yes | QMessageBox::No,
830 QMessageBox::No);
831
832 if (answer != QMessageBox::Yes) {
833 doIt = false;
834 }
835 }
836
837 if (doIt) {
838 image->flatten(m_view->activeNode());
839 }
840 }
841}
842
843inline bool isSelectionMask(KisNodeSP node) {
844 return dynamic_cast<KisSelectionMask*>(node.data());
845}
846
848{
849 bool result = false;
850
851 KisNodeSP prevNode = currentNode->prevSibling();
852 if (isSelectionMask(currentNode) &&
853 prevNode && isSelectionMask(prevNode)) {
854
855 QList<KisNodeSP> mergedNodes;
856 mergedNodes.append(currentNode);
857 mergedNodes.append(prevNode);
858
859 image->mergeMultipleLayers(mergedNodes, currentNode);
860
861 result = true;
862 }
863
864 return result;
865}
866
868{
869 bool result = false;
870
871 if (currentNode->inherits("KisGroupLayer")) {
872 KisGroupLayer *layer = qobject_cast<KisGroupLayer*>(currentNode.data());
874
875 image->flattenLayer(layer);
876 result = true;
877 }
878
879 return result;
880}
881
883{
884 KisImageSP image = m_view->image();
885 if (!image) return;
886
887 KisLayerSP layer = activeLayer();
888 if (!layer) return;
889
890 if (!m_view->blockUntilOperationsFinished(image)) return;
891
892 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes();
893
894 // check if all the layers are a part of a locked group
895 bool hasEditableLayer = false;
896 Q_FOREACH (KisNodeSP node, selectedNodes) {
897 if (node->isEditable(false)) {
898 hasEditableLayer = true;
899 break;
900 }
901 }
902
903 if (!hasEditableLayer) {
905 i18ncp("floating message in layer manager",
906 "Layer is locked", "Layers are locked", selectedNodes.size()),
907 QIcon(), 2000, KisFloatingMessage::Low);
908 return;
909 }
910
911 if (selectedNodes.size() > 1) {
912 image->mergeMultipleLayers(selectedNodes, m_view->activeNode());
913 }
914
915 else if (tryMergeSelectionMasks(m_view->activeNode(), image)) {
916 // already done!
917 } else if (tryFlattenGroupLayer(m_view->activeNode(), image)) {
918 // already done!
919 } else {
920
921 if (!layer->prevSibling()) return;
922 KisLayer *prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
923 if (!prevLayer) return;
924
925 if (prevLayer->userLocked()) {
927 i18nc("floating message in layer manager when previous layer is locked",
928 "Layer is locked"),
929 QIcon(), 2000, KisFloatingMessage::Low);
930 } else {
931 const KisMetaData::MergeStrategy* strategy = nullptr;
932
933 if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) {
935 }
936 else {
938 }
939
940 if (!strategy) return;
941
942 if (!layer->isAnimated() && prevLayer->isAnimated()) {
944 i18nc("floating message in layer manager when trying to merge a non-animated layer into an animated one",
945 "Non-animated layer is merged into the current frame. To merge it into the whole clip, create at least one frame"),
946 QIcon(), 5000, KisFloatingMessage::Medium);
947 }
948 image->mergeDown(layer, strategy);
949 }
950 }
951
952 m_view->updateGUI();
953}
954
956{
957 KisImageSP image = m_view->image();
958 if (!image) return;
959
960 KisLayerSP layer = activeLayer();
961 if (!layer) return;
962
963 if (!m_view->blockUntilOperationsFinished(image)) return;
964 if (!m_view->nodeManager()->canModifyLayer(layer)) return;
965
967 m_view->updateGUI();
968}
969
971{
972 KisLayerSP layer = activeLayer();
973 if (!layer) return;
974
975 m_view->updateGUI();
976}
977
979{
981
982 KoDialog dlg;
983 QWidget *page = new QWidget(&dlg);
984 dlg.setMainWidget(page);
985 QBoxLayout *layout = new QVBoxLayout(page);
986
987 KisFileNameRequester *urlRequester = new KisFileNameRequester(page);
988 urlRequester->setMode(KoFileDialog::SaveFile);
989 urlRequester->setStartDir(QFileInfo(m_view->document()->path()).absolutePath());
990 urlRequester->setMimeTypeFilters(listMimeFilter);
991 urlRequester->setFileName(m_view->document()->path());
992 layout->addWidget(urlRequester);
993
994 QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page);
995 chkInvisible->setChecked(false);
996 layout->addWidget(chkInvisible);
997 QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page);
998 chkDepth->setChecked(true);
999 layout->addWidget(chkDepth);
1000
1001 if (!dlg.exec()) return;
1002
1003 QString path = urlRequester->fileName();
1004
1005 if (path.isEmpty()) return;
1006
1007 QFileInfo f(path);
1008
1009 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName(), false);
1010 if (mimeType.isEmpty()) {
1011 mimeType = "image/png";
1012 }
1013 QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first();
1014 QString basename = f.completeBaseName();
1015
1016 KisImageSP image = m_view->image();
1017 if (!image) return;
1018
1019 KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType);
1020 image->rootLayer()->accept(v);
1021
1022}
1023
1025{
1026 return (activeLayer()->selection() != 0);
1027}
1028
1030{
1031 QString basePath;
1032 QString path = m_view->document()->path();
1033 basePath = QFileInfo(path).absolutePath();
1034 KisImageWSP image = m_view->image();
1035
1036 KisDlgFileLayer dlg(basePath, image->nextLayerName(i18n("File Layer")), m_view->mainWindow());
1037 dlg.resize(dlg.minimumSizeHint());
1038
1039 if (dlg.exec() == QDialog::Accepted) {
1040 QString name = dlg.layerName();
1041 QString fileName = dlg.fileName();
1042
1043 if(fileName.isEmpty()){
1044 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified"));
1045 return 0;
1046 }
1047
1049 QString scalingFilter = dlg.scalingFilter();
1050 KisNodeSP node = new KisFileLayer(image, basePath, fileName, scalingMethod, scalingFilter, name, OPACITY_OPAQUE_U8);
1051 addLayerCommon(activeNode, node, true, 0);
1052 return node;
1053 }
1054 return 0;
1055}
1056
1058{
1060 dlg->style()->cloneWithResourcesSnapshot(
1062 canvasResourcesInterface));
1063}
1064
1066{
1067 KisImageWSP image = m_view->image();
1068 if (!image) return;
1069
1070 KisLayerSP layer = activeLayer();
1071 if (!layer) return;
1072
1073 if (!m_view->blockUntilOperationsFinished(image)) return;
1074 if (!m_view->nodeManager()->canModifyLayer(layer)) return;
1075
1076 KoCanvasResourcesInterfaceSP canvasResourcesInterface = m_view->canvasBase()->resourceManager()->canvasResourcesInterface();
1077
1078 KisPSDLayerStyleSP oldStyle;
1079 if (layer->layerStyle()) {
1080 oldStyle = layer->layerStyle()->clone().dynamicCast<KisPSDLayerStyle>();
1081
1082 } else {
1084 ->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(),
1085 canvasResourcesInterface);
1086 }
1087
1088 KisPSDLayerStyleSP newStyle = oldStyle->clone().dynamicCast<KisPSDLayerStyle>();
1089 // We want to also change the UUID, else it might be considered the same style after save and won't load correctly
1090 newStyle->setUuid(QUuid::createUuid());
1091
1093
1094 std::function<void ()> updateCall(std::bind(updateLayerStyles, layer, &dlg, canvasResourcesInterface));
1095 SignalToFunctionProxy proxy(updateCall);
1096 connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start()));
1097
1098 if (dlg.exec() == QDialog::Accepted) {
1099 KisPSDLayerStyleSP newStyle =
1100 dlg.style()->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(),
1101 canvasResourcesInterface);
1102
1103 KUndo2CommandSP command = toQShared(
1104 new KisSetLayerStyleCommand(layer, oldStyle, newStyle));
1105
1106 image->postExecutionUndoAdapter()->addCommand(command);
1107 }
1108}
1109
qreal v
QVector< KisImageSignalType > KisImageSignalVector
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
const quint8 OPACITY_OPAQUE_U8
A KisActionManager class keeps track of KisActions. These actions are always associated with the GUI....
KisAction * createAction(const QString &name)
QVector< KisPSDLayerStyleSP > styles() const
void readFromPSDXML(const QDomDocument &doc)
void registerPSDPattern(const QDomDocument &doc)
void setStyles(const QVector< KisPSDLayerStyleSP > &styles)
void slotNodeActivated(const KisNodeSP node)
static KisClipboard * instance()
bool autoPinLayersToTimeline(bool defaultValue=false) const
KisFilterConfigurationSP filterConfiguration() const
void setScalingFilter(QString filter)
QString layerName() const
void setFileName(QString fileName)
KisFileLayer::ScalingMethod scaleToImageResolution() const
QString scalingFilter() const
void setScalingMethod(KisFileLayer::ScalingMethod method)
QString fileName() const
KisFilterConfigurationSP configuration() const
void setConfiguration(const KisFilterConfigurationSP config)
KisPSDLayerStyleSP style() const
KisShapeController * shapeController
QString path() const
The KisFileLayer class loads a particular file as a layer into the layer stack.
ScalingMethod scalingMethod() const
QString fileName() const
QString scalingFilter() const
void setStartDir(const QString &path)
void setMimeTypeFilters(const QStringList &filterList, QString defaultFilter=QString())
void setMode(KoFileDialog::DialogType mode)
void setFileName(const QString &path)
static KisResourcesInterfaceSP instance()
void waitForDone()
KisGroupLayerSP rootLayer() const
const KoColorSpace * colorSpace() const
void purgeUnusedData(bool isCancellable)
purge all pixels that have default pixel to free up memory
Definition kis_image.cc:875
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:715
void flattenLayer(KisLayerSP layer)
void flatten(KisNodeSP activeNode)
KisPaintDeviceSP projection() const
qint32 width() const
KisPostExecutionUndoAdapter * postExecutionUndoAdapter() const override
qint32 nHiddenLayers() const
void cropImage(const QRect &newRect)
start asynchronous operation on cropping the image
Definition kis_image.cc:870
void initialRefreshGraph()
double xRes() const
double yRes() const
qint32 height() const
void mergeMultipleLayers(QList< KisNodeSP > mergedLayers, KisNodeSP putAfter)
void mergeDown(KisLayerSP l, const KisMetaData::MergeStrategy *strategy)
QRect bounds() const override
void setResolution(double xres, double yres)
static QStringList supportedMimeTypes(Direction direction)
static const KoID Raster
void addLayerCommon(KisNodeSP activeNode, KisNodeSP layer, bool updateImage=true, KisProcessingApplicator *applicator=0)
KisNodeSP addShapeLayer(KisNodeSP activeNode)
KisNodeSP addGeneratorLayer(KisNodeSP activeNode)
void setView(QPointer< KisView >view)
KisNodeSP addFileLayer(KisNodeSP activeNode)
KisAction * m_imageResizeToLayer
void activateLayer(KisLayerSP layer)
KisLayerManager(KisViewManager *view)
void adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above)
KisPaintDeviceSP activeDevice()
KisAction * m_copyLayerStyle
KisLayerSP activeLayer()
KisAction * m_layerStyle
void setup(KisActionManager *actionManager)
void convertLayerToFileLayer(KisNodeSP source)
KisLayerSP addPaintLayer(KisNodeSP activeNode)
KisAction * m_flattenLayer
KisAction * m_convertGroupAnimated
KisNodeSP addGroupLayer(KisNodeSP activeNode)
KisNodeSP addCloneLayer(KisNodeList nodes)
KisAction * m_imageFlatten
QPointer< KisView > m_imageView
void convertNodeToPaintLayer(KisNodeSP source)
KisAction * m_pasteLayerStyle
KisViewManager * m_view
KisAction * m_imageMergeLayer
KisAction * m_groupLayersSave
~KisLayerManager() override
KisNodeSP addAdjustmentLayer(KisNodeSP activeNode)
KisNodeCommandsAdapter * m_commandsAdapter
static const KisMetaData::MergeStrategy * showDialog(QWidget *parent)
static QStringList suffixesForMimeType(const QString &mimeType)
static QString mimeTypeForFile(const QString &file, bool checkExistingFiles=true)
Find the mimetype for the given filename. The filename must include a suffix.
void addNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis, KisImageLayerAddCommand::Flags flags=KisImageLayerAddCommand::DoRedoUpdates|KisImageLayerAddCommand::DoUndoUpdates)
void addNodeAsync(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis, bool doRedoUpdates=true, bool doUndoUpdates=true, KisProcessingApplicator *applicator=0)
void beginMacro(const KUndo2MagicString &macroName)
virtual KisFilterConfigurationSP filter() const
KisNodeList selectedNodes()
bool canModifyLayers(KisNodeList nodes, bool showWarning=true)
bool canModifyLayer(KisNodeSP node, bool showWarning=true)
The command for setting the node's name.
QRect nonDefaultPixelArea() const
virtual const KoColorSpace * compositionSourceColorSpace() const
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
static KisPart * instance()
Definition KisPart.cpp:131
static void runSingleCommandStroke(KisImageSP image, KUndo2Command *cmd, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
runSingleCommandStroke creates a stroke and runs cmd in it. The text() field of cmd is used as a titl...
const KisStrokeId getStroke() const
void applyCommand(KUndo2Command *command, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
void importFrame(int time, KisPaintDeviceSP sourceDevice, KUndo2Command *parentCommand)
The KisSaveGroupVisitor class saves the groups in a Krita image to separate images.
static void updateLayerStyle(KisLayerSP layer, KisPSDLayerStyleSP style)
bool isNull() const
void setProfile(KisImageWSP image)
virtual void addCommand(KUndo2Command *cmd)=0
bool blockUntilOperationsFinished(KisImageSP image)
blockUntilOperationsFinished blocks the GUI of the application until execution of actions on image is...
KisMainWindow * mainWindow() const
KisDocument * document() const
KisCanvas2 * canvasBase() const
Return the canvas base class.
KisNodeSP activeNode()
KisUndoAdapter * undoAdapter()
The undo adapter is used to add commands to the undo stack.
KisSelectionSP selection()
QWidget * canvas() const
Return the actual widget that is displaying the current image.
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.
KisImageWSP image() const
Return the image this view is displaying.
KisCanvasResourceProvider * canvasResourceProvider()
KisStatusBar * statusBar() const
Return the wrapper class around the statusbar.
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
QPointer< KoCanvasResourceProvider > resourceManager
void toQColor(QColor *c) const
a convenience method for the above.
Definition KoColor.cpp:198
A dialog base class with standard buttons and predefined layouts.
Definition KoDialog.h:116
void setMainWidget(QWidget *widget)
Definition KoDialog.cpp:354
virtual void setCaption(const QString &caption)
Definition KoDialog.cpp:498
QSize minimumSizeHint() const override
Definition KoDialog.cpp:391
T get(const QString &id) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define bounds(x, a, b)
#define warnKrita
Definition kis_debug.h:87
bool isSelectionMask(KisNodeSP node)
void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg, KoCanvasResourcesInterfaceSP canvasResourcesInterface)
bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image)
bool tryFlattenGroupLayer(KisNodeSP currentNode, KisImageSP image)
KisDocument * createDocument(QList< KisNodeSP > nodes, KisImageSP srcImage, const QRect &copiedBounds)
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
QSharedPointer< T > toQShared(T *ptr)
KisSharedPtr< KisFileLayer > KisFileLayerSP
Definition kis_types.h:145
KisSharedPtr< KisAdjustmentLayer > KisAdjustmentLayerSP
Definition kis_types.h:131
KisSharedPtr< KisGeneratorLayer > KisGeneratorLayerSP
Definition kis_types.h:134
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
KUndo2MagicString kundo2_i18n(const char *text)
KUndo2Command * composeCommands(KUndo2Command *parent, KUndo2Command *cmd)
KisNodeList sortAndFilterMergeableInternalNodes(KisNodeList nodes, bool allowMasks)
std::future< KisNodeSP > convertToPaintLayer(KisImageSP image, KisNodeSP src)
void setPinnedToTimeline(bool pinned)
virtual KisPaintDeviceSP projection() const =0
bool isEditable(bool checkVisibility=true) const
KisKeyframeChannel * getKeyframeChannel(const QString &id, bool create)
bool userLocked() const
bool isAnimated() const
virtual KisPaintDeviceSP paintDevice() const =0
QString name() const
void enableAnimation()
bool projectionIsValid() const
const KoColorSpace * colorSpace() const override
bool accept(KisNodeVisitor &v) override
void resetCache(const KoColorSpace *colorSpace)
KisPaintDeviceSP projection() const override
Definition kis_layer.cc:826
KisMetaData::Store * metaData()
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171
void setX(qint32 x) override
Definition kis_layer.cc:986
void setY(qint32 y) override
Definition kis_layer.cc:992
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
KisNodeSP prevSibling() const
Definition kis_node.cpp:402
KisNodeSP firstChild() const
Definition kis_node.cpp:361
quint32 childCount() const
Definition kis_node.cpp:414
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP nextSibling() const
Definition kis_node.cpp:408
The KisPSDLayerStyle class implements loading, saving and applying the PSD layer effects.
KisPaintDeviceSP paintDevice