qdeclarativepincharea.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the QtDeclarative module of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** No Commercial Usage
  11. ** This file contains pre-release code and may not be distributed.
  12. ** You may use this file in accordance with the terms and conditions
  13. ** contained in the Technology Preview License Agreement accompanying
  14. ** this package.
  15. **
  16. ** GNU Lesser General Public License Usage
  17. ** Alternatively, this file may be used under the terms of the GNU Lesser
  18. ** General Public License version 2.1 as published by the Free Software
  19. ** Foundation and appearing in the file LICENSE.LGPL included in the
  20. ** packaging of this file. Please review the following information to
  21. ** ensure the GNU Lesser General Public License version 2.1 requirements
  22. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  23. **
  24. ** In addition, as a special exception, Nokia gives you certain additional
  25. ** rights. These rights are described in the Nokia Qt LGPL Exception
  26. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  27. **
  28. ** If you have questions regarding the use of this file, please contact
  29. ** Nokia at qt-info@nokia.com.
  30. **
  31. **
  32. **
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qdeclarativepincharea.h"
  42. #include <QApplication>
  43. #include <QGraphicsScene>
  44. #include <QGraphicsSceneMouseEvent>
  45. #include <float.h>
  46. #include <math.h>
  47. QT_BEGIN_NAMESPACE
  48. QDeclarativePinch::QDeclarativePinch()
  49. : m_target(0), m_minScale(1.0), m_maxScale(1.0)
  50. , m_minRotation(0.0), m_maxRotation(0.0)
  51. , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
  52. , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
  53. {
  54. }
  55. QDeclarativePinchArea::QDeclarativePinchArea(QDeclarativeItem *parent)
  56. : QDeclarativeItem(parent), absorb(true), stealMouse(false), inPinch(false)
  57. , pinchRejected(false), pinch_(0)
  58. {
  59. setAcceptedMouseButtons(Qt::LeftButton);
  60. setAcceptTouchEvents(true);
  61. setFiltersChildEvents(true);
  62. }
  63. QDeclarativePinchArea::~QDeclarativePinchArea()
  64. {
  65. }
  66. bool QDeclarativePinchArea::isEnabled() const
  67. {
  68. return absorb;
  69. }
  70. void QDeclarativePinchArea::setEnabled(bool a)
  71. {
  72. if (a != absorb) {
  73. absorb = a;
  74. emit enabledChanged();
  75. }
  76. }
  77. bool QDeclarativePinchArea::event(QEvent *event)
  78. {
  79. if (!absorb || !isVisible())
  80. return QDeclarativeItem::event(event);
  81. switch (event->type()) {
  82. case QEvent::TouchBegin:
  83. case QEvent::TouchUpdate: {
  84. QTouchEvent *touch = static_cast<QTouchEvent*>(event);
  85. touchPoints.clear();
  86. for (int i = 0; i < touch->touchPoints().count(); ++i) {
  87. if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
  88. touchPoints << touch->touchPoints().at(i);
  89. }
  90. }
  91. updatePinch();
  92. }
  93. return true;
  94. case QEvent::TouchEnd:
  95. touchPoints.clear();
  96. updatePinch();
  97. break;
  98. default:
  99. return QDeclarativeItem::event(event);
  100. }
  101. return QDeclarativeItem::event(event);
  102. }
  103. void QDeclarativePinchArea::updatePinch()
  104. {
  105. if (touchPoints.count() != 2) {
  106. if (inPinch) {
  107. stealMouse = false;
  108. setKeepMouseGrab(false);
  109. inPinch = false;
  110. const qreal rotationAngle = pinchStartAngle - pinchLastAngle;
  111. QPointF pinchCenter = mapFromScene(sceneLastCenter);
  112. QDeclarativePinchEvent pe(pinchCenter, pinchLastScale, pinchLastAngle, rotationAngle);
  113. pe.setStartCenter(pinchStartCenter);
  114. pe.setLastCenter(pinchCenter);
  115. pe.setLastAngle(pinchLastAngle);
  116. pe.setLastScale(pinchLastScale);
  117. pe.setStartPoint1(mapFromScene(sceneStartPoint1));
  118. pe.setStartPoint2(mapFromScene(sceneStartPoint2));
  119. pe.setPoint1(lastPoint1);
  120. pe.setPoint2(lastPoint2);
  121. emit pinchFinished(&pe);
  122. if (pinch_ && pinch_->target())
  123. pinch_->setActive(false);
  124. }
  125. return;
  126. }
  127. if (touchPoints.at(0).state() & Qt::TouchPointPressed
  128. || touchPoints.at(1).state() & Qt::TouchPointPressed) {
  129. sceneStartPoint1 = touchPoints.at(0).scenePos();
  130. sceneStartPoint2 = touchPoints.at(1).scenePos();
  131. inPinch = false;
  132. pinchRejected = false;
  133. } else if (!pinchRejected){
  134. QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0;
  135. if (grabber == this || !grabber || !grabber->keepMouseGrab()) {
  136. const int dragThreshold = QApplication::startDragDistance();
  137. QPointF p1 = touchPoints.at(0).scenePos();
  138. QPointF p2 = touchPoints.at(1).scenePos();
  139. qreal dx = p1.x() - p2.x();
  140. qreal dy = p1.y() - p2.y();
  141. qreal dist = sqrt(dx*dx + dy*dy);
  142. QPointF sceneCenter = (p1 + p2)/2;
  143. qreal angle = QLineF(p1, p2).angle();
  144. if (angle > 180)
  145. angle -= 360;
  146. if (!inPinch) {
  147. if (qAbs(p1.x()-sceneStartPoint1.x()) > dragThreshold
  148. || qAbs(p1.y()-sceneStartPoint1.y()) > dragThreshold
  149. || qAbs(p2.x()-sceneStartPoint2.x()) > dragThreshold
  150. || qAbs(p2.y()-sceneStartPoint2.y()) > dragThreshold) {
  151. sceneStartCenter = sceneCenter;
  152. sceneLastCenter = sceneCenter;
  153. pinchStartCenter = mapFromScene(sceneCenter);
  154. pinchStartDist = dist;
  155. pinchStartAngle = angle;
  156. pinchLastScale = 1.0;
  157. pinchLastAngle = angle;
  158. lastPoint1 = touchPoints.at(0).pos();
  159. lastPoint2 = touchPoints.at(1).pos();
  160. QDeclarativePinchEvent pe(pinchStartCenter, 1.0, angle, 0.0);
  161. pe.setStartCenter(pinchStartCenter);
  162. pe.setLastCenter(pinchStartCenter);
  163. pe.setLastAngle(pinchLastAngle);
  164. pe.setLastScale(pinchLastScale);
  165. pe.setStartPoint1(mapFromScene(sceneStartPoint1));
  166. pe.setStartPoint2(mapFromScene(sceneStartPoint2));
  167. pe.setPoint1(lastPoint1);
  168. pe.setPoint2(lastPoint2);
  169. emit pinchStarted(&pe);
  170. if (pe.accepted()) {
  171. inPinch = true;
  172. stealMouse = true;
  173. grabMouse();
  174. setKeepMouseGrab(true);
  175. if (pinch_ && pinch_->target()) {
  176. pinchStartPos = pinch()->target()->pos();
  177. pinchStartScale = pinch()->target()->scale();
  178. pinchStartRotation = pinch()->target()->rotation();
  179. pinch_->setActive(true);
  180. }
  181. } else {
  182. pinchRejected = true;
  183. }
  184. }
  185. } else if (pinchStartDist > 0) {
  186. qreal scale = dist / pinchStartDist;
  187. qreal rotationAngle = pinchStartAngle - angle;
  188. if (rotationAngle > 180)
  189. rotationAngle -= 360;
  190. QPointF pinchCenter = mapFromScene(sceneCenter);
  191. QDeclarativePinchEvent pe(pinchCenter, scale, angle, rotationAngle);
  192. pe.setStartCenter(pinchStartCenter);
  193. pe.setLastCenter(mapFromScene(sceneLastCenter));
  194. pe.setLastAngle(pinchLastAngle);
  195. pe.setLastScale(pinchLastScale);
  196. pe.setStartPoint1(mapFromScene(sceneStartPoint1));
  197. pe.setStartPoint2(mapFromScene(sceneStartPoint2));
  198. pe.setPoint1(touchPoints.at(0).pos());
  199. pe.setPoint2(touchPoints.at(1).pos());
  200. pinchLastScale = scale;
  201. sceneLastCenter = sceneCenter;
  202. pinchLastAngle = angle;
  203. lastPoint1 = touchPoints.at(0).pos();
  204. lastPoint2 = touchPoints.at(1).pos();
  205. emit pinchChanged(&pe);
  206. if (pinch_ && pinch_->target()) {
  207. qreal s = pinchStartScale * scale;
  208. s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
  209. pinch()->target()->setScale(s);
  210. QPointF pos = sceneCenter - sceneStartCenter + pinchStartPos;
  211. if (pinch()->axis() & QDeclarativePinch::XAxis) {
  212. qreal x = pos.x();
  213. if (x < pinch()->xmin())
  214. x = pinch()->xmin();
  215. else if (x > pinch()->xmax())
  216. x = pinch()->xmax();
  217. pinch()->target()->setX(x);
  218. }
  219. if (pinch()->axis() & QDeclarativePinch::YAxis) {
  220. qreal y = pos.y();
  221. if (y < pinch()->ymin())
  222. y = pinch()->ymin();
  223. else if (y > pinch()->ymax())
  224. y = pinch()->ymax();
  225. pinch()->target()->setY(y);
  226. }
  227. if (pinchStartRotation >= pinch()->minimumRotation()
  228. && pinchStartRotation <= pinch()->maximumRotation()) {
  229. qreal r = rotationAngle + pinchStartRotation;
  230. r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
  231. pinch()->target()->setRotation(r);
  232. }
  233. }
  234. }
  235. }
  236. }
  237. }
  238. void QDeclarativePinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
  239. {
  240. stealMouse = false;
  241. if (!absorb)
  242. QDeclarativeItem::mousePressEvent(event);
  243. else {
  244. setKeepMouseGrab(false);
  245. event->setAccepted(true);
  246. }
  247. }
  248. void QDeclarativePinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
  249. {
  250. if (!absorb) {
  251. QDeclarativeItem::mouseMoveEvent(event);
  252. return;
  253. }
  254. }
  255. void QDeclarativePinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
  256. {
  257. stealMouse = false;
  258. if (!absorb) {
  259. QDeclarativeItem::mouseReleaseEvent(event);
  260. } else {
  261. QGraphicsScene *s = scene();
  262. if (s && s->mouseGrabberItem() == this)
  263. ungrabMouse();
  264. setKeepMouseGrab(false);
  265. }
  266. }
  267. bool QDeclarativePinchArea::sceneEvent(QEvent *event)
  268. {
  269. bool rv = QDeclarativeItem::sceneEvent(event);
  270. if (event->type() == QEvent::UngrabMouse) {
  271. setKeepMouseGrab(false);
  272. }
  273. return rv;
  274. }
  275. bool QDeclarativePinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
  276. {
  277. QGraphicsSceneMouseEvent mouseEvent(event->type());
  278. QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
  279. QGraphicsScene *s = scene();
  280. QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
  281. bool stealThisEvent = stealMouse;
  282. if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
  283. mouseEvent.setAccepted(false);
  284. for (int i = 0x1; i <= 0x10; i <<= 1) {
  285. if (event->buttons() & i) {
  286. Qt::MouseButton button = Qt::MouseButton(i);
  287. mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
  288. }
  289. }
  290. mouseEvent.setScenePos(event->scenePos());
  291. mouseEvent.setLastScenePos(event->lastScenePos());
  292. mouseEvent.setPos(mapFromScene(event->scenePos()));
  293. mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
  294. switch(mouseEvent.type()) {
  295. case QEvent::GraphicsSceneMouseMove:
  296. mouseMoveEvent(&mouseEvent);
  297. break;
  298. case QEvent::GraphicsSceneMousePress:
  299. qDebug() << "mouse press";
  300. mousePressEvent(&mouseEvent);
  301. break;
  302. case QEvent::GraphicsSceneMouseRelease:
  303. mouseReleaseEvent(&mouseEvent);
  304. break;
  305. default:
  306. break;
  307. }
  308. grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
  309. if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
  310. grabMouse();
  311. return stealThisEvent;
  312. }
  313. if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
  314. stealMouse = false;
  315. if (s && s->mouseGrabberItem() == this)
  316. ungrabMouse();
  317. setKeepMouseGrab(false);
  318. }
  319. return false;
  320. }
  321. bool QDeclarativePinchArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
  322. {
  323. if (!absorb || !isVisible())
  324. return QDeclarativeItem::sceneEventFilter(i, e);
  325. switch (e->type()) {
  326. case QEvent::GraphicsSceneMousePress:
  327. case QEvent::GraphicsSceneMouseMove:
  328. case QEvent::GraphicsSceneMouseRelease:
  329. return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
  330. break;
  331. case QEvent::TouchBegin:
  332. case QEvent::TouchUpdate: {
  333. QTouchEvent *touch = static_cast<QTouchEvent*>(e);
  334. touchPoints.clear();
  335. for (int i = 0; i < touch->touchPoints().count(); ++i)
  336. if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
  337. touchPoints << touch->touchPoints().at(i);
  338. updatePinch();
  339. }
  340. return inPinch;
  341. case QEvent::TouchEnd:
  342. touchPoints.clear();
  343. updatePinch();
  344. break;
  345. default:
  346. break;
  347. }
  348. return QDeclarativeItem::sceneEventFilter(i, e);
  349. }
  350. void QDeclarativePinchArea::geometryChanged(const QRectF &newGeometry,
  351. const QRectF &oldGeometry)
  352. {
  353. QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
  354. }
  355. QVariant QDeclarativePinchArea::itemChange(GraphicsItemChange change,
  356. const QVariant &value)
  357. {
  358. return QDeclarativeItem::itemChange(change, value);
  359. }
  360. QDeclarativePinch *QDeclarativePinchArea::pinch()
  361. {
  362. if (!pinch_)
  363. pinch_ = new QDeclarativePinch;
  364. return pinch_;
  365. }
  366. QT_END_NAMESPACE