Add more QPointerEvent functions needed in Qt Quick

Change-Id: I87a874477b89eb3f5951930f03e305d896a24c2e
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
bb10
Shawn Rutledge 2020-08-29 16:59:21 +02:00
parent d1fc991c6e
commit 8932e80d0c
6 changed files with 195 additions and 0 deletions

View File

@ -605,6 +605,44 @@ QPointerEvent::~QPointerEvent()
{
}
/*!
Returns the point whose \l {QEventPoint::id()}{id} matches the given \a id,
or \c nullptr if no such point is found.
*/
QEventPoint *QPointerEvent::pointById(int id)
{
for (auto &p : m_points) {
if (p.id() == id)
return &p;
}
return nullptr;
}
/*!
Returns \c true if every point in points() has an exclusiveGrabber().
*/
bool QPointerEvent::allPointsGrabbed() const
{
for (const auto &p : points()) {
if (exclusiveGrabber(p) && passiveGrabbers(p).isEmpty())
return false;
}
return true;
}
/*!
Returns \c true if isPointAccepted() is \c true for every point in
points(); otherwise \c false.
*/
bool QPointerEvent::allPointsAccepted() const
{
for (const auto &p : points()) {
if (!p.isAccepted())
return false;
}
return true;
}
/*!
Returns the source device from which this event originates.
@ -844,6 +882,27 @@ QSinglePointEvent::QSinglePointEvent(QEvent::Type type, const QPointingDevice *d
m_points.append(mut);
}
/*! \internal
Constructs a single-point event with the given \a point, which must be an instance
(or copy of one) that already exists in QPointingDevicePrivate::activePoints.
Unlike the other constructor, it does not modify the given \a point in any way.
This is useful when synthesizing a QMouseEvent from one point taken from a QTouchEvent, for example.
\sa QMutableSinglePointEvent()
*/
QSinglePointEvent::QSinglePointEvent(QEvent::Type type, const QPointingDevice *dev, const QEventPoint &point,
Qt::MouseButton button, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source)
: QPointerEvent(type, dev, modifiers),
m_button(button),
m_mouseState(buttons),
m_source(source),
m_doubleClick(false),
m_reserved(0)
{
m_points << point;
}
/*!
Returns \c true if this event represents a \l {button()}{button} being pressed.
*/

View File

@ -63,8 +63,11 @@ QT_BEGIN_NAMESPACE
class QFile;
class QAction;
class QMouseEvent;
class QPointerEvent;
class QScreen;
class QTabletEvent;
class QTouchEvent;
#if QT_CONFIG(gestures)
class QGesture;
#endif
@ -94,6 +97,19 @@ struct QEventPointPrivate;
class Q_GUI_EXPORT QEventPoint
{
Q_GADGET
Q_PROPERTY(const QPointingDevice *device READ device)
Q_PROPERTY(int id READ id)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
Q_PROPERTY(State state READ state)
Q_PROPERTY(ulong timestamp READ timestamp)
Q_PROPERTY(qreal timeHeld READ timeHeld)
Q_PROPERTY(qreal pressure READ pressure)
Q_PROPERTY(qreal rotation READ rotation)
Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
Q_PROPERTY(QVector2D velocity READ velocity)
Q_PROPERTY(QPointF position READ position)
Q_PROPERTY(QPointF scenePosition READ scenePosition)
Q_PROPERTY(QPointF globalPosition READ globalPosition)
public:
enum State : quint8 {
Unknown = Qt::TouchPointUnknownState,
@ -192,9 +208,12 @@ public:
qsizetype pointCount() const { return m_points.count(); }
QEventPoint &point(qsizetype i) { return m_points[i]; }
const QList<QEventPoint> &points() const { return m_points; }
QEventPoint *pointById(int id);
bool allPointsGrabbed() const;
virtual bool isPressEvent() const { return false; }
virtual bool isUpdateEvent() const { return false; }
virtual bool isReleaseEvent() const { return false; }
bool allPointsAccepted() const;
QObject *exclusiveGrabber(const QEventPoint &point) const;
void setExclusiveGrabber(const QEventPoint &point, QObject *exclusiveGrabber);
QList<QPointer <QObject>> passiveGrabbers(const QEventPoint &point) const;
@ -229,6 +248,10 @@ public:
bool isReleaseEvent() const override;
protected:
QSinglePointEvent(Type type, const QPointingDevice *dev, const QEventPoint &point,
Qt::MouseButton button, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source);
Qt::MouseButton m_button = Qt::NoButton;
Qt::MouseButtons m_mouseState = Qt::NoButton;
quint32 m_source : 8; // actually Qt::MouseEventSource
@ -346,6 +369,12 @@ protected:
#if QT_CONFIG(wheelevent)
class Q_GUI_EXPORT QWheelEvent : public QSinglePointEvent
{
Q_GADGET
Q_PROPERTY(const QPointingDevice *device READ pointingDevice)
Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
Q_PROPERTY(QPoint angleDelta READ angleDelta)
Q_PROPERTY(Qt::ScrollPhase phase READ phase)
Q_PROPERTY(bool inverted READ inverted)
public:
enum { DefaultDeltasPerStep = 120 };
@ -360,6 +389,8 @@ public:
inline Qt::ScrollPhase phase() const { return Qt::ScrollPhase(m_phase); }
inline bool inverted() const { return m_invertedScrolling; }
inline bool isInverted() const { return m_invertedScrolling; }
inline bool hasPixelDelta() const { return !m_pixelDelta.isNull(); }
Qt::MouseEventSource source() const { return Qt::MouseEventSource(m_source); }

View File

@ -199,6 +199,12 @@ static_assert(sizeof(QMutableTouchEvent) == sizeof(QTouchEvent));
class Q_GUI_EXPORT QMutableSinglePointEvent : public QSinglePointEvent
{
public:
QMutableSinglePointEvent(Type type, const QPointingDevice *device, const QEventPoint &point,
Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = Qt::NoButton,
Qt::KeyboardModifiers modifiers = Qt::NoModifier,
Qt::MouseEventSource source = Qt::MouseEventSynthesizedByQt) :
QSinglePointEvent(type, device, point, button, buttons, modifiers, source) { }
static QMutableSinglePointEvent *from(QSinglePointEvent *e) { return static_cast<QMutableSinglePointEvent *>(e); }
static QMutableSinglePointEvent &from(QSinglePointEvent &e) { return static_cast<QMutableSinglePointEvent &>(e); }

View File

@ -354,6 +354,33 @@ const QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::D
return nullptr;
}
/*!
\internal
First, ensure that the \a cancelEvent's QTouchEvent::points() list contains
all points that have exclusive grabs. Then send the event to each object
that has an exclusive grab of any of the points.
*/
void QPointingDevicePrivate::sendTouchCancelEvent(QTouchEvent *cancelEvent)
{
// An incoming TouchCancel event will typically not contain any points, but
// QQuickPointerHandler::onGrabChanged needs to be called for each point
// that has an exclusive grabber. Adding those points to the event makes it
// an easy iteration there.
if (cancelEvent->points().isEmpty()) {
for (auto &epd : activePoints.values()) {
if (epd.exclusiveGrabber)
QMutableTouchEvent::from(cancelEvent)->addPoint(epd.eventPoint);
}
}
for (auto &epd : activePoints.values()) {
if (epd.exclusiveGrabber)
QCoreApplication::sendEvent(epd.exclusiveGrabber, cancelEvent);
// The next touch event can only be a TouchBegin, so clean up.
cancelEvent->setExclusiveGrabber(epd.eventPoint, nullptr);
cancelEvent->clearPassiveGrabbers(epd.eventPoint);
}
}
/*! \internal
Returns the active EventPointData instance with the given \a id, if available,
or \c nullptr if not.
@ -422,6 +449,19 @@ QWindow *QPointingDevicePrivate::firstActiveWindow() const
return nullptr;
}
/*! \internal
Return the exclusive grabber of the first point in activePoints.
This is mainly for autotests that try to verify the "current" grabber
outside the context of event delivery, which is something that the rest
of the codebase should not be doing.
*/
QObject *QPointingDevicePrivate::firstPointExclusiveGrabber() const
{
if (activePoints.isEmpty())
return nullptr;
return activePoints.values().first().exclusiveGrabber;
}
void QPointingDevicePrivate::setExclusiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *exclusiveGrabber)
{
Q_Q(QPointingDevice);
@ -446,6 +486,22 @@ void QPointingDevicePrivate::setExclusiveGrabber(const QPointerEvent *event, con
emit q->grabChanged(exclusiveGrabber, QPointingDevice::GrabExclusive, event, point);
}
/*!
\internal
Call QEventPoint::setExclusiveGrabber(nullptr) on each active point that has a grabber.
*/
bool QPointingDevicePrivate::removeExclusiveGrabber(const QPointerEvent *event, const QObject *grabber)
{
bool ret = false;
for (auto &pt : activePoints.values()) {
if (pt.exclusiveGrabber == grabber) {
setExclusiveGrabber(event, pt.eventPoint, nullptr);
ret = true;
}
}
return ret;
}
bool QPointingDevicePrivate::addPassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber)
{
Q_Q(QPointingDevice);
@ -505,6 +561,43 @@ void QPointingDevicePrivate::clearPassiveGrabbers(const QPointerEvent *event, co
persistentPoint->passiveGrabbers.clear();
}
/*!
\internal
Removes the given \a grabber as both passive and exclusive grabber from all
points in activePoints where it's currently found. If \a cancel is \c true,
the transition emitted from the grabChanged() signal will be
\c CancelGrabExclusive or \c CancelGrabPassive. Otherwise it will be
\c UngrabExclusive or \c UngrabPassive.
\note This function provides a way to work around the limitation that we
normally change grabbers only during event delivery; but it's also more expensive.
*/
void QPointingDevicePrivate::removeGrabber(QObject *grabber, bool cancel)
{
Q_Q(QPointingDevice);
for (auto ap : activePoints) {
auto &epd = ap.second;
if (epd.exclusiveGrabber.data() == grabber) {
qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
<< "@" << epd.eventPoint.scenePosition()
<< ": grab" << grabber << "-> nullptr";
epd.exclusiveGrabber.clear();
emit q->grabChanged(grabber,
cancel ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
nullptr, epd.eventPoint);
}
int pi = epd.passiveGrabbers.indexOf(grabber);
if (pi >= 0) {
qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
<< ": removing passive grabber" << grabber;
epd.passiveGrabbers.removeAt(pi);
emit q->grabChanged(grabber,
cancel ? QPointingDevice::CancelGrabPassive : QPointingDevice::UngrabPassive,
nullptr, epd.eventPoint);
}
}
}
/*!
\internal
Finds the device instance belonging to the drawing or eraser end of a particular stylus,

View File

@ -50,6 +50,7 @@ class QDebug;
class QEventPoint;
class QPointerEvent;
class QPointingDevicePrivate;
class QPointerEvent;
class QScreen;
class Q_GUI_EXPORT QPointingDeviceUniqueId

View File

@ -77,6 +77,8 @@ public:
activePoints.reserve(maxPoints);
}
void sendTouchCancelEvent(QTouchEvent *cancelEvent);
/*! \internal
This struct (stored in activePoints) holds persistent state between event deliveries.
*/
@ -91,10 +93,13 @@ public:
QObject *firstActiveTarget() const;
QWindow *firstActiveWindow() const;
QObject *firstPointExclusiveGrabber() const;
void setExclusiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *exclusiveGrabber);
bool removeExclusiveGrabber(const QPointerEvent *event, const QObject *grabber);
bool addPassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber);
bool removePassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber);
void clearPassiveGrabbers(const QPointerEvent *event, const QEventPoint &point);
void removeGrabber(QObject *grabber, bool cancel = false);
using EventPointMap = QFlatMap<int, EventPointData>;
mutable EventPointMap activePoints;