Krita Source Code Documentation
Loading...
Searching...
No Matches
KoPointerEvent.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2
3 SPDX-FileCopyrightText: 2006 Thorsten Zachmann <zachmann@kde.org>
4 SPDX-FileCopyrightText: 2006 C. Boemann Rasmussen <cbo@boemann.dk>
5 SPDX-FileCopyrightText: 2006-2007 Thomas Zander <zander@kde.org>
6 SPDX-FileCopyrightText: 2021 Dmitry Kazakov <dimula73@gmail.com>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "KoPointerEvent.h"
12#include <QTabletEvent>
13#include <QMouseEvent>
14#include <QWheelEvent>
15#include <cmath>
16#include <boost/variant2/variant.hpp>
17
18#include <ksharedconfig.h>
19#include <kconfiggroup.h>
20#include <kis_config_notifier.h>
21#include <kis_assert.h>
22
24{
25private:
26 Q_OBJECT
27public:
29 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()),
30 this, SLOT(slotSettingsChanged()));
32 }
33
34 bool useTouchPressure = true;
35
36private Q_SLOTS:
38
39 KConfigGroup group = KSharedConfig::openConfig()->group("");
40 useTouchPressure = group.readEntry("useTouchPressureSensitivity", true);
41 }
42};
43
45
46#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
47namespace detail {
48
49// Qt's events do not have copy-ctors yet, so we should emulate them
50// See https://bugreports.qt.io/browse/QTBUG-72488
51
52template <class Event> void copyEventHack(const Event *src, QScopedPointer<QEvent> &dst);
53
54template<> void copyEventHack(const QMouseEvent *src, QScopedPointer<QEvent> &dst) {
55 QMouseEvent *tmp = new QMouseEvent(src->type(),
56 src->localPos(), src->windowPos(), src->screenPos(),
57 src->button(), src->buttons(), src->modifiers(),
58 src->source());
59 tmp->setTimestamp(src->timestamp());
60 dst.reset(tmp);
61}
62
63template<> void copyEventHack(const QTabletEvent *src, QScopedPointer<QEvent> &dst) {
64 QTabletEvent *tmp = new QTabletEvent(src->type(),
65 src->posF(), src->globalPosF(),
66 src->deviceType(), src->pointerType(),
67 src->pressure(),
68 src->xTilt(), src->yTilt(),
69 src->tangentialPressure(),
70 src->rotation(),
71 src->z(),
72 src->modifiers(),
73 src->uniqueId(),
74 src->button(), src->buttons());
75 tmp->setTimestamp(src->timestamp());
76 dst.reset(tmp);
77}
78
79template<> void copyEventHack(const QTouchEvent *src, QScopedPointer<QEvent> &dst) {
80 QTouchEvent *tmp = new QTouchEvent(src->type(),
81 src->device(),
82 src->modifiers(),
83 src->touchPointStates(),
84 src->touchPoints());
85 tmp->setTimestamp(src->timestamp());
86 dst.reset(tmp);
87}
88
89}
90#endif
91
92class Q_DECL_HIDDEN KoPointerEvent::Private
93{
94public:
95 template <typename Event>
96 Private(Event *event)
97 : eventPtr(event)
98 {
99 }
100
101 boost::variant2::variant<QMouseEvent*, QTabletEvent*, QTouchEvent*> eventPtr;
103};
104
105bool KoPointerEvent::Private::s_tabletInputReceived;
106
107KoPointerEvent::KoPointerEvent(QMouseEvent *ev, const QPointF &pnt)
108 : point(pnt),
109 d(new Private(ev))
110{
111}
112
113KoPointerEvent::KoPointerEvent(QTabletEvent *ev, const QPointF &pnt)
114 : point(pnt),
115 d(new Private(ev))
116{
117 if (!Private::s_tabletInputReceived) {
118 Private::s_tabletInputReceived = true;
120 }
121}
122
123KoPointerEvent::KoPointerEvent(QTouchEvent* ev, const QPointF &pnt)
124 : point(pnt),
125 d(new Private(ev))
126{
127}
128
130 : point(point)
131 , d(new Private(*(event->d)))
132{
133}
134
136 : point(rhs.point)
137 , d(new Private(*(rhs.d)))
138{
139}
140
142{
143 if (&rhs != this) {
144 *d = *rhs.d;
145 point = rhs.point;
146 }
147
148 return *this;
149}
150
154
155template <typename Event>
156KoPointerEventWrapper::KoPointerEventWrapper(Event *_event, const QPointF &point)
157 : event(_event, point),
158 baseQtEvent(QSharedPointer<QEvent>(static_cast<QEvent*>(_event)))
159{
160}
161
162
163#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
164struct DeepCopyVisitor
165{
166 QPointF point;
167
168 template <typename T>
169 KoPointerEventWrapper operator() (const T *event) {
170 QScopedPointer<QEvent> baseEvent;
171 detail::copyEventHack(event, baseEvent);
172 return {static_cast<T*>(baseEvent.take()), point};
173 }
174};
175#endif
176
178{
179#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
180 return visit(DeepCopyVisitor{point}, d->eventPtr);
181#else
182 struct Visitor {
183
184 QPointF point;
185
186 KoPointerEventWrapper operator() (const QMouseEvent *event) {
187 return KoPointerEventWrapper(event->clone(), point);
188 }
189 KoPointerEventWrapper operator() (const QTabletEvent *event) {
190 return KoPointerEventWrapper(event->clone(), point);
191 }
192 KoPointerEventWrapper operator() (const QTouchEvent *event) {
193 return KoPointerEventWrapper(event->clone(), point);
194 }
195 };
196 return visit(Visitor{point}, d->eventPtr);
197
198
199#endif
200}
201
202Qt::MouseButton KoPointerEvent::button() const
203{
204 struct Visitor {
205 Qt::MouseButton operator() (const QMouseEvent *event) {
206 return event->button();
207 }
208 Qt::MouseButton operator() (const QTabletEvent *event) {
209 return event->button();
210 }
211 Qt::MouseButton operator() (const QTouchEvent *) {
212 return Qt::LeftButton;
213 }
214 };
215
216 return visit(Visitor(), d->eventPtr);
217}
218
219Qt::MouseButtons KoPointerEvent::buttons() const
220{
221 struct Visitor {
222 Qt::MouseButtons operator() (const QMouseEvent *event) {
223 return event->buttons();
224 }
225 Qt::MouseButtons operator() (const QTabletEvent *event) {
226 return event->buttons();
227 }
228 Qt::MouseButtons operator() (const QTouchEvent *) {
229 return Qt::LeftButton;
230 }
231 };
232
233 return visit(Visitor(), d->eventPtr);
234}
235
237{
238#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
239 struct Visitor {
240 QPoint operator() (const QMouseEvent *event) {
241 return event->globalPos();
242 }
243 QPoint operator() (const QTabletEvent *event) {
244 return event->globalPos();
245 }
246 QPoint operator() (const QTouchEvent *event) {
247 return event->touchPoints().constFirst().screenPos().toPoint();
248 }
249#else
250 struct Visitor {
251 QPoint operator() (const QMouseEvent *event) {
252 return event->globalPosition().toPoint();
253 }
254 QPoint operator() (const QTabletEvent *event) {
255 return event->globalPosition().toPoint();
256 }
257 QPoint operator() (const QTouchEvent *event) {
258 return event->points().constFirst().globalPosition().toPoint();
259 }
260#endif
261
262 };
263
264 return visit(Visitor(), d->eventPtr);
265}
266
268{
269#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
270 struct Visitor {
271 QPoint operator() (const QMouseEvent *event) {
272 return event->pos();
273 }
274 QPoint operator() (const QTabletEvent *event) {
275 return event->pos();
276 }
277 QPoint operator() (const QTouchEvent *event) {
278 return event->touchPoints().at(0).pos().toPoint();
279 }
280 };
281#else
282 struct Visitor {
283 QPoint operator() (const QMouseEvent *event) {
284 return event->position().toPoint();
285 }
286 QPoint operator() (const QTabletEvent *event) {
287 return event->position().toPoint();
288 }
289 QPoint operator() (const QTouchEvent *event) {
290 return event->points().at(0).position().toPoint();
291 }
292 };
293#endif
294 return visit(Visitor(), d->eventPtr);
295}
296
298{
299 return pos().x();
300}
301
303{
304 return pos().y();
305}
306
308{
309 struct Visitor {
310 qreal operator() (const QTabletEvent *event) {
311 return event->pressure();
312 }
313 qreal operator() (const QTouchEvent *event) {
314#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
315 return s_optionContainer->useTouchPressure ? event->touchPoints().at(0).pressure() : 1.0;
316#else
317 return s_optionContainer->useTouchPressure ? event->points().at(0).pressure() : 1.0;
318#endif
319 }
320 qreal operator() (...) {
321 return 1.0;
322 }
323 };
324
325 return visit(Visitor(), d->eventPtr);
326}
327
329{
330 struct Visitor {
331 qreal operator() (const QTabletEvent *event) {
332 return event->rotation();
333 }
334 qreal operator() (const QTouchEvent *event) {
335#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
336 return event->touchPoints().at(0).rotation();
337#else
338 return event->points().at(0).rotation();
339#endif
340 }
341 qreal operator() (...) {
342 return 0.0;
343 }
344 };
345
346 return visit(Visitor(), d->eventPtr);
347}
348
350{
351 struct Visitor {
352 qreal operator() (const QTabletEvent *event) {
353 return std::fmod((event->tangentialPressure() - (-1.0)) / (1.0 - (-1.0)), 2.0);
354 }
355 qreal operator() (...) {
356 return 0.0;
357 }
358 };
359
360 return visit(Visitor(), d->eventPtr);
361}
362
364{
365 struct Visitor {
366 int operator() (const QTabletEvent *event) {
367 return event->xTilt();
368 }
369 int operator() (...) {
370 return 0;
371 }
372 };
373
374 return visit(Visitor(), d->eventPtr);
375}
376
377
379{
380 struct Visitor {
381 int operator() (const QTabletEvent *event) {
382 return event->yTilt();
383 }
384 int operator() (...) {
385 return 0;
386 }
387 };
388
389 return visit(Visitor(), d->eventPtr);
390}
391
393{
394 struct Visitor {
395 int operator() (const QTabletEvent *event) {
396 return event->z();
397 }
398 int operator() (...) {
399 return 0;
400 }
401 };
402
403 return visit(Visitor(), d->eventPtr);
404}
405
407{
408 struct Visitor {
409 ulong operator() (const QInputEvent *event) {
410 return event->timestamp();
411 }
412 };
413
414 return visit(Visitor(), d->eventPtr);
415}
416
418{
419 return d->eventPtr.index() == 1;
420}
421
423{
424 return d->eventPtr.index() == 2;
425}
426
428{
429 return Private::s_tabletInputReceived;
430}
431
432Qt::KeyboardModifiers KoPointerEvent::modifiers() const
433{
434 struct Visitor {
435 Qt::KeyboardModifiers operator() (const QInputEvent *event) {
436 return event->modifiers();
437 }
438 };
439
440 return visit(Visitor(), d->eventPtr);
441}
442
444{
445 struct Visitor {
446 void operator() (QInputEvent *event) {
447 event->accept();
448 }
449 };
450
451 return visit(Visitor(), d->eventPtr);
452}
453
455{
456 struct Visitor {
457 void operator() (QInputEvent *event) {
458 event->ignore();
459 }
460 };
461
462 return visit(Visitor(), d->eventPtr);
463}
464
466{
467 struct Visitor {
468 bool operator() (const QInputEvent *event) {
469 return event->isAccepted();
470 }
471 };
472
473 return visit(Visitor(), d->eventPtr);
474}
475
477{
478 struct Visitor {
479 bool operator() (const QInputEvent *event) {
480 return event->spontaneous();
481 }
482 };
483
484 return visit(Visitor(), d->eventPtr);
485}
486
487#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
488void KoPointerEvent::copyQtPointerEvent(const QMouseEvent *event, QScopedPointer<QEvent> &dst)
489{
490 detail::copyEventHack(event, dst);
491}
492
493void KoPointerEvent::copyQtPointerEvent(const QTabletEvent *event, QScopedPointer<QEvent> &dst)
494{
495 detail::copyEventHack(event, dst);
496}
497
498void KoPointerEvent::copyQtPointerEvent(const QTouchEvent *event, QScopedPointer<QEvent> &dst)
499{
500 detail::copyEventHack(event, dst);
501}
502#endif
503
504std::optional<QPointF> KoPointerEvent::fetchGlobalPositionFromPointerEvent(QEvent *event)
505{
506 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(event, std::nullopt);
507
508 if (event->type() == QEvent::TouchBegin || event->type() == QEvent::TouchUpdate || event->type() == QEvent::TouchEnd) {
509 const QTouchEvent *touchEvent = static_cast<const QTouchEvent *>(event);
510#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
511 const QList<QEventPoint> &touchPoints = touchEvent->points();
512#else
513 const QList<QTouchEvent::TouchPoint> &touchPoints = touchEvent->touchPoints();
514#endif
515 if (touchPoints.isEmpty()) {
516 // Getting zero touch points can happen on Android when pressing
517 // on the screen with an entire palm. Punt to using the cursor
518 // position after all.
519 return std::nullopt;
520 } else {
521#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
522 return touchPoints.constFirst().globalPosition();
523#else
524 return touchPoints.constFirst().screenPos();
525#endif
526 }
527 } else if (event->type() == QEvent::TabletPress || event->type() == QEvent::TabletRelease) {
528 const QTabletEvent *tabletEvent = static_cast<const QTabletEvent *>(event);
529#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
530 return tabletEvent->globalPosition();
531#else
532 return tabletEvent->globalPos();
533#endif
534 } else if (event->type() == QEvent::MouseButtonPress ||
535 event->type() == QEvent::MouseButtonRelease ||
536 event->type() == QEvent::MouseMove) {
537 const QMouseEvent *mouseEvent = static_cast<const QMouseEvent *>(event);
538#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
539 return mouseEvent->globalPosition();
540#else
541 return mouseEvent->globalPos();
542#endif
543 }
544
545 return std::nullopt;
546}
547
548#include <KoPointerEvent.moc>
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
static KisConfigNotifier * instance()
const QScopedPointer< Private > d
static std::optional< QPointF > fetchGlobalPositionFromPointerEvent(QEvent *event)
bool spontaneous() const
return if this event was spontaneous (see QMouseEvent::spontaneous())
qreal pressure() const
Private(Event *event)
QPoint globalPos() const
Return the position screen coordinates.
KoPointerEvent & operator=(const KoPointerEvent &rhs)
qreal rotation() const
return the rotation (or a default value)
KoPointerEvent(QMouseEvent *event, const QPointF &point)
Qt::MouseButton button() const
return button pressed (see QMouseEvent::button());
ulong time() const
Qt::MouseButtons buttons() const
return buttons pressed (see QMouseEvent::buttons());
qreal yTilt() const
qreal tangentialPressure() const
bool isTabletEvent() const
bool isTouchEvent() const
boost::variant2::variant< QMouseEvent *, QTabletEvent *, QTouchEvent * > eventPtr
Qt::KeyboardModifiers modifiers() const
static bool s_tabletInputReceived
bool isAccepted() const
return if the event has been accepted.
QPointF point
The point in document coordinates.
qreal xTilt() const
KoPointerEventWrapper deepCopyEvent() const
static bool tabletInputReceived()
QPoint pos() const
return the position in widget coordinates
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
KoPointerEventWrapper(Event *_event, const QPointF &point)