diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-04-24 08:51:47 +0200 |
---|---|---|
committer | Jan Arve Sæther <jan-arve.saether@qt.io> | 2017-04-27 16:10:53 +0000 |
commit | 47479c0e969a3b3d220c77b8bb7cb8f2d58c07ae (patch) | |
tree | 7868201449b1f03df288188f95ce7eda955c7192 /src | |
parent | 822e39df38b20763d2933d7a6d2d6ddf7b9b2639 (diff) |
DragHandler: allow parent to be different from target
The most obvious way to implement a Slider is to allow dragging the
knob - as on a real-world physical sliding potentiometer. But to make
it easier on a touchscreen, it should be possible to touch anywhere
along the slider's travel, as on a QtQuick.Controls 2 Slider. For
that purpose, we need to respond to events within the bounds of one
Item while actually dragging a different Item (the knob). It's
similar to the way that PinchHandler can handle pinch gestures within
one Item while transforming another (which may be too small to get
both fingers inside).
Change-Id: Iac9a5f11a7a45e22d93fe52bf62d157c48d72d3d
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/handlers/qquickdraghandler.cpp | 37 | ||||
-rw-r--r-- | src/quick/handlers/qquickdraghandler_p.h | 4 |
2 files changed, 34 insertions, 7 deletions
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp index 73ad97712e..b4006ab5c7 100644 --- a/src/quick/handlers/qquickdraghandler.cpp +++ b/src/quick/handlers/qquickdraghandler.cpp @@ -75,17 +75,25 @@ bool QQuickDragHandler::wantsEventPoint(QQuickEventPoint *point) void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point) { + if (grabber == this && stateChange == QQuickEventPoint::GrabExclusive) + // In case the grab got handled over from another grabber, we might not get the Press + initializeTargetStartPos(point); enforceConstraints(); QQuickPointerSingleHandler::onGrabChanged(grabber, stateChange, point); } +void QQuickDragHandler::onActiveChanged() +{ + if (!active()) + m_targetStartPos = QPointF(); +} + void QQuickDragHandler::handleEventPoint(QQuickEventPoint *point) { point->setAccepted(); switch (point->state()) { case QQuickEventPoint::Pressed: - if (target() && target()->parentItem()) - m_startPos = target()->parentItem()->mapToScene(target()->position()); + initializeTargetStartPos(point); setPassiveGrab(point); break; case QQuickEventPoint::Updated: { @@ -97,7 +105,7 @@ void QQuickDragHandler::handleEventPoint(QQuickEventPoint *point) if (active()) { setTranslation(delta); if (target() && target()->parentItem()) { - QPointF pos = target()->parentItem()->mapFromScene(m_startPos + delta); + QPointF pos = target()->parentItem()->mapFromScene(m_targetStartPos + delta); enforceAxisConstraints(&pos); target()->setPosition(pos); } @@ -105,13 +113,13 @@ void QQuickDragHandler::handleEventPoint(QQuickEventPoint *point) ((m_xAxis.enabled() && QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point)) || (m_yAxis.enabled() && QQuickWindowPrivate::dragOverThreshold(delta.y(), Qt::YAxis, point)))) { setExclusiveGrab(point); - if (target()) { + if (auto parent = parentItem()) { if (point->pointerEvent()->asPointerTouchEvent()) - target()->setKeepTouchGrab(true); + parent->setKeepTouchGrab(true); // tablet and mouse are treated the same by Item's legacy event handling, and // touch becomes synth-mouse for Flickable, so we need to prevent stealing // mouse grab too, whenever dragging occurs in an enabled direction - target()->setKeepMouseGrab(true); + parent->setKeepMouseGrab(true); } } } break; @@ -139,6 +147,23 @@ void QQuickDragHandler::enforceAxisConstraints(QPointF *localPos) localPos->setY(qBound(m_yAxis.minimum(), localPos->y(), m_yAxis.maximum())); } +void QQuickDragHandler::initializeTargetStartPos(QQuickEventPoint *point) +{ + if (target() && target()->parentItem() && m_targetStartPos.isNull()) { // prefer the m_targetStartPos we got when it got Pressed. + m_targetStartPos = target()->parentItem()->mapToScene(target()->position()); + if (!target()->contains(point->pos())) { + // If pressed outside of target item, move the target item so that the touchpoint is in its center, + // while still respecting the axis constraints. + const QPointF center = target()->parentItem()->mapFromScene(point->scenePos()); + const QPointF pointCenteredInItemPos = target()->parentItem()->mapToScene(center - QPointF(target()->width(), target()->height())/2); + if (m_xAxis.enabled()) + m_targetStartPos.setX(pointCenteredInItemPos.x()); + if (m_yAxis.enabled()) + m_targetStartPos.setY(pointCenteredInItemPos.y()); + } + } +} + void QQuickDragHandler::setTranslation(const QPointF &trans) { if (trans == m_translation) // fuzzy compare? diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h index a75ea6f2c7..54fef697f7 100644 --- a/src/quick/handlers/qquickdraghandler_p.h +++ b/src/quick/handlers/qquickdraghandler_p.h @@ -112,14 +112,16 @@ Q_SIGNALS: protected: bool wantsEventPoint(QQuickEventPoint *point) override; + void onActiveChanged() override; void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point) override; private: void ungrab(); void enforceAxisConstraints(QPointF *localPos); + void initializeTargetStartPos(QQuickEventPoint *point); private: - QPointF m_startPos; + QPointF m_targetStartPos; QPointF m_translation; QQuickDragAxis m_xAxis; QQuickDragAxis m_yAxis; |