File indexing completed on 2024-12-22 04:12:14
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_selection_action_factories.h" 0008 0009 #include <QMimeData> 0010 0011 #include <klocalizedstring.h> 0012 #include <kundo2command.h> 0013 0014 #include <KisMainWindow.h> 0015 #include <KisDocument.h> 0016 #include <KisPart.h> 0017 #include <KoPathShape.h> 0018 #include <KoShapeController.h> 0019 #include <KoShapeRegistry.h> 0020 #include <KoCompositeOpRegistry.h> 0021 #include <KoShapeManager.h> 0022 #include <KoSelection.h> 0023 #include <KoDocumentResourceManager.h> 0024 #include <KoShapeStroke.h> 0025 #include <KoDocumentInfo.h> 0026 #include <KoCanvasBase.h> 0027 0028 #include "KisViewManager.h" 0029 #include "kis_canvas_resource_provider.h" 0030 #include "kis_clipboard.h" 0031 #include "kis_pixel_selection.h" 0032 #include "kis_paint_layer.h" 0033 #include "kis_image.h" 0034 #include "KisImageBarrierLock.h" 0035 #include "kis_fill_painter.h" 0036 #include "kis_transaction.h" 0037 #include "kis_iterator_ng.h" 0038 #include "kis_processing_applicator.h" 0039 #include "kis_group_layer.h" 0040 #include "commands/kis_selection_commands.h" 0041 #include "commands/kis_image_layer_add_command.h" 0042 #include "kis_tool_proxy.h" 0043 #include "kis_canvas2.h" 0044 #include "kis_canvas_controller.h" 0045 #include "kis_selection_manager.h" 0046 #include "commands_new/kis_transaction_based_command.h" 0047 #include "kis_selection_filters.h" 0048 #include "kis_shape_selection.h" 0049 #include "kis_shape_layer.h" 0050 #include <kis_shape_controller.h> 0051 #include "kis_image_animation_interface.h" 0052 #include "kis_time_span.h" 0053 #include "kis_keyframe_channel.h" 0054 #include "kis_node_manager.h" 0055 #include "kis_layer_utils.h" 0056 #include <kis_selection_mask.h> 0057 #include <KisReferenceImagesLayer.h> 0058 0059 #include <processing/fill_processing_visitor.h> 0060 #include <kis_selection_tool_helper.h> 0061 0062 #include "kis_figure_painting_tool_helper.h" 0063 #include "kis_update_outline_job.h" 0064 0065 namespace ActionHelper { 0066 0067 void trimDevice(KisViewManager *view, 0068 KisPaintDeviceSP device, 0069 bool makeSharpClip = false, 0070 const KisTimeSpan &range = KisTimeSpan()) 0071 { 0072 Q_UNUSED(range); // TODO: Allow multiple frame operation across a timespan. 0073 0074 KisImageWSP image = view->image(); 0075 if (!image) return; 0076 0077 KisSelectionSP selection = view->selection(); 0078 0079 QRect rc = (selection) ? selection->selectedExactRect() : image->bounds(); 0080 0081 const KoColorSpace *cs = device->colorSpace(); 0082 0083 // We need to allow for trimming from non-transparent defaultPixel layers. 0084 // Default color should be phased out of use when the area in question is not aligned with image bounds. 0085 // Otherwise, we can maintain default pixel. 0086 const bool hasNonTransparentDefaultPixel = device->defaultPixel() != KoColor::createTransparent(device->colorSpace()); 0087 const bool needsTransparentPixel = selection && rc != image->bounds() && hasNonTransparentDefaultPixel; 0088 0089 if (selection) { 0090 // Apply selection mask. 0091 KisPaintDeviceSP selectionProjection = selection->projection(); 0092 const KoColorSpace *selCs = selection->projection()->colorSpace(); 0093 0094 KisSequentialIterator layerIt(device, rc); 0095 KisSequentialConstIterator selectionIt(selectionProjection, rc); 0096 0097 while (layerIt.nextPixel() && selectionIt.nextPixel()) { 0098 0099 /** 0100 * Sharp method is an exact reverse of COMPOSITE_OVER 0101 * so if you cover the cut/copied piece over its source 0102 * you get an exactly the same image without any seams 0103 */ 0104 if (makeSharpClip) { 0105 qreal dstAlpha = cs->opacityF(layerIt.rawData()); 0106 qreal sel = selCs->opacityF(selectionIt.oldRawData()); 0107 qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha); 0108 float mask = newAlpha / dstAlpha; 0109 0110 cs->applyAlphaNormedFloatMask(layerIt.rawData(), &mask, 1); 0111 } else { 0112 cs->applyAlphaU8Mask(layerIt.rawData(), selectionIt.oldRawData(), 1); 0113 } 0114 } 0115 } 0116 0117 0118 0119 if ( needsTransparentPixel ) { 0120 device->setDefaultPixel(KoColor::createTransparent(device->colorSpace())); 0121 device->purgeDefaultPixels(); 0122 } 0123 0124 device->crop(rc); 0125 } 0126 0127 KisImageSP makeImage(KisViewManager *view, KisNodeList nodes) 0128 { 0129 KisImageWSP image = view->image(); 0130 0131 KisImageSP clipImage = new KisImage(0, image->width(), image->height(), image->colorSpace(), "ClipImage"); 0132 clipImage->setResolution(image->xRes(), image->yRes()); 0133 Q_FOREACH (KisNodeSP node, nodes) { 0134 clipImage->addNode(node, clipImage->root()); 0135 } 0136 0137 clipImage->refreshGraphAsync(); 0138 clipImage->waitForDone(); 0139 0140 return clipImage; 0141 } 0142 } 0143 0144 void KisSelectAllActionFactory::run(KisViewManager *view) 0145 { 0146 KisImageWSP image = view->image(); 0147 if (!image) return; 0148 0149 if (view->canvasBase()->toolProxy()->selectAll()) { 0150 return; 0151 } 0152 0153 KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Select All")); 0154 0155 ap->applyCommand(new KisCommandUtils::LambdaCommand( 0156 [image] () { 0157 return !image->globalSelection() ? 0158 new KisSetEmptyGlobalSelectionCommand(image) : 0; 0159 }), 0160 KisStrokeJobData::SEQUENTIAL, 0161 KisStrokeJobData::EXCLUSIVE); 0162 0163 struct SelectAll : public KisTransactionBasedCommand { 0164 SelectAll(KisImageSP image) : m_image(image) {} 0165 KisImageSP m_image; 0166 KUndo2Command* paint() override { 0167 KisSelectionSP selection = m_image->globalSelection(); 0168 KisSelectionTransaction transaction(selection->pixelSelection()); 0169 selection->pixelSelection()->clear(); 0170 selection->pixelSelection()->select(m_image->bounds()); 0171 return transaction.endAndTake(); 0172 } 0173 }; 0174 0175 ap->applyCommand(new SelectAll(image), 0176 KisStrokeJobData::SEQUENTIAL, 0177 KisStrokeJobData::EXCLUSIVE); 0178 0179 endAction(ap, KisOperationConfiguration(id()).toXML()); 0180 } 0181 0182 void KisDeselectActionFactory::run(KisViewManager *view) 0183 { 0184 KisImageWSP image = view->image(); 0185 if (!image) return; 0186 0187 if (view->canvasBase()->toolProxy()->hasSelection()) { 0188 // see KisCutCopyActionFactory::run 0189 KisImageBarrierLock lock(image, std::try_to_lock); 0190 if (!lock.owns_lock()) return; 0191 0192 view->canvasBase()->toolProxy()->deselect(); 0193 return; 0194 } 0195 0196 KUndo2Command *cmd = new KisDeselectActiveSelectionCommand(view->selection(), image); 0197 0198 KisProcessingApplicator *ap = beginAction(view, cmd->text()); 0199 ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); 0200 endAction(ap, KisOperationConfiguration(id()).toXML()); 0201 } 0202 0203 void KisReselectActionFactory::run(KisViewManager *view) 0204 { 0205 KisImageWSP image = view->image(); 0206 if (!image) return; 0207 0208 KUndo2Command *cmd = new KisReselectActiveSelectionCommand(view->activeNode(), image); 0209 0210 KisProcessingApplicator *ap = beginAction(view, cmd->text()); 0211 ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); 0212 endAction(ap, KisOperationConfiguration(id()).toXML()); 0213 } 0214 0215 void KisFillActionFactory::run(const QString &fillSource, KisViewManager *view) 0216 { 0217 KisNodeSP node = view->activeNode(); 0218 if (!node || !node->hasEditablePaintDevice()) return; 0219 0220 KisSelectionSP selection = view->selection(); 0221 QRect selectedRect = selection ? 0222 selection->selectedRect() : view->image()->bounds(); 0223 Q_UNUSED(selectedRect); 0224 KisPaintDeviceSP filled = node->paintDevice()->createCompositionSourceDevice(); 0225 Q_UNUSED(filled); 0226 bool usePattern = false; 0227 bool useBgColor = false; 0228 0229 if (fillSource.contains("pattern")) { 0230 usePattern = true; 0231 } else if (fillSource.contains("bg")) { 0232 useBgColor = true; 0233 } 0234 0235 KisProcessingApplicator applicator(view->image(), node, 0236 KisProcessingApplicator::NONE, 0237 KisImageSignalVector(), 0238 kundo2_i18n("Flood Fill Layer")); 0239 0240 KisResourcesSnapshotSP resources = 0241 new KisResourcesSnapshot(view->image(), node, view->canvasResourceProvider()->resourceManager()); 0242 if (!fillSource.contains("opacity")) { 0243 resources->setOpacity(1.0); 0244 } 0245 0246 FillProcessingVisitor *visitor = 0247 new FillProcessingVisitor(resources->image()->projection(), 0248 selection, 0249 resources); 0250 0251 visitor->setSeedPoint(QPoint(0, 0)); 0252 visitor->setUsePattern(usePattern); 0253 visitor->setSelectionOnly(true); 0254 visitor->setUseBgColor(useBgColor); 0255 0256 applicator.applyVisitor(visitor, 0257 KisStrokeJobData::SEQUENTIAL, 0258 KisStrokeJobData::EXCLUSIVE); 0259 0260 applicator.end(); 0261 0262 view->canvasResourceProvider()->slotPainting(); 0263 } 0264 0265 void KisClearActionFactory::run(KisViewManager *view) 0266 { 0267 // XXX: "Add saving of XML data for Clear action" 0268 0269 view->canvasBase()->toolProxy()->deleteSelection(); 0270 } 0271 0272 void KisImageResizeToSelectionActionFactory::run(KisViewManager *view) 0273 { 0274 // XXX: "Add saving of XML data for Image Resize To Selection action" 0275 0276 KisSelectionSP selection = view->selection(); 0277 if (!selection) return; 0278 0279 view->image()->cropImage(selection->selectedExactRect()); 0280 } 0281 0282 void KisCutCopyActionFactory::run(bool willCut, bool makeSharpClip, KisViewManager *view) 0283 { 0284 KisImageSP image = view->image(); 0285 if (!image) return; 0286 0287 if (!view->blockUntilOperationsFinished(image)) return; 0288 0289 // Reference layers is a fake node, so it isn't added to the layer stack, this results in KisSelectedShapesProxy not 0290 // being aware of the active shapeManager and its selected shapes. 0291 const auto currentToolHasSelection = 0292 view->canvasBase()->toolProxy()->hasSelection(); 0293 0294 const bool haveShapesSelected = 0295 view->selectionManager()->haveShapesSelected(); 0296 0297 KisNodeSP node = view->activeNode(); 0298 KisSelectionSP selection = view->selection(); 0299 0300 if (!makeSharpClip && (haveShapesSelected || currentToolHasSelection)) { 0301 /** 0302 * Make sure that we use tryBarrierLock() here becasue it does **not** 0303 * cause requestStrokeEnd() to be called in the tools, hence does not 0304 * prevent disruptions in the text tool. 0305 */ 0306 KisImageBarrierLock lock(image, std::try_to_lock); 0307 if (!lock.owns_lock()) return; 0308 0309 // XXX: "Add saving of XML data for Cut/Copy of shapes" 0310 if (willCut) { 0311 view->canvasBase()->toolProxy()->cut(); 0312 } else { 0313 view->canvasBase()->toolProxy()->copy(); 0314 } 0315 } else if (selection) { 0316 KisNodeList selectedNodes = view->nodeManager()->selectedNodes(); 0317 0318 KisNodeList masks; 0319 Q_FOREACH (KisNodeSP node, selectedNodes) { 0320 if (node->inherits("KisMask")) { 0321 masks.append(node); 0322 } 0323 } 0324 0325 selectedNodes = KisLayerUtils::sortAndFilterMergeableInternalNodes(selectedNodes); 0326 0327 KisNodeList nodes; 0328 Q_FOREACH (KisNodeSP node, selectedNodes) { 0329 KisNodeSP dupNode; 0330 if (node->inherits("KisShapeLayer")) { 0331 KisPaintDeviceSP dev = new KisPaintDevice(*node->projection()); 0332 // might have to change node's name (vector to paint layer) 0333 dupNode = new KisPaintLayer(image, node->name(), node->opacity(), dev); 0334 } else { 0335 dupNode = node->clone(); 0336 } 0337 nodes.append(dupNode); 0338 } 0339 0340 Q_FOREACH (KisNodeSP node, nodes) { 0341 KisLayerUtils::recursiveApplyNodes(node, [image, view, makeSharpClip] (KisNodeSP node) { 0342 if (node && node->paintDevice()) { 0343 node->paintDevice()->burnKeyframe(); 0344 } 0345 0346 KisTimeSpan range; 0347 0348 KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Raster.id()); 0349 if (channel) { 0350 const int currentTime = image->animationInterface()->currentTime(); 0351 range = channel->affectedFrames(currentTime); 0352 } 0353 0354 if (node && node->paintDevice() && !node->inherits("KisMask")) { 0355 ActionHelper::trimDevice(view, node->paintDevice(), makeSharpClip, range); 0356 } 0357 }); 0358 } 0359 0360 KisImageSP tempImage = ActionHelper::makeImage(view, nodes); 0361 KisClipboard::instance()->setLayers(nodes, tempImage); 0362 0363 0364 KUndo2MagicString actionName = willCut ? 0365 kundo2_i18n("Cut") : 0366 kundo2_i18n("Copy"); 0367 KisProcessingApplicator *ap = beginAction(view, actionName); 0368 0369 if (willCut) { 0370 selectedNodes.append(masks); 0371 Q_FOREACH (KisNodeSP node, selectedNodes) { 0372 KisLayerUtils::recursiveApplyNodes(node, [selection, masks, ap] (KisNodeSP node){ 0373 0374 if (!node->hasEditablePaintDevice()) { 0375 return; 0376 } 0377 0378 // applied on masks if selected explicitly (when CTRL-X(cut) is used for deletion) 0379 if (node->inherits("KisMask") && !masks.contains(node)) { 0380 return; 0381 } 0382 0383 struct ClearSelection : public KisTransactionBasedCommand { 0384 ClearSelection(KisNodeSP node, KisSelectionSP sel) 0385 : m_node(node), m_sel(sel) {} 0386 KisNodeSP m_node; 0387 KisSelectionSP m_sel; 0388 0389 KUndo2Command* paint() override { 0390 KisSelectionSP cutSelection = m_sel; 0391 // Shrinking the cutting area was previously used 0392 // for getting seamless cut-paste. Now we use makeSharpClip 0393 // instead. 0394 // QRect originalRect = cutSelection->selectedExactRect(); 0395 // static const int preciseSelectionThreshold = 16; 0396 // 0397 // if (originalRect.width() > preciseSelectionThreshold || 0398 // originalRect.height() > preciseSelectionThreshold) { 0399 // cutSelection = new KisSelection(*m_sel); 0400 // delete cutSelection->flatten(); 0401 // 0402 // KisSelectionFilter* filter = new KisShrinkSelectionFilter(1, 1, false); 0403 // 0404 // QRect processingRect = filter->changeRect(originalRect); 0405 // filter->process(cutSelection->pixelSelection(), processingRect); 0406 // } 0407 0408 KisTransaction transaction(m_node->paintDevice()); 0409 m_node->paintDevice()->clearSelection(cutSelection); 0410 m_node->setDirty(cutSelection->selectedRect()); 0411 return transaction.endAndTake(); 0412 } 0413 }; 0414 0415 KUndo2Command *command = new ClearSelection(node, selection); 0416 ap->applyCommand(command, KisStrokeJobData::CONCURRENT, KisStrokeJobData::NORMAL); 0417 0418 }); 0419 } 0420 } 0421 0422 KisOperationConfiguration config(id()); 0423 config.setProperty("will-cut", willCut); 0424 endAction(ap, config.toXML()); 0425 } else if (!makeSharpClip) { 0426 if (willCut) { 0427 view->nodeManager()->cutLayersToClipboard(); 0428 } else { 0429 view->nodeManager()->copyLayersToClipboard(); 0430 } 0431 } 0432 } 0433 0434 void KisCopyMergedActionFactory::run(KisViewManager *view) 0435 { 0436 KisImageWSP image = view->image(); 0437 if (!image) return; 0438 if (!view->blockUntilOperationsFinished(image)) return; 0439 0440 image->barrierLock(); 0441 KisPaintDeviceSP dev = new KisPaintDevice(*image->root()->projection()); 0442 ActionHelper::trimDevice(view, dev); 0443 0444 KisNodeSP node = new KisPaintLayer(image, "Projection", OPACITY_OPAQUE_U8, dev); 0445 KisNodeList nodes{node}; 0446 0447 KisImageSP tempImage = ActionHelper::makeImage(view, nodes); 0448 KisClipboard::instance()->setLayers(nodes, tempImage); 0449 image->unlock(); 0450 0451 KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Copy Merged")); 0452 endAction(ap, KisOperationConfiguration(id()).toXML()); 0453 } 0454 0455 void KisInvertSelectionOperation::runFromXML(KisViewManager* view, const KisOperationConfiguration& config) 0456 { 0457 KisSelectionFilter* filter = new KisInvertSelectionFilter(); 0458 0459 runFilter(filter, view, config); 0460 } 0461 0462 void KisSelectionToVectorActionFactory::run(KisViewManager *view) 0463 { 0464 KisSelectionSP selection = view->selection(); 0465 0466 if (selection->hasShapeSelection()) { 0467 view->showFloatingMessage(i18nc("floating message", 0468 "Selection is already in a vector format "), 0469 QIcon(), 2000, KisFloatingMessage::Low); 0470 return; 0471 } 0472 0473 if (!selection->outlineCacheValid()) { 0474 view->image()->addSpontaneousJob(new KisUpdateOutlineJob(selection, false, Qt::transparent)); 0475 if (!view->blockUntilOperationsFinished(view->image())) { 0476 return; 0477 } 0478 } 0479 0480 QPainterPath selectionOutline = selection->outlineCache(); 0481 QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); 0482 0483 KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline)); 0484 shape->setShapeId(KoPathShapeId); 0485 0486 /** 0487 * Mark a shape that it belongs to a shape selection 0488 */ 0489 if(!shape->userData()) { 0490 shape->setUserData(new KisShapeSelectionMarker); 0491 } 0492 0493 KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection")); 0494 0495 ap->applyCommand(view->canvasBase()->shapeController()->addShape(shape, 0), 0496 KisStrokeJobData::SEQUENTIAL, 0497 KisStrokeJobData::EXCLUSIVE); 0498 0499 endAction(ap, KisOperationConfiguration(id()).toXML()); 0500 } 0501 0502 void KisSelectionToRasterActionFactory::run(KisViewManager *view) 0503 { 0504 KisSelectionSP selection = view->selection(); 0505 0506 if (!selection->hasShapeSelection()) { 0507 view->showFloatingMessage(i18nc("floating message", 0508 "Selection is already in a raster format "), 0509 QIcon(), 2000, KisFloatingMessage::Low); 0510 return; 0511 } 0512 0513 KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection")); 0514 0515 struct RasterizeSelection : public KisTransactionBasedCommand { 0516 RasterizeSelection(KisSelectionSP sel) 0517 : m_sel(sel) {} 0518 KisSelectionSP m_sel; 0519 0520 KUndo2Command* paint() override { 0521 // just create an empty transaction: it will rasterize the 0522 // selection and emit the necessary signals 0523 0524 KisTransaction transaction(m_sel->pixelSelection()); 0525 return transaction.endAndTake(); 0526 } 0527 }; 0528 0529 ap->applyCommand(new RasterizeSelection(selection), 0530 KisStrokeJobData::SEQUENTIAL, 0531 KisStrokeJobData::EXCLUSIVE); 0532 0533 endAction(ap, KisOperationConfiguration(id()).toXML()); 0534 } 0535 0536 void KisShapesToVectorSelectionActionFactory::run(KisViewManager* view) 0537 { 0538 const QList<KoShape*> originalShapes = view->canvasBase()->shapeManager()->selection()->selectedShapes(); 0539 0540 bool hasSelectionShapes = false; 0541 QList<KoShape*> clonedShapes; 0542 0543 Q_FOREACH (KoShape *shape, originalShapes) { 0544 if (dynamic_cast<KisShapeSelectionMarker*>(shape->userData())) { 0545 hasSelectionShapes = true; 0546 continue; 0547 } 0548 0549 clonedShapes << shape->cloneShapeAndBakeAbsoluteTransform(); 0550 } 0551 0552 if (clonedShapes.isEmpty()) { 0553 if (hasSelectionShapes) { 0554 view->showFloatingMessage(i18nc("floating message", 0555 "The shape already belongs to a selection"), 0556 QIcon(), 2000, KisFloatingMessage::Low); 0557 } 0558 return; 0559 } 0560 0561 KisSelectionToolHelper helper(view->canvasBase(), kundo2_i18n("Convert shapes to vector selection")); 0562 helper.addSelectionShapes(clonedShapes); 0563 } 0564 0565 void KisSelectionToShapeActionFactory::run(KisViewManager *view) 0566 { 0567 KisSelectionSP selection = view->selection(); 0568 if (!selection->outlineCacheValid()) { 0569 return; 0570 } 0571 0572 QPainterPath selectionOutline = selection->outlineCache(); 0573 QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); 0574 0575 KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline)); 0576 shape->setShapeId(KoPathShapeId); 0577 0578 KoColor fgColor = view->canvasBase()->resourceManager()->resource(KoCanvasResource::ForegroundColor).value<KoColor>(); 0579 KoShapeStrokeSP border(new KoShapeStroke(1.0, fgColor.toQColor())); 0580 shape->setStroke(border); 0581 0582 KUndo2Command *cmd = view->canvasBase()->shapeController()->addShapeDirect(shape, 0); 0583 KisProcessingApplicator::runSingleCommandStroke(view->image(), cmd); 0584 } 0585 0586 void KisStrokeSelectionActionFactory::run(KisViewManager *view, const StrokeSelectionOptions& params) 0587 { 0588 KisImageWSP image = view->image(); 0589 if (!image) { 0590 return; 0591 } 0592 0593 KisSelectionSP selection = view->selection(); 0594 if (!selection) { 0595 return; 0596 } 0597 0598 int size = params.lineSize; 0599 0600 KisPixelSelectionSP pixelSelection = selection->projection(); 0601 if (!pixelSelection->outlineCacheValid()) { 0602 pixelSelection->recalculateOutlineCache(); 0603 } 0604 0605 QPainterPath outline = pixelSelection->outlineCache(); 0606 QColor color = params.color.toQColor(); 0607 0608 KisNodeSP currentNode = view->canvasResourceProvider()->resourceManager()->resource(KoCanvasResource::CurrentKritaNode).value<KisNodeWSP>(); 0609 if (!currentNode->inherits("KisShapeLayer") && currentNode->paintDevice()) { 0610 KoCanvasResourceProvider * rManager = view->canvasResourceProvider()->resourceManager(); 0611 KisToolShapeUtils::StrokeStyle strokeStyle = KisToolShapeUtils::StrokeStyleForeground; 0612 KisToolShapeUtils::FillStyle fillStyle = params.fillStyle(); 0613 0614 KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), 0615 image, 0616 currentNode, 0617 rManager , 0618 strokeStyle, 0619 fillStyle); 0620 helper.setFGColorOverride(params.color); 0621 helper.setSelectionOverride(0); 0622 QPen pen(Qt::red, size); 0623 pen.setJoinStyle(Qt::RoundJoin); 0624 0625 if (fillStyle != KisToolShapeUtils::FillStyleNone) { 0626 helper.paintPainterPathQPenFill(outline, pen, params.fillColor); 0627 } 0628 else { 0629 helper.paintPainterPathQPen(outline, pen, params.fillColor); 0630 } 0631 } 0632 else if (currentNode->inherits("KisShapeLayer")) { 0633 0634 QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); 0635 0636 KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(outline)); 0637 shape->setShapeId(KoPathShapeId); 0638 0639 KoShapeStrokeSP border(new KoShapeStroke(size, color)); 0640 shape->setStroke(border); 0641 0642 KUndo2Command *cmd = view->canvasBase()->shapeController()->addShapeDirect(shape, 0); 0643 KisProcessingApplicator::runSingleCommandStroke(view->image(), cmd); 0644 } 0645 } 0646 0647 void KisStrokeBrushSelectionActionFactory::run(KisViewManager *view, const StrokeSelectionOptions& params) 0648 { 0649 KisImageWSP image = view->image(); 0650 if (!image) { 0651 return; 0652 } 0653 0654 KisSelectionSP selection = view->selection(); 0655 if (!selection) { 0656 return; 0657 } 0658 0659 KisPixelSelectionSP pixelSelection = selection->projection(); 0660 if (!pixelSelection->outlineCacheValid()) { 0661 pixelSelection->recalculateOutlineCache(); 0662 } 0663 0664 KisNodeSP currentNode = view->canvasResourceProvider()->resourceManager()->resource(KoCanvasResource::CurrentKritaNode).value<KisNodeWSP>(); 0665 if (!currentNode->inherits("KisShapeLayer") && currentNode->paintDevice()) 0666 { 0667 KoCanvasResourceProvider * rManager = view->canvasResourceProvider()->resourceManager(); 0668 QPainterPath outline = pixelSelection->outlineCache(); 0669 KisToolShapeUtils::StrokeStyle strokeStyle = KisToolShapeUtils::StrokeStyleForeground; 0670 KisToolShapeUtils::FillStyle fillStyle = KisToolShapeUtils::FillStyleNone; 0671 KoColor color = params.color; 0672 0673 KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), 0674 image, 0675 currentNode, 0676 rManager, 0677 strokeStyle, 0678 fillStyle); 0679 helper.setFGColorOverride(color); 0680 helper.setSelectionOverride(0); 0681 helper.paintPainterPath(outline); 0682 } 0683 }