Qt 4.8
qdeclarativepincharea.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
44 
45 #include <QApplication>
46 #include <QGraphicsScene>
47 
48 #include <float.h>
49 #include <math.h>
50 
52 
53 
171  : m_target(0), m_minScale(1.0), m_maxScale(1.0)
172  , m_minRotation(0.0), m_maxRotation(0.0)
173  , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
174  , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
175 {
176 }
177 
179 {
180  delete pinch;
181 }
182 
277 {
279  d->init();
280 }
281 
283 {
284 }
285 
296 {
297  Q_D(const QDeclarativePinchArea);
298  return d->absorb;
299 }
300 
302 {
304  if (a != d->absorb) {
305  d->absorb = a;
307  }
308 }
309 
311 {
313  if (!d->absorb || !isVisible())
314  return QDeclarativeItem::event(event);
315  switch (event->type()) {
316  case QEvent::TouchBegin:
317  d->touchEventsActive = true;
318  // No break, continue to next case.
319  case QEvent::TouchUpdate:
320  if (d->touchEventsActive) {
321  QTouchEvent *touch = static_cast<QTouchEvent*>(event);
322  d->touchPoints.clear();
323  for (int i = 0; i < touch->touchPoints().count(); ++i) {
324  if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
325  d->touchPoints << touch->touchPoints().at(i);
326  }
327  }
328  updatePinch();
329  return true;
330  }
331  break;
333  // No break, continue to next case.
334  case QEvent::TouchEnd:
335  d->touchEventsActive = false;
336  d->touchPoints.clear();
337  updatePinch();
338  break;
339  default:
340  return QDeclarativeItem::event(event);
341  }
342 
343  return QDeclarativeItem::event(event);
344 }
345 
347 {
349  if (d->touchPoints.count() == 0) {
350  if (d->inPinch) {
351  d->stealMouse = false;
352  setKeepMouseGrab(false);
353  d->inPinch = false;
354  QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
355  QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
356  pe.setStartCenter(d->pinchStartCenter);
357  pe.setPreviousCenter(pinchCenter);
358  pe.setPreviousAngle(d->pinchLastAngle);
359  pe.setPreviousScale(d->pinchLastScale);
360  pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
361  pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
362  pe.setPoint1(mapFromScene(d->lastPoint1));
363  pe.setPoint2(mapFromScene(d->lastPoint2));
364  emit pinchFinished(&pe);
365  d->pinchStartDist = 0;
366  d->pinchActivated = false;
367  if (d->pinch && d->pinch->target())
368  d->pinch->setActive(false);
369  }
370  return;
371  }
372  QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
373  QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
374  if (d->touchPoints.count() == 2
375  && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) {
376  d->id1 = touchPoint1.id();
377  d->sceneStartPoint1 = touchPoint1.scenePos();
378  d->sceneStartPoint2 = touchPoint2.scenePos();
379  d->inPinch = false;
380  d->pinchRejected = false;
381  d->pinchActivated = true;
382  } else if (d->pinchActivated && !d->pinchRejected) {
383  const int dragThreshold = QApplication::startDragDistance();
384  QPointF p1 = touchPoint1.scenePos();
385  QPointF p2 = touchPoint2.scenePos();
386  qreal dx = p1.x() - p2.x();
387  qreal dy = p1.y() - p2.y();
388  qreal dist = sqrt(dx*dx + dy*dy);
389  QPointF sceneCenter = (p1 + p2)/2;
390  qreal angle = QLineF(p1, p2).angle();
391  if (d->touchPoints.count() == 1) {
392  // If we only have one point then just move the center
393  if (d->id1 == touchPoint1.id())
394  sceneCenter = d->sceneLastCenter + touchPoint1.scenePos() - d->lastPoint1;
395  else
396  sceneCenter = d->sceneLastCenter + touchPoint2.scenePos() - d->lastPoint2;
397  angle = d->pinchLastAngle;
398  }
399  d->id1 = touchPoint1.id();
400  if (angle > 180)
401  angle -= 360;
402  if (!d->inPinch) {
403  if (d->touchPoints.count() >= 2
404  && (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
405  || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
406  || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
407  || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold)) {
408  d->sceneStartCenter = sceneCenter;
409  d->sceneLastCenter = sceneCenter;
410  d->pinchStartCenter = mapFromScene(sceneCenter);
411  d->pinchStartDist = dist;
412  d->pinchStartAngle = angle;
413  d->pinchLastScale = 1.0;
414  d->pinchLastAngle = angle;
415  d->pinchRotation = 0.0;
416  d->lastPoint1 = p1;
417  d->lastPoint2 = p2;
418  QDeclarativePinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
419  pe.setStartCenter(d->pinchStartCenter);
420  pe.setPreviousCenter(d->pinchStartCenter);
421  pe.setPreviousAngle(d->pinchLastAngle);
422  pe.setPreviousScale(d->pinchLastScale);
423  pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
424  pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
425  pe.setPoint1(mapFromScene(d->lastPoint1));
426  pe.setPoint2(mapFromScene(d->lastPoint2));
427  pe.setPointCount(d->touchPoints.count());
428  emit pinchStarted(&pe);
429  if (pe.accepted()) {
430  d->inPinch = true;
431  d->stealMouse = true;
432  QGraphicsScene *s = scene();
433  if (s && s->mouseGrabberItem() != this)
434  grabMouse();
435  setKeepMouseGrab(true);
436  if (d->pinch && d->pinch->target()) {
437  d->pinchStartPos = pinch()->target()->pos();
438  d->pinchStartScale = d->pinch->target()->scale();
439  d->pinchStartRotation = d->pinch->target()->rotation();
440  d->pinch->setActive(true);
441  }
442  } else {
443  d->pinchRejected = true;
444  }
445  }
446  } else if (d->pinchStartDist > 0) {
447  qreal scale = dist ? dist / d->pinchStartDist : d->pinchLastScale;
448  qreal da = d->pinchLastAngle - angle;
449  if (da > 180)
450  da -= 360;
451  else if (da < -180)
452  da += 360;
453  d->pinchRotation += da;
454  QPointF pinchCenter = mapFromScene(sceneCenter);
455  QDeclarativePinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
456  pe.setStartCenter(d->pinchStartCenter);
457  pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
458  pe.setPreviousAngle(d->pinchLastAngle);
459  pe.setPreviousScale(d->pinchLastScale);
460  pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
461  pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
462  pe.setPoint1(touchPoint1.pos());
463  pe.setPoint2(touchPoint2.pos());
464  pe.setPointCount(d->touchPoints.count());
465  d->pinchLastScale = scale;
466  d->sceneLastCenter = sceneCenter;
467  d->pinchLastAngle = angle;
468  d->lastPoint1 = touchPoint1.scenePos();
469  d->lastPoint2 = touchPoint2.scenePos();
470  emit pinchUpdated(&pe);
471  if (d->pinch && d->pinch->target()) {
472  qreal s = d->pinchStartScale * scale;
473  s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
474  pinch()->target()->setScale(s);
475  QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
476  if (pinch()->axis() & QDeclarativePinch::XAxis) {
477  qreal x = pos.x();
478  if (x < pinch()->xmin())
479  x = pinch()->xmin();
480  else if (x > pinch()->xmax())
481  x = pinch()->xmax();
482  pinch()->target()->setX(x);
483  }
484  if (pinch()->axis() & QDeclarativePinch::YAxis) {
485  qreal y = pos.y();
486  if (y < pinch()->ymin())
487  y = pinch()->ymin();
488  else if (y > pinch()->ymax())
489  y = pinch()->ymax();
490  pinch()->target()->setY(y);
491  }
492  if (d->pinchStartRotation >= pinch()->minimumRotation()
493  && d->pinchStartRotation <= pinch()->maximumRotation()) {
494  qreal r = d->pinchRotation + d->pinchStartRotation;
495  r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
496  pinch()->target()->setRotation(r);
497  }
498  }
499  }
500  }
501 }
502 
504 {
506  d->stealMouse = false;
507  if (!d->absorb)
509  else {
510  setKeepMouseGrab(false);
511  event->setAccepted(true);
512  }
513 }
514 
516 {
518  if (!d->absorb) {
520  return;
521  }
522 }
523 
525 {
527  d->stealMouse = false;
528  if (!d->absorb) {
530  } else {
531  QGraphicsScene *s = scene();
532  if (s && s->mouseGrabberItem() == this)
533  ungrabMouse();
534  setKeepMouseGrab(false);
535  }
536 }
537 
539 {
540  bool rv = QDeclarativeItem::sceneEvent(event);
541  if (event->type() == QEvent::UngrabMouse) {
542  setKeepMouseGrab(false);
543  }
544  return rv;
545 }
546 
548 {
551  QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
552 
553  QGraphicsScene *s = scene();
555  bool stealThisEvent = d->stealMouse;
556  if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
557  mouseEvent.setAccepted(false);
558  for (int i = 0x1; i <= 0x10; i <<= 1) {
559  if (event->buttons() & i) {
560  Qt::MouseButton button = Qt::MouseButton(i);
561  mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
562  }
563  }
564  mouseEvent.setScenePos(event->scenePos());
565  mouseEvent.setLastScenePos(event->lastScenePos());
566  mouseEvent.setPos(mapFromScene(event->scenePos()));
567  mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
568 
569  switch(mouseEvent.type()) {
572  break;
575  break;
578  break;
579  default:
580  break;
581  }
583  if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
584  grabMouse();
585 
586  return stealThisEvent;
587  }
589  d->stealMouse = false;
590  if (s && s->mouseGrabberItem() == this)
591  ungrabMouse();
592  setKeepMouseGrab(false);
593  }
594  return false;
595 }
596 
598 {
600  if (!d->absorb || !isVisible())
602  switch (e->type()) {
606  return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
607  break;
608  case QEvent::TouchBegin:
609  case QEvent::TouchUpdate: {
610  QTouchEvent *touch = static_cast<QTouchEvent*>(e);
611  d->touchPoints.clear();
612  for (int i = 0; i < touch->touchPoints().count(); ++i)
613  if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
614  d->touchPoints << touch->touchPoints().at(i);
615  updatePinch();
616  }
617  return d->inPinch;
618  case QEvent::TouchEnd:
619  d->touchPoints.clear();
620  updatePinch();
621  break;
622  default:
623  break;
624  }
625 
627 }
628 
630  const QRectF &oldGeometry)
631 {
632  QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
633 }
634 
636  const QVariant &value)
637 {
638  return QDeclarativeItem::itemChange(change, value);
639 }
640 
642 {
644  if (!d->pinch)
645  d->pinch = new QDeclarativePinch;
646  return d->pinch;
647 }
648 
649 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
int id() const
Returns the id number of this touch point.
Definition: qevent.cpp:4445
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items...
double qreal
Definition: qglobal.h:1193
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QDeclarativeParserStatus ** d
Qt::TouchPointState state() const
Returns the current state of this touch point.
Definition: qevent.cpp:4453
virtual bool event(QEvent *)
bool sceneEventFilter(QGraphicsItem *i, QEvent *e)
Filters events for the item watched.
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
The QGraphicsItem class is the base class for all graphical items in a QGraphicsScene.
Definition: qgraphicsitem.h:89
The QGraphicsSceneMouseEvent class provides mouse events in the graphics view framework.
bool isVisible() const
Returns true if the item is visible; otherwise, false is returned.
QPointF pos() const
Returns the position of the item in parent coordinates.
long ASN1_INTEGER_get ASN1_INTEGER * a
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
GraphicsItemChange
This enum describes the state changes that are notified by QGraphicsItem::itemChange().
void mousePressEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event event, can be reimplemented to receive mouse press events for this item...
QDeclarativePinch * pinch()
void pinchFinished(QDeclarativePinchEvent *pinch)
T * qobject_cast(QObject *object)
Definition: qobject.h:375
QPointF scenePos() const
Returns the scene position of this touch point.
Definition: qevent.cpp:4488
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event event, can be reimplemented to receive mouse press events for this item...
QGraphicsItem * mouseGrabberItem() const
Returns the current mouse grabber item, or 0 if no item is currently grabbing the mouse...
QGraphicsObject * target
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value)
Note that unlike QGraphicsItems, QDeclarativeItem::itemChange() is not called during initial widget p...
void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event event, can be reimplemented to receive mouse move events for this item...
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_D(Class)
Definition: qglobal.h:2482
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
qreal scale() const
Returns the scale factor of the item.
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
QPointF lastScenePos() const
Returns the last recorded mouse cursor position in scene coordinates.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
The QDeclarativeItem class provides the most basic of all visual items in QML.
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event event, can be reimplemented to receive mouse move events for this item...
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
qreal angle() const
Returns the angle of the line in degrees.
Definition: qline.cpp:719
static int startDragDistance()
void setX(qreal x)
Set&#39;s the x coordinate of the item&#39;s position.
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
This function is called to handle this item&#39;s changes in geometry from oldGeometry to newGeometry...
void pinchUpdated(QDeclarativePinchEvent *pinch)
bool sendMouseEvent(QGraphicsSceneMouseEvent *event)
QPointF mapFromScene(const QPointF &point) const
Maps the point point, which is in this item&#39;s scene&#39;s coordinate system, to this item&#39;s coordinate sy...
QPointF pos
the position of the item
qreal angle(const QPointF &p1, const QPointF &p2)
qreal y() const
This convenience function is equivalent to calling pos().
virtual QVariant itemChange(GraphicsItemChange, const QVariant &)
Note that unlike QGraphicsItems, QDeclarativeItem::itemChange() is not called during initial widget p...
QPointF scenePos() const
Returns the mouse cursor position in scene coordinates.
QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition: qpoint.h:376
QPointF pos() const
Returns the position of this touch point, relative to the widget or QGraphicsItem that received the e...
Definition: qevent.cpp:4473
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
qreal x() const
This convenience function is equivalent to calling pos().
void setY(qreal y)
Set&#39;s the y coordinate of the item&#39;s position.
const QList< QTouchEvent::TouchPoint > & touchPoints() const
Returns the list of touch points contained in the touch event.
Definition: qevent.h:820
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
This function is called to handle this item&#39;s changes in geometry from oldGeometry to newGeometry...
static void mouseEvent(MouseAction action, QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
Definition: qtestmouse.h:71
virtual bool sceneEvent(QEvent *)
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
The TouchPoint class provides information about a touch point in a QTouchEvent.
Definition: qevent.h:744
bool keepMouseGrab() const
Returns a value indicating whether mouse input should remain with this item exclusively.
QPointF buttonDownPos(Qt::MouseButton button) const
Returns the mouse cursor position in item coordinates where the specified button was clicked...
void setScale(qreal scale)
Sets the scale factor of the item.
The QTouchEvent class contains parameters that describe a touch event.
Definition: qevent.h:741
QGraphicsScene * scene() const
Returns the current scene for the item, or 0 if the item is not stored in a scene.
void ungrabMouse()
Releases the mouse grab.
void setRotation(qreal angle)
Sets the clockwise rotation angle, in degrees, around the Z axis.
QDeclarativePinchArea(QDeclarativeItem *parent=0)
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
Filters events for the item watched.
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
QPointF mapToScene(const QPointF &point) const
Maps the point point, which is in this item&#39;s coordinate system, to the scene&#39;s coordinate system...
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event event, can be reimplemented to receive mouse release events for this it...
void pinchStarted(QDeclarativePinchEvent *pinch)
void grabMouse()
Grabs the mouse input.
Qt::MouseButtons buttons() const
Returns the combination of mouse buttons that were pressed at the time the event was sent...
void setKeepMouseGrab(bool)
The flag indicating whether the mouse should remain with this item is set to keep.
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event event, can be reimplemented to receive mouse release events for this it...
MouseButton
Definition: qnamespace.h:150