1 /*
2  *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "kis_tool_select_path.h"
20 
21 #include <KoPathShape.h>
22 
23 #include "kis_cursor.h"
24 #include "kis_image.h"
25 #include "kis_painter.h"
26 #include "kis_selection_options.h"
27 #include "kis_canvas_resource_provider.h"
28 #include "kis_canvas2.h"
29 #include "kis_pixel_selection.h"
30 #include "kis_selection_tool_helper.h"
31 #include <KisView.h>
32 
33 
KisToolSelectPath(KoCanvasBase * canvas)34 KisToolSelectPath::KisToolSelectPath(KoCanvasBase * canvas)
35     : KisToolSelectBase<KisDelegatedSelectPathWrapper>(canvas,
36                                                        KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6),
37                                                        i18n("Select path"),
38                                                        new __KisToolSelectPathLocalTool(canvas, this))
39 {
40 }
41 
requestStrokeEnd()42 void KisToolSelectPath::requestStrokeEnd()
43 {
44     localTool()->endPathWithoutLastPoint();
45 }
46 
requestStrokeCancellation()47 void KisToolSelectPath::requestStrokeCancellation()
48 {
49     localTool()->cancelPath();
50 }
51 
52 // Install an event filter to catch right-click events.
53 // This code is duplicated in kis_tool_path.cc
eventFilter(QObject * obj,QEvent * event)54 bool KisToolSelectPath::eventFilter(QObject *obj, QEvent *event)
55 {
56     Q_UNUSED(obj);
57     if (event->type() == QEvent::MouseButtonPress ||
58             event->type() == QEvent::MouseButtonDblClick) {
59         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
60         if (mouseEvent->button() == Qt::RightButton && hasUserInteractionRunning()) {
61             localTool()->removeLastPoint();
62             return true;
63         }
64     } else if (event->type() == QEvent::TabletPress) {
65         QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
66         if (tabletEvent->button() == Qt::RightButton && hasUserInteractionRunning()) {
67             localTool()->removeLastPoint();
68             return true;
69         }
70     }
71     return false;
72 }
73 
createOptionWidgets()74 QList<QPointer<QWidget> > KisToolSelectPath::createOptionWidgets()
75 {
76     QList<QPointer<QWidget> > widgetsList =
77             DelegatedSelectPathTool::createOptionWidgets();
78     QList<QPointer<QWidget> > filteredWidgets;
79     Q_FOREACH (QWidget* widget, widgetsList) {
80         if (widget->objectName() != "Stroke widget") {
81             filteredWidgets.push_back(widget);
82         }
83     }
84     return filteredWidgets;
85 }
86 
beginPrimaryAction(KoPointerEvent * event)87 void KisDelegatedSelectPathWrapper::beginPrimaryAction(KoPointerEvent *event) {
88     DelegatedSelectPathTool::mousePressEvent(event);
89 }
90 
continuePrimaryAction(KoPointerEvent * event)91 void KisDelegatedSelectPathWrapper::continuePrimaryAction(KoPointerEvent *event){
92     DelegatedSelectPathTool::mouseMoveEvent(event);
93 }
94 
endPrimaryAction(KoPointerEvent * event)95 void KisDelegatedSelectPathWrapper::endPrimaryAction(KoPointerEvent *event) {
96     DelegatedSelectPathTool::mouseReleaseEvent(event);
97 }
98 
beginPrimaryDoubleClickAction(KoPointerEvent * event)99 void KisDelegatedSelectPathWrapper::beginPrimaryDoubleClickAction(KoPointerEvent *event)
100 {
101     DelegatedSelectPathTool::mouseDoubleClickEvent(event);
102 }
103 
mousePressEvent(KoPointerEvent * event)104 void KisDelegatedSelectPathWrapper::mousePressEvent(KoPointerEvent *event)
105 {
106     // this event will be forwarded using beginPrimaryAction
107     Q_UNUSED(event);
108 }
109 
mouseMoveEvent(KoPointerEvent * event)110 void KisDelegatedSelectPathWrapper::mouseMoveEvent(KoPointerEvent *event)
111 {
112     DelegatedSelectPathTool::mouseMoveEvent(event);
113 
114     // WARNING: the code is duplicated from KisToolPaint::requestUpdateOutline
115     KisCanvas2 * kiscanvas = dynamic_cast<KisCanvas2*>(canvas());
116     KisPaintingAssistantsDecorationSP decoration = kiscanvas->paintingAssistantsDecoration();
117     if (decoration && decoration->visible() && decoration->hasPaintableAssistants()) {
118         kiscanvas->updateCanvas();
119     }
120 }
121 
mouseReleaseEvent(KoPointerEvent * event)122 void KisDelegatedSelectPathWrapper::mouseReleaseEvent(KoPointerEvent *event)
123 {
124     // this event will be forwarded using continuePrimaryAction
125     Q_UNUSED(event);
126 }
127 
mouseDoubleClickEvent(KoPointerEvent * event)128 void KisDelegatedSelectPathWrapper::mouseDoubleClickEvent(KoPointerEvent *event)
129 {
130     // this event will be forwarded using endPrimaryAction
131     Q_UNUSED(event);
132 }
133 
hasUserInteractionRunning() const134 bool KisDelegatedSelectPathWrapper::hasUserInteractionRunning() const
135 {
136     return localTool()->pathStarted();
137 }
138 
139 
__KisToolSelectPathLocalTool(KoCanvasBase * canvas,KisToolSelectPath * parentTool)140 __KisToolSelectPathLocalTool::__KisToolSelectPathLocalTool(KoCanvasBase * canvas, KisToolSelectPath* parentTool)
141     : KoCreatePathTool(canvas), m_selectionTool(parentTool)
142 {
143     setEnableClosePathShortcut(false);
144 }
145 
paintPath(KoPathShape & pathShape,QPainter & painter,const KoViewConverter & converter)146 void __KisToolSelectPathLocalTool::paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter)
147 {
148     Q_UNUSED(converter);
149     KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
150     if (!kisCanvas)
151         return;
152 
153     QTransform matrix;
154     matrix.scale(kisCanvas->image()->xRes(), kisCanvas->image()->yRes());
155     matrix.translate(pathShape.position().x(), pathShape.position().y());
156     m_selectionTool->paintToolOutline(&painter, m_selectionTool->pixelToView(matrix.map(pathShape.outline())));
157 }
158 
addPathShape(KoPathShape * pathShape)159 void __KisToolSelectPathLocalTool::addPathShape(KoPathShape* pathShape)
160 {
161     pathShape->normalize();
162     pathShape->close();
163 
164     KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
165     if (!kisCanvas)
166         return;
167 
168     KisImageWSP image = kisCanvas->image();
169 
170     KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select by Bezier Curve"));
171 
172     const SelectionMode mode =
173         helper.tryOverrideSelectionMode(kisCanvas->viewManager()->selection(),
174                                         m_selectionTool->selectionMode(),
175                                         m_selectionTool->selectionAction());
176 
177     if (mode == PIXEL_SELECTION) {
178 
179         KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection());
180 
181         KisPainter painter(tmpSel);
182         painter.setPaintColor(KoColor(Qt::black, tmpSel->colorSpace()));
183         painter.setFillStyle(KisPainter::FillStyleForegroundColor);
184         painter.setAntiAliasPolygonFill(m_selectionTool->antiAliasSelection());
185         painter.setStrokeStyle(KisPainter::StrokeStyleNone);
186 
187         QTransform matrix;
188         matrix.scale(image->xRes(), image->yRes());
189         matrix.translate(pathShape->position().x(), pathShape->position().y());
190 
191         QPainterPath path = matrix.map(pathShape->outline());
192         painter.fillPainterPath(path);
193         tmpSel->setOutlineCache(path);
194 
195         helper.selectPixelSelection(tmpSel, m_selectionTool->selectionAction());
196 
197         delete pathShape;
198     } else {
199         helper.addSelectionShape(pathShape, m_selectionTool->selectionAction());
200     }
201 }
202 
resetCursorStyle()203 void KisToolSelectPath::resetCursorStyle()
204 {
205     if (selectionAction() == SELECTION_ADD) {
206         useCursor(KisCursor::load("tool_polygonal_selection_cursor_add.png", 6, 6));
207     } else if (selectionAction() == SELECTION_SUBTRACT) {
208         useCursor(KisCursor::load("tool_polygonal_selection_cursor_sub.png", 6, 6));
209     } else {
210         KisToolSelectBase<KisDelegatedSelectPathWrapper>::resetCursorStyle();
211     }
212 }
213 
214 
215