File indexing completed on 2024-05-12 16:01:33
0001 /* 0002 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "kis_layer_manager.h" 0009 0010 #include <QRect> 0011 #include <QApplication> 0012 #include <QCursor> 0013 #include <QString> 0014 #include <QDialog> 0015 #include <QVBoxLayout> 0016 #include <QFileInfo> 0017 #include <QStandardPaths> 0018 #include <QClipboard> 0019 #include <QMimeData> 0020 0021 #include <kactioncollection.h> 0022 #include <klocalizedstring.h> 0023 #include <QMessageBox> 0024 #include <QUrl> 0025 0026 #include <kis_file_name_requester.h> 0027 #include <kis_icon.h> 0028 #include <KisImportExportManager.h> 0029 #include <KisDocument.h> 0030 #include <KoColorSpace.h> 0031 #include <KoCompositeOpRegistry.h> 0032 #include <KoPointerEvent.h> 0033 #include <KoColorProfile.h> 0034 #include <KoSelection.h> 0035 #include <KisPart.h> 0036 #include <KisMainWindow.h> 0037 0038 #include <filter/kis_filter_configuration.h> 0039 #include <filter/kis_filter.h> 0040 #include <kis_filter_strategy.h> 0041 #include <generator/kis_generator_layer.h> 0042 #include <kis_file_layer.h> 0043 #include <kis_adjustment_layer.h> 0044 #include <kis_mask.h> 0045 #include <kis_clone_layer.h> 0046 #include <kis_group_layer.h> 0047 #include <kis_image.h> 0048 #include <kis_layer.h> 0049 #include <kis_paint_device.h> 0050 #include <kis_selection.h> 0051 #include <flake/kis_shape_layer.h> 0052 #include <kis_undo_adapter.h> 0053 #include <kis_painter.h> 0054 #include <kis_meta_data_store.h> 0055 #include <kis_meta_data_merge_strategy_registry.h> 0056 #include <kis_psd_layer_style.h> 0057 #include <KisMimeDatabase.h> 0058 #include <kis_clipboard.h> 0059 0060 #include "kis_config.h" 0061 #include "kis_cursor.h" 0062 #include "dialogs/kis_dlg_adj_layer_props.h" 0063 #include "dialogs/kis_dlg_adjustment_layer.h" 0064 #include "dialogs/kis_dlg_layer_properties.h" 0065 #include "dialogs/kis_dlg_generator_layer.h" 0066 #include "dialogs/kis_dlg_file_layer.h" 0067 #include "dialogs/kis_dlg_layer_style.h" 0068 #include "dialogs/KisDlgChangeCloneSource.h" 0069 #include "kis_filter_manager.h" 0070 #include "kis_node_visitor.h" 0071 #include "kis_paint_layer.h" 0072 #include "commands/kis_image_commands.h" 0073 #include "commands/kis_node_commands.h" 0074 #include <commands/KisNodeRenameCommand.h> 0075 #include "kis_change_file_layer_command.h" 0076 #include "kis_canvas_resource_provider.h" 0077 #include "kis_selection_manager.h" 0078 #include "kis_statusbar.h" 0079 #include "KisViewManager.h" 0080 #include "kis_zoom_manager.h" 0081 #include "canvas/kis_canvas2.h" 0082 #include "widgets/kis_meta_data_merge_strategy_chooser_widget.h" 0083 #include "widgets/kis_wdg_generator.h" 0084 #include "kis_progress_widget.h" 0085 #include "kis_node_commands_adapter.h" 0086 #include "kis_node_manager.h" 0087 #include "kis_action.h" 0088 #include "kis_action_manager.h" 0089 #include "kis_raster_keyframe_channel.h" 0090 #include "kis_signal_compressor_with_param.h" 0091 #include "kis_abstract_projection_plane.h" 0092 #include "commands_new/kis_set_layer_style_command.h" 0093 #include "kis_post_execution_undo_adapter.h" 0094 #include "kis_selection_mask.h" 0095 #include "kis_layer_utils.h" 0096 #include "lazybrush/kis_colorize_mask.h" 0097 #include "kis_processing_applicator.h" 0098 #include "kis_projection_leaf.h" 0099 #include "KisGlobalResourcesInterface.h" 0100 0101 #include "KisSaveGroupVisitor.h" 0102 #include <kis_asl_layer_style_serializer.h> 0103 0104 0105 KisLayerManager::KisLayerManager(KisViewManager * view) 0106 : m_view(view) 0107 , m_commandsAdapter(new KisNodeCommandsAdapter(m_view)) 0108 0109 { 0110 } 0111 0112 KisLayerManager::~KisLayerManager() 0113 { 0114 delete m_commandsAdapter; 0115 } 0116 0117 void KisLayerManager::setView(QPointer<KisView>view) 0118 { 0119 m_imageView = view; 0120 } 0121 0122 KisLayerSP KisLayerManager::activeLayer() 0123 { 0124 if (m_imageView) { 0125 return m_imageView->currentLayer(); 0126 } 0127 return 0; 0128 } 0129 0130 KisPaintDeviceSP KisLayerManager::activeDevice() 0131 { 0132 if (activeLayer()) { 0133 return activeLayer()->paintDevice(); 0134 } 0135 return 0; 0136 } 0137 0138 void KisLayerManager::activateLayer(KisLayerSP layer) 0139 { 0140 if (m_imageView) { 0141 layersUpdated(); 0142 if (layer) { 0143 m_view->canvasResourceProvider()->slotNodeActivated(layer.data()); 0144 } 0145 } 0146 } 0147 0148 0149 void KisLayerManager::setup(KisActionManager* actionManager) 0150 { 0151 m_imageFlatten = actionManager->createAction("flatten_image"); 0152 connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage())); 0153 0154 m_imageMergeLayer = actionManager->createAction("merge_layer"); 0155 connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer())); 0156 0157 m_flattenLayer = actionManager->createAction("flatten_layer"); 0158 connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer())); 0159 0160 m_groupLayersSave = actionManager->createAction("save_groups_as_images"); 0161 connect(m_groupLayersSave, SIGNAL(triggered()), this, SLOT(saveGroupLayers())); 0162 0163 m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated"); 0164 connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated())); 0165 0166 m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer"); 0167 connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer())); 0168 0169 KisAction *action = actionManager->createAction("trim_to_image"); 0170 connect(action, SIGNAL(triggered()), this, SLOT(trimToImage())); 0171 0172 m_layerStyle = actionManager->createAction("layer_style"); 0173 connect(m_layerStyle, SIGNAL(triggered()), this, SLOT(layerStyle())); 0174 0175 m_copyLayerStyle = actionManager->createAction("copy_layer_style"); 0176 connect(m_copyLayerStyle, SIGNAL(triggered()), this, SLOT(copyLayerStyle())); 0177 0178 m_pasteLayerStyle = actionManager->createAction("paste_layer_style"); 0179 connect(m_pasteLayerStyle, SIGNAL(triggered()), this, SLOT(pasteLayerStyle())); 0180 } 0181 0182 void KisLayerManager::updateGUI() 0183 { 0184 KisImageSP image = m_view->image(); 0185 KisLayerSP layer = activeLayer(); 0186 0187 const bool isGroupLayer = layer && layer->inherits("KisGroupLayer"); 0188 0189 m_imageMergeLayer->setText( 0190 isGroupLayer ? 0191 i18nc("@action:inmenu", "Merge Group") : 0192 i18nc("@action:inmenu", "Merge with Layer Below")); 0193 m_flattenLayer->setVisible(!isGroupLayer); 0194 0195 if (m_view->statusBar()) 0196 m_view->statusBar()->setProfile(image); 0197 } 0198 0199 void KisLayerManager::imageResizeToActiveLayer() 0200 { 0201 KisLayerSP layer; 0202 KisImageWSP image = m_view->image(); 0203 0204 if (image && (layer = activeLayer())) { 0205 QRect cropRect = layer->projection()->nonDefaultPixelArea(); 0206 if (!cropRect.isEmpty()) { 0207 image->cropImage(cropRect); 0208 } else { 0209 m_view->showFloatingMessage( 0210 i18nc("floating message in layer manager", 0211 "Layer is empty "), 0212 QIcon(), 2000, KisFloatingMessage::Low); 0213 } 0214 } 0215 } 0216 0217 void KisLayerManager::trimToImage() 0218 { 0219 KisImageWSP image = m_view->image(); 0220 if (image) { 0221 image->cropImage(image->bounds()); 0222 } 0223 } 0224 0225 void KisLayerManager::layerProperties() 0226 { 0227 if (!m_view) return; 0228 if (!m_view->document()) return; 0229 0230 KisLayerSP layer = activeLayer(); 0231 if (!layer) return; 0232 0233 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0234 const bool multipleLayersSelected = selectedNodes.size() > 1; 0235 0236 if (!m_view->nodeManager()->canModifyLayers(selectedNodes)) return; 0237 0238 KisAdjustmentLayerSP adjustmentLayer = KisAdjustmentLayerSP(dynamic_cast<KisAdjustmentLayer*>(layer.data())); 0239 KisGeneratorLayerSP generatorLayer = KisGeneratorLayerSP(dynamic_cast<KisGeneratorLayer*>(layer.data())); 0240 KisFileLayerSP fileLayer = KisFileLayerSP(dynamic_cast<KisFileLayer*>(layer.data())); 0241 0242 if (adjustmentLayer && !multipleLayersSelected) { 0243 0244 KisPaintDeviceSP dev = adjustmentLayer->projection(); 0245 0246 KisDlgAdjLayerProps dlg(adjustmentLayer, adjustmentLayer.data(), dev, m_view, adjustmentLayer->filter().data(), adjustmentLayer->name(), i18n("Filter Layer Properties"), m_view->mainWindow(), "dlgadjlayerprops"); 0247 dlg.resize(dlg.minimumSizeHint()); 0248 0249 0250 KisFilterConfigurationSP configBefore(adjustmentLayer->filter()); 0251 KIS_ASSERT_RECOVER_RETURN(configBefore); 0252 QString xmlBefore = configBefore->toXML(); 0253 0254 0255 if (dlg.exec() == QDialog::Accepted) { 0256 0257 adjustmentLayer->setName(dlg.layerName()); 0258 0259 KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); 0260 Q_ASSERT(configAfter); 0261 QString xmlAfter = configAfter->toXML(); 0262 0263 if(xmlBefore != xmlAfter) { 0264 KisChangeFilterCmd *cmd 0265 = new KisChangeFilterCmd(adjustmentLayer, 0266 configBefore->cloneWithResourcesSnapshot(), 0267 configAfter->cloneWithResourcesSnapshot()); 0268 // FIXME: check whether is needed 0269 cmd->redo(); 0270 m_view->undoAdapter()->addCommand(cmd); 0271 m_view->document()->setModified(true); 0272 } 0273 } 0274 else { 0275 KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); 0276 Q_ASSERT(configAfter); 0277 QString xmlAfter = configAfter->toXML(); 0278 0279 if(xmlBefore != xmlAfter) { 0280 adjustmentLayer->setFilter(configBefore->cloneWithResourcesSnapshot()); 0281 adjustmentLayer->setDirty(); 0282 } 0283 } 0284 } 0285 else if (generatorLayer && !multipleLayersSelected) { 0286 KisFilterConfigurationSP configBefore(generatorLayer->filter()); 0287 Q_ASSERT(configBefore); 0288 0289 KisDlgGeneratorLayer *dlg = new KisDlgGeneratorLayer(generatorLayer->name(), m_view, m_view->mainWindow(), generatorLayer, configBefore, KisStrokeId()); 0290 dlg->setWindowTitle(i18n("Fill Layer Properties")); 0291 dlg->setAttribute(Qt::WA_DeleteOnClose); 0292 0293 dlg->setConfiguration(configBefore.data()); 0294 0295 Qt::WindowFlags flags = dlg->windowFlags(); 0296 dlg->setWindowFlags(flags | Qt::Tool | Qt::Dialog); 0297 dlg->show(); 0298 0299 } 0300 else if (fileLayer && !multipleLayersSelected){ 0301 QString basePath = QFileInfo(m_view->document()->path()).absolutePath(); 0302 QString fileNameOld = fileLayer->fileName(); 0303 KisFileLayer::ScalingMethod scalingMethodOld = fileLayer->scalingMethod(); 0304 KisDlgFileLayer dlg(basePath, fileLayer->name(), m_view->mainWindow()); 0305 dlg.setCaption(i18n("File Layer Properties")); 0306 dlg.setFileName(fileNameOld); 0307 dlg.setScalingMethod(scalingMethodOld); 0308 0309 if (dlg.exec() == QDialog::Accepted) { 0310 const QString fileNameNew = dlg.fileName(); 0311 KisFileLayer::ScalingMethod scalingMethodNew = dlg.scaleToImageResolution(); 0312 0313 if(fileNameNew.isEmpty()){ 0314 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); 0315 return; 0316 } 0317 fileLayer->setName(dlg.layerName()); 0318 0319 if (fileNameOld!= fileNameNew || scalingMethodOld != scalingMethodNew) { 0320 KisChangeFileLayerCmd *cmd 0321 = new KisChangeFileLayerCmd(fileLayer, 0322 basePath, 0323 fileNameOld, 0324 scalingMethodOld, 0325 basePath, 0326 fileNameNew, 0327 scalingMethodNew); 0328 m_view->undoAdapter()->addCommand(cmd); 0329 } 0330 } 0331 } else { // If layer == normal painting layer, vector layer, or group layer 0332 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0333 0334 KisDlgLayerProperties *dialog = new KisDlgLayerProperties(selectedNodes, m_view, m_view->canvas()); 0335 dialog->resize(dialog->minimumSizeHint()); 0336 dialog->setAttribute(Qt::WA_DeleteOnClose); 0337 Qt::WindowFlags flags = dialog->windowFlags(); 0338 #ifdef Q_OS_ANDROID 0339 // a Qt::Tool window seems incapable of receiving keyboard focus 0340 dialog->setWindowFlags(flags | Qt::Dialog); 0341 #else 0342 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog); 0343 #endif 0344 dialog->show(); 0345 dialog->activateWindow(); 0346 } 0347 } 0348 0349 void KisLayerManager::changeCloneSource() 0350 { 0351 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0352 if (selectedNodes.isEmpty()) { 0353 return; 0354 } 0355 0356 QList<KisCloneLayerSP> cloneLayers; 0357 KisNodeSP node; 0358 Q_FOREACH (node, selectedNodes) { 0359 KisCloneLayerSP cloneLayer(qobject_cast<KisCloneLayer *>(node.data())); 0360 if (cloneLayer) { 0361 cloneLayers << cloneLayer; 0362 } 0363 } 0364 0365 if (cloneLayers.isEmpty()) { 0366 return; 0367 } 0368 0369 if (!m_view->nodeManager()->canModifyLayers(implicitCastList<KisNodeSP>(cloneLayers))) return; 0370 0371 KisDlgChangeCloneSource *dialog = new KisDlgChangeCloneSource(cloneLayers, m_view); 0372 dialog->setCaption(i18n("Change Clone Layer")); 0373 dialog->resize(dialog->minimumSizeHint()); 0374 dialog->setAttribute(Qt::WA_DeleteOnClose); 0375 Qt::WindowFlags flags = dialog->windowFlags(); 0376 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog); 0377 dialog->show(); 0378 dialog->activateWindow(); 0379 } 0380 0381 void KisLayerManager::copyLayerStyle() 0382 { 0383 KisImageSP image = m_view->image(); 0384 if (!image) return; 0385 0386 KisLayerSP layer = activeLayer(); 0387 if (!layer) return; 0388 0389 KisPSDLayerStyleSP layerStyle = layer->layerStyle(); 0390 if (!layerStyle) return; 0391 0392 KisAslLayerStyleSerializer serializer; 0393 serializer.setStyles(QVector<KisPSDLayerStyleSP>() << layerStyle); 0394 QString psdxml = serializer.formPsdXmlDocument().toString(); 0395 0396 if (!psdxml.isEmpty()) { 0397 QMimeData *mimeData = new QMimeData; 0398 0399 mimeData->setText(psdxml); 0400 mimeData->setData("application/x-krita-layer-style", psdxml.toUtf8()); 0401 0402 QGuiApplication::clipboard()->setMimeData(mimeData); 0403 } 0404 } 0405 0406 void KisLayerManager::pasteLayerStyle() 0407 { 0408 KisImageSP image = m_view->image(); 0409 if (!image) return; 0410 0411 KisLayerSP layer = activeLayer(); 0412 if (!layer) return; 0413 0414 QString aslXml; 0415 0416 if (KisClipboard::instance()->hasLayerStyles()) { 0417 aslXml = QString::fromUtf8(QGuiApplication::clipboard()->mimeData()->data("application/x-krita-layer-style")); 0418 } else { 0419 aslXml = QGuiApplication::clipboard()->text(); 0420 } 0421 0422 if (aslXml.isEmpty()) return; 0423 0424 QDomDocument aslDoc; 0425 if (!aslDoc.setContent(aslXml)) return; 0426 0427 KisAslLayerStyleSerializer serializer; 0428 serializer.registerPSDPattern(aslDoc); 0429 serializer.readFromPSDXML(aslDoc); 0430 0431 if (serializer.styles().size() != 1) return; 0432 0433 KisPSDLayerStyleSP newStyle = serializer.styles().first()->cloneWithResourcesSnapshot( 0434 KisGlobalResourcesInterface::instance(), 0435 m_view->canvasBase()->resourceManager()->canvasResourcesInterface()); 0436 KUndo2Command *cmd = new KisSetLayerStyleCommand(layer, layer->layerStyle(), newStyle); 0437 0438 KisProcessingApplicator::runSingleCommandStroke(image, cmd); 0439 image->waitForDone(); 0440 } 0441 0442 void KisLayerManager::convertNodeToPaintLayer(KisNodeSP source) 0443 { 0444 KisImageWSP image = m_view->image(); 0445 if (!image) return; 0446 0447 // this precondition must be checked at higher level 0448 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false)); 0449 0450 KisLayer *srcLayer = qobject_cast<KisLayer*>(source.data()); 0451 if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) { 0452 image->flattenLayer(srcLayer); 0453 return; 0454 } 0455 0456 KisLayerUtils::convertToPaintLayer(image, source); 0457 } 0458 0459 void KisLayerManager::convertGroupToAnimated() 0460 { 0461 KisGroupLayerSP group = dynamic_cast<KisGroupLayer*>(activeLayer().data()); 0462 if (group.isNull()) return; 0463 0464 if (!m_view->nodeManager()->canModifyLayer(group)) return; 0465 0466 KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), group->name(), OPACITY_OPAQUE_U8); 0467 animatedLayer->enableAnimation(); 0468 KisRasterKeyframeChannel *contentChannel = dynamic_cast<KisRasterKeyframeChannel*>( 0469 animatedLayer->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true)); 0470 KIS_ASSERT_RECOVER_RETURN(contentChannel); 0471 0472 KisNodeSP child = group->firstChild(); 0473 int time = 0; 0474 while (child) { 0475 contentChannel->importFrame(time, child->projection(), NULL); 0476 time++; 0477 0478 child = child->nextSibling(); 0479 } 0480 0481 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to an animated layer")); 0482 m_commandsAdapter->addNode(animatedLayer, group->parent(), group); 0483 m_commandsAdapter->removeNode(group); 0484 m_commandsAdapter->endMacro(); 0485 } 0486 0487 void KisLayerManager::convertLayerToFileLayer(KisNodeSP source) 0488 { 0489 KisImageSP image = m_view->image(); 0490 if (!image) return; 0491 0492 // this precondition must be checked at higher level 0493 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false)); 0494 0495 QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); 0496 0497 KoDialog dlg; 0498 QWidget *page = new QWidget(&dlg); 0499 dlg.setMainWidget(page); 0500 QBoxLayout *layout = new QVBoxLayout(page); 0501 dlg.setWindowTitle(i18n("Save layers to...")); 0502 QLabel *lbl = new QLabel(i18n("Choose the location where the layer will be saved to. The new file layer will then reference this location.")); 0503 lbl->setWordWrap(true); 0504 layout->addWidget(lbl); 0505 KisFileNameRequester *urlRequester = new KisFileNameRequester(page); 0506 urlRequester->setMode(KoFileDialog::SaveFile); 0507 urlRequester->setMimeTypeFilters(listMimeFilter); 0508 urlRequester->setFileName(m_view->document()->path()); 0509 if (!m_view->document()->path().isEmpty()) { 0510 QFileInfo location = QFileInfo(m_view->document()->path()).completeBaseName(); 0511 location.setFile(location.dir(), location.completeBaseName() + "_" + source->name() + ".png"); 0512 urlRequester->setFileName(location.absoluteFilePath()); 0513 } 0514 else { 0515 const QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); 0516 const QString proposedFileName = QDir(location.absoluteFilePath()).absoluteFilePath(source->name() + ".png"); 0517 urlRequester->setFileName(proposedFileName); 0518 } 0519 0520 layout->addWidget(urlRequester); 0521 if (!dlg.exec()) return; 0522 0523 QString path = urlRequester->fileName(); 0524 0525 if (path.isEmpty()) return; 0526 0527 QFileInfo f(path); 0528 0529 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName()); 0530 if (mimeType.isEmpty()) { 0531 mimeType = "image/png"; 0532 } 0533 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument()); 0534 0535 QRect bounds = source->exactBounds(); 0536 if (bounds.isEmpty()) { 0537 bounds = image->bounds(); 0538 } 0539 KisImageSP dst = new KisImage(doc->createUndoStore(), 0540 image->width(), 0541 image->height(), 0542 image->projection()->compositionSourceColorSpace(), 0543 source->name()); 0544 dst->setResolution(image->xRes(), image->yRes()); 0545 doc->setFileBatchMode(false); 0546 doc->setCurrentImage(dst); 0547 KisNodeSP node = source->clone(); 0548 dst->addNode(node); 0549 dst->initialRefreshGraph(); 0550 dst->cropImage(bounds); 0551 dst->waitForDone(); 0552 0553 bool r = doc->exportDocumentSync(path, mimeType.toLatin1()); 0554 if (!r) { 0555 0556 qWarning() << "Converting layer to file layer. path:"<< path << "gave errors" << doc->errorMessage(); 0557 } else { 0558 QString basePath = QFileInfo(m_view->document()->path()).absolutePath(); 0559 QString relativePath = QDir(basePath).relativeFilePath(path); 0560 KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, source->name(), OPACITY_OPAQUE_U8); 0561 fileLayer->setX(bounds.x()); 0562 fileLayer->setY(bounds.y()); 0563 KisNodeSP dstParent = source->parent(); 0564 KisNodeSP dstAboveThis = source->prevSibling(); 0565 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a file layer")); 0566 m_commandsAdapter->removeNode(source); 0567 m_commandsAdapter->addNode(fileLayer, dstParent, dstAboveThis); 0568 m_commandsAdapter->endMacro(); 0569 } 0570 doc->closePath(false); 0571 } 0572 0573 void KisLayerManager::adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above) 0574 { 0575 Q_ASSERT(activeNode); 0576 0577 parent = activeNode; 0578 above = parent->lastChild(); 0579 0580 if (parent->inherits("KisGroupLayer") && parent->collapsed()) { 0581 above = parent; 0582 parent = parent->parent(); 0583 return; 0584 } 0585 0586 while (parent && 0587 (!parent->allowAsChild(node) || !parent->isEditable(false))) { 0588 0589 above = parent; 0590 parent = parent->parent(); 0591 } 0592 0593 if (!parent) { 0594 warnKrita << "KisLayerManager::adjustLayerPosition:" 0595 << "No node accepted newly created node"; 0596 0597 parent = m_view->image()->root(); 0598 above = parent->lastChild(); 0599 } 0600 } 0601 0602 void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisNodeSP layer, bool updateImage, KisProcessingApplicator *applicator) 0603 { 0604 KisNodeSP parent; 0605 KisNodeSP above; 0606 adjustLayerPosition(layer, activeNode, parent, above); 0607 0608 KisGroupLayer *group = dynamic_cast<KisGroupLayer*>(parent.data()); 0609 const bool parentForceUpdate = group && !group->projectionIsValid(); 0610 updateImage |= parentForceUpdate; 0611 0612 m_commandsAdapter->addNodeAsync(layer, parent, above, updateImage, updateImage, applicator); 0613 } 0614 0615 KisLayerSP KisLayerManager::addPaintLayer(KisNodeSP activeNode) 0616 { 0617 KisImageWSP image = m_view->image(); 0618 KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName( i18n("Paint Layer") ), OPACITY_OPAQUE_U8, image->colorSpace()); 0619 0620 KisConfig cfg(true); 0621 layer->setPinnedToTimeline(cfg.autoPinLayersToTimeline()); 0622 0623 addLayerCommon(activeNode, layer, false, 0); 0624 0625 return layer; 0626 } 0627 0628 KisNodeSP KisLayerManager::addGroupLayer(KisNodeSP activeNode) 0629 { 0630 KisImageWSP image = m_view->image(); 0631 KisGroupLayerSP group = new KisGroupLayer(image.data(), image->nextLayerName( i18nc("A group of layers", "Group") ), OPACITY_OPAQUE_U8); 0632 addLayerCommon(activeNode, group, false, 0); 0633 return group; 0634 } 0635 0636 KisNodeSP KisLayerManager::addCloneLayer(KisNodeList nodes) 0637 { 0638 KisImageWSP image = m_view->image(); 0639 0640 KisNodeList filteredNodes = KisLayerUtils::sortAndFilterMergableInternalNodes(nodes, false); 0641 if (filteredNodes.isEmpty()) return KisNodeSP(); 0642 0643 KisNodeSP newAbove = filteredNodes.last(); 0644 0645 KisNodeSP node, lastClonedNode; 0646 Q_FOREACH (node, filteredNodes) { 0647 lastClonedNode = new KisCloneLayer(qobject_cast<KisLayer*>(node.data()), image.data(), image->nextLayerName( i18n("Clone Layer") ), OPACITY_OPAQUE_U8); 0648 addLayerCommon(newAbove, lastClonedNode, true, 0 ); 0649 } 0650 0651 return lastClonedNode; 0652 } 0653 0654 KisNodeSP KisLayerManager::addShapeLayer(KisNodeSP activeNode) 0655 { 0656 if (!m_view) return 0; 0657 if (!m_view->document()) return 0; 0658 0659 KisImageWSP image = m_view->image(); 0660 KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(i18n("Vector Layer")), OPACITY_OPAQUE_U8); 0661 0662 addLayerCommon(activeNode, layer, false, 0); 0663 0664 return layer; 0665 } 0666 0667 KisNodeSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode) 0668 { 0669 KisImageWSP image = m_view->image(); 0670 0671 KisSelectionSP selection = m_view->selection(); 0672 0673 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, 0674 KisImageSignalVector(), 0675 kundo2_i18n("Add Layer")); 0676 0677 0678 KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection, &applicator); 0679 0680 KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original()); 0681 0682 KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(i18n("Filter Layer")), i18n("New Filter Layer"), m_view, qApp->activeWindow()); 0683 dlg.resize(dlg.minimumSizeHint()); 0684 0685 // ensure that the device may be free'd by the dialog 0686 // when it is not needed anymore 0687 previewDevice = 0; 0688 0689 if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) { 0690 // XXX: add messagebox warning if there's no filter set! 0691 applicator.cancel(); 0692 } else { 0693 applicator.applyCommand(new KisNodeRenameCommand(adjl, adjl->name(), dlg.layerName())); 0694 applicator.end(); 0695 } 0696 0697 return adjl; 0698 } 0699 0700 KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode, const QString & name, 0701 KisFilterConfigurationSP filter, 0702 KisSelectionSP selection, 0703 KisProcessingApplicator *applicator) 0704 { 0705 KisImageWSP image = m_view->image(); 0706 KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter ? filter->cloneWithResourcesSnapshot() : 0, selection); 0707 addLayerCommon(activeNode, layer, true, applicator); 0708 0709 return layer; 0710 } 0711 0712 KisGeneratorLayerSP KisLayerManager::addGeneratorLayer(KisNodeSP activeNode, const QString &name, KisFilterConfigurationSP filter, KisSelectionSP selection, KisProcessingApplicator *applicator) 0713 { 0714 KisImageWSP image = m_view->image(); 0715 auto layer = new KisGeneratorLayer(image, name, filter, selection); 0716 addLayerCommon(activeNode, layer, true, applicator); 0717 0718 return layer; 0719 } 0720 0721 KisNodeSP KisLayerManager::addGeneratorLayer(KisNodeSP activeNode) 0722 { 0723 KisImageWSP image = m_view->image(); 0724 KisSelectionSP selection = m_view->selection(); 0725 QColor currentForeground = m_view->canvasResourceProvider()->fgColor().toQColor(); 0726 0727 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, KisImageSignalVector(), kundo2_i18n("Add Layer")); 0728 0729 KisGeneratorLayerSP node = addGeneratorLayer(activeNode, QString(), nullptr, selection, &applicator); 0730 0731 KisDlgGeneratorLayer dlg(image->nextLayerName(i18n("Fill Layer")), m_view, m_view->mainWindow(), node, nullptr, applicator.getStroke()); 0732 KisFilterConfigurationSP defaultConfig = dlg.configuration(); 0733 defaultConfig->setProperty("color", currentForeground); 0734 dlg.setConfiguration(defaultConfig); 0735 0736 if (dlg.exec() == QDialog::Accepted) { 0737 applicator.applyCommand(new KisNodeRenameCommand(node, node->name(), dlg.layerName())); 0738 applicator.end(); 0739 return node; 0740 } 0741 else { 0742 applicator.cancel(); 0743 return nullptr; 0744 } 0745 } 0746 0747 void KisLayerManager::flattenImage() 0748 { 0749 KisImageSP image = m_view->image(); 0750 0751 if (!m_view->blockUntilOperationsFinished(image)) return; 0752 0753 if (image) { 0754 bool doIt = true; 0755 0756 if (image->nHiddenLayers() > 0) { 0757 int answer = QMessageBox::warning(m_view->mainWindow(), 0758 i18nc("@title:window", "Flatten Image"), 0759 i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"), 0760 QMessageBox::Yes | QMessageBox::No, 0761 QMessageBox::No); 0762 0763 if (answer != QMessageBox::Yes) { 0764 doIt = false; 0765 } 0766 } 0767 0768 if (doIt) { 0769 image->flatten(m_view->activeNode()); 0770 } 0771 } 0772 } 0773 0774 inline bool isSelectionMask(KisNodeSP node) { 0775 return dynamic_cast<KisSelectionMask*>(node.data()); 0776 } 0777 0778 bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image) 0779 { 0780 bool result = false; 0781 0782 KisNodeSP prevNode = currentNode->prevSibling(); 0783 if (isSelectionMask(currentNode) && 0784 prevNode && isSelectionMask(prevNode)) { 0785 0786 QList<KisNodeSP> mergedNodes; 0787 mergedNodes.append(currentNode); 0788 mergedNodes.append(prevNode); 0789 0790 image->mergeMultipleLayers(mergedNodes, currentNode); 0791 0792 result = true; 0793 } 0794 0795 return result; 0796 } 0797 0798 bool tryFlattenGroupLayer(KisNodeSP currentNode, KisImageSP image) 0799 { 0800 bool result = false; 0801 0802 if (currentNode->inherits("KisGroupLayer")) { 0803 KisGroupLayer *layer = qobject_cast<KisGroupLayer*>(currentNode.data()); 0804 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(layer, false); 0805 0806 image->flattenLayer(layer); 0807 result = true; 0808 } 0809 0810 return result; 0811 } 0812 0813 void KisLayerManager::mergeLayer() 0814 { 0815 KisImageSP image = m_view->image(); 0816 if (!image) return; 0817 0818 KisLayerSP layer = activeLayer(); 0819 if (!layer) return; 0820 0821 if (!m_view->blockUntilOperationsFinished(image)) return; 0822 0823 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0824 0825 // check if all the layers are a part of a locked group 0826 bool hasEditableLayer = false; 0827 Q_FOREACH (KisNodeSP node, selectedNodes) { 0828 if (node->isEditable(false)) { 0829 hasEditableLayer = true; 0830 break; 0831 } 0832 } 0833 0834 if (!hasEditableLayer) { 0835 m_view->showFloatingMessage( 0836 i18ncp("floating message in layer manager", 0837 "Layer is locked", "Layers are locked", selectedNodes.size()), 0838 QIcon(), 2000, KisFloatingMessage::Low); 0839 return; 0840 } 0841 0842 if (selectedNodes.size() > 1) { 0843 image->mergeMultipleLayers(selectedNodes, m_view->activeNode()); 0844 } 0845 0846 else if (tryMergeSelectionMasks(m_view->activeNode(), image)) { 0847 // already done! 0848 } else if (tryFlattenGroupLayer(m_view->activeNode(), image)) { 0849 // already done! 0850 } else { 0851 0852 if (!layer->prevSibling()) return; 0853 KisLayer *prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data()); 0854 if (!prevLayer) return; 0855 if (prevLayer->userLocked()) { 0856 m_view->showFloatingMessage( 0857 i18nc("floating message in layer manager when previous layer is locked", 0858 "Layer is locked"), 0859 QIcon(), 2000, KisFloatingMessage::Low); 0860 } 0861 0862 else if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) { 0863 image->mergeDown(layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); 0864 } 0865 else { 0866 const KisMetaData::MergeStrategy* strategy = KisMetaDataMergeStrategyChooserWidget::showDialog(m_view->mainWindow()); 0867 if (!strategy) return; 0868 image->mergeDown(layer, strategy); 0869 } 0870 } 0871 0872 m_view->updateGUI(); 0873 } 0874 0875 void KisLayerManager::flattenLayer() 0876 { 0877 KisImageSP image = m_view->image(); 0878 if (!image) return; 0879 0880 KisLayerSP layer = activeLayer(); 0881 if (!layer) return; 0882 0883 if (!m_view->blockUntilOperationsFinished(image)) return; 0884 if (!m_view->nodeManager()->canModifyLayer(layer)) return; 0885 0886 convertNodeToPaintLayer(layer); 0887 m_view->updateGUI(); 0888 } 0889 0890 void KisLayerManager::layersUpdated() 0891 { 0892 KisLayerSP layer = activeLayer(); 0893 if (!layer) return; 0894 0895 m_view->updateGUI(); 0896 } 0897 0898 void KisLayerManager::saveGroupLayers() 0899 { 0900 QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); 0901 0902 KoDialog dlg; 0903 QWidget *page = new QWidget(&dlg); 0904 dlg.setMainWidget(page); 0905 QBoxLayout *layout = new QVBoxLayout(page); 0906 0907 KisFileNameRequester *urlRequester = new KisFileNameRequester(page); 0908 urlRequester->setMode(KoFileDialog::SaveFile); 0909 urlRequester->setStartDir(QFileInfo(m_view->document()->path()).absolutePath()); 0910 urlRequester->setMimeTypeFilters(listMimeFilter); 0911 urlRequester->setFileName(m_view->document()->path()); 0912 layout->addWidget(urlRequester); 0913 0914 QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page); 0915 chkInvisible->setChecked(false); 0916 layout->addWidget(chkInvisible); 0917 QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page); 0918 chkDepth->setChecked(true); 0919 layout->addWidget(chkDepth); 0920 0921 if (!dlg.exec()) return; 0922 0923 QString path = urlRequester->fileName(); 0924 0925 if (path.isEmpty()) return; 0926 0927 QFileInfo f(path); 0928 0929 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName(), false); 0930 if (mimeType.isEmpty()) { 0931 mimeType = "image/png"; 0932 } 0933 QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first(); 0934 QString basename = f.completeBaseName(); 0935 0936 KisImageSP image = m_view->image(); 0937 if (!image) return; 0938 0939 KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType); 0940 image->rootLayer()->accept(v); 0941 0942 } 0943 0944 bool KisLayerManager::activeLayerHasSelection() 0945 { 0946 return (activeLayer()->selection() != 0); 0947 } 0948 0949 KisNodeSP KisLayerManager::addFileLayer(KisNodeSP activeNode) 0950 { 0951 QString basePath; 0952 QString path = m_view->document()->path(); 0953 basePath = QFileInfo(path).absolutePath(); 0954 KisImageWSP image = m_view->image(); 0955 0956 KisDlgFileLayer dlg(basePath, image->nextLayerName(i18n("File Layer")), m_view->mainWindow()); 0957 dlg.resize(dlg.minimumSizeHint()); 0958 0959 if (dlg.exec() == QDialog::Accepted) { 0960 QString name = dlg.layerName(); 0961 QString fileName = dlg.fileName(); 0962 0963 if(fileName.isEmpty()){ 0964 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); 0965 return 0; 0966 } 0967 0968 KisFileLayer::ScalingMethod scalingMethod = dlg.scaleToImageResolution(); 0969 KisNodeSP node = new KisFileLayer(image, basePath, fileName, scalingMethod, name, OPACITY_OPAQUE_U8); 0970 addLayerCommon(activeNode, node, true, 0); 0971 return node; 0972 } 0973 return 0; 0974 } 0975 0976 void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg, KoCanvasResourcesInterfaceSP canvasResroucesInterface) 0977 { 0978 KisSetLayerStyleCommand::updateLayerStyle(layer, 0979 dlg->style()->cloneWithResourcesSnapshot( 0980 KisGlobalResourcesInterface::instance(), 0981 canvasResroucesInterface)); 0982 } 0983 0984 void KisLayerManager::layerStyle() 0985 { 0986 KisImageWSP image = m_view->image(); 0987 if (!image) return; 0988 0989 KisLayerSP layer = activeLayer(); 0990 if (!layer) return; 0991 0992 if (!m_view->blockUntilOperationsFinished(image)) return; 0993 if (!m_view->nodeManager()->canModifyLayer(layer)) return; 0994 0995 KoCanvasResourcesInterfaceSP canvasResroucesInterface = m_view->canvasBase()->resourceManager()->canvasResourcesInterface(); 0996 0997 KisPSDLayerStyleSP oldStyle; 0998 if (layer->layerStyle()) { 0999 oldStyle = layer->layerStyle()->clone().dynamicCast<KisPSDLayerStyle>(); 1000 1001 } else { 1002 oldStyle = toQShared(new KisPSDLayerStyle("", KisGlobalResourcesInterface::instance())) 1003 ->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(), 1004 canvasResroucesInterface); 1005 } 1006 1007 KisPSDLayerStyleSP newStyle = oldStyle->clone().dynamicCast<KisPSDLayerStyle>(); 1008 newStyle->setResourcesInterface(KisGlobalResourcesInterface::instance()); 1009 1010 KisDlgLayerStyle dlg(newStyle, m_view->canvasResourceProvider()); 1011 1012 std::function<void ()> updateCall(std::bind(updateLayerStyles, layer, &dlg, canvasResroucesInterface)); 1013 SignalToFunctionProxy proxy(updateCall); 1014 connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start())); 1015 1016 if (dlg.exec() == QDialog::Accepted) { 1017 KisPSDLayerStyleSP newStyle = 1018 dlg.style()->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(), 1019 canvasResroucesInterface); 1020 1021 KUndo2CommandSP command = toQShared( 1022 new KisSetLayerStyleCommand(layer, oldStyle, newStyle)); 1023 1024 image->postExecutionUndoAdapter()->addCommand(command); 1025 } 1026 } 1027