Krita Source Code Documentation
Loading...
Searching...
No Matches
KoToolProxy.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2006-2007 Thomas Zander <zander@kde.org>
3 * SPDX-FileCopyrightText: 2006-2011 Boudewijn Rempt <boud@valdyas.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7#include "KoToolProxy.h"
8#include "KoToolProxy_p.h"
9
10#include <QMimeData>
11#include <QUrl>
12#include <QApplication>
13#include <QTouchEvent>
14#include <QClipboard>
15#include <QEvent>
16
17#include <kundo2command.h>
18#include <KoProperties.h>
19
20#include <FlakeDebug.h>
21#include <klocalizedstring.h>
22
23#include "KoToolBase.h"
24#include "KoPointerEvent.h"
25#include "KoInputDevice.h"
26#include "KoToolManager_p.h"
27#include "KoToolSelection.h"
28#include "KoCanvasBase.h"
29#include "KoCanvasController.h"
30#include "KoShapeManager.h"
31#include "KoSelection.h"
32#include "KoShapeLayer.h"
33#include "KoShapeRegistry.h"
34#include "KoShapeController.h"
35#include "KoViewConverter.h"
36#include "KoShapeFactoryBase.h"
37#include "kis_assert.h"
38#include "kactioncollection.h"
39#include "kis_global.h"
40#include "kis_algebra_2d.h"
41
42
44 : parent(p)
45{
46 scrollTimer.setInterval(100);
47}
48
49void KoToolProxyPrivate::timeout() // Auto scroll the canvas
50{
51 Q_ASSERT(controller);
52
53 const QPoint originalWidgetPoint = parent->documentToWidget(widgetScrollPointDoc).toPoint();
54
55 const QPointF margin(10.0, 10.0);
56
57 const QPointF mouseAreaTopLeftWidget = parent->documentToWidget(widgetScrollPointDoc) - margin;
58 const QPointF mouseAreaBottomRightWidget = mouseAreaTopLeftWidget + 2 * margin;
59
60 const QPointF mouseAreaTopLeftDoc = parent->widgetToDocument(mouseAreaTopLeftWidget);
61 const QPointF mouseAreaBottomRightDoc = parent->widgetToDocument(mouseAreaBottomRightWidget);
62 QRectF mouseAreaDoc(mouseAreaTopLeftDoc, mouseAreaBottomRightDoc);
63
64
65 const QPointF oldPreferredCenter = controller->preferredCenter();
66
67 controller->ensureVisibleDoc(mouseAreaDoc, true);
68
69 const QPointF newPreferredCenter = controller->preferredCenter();
70
71 // if scrolling has happened, then just return!
72 if (oldPreferredCenter == newPreferredCenter) {
73 return;
74 }
75
76 widgetScrollPointDoc = parent->widgetToDocument(originalWidgetPoint);
77
78 QMouseEvent event(QEvent::MouseMove, originalWidgetPoint, Qt::LeftButton, Qt::LeftButton, QFlags<Qt::KeyboardModifier>());
81}
82
84{
85 if (controller == 0) return;
86 if (!activeTool) return;
87 if (!activeTool->wantsAutoScroll()) return;
88 if (!event.isAccepted()) return;
89 if (!isToolPressed) return;
90 if (event.buttons() != Qt::LeftButton) return;
91
92
93 widgetScrollPointDoc = event.point;
94
95 if (! scrollTimer.isActive())
96 scrollTimer.start();
97}
98
100{
101 if (hasSelection == newSelection)
102 return;
103 hasSelection = newSelection;
105}
106
108{
109 if (!activeTool)
110 return false;
111
112 KoShapeManager * shapeManager = activeTool->canvas()->shapeManager();
113 KoShapeLayer * activeLayer = shapeManager->selection()->activeLayer();
114 if (activeLayer && !activeLayer->isShapeEditable())
115 return false;
116 return true;
117}
118
119KoToolProxy::KoToolProxy(KoCanvasBase *canvas, QObject *parent)
120 : QObject(parent),
121 d(new KoToolProxyPrivate(this))
122{
123 KoToolManager::instance()->priv()->registerToolProxy(this, canvas);
124
125 connect(&d->scrollTimer, SIGNAL(timeout()), this, SLOT(timeout()));
126}
127
129{
130 delete d;
131}
132
133void KoToolProxy::paint(QPainter &painter, const KoViewConverter &converter)
134{
135 if (d->activeTool) d->activeTool->paint(painter, converter);
136}
137
142
144{
145 return d->controller->canvas();
146}
147
149{
150 return d->multiClickCount;
151}
152
154{
155 QPointF globalPoint = ev->globalPos();
156
157 if (d->multiClickSource != eventType) {
158 d->multiClickCount = 0;
159 }
160
161 if (d->multiClickGlobalPoint != globalPoint) {
162 if (qAbs(globalPoint.x() - d->multiClickGlobalPoint.x()) > 5||
163 qAbs(globalPoint.y() - d->multiClickGlobalPoint.y()) > 5) {
164 d->multiClickCount = 0;
165 }
166 d->multiClickGlobalPoint = globalPoint;
167 }
168
169 if (d->multiClickCount && d->multiClickTimeStamp.elapsed() < QApplication::doubleClickInterval()) {
170 // One more multiclick;
172 } else {
173 d->multiClickTimeStamp.start();
174 d->multiClickCount = 1;
175 d->multiClickSource = QEvent::Type(eventType);
176 }
177
178 if (d->activeTool) {
179 switch (d->multiClickCount) {
180 case 0:
181 case 1:
183 break;
184 case 2:
186 break;
187 case 3:
188 default:
190 break;
191 }
192 } else {
193 d->multiClickCount = 0;
194 ev->ignore();
195 }
196
197}
198
199void KoToolProxy::tabletEvent(QTabletEvent *event, const QPointF &point)
200{
201 // We get these events exclusively from KisToolProxy - accept them
202 event->accept();
203
205 KoInputDevice::convertPointerType(event), event->uniqueId());
206 KoToolManager::instance()->priv()->switchInputDevice(id);
207
208 KoPointerEvent ev(event, point);
209
210 switch (event->type()) {
211 case QEvent::TabletPress:
212 countMultiClick(&ev, event->type());
213 break;
214 case QEvent::TabletRelease:
215 d->scrollTimer.stop();
216 if (d->activeTool)
218 break;
219 case QEvent::TabletMove:
220 if (d->activeTool)
222 d->checkAutoScroll(ev);
223 default:
224 ; // ignore the rest.
225 }
226
227 d->mouseLeaveWorkaround = true;
229}
230
232{
233 d->mouseLeaveWorkaround = false;
234 KoInputDevice id;
235 KoToolManager::instance()->priv()->switchInputDevice(id);
236 d->mouseDownPoint = ev->pos();
237
238
239 // this tries to make sure another mouse press event doesn't happen
240 // before a release event happens
241 if (d->isToolPressed) {
243 d->scrollTimer.stop();
244
245 if (d->activeTool) {
247 }
248
249 d->isToolPressed = false;
250
251 return;
252 }
253
254 countMultiClick(ev, QEvent::MouseButtonPress);
255
256 d->isToolPressed = true;
257}
258
259void KoToolProxy::mousePressEvent(QMouseEvent *event, const QPointF &point)
260{
261 KoPointerEvent ev(event, point);
262 mousePressEvent(&ev);
264}
265
266void KoToolProxy::mouseDoubleClickEvent(QMouseEvent *event, const QPointF &point)
267{
268 KoPointerEvent ev(event, point);
271}
272
274{
275 // let us handle it as any other mousepress (where we then detect multi clicks
276 mousePressEvent(event);
277}
278
279void KoToolProxy::mouseMoveEvent(QMouseEvent *event, const QPointF &point)
280{
281 KoPointerEvent ev(event, point);
282 mouseMoveEvent(&ev);
284}
285
287{
288 if (d->mouseLeaveWorkaround) {
289 d->mouseLeaveWorkaround = false;
290 return;
291 }
292 KoInputDevice id;
293 KoToolManager::instance()->priv()->switchInputDevice(id);
294 if (d->activeTool == 0) {
295 event->ignore();
296 return;
297 }
298
299 d->activeTool->mouseMoveEvent(event);
300
301 d->checkAutoScroll(*event);
302}
303
304void KoToolProxy::mouseReleaseEvent(QMouseEvent *event, const QPointF &point)
305{
306 KoPointerEvent ev(event, point);
309}
310
312{
313 d->mouseLeaveWorkaround = false;
314 KoInputDevice id;
315 KoToolManager::instance()->priv()->switchInputDevice(id);
316 d->scrollTimer.stop();
317
318 if (d->activeTool) {
320 } else {
321 event->ignore();
322 }
323
324 d->isToolPressed = false;
325}
326
327void KoToolProxy::keyPressEvent(QKeyEvent *event)
328{
329 if (d->activeTool)
330 d->activeTool->keyPressEvent(event);
331 else
332 event->ignore();
333}
334
335void KoToolProxy::keyReleaseEvent(QKeyEvent *event)
336{
337 if (d->activeTool)
339 else
340 event->ignore();
341
342 d->isToolPressed = false;
343}
344
351
352QVariant KoToolProxy::inputMethodQuery(Qt::InputMethodQuery query) const
353{
354 if (d->activeTool)
355 return d->activeTool->inputMethodQuery(query);
356 return QVariant();
357}
358
359void KoToolProxy::inputMethodEvent(QInputMethodEvent *event)
360{
362}
363
364void KoToolProxy::focusInEvent(QFocusEvent *event)
365{
366 if (d->activeTool) d->activeTool->focusInEvent(event);
367}
368
369void KoToolProxy::focusOutEvent(QFocusEvent *event)
370{
371 if (d->activeTool) d->activeTool->focusOutEvent(event);
372}
373
375{
376 return d->activeTool ? d->activeTool->popupActionsMenu() : 0;
377}
378
383
385{
386 if (d->activeTool) {
387 disconnect(d->activeTool, SIGNAL(selectionChanged(bool)), this, SLOT(selectionChanged(bool)));
388 d->toolPriorityShortcuts.clear();
389 }
390
391 d->activeTool = tool;
392
393 if (tool) {
396 if (collection) {
397 Q_FOREACH(QAction *action, collection->actions()) {
398
399 const QVariant prop = action->property("tool_action");
400
401 if (prop.isValid()) {
402 const QStringList tools = prop.toStringList();
403
404 if (tools.contains(d->activeTool->toolId())) {
405 const QList<QKeySequence> shortcuts = action->shortcuts();
406 std::copy(shortcuts.begin(), shortcuts.end(),
407 std::back_inserter(d->toolPriorityShortcuts));
408 }
409 }
410 }
411 }
412
413 connect(d->activeTool, SIGNAL(selectionChanged(bool)), this, SLOT(selectionChanged(bool)));
415 Q_EMIT toolChanged(tool->toolId());
416 }
417}
418
419void KoToolProxy::touchEvent(QTouchEvent* event, const QPointF& point)
420{
421 // only one "touchpoint" events should be here
422 KoPointerEvent ev(event, point);
423
424 if (!d->activeTool) return;
425
426 switch (event->touchPointStates())
427 {
428 case Qt::TouchPointPressed:
429 countMultiClick(&ev, QEvent::TouchBegin);
430 break;
431 case Qt::TouchPointMoved:
433 break;
434 case Qt::TouchPointReleased:
436 break;
437 default: // don't care
438 ;
439 }
440
442}
443
448
453
458
460{
461 return d->activeTool ? d->activeTool->hasSelection() : false;
462}
463
465{
467 d->activeTool->cut();
468}
469
471{
472 if (d->activeTool)
473 d->activeTool->copy();
474}
475
477{
478 bool success = false;
479
480 if (d->activeTool && d->isActiveLayerEditable()) {
481 success = d->activeTool->paste();
482 }
483
484 return success;
485}
486
488{
489 bool success = false;
490
491 if (d->activeTool && d->isActiveLayerEditable()) {
492 success = d->activeTool->selectAll();
493 }
494
495 return success;
496}
497
499{
500 if (d->activeTool)
502}
503
504void KoToolProxy::dragMoveEvent(QDragMoveEvent *event, const QPointF &point)
505{
506 if (d->activeTool)
507 d->activeTool->dragMoveEvent(event, point);
508}
509
510void KoToolProxy::dragLeaveEvent(QDragLeaveEvent *event)
511{
512 if (d->activeTool)
513 d->activeTool->dragLeaveEvent(event);
514}
515
516void KoToolProxy::dropEvent(QDropEvent *event, const QPointF &point)
517{
518 if (d->activeTool)
519 d->activeTool->dropEvent(event, point);
520}
521
527
528void KoToolProxy::processEvent(QEvent *e) const
529{
530 if(e->type()==QEvent::ShortcutOverride
531 && d->activeTool
533 && (static_cast<QKeyEvent*>(e)->modifiers()==Qt::NoModifier ||
534 static_cast<QKeyEvent*>(e)->modifiers()==Qt::ShiftModifier
535#ifdef Q_OS_WIN
536 // we should disallow AltGr shortcuts if a text box is in focus
537 || (static_cast<QKeyEvent*>(e)->modifiers()==(Qt::AltModifier | Qt::ControlModifier) &&
538 static_cast<QKeyEvent*>(e)->key() < Qt::Key_Escape)
539#endif
540 )) {
541 e->accept();
542 }
543}
544
551
558
565
567{
568 if (d->activeTool) {
570 }
571}
572
574{
575 return d;
576}
577
578//have to include this because of Q_PRIVATE_SLOT
579#include "moc_KoToolProxy.cpp"
const Params2D p
A container for a set of QAction objects.
QList< QAction * > actions() const
The PopupWidgetInterface abstract class defines the basic interface that will be used by all popup wi...
virtual KoShapeManager * shapeManager() const =0
virtual QPointF preferredCenter() const =0
Returns the currently set preferred center point in view coordinates (pixels)
virtual void ensureVisibleDoc(const QRectF &docRect, bool smooth)=0
Scrolls the content of the canvas so that the given rect is visible.
KisKActionCollection * actionCollection
virtual KoCanvasBase * canvas() const
static InputDevice convertDeviceType(QTabletEvent *event)
static Pointer convertPointerType(QTabletEvent *event)
QPoint globalPos() const
Return the position screen coordinates.
Qt::MouseButtons buttons() const
return buttons pressed (see QMouseEvent::buttons());
bool isAccepted() const
return if the event has been accepted.
KoPointerEventWrapper deepCopyEvent() const
QPoint pos() const
return the position in widget coordinates
KoShapeLayer * activeLayer() const
KoSelection * selection
virtual bool isShapeEditable(bool recursive=true) const
checks recursively if the shape or one of its parents is not visible or locked
Definition KoShape.cpp:965
virtual void requestRedoDuringStroke()
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
virtual void deleteSelection()
virtual void requestUndoDuringStroke()
virtual void requestStrokeCancellation()
virtual KisPopupWidgetInterface * popupWidget()
Definition KoToolBase.h:340
virtual void mouseTripleClickEvent(KoPointerEvent *event)
Q_INVOKABLE QString toolId() const
virtual void keyReleaseEvent(QKeyEvent *event)
virtual void focusInEvent(QFocusEvent *event)
virtual void dropEvent(QDropEvent *event, const QPointF &point)
virtual void copy() const
virtual bool paste()
virtual void focusOutEvent(QFocusEvent *event)
virtual void mousePressEvent(KoPointerEvent *event)=0
virtual void deselect()
deselect the tool should clear the selection if it has one.
virtual void repaintDecorations()
virtual void mouseMoveEvent(KoPointerEvent *event)=0
virtual bool hasSelection()
virtual void mouseReleaseEvent(KoPointerEvent *event)=0
virtual void keyPressEvent(QKeyEvent *event)
bool isInTextMode() const
virtual bool selectAll()
selectAll select all data the tool can select.
virtual QMenu * popupActionsMenu()
Definition KoToolBase.h:334
virtual void cut()
virtual void mouseDoubleClickEvent(KoPointerEvent *event)
virtual void requestStrokeEnd()
virtual void inputMethodEvent(QInputMethodEvent *event)
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const
virtual void paint(QPainter &painter, const KoViewConverter &converter)=0
virtual bool wantsAutoScroll() const
virtual void dragMoveEvent(QDragMoveEvent *event, const QPointF &point)
virtual void explicitUserStrokeEndRequest()
explicitUserStrokeEndRequest is called by the input manager when the user presses Enter key or any eq...
virtual void dragLeaveEvent(QDragLeaveEvent *event)
KoToolManager::Private * priv()
static KoToolManager * instance()
Return the toolmanager singleton.
void selectionChanged(bool newSelection)
KoToolBase * activeTool
void setCanvasController(KoCanvasController *controller)
the toolManager tells us which KoCanvasController this toolProxy is working for.
QEvent::Type multiClickSource
QElapsedTimer multiClickTimeStamp
void checkAutoScroll(const KoPointerEvent &event)
boost::optional< KoPointerEventWrapper > lastPointerEvent
KoCanvasController * controller
KoToolProxyPrivate(KoToolProxy *p)
QPointF widgetScrollPointDoc
QPointF multiClickGlobalPoint
KoToolProxy * parent
QVector< QKeySequence > toolPriorityShortcuts
void mouseMoveEvent(QMouseEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
KisPopupWidgetInterface * popupWidget()
Forwarded to the current KoToolBase.
void mousePressEvent(QMouseEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
void copy() const
Forwarded to the current KoToolBase.
void deselect()
Forwarded to the current KoToolBase.
void cut()
Forwarded to the current KoToolBase.
bool hasSelection() const
returns true if the current tool holds a selection
void dragLeaveEvent(QDragLeaveEvent *event)
Forwarded to the current KoToolBase.
KoToolProxyPrivate *const d
void requestUndoDuringStroke()
Forwarded to the current KoToolBase.
KoPointerEvent * lastDeliveredPointerEvent() const
void processEvent(QEvent *) const
virtual QPointF widgetToDocument(const QPointF &widgetPoint) const =0
void requestRedoDuringStroke()
Forwarded to the current KoToolBase.
KoCanvasBase * canvas() const
void paint(QPainter &painter, const KoViewConverter &converter)
Forwarded to the current KoToolBase.
void explicitUserStrokeEndRequest()
Forwarded to the current KoToolBase.
void tabletEvent(QTabletEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
virtual QPointF documentToWidget(const QPointF &documentPoint) const =0
QMenu * popupActionsMenu()
Forwarded to the current KoToolBase.
void touchEvent(QTouchEvent *event, const QPointF &point)
void countMultiClick(KoPointerEvent *ev, int eventType)
void focusInEvent(QFocusEvent *event)
Forwarded to the current KoToolBase.
void deleteSelection()
Forwarded to the current KoToolBase.
bool paste()
Forwarded to the current KoToolBase.
int multiClickCount() const
bool selectAll()
Forwarded to the current KoToolBase.
void mouseDoubleClickEvent(QMouseEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
void focusOutEvent(QFocusEvent *event)
Forwarded to the current KoToolBase.
KoToolProxy(KoCanvasBase *canvas, QObject *parent=0)
QVector< QKeySequence > toolPriorityShortcuts() const
KoToolProxyPrivate * priv()
void keyReleaseEvent(QKeyEvent *event)
Forwarded to the current KoToolBase.
void toolChanged(const QString &toolId)
void requestStrokeEnd()
Forwarded to the current KoToolBase.
void requestStrokeCancellation()
Forwarded to the current KoToolBase.
void inputMethodEvent(QInputMethodEvent *event)
Forwarded to the current KoToolBase.
virtual void setActiveTool(KoToolBase *tool)
Set the new active tool.
QVariant inputMethodQuery(Qt::InputMethodQuery query) const
Forwarded to the current KoToolBase.
~KoToolProxy() override
void keyPressEvent(QKeyEvent *event)
Forwarded to the current KoToolBase.
void dropEvent(QDropEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
void dragMoveEvent(QDragMoveEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
void mouseReleaseEvent(QMouseEvent *event, const QPointF &point)
Forwarded to the current KoToolBase.
void repaintDecorations()
Forwarded to the current KoToolBase.
void selectionChanged(bool hasSelection)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130