diff --git a/src/qmlcontrols/draganddrop/DeclarativeDragArea.h b/src/qmlcontrols/draganddrop/DeclarativeDragArea.h --- a/src/qmlcontrols/draganddrop/DeclarativeDragArea.h +++ b/src/qmlcontrols/draganddrop/DeclarativeDragArea.h @@ -146,6 +146,7 @@ void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; bool childMouseEventFilter(QQuickItem *item, QEvent *event) Q_DECL_OVERRIDE; private: @@ -164,6 +165,7 @@ QImage m_delegateImage; int m_startDragDistance; QPointF m_buttonDownPos; + int m_pressAndHoldTimerId; }; #endif // DECLARATIVEDRAGAREA_H diff --git a/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp b/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp --- a/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp +++ b/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp @@ -51,7 +51,8 @@ m_dragActive(false), m_supportedActions(Qt::MoveAction), m_defaultAction(Qt::MoveAction), - m_data(new DeclarativeMimeData()) // m_data is owned by us, and we shouldn't pass it to Qt directly as it will automatically delete it after the drag and drop. + m_data(new DeclarativeMimeData()), // m_data is owned by us, and we shouldn't pass it to Qt directly as it will automatically delete it after the drag and drop. + m_pressAndHoldTimerId(0) { m_startDragDistance = QGuiApplication::styleHints()->startDragDistance(); setAcceptedMouseButtons(Qt::LeftButton); @@ -209,27 +210,62 @@ void DeclarativeDragArea::mousePressEvent(QMouseEvent* event) { + m_pressAndHoldTimerId = startTimer(QGuiApplication::styleHints()->mousePressAndHoldInterval()); m_buttonDownPos = event->screenPos(); m_draggingJustStarted = true; setKeepMouseGrab(true); } void DeclarativeDragArea::mouseReleaseEvent(QMouseEvent* event) { Q_UNUSED(event); + killTimer(m_pressAndHoldTimerId); + m_pressAndHoldTimerId = 0; m_draggingJustStarted = false; setKeepMouseGrab(false); ungrabMouse(); } +void DeclarativeDragArea::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == m_pressAndHoldTimerId && m_draggingJustStarted && m_enabled) { + // Grab delegate before starting drag + if (m_delegate) { + // Another grab is already in progress + if (m_grabResult) { + return; + } + m_grabResult = m_delegate->grabToImage(); + if (m_grabResult) { + connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this, [this]() { + startDrag(m_grabResult->image()); + m_grabResult.reset(); + }); + return; + } + } + + // No delegate or grab failed, start drag immediately + startDrag(m_delegateImage); + } +} + void DeclarativeDragArea::mouseMoveEvent(QMouseEvent *event) { if ( !m_enabled || QLineF(event->screenPos(), m_buttonDownPos).length() < m_startDragDistance) { return; } + //don't start drags on move for touch events, they'll be handled only by press and hold + //reset timer if moved more than m_startDragDistance + if (event->source() == Qt::MouseEventSynthesizedByQt) { + killTimer(m_pressAndHoldTimerId); + m_pressAndHoldTimerId = 0; + return; + } + if (m_draggingJustStarted) { // Grab delegate before starting drag if (m_delegate) {