33QQuickMultiPointHandler::QQuickMultiPointHandler(QQuickItem *parent,
int minimumPointCount,
int maximumPointCount)
34 : QQuickPointerDeviceHandler(*(
new QQuickMultiPointHandlerPrivate(minimumPointCount, maximumPointCount)), parent)
38bool QQuickMultiPointHandler::wantsPointerEvent(QPointerEvent *event)
40 Q_D(QQuickMultiPointHandler);
41 if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
44 if (event->type() == QEvent::Wheel)
48#if QT_CONFIG(gestures)
49 if (event->type() == QEvent::NativeGesture && event->point(0).state() != QEventPoint::Released)
60 const auto candidatePoints = eligiblePoints(event);
61 if (candidatePoints.size() != d->currentPoints.size()) {
62 d->currentPoints.clear();
66 emit centroidChanged();
68 }
else if (hasCurrentPoints(event)) {
72 ret = ret || (candidatePoints.size() >= minimumPointCount() && candidatePoints.size() <= maximumPointCount());
74 const int c = candidatePoints.size();
75 d->currentPoints.resize(c);
76 for (
int i = 0; i < c; ++i) {
77 d->currentPoints[i].reset(event, candidatePoints[i]);
78 if (
auto par = parentItem())
79 d->currentPoints[i].localize(par);
82 d->currentPoints.clear();
87void QQuickMultiPointHandler::handlePointerEventImpl(QPointerEvent *event)
89 Q_D(QQuickMultiPointHandler);
90 QQuickPointerHandler::handlePointerEventImpl(event);
94 for (QQuickHandlerPoint &p : d->currentPoints) {
95 if (
const QEventPoint *ep = event->pointById(p.id()))
98 QPointF sceneGrabPos = d->centroid.sceneGrabPosition();
99 d->centroid.reset(d->currentPoints);
100 d->centroid.m_sceneGrabPosition = sceneGrabPos;
101 emit centroidChanged();
104void QQuickMultiPointHandler::onActiveChanged()
106 Q_D(QQuickMultiPointHandler);
108 d->centroid.m_sceneGrabPosition = d->centroid.m_scenePosition;
115 d->centroid.m_pressedButtons = Qt::NoButton;
116 d->centroid.m_pressedModifiers = Qt::NoModifier;
120void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point)
122 Q_D(QQuickMultiPointHandler);
127 if (transition == QPointingDevice::UngrabExclusive || transition == QPointingDevice::CancelGrabExclusive)
128 d->currentPoints.clear();
131 switch (transition) {
132 case QPointingDevice::GrabExclusive:
133 for (
auto &pt : d->currentPoints)
134 if (pt.id() == point.id()) {
135 pt.m_sceneGrabPosition = point.scenePosition();
138 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
140 case QPointingDevice::GrabPassive:
141 case QPointingDevice::UngrabPassive:
142 case QPointingDevice::UngrabExclusive:
143 case QPointingDevice::CancelGrabPassive:
144 case QPointingDevice::CancelGrabExclusive:
145 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
147 case QPointingDevice::OverrideGrabPassive:
152QVector<QEventPoint> QQuickMultiPointHandler::eligiblePoints(QPointerEvent *event)
154 QVector<QEventPoint> ret;
157 bool stealingAllowed = event->isBeginEvent() || event->isEndEvent();
158 for (
int i = 0; i < event->pointCount(); ++i) {
159 auto &p = event->point(i);
160 if (QQuickDeliveryAgentPrivate::isMouseEvent(event)) {
161 if (
static_cast<QMouseEvent *>(event)->buttons() == Qt::NoButton)
164 if (!stealingAllowed) {
165 QObject *exclusiveGrabber = event->exclusiveGrabber(p);
166 if (exclusiveGrabber && exclusiveGrabber !=
this && !canGrab(event, p))
169 if (p.state() != QEventPoint::Released && wantsEventPoint(event, p))
194void QQuickMultiPointHandler::setMinimumPointCount(
int c)
196 Q_D(QQuickMultiPointHandler);
197 if (d->minimumPointCount == c)
200 d->minimumPointCount = c;
201 emit minimumPointCountChanged();
202 if (d->maximumPointCount < 0)
203 emit maximumPointCountChanged();
227void QQuickMultiPointHandler::setMaximumPointCount(
int maximumPointCount)
229 Q_D(QQuickMultiPointHandler);
230 if (d->maximumPointCount == maximumPointCount)
233 d->maximumPointCount = maximumPointCount;
234 emit maximumPointCountChanged();
268bool QQuickMultiPointHandler::hasCurrentPoints(QPointerEvent *event)
270 Q_D(
const QQuickMultiPointHandler);
271 if (event->pointCount() < d->currentPoints.size() || d->currentPoints.size() == 0)
275 for (
const QQuickHandlerPoint &p : std::as_const(d->currentPoints)) {
276 const QEventPoint *ep = event->pointById(p.id());
279 if (ep->state() == QEventPoint::Released)
285qreal QQuickMultiPointHandler::averageTouchPointDistance(
const QPointF &ref)
287 Q_D(
const QQuickMultiPointHandler);
289 if (Q_UNLIKELY(d->currentPoints.size() == 0))
291 for (
const QQuickHandlerPoint &p : d->currentPoints)
292 ret += QVector2D(p.scenePosition() - ref).length();
293 return ret / d->currentPoints.size();
296qreal QQuickMultiPointHandler::averageStartingDistance(
const QPointF &ref)
298 Q_D(
const QQuickMultiPointHandler);
301 if (Q_UNLIKELY(d->currentPoints.size() == 0))
303 for (
const QQuickHandlerPoint &p : d->currentPoints)
304 ret += QVector2D(p.sceneGrabPosition() - ref).length();
305 return ret / d->currentPoints.size();
308QVector<QQuickMultiPointHandler::PointData> QQuickMultiPointHandler::angles(
const QPointF &ref)
const
310 Q_D(
const QQuickMultiPointHandler);
311 QVector<PointData> angles;
312 angles.reserve(d->currentPoints.size());
313 for (
const QQuickHandlerPoint &p : d->currentPoints) {
314 qreal angle = QLineF(ref, p.scenePosition()).angle();
315 angles.append(PointData(p.id(), -angle));
320qreal QQuickMultiPointHandler::averageAngleDelta(
const QVector<PointData> &old,
const QVector<PointData> &newAngles)
322 qreal avgAngleDelta = 0;
325 auto oldBegin = old.constBegin();
327 for (PointData newData : newAngles) {
328 quint64 id = newData.id;
329 auto it = std::find_if(oldBegin, old.constEnd(), [id] (PointData pd) {
return pd.id == id; });
331 if (it != old.constEnd()) {
332 PointData oldData = *it;
337 angleD = remainder(newData.angle - oldData.angle, qreal(360));
344 avgAngleDelta += angleD;
347 avgAngleDelta /= numSamples;
349 return avgAngleDelta;
360bool QQuickMultiPointHandler::grabPoints(QPointerEvent *event,
const QVector<QEventPoint> &points)
362 if (points.isEmpty())
365 for (
auto &point : points) {
366 if (event->exclusiveGrabber(point) !=
this && !canGrab(event, point)) {
372 for (
const auto &point : std::as_const(points))
373 setExclusiveGrab(event, point);
378void QQuickMultiPointHandler::moveTarget(QPointF pos)
380 Q_D(QQuickMultiPointHandler);
381 if (QQuickItem *t = target()) {
382 d->xMetaProperty().write(t, pos.x());
383 d->yMetaProperty().write(t, pos.y());
384 d->centroid.m_position = t->mapFromScene(d->centroid.m_scenePosition);
386 qWarning() <<
"moveTarget: target is null";
390QQuickMultiPointHandlerPrivate::QQuickMultiPointHandlerPrivate(
int minPointCount,
int maxPointCount)
391 : QQuickPointerDeviceHandlerPrivate()
392 , minimumPointCount(minPointCount)
393 , maximumPointCount(maxPointCount)
397QMetaProperty &QQuickMultiPointHandlerPrivate::xMetaProperty()
const
399 Q_Q(
const QQuickMultiPointHandler);
400 if (!xProperty.isValid() && q->target()) {
401 const QMetaObject *targetMeta = q->target()->metaObject();
402 xProperty = targetMeta->property(targetMeta->indexOfProperty(
"x"));
407QMetaProperty &QQuickMultiPointHandlerPrivate::yMetaProperty()
const
409 Q_Q(
const QQuickMultiPointHandler);
410 if (!yProperty.isValid() && q->target()) {
411 const QMetaObject *targetMeta = q->target()->metaObject();
412 yProperty = targetMeta->property(targetMeta->indexOfProperty(
"y"));