File indexing completed on 2024-05-19 04:28:58
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 QString scalingFilterOld = fileLayer->scalingFilter(); 0305 KisDlgFileLayer dlg(basePath, fileLayer->name(), m_view->mainWindow()); 0306 dlg.setCaption(i18n("File Layer Properties")); 0307 dlg.setFileName(fileNameOld); 0308 dlg.setScalingMethod(scalingMethodOld); 0309 dlg.setScalingFilter(scalingFilterOld); 0310 0311 if (dlg.exec() == QDialog::Accepted) { 0312 const QString fileNameNew = dlg.fileName(); 0313 KisFileLayer::ScalingMethod scalingMethodNew = dlg.scaleToImageResolution(); 0314 QString scalingFilterNew = dlg.scalingFilter(); 0315 0316 if(fileNameNew.isEmpty()){ 0317 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); 0318 return; 0319 } 0320 fileLayer->setName(dlg.layerName()); 0321 0322 if (fileNameOld!= fileNameNew || scalingMethodOld != scalingMethodNew || scalingFilterOld != scalingFilterNew) { 0323 KisChangeFileLayerCmd *cmd 0324 = new KisChangeFileLayerCmd(fileLayer, 0325 basePath, 0326 fileNameOld, 0327 scalingMethodOld, 0328 scalingFilterOld, 0329 basePath, 0330 fileNameNew, 0331 scalingMethodNew, 0332 scalingFilterNew); 0333 m_view->undoAdapter()->addCommand(cmd); 0334 } 0335 } 0336 } else { // If layer == normal painting layer, vector layer, or group layer 0337 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0338 0339 KisDlgLayerProperties *dialog = new KisDlgLayerProperties(selectedNodes, m_view, m_view->canvas()); 0340 dialog->resize(dialog->minimumSizeHint()); 0341 dialog->setAttribute(Qt::WA_DeleteOnClose); 0342 Qt::WindowFlags flags = dialog->windowFlags(); 0343 #ifdef Q_OS_ANDROID 0344 // a Qt::Tool window seems incapable of receiving keyboard focus 0345 dialog->setWindowFlags(flags | Qt::Dialog); 0346 #else 0347 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog); 0348 #endif 0349 dialog->show(); 0350 dialog->activateWindow(); 0351 } 0352 } 0353 0354 void KisLayerManager::changeCloneSource() 0355 { 0356 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0357 if (selectedNodes.isEmpty()) { 0358 return; 0359 } 0360 0361 QList<KisCloneLayerSP> cloneLayers; 0362 KisNodeSP node; 0363 Q_FOREACH (node, selectedNodes) { 0364 KisCloneLayerSP cloneLayer(qobject_cast<KisCloneLayer *>(node.data())); 0365 if (cloneLayer) { 0366 cloneLayers << cloneLayer; 0367 } 0368 } 0369 0370 if (cloneLayers.isEmpty()) { 0371 return; 0372 } 0373 0374 if (!m_view->nodeManager()->canModifyLayers(implicitCastList<KisNodeSP>(cloneLayers))) return; 0375 0376 KisDlgChangeCloneSource *dialog = new KisDlgChangeCloneSource(cloneLayers, m_view); 0377 dialog->setCaption(i18n("Change Clone Layer")); 0378 dialog->resize(dialog->minimumSizeHint()); 0379 dialog->setAttribute(Qt::WA_DeleteOnClose); 0380 Qt::WindowFlags flags = dialog->windowFlags(); 0381 dialog->setWindowFlags(flags | Qt::Tool | Qt::Dialog); 0382 dialog->show(); 0383 dialog->activateWindow(); 0384 } 0385 0386 void KisLayerManager::copyLayerStyle() 0387 { 0388 KisImageSP image = m_view->image(); 0389 if (!image) return; 0390 0391 KisLayerSP layer = activeLayer(); 0392 if (!layer) return; 0393 0394 KisPSDLayerStyleSP layerStyle = layer->layerStyle(); 0395 if (!layerStyle) return; 0396 0397 KisAslLayerStyleSerializer serializer; 0398 serializer.setStyles(QVector<KisPSDLayerStyleSP>() << layerStyle); 0399 QString psdxml = serializer.formPsdXmlDocument().toString(); 0400 0401 if (!psdxml.isEmpty()) { 0402 QMimeData *mimeData = new QMimeData; 0403 0404 mimeData->setText(psdxml); 0405 mimeData->setData("application/x-krita-layer-style", psdxml.toUtf8()); 0406 0407 QGuiApplication::clipboard()->setMimeData(mimeData); 0408 } 0409 } 0410 0411 void KisLayerManager::pasteLayerStyle() 0412 { 0413 KisImageSP image = m_view->image(); 0414 if (!image) return; 0415 0416 KisLayerSP layer = activeLayer(); 0417 if (!layer) return; 0418 0419 QString aslXml; 0420 0421 if (KisClipboard::instance()->hasLayerStyles()) { 0422 aslXml = QString::fromUtf8(QGuiApplication::clipboard()->mimeData()->data("application/x-krita-layer-style")); 0423 } else { 0424 aslXml = QGuiApplication::clipboard()->text(); 0425 } 0426 0427 if (aslXml.isEmpty()) return; 0428 0429 QDomDocument aslDoc; 0430 if (!aslDoc.setContent(aslXml)) return; 0431 0432 KisAslLayerStyleSerializer serializer; 0433 serializer.registerPSDPattern(aslDoc); 0434 serializer.readFromPSDXML(aslDoc); 0435 0436 if (serializer.styles().size() != 1) return; 0437 0438 KisPSDLayerStyleSP newStyle = serializer.styles().first()->cloneWithResourcesSnapshot( 0439 KisGlobalResourcesInterface::instance(), 0440 m_view->canvasBase()->resourceManager()->canvasResourcesInterface()); 0441 KUndo2Command *cmd = new KisSetLayerStyleCommand(layer, layer->layerStyle(), newStyle); 0442 0443 KisProcessingApplicator::runSingleCommandStroke(image, cmd); 0444 image->waitForDone(); 0445 } 0446 0447 void KisLayerManager::convertNodeToPaintLayer(KisNodeSP source) 0448 { 0449 KisImageWSP image = m_view->image(); 0450 if (!image) return; 0451 0452 // this precondition must be checked at higher level 0453 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false)); 0454 0455 KisLayer *srcLayer = qobject_cast<KisLayer*>(source.data()); 0456 if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) { 0457 image->flattenLayer(srcLayer); 0458 return; 0459 } 0460 0461 (void) KisLayerUtils::convertToPaintLayer(image, source); 0462 } 0463 0464 void KisLayerManager::convertGroupToAnimated() 0465 { 0466 KisGroupLayerSP group = dynamic_cast<KisGroupLayer*>(activeLayer().data()); 0467 if (group.isNull()) return; 0468 0469 if (!m_view->nodeManager()->canModifyLayer(group)) return; 0470 0471 KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), group->name(), OPACITY_OPAQUE_U8); 0472 animatedLayer->enableAnimation(); 0473 KisRasterKeyframeChannel *contentChannel = dynamic_cast<KisRasterKeyframeChannel*>( 0474 animatedLayer->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true)); 0475 KIS_ASSERT_RECOVER_RETURN(contentChannel); 0476 0477 KisNodeSP child = group->firstChild(); 0478 int time = 0; 0479 while (child) { 0480 contentChannel->importFrame(time, child->projection(), NULL); 0481 time++; 0482 0483 child = child->nextSibling(); 0484 } 0485 0486 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to an animated layer")); 0487 m_commandsAdapter->addNode(animatedLayer, group->parent(), group); 0488 m_commandsAdapter->removeNode(group); 0489 m_commandsAdapter->endMacro(); 0490 } 0491 0492 void KisLayerManager::convertLayerToFileLayer(KisNodeSP source) 0493 { 0494 KisImageSP image = m_view->image(); 0495 if (!image) return; 0496 0497 // this precondition must be checked at higher level 0498 KIS_SAFE_ASSERT_RECOVER_RETURN(source->isEditable(false)); 0499 0500 QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); 0501 0502 KoDialog dlg; 0503 QWidget *page = new QWidget(&dlg); 0504 dlg.setMainWidget(page); 0505 QBoxLayout *layout = new QVBoxLayout(page); 0506 dlg.setWindowTitle(i18n("Save layers to...")); 0507 QLabel *lbl = new QLabel(i18n("Choose the location where the layer will be saved to. The new file layer will then reference this location.")); 0508 lbl->setWordWrap(true); 0509 layout->addWidget(lbl); 0510 KisFileNameRequester *urlRequester = new KisFileNameRequester(page); 0511 urlRequester->setMode(KoFileDialog::SaveFile); 0512 urlRequester->setMimeTypeFilters(listMimeFilter); 0513 urlRequester->setFileName(m_view->document()->path()); 0514 if (!m_view->document()->path().isEmpty()) { 0515 QFileInfo location = QFileInfo(m_view->document()->path()).completeBaseName(); 0516 location.setFile(location.dir(), location.completeBaseName() + "_" + source->name() + ".png"); 0517 urlRequester->setFileName(location.absoluteFilePath()); 0518 } 0519 else { 0520 const QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); 0521 const QString proposedFileName = QDir(location.absoluteFilePath()).absoluteFilePath(source->name() + ".png"); 0522 urlRequester->setFileName(proposedFileName); 0523 } 0524 0525 layout->addWidget(urlRequester); 0526 if (!dlg.exec()) return; 0527 0528 QString path = urlRequester->fileName(); 0529 0530 if (path.isEmpty()) return; 0531 0532 QFileInfo f(path); 0533 0534 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName()); 0535 if (mimeType.isEmpty()) { 0536 mimeType = "image/png"; 0537 } 0538 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument()); 0539 0540 QRect bounds = source->exactBounds(); 0541 if (bounds.isEmpty()) { 0542 bounds = image->bounds(); 0543 } 0544 KisImageSP dst = new KisImage(doc->createUndoStore(), 0545 image->width(), 0546 image->height(), 0547 image->projection()->compositionSourceColorSpace(), 0548 source->name()); 0549 dst->setResolution(image->xRes(), image->yRes()); 0550 doc->setFileBatchMode(false); 0551 doc->setCurrentImage(dst); 0552 KisNodeSP node = source->clone(); 0553 dst->addNode(node); 0554 dst->initialRefreshGraph(); 0555 dst->cropImage(bounds); 0556 dst->waitForDone(); 0557 0558 bool r = doc->exportDocumentSync(path, mimeType.toLatin1()); 0559 if (!r) { 0560 0561 qWarning() << "Converting layer to file layer. path:"<< path << "gave errors" << doc->errorMessage(); 0562 } else { 0563 QString basePath = QFileInfo(m_view->document()->path()).absolutePath(); 0564 QString relativePath = QDir(basePath).relativeFilePath(path); 0565 KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, "Bicubic", source->name(), OPACITY_OPAQUE_U8); 0566 fileLayer->setX(bounds.x()); 0567 fileLayer->setY(bounds.y()); 0568 KisNodeSP dstParent = source->parent(); 0569 KisNodeSP dstAboveThis = source->prevSibling(); 0570 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a file layer")); 0571 m_commandsAdapter->removeNode(source); 0572 m_commandsAdapter->addNode(fileLayer, dstParent, dstAboveThis); 0573 m_commandsAdapter->endMacro(); 0574 } 0575 doc->closePath(false); 0576 } 0577 0578 void KisLayerManager::adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above) 0579 { 0580 Q_ASSERT(activeNode); 0581 0582 parent = activeNode; 0583 above = parent->lastChild(); 0584 0585 if (parent->inherits("KisGroupLayer") && parent->collapsed()) { 0586 above = parent; 0587 parent = parent->parent(); 0588 return; 0589 } 0590 0591 while (parent && 0592 (!parent->allowAsChild(node) || !parent->isEditable(false))) { 0593 0594 above = parent; 0595 parent = parent->parent(); 0596 } 0597 0598 if (!parent) { 0599 warnKrita << "KisLayerManager::adjustLayerPosition:" 0600 << "No node accepted newly created node"; 0601 0602 parent = m_view->image()->root(); 0603 above = parent->lastChild(); 0604 } 0605 } 0606 0607 void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisNodeSP layer, bool updateImage, KisProcessingApplicator *applicator) 0608 { 0609 KisNodeSP parent; 0610 KisNodeSP above; 0611 adjustLayerPosition(layer, activeNode, parent, above); 0612 0613 KisGroupLayer *group = dynamic_cast<KisGroupLayer*>(parent.data()); 0614 const bool parentForceUpdate = group && !group->projectionIsValid(); 0615 updateImage |= parentForceUpdate; 0616 0617 m_commandsAdapter->addNodeAsync(layer, parent, above, updateImage, updateImage, applicator); 0618 } 0619 0620 KisLayerSP KisLayerManager::addPaintLayer(KisNodeSP activeNode) 0621 { 0622 KisImageWSP image = m_view->image(); 0623 KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName( i18n("Paint Layer") ), OPACITY_OPAQUE_U8, image->colorSpace()); 0624 0625 KisConfig cfg(true); 0626 layer->setPinnedToTimeline(cfg.autoPinLayersToTimeline()); 0627 0628 addLayerCommon(activeNode, layer, false, 0); 0629 0630 return layer; 0631 } 0632 0633 KisNodeSP KisLayerManager::addGroupLayer(KisNodeSP activeNode) 0634 { 0635 KisImageWSP image = m_view->image(); 0636 KisGroupLayerSP group = new KisGroupLayer(image.data(), image->nextLayerName( i18nc("A group of layers", "Group") ), OPACITY_OPAQUE_U8); 0637 addLayerCommon(activeNode, group, false, 0); 0638 return group; 0639 } 0640 0641 KisNodeSP KisLayerManager::addCloneLayer(KisNodeList nodes) 0642 { 0643 KisImageWSP image = m_view->image(); 0644 0645 KisNodeList filteredNodes = KisLayerUtils::sortAndFilterMergeableInternalNodes(nodes, false); 0646 if (filteredNodes.isEmpty()) return KisNodeSP(); 0647 0648 KisNodeSP newAbove = filteredNodes.last(); 0649 0650 KisNodeSP node, lastClonedNode; 0651 Q_FOREACH (node, filteredNodes) { 0652 lastClonedNode = new KisCloneLayer(qobject_cast<KisLayer*>(node.data()), image.data(), image->nextLayerName( i18n("Clone Layer") ), OPACITY_OPAQUE_U8); 0653 addLayerCommon(newAbove, lastClonedNode, true, 0 ); 0654 } 0655 0656 return lastClonedNode; 0657 } 0658 0659 KisNodeSP KisLayerManager::addShapeLayer(KisNodeSP activeNode) 0660 { 0661 if (!m_view) return 0; 0662 if (!m_view->document()) return 0; 0663 0664 KisImageWSP image = m_view->image(); 0665 KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(i18n("Vector Layer")), OPACITY_OPAQUE_U8); 0666 0667 addLayerCommon(activeNode, layer, false, 0); 0668 0669 return layer; 0670 } 0671 0672 KisNodeSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode) 0673 { 0674 KisImageWSP image = m_view->image(); 0675 0676 KisSelectionSP selection = m_view->selection(); 0677 0678 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, 0679 KisImageSignalVector(), 0680 kundo2_i18n("Add Layer")); 0681 0682 0683 KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection, &applicator); 0684 0685 KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original()); 0686 0687 KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(i18n("Filter Layer")), i18n("New Filter Layer"), m_view, qApp->activeWindow()); 0688 dlg.resize(dlg.minimumSizeHint()); 0689 0690 // ensure that the device may be free'd by the dialog 0691 // when it is not needed anymore 0692 previewDevice = 0; 0693 0694 if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) { 0695 // XXX: add messagebox warning if there's no filter set! 0696 applicator.cancel(); 0697 } else { 0698 applicator.applyCommand(new KisNodeRenameCommand(adjl, adjl->name(), dlg.layerName())); 0699 applicator.end(); 0700 } 0701 0702 return adjl; 0703 } 0704 0705 KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode, const QString & name, 0706 KisFilterConfigurationSP filter, 0707 KisSelectionSP selection, 0708 KisProcessingApplicator *applicator) 0709 { 0710 KisImageWSP image = m_view->image(); 0711 KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter ? filter->cloneWithResourcesSnapshot() : 0, selection); 0712 addLayerCommon(activeNode, layer, true, applicator); 0713 0714 return layer; 0715 } 0716 0717 KisGeneratorLayerSP KisLayerManager::addGeneratorLayer(KisNodeSP activeNode, const QString &name, KisFilterConfigurationSP filter, KisSelectionSP selection, KisProcessingApplicator *applicator) 0718 { 0719 KisImageWSP image = m_view->image(); 0720 auto layer = new KisGeneratorLayer(image, name, filter, selection); 0721 addLayerCommon(activeNode, layer, true, applicator); 0722 0723 return layer; 0724 } 0725 0726 KisNodeSP KisLayerManager::addGeneratorLayer(KisNodeSP activeNode) 0727 { 0728 KisImageWSP image = m_view->image(); 0729 KisSelectionSP selection = m_view->selection(); 0730 QColor currentForeground = m_view->canvasResourceProvider()->fgColor().toQColor(); 0731 0732 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, KisImageSignalVector(), kundo2_i18n("Add Layer")); 0733 0734 KisGeneratorLayerSP node = addGeneratorLayer(activeNode, QString(), nullptr, selection, &applicator); 0735 0736 KisDlgGeneratorLayer dlg(image->nextLayerName(i18n("Fill Layer")), m_view, m_view->mainWindow(), node, nullptr, applicator.getStroke()); 0737 KisFilterConfigurationSP defaultConfig = dlg.configuration(); 0738 defaultConfig->setProperty("color", currentForeground); 0739 dlg.setConfiguration(defaultConfig); 0740 0741 if (dlg.exec() == QDialog::Accepted) { 0742 applicator.applyCommand(new KisNodeRenameCommand(node, node->name(), dlg.layerName())); 0743 applicator.end(); 0744 return node; 0745 } 0746 else { 0747 applicator.cancel(); 0748 return nullptr; 0749 } 0750 } 0751 0752 void KisLayerManager::flattenImage() 0753 { 0754 KisImageSP image = m_view->image(); 0755 0756 if (!m_view->blockUntilOperationsFinished(image)) return; 0757 0758 if (image) { 0759 bool doIt = true; 0760 0761 if (image->nHiddenLayers() > 0) { 0762 int answer = QMessageBox::warning(m_view->mainWindow(), 0763 i18nc("@title:window", "Flatten Image"), 0764 i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"), 0765 QMessageBox::Yes | QMessageBox::No, 0766 QMessageBox::No); 0767 0768 if (answer != QMessageBox::Yes) { 0769 doIt = false; 0770 } 0771 } 0772 0773 if (doIt) { 0774 image->flatten(m_view->activeNode()); 0775 } 0776 } 0777 } 0778 0779 inline bool isSelectionMask(KisNodeSP node) { 0780 return dynamic_cast<KisSelectionMask*>(node.data()); 0781 } 0782 0783 bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image) 0784 { 0785 bool result = false; 0786 0787 KisNodeSP prevNode = currentNode->prevSibling(); 0788 if (isSelectionMask(currentNode) && 0789 prevNode && isSelectionMask(prevNode)) { 0790 0791 QList<KisNodeSP> mergedNodes; 0792 mergedNodes.append(currentNode); 0793 mergedNodes.append(prevNode); 0794 0795 image->mergeMultipleLayers(mergedNodes, currentNode); 0796 0797 result = true; 0798 } 0799 0800 return result; 0801 } 0802 0803 bool tryFlattenGroupLayer(KisNodeSP currentNode, KisImageSP image) 0804 { 0805 bool result = false; 0806 0807 if (currentNode->inherits("KisGroupLayer")) { 0808 KisGroupLayer *layer = qobject_cast<KisGroupLayer*>(currentNode.data()); 0809 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(layer, false); 0810 0811 image->flattenLayer(layer); 0812 result = true; 0813 } 0814 0815 return result; 0816 } 0817 0818 void KisLayerManager::mergeLayer() 0819 { 0820 KisImageSP image = m_view->image(); 0821 if (!image) return; 0822 0823 KisLayerSP layer = activeLayer(); 0824 if (!layer) return; 0825 0826 if (!m_view->blockUntilOperationsFinished(image)) return; 0827 0828 QList<KisNodeSP> selectedNodes = m_view->nodeManager()->selectedNodes(); 0829 0830 // check if all the layers are a part of a locked group 0831 bool hasEditableLayer = false; 0832 Q_FOREACH (KisNodeSP node, selectedNodes) { 0833 if (node->isEditable(false)) { 0834 hasEditableLayer = true; 0835 break; 0836 } 0837 } 0838 0839 if (!hasEditableLayer) { 0840 m_view->showFloatingMessage( 0841 i18ncp("floating message in layer manager", 0842 "Layer is locked", "Layers are locked", selectedNodes.size()), 0843 QIcon(), 2000, KisFloatingMessage::Low); 0844 return; 0845 } 0846 0847 if (selectedNodes.size() > 1) { 0848 image->mergeMultipleLayers(selectedNodes, m_view->activeNode()); 0849 } 0850 0851 else if (tryMergeSelectionMasks(m_view->activeNode(), image)) { 0852 // already done! 0853 } else if (tryFlattenGroupLayer(m_view->activeNode(), image)) { 0854 // already done! 0855 } else { 0856 0857 if (!layer->prevSibling()) return; 0858 KisLayer *prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data()); 0859 if (!prevLayer) return; 0860 0861 if (prevLayer->userLocked()) { 0862 m_view->showFloatingMessage( 0863 i18nc("floating message in layer manager when previous layer is locked", 0864 "Layer is locked"), 0865 QIcon(), 2000, KisFloatingMessage::Low); 0866 } else { 0867 const KisMetaData::MergeStrategy* strategy = nullptr; 0868 0869 if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) { 0870 strategy = KisMetaData::MergeStrategyRegistry::instance()->get("Drop"); 0871 } 0872 else { 0873 strategy = KisMetaDataMergeStrategyChooserWidget::showDialog(m_view->mainWindow()); 0874 } 0875 0876 if (!strategy) return; 0877 0878 if (!layer->isAnimated() && prevLayer->isAnimated()) { 0879 m_view->showFloatingMessage( 0880 i18nc("floating message in layer manager when trying to merge a non-animated layer into an animated one", 0881 "Non-animated layer is merged into the current frame. To merge it into the whole clip, create at least one frame"), 0882 QIcon(), 5000, KisFloatingMessage::Medium); 0883 } 0884 image->mergeDown(layer, strategy); 0885 } 0886 } 0887 0888 m_view->updateGUI(); 0889 } 0890 0891 void KisLayerManager::flattenLayer() 0892 { 0893 KisImageSP image = m_view->image(); 0894 if (!image) return; 0895 0896 KisLayerSP layer = activeLayer(); 0897 if (!layer) return; 0898 0899 if (!m_view->blockUntilOperationsFinished(image)) return; 0900 if (!m_view->nodeManager()->canModifyLayer(layer)) return; 0901 0902 convertNodeToPaintLayer(layer); 0903 m_view->updateGUI(); 0904 } 0905 0906 void KisLayerManager::layersUpdated() 0907 { 0908 KisLayerSP layer = activeLayer(); 0909 if (!layer) return; 0910 0911 m_view->updateGUI(); 0912 } 0913 0914 void KisLayerManager::saveGroupLayers() 0915 { 0916 QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); 0917 0918 KoDialog dlg; 0919 QWidget *page = new QWidget(&dlg); 0920 dlg.setMainWidget(page); 0921 QBoxLayout *layout = new QVBoxLayout(page); 0922 0923 KisFileNameRequester *urlRequester = new KisFileNameRequester(page); 0924 urlRequester->setMode(KoFileDialog::SaveFile); 0925 urlRequester->setStartDir(QFileInfo(m_view->document()->path()).absolutePath()); 0926 urlRequester->setMimeTypeFilters(listMimeFilter); 0927 urlRequester->setFileName(m_view->document()->path()); 0928 layout->addWidget(urlRequester); 0929 0930 QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page); 0931 chkInvisible->setChecked(false); 0932 layout->addWidget(chkInvisible); 0933 QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page); 0934 chkDepth->setChecked(true); 0935 layout->addWidget(chkDepth); 0936 0937 if (!dlg.exec()) return; 0938 0939 QString path = urlRequester->fileName(); 0940 0941 if (path.isEmpty()) return; 0942 0943 QFileInfo f(path); 0944 0945 QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName(), false); 0946 if (mimeType.isEmpty()) { 0947 mimeType = "image/png"; 0948 } 0949 QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first(); 0950 QString basename = f.completeBaseName(); 0951 0952 KisImageSP image = m_view->image(); 0953 if (!image) return; 0954 0955 KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType); 0956 image->rootLayer()->accept(v); 0957 0958 } 0959 0960 bool KisLayerManager::activeLayerHasSelection() 0961 { 0962 return (activeLayer()->selection() != 0); 0963 } 0964 0965 KisNodeSP KisLayerManager::addFileLayer(KisNodeSP activeNode) 0966 { 0967 QString basePath; 0968 QString path = m_view->document()->path(); 0969 basePath = QFileInfo(path).absolutePath(); 0970 KisImageWSP image = m_view->image(); 0971 0972 KisDlgFileLayer dlg(basePath, image->nextLayerName(i18n("File Layer")), m_view->mainWindow()); 0973 dlg.resize(dlg.minimumSizeHint()); 0974 0975 if (dlg.exec() == QDialog::Accepted) { 0976 QString name = dlg.layerName(); 0977 QString fileName = dlg.fileName(); 0978 0979 if(fileName.isEmpty()){ 0980 QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); 0981 return 0; 0982 } 0983 0984 KisFileLayer::ScalingMethod scalingMethod = dlg.scaleToImageResolution(); 0985 QString scalingFilter = dlg.scalingFilter(); 0986 KisNodeSP node = new KisFileLayer(image, basePath, fileName, scalingMethod, scalingFilter, name, OPACITY_OPAQUE_U8); 0987 addLayerCommon(activeNode, node, true, 0); 0988 return node; 0989 } 0990 return 0; 0991 } 0992 0993 void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg, KoCanvasResourcesInterfaceSP canvasResourcesInterface) 0994 { 0995 KisSetLayerStyleCommand::updateLayerStyle(layer, 0996 dlg->style()->cloneWithResourcesSnapshot( 0997 KisGlobalResourcesInterface::instance(), 0998 canvasResourcesInterface)); 0999 } 1000 1001 void KisLayerManager::layerStyle() 1002 { 1003 KisImageWSP image = m_view->image(); 1004 if (!image) return; 1005 1006 KisLayerSP layer = activeLayer(); 1007 if (!layer) return; 1008 1009 if (!m_view->blockUntilOperationsFinished(image)) return; 1010 if (!m_view->nodeManager()->canModifyLayer(layer)) return; 1011 1012 KoCanvasResourcesInterfaceSP canvasResourcesInterface = m_view->canvasBase()->resourceManager()->canvasResourcesInterface(); 1013 1014 KisPSDLayerStyleSP oldStyle; 1015 if (layer->layerStyle()) { 1016 oldStyle = layer->layerStyle()->clone().dynamicCast<KisPSDLayerStyle>(); 1017 1018 } else { 1019 oldStyle = toQShared(new KisPSDLayerStyle("", KisGlobalResourcesInterface::instance())) 1020 ->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(), 1021 canvasResourcesInterface); 1022 } 1023 1024 KisPSDLayerStyleSP newStyle = oldStyle->clone().dynamicCast<KisPSDLayerStyle>(); 1025 // We want to also change the UUID, else it might be considered the same style after save and won't load correctly 1026 newStyle->setUuid(QUuid::createUuid()); 1027 newStyle->setResourcesInterface(KisGlobalResourcesInterface::instance()); 1028 1029 KisDlgLayerStyle dlg(newStyle, m_view->canvasResourceProvider()); 1030 1031 std::function<void ()> updateCall(std::bind(updateLayerStyles, layer, &dlg, canvasResourcesInterface)); 1032 SignalToFunctionProxy proxy(updateCall); 1033 connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start())); 1034 1035 if (dlg.exec() == QDialog::Accepted) { 1036 KisPSDLayerStyleSP newStyle = 1037 dlg.style()->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(), 1038 canvasResourcesInterface); 1039 1040 KUndo2CommandSP command = toQShared( 1041 new KisSetLayerStyleCommand(layer, oldStyle, newStyle)); 1042 1043 image->postExecutionUndoAdapter()->addCommand(command); 1044 } 1045 } 1046