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

0001 /*
0002  * KDE. Krita Project.
0003  *
0004  * SPDX-FileCopyrightText: 2022 Deif Lou <ginoba@gmail.com>
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <kis_cursor.h>
0010 #include <KoPathShape.h>
0011 #include <KisViewManager.h>
0012 #include <canvas/kis_canvas2.h>
0013 #include <kis_canvas_resource_provider.h>
0014 #include <KoIcon.h>
0015 
0016 #include "KisPathEnclosingProducer.h"
0017 
0018 KisToolPathLocalTool::KisToolPathLocalTool(KoCanvasBase * canvas, KisPathEnclosingProducer* parentTool)
0019     : KoCreatePathTool(canvas)
0020     , m_parentTool(parentTool)
0021 {}
0022 
0023 void KisToolPathLocalTool::paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter)
0024 {
0025     Q_UNUSED(converter);
0026 
0027     QTransform matrix;
0028     matrix.scale(m_parentTool->image()->xRes(), m_parentTool->image()->yRes());
0029     matrix.translate(pathShape.position().x(), pathShape.position().y());
0030     m_parentTool->paintToolOutline(&painter, m_parentTool->pixelToView(matrix.map(pathShape.outline())));
0031 }
0032 
0033 void KisToolPathLocalTool::addPathShape(KoPathShape* pathShape)
0034 {
0035     m_parentTool->addPathShape(pathShape);
0036 }
0037 
0038 void KisToolPathLocalTool::beginShape()
0039 {
0040     m_parentTool->beginShape();
0041 }
0042 
0043 void KisToolPathLocalTool::endShape()
0044 {
0045     m_parentTool->endShape();
0046 }
0047 
0048 KisPathEnclosingProducer::KisPathEnclosingProducer(KoCanvasBase * canvas)
0049     : KisDynamicDelegateTool<DelegatedPathTool>(canvas,
0050                                                 KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6),
0051                                                 new KisToolPathLocalTool(canvas, this))
0052 {
0053     setObjectName("enclosing_tool_path");
0054     setSupportOutline(true);
0055     setOutlineEnabled(false);
0056 
0057     KisCanvas2 *kritaCanvas = dynamic_cast<KisCanvas2*>(canvas);
0058 
0059     connect(kritaCanvas->viewManager()->canvasResourceProvider(), SIGNAL(sigEffectiveCompositeOpChanged()), SLOT(resetCursorStyle()));
0060 }
0061 
0062 KisPathEnclosingProducer::~KisPathEnclosingProducer()
0063 {}
0064 
0065 void  KisPathEnclosingProducer::resetCursorStyle()
0066 {
0067     if (isEraser()) {
0068         useCursor(KisCursor::load("tool_polygonal_selection_enclose_eraser_cursor.png", 6, 6));
0069     } else {
0070         KisDynamicDelegateTool::resetCursorStyle();
0071     }
0072 
0073     overrideCursorIfNotEditable();
0074 }
0075 
0076 void KisPathEnclosingProducer::requestStrokeEnd()
0077 {
0078     KisDynamicDelegateTool::requestStrokeEnd();
0079     localTool()->endPathWithoutLastPoint();
0080 }
0081 
0082 void KisPathEnclosingProducer::requestStrokeCancellation()
0083 {
0084     KisDynamicDelegateTool::requestStrokeCancellation();
0085     localTool()->cancelPath();
0086 }
0087 
0088 KisPopupWidgetInterface* ::KisPathEnclosingProducer::popupWidget()
0089 {
0090     return m_hasUserInteractionRunning ? nullptr : KisDynamicDelegateTool::popupWidget();
0091 }
0092 
0093 void KisPathEnclosingProducer::mousePressEvent(KoPointerEvent *event)
0094 {
0095     Q_UNUSED(event)
0096 }
0097 
0098 // Install an event filter to catch right-click events.
0099 // The simplest way to accommodate the popup palette binding.
0100 // This code is duplicated in kis_tool_select_path.cc
0101 bool KisPathEnclosingProducer::eventFilter(QObject *obj, QEvent *event)
0102 {
0103     Q_UNUSED(obj);
0104     if (!m_hasUserInteractionRunning) {
0105         return false;
0106     }
0107     if (event->type() == QEvent::MouseButtonPress ||
0108             event->type() == QEvent::MouseButtonDblClick) {
0109         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
0110         if (mouseEvent->button() == Qt::RightButton) {
0111             localTool()->removeLastPoint();
0112             return true;
0113         }
0114     } else if (event->type() == QEvent::TabletPress) {
0115         QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
0116         if (tabletEvent->button() == Qt::RightButton) {
0117             localTool()->removeLastPoint();
0118             return true;
0119         }
0120     }
0121     return false;
0122 }
0123 
0124 void KisPathEnclosingProducer::beginAlternateAction(KoPointerEvent *event, AlternateAction action) {
0125     KisDynamicDelegateTool::beginAlternateAction(event, action);
0126     if (!nodeEditable()) return;
0127 
0128     if (nodePaintAbility() == KisDynamicDelegateTool::MYPAINTBRUSH_UNPAINTABLE) {
0129         KisCanvas2 * kiscanvas = static_cast<KisCanvas2*>(canvas());
0130         QString message = i18n("The MyPaint Brush Engine is not available for this colorspace");
0131         kiscanvas->viewManager()->showFloatingMessage(message, koIcon("object-locked"));
0132         event->ignore();
0133         return;
0134     }
0135 }
0136 
0137 void KisPathEnclosingProducer::beginPrimaryAction(KoPointerEvent* event)
0138 {
0139     if (!nodeEditable()) return;
0140     KisDynamicDelegateTool::mousePressEvent(event);
0141 }
0142 
0143 void KisPathEnclosingProducer::continuePrimaryAction(KoPointerEvent *event)
0144 {
0145     mouseMoveEvent(event);
0146 }
0147 
0148 void KisPathEnclosingProducer::endPrimaryAction(KoPointerEvent *event)
0149 {
0150     mouseReleaseEvent(event);
0151 }
0152 
0153 void KisPathEnclosingProducer::beginPrimaryDoubleClickAction(KoPointerEvent *event)
0154 {
0155     KisDynamicDelegateTool::mouseDoubleClickEvent(event);
0156 }
0157 
0158 void KisPathEnclosingProducer::addPathShape(KoPathShape* pathShape)
0159 {
0160     KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
0161     if (!kisCanvas) {
0162         return;
0163     }
0164 
0165     KisImageWSP image = kisCanvas->image();
0166     KisPixelSelectionSP enclosingMask = new KisPixelSelection();
0167 
0168     pathShape->normalize();
0169     pathShape->close();
0170 
0171     KisPainter painter(enclosingMask);
0172     painter.setPaintColor(KoColor(Qt::white, enclosingMask->colorSpace()));
0173     painter.setAntiAliasPolygonFill(false);
0174     painter.setFillStyle(KisPainter::FillStyleForegroundColor);
0175     painter.setStrokeStyle(KisPainter::StrokeStyleNone);
0176 
0177     QTransform matrix;
0178     matrix.scale(image->xRes(), image->yRes());
0179     matrix.translate(pathShape->position().x(), pathShape->position().y());
0180 
0181     QPainterPath path = matrix.map(pathShape->outline());
0182     painter.fillPainterPath(path);
0183     enclosingMask->setOutlineCache(path);
0184 
0185     delete pathShape;
0186 
0187     emit enclosingMaskProduced(enclosingMask);
0188 }
0189 
0190 bool KisPathEnclosingProducer::hasUserInteractionRunning() const
0191 {
0192     return m_hasUserInteractionRunning;
0193 }
0194 
0195 void KisPathEnclosingProducer::beginShape()
0196 {
0197     m_hasUserInteractionRunning = true;
0198 }
0199 
0200 void KisPathEnclosingProducer::endShape()
0201 {
0202     m_hasUserInteractionRunning = false;
0203 }