File indexing completed on 2024-12-22 04:16:38

0001 /*
0002  *  kis_tool_select_polygonal.h - part of Krayon^WKrita
0003  *
0004  *  SPDX-FileCopyrightText: 2000 John Califf <jcaliff@compuzone.net>
0005  *  SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0006  *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
0007  *  SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com>
0008  *  SPDX-FileCopyrightText: 2015 Michael Abrahams <miabraha@gmail.com>
0009  *
0010  *  SPDX-License-Identifier: GPL-2.0-or-later
0011  */
0012 
0013 #include "kis_tool_select_polygonal.h"
0014 
0015 #include <KoPathShape.h>
0016 
0017 #include "kis_algebra_2d.h"
0018 #include "kis_painter.h"
0019 #include <brushengine/kis_paintop_registry.h>
0020 #include "kis_selection_options.h"
0021 #include "kis_canvas2.h"
0022 #include "kis_pixel_selection.h"
0023 #include "kis_selection_tool_helper.h"
0024 #include "kis_shape_tool_helper.h"
0025 #include <kis_default_bounds.h>
0026 
0027 #include "KisViewManager.h"
0028 #include "kis_selection_manager.h"
0029 #include <kis_command_utils.h>
0030 #include <kis_selection_filters.h>
0031 
0032 __KisToolSelectPolygonalLocal::__KisToolSelectPolygonalLocal(KoCanvasBase *canvas)
0033     : KisToolPolylineBase(canvas, KisToolPolylineBase::SELECT,
0034                           KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6))
0035 {
0036     setObjectName("tool_select_polygonal");
0037 }
0038 
0039 
0040 KisToolSelectPolygonal::KisToolSelectPolygonal(KoCanvasBase *canvas):
0041     KisToolSelectBase<__KisToolSelectPolygonalLocal>(canvas, i18n("Polygonal Selection"))
0042 {
0043 }
0044 
0045 void KisToolSelectPolygonal::finishPolyline(const QVector<QPointF> &points)
0046 {
0047     KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
0048     Q_ASSERT(kisCanvas);
0049     if (!kisCanvas)
0050         return;
0051 
0052     const QRectF boundingViewRect = pixelToView(KisAlgebra2D::accumulateBounds(points));
0053 
0054     KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select Polygon"));
0055 
0056     if (helper.tryDeselectCurrentSelection(pixelToView(boundingViewRect), selectionAction())) {
0057         return;
0058     }
0059 
0060     const SelectionMode mode =
0061         helper.tryOverrideSelectionMode(kisCanvas->viewManager()->selection(),
0062                                         selectionMode(),
0063                                         selectionAction());
0064 
0065     if (mode == PIXEL_SELECTION) {
0066         KisProcessingApplicator applicator(currentImage(),
0067                                            currentNode(),
0068                                            KisProcessingApplicator::NONE,
0069                                            KisImageSignalVector(),
0070                                            kundo2_i18n("Select Polygon"));
0071 
0072         KisPixelSelectionSP tmpSel =
0073             new KisPixelSelection(new KisDefaultBounds(currentImage()));
0074 
0075         const bool antiAlias = antiAliasSelection();
0076         const int grow = growSelection();
0077         const int feather = featherSelection();
0078 
0079         QPainterPath path;
0080         path.addPolygon(points);
0081         path.closeSubpath();
0082 
0083         KUndo2Command *cmd = new KisCommandUtils::LambdaCommand(
0084             [tmpSel, antiAlias, grow, feather, path]() mutable
0085             -> KUndo2Command * {
0086                 KisPainter painter(tmpSel);
0087                 painter.setPaintColor(KoColor(Qt::black, tmpSel->colorSpace()));
0088                 // Since the feathering already smooths the selection, the
0089                 // antiAlias is not applied if we must feather
0090                 painter.setAntiAliasPolygonFill(antiAlias && feather == 0);
0091                 painter.setFillStyle(KisPainter::FillStyleForegroundColor);
0092                 painter.setStrokeStyle(KisPainter::StrokeStyleNone);
0093 
0094                 painter.paintPainterPath(path);
0095 
0096                 if (grow > 0) {
0097                     KisGrowSelectionFilter biggy(grow, grow);
0098                     biggy.process(tmpSel,
0099                                   tmpSel->selectedRect().adjusted(-grow,
0100                                                                   -grow,
0101                                                                   grow,
0102                                                                   grow));
0103                 } else if (grow < 0) {
0104                     KisShrinkSelectionFilter tiny(-grow, -grow, false);
0105                     tiny.process(tmpSel, tmpSel->selectedRect());
0106                 }
0107                 if (feather > 0) {
0108                     KisFeatherSelectionFilter feathery(feather);
0109                     feathery.process(tmpSel,
0110                                      tmpSel->selectedRect().adjusted(-feather,
0111                                                                      -feather,
0112                                                                      feather,
0113                                                                      feather));
0114                 }
0115 
0116                 if (grow == 0 && feather == 0) {
0117                     tmpSel->setOutlineCache(path);
0118                 } else {
0119                     tmpSel->invalidateOutlineCache();
0120                 }
0121 
0122                 return 0;
0123             });
0124 
0125         applicator.applyCommand(cmd, KisStrokeJobData::SEQUENTIAL);
0126         helper.selectPixelSelection(applicator, tmpSel, selectionAction());
0127         applicator.end();
0128 
0129     } else {
0130         KoPathShape* path = new KoPathShape();
0131         path->setShapeId(KoPathShapeId);
0132 
0133         QTransform resolutionMatrix;
0134         resolutionMatrix.scale(1 / currentImage()->xRes(), 1 / currentImage()->yRes());
0135         path->moveTo(resolutionMatrix.map(points[0]));
0136         for (int i = 1; i < points.count(); i++)
0137             path->lineTo(resolutionMatrix.map(points[i]));
0138         path->close();
0139         path->normalize();
0140 
0141         helper.addSelectionShape(path, selectionAction());
0142     }
0143 }
0144 
0145 void KisToolSelectPolygonal::beginShape()
0146 {
0147     beginSelectInteraction();
0148 }
0149 
0150 void KisToolSelectPolygonal::endShape()
0151 {
0152     endSelectInteraction();
0153 }
0154 
0155 void KisToolSelectPolygonal::resetCursorStyle()
0156 {
0157     if (selectionAction() == SELECTION_ADD) {
0158         useCursor(KisCursor::load("tool_polygonal_selection_cursor_add.png", 6, 6));
0159     } else if (selectionAction() == SELECTION_SUBTRACT) {
0160         useCursor(KisCursor::load("tool_polygonal_selection_cursor_sub.png", 6, 6));
0161     } else if (selectionAction() == SELECTION_INTERSECT) {
0162         useCursor(KisCursor::load("tool_polygonal_selection_cursor_inter.png", 6, 6));
0163     } else if (selectionAction() == SELECTION_SYMMETRICDIFFERENCE) {
0164         useCursor(KisCursor::load("tool_polygonal_selection_cursor_symdiff.png", 6, 6));
0165     } else {
0166         KisToolSelectBase<__KisToolSelectPolygonalLocal>::resetCursorStyle();
0167     }
0168 }
0169