569void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints remap)
573 bool started =
false;
576 QList<QEventPoint> touchPoints;
577 bool touchPointsFromEvent =
false;
578 QPointingDevice *dev =
nullptr;
580 switch (event->type()) {
581 case QEvent::TouchBegin:
582 case QEvent::TouchUpdate:
583 case QEvent::TouchEnd: {
584 QTouchEvent* te =
static_cast<QTouchEvent*>(event);
585 touchPoints = te->points();
586 touchPointsFromEvent =
true;
587 dev =
const_cast<QPointingDevice *>(te->pointingDevice());
590 case QEvent::MouseButtonPress: {
591 auto da = QQuickItemPrivate::get(
this)->deliveryAgentPrivate();
592 _mouseQpaTouchPoint = QEventPoint(da->touchMouseId);
593 _touchMouseDevice = da->touchMouseDevice;
596 case QEvent::MouseMove:
597 case QEvent::MouseButtonRelease: {
598 QMouseEvent *me =
static_cast<QMouseEvent*>(event);
599 _mouseQpaTouchPoint = me->points().first();
600 dev =
const_cast<QPointingDevice *>(me->pointingDevice());
601 if (event->type() == QEvent::MouseButtonPress) {
605 touchPoints << _mouseQpaTouchPoint;
609 qWarning(
"updateTouchData: unhandled event type %d", event->type());
613 int numTouchPoints = touchPoints.size();
615 for (
const QEventPoint &p : std::as_const(touchPoints)) {
616 QEventPoint::State touchPointState = p.state();
618 if (touchPointState & QEventPoint::State::Released) {
619 QQuickTouchPoint* dtp =
static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
622 updateTouchPoint(dtp, &p);
623 dtp->setPressed(
false);
624 _releasedTouchPoints.append(dtp);
625 _touchPoints.remove(id);
629 if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) {
630 for (QEventPoint &p : touchPoints) {
631 QPointF oldPos = p.position();
632 auto transformBack = qScopeGuard([&] { QMutableEventPoint::setPosition(p, oldPos); });
633 if (touchPointsFromEvent && remap == RemapEventPoints::ToLocal)
634 QMutableEventPoint::setPosition(p, mapFromScene(p.scenePosition()));
635 QEventPoint::State touchPointState = p.state();
637 if (touchPointState & QEventPoint::State::Released) {
639 }
else if (!_touchPoints.contains(id)) {
643 }
else if ((touchPointState & QEventPoint::State::Updated) ||
644 (touchPointState & QEventPoint::State::Stationary)) {
646 QQuickTouchPoint* dtp =
static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
648 _movedTouchPoints.append(dtp);
649 updateTouchPoint(dtp,&p);
652 QQuickTouchPoint* dtp =
static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
654 updateTouchPoint(dtp,&p);
660 bool offerGrab =
false;
661 const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
666 const auto overThreshold = [dragThreshold](qreal delta) {
667 return qAbs(delta) > dragThreshold
668 && !qFuzzyCompare(qAbs(delta), qreal(dragThreshold));
671 for (
const QEventPoint &p : std::as_const(touchPoints)) {
672 if (p.state() == QEventPoint::State::Released)
674 const QPointF currentPos = mapFromScene(p.scenePosition());
675 const QPointF startPos = mapFromScene(p.scenePressPosition());
676 if (overThreshold(currentPos.x() - startPos.x()))
678 else if (overThreshold(currentPos.y() - startPos.y()))
685 QQuickGrabGestureEvent event;
686 event._touchPoints = _touchPoints.values();
687 emit gestureStarted(&event);
688 if (event.wantsGrab() && dev)
694 emit released(_releasedTouchPoints);
696 emit updated(_movedTouchPoints);
697 if (started && !_pressedTouchPoints.isEmpty())
698 emit pressed(_pressedTouchPoints);
699 if (ended || moved || started) emit touchUpdated(_touchPoints.values());
798void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp,
const QEventPoint *p)
802 dtp->setUniqueId(p->uniqueId());
803 dtp->setPosition(p->position());
804 dtp->setEllipseDiameters(p->ellipseDiameters());
805 dtp->setPressure(p->pressure());
806 dtp->setRotation(p->rotation());
807 dtp->setVelocity(p->velocity());
808 QRectF area(QPointF(), p->ellipseDiameters());
809 area.moveCenter(p->position());
812 if (p->state() == QEventPoint::State::Pressed) {
816 dtp->setStartX(p->position().x());
817 dtp->setStartY(p->position().y());
819 dtp->setPreviousX(p->lastPosition().x());
820 dtp->setPreviousY(p->lastPosition().y());
821 dtp->setSceneX(p->scenePosition().x());
822 dtp->setSceneY(p->scenePosition().y());
825void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp,
const QMouseEvent *e)
827 dtp->setPreviousX(dtp->x());
828 dtp->setPreviousY(dtp->y());
829 dtp->setPosition(e->position());
830 if (e->type() == QEvent::MouseButtonPress) {
831 dtp->setStartX(e->position().x());
832 dtp->setStartY(e->position().y());
834 dtp->setSceneX(e->scenePosition().x());
835 dtp->setSceneY(e->scenePosition().y());
928bool QQuickMultiPointTouchArea::sendMouseEvent(QMouseEvent *event)
930 const QPointF localPos = mapFromScene(event->scenePosition());
932 QQuickWindow *c = window();
933 QQuickItem *grabber = c ? c->mouseGrabberItem() :
nullptr;
934 bool stealThisEvent = _stealMouse;
935 if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
936 QMutableSinglePointEvent mouseEvent(*event);
937 const auto oldPosition = mouseEvent.position();
938 QMutableEventPoint::setPosition(mouseEvent.point(0), localPos);
939 mouseEvent.setSource(Qt::MouseEventSynthesizedByQt);
940 mouseEvent.setAccepted(
false);
941 QMouseEvent *pmouseEvent =
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&mouseEvent));
943 switch (mouseEvent.type()) {
944 case QEvent::MouseMove:
945 mouseMoveEvent(pmouseEvent);
947 case QEvent::MouseButtonPress:
948 mousePressEvent(pmouseEvent);
950 case QEvent::MouseButtonRelease:
951 mouseReleaseEvent(pmouseEvent);
956 grabber = c ? c->mouseGrabberItem() :
nullptr;
957 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber !=
this)
960 QMutableEventPoint::setPosition(mouseEvent.point(0), oldPosition);
961 return stealThisEvent;
963 if (event->type() == QEvent::MouseButtonRelease) {
965 if (c && c->mouseGrabberItem() ==
this)
967 setKeepMouseGrab(
false);
972bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEvent *event)
974 if (!isEnabled() || !isVisible())
975 return QQuickItem::childMouseEventFilter(receiver, event);
976 switch (event->type()) {
977 case QEvent::MouseButtonPress: {
978 auto da = QQuickItemPrivate::get(
this)->deliveryAgentPrivate();
981 if (
static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventSynthesizedByQt &&
982 _lastFilterableTouchPointIds.contains(da->touchMouseId))
985 case QEvent::MouseMove:
986 case QEvent::MouseButtonRelease:
987 return sendMouseEvent(
static_cast<QMouseEvent *>(event));
988 case QEvent::TouchBegin:
989 _lastFilterableTouchPointIds.clear();
991 case QEvent::TouchUpdate:
992 for (
const auto &tp :
static_cast<QTouchEvent*>(event)->points()) {
993 if (tp.state() == QEventPoint::State::Pressed)
994 _lastFilterableTouchPointIds << tp.id();
996 if (!shouldFilter(event))
998 updateTouchData(event, RemapEventPoints::ToLocal);
1000 case QEvent::TouchEnd: {
1001 if (!shouldFilter(event))
1003 updateTouchData(event, RemapEventPoints::ToLocal);
1010 return QQuickItem::childMouseEventFilter(receiver, event);
1013bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event)
1015 QQuickWindow *c = window();
1016 QQuickItem *grabber = c ? c->mouseGrabberItem() :
nullptr;
1017 bool disabledItem = grabber && !grabber->isEnabled();
1018 bool stealThisEvent = _stealMouse;
1019 bool containsPoint =
false;
1020 if (!stealThisEvent) {
1021 switch (event->type()) {
1022 case QEvent::MouseButtonPress:
1023 case QEvent::MouseMove:
1024 case QEvent::MouseButtonRelease: {
1025 QMouseEvent *me =
static_cast<QMouseEvent*>(event);
1026 containsPoint = contains(mapFromScene(me->scenePosition()));
1029 case QEvent::TouchBegin:
1030 case QEvent::TouchUpdate:
1031 case QEvent::TouchEnd: {
1032 QTouchEvent *te =
static_cast<QTouchEvent*>(event);
1033 for (
const QEventPoint &point : te->points()) {
1034 if (contains(mapFromScene(point.scenePosition()))) {
1035 containsPoint =
true;
1045 if ((stealThisEvent || containsPoint) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
1052QSGNode *QQuickMultiPointTouchArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1056 if (!qmlMptaVisualTouchDebugging())
1059 QSGInternalRectangleNode *rectangle =
static_cast<QSGInternalRectangleNode *>(oldNode);
1060 if (!rectangle) rectangle = QQuickItemPrivate::get(
this)->sceneGraphContext()->createInternalRectangleNode();
1062 rectangle->setRect(QRectF(0, 0, width(), height()));
1063 rectangle->setColor(QColor(255, 0, 0, 50));
1064 rectangle->update();