Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_polyline_base.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7
8#include <QAction>
9
10#include <KoPointerEvent.h>
11#include <KoCanvasBase.h>
12#include <KoCanvasController.h>
13#include <KoViewConverter.h>
15
17#include "kis_canvas2.h"
19#include <KisViewManager.h>
20#include <kis_action.h>
21#include <kactioncollection.h>
22#include <kis_icon.h>
23
24#include "kis_action_registry.h"
25
26#define SNAPPING_THRESHOLD 10
27#define SNAPPING_HANDLE_RADIUS 8
28#define PREVIEW_LINE_WIDTH 1
29
31 : KisToolShape(canvas, cursor),
32 m_dragging(false),
33 m_type(type),
34 m_closeSnappingActivated(false)
35{
36 KisCanvas2 *kritaCanvas = dynamic_cast<KisCanvas2*>(canvas);
37
38 connect(kritaCanvas->viewManager()->canvasResourceProvider(), SIGNAL(sigEffectiveCompositeOpChanged()), SLOT(resetCursorStyle()));
39}
40
41
42void KisToolPolylineBase::activate(const QSet<KoShape *> &shapes)
43{
45 connect(action("undo_polygon_selection"), SIGNAL(triggered()), SLOT(undoSelectionOrCancel()), Qt::UniqueConnection);
46
47 KisInputManager *inputManager = (static_cast<KisCanvas2*>(canvas()))->globalInputManager();
48 if (inputManager) {
49 inputManager->attachPriorityEventFilter(this);
50 }
51}
52
54{
55 disconnect(action("undo_polygon_selection"), 0, this, 0);
57
58 KisInputManager *inputManager = (static_cast<KisCanvas2*>(canvas()))->globalInputManager();
59 if (inputManager) {
60 inputManager->detachPriorityEventFilter(this);
61 }
62
64}
65
70
75
80
81// Install an event filter to catch right-click events.
82// The simplest way to accommodate the popup palette binding.
83bool KisToolPolylineBase::eventFilter(QObject *obj, QEvent *event)
84{
85 Q_UNUSED(obj);
86
87 if (!m_dragging) {
88 return false;
89 }
90 if (event->type() == QEvent::MouseButtonPress ||
91 event->type() == QEvent::MouseButtonDblClick) {
92 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
93 if (mouseEvent->button() == Qt::RightButton) {
95 return true;
96 }
97 } else if (event->type() == QEvent::TabletPress) {
98 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
99 if (tabletEvent->button() == Qt::RightButton) {
101 return true;
102 }
103 }
104 return false;
105}
106
108{
109 Q_UNUSED(event);
110 NodePaintAbility paintability = nodePaintAbility();
111 if ((m_type == PAINT && (!nodeEditable() || paintability == UNPAINTABLE || paintability == KisToolPaint::CLONE || paintability == KisToolPaint::MYPAINTBRUSH_UNPAINTABLE)) ||
112 (m_type == SELECT && !selectionEditable())) {
113
114 if (paintability == KisToolPaint::CLONE){
115 KisCanvas2 * kiscanvas = static_cast<KisCanvas2*>(canvas());
116 QString message = i18n("This tool cannot paint on clone layers. Please select a paint or vector layer or mask.");
117 kiscanvas->viewManager()->showFloatingMessage(message, koIcon("object-locked"));
118 }
119
120 if (paintability == KisToolPaint::MYPAINTBRUSH_UNPAINTABLE) {
121 KisCanvas2 * kiscanvas = static_cast<KisCanvas2*>(canvas());
122 QString message = i18n("The MyPaint Brush Engine is not available for this colorspace");
123 kiscanvas->viewManager()->showFloatingMessage(message, koIcon("object-locked"));
124 }
125
126 event->ignore();
127 return;
128 }
129
131
133 m_points.append(m_points.first());
134 endStroke();
135 } else {
136 beginShape();
137 m_dragging = true;
138 }
139}
140
152
154{
155 endStroke();
156
157 // this action will have no continuation
158 event->ignore();
159}
160
172
174{
175 if (m_dragging && !m_points.empty()) {
176 // erase old lines on canvas
177 QRectF updateRect = dragBoundingRect();
178 // get current mouse position
180 // draw new lines on canvas
181 updateRect |= dragBoundingRect();
182 updateCanvasViewRect(updateRect);
183
184
185 QPointF basePoint = pixelToView(m_points.first());
187 m_points.size() > 1 &&
188 (basePoint - pixelToView(m_dragEnd)).manhattanLength() < SNAPPING_THRESHOLD;
189
192 } else {
194 }
195}
196
198{
199 if (m_dragging) {
200 // Initialize with the dragging segment's rect
201 QRectF updateRect = dragBoundingRect();
202
203 if (m_points.size() > 1) {
204 // Add the rect for the last segment
205 const QRectF lastSegmentRect =
206 pixelToView(QRectF(m_points.last(), m_points.at(m_points.size() - 2)).normalized())
208 updateRect = updateRect.united(lastSegmentRect);
209
210 m_points.pop_back();
211 }
212 m_dragStart = m_points.last();
213
214 // Add the new dragging segment's rect
215 updateRect = updateRect.united(dragBoundingRect());
216 updateCanvasViewRect(updateRect);
217 }
218}
219
221{
222 if (m_points.size() > 1) {
224 } else {
225 cancelStroke();
226 }
227}
228
229void KisToolPolylineBase::paint(QPainter& gc, const KoViewConverter &converter)
230{
231 Q_UNUSED(converter);
232
233 if (!canvas() || !currentImage())
234 return;
235
236 QPointF start, end;
237 QPointF startPos;
238 QPointF endPos;
239
240 QPainterPath path;
241 if (m_dragging && !m_points.empty()) {
242 startPos = pixelToView(m_dragStart);
243 endPos = pixelToView(m_dragEnd);
244 path.moveTo(startPos);
245 path.lineTo(endPos);
246 }
247
248 for (vQPointF::iterator it = m_points.begin(); it != m_points.end(); ++it) {
249
250 if (it == m_points.begin()) {
251 start = (*it);
252 } else {
253 end = (*it);
254
255 startPos = pixelToView(start);
256 endPos = pixelToView(end);
257 path.moveTo(startPos);
258 path.lineTo(endPos);
259 start = end;
260 }
261 }
262
264 QPointF basePoint = pixelToView(m_points.first());
265 path.addEllipse(basePoint, SNAPPING_HANDLE_RADIUS, SNAPPING_HANDLE_RADIUS);
266 }
267
268 paintToolOutline(&gc, path);
269 KisToolPaint::paint(gc,converter);
270}
271
276
278{
279 if (!m_dragging) return;
280
281 m_dragging = false;
282 if(m_points.count() > 1) {
284 }
285 m_points.clear();
287 updateArea();
288 endShape();
289}
290
292{
293 if (!m_dragging) return;
294
295 m_dragging = false;
296 m_points.clear();
298 updateArea();
299 endShape();
300}
301
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisViewManager * viewManager() const
Central object to manage canvas input.
void detachPriorityEventFilter(QObject *filter)
detachPriorityEventFilter
void attachPriorityEventFilter(QObject *filter, int priority=0)
attachPriorityEventFilter
The PopupWidgetInterface abstract class defines the basic interface that will be used by all popup wi...
virtual void requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event)
void paint(QPainter &gc, const KoViewConverter &converter) override
void setMode(ToolMode mode) override
void mouseMoveEvent(KoPointerEvent *event) override
void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override
void activate(const QSet< KoShape * > &shapes) override
KisToolPolylineBase(KoCanvasBase *canvas, KisToolPolylineBase::ToolType type, const QCursor &cursor=KisCursor::load("tool_polygon_cursor.png", 6, 6))
void endPrimaryAction(KoPointerEvent *event) override
KisPopupWidgetInterface * popupWidget() override
void beginPrimaryAction(KoPointerEvent *event) override
void requestStrokeCancellation() override
void beginPrimaryDoubleClickAction(KoPointerEvent *event) override
void paint(QPainter &gc, const KoViewConverter &converter) override
void mouseMoveEvent(KoPointerEvent *event) override
bool eventFilter(QObject *obj, QEvent *event) override
virtual void finishPolyline(const QVector< QPointF > &points)=0
void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override
virtual void beginShape()
virtual void endShape()
void activate(const QSet< KoShape * > &shapes) override
KisCanvasResourceProvider * canvasResourceProvider()
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
QPointF point
The point in document coordinates.
virtual KisPopupWidgetInterface * popupWidget()
Definition KoToolBase.h:340
virtual void deactivate()
QAction * action(const QString &name) const
#define bounds(x, a, b)
#define koIcon(name)
Use these macros for icons without any issues.
Definition kis_icon.h:25
#define CHECK_MODE_SANITY_OR_RETURN(_mode)
Definition kis_tool.h:27
#define SNAPPING_HANDLE_RADIUS
#define PREVIEW_LINE_WIDTH
#define SNAPPING_THRESHOLD
void updateCanvasPixelRect(const QRectF &pixelRect)
Update the canvas for the given rectangle in image pixel coordinates.
Definition kis_tool.cc:322
KisImageWSP currentImage()
Definition kis_tool.cc:393
KisTool::NodePaintAbility nodePaintAbility()
Definition kis_tool.cc:539
virtual void resetCursorStyle()
Definition kis_tool.cc:613
bool nodeEditable()
Checks checks if the current node is editable.
Definition kis_tool.cc:651
QPointF pixelToView(const QPoint &pixelCoord) const
Definition kis_tool.cc:269
void paintToolOutline(QPainter *painter, const KisOptimizedBrushOutline &path)
Definition kis_tool.cc:589
KisImageWSP image() const
Definition kis_tool.cc:332
@ PAINT_MODE
Definition kis_tool.h:300
@ HOVER_MODE
Definition kis_tool.h:299
QPointF convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset=QPointF(), bool useModifiers=true)
Definition kis_tool.cc:214
bool selectionEditable()
Checks checks if the selection is editable, only applies to local selection as global selection is al...
Definition kis_tool.cc:696
void updateCanvasViewRect(const QRectF &viewRect)
Update the canvas for the given rectangle in view coordinates.
Definition kis_tool.cc:327
AlternateAction
Definition kis_tool.h:134
@ ChangeSizeSnap
Definition kis_tool.h:136
@ ChangeSize
Definition kis_tool.h:135
NodePaintAbility
Definition kis_tool.h:148
@ MYPAINTBRUSH_UNPAINTABLE
Definition kis_tool.h:153
@ UNPAINTABLE
Definition kis_tool.h:152
KisCanvas2 * canvas