File indexing completed on 2024-05-19 04:29:01
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_node_manager.h" 0008 0009 #include <QStandardPaths> 0010 #include <QMessageBox> 0011 #include <KisSignalMapper.h> 0012 #include <QApplication> 0013 0014 #include <kactioncollection.h> 0015 0016 #include <QKeySequence> 0017 0018 #include <kis_icon.h> 0019 #include <KoSelection.h> 0020 #include <KoShapeManager.h> 0021 #include <KoShape.h> 0022 #include <KoShapeLayer.h> 0023 #include <KisImportExportManager.h> 0024 #include <KoFileDialog.h> 0025 #include <KoToolManager.h> 0026 #include <KoProperties.h> 0027 0028 #include <KoColorSpace.h> 0029 #include <KoColorSpaceRegistry.h> 0030 #include <KoColorModelStandardIds.h> 0031 0032 #include <kis_types.h> 0033 #include <kis_node.h> 0034 #include <kis_selection.h> 0035 #include <kis_selection_mask.h> 0036 #include <kis_layer.h> 0037 #include <kis_mask.h> 0038 #include <kis_image.h> 0039 #include <kis_painter.h> 0040 #include <kis_paint_layer.h> 0041 #include <KisMimeDatabase.h> 0042 #include <KisReferenceImagesLayer.h> 0043 0044 #include "KisPart.h" 0045 #include "canvas/kis_canvas2.h" 0046 #include "kis_shape_controller.h" 0047 #include "kis_canvas_resource_provider.h" 0048 #include "KisViewManager.h" 0049 #include "KisDocument.h" 0050 #include "kis_mask_manager.h" 0051 #include "kis_group_layer.h" 0052 #include "kis_layer_manager.h" 0053 #include "kis_selection_manager.h" 0054 #include "kis_node_commands_adapter.h" 0055 #include "kis_action.h" 0056 #include "kis_action_manager.h" 0057 #include "kis_processing_applicator.h" 0058 #include "kis_sequential_iterator.h" 0059 #include "kis_transaction.h" 0060 #include "kis_node_selection_adapter.h" 0061 #include "kis_node_insertion_adapter.h" 0062 #include "kis_node_juggler_compressed.h" 0063 #include "KisNodeDisplayModeAdapter.h" 0064 #include "kis_clipboard.h" 0065 #include "kis_node_dummies_graph.h" 0066 #include "kis_mimedata.h" 0067 #include "kis_layer_utils.h" 0068 #include "krita_utils.h" 0069 #include "kis_shape_layer.h" 0070 #include "kis_keyframe_channel.h" 0071 #include "kis_raster_keyframe_channel.h" 0072 #include "kis_paint_device_frames_interface.h" 0073 #include "kis_layer_utils.h" 0074 0075 #include "processing/kis_mirror_processing_visitor.h" 0076 #include "KisView.h" 0077 0078 #include <kis_signals_blocker.h> 0079 #include <libs/image/kis_layer_properties_icons.h> 0080 #include <libs/image/commands/kis_node_property_list_command.h> 0081 #include <KisSynchronizedConnection.h> 0082 0083 struct KisNodeManager::Private { 0084 0085 Private(KisNodeManager *_q, KisViewManager *v) 0086 : q(_q) 0087 , view(v) 0088 , imageView(0) 0089 , layerManager(v) 0090 , maskManager(v) 0091 , commandsAdapter(v) 0092 , nodeSelectionAdapter(new KisNodeSelectionAdapter(q)) 0093 , nodeInsertionAdapter(new KisNodeInsertionAdapter(q)) 0094 , nodeDisplayModeAdapter(new KisNodeDisplayModeAdapter()) 0095 , lastRequestedIsolatedModeStatus(false) 0096 { 0097 } 0098 0099 KisNodeManager * q {nullptr}; 0100 KisViewManager * view {nullptr}; 0101 QPointer<KisView>imageView; 0102 KisLayerManager layerManager; 0103 KisMaskManager maskManager; 0104 KisNodeCommandsAdapter commandsAdapter; 0105 QScopedPointer<KisNodeSelectionAdapter> nodeSelectionAdapter; 0106 QScopedPointer<KisNodeInsertionAdapter> nodeInsertionAdapter; 0107 QScopedPointer<KisNodeDisplayModeAdapter> nodeDisplayModeAdapter; 0108 0109 KisAction *pinToTimeline {nullptr}; 0110 0111 KisNodeList selectedNodes; 0112 QPointer<KisNodeJugglerCompressed> nodeJuggler; 0113 0114 KisNodeWSP previouslyActiveNode; 0115 0116 bool activateNodeImpl(KisNodeSP node); 0117 0118 KisSignalMapper nodeCreationSignalMapper; 0119 KisSignalMapper nodeConversionSignalMapper; 0120 0121 bool lastRequestedIsolatedModeStatus {false}; 0122 KisSynchronizedConnection<KisNodeSP, KisNodeList> activateNodeConnection; 0123 0124 void saveDeviceAsImage(KisPaintDeviceSP device, 0125 const QString &defaultName, 0126 const QRect &bounds, 0127 qreal xRes, 0128 qreal yRes, 0129 quint8 opacity); 0130 0131 void mergeTransparencyMaskAsAlpha(bool writeToLayers); 0132 KisNodeJugglerCompressed* lazyGetJuggler(const KUndo2MagicString &actionName); 0133 }; 0134 0135 bool KisNodeManager::Private::activateNodeImpl(KisNodeSP node) 0136 { 0137 Q_ASSERT(view); 0138 Q_ASSERT(view->canvasBase()); 0139 Q_ASSERT(view->canvasBase()->globalShapeManager()); 0140 Q_ASSERT(imageView); 0141 if (node && node == q->activeNode()) { 0142 return false; 0143 } 0144 0145 // Set the selection on the shape manager to the active layer 0146 // and set call KoSelection::setActiveLayer( KoShapeLayer* layer ) 0147 // with the parent of the active layer. 0148 KoSelection *selection = view->canvasBase()->globalShapeManager()->selection(); 0149 Q_ASSERT(selection); 0150 selection->deselectAll(); 0151 0152 if (!node) { 0153 selection->setActiveLayer(0); 0154 imageView->setCurrentNode(0); 0155 maskManager.activateMask(0); 0156 layerManager.activateLayer(0); 0157 previouslyActiveNode = q->activeNode(); 0158 } else { 0159 0160 previouslyActiveNode = q->activeNode(); 0161 0162 KoShape * shape = view->document()->shapeForNode(node); 0163 0164 //if (!shape) return false; 0165 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shape, false); 0166 0167 selection->select(shape); 0168 KoShapeLayer * shapeLayer = dynamic_cast<KoShapeLayer*>(shape); 0169 0170 //if (!shapeLayer) return false; 0171 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shapeLayer, false); 0172 0173 // shapeLayer->setGeometryProtected(node->userLocked()); 0174 // shapeLayer->setVisible(node->visible()); 0175 selection->setActiveLayer(shapeLayer); 0176 0177 imageView->setCurrentNode(node); 0178 if (KisLayerSP layer = qobject_cast<KisLayer*>(node.data())) { 0179 maskManager.activateMask(0); 0180 layerManager.activateLayer(layer); 0181 } else if (KisMaskSP mask = dynamic_cast<KisMask*>(node.data())) { 0182 maskManager.activateMask(mask); 0183 // XXX_NODE: for now, masks cannot be nested. 0184 layerManager.activateLayer(static_cast<KisLayer*>(node->parent().data())); 0185 } 0186 } 0187 return true; 0188 } 0189 0190 KisNodeManager::KisNodeManager(KisViewManager *view) 0191 : m_d(new Private(this, view)) 0192 { 0193 m_d->activateNodeConnection.connectOutputSlot(this, &KisNodeManager::slotImageRequestNodeReselection); 0194 } 0195 0196 KisNodeManager::~KisNodeManager() 0197 { 0198 delete m_d; 0199 } 0200 0201 void KisNodeManager::setView(QPointer<KisView>imageView) 0202 { 0203 m_d->maskManager.setView(imageView); 0204 m_d->layerManager.setView(imageView); 0205 0206 if (m_d->imageView) { 0207 KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController()); 0208 Q_ASSERT(shapeController); 0209 shapeController->disconnect(SIGNAL(sigActivateNode(KisNodeSP)), this); 0210 m_d->imageView->image()->disconnect(this); 0211 m_d->imageView->image()->disconnect(&m_d->activateNodeConnection); 0212 } 0213 0214 m_d->imageView = imageView; 0215 0216 if (m_d->imageView) { 0217 KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController()); 0218 Q_ASSERT(shapeController); 0219 connect(shapeController, SIGNAL(sigActivateNode(KisNodeSP)), SLOT(slotNonUiActivatedNode(KisNodeSP))); 0220 m_d->activateNodeConnection.connectInputSignal(m_d->imageView->image(), &KisImage::sigRequestNodeReselection); 0221 m_d->imageView->resourceProvider()->slotNodeActivated(m_d->imageView->currentNode()); 0222 connect(m_d->imageView->image(), SIGNAL(sigIsolatedModeChanged()), this, SLOT(handleExternalIsolationChange())); 0223 } 0224 0225 } 0226 0227 #define NEW_LAYER_ACTION(id, layerType) \ 0228 { \ 0229 action = actionManager->createAction(id); \ 0230 m_d->nodeCreationSignalMapper.setMapping(action, layerType); \ 0231 connect(action, SIGNAL(triggered()), \ 0232 &m_d->nodeCreationSignalMapper, SLOT(map())); \ 0233 } 0234 0235 #define CONVERT_NODE_ACTION_2(id, layerType, exclude) \ 0236 { \ 0237 action = actionManager->createAction(id); \ 0238 action->setExcludedNodeTypes(QStringList(exclude)); \ 0239 actionManager->addAction(id, action); \ 0240 m_d->nodeConversionSignalMapper.setMapping(action, layerType); \ 0241 connect(action, SIGNAL(triggered()), \ 0242 &m_d->nodeConversionSignalMapper, SLOT(map())); \ 0243 } 0244 0245 #define CONVERT_NODE_ACTION(id, layerType) \ 0246 CONVERT_NODE_ACTION_2(id, layerType, layerType) 0247 0248 void KisNodeManager::setup(KisKActionCollection * actionCollection, KisActionManager* actionManager) 0249 { 0250 m_d->layerManager.setup(actionManager); 0251 m_d->maskManager.setup(actionCollection, actionManager); 0252 0253 KisAction * action = 0; 0254 0255 action = actionManager->createAction("mirrorNodeX"); 0256 connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeX())); 0257 0258 action = actionManager->createAction("mirrorNodeY"); 0259 connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeY())); 0260 0261 action = actionManager->createAction("mirrorAllNodesX"); 0262 connect(action, SIGNAL(triggered()), this, SLOT(mirrorAllNodesX())); 0263 0264 action = actionManager->createAction("mirrorAllNodesY"); 0265 connect(action, SIGNAL(triggered()), this, SLOT(mirrorAllNodesY())); 0266 0267 action = actionManager->createAction("activateNextLayer"); 0268 connect(action, SIGNAL(triggered()), this, SLOT(activateNextNode())); 0269 0270 action = actionManager->createAction("activateNextSiblingLayer"); 0271 connect(action, SIGNAL(triggered()), this, SLOT(activateNextSiblingNode())); 0272 0273 action = actionManager->createAction("activatePreviousLayer"); 0274 connect(action, SIGNAL(triggered()), this, SLOT(activatePreviousNode())); 0275 0276 action = actionManager->createAction("activatePreviousSiblingLayer"); 0277 connect(action, SIGNAL(triggered()), this, SLOT(activatePreviousSiblingNode())); 0278 0279 action = actionManager->createAction("switchToPreviouslyActiveNode"); 0280 connect(action, SIGNAL(triggered()), this, SLOT(switchToPreviouslyActiveNode())); 0281 0282 action = actionManager->createAction("save_node_as_image"); 0283 connect(action, SIGNAL(triggered()), this, SLOT(saveNodeAsImage())); 0284 0285 action = actionManager->createAction("save_vector_node_to_svg"); 0286 connect(action, SIGNAL(triggered()), this, SLOT(saveVectorLayerAsImage())); 0287 action->setActivationFlags(KisAction::ACTIVE_SHAPE_LAYER); 0288 0289 action = actionManager->createAction("duplicatelayer"); 0290 connect(action, SIGNAL(triggered()), this, SLOT(duplicateActiveNode())); 0291 0292 action = actionManager->createAction("copy_layer_clipboard"); 0293 connect(action, SIGNAL(triggered()), this, SLOT(copyLayersToClipboard())); 0294 0295 action = actionManager->createAction("cut_layer_clipboard"); 0296 connect(action, SIGNAL(triggered()), this, SLOT(cutLayersToClipboard())); 0297 0298 action = actionManager->createAction("paste_layer_from_clipboard"); 0299 connect(action, SIGNAL(triggered()), this, SLOT(pasteLayersFromClipboard())); 0300 0301 action = actionManager->createAction("create_quick_group"); 0302 connect(action, SIGNAL(triggered()), this, SLOT(createQuickGroup())); 0303 0304 action = actionManager->createAction("create_quick_clipping_group"); 0305 connect(action, SIGNAL(triggered()), this, SLOT(createQuickClippingGroup())); 0306 0307 action = actionManager->createAction("quick_ungroup"); 0308 connect(action, SIGNAL(triggered()), this, SLOT(quickUngroup())); 0309 0310 action = actionManager->createAction("select_all_layers"); 0311 connect(action, SIGNAL(triggered()), this, SLOT(selectAllNodes())); 0312 0313 action = actionManager->createAction("select_visible_layers"); 0314 connect(action, SIGNAL(triggered()), this, SLOT(selectVisibleNodes())); 0315 0316 action = actionManager->createAction("select_locked_layers"); 0317 connect(action, SIGNAL(triggered()), this, SLOT(selectLockedNodes())); 0318 0319 action = actionManager->createAction("select_invisible_layers"); 0320 connect(action, SIGNAL(triggered()), this, SLOT(selectInvisibleNodes())); 0321 0322 action = actionManager->createAction("select_unlocked_layers"); 0323 connect(action, SIGNAL(triggered()), this, SLOT(selectUnlockedNodes())); 0324 0325 action = actionManager->createAction("new_from_visible"); 0326 connect(action, SIGNAL(triggered()), this, SLOT(createFromVisible())); 0327 0328 action = actionManager->createAction("pin_to_timeline"); 0329 action->setCheckable(true); 0330 connect(action, SIGNAL(toggled(bool)), this, SLOT(slotPinToTimeline(bool))); 0331 m_d->pinToTimeline = action; 0332 0333 NEW_LAYER_ACTION("add_new_paint_layer", "KisPaintLayer"); 0334 0335 NEW_LAYER_ACTION("add_new_group_layer", "KisGroupLayer"); 0336 0337 NEW_LAYER_ACTION("add_new_clone_layer", "KisCloneLayer"); 0338 0339 NEW_LAYER_ACTION("add_new_shape_layer", "KisShapeLayer"); 0340 0341 NEW_LAYER_ACTION("add_new_adjustment_layer", "KisAdjustmentLayer"); 0342 0343 NEW_LAYER_ACTION("add_new_fill_layer", "KisGeneratorLayer"); 0344 0345 NEW_LAYER_ACTION("add_new_file_layer", "KisFileLayer"); 0346 0347 NEW_LAYER_ACTION("add_new_transparency_mask", "KisTransparencyMask"); 0348 0349 NEW_LAYER_ACTION("add_new_filter_mask", "KisFilterMask"); 0350 0351 NEW_LAYER_ACTION("add_new_colorize_mask", "KisColorizeMask"); 0352 0353 NEW_LAYER_ACTION("add_new_transform_mask", "KisTransformMask"); 0354 0355 NEW_LAYER_ACTION("add_new_selection_mask", "KisSelectionMask"); 0356 0357 connect(&m_d->nodeCreationSignalMapper, SIGNAL(mapped(QString)), 0358 this, SLOT(createNode(QString))); 0359 0360 CONVERT_NODE_ACTION("convert_to_paint_layer", "KisPaintLayer"); 0361 0362 CONVERT_NODE_ACTION_2("convert_to_selection_mask", "KisSelectionMask", QStringList() << "KisSelectionMask" << "KisColorizeMask"); 0363 0364 CONVERT_NODE_ACTION_2("convert_to_filter_mask", "KisFilterMask", QStringList() << "KisFilterMask" << "KisColorizeMask"); 0365 0366 CONVERT_NODE_ACTION_2("convert_to_transparency_mask", "KisTransparencyMask", QStringList() << "KisTransparencyMask" << "KisColorizeMask"); 0367 0368 CONVERT_NODE_ACTION("convert_to_animated", "animated"); 0369 0370 CONVERT_NODE_ACTION_2("convert_to_file_layer", "KisFileLayer", QStringList() << "KisFileLayer" << "KisCloneLayer"); 0371 0372 connect(&m_d->nodeConversionSignalMapper, SIGNAL(mapped(QString)), 0373 this, SLOT(convertNode(QString))); 0374 0375 // Isolation Modes... 0376 // Post Qt5.14 this can be replaced with QActionGroup + ExclusionPolicy::ExclusiveOptional. 0377 action = actionManager->createAction("isolate_active_layer"); 0378 connect(action, SIGNAL(toggled(bool)), this, SLOT(setIsolateActiveLayerMode(bool))); 0379 action = actionManager->createAction("isolate_active_group"); 0380 connect(action, SIGNAL(triggered(bool)), this, SLOT(setIsolateActiveGroupMode(bool))); 0381 connect(this, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(changeIsolationRoot(KisNodeSP))); 0382 0383 action = actionManager->createAction("toggle_layer_visibility"); 0384 connect(action, SIGNAL(triggered()), this, SLOT(toggleVisibility())); 0385 0386 action = actionManager->createAction("toggle_layer_lock"); 0387 connect(action, SIGNAL(triggered()), this, SLOT(toggleLock())); 0388 0389 action = actionManager->createAction("toggle_layer_inherit_alpha"); 0390 connect(action, SIGNAL(triggered()), this, SLOT(toggleInheritAlpha())); 0391 0392 action = actionManager->createAction("toggle_layer_alpha_lock"); 0393 connect(action, SIGNAL(triggered()), this, SLOT(toggleAlphaLock())); 0394 0395 action = actionManager->createAction("split_alpha_into_mask"); 0396 connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaIntoMask())); 0397 0398 action = actionManager->createAction("split_alpha_write"); 0399 connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaWrite())); 0400 0401 // HINT: we can save even when the nodes are not editable 0402 action = actionManager->createAction("split_alpha_save_merged"); 0403 connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaSaveMerged())); 0404 } 0405 0406 void KisNodeManager::updateGUI() 0407 { 0408 // enable/disable all relevant actions 0409 m_d->layerManager.updateGUI(); 0410 m_d->maskManager.updateGUI(); 0411 } 0412 0413 KisNodeSP KisNodeManager::activeNode() 0414 { 0415 if (m_d->imageView) { 0416 return m_d->imageView->currentNode(); 0417 } 0418 return 0; 0419 } 0420 0421 KisLayerSP KisNodeManager::activeLayer() 0422 { 0423 return m_d->layerManager.activeLayer(); 0424 } 0425 0426 const KoColorSpace* KisNodeManager::activeColorSpace() 0427 { 0428 if (m_d->maskManager.activeDevice()) { 0429 return m_d->maskManager.activeDevice()->colorSpace(); 0430 } else { 0431 Q_ASSERT(m_d->layerManager.activeLayer()); 0432 if (m_d->layerManager.activeLayer()->parentLayer()) 0433 return m_d->layerManager.activeLayer()->parentLayer()->colorSpace(); 0434 else 0435 return m_d->view->image()->colorSpace(); 0436 } 0437 } 0438 0439 bool KisNodeManager::canModifyLayers(KisNodeList nodes, bool showWarning) 0440 { 0441 KisNodeSP lockedNode; 0442 Q_FOREACH (KisNodeSP node, nodes) { 0443 if (!node->isEditable(false)) { 0444 lockedNode = node; 0445 break; 0446 } 0447 } 0448 0449 if (lockedNode && showWarning) { 0450 QString errorMessage; 0451 0452 if (nodes.size() <= 1) { 0453 errorMessage = i18n("Layer is locked"); 0454 } else { 0455 errorMessage = i18n("Layer \"%1\" is locked", lockedNode->name()); 0456 } 0457 0458 m_d->view->showFloatingMessage(errorMessage, QIcon()); 0459 } 0460 0461 return !lockedNode; 0462 } 0463 0464 bool KisNodeManager::canModifyLayer(KisNodeSP node, bool showWarning) 0465 { 0466 return canModifyLayers({node}, showWarning); 0467 } 0468 0469 bool KisNodeManager::canMoveLayers(KisNodeList nodes, bool showWarning) 0470 { 0471 KisNodeSP lockedNode; 0472 Q_FOREACH (KisNodeSP node, nodes) { 0473 if (node->parent() && !node->parent()->isEditable(false)) { 0474 lockedNode = node->parent(); 0475 break; 0476 } 0477 } 0478 0479 if (lockedNode && showWarning) { 0480 QString errorMessage = i18n("Layer \"%1\" is locked", lockedNode->name()); 0481 m_d->view->showFloatingMessage(errorMessage, QIcon()); 0482 } 0483 0484 return !lockedNode; 0485 } 0486 0487 bool KisNodeManager::canMoveLayer(KisNodeSP node, bool showWarning) 0488 { 0489 return canMoveLayers({node}, showWarning); 0490 } 0491 0492 void KisNodeManager::moveNodeAt(KisNodeSP node, KisNodeSP parent, int index) 0493 { 0494 if (parent->allowAsChild(node)) { 0495 if (node->inherits("KisSelectionMask") && parent->inherits("KisLayer")) { 0496 KisSelectionMask *m = dynamic_cast<KisSelectionMask*>(node.data()); 0497 KisLayer *l = qobject_cast<KisLayer*>(parent.data()); 0498 if (m && m->active() && l && l->selectionMask()) { 0499 l->selectionMask()->setActive(false); 0500 } 0501 } 0502 m_d->commandsAdapter.moveNode(node, parent, index); 0503 } 0504 } 0505 0506 void KisNodeManager::moveNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis) 0507 { 0508 KUndo2MagicString actionName = kundo2_i18n("Move Nodes"); 0509 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 0510 juggler->moveNode(nodes, parent, aboveThis); 0511 } 0512 0513 void KisNodeManager::copyNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis) 0514 { 0515 KUndo2MagicString actionName = kundo2_i18n("Copy Nodes"); 0516 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 0517 juggler->copyNode(nodes, parent, aboveThis); 0518 } 0519 0520 void KisNodeManager::addNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis) 0521 { 0522 KUndo2MagicString actionName = kundo2_i18n("Add Nodes"); 0523 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 0524 juggler->addNode(nodes, parent, aboveThis); 0525 } 0526 0527 void KisNodeManager::toggleIsolateActiveNode() 0528 { 0529 QAction* action = m_d->view->actionManager()->actionByName("isolate_active_layer"); 0530 action->toggle(); 0531 } 0532 0533 void KisNodeManager::setIsolateActiveLayerMode(bool checked) 0534 { 0535 KisImageWSP image = m_d->view->image(); 0536 KIS_ASSERT_RECOVER_RETURN(image); 0537 0538 const bool groupIsolationState = image->isIsolatingGroup(); 0539 changeIsolationMode(checked, groupIsolationState); 0540 } 0541 0542 void KisNodeManager::setIsolateActiveGroupMode(bool checked) 0543 { 0544 KisImageWSP image = m_d->view->image(); 0545 KIS_ASSERT_RECOVER_RETURN(image); 0546 0547 const bool layerIsolationState = image->isIsolatingLayer(); 0548 changeIsolationMode(layerIsolationState, checked); 0549 } 0550 0551 void KisNodeManager::changeIsolationMode(bool isolateActiveLayer, bool isolateActiveGroup) 0552 { 0553 KisImageWSP image = m_d->view->image(); 0554 KisNodeSP activeNode = this->activeNode(); 0555 KIS_ASSERT_RECOVER_RETURN(image && activeNode); 0556 0557 if (isolateActiveLayer || isolateActiveGroup) { 0558 if (image->startIsolatedMode(activeNode, isolateActiveLayer, isolateActiveGroup) == false) { 0559 reinitializeIsolationActionGroup(); 0560 } 0561 } else { 0562 image->stopIsolatedMode(); 0563 } 0564 } 0565 0566 void KisNodeManager::changeIsolationRoot(KisNodeSP isolationRoot) 0567 { 0568 KisImageWSP image = m_d->view->image(); 0569 if (!image || !isolationRoot) return; 0570 0571 const bool isIsolatingLayer = image->isIsolatingLayer(); 0572 const bool isIsolatingGroup = image->isIsolatingGroup(); 0573 0574 // Restart isolation with a new root node and the same settings. 0575 if (image->startIsolatedMode(isolationRoot, isIsolatingLayer, isIsolatingGroup) == false) { 0576 reinitializeIsolationActionGroup(); 0577 } 0578 } 0579 0580 void KisNodeManager::handleExternalIsolationChange() 0581 { 0582 // It might be that we have multiple Krita windows open. In such a case 0583 // only the currently active one should restart isolated mode 0584 if (!m_d->view->mainWindowAsQWidget()->isActiveWindow()) return; 0585 0586 KisImageWSP image = m_d->view->image(); 0587 KisNodeSP activeNode = this->activeNode(); 0588 0589 const bool isIsolatingLayer = image->isIsolatingLayer(); 0590 const bool isIsolatingGroup = image->isIsolatingGroup(); 0591 0592 m_d->view->actionManager()->actionByName("isolate_active_layer")->setChecked(isIsolatingLayer); 0593 m_d->view->actionManager()->actionByName("isolate_active_group")->setChecked(isIsolatingGroup); 0594 } 0595 0596 void KisNodeManager::reinitializeIsolationActionGroup() 0597 { 0598 m_d->view->actionManager()->actionByName("isolate_active_layer")->setChecked(false); 0599 m_d->view->actionManager()->actionByName("isolate_active_group")->setChecked(false); 0600 } 0601 0602 KisNodeSP KisNodeManager::createNode(const QString & nodeType, bool quiet, KisPaintDeviceSP copyFrom) 0603 { 0604 if (!m_d->view->blockUntilOperationsFinished(m_d->view->image())) { 0605 return 0; 0606 } 0607 0608 KisNodeSP activeNode = this->activeNode(); 0609 if (!activeNode) { 0610 activeNode = m_d->view->image()->root(); 0611 } 0612 0613 KIS_ASSERT_RECOVER_RETURN_VALUE(activeNode, 0); 0614 0615 /// the check for editability happens inside the functions 0616 /// themselves, because layers can be created anyway (in a 0617 /// different position), but masks cannot. 0618 0619 // XXX: make factories for this kind of stuff, 0620 // with a registry 0621 0622 if (nodeType == "KisPaintLayer") { 0623 return m_d->layerManager.addPaintLayer(activeNode); 0624 } else if (nodeType == "KisGroupLayer") { 0625 return m_d->layerManager.addGroupLayer(activeNode); 0626 } else if (nodeType == "KisAdjustmentLayer") { 0627 return m_d->layerManager.addAdjustmentLayer(activeNode); 0628 } else if (nodeType == "KisGeneratorLayer") { 0629 return m_d->layerManager.addGeneratorLayer(activeNode); 0630 } else if (nodeType == "KisShapeLayer") { 0631 return m_d->layerManager.addShapeLayer(activeNode); 0632 } else if (nodeType == "KisCloneLayer") { 0633 KisNodeList nodes = selectedNodes(); 0634 if (nodes.isEmpty()) { 0635 nodes.append(activeNode); 0636 } 0637 0638 return m_d->layerManager.addCloneLayer(nodes); 0639 } else if (nodeType == "KisTransparencyMask") { 0640 return m_d->maskManager.createTransparencyMask(activeNode, copyFrom, false); 0641 } else if (nodeType == "KisFilterMask") { 0642 return m_d->maskManager.createFilterMask(activeNode, copyFrom, quiet, false); 0643 } else if (nodeType == "KisColorizeMask") { 0644 return m_d->maskManager.createColorizeMask(activeNode); 0645 } else if (nodeType == "KisTransformMask") { 0646 return m_d->maskManager.createTransformMask(activeNode); 0647 } else if (nodeType == "KisSelectionMask") { 0648 return m_d->maskManager.createSelectionMask(activeNode, copyFrom, false); 0649 } else if (nodeType == "KisFileLayer") { 0650 return m_d->layerManager.addFileLayer(activeNode); 0651 } 0652 return 0; 0653 } 0654 0655 void KisNodeManager::createFromVisible() 0656 { 0657 KisLayerUtils::newLayerFromVisible(m_d->view->image(), m_d->view->image()->root()->lastChild()); 0658 } 0659 0660 void KisNodeManager::slotPinToTimeline(bool value) 0661 { 0662 Q_FOREACH (KisNodeSP node, selectedNodes()) { 0663 node->setPinnedToTimeline(value); 0664 } 0665 } 0666 0667 KisLayerSP KisNodeManager::createPaintLayer() 0668 { 0669 KisNodeSP node = createNode("KisPaintLayer"); 0670 return dynamic_cast<KisLayer*>(node.data()); 0671 } 0672 0673 void KisNodeManager::convertNode(const QString &nodeType) 0674 { 0675 if (!m_d->view->blockUntilOperationsFinished(m_d->view->image())) { 0676 return; 0677 } 0678 0679 KisNodeSP activeNode = this->activeNode(); 0680 if (!activeNode) return; 0681 0682 if (!canModifyLayer(activeNode)) return; 0683 0684 if (nodeType == "KisPaintLayer") { 0685 m_d->layerManager.convertNodeToPaintLayer(activeNode); 0686 } else if (nodeType == "KisSelectionMask" || 0687 nodeType == "KisFilterMask" || 0688 nodeType == "KisTransparencyMask") { 0689 0690 KisPaintDeviceSP copyFrom = activeNode->paintDevice() ? 0691 activeNode->paintDevice() : activeNode->projection(); 0692 0693 m_d->commandsAdapter.beginMacro(kundo2_i18n("Convert to a Selection Mask")); 0694 0695 bool result = false; 0696 0697 if (nodeType == "KisSelectionMask") { 0698 result = !m_d->maskManager.createSelectionMask(activeNode, copyFrom, true).isNull(); 0699 } else if (nodeType == "KisFilterMask") { 0700 result = !m_d->maskManager.createFilterMask(activeNode, copyFrom, false, true).isNull(); 0701 } else if (nodeType == "KisTransparencyMask") { 0702 result = !m_d->maskManager.createTransparencyMask(activeNode, copyFrom, true).isNull(); 0703 } 0704 0705 m_d->commandsAdapter.endMacro(); 0706 0707 if (!result) { 0708 m_d->view->blockUntilOperationsFinishedForced(m_d->imageView->image()); 0709 m_d->commandsAdapter.undoLastCommand(); 0710 } 0711 0712 } else if (nodeType == "KisFileLayer") { 0713 m_d->layerManager.convertLayerToFileLayer(activeNode); 0714 } else { 0715 warnKrita << "Unsupported node conversion type:" << nodeType; 0716 } 0717 } 0718 0719 void KisNodeManager::slotSomethingActivatedNodeImpl(KisNodeSP node) 0720 { 0721 KisDummiesFacadeBase *dummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(m_d->imageView->document()->shapeController()); 0722 KIS_SAFE_ASSERT_RECOVER_RETURN(dummiesFacade); 0723 0724 const bool nodeVisible = !isNodeHidden(node, !m_d->nodeDisplayModeAdapter->showGlobalSelectionMask()); 0725 if (!nodeVisible) { 0726 return; 0727 } 0728 0729 KIS_ASSERT_RECOVER_RETURN(node != activeNode()); 0730 if (m_d->activateNodeImpl(node)) { 0731 emit sigUiNeedChangeActiveNode(node); 0732 emit sigNodeActivated(node); 0733 nodesUpdated(); 0734 if (node) { 0735 bool toggled = m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked(); 0736 if (toggled) { 0737 m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine); 0738 } 0739 } 0740 } 0741 } 0742 0743 void KisNodeManager::slotNonUiActivatedNode(KisNodeSP node) 0744 { 0745 // the node must still be in the graph, some asynchronous 0746 // signals may easily break this requirement 0747 if (node && !node->graphListener()) { 0748 node = 0; 0749 } 0750 0751 if (node == activeNode()) return; 0752 0753 slotSomethingActivatedNodeImpl(node); 0754 0755 if (node) { 0756 bool toggled = m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked(); 0757 if (toggled) { 0758 m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine); 0759 } 0760 } 0761 } 0762 0763 void KisNodeManager::slotUiActivatedNode(KisNodeSP node) 0764 { 0765 // the node must still be in the graph, some asynchronous 0766 // signals may easily break this requirement 0767 if (node && !node->graphListener()) { 0768 node = 0; 0769 } 0770 0771 if (node) { 0772 QStringList vectorTools = QStringList() 0773 << "InteractionTool" 0774 << "KarbonGradientTool" 0775 << "KarbonCalligraphyTool" 0776 << "PathTool"; 0777 0778 QStringList pixelTools = QStringList() 0779 << "KritaShape/KisToolBrush" 0780 << "KritaShape/KisToolDyna" 0781 << "KritaShape/KisToolMultiBrush" 0782 << "KritaFill/KisToolFill" 0783 << "KritaFill/KisToolGradient"; 0784 0785 0786 KisSelectionMask *selectionMask = dynamic_cast<KisSelectionMask*>(node.data()); 0787 const bool nodeHasVectorAbilities = node->inherits("KisShapeLayer") || 0788 (selectionMask && selectionMask->selection()->hasShapeSelection()); 0789 0790 if (nodeHasVectorAbilities) { 0791 if (pixelTools.contains(KoToolManager::instance()->activeToolId())) { 0792 KoToolManager::instance()->switchToolRequested("InteractionTool"); 0793 } 0794 } 0795 else { 0796 if (vectorTools.contains(KoToolManager::instance()->activeToolId())) { 0797 KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush"); 0798 } 0799 } 0800 } 0801 0802 if (node == activeNode()) return; 0803 0804 slotSomethingActivatedNodeImpl(node); 0805 } 0806 0807 void KisNodeManager::nodesUpdated() 0808 { 0809 KisNodeSP node = activeNode(); 0810 if (!node) return; 0811 0812 m_d->layerManager.layersUpdated(); 0813 m_d->maskManager.masksUpdated(); 0814 0815 m_d->view->updateGUI(); 0816 m_d->view->selectionManager()->selectionChanged(); 0817 0818 { 0819 KisSignalsBlocker b(m_d->pinToTimeline); 0820 m_d->pinToTimeline->setChecked(node->isPinnedToTimeline()); 0821 } 0822 } 0823 0824 KisPaintDeviceSP KisNodeManager::activePaintDevice() 0825 { 0826 return m_d->maskManager.activeMask() ? 0827 m_d->maskManager.activeDevice() : 0828 m_d->layerManager.activeDevice(); 0829 } 0830 0831 void KisNodeManager::nodeProperties(KisNodeSP node) 0832 { 0833 if ((selectedNodes().size() > 1 && node->inherits("KisLayer")) || node->inherits("KisLayer")) { 0834 m_d->layerManager.layerProperties(); 0835 } 0836 else if (node->inherits("KisMask")) { 0837 m_d->maskManager.maskProperties(); 0838 } 0839 } 0840 0841 void KisNodeManager::changeCloneSource() 0842 { 0843 m_d->layerManager.changeCloneSource(); 0844 } 0845 0846 qint32 KisNodeManager::convertOpacityToInt(qreal opacity) 0847 { 0848 /** 0849 * Scales opacity from the range 0...100 0850 * to the integer range 0...255 0851 */ 0852 0853 return qMin(255, int(opacity * 2.55 + 0.5)); 0854 } 0855 0856 void KisNodeManager::setNodeName(KisNodeSP node, const QString &name) 0857 { 0858 if (!node) return; 0859 if (node->name() == name) return; 0860 0861 m_d->commandsAdapter.setNodeName(node, name); 0862 0863 } 0864 0865 void KisNodeManager::setNodeOpacity(KisNodeSP node, qint32 opacity) 0866 { 0867 if (!node) return; 0868 if (node->opacity() == opacity) return; 0869 0870 m_d->commandsAdapter.setOpacity(node, opacity); 0871 } 0872 0873 void KisNodeManager::setNodeCompositeOp(KisNodeSP node, 0874 const KoCompositeOp* compositeOp) 0875 { 0876 if (!node) return; 0877 if (node->compositeOp() == compositeOp) return; 0878 0879 m_d->commandsAdapter.setCompositeOp(node, compositeOp); 0880 } 0881 0882 void KisNodeManager::slotImageRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes) 0883 { 0884 if (activeNode) { 0885 slotNonUiActivatedNode(activeNode); 0886 } 0887 if (!selectedNodes.isEmpty()) { 0888 slotSetSelectedNodes(selectedNodes); 0889 } 0890 } 0891 0892 void KisNodeManager::slotSetSelectedNodes(const KisNodeList &nodes) 0893 { 0894 m_d->selectedNodes = nodes; 0895 emit sigUiNeedChangeSelectedNodes(nodes); 0896 } 0897 0898 KisNodeList KisNodeManager::selectedNodes() 0899 { 0900 return m_d->selectedNodes; 0901 } 0902 0903 KisNodeSelectionAdapter* KisNodeManager::nodeSelectionAdapter() const 0904 { 0905 return m_d->nodeSelectionAdapter.data(); 0906 } 0907 0908 KisNodeInsertionAdapter* KisNodeManager::nodeInsertionAdapter() const 0909 { 0910 return m_d->nodeInsertionAdapter.data(); 0911 } 0912 0913 KisNodeDisplayModeAdapter *KisNodeManager::nodeDisplayModeAdapter() const 0914 { 0915 return m_d->nodeDisplayModeAdapter.data(); 0916 } 0917 0918 bool KisNodeManager::isNodeHidden(KisNodeSP node, bool isGlobalSelectionHidden) 0919 { 0920 if (node && node->isFakeNode()) { 0921 return true; 0922 } 0923 0924 if (isGlobalSelectionHidden && dynamic_cast<KisSelectionMask *>(node.data()) && 0925 (!node->parent() || !node->parent()->parent())) { 0926 return true; 0927 } 0928 0929 return false; 0930 } 0931 0932 bool KisNodeManager::trySetNodeProperties(KisNodeSP node, KisImageSP image, KisBaseNode::PropertyList properties) const 0933 { 0934 const KisPaintLayer *paintLayer = dynamic_cast<KisPaintLayer*>(node.data()); 0935 if (paintLayer) { 0936 const auto onionSkinOn = KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::onionSkins, true); 0937 0938 if (properties.contains(onionSkinOn)) { 0939 const KisPaintDeviceSP &paintDevice = paintLayer->paintDevice(); 0940 if (paintDevice && paintDevice->defaultPixel().opacityU8() == 255) { 0941 m_d->view->showFloatingMessage(i18n("Onion skins require a layer with transparent background."), QIcon()); 0942 return false; 0943 } 0944 } 0945 } 0946 0947 KisNodePropertyListCommand::setNodePropertiesAutoUndo(node, image, properties); 0948 0949 return true; 0950 } 0951 0952 void KisNodeManager::nodeOpacityChanged(qreal opacity) 0953 { 0954 KisNodeSP node = activeNode(); 0955 0956 setNodeOpacity(node, convertOpacityToInt(opacity)); 0957 } 0958 0959 void KisNodeManager::nodeCompositeOpChanged(const KoCompositeOp* op) 0960 { 0961 KisNodeSP node = activeNode(); 0962 0963 setNodeCompositeOp(node, op); 0964 } 0965 0966 void KisNodeManager::duplicateActiveNode() 0967 { 0968 KUndo2MagicString actionName = kundo2_i18n("Duplicate Nodes"); 0969 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 0970 juggler->duplicateNode(selectedNodes()); 0971 } 0972 0973 KisNodeJugglerCompressed* KisNodeManager::Private::lazyGetJuggler(const KUndo2MagicString &actionName) 0974 { 0975 KisImageWSP image = view->image(); 0976 0977 if (!nodeJuggler || 0978 (nodeJuggler && 0979 (nodeJuggler->isEnded() || 0980 !nodeJuggler->canMergeAction(actionName)))) { 0981 0982 nodeJuggler = new KisNodeJugglerCompressed(actionName, image, q, 750); 0983 nodeJuggler->setAutoDelete(true); 0984 } 0985 0986 return nodeJuggler; 0987 } 0988 0989 void KisNodeManager::raiseNode() 0990 { 0991 if (!canMoveLayers(selectedNodes())) return; 0992 0993 KUndo2MagicString actionName = kundo2_i18n("Raise Nodes"); 0994 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 0995 juggler->raiseNode(selectedNodes()); 0996 } 0997 0998 void KisNodeManager::lowerNode() 0999 { 1000 if (!canMoveLayers(selectedNodes())) return; 1001 1002 KUndo2MagicString actionName = kundo2_i18n("Lower Nodes"); 1003 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1004 juggler->lowerNode(selectedNodes()); 1005 } 1006 1007 void KisNodeManager::removeSingleNode(KisNodeSP node) 1008 { 1009 if (!node || !node->parent()) { 1010 return; 1011 } 1012 1013 KisNodeList nodes; 1014 nodes << node; 1015 removeSelectedNodes(nodes); 1016 } 1017 1018 void KisNodeManager::removeSelectedNodes(KisNodeList nodes) 1019 { 1020 if (!canModifyLayers(nodes)) return; 1021 1022 KUndo2MagicString actionName = kundo2_i18n("Remove Nodes"); 1023 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1024 juggler->removeNode(nodes); 1025 } 1026 1027 void KisNodeManager::removeNode() 1028 { 1029 removeSelectedNodes(selectedNodes()); 1030 } 1031 1032 void KisNodeManager::mirrorNodeX() 1033 { 1034 KisNodeList nodes = selectedNodes(); 1035 1036 KUndo2MagicString commandName; 1037 if (nodes.size() == 1 && nodes[0]->inherits("KisMask")) { 1038 commandName = kundo2_i18n("Mirror Mask Horizontally"); 1039 } 1040 else { 1041 commandName = kundo2_i18np("Mirror Layer Horizontally", "Mirror %1 Layers Horizontally", nodes.size()); 1042 } 1043 mirrorNodes(nodes, commandName, Qt::Horizontal, m_d->view->selection()); 1044 } 1045 1046 void KisNodeManager::mirrorNodeY() 1047 { 1048 KisNodeList nodes = selectedNodes(); 1049 1050 KUndo2MagicString commandName; 1051 if (nodes.size() == 1 && nodes[0]->inherits("KisMask")) { 1052 commandName = kundo2_i18n("Mirror Mask Vertically"); 1053 } 1054 else { 1055 commandName = kundo2_i18np("Mirror Layer Vertically", "Mirror %1 Layers Vertically", nodes.size()); 1056 } 1057 mirrorNodes(nodes, commandName, Qt::Vertical, m_d->view->selection()); 1058 } 1059 1060 void KisNodeManager::mirrorAllNodesX() 1061 { 1062 KisNodeSP node = m_d->view->image()->root(); 1063 mirrorNode(node, kundo2_i18n("Mirror All Layers Horizontally"), 1064 Qt::Horizontal, m_d->view->selection()); 1065 } 1066 1067 void KisNodeManager::mirrorAllNodesY() 1068 { 1069 KisNodeSP node = m_d->view->image()->root(); 1070 mirrorNode(node, kundo2_i18n("Mirror All Layers Vertically"), 1071 Qt::Vertical, m_d->view->selection()); 1072 } 1073 1074 void KisNodeManager::activateNextNode(bool siblingsOnly) 1075 { 1076 KisNodeSP activeNode = this->activeNode(); 1077 if (!activeNode) return; 1078 1079 KisNodeSP nextNode = activeNode->nextSibling(); 1080 1081 if (!siblingsOnly) { 1082 // Recurse groups... 1083 while (nextNode && nextNode->childCount() > 0) { 1084 nextNode = nextNode->firstChild(); 1085 } 1086 1087 // Out of nodes? Back out of group... 1088 if (!nextNode && activeNode->parent()) { 1089 nextNode = activeNode->parent(); 1090 } 1091 } 1092 1093 // Skip nodes hidden from tree view.. 1094 while (nextNode && isNodeHidden(nextNode, m_d->nodeDisplayModeAdapter->showGlobalSelectionMask())) { 1095 nextNode = nextNode->nextSibling(); 1096 } 1097 1098 // Select node, unless root.. 1099 if (nextNode && nextNode->parent()) { 1100 slotNonUiActivatedNode(nextNode); 1101 } 1102 } 1103 1104 void KisNodeManager::activateNextSiblingNode() 1105 { 1106 activateNextNode(true); 1107 } 1108 1109 void KisNodeManager::activatePreviousNode(bool siblingsOnly) 1110 { 1111 KisNodeSP activeNode = this->activeNode(); 1112 if (!activeNode) return; 1113 1114 KisNodeSP nextNode = activeNode->prevSibling(); 1115 1116 if (!siblingsOnly) { 1117 // Enter groups.. 1118 if (activeNode->childCount() > 0) { 1119 nextNode = activeNode->lastChild(); 1120 } 1121 1122 // Out of nodes? Back out of group... 1123 if (!nextNode && activeNode->parent()) { 1124 nextNode = activeNode->parent()->prevSibling(); 1125 } 1126 } 1127 1128 // Skip nodes hidden from tree view.. 1129 while (nextNode && isNodeHidden(nextNode, m_d->nodeDisplayModeAdapter->showGlobalSelectionMask())) { 1130 nextNode = nextNode->prevSibling(); 1131 } 1132 1133 // Select node, unless root.. 1134 if (nextNode && nextNode->parent()) { 1135 slotNonUiActivatedNode(nextNode); 1136 } 1137 } 1138 1139 void KisNodeManager::activatePreviousSiblingNode() 1140 { 1141 activatePreviousNode(true); 1142 } 1143 1144 void KisNodeManager::switchToPreviouslyActiveNode() 1145 { 1146 if (m_d->previouslyActiveNode && m_d->previouslyActiveNode->parent()) { 1147 slotNonUiActivatedNode(m_d->previouslyActiveNode); 1148 } 1149 } 1150 1151 void KisNodeManager::mirrorNode(KisNodeSP node, 1152 const KUndo2MagicString& actionName, 1153 Qt::Orientation orientation, 1154 KisSelectionSP selection) 1155 { 1156 KisNodeList nodes = {node}; 1157 mirrorNodes(nodes, actionName, orientation, selection); 1158 } 1159 1160 void KisNodeManager::mirrorNodes(KisNodeList nodes, 1161 const KUndo2MagicString& actionName, 1162 Qt::Orientation orientation, 1163 KisSelectionSP selection) 1164 { 1165 Q_FOREACH(KisNodeSP node, nodes) { 1166 if (!canModifyLayer(node)) return; 1167 } 1168 1169 KisImageSignalVector emitSignals; 1170 1171 KisProcessingApplicator applicator(m_d->view->image(), nodes, 1172 KisProcessingApplicator::RECURSIVE, 1173 emitSignals, actionName); 1174 1175 KisProcessingVisitorSP visitor; 1176 1177 if (selection) { 1178 visitor = new KisMirrorProcessingVisitor(selection, orientation); 1179 } else { 1180 visitor = new KisMirrorProcessingVisitor(m_d->view->image()->bounds(), orientation); 1181 } 1182 1183 if (!selection) { 1184 applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); 1185 } else { 1186 applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT); 1187 } 1188 1189 applicator.end(); 1190 1191 nodesUpdated(); 1192 } 1193 1194 void KisNodeManager::Private::saveDeviceAsImage(KisPaintDeviceSP device, 1195 const QString &defaultName, 1196 const QRect &bounds, 1197 qreal xRes, 1198 qreal yRes, 1199 quint8 opacity) 1200 { 1201 KoFileDialog dialog(view->mainWindowAsQWidget(), KoFileDialog::SaveFile, "savenodeasimage"); 1202 dialog.setCaption(i18n("Export \"%1\"", defaultName)); 1203 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); 1204 dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export)); 1205 QString filename = dialog.filename(); 1206 1207 if (filename.isEmpty()) return; 1208 1209 1210 if (filename.isEmpty()) return; 1211 1212 QString mimefilter = KisMimeDatabase::mimeTypeForFile(filename, false); 1213 1214 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument()); 1215 1216 KisImageSP dst = new KisImage(doc->createUndoStore(), 1217 bounds.width(), 1218 bounds.height(), 1219 device->compositionSourceColorSpace(), 1220 defaultName); 1221 dst->setResolution(xRes, yRes); 1222 doc->setCurrentImage(dst); 1223 KisPaintLayer* paintLayer = new KisPaintLayer(dst, "paint device", opacity); 1224 paintLayer->paintDevice()->makeCloneFrom(device, bounds); 1225 dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0)); 1226 1227 dst->initialRefreshGraph(); 1228 1229 if (!doc->exportDocumentSync(filename, mimefilter.toLatin1())) { 1230 QMessageBox::warning(qApp->activeWindow(), 1231 i18nc("@title:window", "Krita"), 1232 i18n("Could not save the layer. %1", doc->errorMessage().toUtf8().data()), 1233 QMessageBox::Ok); 1234 1235 } 1236 } 1237 1238 void KisNodeManager::saveNodeAsImage() 1239 { 1240 KisNodeSP node = activeNode(); 1241 1242 if (!node) { 1243 warnKrita << "BUG: Save Node As Image was called without any node selected"; 1244 return; 1245 } 1246 1247 KisPaintDeviceSP saveDevice = node->projection(); 1248 1249 if (!saveDevice) { 1250 m_d->view->showFloatingMessage(i18nc("warning message when trying to export a transform mask", "Layer has no pixel data"), QIcon()); 1251 return; 1252 } 1253 1254 KisImageSP image = m_d->view->image(); 1255 QRect saveRect = image->bounds() | node->exactBounds(); 1256 1257 m_d->saveDeviceAsImage(saveDevice, 1258 node->name(), 1259 saveRect, 1260 image->xRes(), image->yRes(), 1261 node->opacity()); 1262 } 1263 1264 #include "SvgWriter.h" 1265 1266 void KisNodeManager::saveVectorLayerAsImage() 1267 { 1268 KisShapeLayerSP shapeLayer = qobject_cast<KisShapeLayer*>(activeNode().data()); 1269 if (!shapeLayer) { 1270 return; 1271 } 1272 1273 KoFileDialog dialog(m_d->view->mainWindowAsQWidget(), KoFileDialog::SaveFile, "savenodeasimage"); 1274 dialog.setCaption(i18nc("@title:window", "Export to SVG")); 1275 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); 1276 dialog.setMimeTypeFilters(QStringList() << "image/svg+xml", "image/svg+xml"); 1277 QString filename = dialog.filename(); 1278 1279 if (filename.isEmpty()) return; 1280 1281 QUrl url = QUrl::fromLocalFile(filename); 1282 1283 if (url.isEmpty()) return; 1284 1285 const QSizeF sizeInPx = m_d->view->image()->bounds().size(); 1286 const QSizeF sizeInPt(sizeInPx.width() / m_d->view->image()->xRes(), 1287 sizeInPx.height() / m_d->view->image()->yRes()); 1288 1289 QList<KoShape*> shapes = shapeLayer->shapes(); 1290 std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex); 1291 1292 SvgWriter writer(shapes); 1293 if (!writer.save(filename, sizeInPt, true)) { 1294 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita"), i18n("Could not save to svg: %1", filename)); 1295 } 1296 } 1297 1298 void KisNodeManager::slotSplitAlphaIntoMask() 1299 { 1300 1301 KisNodeSP node = activeNode(); 1302 if (!canModifyLayer(node)) return; 1303 1304 // guaranteed by KisActionManager 1305 KIS_ASSERT_RECOVER_RETURN(node->hasEditablePaintDevice()); 1306 1307 KisLayerUtils::splitAlphaToMask(node->image(), node, m_d->maskManager.createMaskNameCommon(node, "KisTransparencyMask", i18n("Transparency Mask"))); 1308 } 1309 1310 void KisNodeManager::Private::mergeTransparencyMaskAsAlpha(bool writeToLayers) 1311 { 1312 KisNodeSP node = q->activeNode(); 1313 KisNodeSP parentNode = node->parent(); 1314 1315 // guaranteed by KisActionManager 1316 KIS_ASSERT_RECOVER_RETURN(node->inherits("KisTransparencyMask")); 1317 1318 if (writeToLayers && (!parentNode->hasEditablePaintDevice() || !node->isEditable(false))) { 1319 QMessageBox::information(view->mainWindowAsQWidget(), 1320 i18nc("@title:window", "Layer %1 is not editable", parentNode->name()), 1321 i18n("Cannot write alpha channel of " 1322 "the parent layer \"%1\".\n" 1323 "The operation will be cancelled.", parentNode->name())); 1324 return; 1325 } 1326 1327 KisPaintDeviceSP dstDevice; 1328 if (writeToLayers) { 1329 KIS_ASSERT_RECOVER_RETURN(parentNode->paintDevice()); 1330 dstDevice = parentNode->paintDevice(); 1331 } else { 1332 KisPaintDeviceSP copyDevice = parentNode->paintDevice(); 1333 if (!copyDevice) { 1334 copyDevice = parentNode->original(); 1335 } 1336 dstDevice = new KisPaintDevice(*copyDevice); 1337 } 1338 1339 const KoColorSpace *dstCS = dstDevice->colorSpace(); 1340 1341 KisPaintDeviceSP selectionDevice = node->paintDevice(); 1342 KIS_ASSERT_RECOVER_RETURN(selectionDevice->colorSpace()->pixelSize() == 1); 1343 1344 const QRect processRect = 1345 selectionDevice->exactBounds() | 1346 dstDevice->exactBounds() | 1347 selectionDevice->defaultBounds()->bounds(); 1348 1349 QScopedPointer<KisTransaction> transaction; 1350 1351 if (writeToLayers) { 1352 commandsAdapter.beginMacro(kundo2_i18n("Write Alpha into a Layer")); 1353 transaction.reset(new KisTransaction(kundo2_noi18n("__write_alpha_channel__"), dstDevice)); 1354 } 1355 1356 KisSequentialIterator srcIt(selectionDevice, processRect); 1357 KisSequentialIterator dstIt(dstDevice, processRect); 1358 1359 while (srcIt.nextPixel() && dstIt.nextPixel()) { 1360 quint8 *alpha8Ptr = srcIt.rawData(); 1361 quint8 *dstPtr = dstIt.rawData(); 1362 1363 dstCS->setOpacity(dstPtr, *alpha8Ptr, 1); 1364 } 1365 1366 if (writeToLayers) { 1367 commandsAdapter.addExtraCommand(transaction->endAndTake()); 1368 commandsAdapter.removeNode(node); 1369 commandsAdapter.endMacro(); 1370 } else { 1371 KisImageWSP image = view->image(); 1372 QRect saveRect = image->bounds(); 1373 1374 saveDeviceAsImage(dstDevice, parentNode->name(), 1375 saveRect, 1376 image->xRes(), image->yRes(), 1377 OPACITY_OPAQUE_U8); 1378 } 1379 } 1380 1381 1382 void KisNodeManager::slotSplitAlphaWrite() 1383 { 1384 m_d->mergeTransparencyMaskAsAlpha(true); 1385 } 1386 1387 void KisNodeManager::slotSplitAlphaSaveMerged() 1388 { 1389 m_d->mergeTransparencyMaskAsAlpha(false); 1390 } 1391 1392 void KisNodeManager::toggleLock() 1393 { 1394 KisNodeList nodes = this->selectedNodes(); 1395 KisNodeSP active = activeNode(); 1396 if (nodes.isEmpty() || !active) return; 1397 1398 bool isLocked = active->userLocked(); 1399 1400 for (auto &node : nodes) { 1401 KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::locked, !isLocked, m_d->view->image()); 1402 } 1403 } 1404 1405 void KisNodeManager::toggleVisibility() 1406 { 1407 KisNodeList nodes = this->selectedNodes(); 1408 KisNodeSP active = activeNode(); 1409 if (nodes.isEmpty() || !active) return; 1410 1411 bool isVisible = active->visible(); 1412 1413 for (auto &node : nodes) { 1414 KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::visible, !isVisible, m_d->view->image()); 1415 } 1416 } 1417 1418 void KisNodeManager::toggleAlphaLock() 1419 { 1420 KisNodeList nodes = this->selectedNodes(); 1421 KisNodeSP active = activeNode(); 1422 if (nodes.isEmpty() || !active) return; 1423 1424 auto layer = qobject_cast<KisPaintLayer*>(active.data()); 1425 if (!layer) { 1426 return; 1427 } 1428 1429 bool isAlphaLocked = layer->alphaLocked(); 1430 for (auto &node : nodes) { 1431 auto layer = qobject_cast<KisPaintLayer*>(node.data()); 1432 if (layer) { 1433 KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::alphaLocked, !isAlphaLocked, m_d->view->image()); 1434 } 1435 } 1436 } 1437 1438 void KisNodeManager::toggleInheritAlpha() 1439 { 1440 KisNodeList nodes = this->selectedNodes(); 1441 KisNodeSP active = activeNode(); 1442 if (nodes.isEmpty() || !active) return; 1443 1444 auto layer = qobject_cast<KisLayer*>(active.data()); 1445 if (!layer) { 1446 return; 1447 } 1448 1449 bool isAlphaDisabled = layer->alphaChannelDisabled(); 1450 for (auto &node : nodes) { 1451 auto layer = qobject_cast<KisLayer*>(node.data()); 1452 if (layer) { 1453 KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::inheritAlpha, !isAlphaDisabled, m_d->view->image()); 1454 } 1455 } 1456 } 1457 1458 void KisNodeManager::cutLayersToClipboard() 1459 { 1460 KisNodeList nodes = this->selectedNodes(); 1461 if (nodes.isEmpty()) return; 1462 1463 KisNodeList::Iterator it = nodes.begin(); 1464 while (it != nodes.end()) { 1465 // make sure the deleted nodes aren't referenced here again 1466 if (!it->data()->parent()) { 1467 nodes.erase(it); 1468 } 1469 it++; 1470 } 1471 1472 KisClipboard::instance()->setLayers(nodes, m_d->view->image(), false); 1473 1474 if (canModifyLayers(nodes)) { 1475 KUndo2MagicString actionName = kundo2_i18n("Cut Nodes"); 1476 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1477 juggler->removeNode(nodes); 1478 } 1479 } 1480 1481 void KisNodeManager::copyLayersToClipboard() 1482 { 1483 KisNodeList nodes = this->selectedNodes(); 1484 KisClipboard::instance()->setLayers(nodes, m_d->view->image(), true); 1485 } 1486 1487 void KisNodeManager::pasteLayersFromClipboard(bool changeOffset, QPointF offset) 1488 { 1489 const QMimeData *data = KisClipboard::instance()->layersMimeData(); 1490 if (!data) return; 1491 1492 KisNodeSP activeNode = this->activeNode(); 1493 1494 KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController()); 1495 Q_ASSERT(shapeController); 1496 1497 KisDummiesFacadeBase *dummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(m_d->imageView->document()->shapeController()); 1498 Q_ASSERT(dummiesFacade); 1499 1500 const bool copyNode = false; 1501 KisImageSP image = m_d->view->image(); 1502 KisNodeDummy *parentDummy = dummiesFacade->dummyForNode(activeNode); 1503 KisNodeDummy *aboveThisDummy = parentDummy ? parentDummy->lastChild() : 0; 1504 1505 KisMimeData::insertMimeLayers(data, 1506 image, 1507 shapeController, 1508 parentDummy, 1509 aboveThisDummy, 1510 copyNode, 1511 nodeInsertionAdapter(), 1512 changeOffset, 1513 offset); 1514 } 1515 1516 bool KisNodeManager::createQuickGroupImpl(KisNodeJugglerCompressed *juggler, 1517 const QString &overrideGroupName, 1518 KisNodeSP *newGroup, 1519 KisNodeSP *newLastChild) 1520 { 1521 KisNodeSP active = activeNode(); 1522 if (!active) return false; 1523 1524 if (!canMoveLayer(active)) return false; 1525 1526 KisImageSP image = m_d->view->image(); 1527 QString groupName = !overrideGroupName.isEmpty() ? overrideGroupName : image->nextLayerName(i18nc("A group of layers", "Group")); 1528 KisGroupLayerSP group = new KisGroupLayer(image.data(), groupName, OPACITY_OPAQUE_U8); 1529 1530 KisNodeList nodes1; 1531 nodes1 << group; 1532 1533 KisNodeList nodes2; 1534 nodes2 = KisLayerUtils::sortMergeableNodes(image->root(), selectedNodes()); 1535 KisLayerUtils::filterMergeableNodes(nodes2); 1536 1537 if (nodes2.size() == 0) return false; 1538 1539 if (KisLayerUtils::checkIsChildOf(active, nodes2)) { 1540 active = nodes2.first(); 1541 } 1542 1543 KisNodeSP parent = active->parent(); 1544 KisNodeSP aboveThis = active; 1545 1546 juggler->addNode(nodes1, parent, aboveThis); 1547 juggler->moveNode(nodes2, group, 0); 1548 1549 *newGroup = group; 1550 *newLastChild = nodes2.last(); 1551 1552 return true; 1553 } 1554 1555 void KisNodeManager::createQuickGroup() 1556 { 1557 KUndo2MagicString actionName = kundo2_i18n("Quick Group"); 1558 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1559 1560 KisNodeSP parent; 1561 KisNodeSP above; 1562 1563 createQuickGroupImpl(juggler, "", &parent, &above); 1564 } 1565 1566 void KisNodeManager::createQuickClippingGroup() 1567 { 1568 KUndo2MagicString actionName = kundo2_i18n("Quick Clipping Group"); 1569 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1570 1571 KisNodeSP parent; 1572 KisNodeSP above; 1573 1574 KisImageSP image = m_d->view->image(); 1575 if (createQuickGroupImpl(juggler, image->nextLayerName(i18nc("default name for a clipping group layer", "Clipping Group")), &parent, &above)) { 1576 KisPaintLayerSP maskLayer = new KisPaintLayer(image.data(), i18nc("default name for quick clip group mask layer", "Mask Layer"), OPACITY_OPAQUE_U8, image->colorSpace()); 1577 maskLayer->disableAlphaChannel(true); 1578 1579 juggler->addNode(KisNodeList() << maskLayer, parent, above); 1580 } 1581 } 1582 1583 void KisNodeManager::quickUngroup() 1584 { 1585 KisNodeSP active = activeNode(); 1586 if (!active) return; 1587 1588 if (!canModifyLayer(active)) return; 1589 1590 KisNodeSP parent = active->parent(); 1591 KisNodeSP aboveThis = active; 1592 1593 auto checkCanMoveLayers = [this] (KisNodeList nodes, KisNodeSP newParent) -> bool { 1594 auto incompatibleNode = 1595 std::find_if(nodes.begin(), nodes.end(), 1596 [newParent] (KisNodeSP node) { 1597 return !newParent->allowAsChild(node); 1598 }); 1599 1600 if (incompatibleNode != nodes.end()) { 1601 const QString message = 1602 newParent->parent() ? 1603 i18n("Cannot move layer \"%1\" into new parent \"%2\"", 1604 (*incompatibleNode)->name(), 1605 newParent->name()) : 1606 i18n("Cannot move layer \"%1\" into the root layer", 1607 (*incompatibleNode)->name()); 1608 m_d->view->showFloatingMessage(message, QIcon()); 1609 return false; 1610 } 1611 return true; 1612 }; 1613 1614 KUndo2MagicString actionName = kundo2_i18n("Quick Ungroup"); 1615 1616 if (parent && dynamic_cast<KisGroupLayer*>(active.data())) { 1617 KisNodeList nodes = active->childNodes(QStringList(), KoProperties()); 1618 1619 if (checkCanMoveLayers(nodes, parent)) { 1620 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1621 juggler->moveNode(nodes, parent, active); 1622 juggler->removeNode(KisNodeList() << active); 1623 } 1624 } else if (parent && parent->parent()) { 1625 KisNodeSP grandParent = parent->parent(); 1626 1627 KisNodeList allChildNodes = parent->childNodes(QStringList(), KoProperties()); 1628 KisNodeList allSelectedNodes = selectedNodes(); 1629 1630 const bool removeParent = KritaUtils::compareListsUnordered(allChildNodes, allSelectedNodes); 1631 1632 if (checkCanMoveLayers(allSelectedNodes, parent)) { 1633 KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); 1634 juggler->moveNode(allSelectedNodes, grandParent, parent); 1635 if (removeParent) { 1636 juggler->removeNode(KisNodeList() << parent); 1637 } 1638 } 1639 } 1640 } 1641 1642 void KisNodeManager::selectLayersImpl(const KoProperties &props, const KoProperties &invertedProps) 1643 { 1644 KisImageSP image = m_d->view->image(); 1645 KisNodeList nodes = KisLayerUtils::findNodesWithProps(image->root(), props, true); 1646 1647 KisNodeList selectedNodes = this->selectedNodes(); 1648 1649 if (KritaUtils::compareListsUnordered(nodes, selectedNodes)) { 1650 nodes = KisLayerUtils::findNodesWithProps(image->root(), invertedProps, true); 1651 } 1652 1653 if (!nodes.isEmpty()) { 1654 slotImageRequestNodeReselection(nodes.last(), nodes); 1655 } 1656 } 1657 1658 void KisNodeManager::selectAllNodes() 1659 { 1660 KoProperties props; 1661 selectLayersImpl(props, props); 1662 } 1663 1664 void KisNodeManager::selectVisibleNodes() 1665 { 1666 KoProperties props; 1667 props.setProperty("visible", true); 1668 1669 KoProperties invertedProps; 1670 invertedProps.setProperty("visible", false); 1671 1672 selectLayersImpl(props, invertedProps); 1673 } 1674 1675 void KisNodeManager::selectLockedNodes() 1676 { 1677 KoProperties props; 1678 props.setProperty("locked", true); 1679 1680 KoProperties invertedProps; 1681 invertedProps.setProperty("locked", false); 1682 1683 selectLayersImpl(props, invertedProps); 1684 } 1685 1686 void KisNodeManager::selectInvisibleNodes() 1687 { 1688 KoProperties props; 1689 props.setProperty("visible", false); 1690 1691 KoProperties invertedProps; 1692 invertedProps.setProperty("visible", true); 1693 1694 selectLayersImpl(props, invertedProps); 1695 } 1696 1697 void KisNodeManager::selectUnlockedNodes() 1698 { 1699 KoProperties props; 1700 props.setProperty("locked", false); 1701 1702 KoProperties invertedProps; 1703 invertedProps.setProperty("locked", true); 1704 1705 selectLayersImpl(props, invertedProps); 1706 } 1707 1708 void KisNodeManager::slotUiActivateNode() 1709 { 1710 if (!sender()->property("node").isNull()) { 1711 QString name = sender()->property("node").toString(); 1712 KisNodeSP node = KisLayerUtils::findNodeByName(m_d->imageView->image()->rootLayer(),name); 1713 if (node) { 1714 slotUiActivatedNode(node); 1715 } 1716 } 1717 }