0.2 version add desktop components multitouch, joystick, multicast
[mardrone] / mardrone / qdeclarativetoucharea.cpp
diff --git a/mardrone/qdeclarativetoucharea.cpp b/mardrone/qdeclarativetoucharea.cpp
new file mode 100644 (file)
index 0000000..34e5992
--- /dev/null
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QML Touch Area plugin of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qdeclarativetoucharea.h"
+#include <QEvent>
+#include <QGraphicsScene>
+#include <QGraphicsSceneMouseEvent>
+#include <QDeclarativeExpression>
+#include <QDeclarativeInfo>
+#include <math.h>
+
+
+void
+QDeclarativeTouchArea::registerQML()
+{
+    qmlRegisterType<QDeclarativeTouchArea>("TouchArea", 1, 0, "TouchArea");
+    qmlRegisterType<QDeclarativeTouchPoint>("TouchArea", 1, 0, "TouchPoint");
+}
+
+QDeclarativeTouchArea::QDeclarativeTouchArea(QDeclarativeItem *parent)
+    : QDeclarativeItem(parent),
+      _minimumTouches(0),
+      _maximumTouches(INT_MAX),
+      _scaleFactor(1.0),
+      _rotationAngle(0.0),
+      _parentTouchArea(this),
+      _active(false),
+      _stealMouse(false)
+{
+    setAcceptTouchEvents(true);
+    setAcceptedMouseButtons(Qt::LeftButton);
+    setFiltersChildEvents(true);
+}
+
+void QDeclarativeTouchArea::updateTopTouchArea() {
+    for (QDeclarativeItem* pItem = parentItem(); pItem != 0; pItem = pItem->parentItem()) {
+        if (QDeclarativeTouchArea* ta = qobject_cast<QDeclarativeTouchArea*>(pItem)) {
+            _parentTouchArea = ta;
+            break;
+        }
+    }
+}
+
+QDeclarativeTouchArea::~QDeclarativeTouchArea() {
+}
+
+bool QDeclarativeTouchArea::sceneEvent(QEvent *event) {
+    bool rv = false;
+    switch (event->type()) {
+    case QEvent::TouchBegin:
+        updateTopTouchArea();
+        if (_parentTouchArea != this) {
+            if (_active || !_parentTouchArea->_active) {
+                _active = true;
+                _parentTouchArea->_active = true;
+                updateTouchData(event);
+                rv = true;
+            }
+        } else {
+            updateTouchData(event);
+            rv = true;
+        }
+        break;
+    case QEvent::TouchUpdate:
+        updateTouchData(event);
+        rv = true;
+        break;
+    case QEvent::TouchEnd: {
+        updateTouchData(event);
+        if (_parentTouchArea != this) {
+            if (_touches.empty()) {
+                _active = false;
+                _parentTouchArea->_active = false;
+            }
+        }
+        rv = true;
+        break;
+    }
+    default:
+        break;
+    }
+
+    if (!rv)
+        rv = QDeclarativeItem::sceneEvent(event);
+    if (event->type() == QEvent::UngrabMouse) {
+        setKeepMouseGrab(false);
+    }
+    return rv;
+}
+
+void QDeclarativeTouchArea::updateTouchData(QEvent *event) {
+    bool ended = false;
+    bool moved = false;
+    bool started = false;
+
+    QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0;
+    QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
+    if (grabber == this || !grabber || !grabber->keepMouseGrab() || touchGrabber) {
+        if (_stealMouse && (grabber != this || !grabber->keepMouseGrab())) {
+            grabMouse();
+            setKeepMouseGrab(true);
+        }
+
+        if (!_keepMouseFocus.script().isEmpty()) {
+            QDeclarativeExpression expr(_keepMouseFocus.context(), _keepMouseFocus.scopeObject(), _keepMouseFocus.script());
+            QVariant result = expr.evaluate();
+            if (expr.hasError())
+                qmlInfo(this) << expr.error();
+            else
+                _stealMouse = true;
+        }
+    }
+
+    QTouchEvent *e = static_cast<QTouchEvent*>(event);
+    clearChangedAndReleasedTouches();
+
+    QList<QTouchEvent::TouchPoint> touchPoints = e->touchPoints();
+    int numTouchPoints = touchPoints.count();
+    if (numTouchPoints >= _minimumTouches && numTouchPoints <= _maximumTouches) {
+        foreach (QTouchEvent::TouchPoint p, touchPoints) {
+            Qt::TouchPointState touchPointState = p.state();
+            int id = p.id();
+            if (touchPointState & Qt::TouchPointReleased) {
+                QDeclarativeTouchPoint* dtp = static_cast<QDeclarativeTouchPoint*>(_touches[id]);
+                _changedTouches.insert(id,dtp);
+                _releasedTouches.append(dtp);
+                _touches.remove(id);
+                ended = true;
+            } else if (touchPointState & Qt::TouchPointMoved) {
+                updateTouchPoint(static_cast<QDeclarativeTouchPoint*>(_touches[id]),&p);
+                updatePinch(&touchPoints);
+                moved = true;
+            } else if (!_touches.contains(id)) {
+                    addTouchPoint(&p);
+                    started = true;
+            }
+        }
+        if (moved) emit(touchMove());
+        if (ended) emit(touchEnd());
+        if (started) emit(touchStart());
+    }
+    event->accept();
+}
+
+void QDeclarativeTouchArea::clearChangedAndReleasedTouches() {
+    foreach (QObject *p, _releasedTouches) {
+        QDeclarativeTouchPoint* dtp = static_cast<QDeclarativeTouchPoint*>(p);
+        if (!dtp->isQmlReferenced())
+            delete dtp;
+        else
+            dtp->setValid(false);
+    }
+    _changedTouches.clear();
+    _releasedTouches.clear();
+}
+
+void QDeclarativeTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) {
+    QDeclarativeTouchPoint *dtp = 0;
+    foreach (QObject* proto, _touchPrototypes) {
+        QDeclarativeTouchPoint* tp = static_cast<QDeclarativeTouchPoint*>(proto);
+        if (!tp->isValid()) {
+            tp->setValid(true);
+            dtp = tp;
+            break;
+        }
+    }
+
+    if (dtp == 0)
+        dtp = new QDeclarativeTouchPoint(false);
+    dtp->setId(p->id());
+    updateTouchPoint(dtp,p);
+    _touches.insert(p->id(),dtp);
+}
+
+void QDeclarativeTouchArea::addTouchPrototype(QDeclarativeTouchPoint *prototype) {
+    int id = _touchPrototypes.count();
+    prototype->setId(id);
+    _touchPrototypes.insert(id, prototype);
+}
+
+void QDeclarativeTouchArea::updateTouchPoint(QDeclarativeTouchPoint *dtp, const QTouchEvent::TouchPoint *p) {
+    dtp->setX(p->pos().x());
+    dtp->setY(p->pos().y());
+    dtp->setSceneX(p->scenePos().x());
+    dtp->setSceneY(p->scenePos().y());
+    _changedTouches.insert(dtp->id(),dtp);
+}
+
+void QDeclarativeTouchArea::updatePinch(QList<QTouchEvent::TouchPoint> *touchPoints) {
+    if (touchPoints->count()==2) {
+        QTouchEvent::TouchPoint tp1 = touchPoints->at(0);
+        QTouchEvent::TouchPoint tp2 = touchPoints->at(1);
+
+        QPointF tp1LastPos = tp1.lastPos();
+        QPointF tp2LastPos = tp2.lastPos();
+        QPointF tp1Pos = tp1.pos();
+        QPointF tp2Pos = tp2.pos();
+
+        QPointF deltaA = tp1LastPos - tp2LastPos;
+        QPointF deltaB = tp1Pos - tp2Pos;
+
+        qreal distanceA = sqrt(pow(deltaA.x(),2.0)+pow(deltaA.y(),2.0));
+        qreal distanceB = sqrt(pow(deltaB.x(),2.0)+pow(deltaB.y(),2.0));
+
+        if (distanceA != 0 && distanceB != 0) {
+            _scaleFactor*=(distanceB/distanceA);
+            emit(scaleFactorChanged());
+        }
+
+        QLineF lineA(tp1LastPos, tp2LastPos);
+        QLineF lineB(tp1Pos,tp2Pos);
+        _rotationAngle-=lineA.angleTo(lineB);
+        emit(rotationAngleChanged());
+    }
+
+}
+
+bool QDeclarativeTouchArea::event(QEvent *event)
+{
+    switch (event->type()) {
+    case QEvent::TouchBegin:
+    case QEvent::TouchUpdate: {
+            updateTouchData(event);
+        }
+        return true;
+    case QEvent::TouchEnd: {
+            updateTouchData(event);
+            _stealMouse = false;
+            QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
+            if (touchGrabber == this)
+                ungrabMouse();
+            setKeepMouseGrab(false);
+        }
+        return true;
+    default:
+        return QDeclarativeItem::event(event);
+    }
+
+    return QDeclarativeItem::event(event);
+}
+
+bool QDeclarativeTouchArea::sceneEventFilter(QGraphicsItem *i, QEvent *event)
+{
+    if (!isVisible())
+        return QDeclarativeItem::sceneEventFilter(i, event);
+    switch (event->type()) {
+    case QEvent::TouchBegin:
+    case QEvent::TouchUpdate:
+            updateTouchData(event);
+        return true;
+    case QEvent::TouchEnd: {
+            updateTouchData(event);
+            _stealMouse = false;
+            QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
+            if (touchGrabber == this)
+                ungrabMouse();
+            setKeepMouseGrab(false);
+        }
+        return true;
+    default:
+        break;
+    }
+    return QDeclarativeItem::sceneEventFilter(i, event);
+}
+