aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp37
-rw-r--r--src/quick/handlers/qquickdraghandler_p.h4
-rw-r--r--tests/manual/pointer/content/Slider.qml16
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"