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
40
42 : parent(p)
43{
44 scrollTimer.setInterval(100);
45}
46
47void KoToolProxyPrivate::timeout() // Auto scroll the canvas
48{
49 Q_ASSERT(controller);
50
51 const QPoint originalWidgetPoint = parent->documentToWidget(widgetScrollPointDoc).toPoint();
52
53 QRectF mouseArea(widgetScrollPointDoc, QSizeF(10, 10));
54 mouseArea.setTopLeft(mouseArea.center());
55
56 const QPointF oldPreferredCenter = controller->preferredCenter();
57
58 controller->ensureVisibleDoc(mouseArea, true);
59
60 const QPointF newPreferredCenter = controller->preferredCenter();
61
62 // if scrolling has happened, then just return!
63 if (oldPreferredCenter == newPreferredCenter) {
64 return;
65 }
66
67 widgetScrollPointDoc = parent->widgetToDocument(originalWidgetPoint);
68
69 QMouseEvent event(QEvent::MouseMove, originalWidgetPoint, Qt::LeftButton, Qt::LeftButton, QFlags<Qt::KeyboardModifier>());
72}
73
75{
76 if (controller == 0) return;
77 if (!activeTool) return;
78 if (!activeTool->wantsAutoScroll()) return;
79 if (!event.isAccepted()) return;
80 if (!isToolPressed) return;
81 if (event.buttons() != Qt::LeftButton) return;
82
83
84 widgetScrollPointDoc = event.point;
85
86 if (! scrollTimer.isActive())
87 scrollTimer.start();
88}
89
91{
92 if (hasSelection == newSelection)
93 return;
94 hasSelection = newSelection;
96}
97
99{
100 if (!activeTool)
101 return false;
102
103 KoShapeManager * shapeManager = activeTool->canvas()->shapeManager();
104 KoShapeLayer * activeLayer = shapeManager->selection()->activeLayer();
105 if (activeLayer && !activeLayer->isShapeEditable())
106 return false;
107 return true;
108}
109
110KoToolProxy::KoToolProxy(KoCanvasBase *canvas, QObject *parent)
111 : QObject(parent),
112 d(new KoToolProxyPrivate(this))
113{
114 KoToolManager::instance()->priv()->registerToolProxy(this, canvas);
115
116 connect(&d->scrollTimer, SIGNAL(timeout()), this, SLOT(timeout()));
117}
118
120{
121 delete d;
122}
123
124void KoToolProxy::paint(QPainter &painter, const KoViewConverter &converter)
125{
126 if (d->activeTool) d->activeTool->paint(painter, converter);
127}
128
133
135{
136 return d->controller->canvas();
137}
138
140{
141 QPointF globalPoint = ev->globalPos();
142
143 if (d->multiClickSource != eventType) {
144 d->multiClickCount = 0;
145 }
146
147 if (d->multiClickGlobalPoint != globalPoint) {
148 if (qAbs(globalPoint.x() - d->multiClickGlobalPoint.x()) > 5||
149 qAbs(globalPoint.y() - d->multiClickGlobalPoint.y()) > 5) {
150 d->multiClickCount = 0;
151 }
152 d->multiClickGlobalPoint = globalPoint;
153 }
154
155 if (d->multiClickCount && d->multiClickTimeStamp.elapsed() < QApplication::doubleClickInterval()) {
156 // One more multiclick;
158 } else {
159 d->multiClickTimeStamp.start();
160 d->multiClickCount = 1;
161 d->multiClickSource = QEvent::Type(eventType);
162 }
163
164 if (d->activeTool) {
165 switch (d->multiClickCount) {
166 case 0:
167 case 1:
169 break;
170 case 2:
172 break;
173 case 3:
174 default:
176 break;
177 }
178 } else {
179 d->multiClickCount = 0;
180 ev->ignore();
181 }
182
183}
184
185void KoToolProxy::tabletEvent(QTabletEvent *event, const QPointF &point)
186{
187 // We get these events exclusively from KisToolProxy - accept them
188 event->accept();
189
191 KoInputDevice::convertPointerType(event), event->uniqueId());
192 KoToolManager::instance()->priv()->switchInputDevice(id);
193
194 KoPointerEvent ev(event, point);
195
196 switch (event->type()) {
197 case QEvent::TabletPress:
198 countMultiClick(&ev, event->type());
199 break;
200 case QEvent::TabletRelease:
201 d->scrollTimer.stop();
202 if (d->activeTool)
204 break;
205 case QEvent::TabletMove:
206 if (d->activeTool)
208 d->checkAutoScroll(ev);
209 default:
210 ; // ignore the rest.
211 }
212
213 d->mouseLeaveWorkaround = true;
215}
216
218{
219 d->mouseLeaveWorkaround = false;
220 KoInputDevice id;
221 KoToolManager::instance()->priv()->switchInputDevice(id);
222 d->mouseDownPoint = ev->pos();
223
224
225 // this tries to make sure another mouse press event doesn't happen
226 // before a release event happens
227 if (d->isToolPressed) {
229 d->scrollTimer.stop();
230
231 if (d->activeTool) {
233 }
234
235 d->isToolPressed = false;
236
237 return;
238 }
239
240 countMultiClick(ev, QEvent::MouseButtonPress);
241
242 d->isToolPressed = true;
243}
244
245void KoToolProxy::mousePressEvent(QMouseEvent *event, const QPointF &point)
246{
247 KoPointerEvent ev(event, point);
248 mousePressEvent(&ev);
250}
251
252void KoToolProxy::mouseDoubleClickEvent(QMouseEvent *event, const QPointF &point)
253{
254 KoPointerEvent ev(event, point);
257}
258
260{
261 // let us handle it as any other mousepress (where we then detect multi clicks
262 mousePressEvent(event);
263}
264
265void KoToolProxy::mouseMoveEvent(QMouseEvent *event, const QPointF &point)
266{
267 KoPointerEvent ev(event, point);
268 mouseMoveEvent(&ev);
270}
271
273{
274 if (d->mouseLeaveWorkaround) {
275 d->mouseLeaveWorkaround = false;
276 return;
277 }
278 KoInputDevice id;
279 KoToolManager::instance()->priv()->switchInputDevice(id);
280 if (d->activeTool == 0) {
281 event->ignore();
282 return;
283 }
284
285 d->activeTool->mouseMoveEvent(event);
286
287 d->checkAutoScroll(*event);
288}
289
290void KoToolProxy::mouseReleaseEvent(QMouseEvent *event, const QPointF &point)
291{
292 KoPointerEvent ev(event, point);
295}
296
298{
299 d->mouseLeaveWorkaround = false;
300 KoInputDevice id;
301 KoToolManager::instance()->priv()->switchInputDevice(id);
302 d->scrollTimer.stop();
303
304 if (d->activeTool) {
306 } else {
307 event->ignore();
308 }
309
310 d->isToolPressed = false;
311}
312
313void KoToolProxy::keyPressEvent(QKeyEvent *event)
314{
315 if (d->activeTool)
316 d->activeTool->keyPressEvent(event);
317 else
318 event->ignore();
319}
320
321void KoToolProxy::keyReleaseEvent(QKeyEvent *event)
322{
323 if (d->activeTool)
325 else
326 event->ignore();
327
328 d->isToolPressed = false;
329}
330
337
338QVariant KoToolProxy::inputMethodQuery(Qt::InputMethodQuery query) const
339{
340 if (d->activeTool)
341 return d->activeTool->inputMethodQuery(query);
342 return QVariant();
343}
344
345void KoToolProxy::inputMethodEvent(QInputMethodEvent *event)
346{
348}
349
350void KoToolProxy::focusInEvent(QFocusEvent *event)
351{
352 if (d->activeTool) d->activeTool->focusInEvent(event);
353}
354
355void KoToolProxy::focusOutEvent(QFocusEvent *event)
356{
357 if (d->activeTool) d->activeTool->focusOutEvent(event);
358}
359
361{
362 return d->activeTool ? d->activeTool->popupActionsMenu() : 0;
363}
364
369
371{
372 if (d->activeTool) {
373 disconnect(d->activeTool, SIGNAL(selectionChanged(bool)), this, SLOT(selectionChanged(bool)));
374 d->toolPriorityShortcuts.clear();
375 }
376
377 d->activeTool = tool;
378
379 if (tool) {
382 if (collection) {
383 Q_FOREACH(QAction *action, collection->actions()) {
384
385 const QVariant prop = action->property("tool_action");
386
387 if (prop.isValid()) {
388 const QStringList tools = prop.toStringList();
389
390 if (tools.contains(d->activeTool->toolId())) {
391 const QList<QKeySequence> shortcuts = action->shortcuts();
392 std::copy(shortcuts.begin(), shortcuts.end(),
393 std::back_inserter(d->toolPriorityShortcuts));
394 }
395 }
396 }
397 }
398
399 connect(d->activeTool, SIGNAL(selectionChanged(bool)), this, SLOT(selectionChanged(bool)));
401 Q_EMIT toolChanged(tool->toolId());
402 }
403}
404
405void KoToolProxy::touchEvent(QTouchEvent* event, const QPointF& point)
406{
407 // only one "touchpoint" events should be here
408 KoPointerEvent ev(event, point);
409
410 if (!d->activeTool) return;
411
412 switch (event->touchPointStates())
413 {
414 case Qt::TouchPointPressed:
415 countMultiClick(&ev, QEvent::TouchBegin);
416 break;
417 case Qt::TouchPointMoved:
419 break;
420 case Qt::TouchPointReleased:
422 break;
423 default: // don't care
424 ;
425 }
426
428}
429
434
439
444
446{
447 return d->activeTool ? d->activeTool->hasSelection() : false;
448}
449
451{
453 d->activeTool->cut();
454}
455
457{
458 if (d->activeTool)
459 d->activeTool->copy();
460}
461
463{
464 bool success = false;
465
466 if (d->activeTool && d->isActiveLayerEditable()) {
467 success = d->activeTool->paste();
468 }
469
470 return success;
471}
472
474{
475 bool success = false;
476
477 if (d->activeTool && d->isActiveLayerEditable()) {
478 success = d->activeTool->selectAll();
479 }
480
481 return success;
482}
483
485{
486 if (d->activeTool)
488}
489
490void KoToolProxy::dragMoveEvent(QDragMoveEvent *event, const QPointF &point)
491{
492 if (d->activeTool)
493 d->activeTool->dragMoveEvent(event, point);
494}
495
496void KoToolProxy::dragLeaveEvent(QDragLeaveEvent *event)
497{
498 if (d->activeTool)
499 d->activeTool->dragLeaveEvent(event);
500}
501
502void KoToolProxy::dropEvent(QDropEvent *event, const QPointF &point)
503{
504 if (d->activeTool)
505 d->activeTool->dropEvent(event, point);
506}
507
513
514void KoToolProxy::processEvent(QEvent *e) const
515{
516 if(e->type()==QEvent::ShortcutOverride
517 && d->activeTool
519 && (static_cast<QKeyEvent*>(e)->modifiers()==Qt::NoModifier ||
520 static_cast<QKeyEvent*>(e)->modifiers()==Qt::ShiftModifier
521#ifdef Q_OS_WIN
522 // we should disallow AltGr shortcuts if a text box is in focus
523 || (static_cast<QKeyEvent*>(e)->modifiers()==(Qt::AltModifier | Qt::ControlModifier) &&
524 static_cast<QKeyEvent*>(e)->key() < Qt::Key_Escape)
525#endif
526 )) {
527 e->accept();
528 }
529}
530
537
544
551
553{
554 if (d->activeTool) {
556 }
557}
558
560{
561 return d;
562}
563
564//have to include this because of Q_PRIVATE_SLOT
565#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:970
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.
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