27QQuickMultiPointHandler::QQuickMultiPointHandler(QQuickItem *parent,
int minimumPointCount,
int maximumPointCount)
28 : QQuickPointerDeviceHandler(*(
new QQuickMultiPointHandlerPrivate(minimumPointCount, maximumPointCount)), parent)
32bool QQuickMultiPointHandler::wantsPointerEvent(QPointerEvent *event)
34 Q_D(QQuickMultiPointHandler);
35 if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
38 if (event->type() == QEvent::Wheel)
42#if QT_CONFIG(gestures)
43 if (event->type() == QEvent::NativeGesture && event->point(0).state() != QEventPoint::Released)
54 const auto candidatePoints = eligiblePoints(event);
55 if (candidatePoints.size() != d->currentPoints.size()) {
56 d->currentPoints.clear();
60 emit centroidChanged();
62 }
else if (hasCurrentPoints(event)) {
66 ret = ret || (candidatePoints.size() >= minimumPointCount() && candidatePoints.size() <= maximumPointCount());
68 const int c = candidatePoints.size();
69 d->currentPoints.resize(c);
70 for (
int i = 0; i < c; ++i) {
71 d->currentPoints[i].reset(event, candidatePoints[i]);
72 if (
auto par = parentItem())
73 d->currentPoints[i].localize(par);
76 d->currentPoints.clear();
81void QQuickMultiPointHandler::handlePointerEventImpl(QPointerEvent *event)
83 Q_D(QQuickMultiPointHandler);
84 QQuickPointerHandler::handlePointerEventImpl(event);
88 for (QQuickHandlerPoint &p : d->currentPoints) {
89 if (
const QEventPoint *ep = event->pointById(p.id()))
92 QPointF sceneGrabPos = d->centroid.sceneGrabPosition();
93 d->centroid.reset(d->currentPoints);
94 d->centroid.m_sceneGrabPosition = sceneGrabPos;
95 emit centroidChanged();
98void QQuickMultiPointHandler::onActiveChanged()
100 Q_D(QQuickMultiPointHandler);
102 d->centroid.m_sceneGrabPosition = d->centroid.m_scenePosition;
109 d->centroid.m_pressedButtons = Qt::NoButton;
110 d->centroid.m_pressedModifiers = Qt::NoModifier;
114void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point)
116 Q_D(QQuickMultiPointHandler);
121 if (transition == QPointingDevice::UngrabExclusive || transition == QPointingDevice::CancelGrabExclusive)
122 d->currentPoints.clear();
125 switch (transition) {
126 case QPointingDevice::GrabExclusive:
127 for (
auto &pt : d->currentPoints)
128 if (pt.id() == point.id()) {
129 pt.m_sceneGrabPosition = point.scenePosition();
132 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
134 case QPointingDevice::GrabPassive:
135 case QPointingDevice::UngrabPassive:
136 case QPointingDevice::UngrabExclusive:
137 case QPointingDevice::CancelGrabPassive:
138 case QPointingDevice::CancelGrabExclusive:
139 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
141 case QPointingDevice::OverrideGrabPassive:
146QVector<QEventPoint> QQuickMultiPointHandler::eligiblePoints(QPointerEvent *event)
148 QVector<QEventPoint> ret;
151 bool stealingAllowed = event->isBeginEvent() || event->isEndEvent();
152 for (
int i = 0; i < event->pointCount(); ++i) {
153 auto &p = event->point(i);
154 if (QQuickDeliveryAgentPrivate::isMouseEvent(event)) {
155 if (
static_cast<QMouseEvent *>(event)->buttons() == Qt::NoButton)
158 if (!stealingAllowed) {
159 QObject *exclusiveGrabber = event->exclusiveGrabber(p);
160 if (exclusiveGrabber && exclusiveGrabber !=
this && !canGrab(event, p))
163 if (p.state() != QEventPoint::Released && wantsEventPoint(event, p))
188void QQuickMultiPointHandler::setMinimumPointCount(
int c)
190 Q_D(QQuickMultiPointHandler);
191 if (d->minimumPointCount == c)
194 d->minimumPointCount = c;
195 emit minimumPointCountChanged();
196 if (d->maximumPointCount < 0)
197 emit maximumPointCountChanged();
221void QQuickMultiPointHandler::setMaximumPointCount(
int maximumPointCount)
223 Q_D(QQuickMultiPointHandler);
224 if (d->maximumPointCount == maximumPointCount)
227 d->maximumPointCount = maximumPointCount;
228 emit maximumPointCountChanged();
262bool QQuickMultiPointHandler::hasCurrentPoints(QPointerEvent *event)
264 Q_D(
const QQuickMultiPointHandler);
265 if (event->pointCount() < d->currentPoints.size() || d->currentPoints.size() == 0)
269 for (
const QQuickHandlerPoint &p : std::as_const(d->currentPoints)) {
270 const QEventPoint *ep = event->pointById(p.id());
273 if (ep->state() == QEventPoint::Released)
279qreal QQuickMultiPointHandler::averageTouchPointDistance(
const QPointF &ref)
281 Q_D(
const QQuickMultiPointHandler);
283 if (Q_UNLIKELY(d->currentPoints.size() == 0))
285 for (
const QQuickHandlerPoint &p : d->currentPoints)
286 ret += QVector2D(p.scenePosition() - ref).length();
287 return ret / d->currentPoints.size();
290qreal QQuickMultiPointHandler::averageStartingDistance(
const QPointF &ref)
292 Q_D(
const QQuickMultiPointHandler);
295 if (Q_UNLIKELY(d->currentPoints.size() == 0))
297 for (
const QQuickHandlerPoint &p : d->currentPoints)
298 ret += QVector2D(p.sceneGrabPosition() - ref).length();
299 return ret / d->currentPoints.size();
302QVector<QQuickMultiPointHandler::PointData> QQuickMultiPointHandler::angles(
const QPointF &ref)
const
304 Q_D(
const QQuickMultiPointHandler);
305 QVector<PointData> angles;
306 angles.reserve(d->currentPoints.size());
307 for (
const QQuickHandlerPoint &p : d->currentPoints) {
308 qreal angle = QLineF(ref, p.scenePosition()).angle();
309 angles.append(PointData(p.id(), -angle));
314qreal QQuickMultiPointHandler::averageAngleDelta(
const QVector<PointData> &old,
const QVector<PointData> &newAngles)
316 qreal avgAngleDelta = 0;
319 auto oldBegin = old.constBegin();
321 for (PointData newData : newAngles) {
322 quint64 id = newData.id;
323 auto it = std::find_if(oldBegin, old.constEnd(), [id] (PointData pd) {
return pd.id == id; });
325 if (it != old.constEnd()) {
326 PointData oldData = *it;
331 angleD = remainder(newData.angle - oldData.angle, qreal(360));
338 avgAngleDelta += angleD;
341 avgAngleDelta /= numSamples;
343 return avgAngleDelta;
354bool QQuickMultiPointHandler::grabPoints(QPointerEvent *event,
const QVector<QEventPoint> &points)
356 if (points.isEmpty())
359 for (
auto &point : points) {
360 if (event->exclusiveGrabber(point) !=
this && !canGrab(event, point)) {
366 for (
const auto &point : std::as_const(points))
367 setExclusiveGrab(event, point);
372void QQuickMultiPointHandler::moveTarget(QPointF pos)
374 Q_D(QQuickMultiPointHandler);
375 if (QQuickItem *t = target()) {
376 d->xMetaProperty().write(t, pos.x());
377 d->yMetaProperty().write(t, pos.y());
378 d->centroid.m_position = t->mapFromScene(d->centroid.m_scenePosition);
380 qWarning() <<
"moveTarget: target is null";
384QQuickMultiPointHandlerPrivate::QQuickMultiPointHandlerPrivate(
int minPointCount,
int maxPointCount)
385 : QQuickPointerDeviceHandlerPrivate()
386 , minimumPointCount(minPointCount)
387 , maximumPointCount(maxPointCount)
391QMetaProperty &QQuickMultiPointHandlerPrivate::xMetaProperty()
const
393 Q_Q(
const QQuickMultiPointHandler);
394 if (!xProperty.isValid() && q->target()) {
395 const QMetaObject *targetMeta = q->target()->metaObject();
396 xProperty = targetMeta->property(targetMeta->indexOfProperty(
"x"));
401QMetaProperty &QQuickMultiPointHandlerPrivate::yMetaProperty()
const
403 Q_Q(
const QQuickMultiPointHandler);
404 if (!yProperty.isValid() && q->target()) {
405 const QMetaObject *targetMeta = q->target()->metaObject();
406 yProperty = targetMeta->property(targetMeta->indexOfProperty(
"y"));