aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2017-02-14 10:04:49 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2017-02-21 15:28:36 +0000
commit507efe5a8a2390813fb620a91b0b3b6b383f599d (patch)
treef60fdb68f5af695197673706fa5a6d3a0c93bfbe /src
parent8967a1b7b86306879a3113b290610b03727670ff (diff)
unify handler grab state handling into onGrabChanged
onGrabChanged and handleGrab looked redundant. It was also not clear how important it is for handlers to react to passive ungrabs, overrides or cancellations. Rather than debating about when to call one of these and when not to, let's centralize the responsibility in QQuickEventPoint (because the grabber pointers are stored there, so it's the ultimate destination of any grab change), and let's notify all the relevant handlers about all changes, with enough information that each handler can decide for itself what's important and what isn't. But so far most handlers don't need to override this virtual. The base class QQuickPointerHandler takes care of setting the active property to false, rejecting the eventpoint, and unsetting keepMouseGrab and keepTouchGrab whenever grab is lost; and emitting grabChanged or canceled as appropriate to notify any QML code which needs to know. Subclasses mainly care about the change of active state: they must initiate active state themselves, and may react when it reverts to false. Change-Id: I6c7f29472d12564d74ae091b0c81fa08fe131ce7 Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp99
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h4
-rw-r--r--src/quick/handlers/qquickpointersinglehandler.cpp30
-rw-r--r--src/quick/handlers/qquickpointersinglehandler_p.h3
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp18
-rw-r--r--src/quick/handlers/qquicktaphandler_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp32
-rw-r--r--src/quick/items/qquickevents_p_p.h12
8 files changed, 126 insertions, 74 deletions
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index 90d07b5d6d..88c6800dcc 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -76,48 +76,75 @@ QQuickPointerHandler::~QQuickPointerHandler()
}
}
+/*!
+ Notification that the grab has changed in some way which is relevant to this handler.
+ The \a grabber (subject) will be the PointerHandler whose state is changing,
+ or null if the state change regards an Item. (TODO do we have any such cases?)
+ The \a stateChange (verb) tells what happened.
+ The \a point (object) is the point that was grabbed or ungrabbed.
+ EventPoint has the sole responsibility to call this function.
+ The PointerHandler must react in whatever way is appropriate, and must
+ emit the relevant signals (for the benefit of QML code).
+ A subclass is allowed to override this virtual function, but must always
+ call its parent class's implementation in addition to (usually after)
+ whatever custom behavior it implements.
+*/
+void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point)
+{
+ qCDebug(lcPointerHandlerDispatch) << point << stateChange << grabber;
+ Q_ASSERT(point);
+ if (grabber == this) {
+ bool wasCanceled = false;
+ emit grabChanged(point);
+ switch (stateChange) {
+ case QQuickEventPoint::GrabPassive:
+ case QQuickEventPoint::GrabExclusive:
+ break;
+ case QQuickEventPoint::CancelGrabPassive:
+ case QQuickEventPoint::CancelGrabExclusive:
+ wasCanceled = true; // the grab was stolen by something else
+ Q_FALLTHROUGH();
+ case QQuickEventPoint::UngrabPassive:
+ case QQuickEventPoint::UngrabExclusive:
+ setActive(false);
+ point->setAccepted(false);
+ if (auto par = parentItem()) {
+ par->setKeepMouseGrab(m_hadKeepMouseGrab);
+ par->setKeepTouchGrab(m_hadKeepTouchGrab);
+ }
+ case QQuickEventPoint::OverrideGrabPassive:
+ // Passive grab is still there, but we won't receive point updates right now.
+ // No need to notify about this.
+ return;
+ }
+ if (wasCanceled)
+ emit canceled(point);
+ else
+ emit grabChanged(point);
+ }
+}
+
void QQuickPointerHandler::setPassiveGrab(QQuickEventPoint *point, bool grab)
{
+ qCDebug(lcPointerHandlerDispatch) << point << grab;
if (grab) {
point->setGrabberPointerHandler(this, false);
- emit grabChanged(point);
- } else if (point->grabberPointerHandler() == this) {
- // TODO should giving up passive grab imply giving up exclusive grab too?
- // we're being inconsistent here: check whether the exclusive grabber is this,
- // then say that the passive grab was canceled.
- point->cancelPassiveGrab(this);
- emit grabChanged(point);
+ } else {
+ point->removePassiveGrabber(this);
}
}
void QQuickPointerHandler::setExclusiveGrab(QQuickEventPoint *point, bool grab)
{
- QQuickPointerHandler *oldGrabber = point->grabberPointerHandler();
- if (grab && oldGrabber != this) {
- if (target()) {
- m_hadKeepMouseGrab = target()->keepMouseGrab();
- m_hadKeepTouchGrab = target()->keepTouchGrab();
- }
- if (oldGrabber)
- oldGrabber->handleGrabCancel(point);
- point->setGrabberPointerHandler(this, true);
- onGrabChanged(point);
-// emit grabChanged(point); // TODO maybe
- } else if (!grab && oldGrabber == this) {
- if (auto tgt = target()) {
- tgt->setKeepMouseGrab(m_hadKeepMouseGrab);
- tgt->setKeepTouchGrab(m_hadKeepTouchGrab);
- }
- point->setGrabberPointerHandler(nullptr, true);
- onGrabChanged(point);
-// emit grabChanged(point); // TODO maybe
- }
+ // TODO m_hadKeepMouseGrab m_hadKeepTouchGrab
+ qCDebug(lcPointerHandlerDispatch) << point << grab;
+ point->setGrabberPointerHandler(grab ? this : nullptr, true);
}
void QQuickPointerHandler::cancelAllGrabs(QQuickEventPoint *point)
{
+ qCDebug(lcPointerHandlerDispatch) << point;
point->cancelAllGrabs(this);
- emit grabChanged(point);
}
QPointF QQuickPointerHandler::eventPos(const QQuickEventPoint *point) const
@@ -177,22 +204,6 @@ void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
setActive(false);
}
-void QQuickPointerHandler::handleGrabCancel(QQuickEventPoint *point)
-{
- qCDebug(lcPointerHandlerDispatch) << point;
- Q_ASSERT(point);
- setActive(false);
- point->setAccepted(false);
- emit canceled(point);
-}
-
-void QQuickPointerHandler::handleGrab(QQuickEventPoint *point, QQuickPointerHandler *grabber, bool grab)
-{
- Q_UNUSED(point);
- Q_UNUSED(grabber);
- Q_UNUSED(grab);
-}
-
bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
{
Q_UNUSED(event)
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index 39362ca2e0..715000114e 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -98,12 +98,10 @@ protected:
virtual void handlePointerEventImpl(QQuickPointerEvent *event);
void setActive(bool active);
virtual void onActiveChanged() { }
- virtual void onGrabChanged(QQuickEventPoint *) { }
+ virtual void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point);
void setPassiveGrab(QQuickEventPoint *point, bool grab = true);
void setExclusiveGrab(QQuickEventPoint *point, bool grab = true);
void cancelAllGrabs(QQuickEventPoint *point);
- virtual void handleGrabCancel(QQuickEventPoint *point);
- virtual void handleGrab(QQuickEventPoint *point, QQuickPointerHandler *grabber, bool grab);
QPointF eventPos(const QQuickEventPoint *point) const;
bool parentContains(const QQuickEventPoint *point) const;
diff --git a/src/quick/handlers/qquickpointersinglehandler.cpp b/src/quick/handlers/qquickpointersinglehandler.cpp
index c0c88f3852..ec66112519 100644
--- a/src/quick/handlers/qquickpointersinglehandler.cpp
+++ b/src/quick/handlers/qquickpointersinglehandler.cpp
@@ -141,18 +141,28 @@ bool QQuickPointerSingleHandler::wantsEventPoint(QQuickEventPoint *point)
return parentContains(point);
}
-void QQuickPointerSingleHandler::handleGrabCancel(QQuickEventPoint *point)
+void QQuickPointerSingleHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point)
{
- QQuickPointerHandler::handleGrabCancel(point);
- reset();
-}
-
-void QQuickPointerSingleHandler::onGrabChanged(QQuickEventPoint *point)
-{
- bool grabbing = (point->exclusiveGrabber() == this);
- setActive(grabbing);
- if (grabbing)
+ QQuickPointerHandler::onGrabChanged(grabber, stateChange, point);
+ if (grabber != this)
+ return;
+ switch (stateChange) {
+ case QQuickEventPoint::GrabExclusive:
+ setActive(true);
+ Q_FALLTHROUGH();
+ case QQuickEventPoint::GrabPassive:
m_sceneGrabPos = point->sceneGrabPos();
+ break;
+ case QQuickEventPoint::OverrideGrabPassive:
+ return; // don't emit
+ case QQuickEventPoint::UngrabPassive:
+ case QQuickEventPoint::UngrabExclusive:
+ case QQuickEventPoint::CancelGrabPassive:
+ case QQuickEventPoint::CancelGrabExclusive:
+ // the grab is lost or relinquished, so the point is no longer relevant
+ reset();
+ break;
+ }
emit singlePointGrabChanged();
}
diff --git a/src/quick/handlers/qquickpointersinglehandler_p.h b/src/quick/handlers/qquickpointersinglehandler_p.h
index 8858b2c080..ca907e7489 100644
--- a/src/quick/handlers/qquickpointersinglehandler_p.h
+++ b/src/quick/handlers/qquickpointersinglehandler_p.h
@@ -100,8 +100,7 @@ protected:
virtual void handleEventPoint(QQuickEventPoint *point) = 0;
quint64 pointId() const { return m_pointId; }
QQuickEventPoint *currentPoint(QQuickPointerEvent *ev) { return ev->pointById(m_pointId); }
- void handleGrabCancel(QQuickEventPoint *point) override;
- void onGrabChanged(QQuickEventPoint *point) override;
+ void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point) override;
private:
void setPressedButtons(Qt::MouseButtons buttons);
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 228b6bbaf3..b05d32f4b4 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -132,9 +132,9 @@ bool QQuickTapHandler::wantsEventPoint(QQuickEventPoint *point)
}
break;
}
- // If this is the grabber, returning false from this function will
- // cancel the grab, so handleGrabCancel() and setPressed(false) will be called.
- // But when m_gesturePolicy is DragThreshold, we don't grab, but
+ // If this is the grabber, returning false from this function will cancel the grab,
+ // so onGrabChanged(this, CancelGrabExclusive, point) and setPressed(false) will be called.
+ // But when m_gesturePolicy is DragThreshold, we don't get an exclusive grab, but
// we still don't want to be pressed anymore.
if (!ret)
setPressed(false, true, point);
@@ -254,7 +254,10 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi
m_longPressTimer.stop();
m_holdTimer.invalidate();
}
- setPassiveGrab(point, press);
+ if (m_gesturePolicy == DragThreshold)
+ setPassiveGrab(point, press);
+ else
+ setExclusiveGrab(point, press);
if (!cancel && !press && point->timeHeld() < longPressThreshold()) {
// Assuming here that pointerEvent()->timestamp() is in ms.
qreal ts = point->pointerEvent()->timestamp() / 1000.0;
@@ -274,10 +277,11 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi
}
}
-void QQuickTapHandler::handleGrabCancel(QQuickEventPoint *point)
+void QQuickTapHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point)
{
- QQuickPointerSingleHandler::handleGrabCancel(point);
- setPressed(false, true, point);
+ QQuickPointerSingleHandler::onGrabChanged(grabber, stateChange, point);
+ if (grabber == this && stateChange == QQuickEventPoint::CancelGrabExclusive)
+ setPressed(false, true, point);
}
void QQuickTapHandler::connectPreRenderSignal(bool conn)
diff --git a/src/quick/handlers/qquicktaphandler_p.h b/src/quick/handlers/qquicktaphandler_p.h
index bc292ecb12..5956a7f185 100644
--- a/src/quick/handlers/qquicktaphandler_p.h
+++ b/src/quick/handlers/qquicktaphandler_p.h
@@ -102,7 +102,7 @@ Q_SIGNALS:
void longPressed();
protected:
- void handleGrabCancel(QQuickEventPoint *point) override;
+ void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point) override;
void timerEvent(QTimerEvent *event) override;
private:
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 1843d2b656..cddcf02955 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -651,11 +651,18 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
}
if (exclusive) {
if (grabber != m_exclusiveGrabber.data()) {
+ if (grabber) {
+ grabber->onGrabChanged(grabber, GrabExclusive, this);
+ for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) {
+ if (passiveGrabber != grabber)
+ passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this);
+ }
+ } else if (QQuickPointerHandler *oldGrabberPointerHandler = qmlobject_cast<QQuickPointerHandler *>(m_exclusiveGrabber.data())) {
+ oldGrabberPointerHandler->onGrabChanged(oldGrabberPointerHandler, UngrabExclusive, this);
+ }
m_exclusiveGrabber = QPointer<QObject>(grabber);
m_grabberIsHandler = true;
m_sceneGrabPos = m_scenePos;
- for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers)
- passiveGrabber->handleGrab(this, grabber, true);
}
} else {
if (!grabber) {
@@ -663,8 +670,10 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
return;
}
auto ptr = QPointer<QQuickPointerHandler>(grabber);
- if (!m_passiveGrabbers.contains(ptr))
+ if (!m_passiveGrabbers.contains(ptr)) {
m_passiveGrabbers.append(ptr);
+ grabber->onGrabChanged(grabber, GrabPassive, this);
+ }
}
}
@@ -684,7 +693,7 @@ void QQuickEventPoint::cancelExclusiveGrab()
<< ": grab (exclusive)" << m_exclusiveGrabber << "-> nullptr";
}
if (auto handler = grabberPointerHandler())
- handler->handleGrabCancel(this);
+ handler->onGrabChanged(handler, CancelGrabExclusive, this);
m_exclusiveGrabber.clear();
}
@@ -695,16 +704,25 @@ void QQuickEventPoint::cancelExclusiveGrab()
*/
void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler)
{
- if (m_passiveGrabbers.removeOne(QPointer<QQuickPointerHandler>(handler))) {
+ if (removePassiveGrabber(handler)) {
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
<< ": grab (passive)" << handler << "removed";
}
- handler->handleGrabCancel(this);
+ handler->onGrabChanged(handler, CancelGrabPassive, this);
}
}
/*!
+ If this point has the given \a handler as a passive grabber, remove it as grabber.
+ Returns true if it was removed, false if it wasn't a grabber.
+*/
+bool QQuickEventPoint::removePassiveGrabber(QQuickPointerHandler *handler)
+{
+ return m_passiveGrabbers.removeOne(handler);
+}
+
+/*!
If the given \a handler is grabbing this point passively, exclusively
or both, cancel the grab and remove it as grabber.
This normally happens when the handler decides that the behavior of this
@@ -718,7 +736,7 @@ void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler)
void QQuickEventPoint::cancelAllGrabs(QQuickPointerHandler *handler)
{
if (m_exclusiveGrabber == handler) {
- handler->handleGrabCancel(this);
+ handler->onGrabChanged(handler, CancelGrabExclusive, this);
m_exclusiveGrabber.clear();
}
cancelPassiveGrab(handler);
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 00da53eb48..ede0ebfde6 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -275,6 +275,17 @@ public:
};
Q_ENUM(State)
+ enum GrabState {
+ GrabPassive = 0,
+ GrabExclusive,
+ UngrabPassive,
+ UngrabExclusive,
+ CancelGrabPassive,
+ CancelGrabExclusive,
+ OverrideGrabPassive
+ };
+ Q_ENUM(GrabState)
+
QQuickEventPoint(QQuickPointerEvent *parent);
void reset(Qt::TouchPointState state, const QPointF &scenePos, quint64 pointId, ulong timestamp, const QVector2D &velocity = QVector2D());
@@ -306,6 +317,7 @@ public:
Q_INVOKABLE void cancelExclusiveGrab();
Q_INVOKABLE void cancelPassiveGrab(QQuickPointerHandler *handler);
+ bool removePassiveGrabber(QQuickPointerHandler *handler);
void cancelAllGrabs(QQuickPointerHandler *handler);
QVector<QPointer <QQuickPointerHandler> > passiveGrabbers() const { return m_passiveGrabbers; }