diff options
author | Liang Qi <liang.qi@qt.io> | 2017-12-20 08:32:22 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-12-20 08:50:58 +0100 |
commit | 9a38fdcf8f9b734808bb54422e306872f3bfa944 (patch) | |
tree | 20fd361db6c505d99a40ab7a695511b97dcdcbd3 /src/quick/items | |
parent | 1db9405128972d5ba77e33181bee40356f718cea (diff) | |
parent | 4fff2bb14e55484eacec0a1b49a2b02958f75eca (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml
tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml
tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml
tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml
tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml
tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml
tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml
tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml
tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml
tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml
tests/manual/pointer/content/FakeFlickable.qml
tests/manual/pointer/content/FlashAnimation.qml
tests/manual/pointer/content/MomentumAnimation.qml
tests/manual/pointer/content/MouseAreaButton.qml
tests/manual/pointer/content/MouseAreaSlider.qml
tests/manual/pointer/content/MptaButton.qml
tests/manual/pointer/content/MultiButton.qml
tests/manual/pointer/content/ScrollBar.qml
tests/manual/pointer/content/Slider.qml
tests/manual/pointer/content/TapHandlerButton.qml
tests/manual/pointer/fakeFlickable.qml
tests/manual/pointer/flickableWithHandlers.qml
tests/manual/pointer/flingAnimation.qml
tests/manual/pointer/joystick.qml
tests/manual/pointer/main.cpp
tests/manual/pointer/main.qml
tests/manual/pointer/map.qml
tests/manual/pointer/map2.qml
tests/manual/pointer/mixer.qml
tests/manual/pointer/multibuttons.qml
tests/manual/pointer/photosurface.qml
tests/manual/pointer/pinchDragFlingMPTA.qml
tests/manual/pointer/pinchHandler.qml
tests/manual/pointer/singlePointHandlerProperties.qml
tests/manual/pointer/tapHandler.qml
tests/manual/pointer/tapWithModifiers.qml
tests/manual/shapestest/main.cpp
Change-Id: I4f233a521305fab1ebfecbac801da192434ed524
Diffstat (limited to 'src/quick/items')
-rw-r--r-- | src/quick/items/qquickevents.cpp | 32 | ||||
-rw-r--r-- | src/quick/items/qquickevents_p_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 56 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 48 | ||||
-rw-r--r-- | src/quick/items/qquickopenglshadereffect.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 172 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 1 |
8 files changed, 172 insertions, 142 deletions
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 8653d758de..4a786d5569 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -790,17 +790,19 @@ QQuickItem *QQuickEventPoint::grabberItem() const void QQuickEventPoint::setGrabberItem(QQuickItem *grabber) { if (grabber != m_exclusiveGrabber.data()) { + QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler(); + if (oldGrabberHandler && !oldGrabberHandler->approveGrabTransition(this, grabber)) + return; if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) { qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this) << ": grab" << m_exclusiveGrabber << "->" << grabber; } - QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler(); - QQuickItem *oldGrabberItem = grabberItem(); m_exclusiveGrabber = QPointer<QObject>(grabber); m_grabberIsHandler = false; m_sceneGrabPos = m_scenePos; + QQuickItem *oldGrabberItem = grabberItem(); if (oldGrabberHandler) - oldGrabberHandler->onGrabChanged(oldGrabberHandler, CancelGrabExclusive, this); + oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this); else if (oldGrabberItem && oldGrabberItem != grabber && grabber && pointerEvent()->asPointerTouchEvent()) oldGrabberItem->touchUngrabEvent(); for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) @@ -837,26 +839,24 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b } if (exclusive) { if (grabber != m_exclusiveGrabber.data()) { + QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler(); + QQuickItem *oldGrabberItem = grabberItem(); + m_exclusiveGrabber = QPointer<QObject>(grabber); + m_grabberIsHandler = true; + m_sceneGrabPos = m_scenePos; if (grabber) { - // set variables before notifying the new grabber - m_exclusiveGrabber = QPointer<QObject>(grabber); - m_grabberIsHandler = true; - m_sceneGrabPos = m_scenePos; 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); - } else if (!m_exclusiveGrabber.isNull()) { - // If there is a previous grabber and it's not a PointerHandler, it must be an Item. - QQuickItem *oldGrabberItem = static_cast<QQuickItem *>(m_exclusiveGrabber.data()); - // If this point came from a touchscreen, notify that previous grabber Item that it's losing its touch grab. - if (pointerEvent()->asPointerTouchEvent()) - oldGrabberItem->touchUngrabEvent(); } - // set variables after notifying the old grabber + if (oldGrabberHandler) + oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this); + else if (oldGrabberItem && pointerEvent()->asPointerTouchEvent()) + oldGrabberItem->touchUngrabEvent(); + // touchUngrabEvent() can result in the grabber being set to null (MPTA does that, for example). + // So set it again to ensure that final state is what we want. m_exclusiveGrabber = QPointer<QObject>(grabber); m_grabberIsHandler = true; m_sceneGrabPos = m_scenePos; diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 09a63febdc..af5857cf63 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -306,7 +306,6 @@ public: void setExclusiveGrabber(QObject *exclusiveGrabber); QQuickItem *grabberItem() const; - Q_DECL_DEPRECATED QQuickItem *grabber() const { return grabberItem(); } void setGrabberItem(QQuickItem *exclusiveGrabber); QQuickPointerHandler *grabberPointerHandler() const; diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index cd918cef5f..bec5f06d72 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -725,7 +725,19 @@ QQuickFlickable::~QQuickFlickable() These properties hold the surface coordinate currently at the top-left corner of the Flickable. For example, if you flick an image up 100 pixels, - \c contentY will be 100. + \c contentY will increase by 100. + + \note If you flick back to the origin (the top-left corner), after the + rebound animation, \c contentX will settle to the same value as \c originX, + and \c contentY to \c originY. These are usually (0,0), however ListView + and GridView may have an arbitrary origin due to delegate size variation, + or item insertion/removal outside the visible region. So if you want to + implement something like a vertical scrollbar, one way is to use + \c {y: (contentY - originY) * (height / contentHeight)} + for the position; another way is to use the normalized values in + \l {QtQuick::Flickable::visibleArea}{visibleArea}. + + \sa originX, originY */ qreal QQuickFlickable::contentX() const { @@ -739,7 +751,8 @@ void QQuickFlickable::setContentX(qreal pos) d->hData.explicitValue = true; d->resetTimeline(d->hData); d->hData.vTime = d->timeline.time(); - movementEnding(true, false); + if (isMoving() || isFlicking()) + movementEnding(true, false); if (-pos != d->hData.move.value()) d->hData.move.setValue(-pos); } @@ -756,7 +769,8 @@ void QQuickFlickable::setContentY(qreal pos) d->vData.explicitValue = true; d->resetTimeline(d->vData); d->vData.vTime = d->timeline.time(); - movementEnding(false, true); + if (isMoving() || isFlicking()) + movementEnding(false, true); if (-pos != d->vData.move.value()) d->vData.move.setValue(-pos); } @@ -2150,6 +2164,8 @@ void QQuickFlickable::setRightMargin(qreal m) This is usually (0,0), however ListView and GridView may have an arbitrary origin due to delegate size variation, or item insertion/removal outside the visible region. + + \sa contentX, contentY */ qreal QQuickFlickable::originY() const @@ -2180,25 +2196,25 @@ qreal QQuickFlickable::originX() const void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center) { Q_D(QQuickFlickable); - if (w != d->hData.viewSize) { - qreal oldSize = d->hData.viewSize; - d->hData.viewSize = w; - d->contentItem->setWidth(w); + const qreal oldHSize = d->hData.viewSize; + const qreal oldVSize = d->vData.viewSize; + const bool needToUpdateWidth = w != oldHSize; + const bool needToUpdateHeight = h != oldVSize; + d->hData.viewSize = w; + d->vData.viewSize = h; + d->contentItem->setSize(QSizeF(w, h)); + if (needToUpdateWidth) emit contentWidthChanged(); - if (center.x() != 0) { - qreal pos = center.x() * w / oldSize; - setContentX(contentX() + pos - center.x()); - } - } - if (h != d->vData.viewSize) { - qreal oldSize = d->vData.viewSize; - d->vData.viewSize = h; - d->contentItem->setHeight(h); + if (needToUpdateHeight) emit contentHeightChanged(); - if (center.y() != 0) { - qreal pos = center.y() * h / oldSize; - setContentY(contentY() + pos - center.y()); - } + + if (center.x() != 0) { + qreal pos = center.x() * w / oldHSize; + setContentX(contentX() + pos - center.x()); + } + if (center.y() != 0) { + qreal pos = center.y() * h / oldVSize; + setContentY(contentY() + pos - center.y()); } d->updateBeginningEnd(); } diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index f8374bdbc2..2009d76677 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3253,7 +3253,7 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o) // because there can be multiple handlers... that->setAcceptedMouseButtons(Qt::AllButtons); QQuickItemPrivate *p = QQuickItemPrivate::get(that); - p->extra.value().pointerHandlers.append(pointerHandler); + p->extra.value().pointerHandlers.prepend(pointerHandler); } else { QQuickWindow *thisWindow = qmlobject_cast<QQuickWindow *>(o); QQuickItem *item = that; diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 1d0d042839..c203f389ae 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -926,7 +926,6 @@ void QQuickItemView::setDisplacedTransition(QQuickTransition *transition) void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) { - Q_Q(QQuickItemView); if (!isValid()) return; if (mode < QQuickItemView::Beginning || mode > QQuickItemView::SnapPosition) @@ -953,11 +952,16 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) item = visibleItem(idx); } if (item) { + const bool stickyHeader = hasStickyHeader(); + const bool stickyFooter = hasStickyFooter(); + const qreal stickyHeaderSize = stickyHeader ? headerSize() : 0; + const qreal stickyFooterSize = stickyFooter ? footerSize() : 0; + const qreal itemPos = item->position(); switch (mode) { case QQuickItemView::Beginning: pos = itemPos; - if (header && (index < 0 || hasStickyHeader())) + if (header && (index < 0 || stickyHeader)) pos -= headerSize(); break; case QQuickItemView::Center: @@ -965,30 +969,29 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) break; case QQuickItemView::End: pos = itemPos - viewSize + item->size(); - if (footer && (index >= modelCount || hasStickyFooter())) + if (footer && (index >= modelCount || stickyFooter)) pos += footerSize(); break; case QQuickItemView::Visible: - if (itemPos > pos + viewSize) - pos = itemPos - viewSize + item->size(); - else if (item->endPosition() <= pos) - pos = itemPos; + if (itemPos > pos + viewSize - stickyFooterSize) + pos = item->endPosition() - viewSize + stickyFooterSize; + else if (item->endPosition() <= pos - stickyHeaderSize) + pos = itemPos - stickyHeaderSize; break; case QQuickItemView::Contain: - if (item->endPosition() >= pos + viewSize) - pos = itemPos - viewSize + item->size(); - if (itemPos < pos) - pos = itemPos; + if (item->endPosition() >= pos + viewSize + stickyFooterSize) + pos = itemPos - viewSize + item->size() + stickyFooterSize; + if (itemPos - stickyHeaderSize < pos) + pos = itemPos - stickyHeaderSize; break; case QQuickItemView::SnapPosition: - pos = itemPos - highlightRangeStart; + pos = itemPos - highlightRangeStart - stickyHeaderSize; break; } pos = qMin(pos, maxExtent); qreal minExtent = calculatedMinExtent(); pos = qMax(pos, minExtent); moveReason = QQuickItemViewPrivate::Other; - q->cancelFlick(); setPosition(pos); if (highlight) { @@ -1246,16 +1249,26 @@ void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometry void QQuickItemView::destroyRemoved() { Q_D(QQuickItemView); + + bool hasRemoveTransition = false; + bool hasRemoveTransitionAsTarget = false; + if (d->transitioner) { + hasRemoveTransition = d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false); + hasRemoveTransitionAsTarget = d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true); + } + for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end();) { FxViewItem *item = *it; if (item->index == -1 && (!item->attached || item->attached->delayRemove() == false)) { - if (d->transitioner && d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) { + if (hasRemoveTransitionAsTarget) { // don't remove from visibleItems until next layout() d->runDelayedRemoveTransition = true; QObject::disconnect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved())); ++it; } else { + if (hasRemoveTransition) + d->runDelayedRemoveTransition = true; d->releaseItem(item); it = d->visibleItems.erase(it); } @@ -1384,7 +1397,6 @@ void QQuickItemView::trackedPositionChanged() pos = qMax(trackedPos, toItemPos); } if (viewPos != pos) { - cancelFlick(); d->calcVelocity = true; d->setPosition(pos); d->calcVelocity = false; @@ -1934,8 +1946,9 @@ void QQuickItemViewPrivate::layout() if (transitioner) { // items added in the last refill() may need to be transitioned in - e.g. a remove // causes items to slide up into view - if (transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, false) - || transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) { + if (lastIndexInView != -1 && + (transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, false) + || transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false))) { translateAndTransitionItemsAfter(lastIndexInView, insertionPosChanges, removalPosChanges); } @@ -1978,7 +1991,6 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult } updateUnrequestedIndexes(); - moveReason = QQuickItemViewPrivate::Other; FxViewItem *prevVisibleItemsFirst = visibleItems.count() ? *visibleItems.constBegin() : 0; int prevItemCount = itemCount; diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index c3e0ba05bd..94a5b6a646 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -896,7 +896,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic bool geometryUsesTextureSubRect = false; if (m_supportsAtlasTextures && material->textureProviders.size() == 1) { QSGTextureProvider *provider = material->textureProviders.at(0); - if (provider->texture()) { + if (provider && provider->texture()) { srcRect = provider->texture()->normalizedTextureSubRect(); geometryUsesTextureSubRect = true; } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index caae188ed8..db7a80ee9a 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -762,19 +762,18 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) auto point = pointerEventInstance(touchMouseDevice)->pointById(touchMouseId); if (point) { auto originalEvent = pointerEventInstance(point->pointerEvent()->device()); - for (int i = 0; i < originalEvent->pointCount(); ++i) - originalEvent->point(i)->cancelExclusiveGrab(); + for (int i = 0; i < originalEvent->pointCount(); ++i) { + QQuickEventPoint *pt = originalEvent->point(i); + if (pt->exclusiveGrabber()) + pt->cancelExclusiveGrab(); + } point->setGrabberItem(grabber); - for (auto handler : point->passiveGrabbers()) - point->cancelPassiveGrab(handler); } } else { QQuickPointerEvent *event = pointerEventInstance(QQuickPointerDevice::genericMouseDevice()); Q_ASSERT(event->pointCount() == 1); auto point = event->point(0); point->setGrabberItem(grabber); - for (auto handler : point->passiveGrabbers()) - point->cancelPassiveGrab(handler); } @@ -840,11 +839,12 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to bool ungrab = false; const auto touchDevices = QQuickPointerDevice::touchDevices(); for (auto device : touchDevices) { - auto pointerEvent = pointerEventInstance(device); - for (int i = 0; i < pointerEvent->pointCount(); ++i) { - if (pointerEvent->point(i)->exclusiveGrabber() == grabber) { - pointerEvent->point(i)->setGrabberItem(nullptr); - ungrab = true; + if (auto pointerEvent = queryPointerEventInstance(device)) { + for (int i = 0; i < pointerEvent->pointCount(); ++i) { + if (pointerEvent->point(i)->exclusiveGrabber() == grabber) { + pointerEvent->point(i)->setGrabberItem(nullptr); + ungrab = true; + } } } } @@ -1309,6 +1309,8 @@ QQuickWindow::~QQuickWindow() delete d->dragGrabber; d->dragGrabber = 0; #endif delete d->contentItem; d->contentItem = 0; + qDeleteAll(d->pointerEventInstances); + d->pointerEventInstances.clear(); d->renderJobMutex.lock(); qDeleteAll(d->beforeSynchronizingJobs); @@ -1510,14 +1512,15 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const Q_D(const QQuickWindow); if (d->touchMouseId != -1 && d->touchMouseDevice) { - QQuickPointerEvent *event = d->pointerEventInstance(d->touchMouseDevice); - auto point = event->pointById(d->touchMouseId); - return point ? point->grabberItem() : nullptr; + if (QQuickPointerEvent *event = d->queryPointerEventInstance(d->touchMouseDevice)) { + auto point = event->pointById(d->touchMouseId); + return point ? point->grabberItem() : nullptr; + } + } else if (QQuickPointerEvent *event = d->queryPointerEventInstance(QQuickPointerDevice::genericMouseDevice())) { + Q_ASSERT(event->pointCount()); + return event->point(0)->grabberItem(); } - - QQuickPointerEvent *event = d->pointerEventInstance(QQuickPointerDevice::genericMouseDevice()); - Q_ASSERT(event->pointCount()); - return event->point(0)->grabberItem(); + return nullptr; } @@ -1691,8 +1694,10 @@ void QQuickWindowPrivate::deliverToPassiveGrabbers(const QVector<QPointer <QQuic alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par); sendFilteredPointerEventResult << qMakePair<QQuickItem*, bool>(par, alreadyFiltered); } - if (!alreadyFiltered) + if (!alreadyFiltered) { + pointerEvent->localize(handler->parentItem()); handler->handlePointerEvent(pointerEvent); + } } } } @@ -1707,24 +1712,27 @@ void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEven if (point->exclusiveGrabber()) { if (auto grabber = point->grabberItem()) { + bool handled = false; if (sendFilteredPointerEvent(pointerEvent, grabber)) - return; + handled = true; // if the grabber is an Item: // if the update consists of changing button state, don't accept it unless // the button is one in which the grabber is interested Qt::MouseButtons acceptedButtons = grabber->acceptedMouseButtons(); - if (pointerEvent->button() != Qt::NoButton && acceptedButtons + if (!handled && pointerEvent->button() != Qt::NoButton && acceptedButtons && !(acceptedButtons & pointerEvent->button())) { pointerEvent->setAccepted(false); - return; + handled = true; } // send update - QPointF localPos = grabber->mapFromScene(lastMousePosition); - auto me = pointerEvent->asMouseEvent(localPos); - me->accept(); - QCoreApplication::sendEvent(grabber, me); - point->setAccepted(me->isAccepted()); + if (!handled) { + QPointF localPos = grabber->mapFromScene(lastMousePosition); + auto me = pointerEvent->asMouseEvent(localPos); + me->accept(); + QCoreApplication::sendEvent(grabber, me); + point->setAccepted(me->isAccepted()); + } // release event: ungrab if no buttons are pressed anymore if (mouseIsReleased) @@ -1738,6 +1746,7 @@ void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEven if (mouseIsReleased) point->setGrabberPointerHandler(nullptr, true); } + deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent); } else { bool delivered = false; if (pointerEvent->isPressEvent()) { @@ -1929,7 +1938,8 @@ bool QQuickWindowPrivate::deliverNativeGestureEvent(QQuickItem *item, QNativeGes { QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - if ((itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) && !item->contains(event->localPos())) + QPointF p = item->mapFromScene(event->windowPos()); + if ((itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) && !item->contains(p)) return false; QList<QQuickItem *> children = itemPrivate->paintOrderChildItems(); @@ -1952,7 +1962,6 @@ bool QQuickWindowPrivate::deliverNativeGestureEvent(QQuickItem *item, QNativeGes } // If still not accepted, try direct delivery to the item - QPointF p = item->mapFromScene(event->localPos()); if (item->contains(p)) { QNativeGestureEvent copy(event->gestureType(), event->device(), p, event->windowPos(), event->screenPos(), event->value(), 0L, 0L); // TODO can't copy things I can't access @@ -1973,15 +1982,16 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) qCDebug(DBG_TOUCH) << event; Q_Q(QQuickWindow); + if (q->mouseGrabberItem()) + q->mouseGrabberItem()->ungrabMouse(); + touchMouseId = -1; + touchMouseDevice = nullptr; + // A TouchCancel event will typically not contain any points. // Deliver it to all items and handlers that have active touches. QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::touchDevice(event->device())); for (int i = 0; i < pointerEvent->pointCount(); ++i) pointerEvent->point(i)->cancelExclusiveGrabImpl(event); - touchMouseId = -1; - touchMouseDevice = nullptr; - if (q->mouseGrabberItem()) - q->mouseGrabberItem()->ungrabMouse(); // The next touch event can only be a TouchBegin, so clean up. pointerEvent->clearGrabbers(); @@ -2200,7 +2210,7 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() } } -QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType) const +QQuickPointerEvent *QQuickWindowPrivate::queryPointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType) const { // Search for a matching reusable event object. for (QQuickPointerEvent *e : pointerEventInstances) { @@ -2213,9 +2223,14 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic if (e->device() == device) return e; } + return nullptr; +} - // Not found: we have to create a suitable event instance. - QQuickPointerEvent *ev = nullptr; +QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType) const +{ + QQuickPointerEvent *ev = queryPointerEventInstance(device, eventType); + if (ev) + return ev; QQuickWindow *q = const_cast<QQuickWindow*>(q_func()); switch (device->type()) { case QQuickPointerDevice::Mouse: @@ -2397,6 +2412,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event) // Deliver touch points to existing grabbers void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event) { + bool done = false; const auto grabbers = event->exclusiveGrabbers(); for (auto grabber : grabbers) { // The grabber is guaranteed to be either an item or a handler. @@ -2406,52 +2422,52 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve QQuickPointerHandler *handler = static_cast<QQuickPointerHandler *>(grabber); receiver = static_cast<QQuickPointerHandler *>(grabber)->parentItem(); if (sendFilteredPointerEvent(event, receiver)) - return; + done = true; event->localize(receiver); handler->handlePointerEvent(event); if (event->allPointsAccepted()) - return; + done = true; } + if (done) + break; // If the grabber is an item or the grabbing handler didn't handle it, // then deliver the event to the item (which may have multiple handlers). deliverMatchingPointsToItem(receiver, event); } - // If some points weren't grabbed, deliver only to non-grabber PointerHandlers - if (!event->allPointsGrabbed()) { - int pointCount = event->pointCount(); + // Deliver to each eventpoint's passive grabbers (but don't visit any handler more than once) + int pointCount = event->pointCount(); + for (int i = 0; i < pointCount; ++i) { + QQuickEventPoint *point = event->point(i); + deliverToPassiveGrabbers(point->passiveGrabbers(), event); + } + + if (done) + return; - // Deliver to each eventpoint's passive grabbers (but don't visit any handler more than once) + // If some points weren't grabbed, deliver only to non-grabber PointerHandlers in reverse paint order + if (!event->allPointsGrabbed()) { + QVector<QQuickItem *> targetItems; for (int i = 0; i < pointCount; ++i) { QQuickEventPoint *point = event->point(i); - deliverToPassiveGrabbers(point->passiveGrabbers(), event); - } - - // If some points weren't grabbed, deliver to non-grabber PointerHandlers in reverse paint order - if (!event->allPointsGrabbed()) { - QVector<QQuickItem *> targetItems; - for (int i = 0; i < pointCount; ++i) { - QQuickEventPoint *point = event->point(i); - if (point->state() == QQuickEventPoint::Pressed) - continue; // presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints - QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point->scenePosition(), false, false); - if (targetItems.count()) { - targetItems = mergePointerTargets(targetItems, targetItemsForPoint); - } else { - targetItems = targetItemsForPoint; - } - } - - for (QQuickItem *item: targetItems) { - if (grabbers.contains(item)) - continue; - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - event->localize(item); - itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers - if (event->allPointsGrabbed()) - break; + if (point->state() == QQuickEventPoint::Pressed) + continue; // presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints + QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point->scenePosition(), false, false); + if (targetItems.count()) { + targetItems = mergePointerTargets(targetItems, targetItemsForPoint); + } else { + targetItems = targetItemsForPoint; } } + for (QQuickItem *item : targetItems) { + if (grabbers.contains(item)) + continue; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + event->localize(item); + itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers + if (event->allPointsGrabbed()) + break; + } } } @@ -2490,7 +2506,7 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, continue; deliverMatchingPointsToItem(item, event, handlersOnly); if (event->allPointsAccepted()) - break; + handlersOnly = true; } return event->allPointsAccepted(); @@ -2505,8 +2521,9 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo // Let the Item's handlers (if any) have the event first. // However, double click should never be delivered to handlers. if (!pointerEvent->isDoubleClickEvent()) { + bool wasAccepted = pointerEvent->allPointsAccepted(); itemPrivate->handlePointerEvent(pointerEvent); - allowDoubleClick = !(pointerEvent->asPointerMouseEvent() && pointerEvent->isPressEvent() && pointerEvent->allPointsAccepted()); + allowDoubleClick = wasAccepted || !(pointerEvent->asPointerMouseEvent() && pointerEvent->isPressEvent() && pointerEvent->allPointsAccepted()); } if (handlersOnly) return; @@ -2818,17 +2835,10 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event // get a touch event customized for delivery to filteringParent QScopedPointer<QTouchEvent> filteringParentTouchEvent(pte->touchEventForItem(receiver, true)); if (filteringParentTouchEvent) { - QVarLengthArray<QPair<QQuickPointerHandler *, QQuickEventPoint *>, 32> passiveGrabsToCancel; if (filteringParent->childMouseEventFilter(receiver, filteringParentTouchEvent.data())) { qCDebug(DBG_TOUCH) << "touch event intercepted by childMouseEventFilter of " << filteringParent; skipDelivery.append(filteringParent); for (auto point: qAsConst(filteringParentTouchEvent->touchPoints())) { - auto pointerEventPoint = pte->pointById(point.id()); - for (auto handler : pointerEventPoint->passiveGrabbers()) { - QPair<QQuickPointerHandler *, QQuickEventPoint *> grab(handler, pointerEventPoint); - if (!passiveGrabsToCancel.contains(grab)) - passiveGrabsToCancel.append(grab); - } QQuickEventPoint *pt = event->pointById(point.id()); pt->setAccepted(); pt->setGrabberItem(filteringParent); @@ -2874,12 +2884,6 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set if (mouseEvent->isAccepted()) filteringParent->grabMouse(); - auto pointerEventPoint = pte->pointById(tp.id()); - for (auto handler : pointerEventPoint->passiveGrabbers()) { - QPair<QQuickPointerHandler *, QQuickEventPoint *> grab(handler, pointerEventPoint); - if (!passiveGrabsToCancel.contains(grab)) - passiveGrabsToCancel.append(grab); - } } filtered = true; } @@ -2895,8 +2899,6 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event } } } - for (auto grab : passiveGrabsToCancel) - grab.second->cancelPassiveGrab(grab.first); } } } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 06891406ab..87d7f63c8b 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -167,6 +167,7 @@ public: // the device-specific event instances which are reused during event delivery mutable QVector<QQuickPointerEvent *> pointerEventInstances; + QQuickPointerEvent *queryPointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType = QEvent::None) const; QQuickPointerEvent *pointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType = QEvent::None) const; // delivery of pointer events: |