diff options
-rw-r--r-- | src/quick/handlers/qquickdraghandler.cpp | 37 | ||||
-rw-r--r-- | src/quick/handlers/qquickdraghandler_p.h | 4 | ||||
-rw-r--r-- | tests/manual/pointer/content/Slider.qml | 16 |
3 files changed, 43 insertions, 14 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; diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml index 44dea8e33b..ecf45c02f3 100644 --- a/tests/manual/pointer/content/Slider.qml +++ b/tests/manual/pointer/content/Slider.qml @@ -50,6 +50,15 @@ Item { property alias pressed: tap.isPressed signal tapped + DragHandler { + id: dragHandler + objectName: label.text + " DragHandler" + target: knob + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + Rectangle { id: slot anchors.top: parent.top @@ -90,13 +99,6 @@ Item { onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier transformOrigin: Item.Center function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } - DragHandler { - id: dragHandler - objectName: label.text + " DragHandler" - xAxis.enabled: false - yAxis.minimum: slot.y - yAxis.maximum: slot.height + slot.y - knob.height - } TapHandler { id: tap objectName: label.text + " TapHandler" |