File indexing completed on 2024-12-22 04:16:38
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_tool_select_path.h" 0008 0009 #include <KoPathShape.h> 0010 0011 #include "kis_canvas2.h" 0012 #include "kis_canvas_resource_provider.h" 0013 #include "kis_cursor.h" 0014 #include "kis_image.h" 0015 #include "kis_painter.h" 0016 #include "kis_pixel_selection.h" 0017 #include "kis_selection_options.h" 0018 #include "kis_selection_tool_helper.h" 0019 #include <KisView.h> 0020 #include <kis_command_utils.h> 0021 #include <kis_selection_filters.h> 0022 #include <KisOptimizedBrushOutline.h> 0023 #include <kis_default_bounds.h> 0024 0025 KisToolSelectPath::KisToolSelectPath(KoCanvasBase * canvas) 0026 : KisToolSelectBase<KisDelegatedSelectPathWrapper>(canvas, 0027 KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6), 0028 i18n("Select path"), 0029 new __KisToolSelectPathLocalTool(canvas, this)) 0030 {} 0031 0032 void KisToolSelectPath::requestStrokeEnd() 0033 { 0034 localTool()->endPathWithoutLastPoint(); 0035 } 0036 0037 void KisToolSelectPath::requestStrokeCancellation() 0038 { 0039 localTool()->cancelPath(); 0040 } 0041 0042 // Install an event filter to catch right-click events. 0043 // This code is duplicated in kis_tool_path.cc 0044 bool KisToolSelectPath::eventFilter(QObject *obj, QEvent *event) 0045 { 0046 Q_UNUSED(obj); 0047 if (!localTool()->pathStarted()) { 0048 return false; 0049 } 0050 if (event->type() == QEvent::MouseButtonPress || 0051 event->type() == QEvent::MouseButtonDblClick) { 0052 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); 0053 if (mouseEvent->button() == Qt::RightButton && isSelecting()) { 0054 localTool()->removeLastPoint(); 0055 return true; 0056 } 0057 } else if (event->type() == QEvent::TabletPress) { 0058 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event); 0059 if (tabletEvent->button() == Qt::RightButton && isSelecting()) { 0060 localTool()->removeLastPoint(); 0061 return true; 0062 } 0063 } 0064 return false; 0065 } 0066 0067 QList<QPointer<QWidget> > KisToolSelectPath::createOptionWidgets() 0068 { 0069 QList<QPointer<QWidget> > widgetsList = 0070 DelegatedSelectPathTool::createOptionWidgets(); 0071 QList<QPointer<QWidget> > filteredWidgets; 0072 Q_FOREACH (QWidget* widget, widgetsList) { 0073 if (widget->objectName() != "Stroke widget") { 0074 filteredWidgets.push_back(widget); 0075 } 0076 } 0077 return filteredWidgets; 0078 } 0079 0080 void KisDelegatedSelectPathWrapper::beginPrimaryAction(KoPointerEvent *event) { 0081 DelegatedSelectPathTool::mousePressEvent(event); 0082 } 0083 0084 void KisDelegatedSelectPathWrapper::continuePrimaryAction(KoPointerEvent *event){ 0085 DelegatedSelectPathTool::mouseMoveEvent(event); 0086 } 0087 0088 void KisDelegatedSelectPathWrapper::endPrimaryAction(KoPointerEvent *event) { 0089 DelegatedSelectPathTool::mouseReleaseEvent(event); 0090 } 0091 0092 void KisDelegatedSelectPathWrapper::beginPrimaryDoubleClickAction(KoPointerEvent *event) 0093 { 0094 DelegatedSelectPathTool::mouseDoubleClickEvent(event); 0095 } 0096 0097 void KisDelegatedSelectPathWrapper::mousePressEvent(KoPointerEvent *event) 0098 { 0099 // this event will be forwarded using beginPrimaryAction 0100 Q_UNUSED(event); 0101 } 0102 0103 void KisDelegatedSelectPathWrapper::mouseMoveEvent(KoPointerEvent *event) 0104 { 0105 DelegatedSelectPathTool::mouseMoveEvent(event); 0106 0107 // WARNING: the code is duplicated from KisToolPaint::requestUpdateOutline 0108 KisCanvas2 *kiscanvas = qobject_cast<KisCanvas2*>(canvas()); 0109 KisPaintingAssistantsDecorationSP decoration = kiscanvas->paintingAssistantsDecoration(); 0110 if (decoration && decoration->visible() && decoration->hasPaintableAssistants()) { 0111 kiscanvas->updateCanvasDecorations(); 0112 } 0113 } 0114 0115 void KisDelegatedSelectPathWrapper::mouseReleaseEvent(KoPointerEvent *event) 0116 { 0117 // this event will be forwarded using continuePrimaryAction 0118 Q_UNUSED(event); 0119 } 0120 0121 void KisDelegatedSelectPathWrapper::mouseDoubleClickEvent(KoPointerEvent *event) 0122 { 0123 // this event will be forwarded using endPrimaryAction 0124 Q_UNUSED(event); 0125 } 0126 0127 __KisToolSelectPathLocalTool::__KisToolSelectPathLocalTool(KoCanvasBase * canvas, KisToolSelectPath* parentTool) 0128 : KoCreatePathTool(canvas), m_selectionTool(parentTool) 0129 { 0130 setEnableClosePathShortcut(false); 0131 } 0132 0133 void __KisToolSelectPathLocalTool::paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter) 0134 { 0135 Q_UNUSED(converter); 0136 KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas()); 0137 if (!kisCanvas) 0138 return; 0139 0140 QTransform matrix; 0141 matrix.scale(kisCanvas->image()->xRes(), kisCanvas->image()->yRes()); 0142 matrix.translate(pathShape.position().x(), pathShape.position().y()); 0143 m_selectionTool->paintToolOutline(&painter, m_selectionTool->pixelToView(matrix.map(pathShape.outline()))); 0144 } 0145 0146 void __KisToolSelectPathLocalTool::addPathShape(KoPathShape* pathShape) 0147 { 0148 pathShape->normalize(); 0149 pathShape->close(); 0150 0151 KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas()); 0152 if (!kisCanvas) 0153 return; 0154 0155 KisImageWSP image = kisCanvas->image(); 0156 0157 KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select by Bezier Curve")); 0158 0159 const SelectionMode mode = 0160 helper.tryOverrideSelectionMode(kisCanvas->viewManager()->selection(), 0161 m_selectionTool->selectionMode(), 0162 m_selectionTool->selectionAction()); 0163 0164 if (mode == PIXEL_SELECTION) { 0165 KisProcessingApplicator applicator( 0166 m_selectionTool->currentImage(), 0167 m_selectionTool->currentNode(), 0168 KisProcessingApplicator::NONE, 0169 KisImageSignalVector(), 0170 kundo2_i18n("Select by Bezier Curve")); 0171 0172 KisPixelSelectionSP tmpSel = new KisPixelSelection( 0173 new KisDefaultBounds(m_selectionTool->currentImage())); 0174 0175 const bool antiAlias = m_selectionTool->antiAliasSelection(); 0176 const int grow = m_selectionTool->growSelection(); 0177 const int feather = m_selectionTool->featherSelection(); 0178 0179 QTransform matrix; 0180 matrix.scale(image->xRes(), image->yRes()); 0181 matrix.translate(pathShape->position().x(), pathShape->position().y()); 0182 0183 QPainterPath path = matrix.map(pathShape->outline()); 0184 0185 KUndo2Command *cmd = new KisCommandUtils::LambdaCommand( 0186 [tmpSel, antiAlias, grow, feather, path]() mutable 0187 -> KUndo2Command * { 0188 KisPainter painter(tmpSel); 0189 painter.setPaintColor(KoColor(Qt::black, tmpSel->colorSpace())); 0190 // Since the feathering already smooths the selection, the 0191 // antiAlias is not applied if we must feather 0192 painter.setAntiAliasPolygonFill(antiAlias && feather == 0); 0193 painter.setFillStyle(KisPainter::FillStyleForegroundColor); 0194 painter.setStrokeStyle(KisPainter::StrokeStyleNone); 0195 0196 painter.fillPainterPath(path); 0197 0198 if (grow > 0) { 0199 KisGrowSelectionFilter biggy(grow, grow); 0200 biggy.process(tmpSel, 0201 tmpSel->selectedRect().adjusted(-grow, 0202 -grow, 0203 grow, 0204 grow)); 0205 } else if (grow < 0) { 0206 KisShrinkSelectionFilter tiny(-grow, -grow, false); 0207 tiny.process(tmpSel, tmpSel->selectedRect()); 0208 } 0209 if (feather > 0) { 0210 KisFeatherSelectionFilter feathery(feather); 0211 feathery.process(tmpSel, 0212 tmpSel->selectedRect().adjusted(-feather, 0213 -feather, 0214 feather, 0215 feather)); 0216 } 0217 0218 if (grow == 0 && feather == 0) { 0219 tmpSel->setOutlineCache(path); 0220 } else { 0221 tmpSel->invalidateOutlineCache(); 0222 } 0223 0224 return 0; 0225 }); 0226 0227 applicator.applyCommand(cmd, KisStrokeJobData::SEQUENTIAL); 0228 helper.selectPixelSelection(applicator, 0229 tmpSel, 0230 m_selectionTool->selectionAction()); 0231 applicator.end(); 0232 0233 delete pathShape; 0234 0235 } else { 0236 helper.addSelectionShape(pathShape, m_selectionTool->selectionAction()); 0237 } 0238 } 0239 0240 void __KisToolSelectPathLocalTool::beginShape() 0241 { 0242 KisToolSelectPath* selectPathTool = dynamic_cast<KisToolSelectPath*>(m_selectionTool); 0243 KIS_ASSERT(selectPathTool); 0244 selectPathTool->beginSelectInteraction(); 0245 } 0246 0247 void __KisToolSelectPathLocalTool::endShape() 0248 { 0249 KisToolSelectPath* selectPathTool = dynamic_cast<KisToolSelectPath*>(m_selectionTool); 0250 KIS_ASSERT(selectPathTool); 0251 selectPathTool->endSelectInteraction(); 0252 } 0253 0254 void KisToolSelectPath::resetCursorStyle() 0255 { 0256 if (selectionAction() == SELECTION_ADD) { 0257 useCursor(KisCursor::load("tool_polygonal_selection_cursor_add.png", 6, 6)); 0258 } else if (selectionAction() == SELECTION_SUBTRACT) { 0259 useCursor(KisCursor::load("tool_polygonal_selection_cursor_sub.png", 6, 6)); 0260 } else if (selectionAction() == SELECTION_INTERSECT) { 0261 useCursor(KisCursor::load("tool_polygonal_selection_cursor_inter.png", 6, 6)); 0262 } else if (selectionAction() == SELECTION_SYMMETRICDIFFERENCE) { 0263 useCursor(KisCursor::load("tool_polygonal_selection_cursor_symdiff.png", 6, 6)); 0264 } else { 0265 KisToolSelectBase<KisDelegatedSelectPathWrapper>::resetCursorStyle(); 0266 } 0267 } 0268 0269