summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/imports/location/location.cpp1
-rw-r--r--src/imports/location/location.pro7
-rw-r--r--src/imports/location/qdeclarativegeomap.cpp30
-rw-r--r--src/imports/location/qdeclarativegeomap_p.h5
-rw-r--r--src/imports/location/qdeclarativegeomapflickable.cpp352
-rw-r--r--src/imports/location/qdeclarativegeomapflickable_p.h49
-rw-r--r--src/imports/location/qdeclarativegeomapgesturearea.cpp1407
-rw-r--r--src/imports/location/qdeclarativegeomapgesturearea_p.h365
-rw-r--r--src/imports/location/qdeclarativegeomappincharea.cpp499
-rw-r--r--src/imports/location/qdeclarativegeomappincharea_p.h209
-rw-r--r--src/src.pro1
11 files changed, 1927 insertions, 998 deletions
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp
index acf84429..015ec3dc 100644
--- a/src/imports/location/location.cpp
+++ b/src/imports/location/location.cpp
@@ -136,6 +136,7 @@ public:
qmlRegisterUncreatableType<QDeclarativeGeoMapFlickable>(uri, 5, 0, "MapFlickable", QDeclarativeGeoMapFlickable::tr("(Map)Flickable is not intended instantiable by developer."));
qmlRegisterUncreatableType<QDeclarativeGeoMapPinchArea>(uri, 5, 0, "MapPinchArea", QDeclarativeGeoMapPinchArea::tr("(Map)PinchArea is not intended instantiable by developer."));
qmlRegisterUncreatableType<QDeclarativeGeoMapPinchEvent>(uri, 5, 0, "MapPinchEvent", QDeclarativeGeoMapPinchEvent::tr("(Map)PinchEvent is not intended instantiable by developer."));
+ qmlRegisterUncreatableType<QDeclarativeGeoMapGestureArea>(uri, 5, 0, "MapGestureArea", QDeclarativeGeoMapGestureArea::tr("(Map)GestureArea is not intended instantiable by developer."));
qmlRegisterUncreatableType<QDeclarativeGeoMapType>(uri, 5, 0, "MapType",QDeclarativeGeoMapType::tr("MapType is not intended instantiable by developer."));
qmlRegisterType<QDeclarativeCategory>(uri, 5, 0, "Category");
qmlRegisterType<QDeclarativePlaceEditorialModel>(uri, 5, 0, "EditorialModel");
diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro
index 189058bc..f17ce858 100644
--- a/src/imports/location/location.pro
+++ b/src/imports/location/location.pro
@@ -10,6 +10,7 @@ target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
INCLUDEPATH += ../../location/maps
INCLUDEPATH *= $$PWD
+DEFINES += TOUCH_EVENT_WORKAROUND
# On some platforms, build both versions because debug and release
# versions are incompatible
@@ -45,7 +46,8 @@ HEADERS += qdeclarativeposition_p.h \
qdeclarativepolylinemapitem_p.h \
qdeclarativeroutemapitem_p.h \
qgeomapitemgeometry_p.h \
- qdeclarativegeomapcopyrightsnotice_p.h
+ qdeclarativegeomapcopyrightsnotice_p.h \
+ qdeclarativegeomapgesturearea_p.h
SOURCES += qdeclarativeposition.cpp \
location.cpp \
@@ -78,7 +80,8 @@ SOURCES += qdeclarativeposition.cpp \
qdeclarativepolylinemapitem.cpp \
qdeclarativeroutemapitem.cpp \
qgeomapitemgeometry.cpp \
- qdeclarativegeomapcopyrightsnotice.cpp
+ qdeclarativegeomapcopyrightsnotice.cpp \
+ qdeclarativegeomapgesturearea.cpp
include(declarativeplaces/declarativeplaces.pri)
diff --git a/src/imports/location/qdeclarativegeomap.cpp b/src/imports/location/qdeclarativegeomap.cpp
index 9b8473d4..e5d38555 100644
--- a/src/imports/location/qdeclarativegeomap.cpp
+++ b/src/imports/location/qdeclarativegeomap.cpp
@@ -207,8 +207,9 @@ QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
connect(this, SIGNAL(childrenChanged()), this, SLOT(onMapChildrenChanged()), Qt::QueuedConnection);
// Create internal flickable and pinch area.
- flickable_ = new QDeclarativeGeoMapFlickable(this);
- pinchArea_ = new QDeclarativeGeoMapPinchArea(this, this);
+ gestureArea_ = new QDeclarativeGeoMapGestureArea(this, this);
+ flickable_ = new QDeclarativeGeoMapFlickable(this, gestureArea_);
+ pinchArea_ = new QDeclarativeGeoMapPinchArea(this, gestureArea_);
}
QDeclarativeGeoMap::~QDeclarativeGeoMap()
@@ -344,21 +345,36 @@ bool QDeclarativeGeoMap::mouseEvent(QMouseEvent* event)
return false;
switch (event->type()) {
case QEvent::MouseButtonPress:
- return flickable_->mousePressEvent(event);
+ return gestureArea_->mousePressEvent(event);
case QEvent::MouseButtonRelease:
- return flickable_->mouseReleaseEvent(event);
+ return gestureArea_->mouseReleaseEvent(event);
case QEvent::MouseMove:
- return flickable_->mouseMoveEvent(event);
+ return gestureArea_->mouseMoveEvent(event);
default:
return false;
}
}
+
+/*!
+ \qmlproperty MapPinchArea QtLocation5::Map::gesture
+
+ Contains the MapGestureArea created with the Map. This covers pan, flick and pinch gestures.
+ Use \c{gesture.enabled: true} to enable basic gestures, or see \l{MapGestureArea} for
+ further details.
+*/
+
+QDeclarativeGeoMapGestureArea* QDeclarativeGeoMap::gesture()
+{
+ return gestureArea_;
+}
+
/*!
\qmlproperty MapPinchArea QtLocation5::Map::pinch
Contains the MapPinchArea created with the Map. Use \c{pinch.enabled: true}
to enable basic pinch gestures, or see \l{MapPinchArea} for further details.
+ This object will be deprecated, use the gesture object instead.
*/
QDeclarativeGeoMapPinchArea* QDeclarativeGeoMap::pinch()
@@ -371,6 +387,7 @@ QDeclarativeGeoMapPinchArea* QDeclarativeGeoMap::pinch()
Contains the MapFlickable created with the Map. Use \c{flick.enabled: true}
to enable basic flick gestures, or see \l{MapFlickable} for further details.
+ This object will be deprecated, use the gesture object instead.
*/
QDeclarativeGeoMapFlickable* QDeclarativeGeoMap::flick()
@@ -486,6 +503,7 @@ void QDeclarativeGeoMap::mappingManagerInitialized()
map_->setActiveMapType(QGeoMapType());
flickable_->setMap(map_);
+ pinchArea_->setMap(map_);
copyrightsWPtr_ = new QDeclarativeGeoMapCopyrightNotice(this);
connect(map_,
@@ -967,7 +985,7 @@ void QDeclarativeGeoMap::touchEvent(QTouchEvent *event)
}
QLOC_TRACE0;
event->accept();
- pinchArea_->touchEvent(event);
+ gestureArea_->touchEvent(event);
}
/*!
diff --git a/src/imports/location/qdeclarativegeomap_p.h b/src/imports/location/qdeclarativegeomap_p.h
index cf44ee95..b95b3dc3 100644
--- a/src/imports/location/qdeclarativegeomap_p.h
+++ b/src/imports/location/qdeclarativegeomap_p.h
@@ -53,6 +53,7 @@
#include <QtQuick/QQuickPaintedItem>
#include <QtQml/QQmlParserStatus>
#include "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapgesturearea_p.h"
#include "qdeclarativegeomapflickable_p.h"
#include "qdeclarativegeomappincharea_p.h"
#include "qgeomapcontroller_p.h"
@@ -100,6 +101,7 @@ class QDeclarativeGeoMap : public QQuickItem
{
Q_OBJECT
+ Q_PROPERTY(QDeclarativeGeoMapGestureArea* gesture READ gesture CONSTANT)
Q_PROPERTY(QDeclarativeGeoMapPinchArea* pinch READ pinch CONSTANT)
Q_PROPERTY(QDeclarativeGeoMapFlickable* flick READ flick CONSTANT)
Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
@@ -166,6 +168,7 @@ public:
bool mouseEvent(QMouseEvent* event);
QDeclarativeGeoMapPinchArea* pinch();
+ QDeclarativeGeoMapGestureArea* gesture();
Q_INVOKABLE void fitViewportToMapItems();
@@ -227,6 +230,7 @@ private:
bool mappingManagerInitialized_;
QList<QDeclarativeGeoMapItemView*> mapViews_;
+ QDeclarativeGeoMapGestureArea* gestureArea_;
QDeclarativeGeoMapFlickable* flickable_;
QDeclarativeGeoMapPinchArea* pinchArea_;
@@ -246,6 +250,7 @@ private:
QMutex updateMutex_;
friend class QDeclarativeGeoMapItem;
friend class QDeclarativeGeoMapItemView;
+ friend class QDeclarativeGeoMapGestureArea;
friend class QDeclarativeGeoMapPinchArea;
friend class QDeclarativeGeoMapFlickable;
Q_DISABLE_COPY(QDeclarativeGeoMap)
diff --git a/src/imports/location/qdeclarativegeomapflickable.cpp b/src/imports/location/qdeclarativegeomapflickable.cpp
index 78e6a3b0..5a5650ab 100644
--- a/src/imports/location/qdeclarativegeomapflickable.cpp
+++ b/src/imports/location/qdeclarativegeomapflickable.cpp
@@ -40,33 +40,9 @@
****************************************************************************/
#include <QtGui/QGuiApplication>
-#include <QtGui/QStyleHints>
-#include <QPropertyAnimation>
-#include <QEasingCurve>
#include "qdeclarativegeomapflickable_p.h"
-#include "qgeomapcontroller_p.h"
-#include <QTimer>
-#include "qgeomap_p.h"
-#include "math.h"
-
-#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
-#define QML_MAP_FLICK_MINIMUMDECELERATION 500
-#define QML_MAP_FLICK_DEFAULTDECELERATION 2500
-#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000
-// The number of samples to use in calculating the velocity of a flick
-#define QML_MAP_FLICK_SAMPLEBUFFER 3
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#define QML_MAP_FLICK_DISCARDSAMPLES 1
-
-// FlickThreshold determines how far the "mouse" must have moved
-// before we perform a flick.
-static const int FlickThreshold = 20;
-// RetainGrabVelocity is the maxmimum instantaneous velocity that
-// will ensure the Flickable retains the grab on consecutive flicks.
-static const int RetainGrabVelocity = 15;
-// Really slow flicks can be annoying.
-const qreal MinimumFlickVelocity = 75.0;
+#include "qdeclarativegeomapgesturearea_p.h"
+
QT_BEGIN_NAMESPACE
@@ -171,334 +147,18 @@ QT_BEGIN_NAMESPACE
The order of onMovementEnded() and onFlickEnded() is not specified.
*/
-QDeclarativeGeoMapFlickable::QDeclarativeGeoMapFlickable(QObject *parent)
+QDeclarativeGeoMapFlickable::QDeclarativeGeoMapFlickable(QObject *parent,
+ QDeclarativeGeoMapGestureArea *gestureArea)
: QObject(parent),
- pressed_(false),
- maxVelocity_(QML_MAP_FLICK_DEFAULTMAXVELOCITY),
- deceleration_(QML_MAP_FLICK_DEFAULTDECELERATION),
- velocityX_(0.0),
- velocityY_(0.0),
- flicking_(false),
- map_(0),
- animation_(0),
- enabled_(true),
- moving_(false)
+ gestureArea_(gestureArea)
{
- pressTime_.invalidate();
- lastPosTime_.invalidate();
- velocityTime_.invalidate();
+ gestureArea_->registerFlickDeprecated(this);
}
QDeclarativeGeoMapFlickable::~QDeclarativeGeoMapFlickable()
{
}
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::setMap(QGeoMap* map)
-{
- if (map_ || !map)
- return;
- map_ = map;
- animation_ = new QPropertyAnimation(map_->mapController(), "center", this);
- animation_->setEasingCurve(QEasingCurve(QEasingCurve::OutQuad));
- connect(animation_, SIGNAL(finished()), this, SLOT(flickAnimationFinished()));
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapFlickable::deceleration() const
-{
- return deceleration_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::setDeceleration(qreal deceleration)
-{
- if (deceleration < QML_MAP_FLICK_MINIMUMDECELERATION)
- deceleration = QML_MAP_FLICK_MINIMUMDECELERATION;
- else if (deceleration > QML_MAP_FLICK_MAXIMUMDECELERATION)
- deceleration = QML_MAP_FLICK_MAXIMUMDECELERATION;
- if (deceleration == deceleration_)
- return;
- deceleration_ = deceleration;
- emit decelerationChanged();
-}
-
-/*!
- \internal
-*/
-bool QDeclarativeGeoMapFlickable::mousePressEvent(QMouseEvent *event)
-{
- if (!enabled_)
- return false;
- stop();
- pressed_ = true;
- lastPos_ = QPointF();
- pressPos_ = event->pos();
- lastPosTime_.start();
- pressTime_.start();
- velocityTime_.start();
- return true;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::stop()
-{
- velocityBufferX_.clear();
- velocityBufferY_.clear();
- velocityX_ = 0.0;
- velocityY_ = 0.0;
- if (moving_) {
- moving_ = false;
- emit movementEnded();
- }
- if (flicking_) {
- flicking_ = false;
- if (animation_->state() == QPropertyAnimation::Running)
- animation_->stop();
- emit flickEnded();
- }
- lastPosTime_.invalidate();
- pressTime_.invalidate();
- velocityTime_.invalidate();
-}
-
-/*!
- \internal
-*/
-bool QDeclarativeGeoMapFlickable::mouseMoveEvent(QMouseEvent *event)
-{
- if (!enabled_ || !pressed_ || !lastPosTime_.isValid())
- return false;
- // Check if thresholds for normal panning are met.
- // (normal panning vs flicking: flicking will start from mouse release event).
- int dyFromPress = int(event->pos().y() - pressPos_.y());
- int dxFromPress = int(event->pos().x() - pressPos_.x());
- int dyFromLastPos;
- int dxFromLastPos;
- if (!lastPos_.isNull()) {
- dyFromLastPos = event->pos().y() - lastPos_.y();
- dxFromLastPos = event->pos().x() - lastPos_.x();
- }
-
- // Simple pan (drag) while being pressed
- const int startDragDistance = qApp->styleHints()->startDragDistance();
- if ((qAbs(dyFromPress) > startDragDistance
- || qAbs(dxFromPress) > startDragDistance
- || pressTime_.elapsed() > 200) && !lastPos_.isNull()) {
-
- if (!moving_) {
- moving_ = true;
- emit movementStarted();
- }
- updateCamera(dxFromLastPos, dyFromLastPos, 0);
- }
- // Take velocity samples, used later to determine the flick
- // duration and speed (when mouse is released).
- if (!lastPos_.isNull()) {
- qreal elapsed = qreal(lastPosTime_.elapsed()) / 1000.;
- if (elapsed <= 0) {
- lastPos_ = event->pos();
- return false;
- }
- lastPosTime_.restart();
- addVelocitySample(velocityBufferY_, double(dyFromLastPos)/elapsed);
- addVelocitySample(velocityBufferX_, double(dxFromLastPos)/elapsed);
- }
- lastPos_ = event->pos();
- return true;
-}
-
-/*!
- \internal
-*/
-// FIXME:
-// - not left right / up down flicking, so if map is rotated, will act unintuitively
-void QDeclarativeGeoMapFlickable::updateCamera(int dx, int dy, int timeMs)
-{
- if (timeMs < 0)
- return;
- AnimatableCoordinate animationStartCoordinate = map_->mapController()->center();
- QGeoCoordinate coordinate = animationStartCoordinate.coordinate();
- if (timeMs == 0) {
- // No animation, just set new values.
- QPointF p = map_->coordinateToScreenPosition(coordinate);
- p.setY(p.y() - dy);
- p.setX(p.x() - dx);
- animationStartCoordinate.setCoordinate(map_->screenPositionToCoordinate(p));
- map_->mapController()->setCenter(animationStartCoordinate);
- } else {
- //qDebug() << "Will do flick animation dx (pix), dy (pix), time (ms): " << dx << dy << timeMs;
- if (animation_->state() == QPropertyAnimation::Running)
- animation_->stop();
- AnimatableCoordinate animationEndCoordinate = map_->mapController()->center();
- animation_->setDuration(timeMs);
- coordinate.setLongitude(coordinate.longitude() - (dx / pow(2.0, map_->mapController()->zoom())));
- coordinate.setLatitude(coordinate.latitude() + (dy / pow(2.0, map_->mapController()->zoom())));
- animationEndCoordinate.setCoordinate(coordinate);
- animation_->setStartValue(QVariant::fromValue(animationStartCoordinate));
- animation_->setEndValue(QVariant::fromValue(animationEndCoordinate));
- //qDebug() << "The latitude will go from:" << animationStartCoordinate.coordinate().latitude() << "to:" << animationEndCoordinate.coordinate().latitude();
- //qDebug() << "The longitude will go from:" << animationStartCoordinate.coordinate().longitude() << "to:" << animationEndCoordinate.coordinate().longitude();
- // start animation straight away, user may disable the flick in the flickStarted() handler
- animation_->start();
- flicking_ = true;
- emit flickStarted();
- }
-}
-
-/*!
- \internal
- Adds velocity sample to sample buffer. Data is later used to calculate
- flick speed. By default 3 latest samples are considered.
-*/
-void QDeclarativeGeoMapFlickable::addVelocitySample(QVector<qreal>& buffer, qreal sample)
-{
- if (sample > maxVelocity_)
- sample = maxVelocity_;
- else if (sample < -maxVelocity_)
- sample = -maxVelocity_;
- buffer.append(sample);
- if (buffer.count() > QML_MAP_FLICK_SAMPLEBUFFER)
- buffer.remove(0);
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::updateVelocity(QVector<qreal>& buffer, qreal& velocity)
-{
- if (buffer.count() > QML_MAP_FLICK_DISCARDSAMPLES) {
- velocity = 0;
- int count = buffer.count() - QML_MAP_FLICK_DISCARDSAMPLES;
- for (int i = 0; i < count; ++i) {
- qreal v = buffer.at(i);
- velocity += v;
- }
- velocity /= count;
- }
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::setEnabled(bool enabled)
-{
- if (enabled_ == enabled)
- return;
- enabled_ = enabled;
- if (!enabled_)
- stop();
- emit enabledChanged();
-}
-
-/*!
- \internal
-*/
-bool QDeclarativeGeoMapFlickable::enabled() const
-{
- return enabled_;
-}
-
-/*!
- \internal
-*/
-bool QDeclarativeGeoMapFlickable::mouseReleaseEvent(QMouseEvent *event)
-{
- if (!pressed_ || !enabled_)
- return false;
- pressed_ = false;
-
- // if we drag then pause before release we should not cause a flick.
- if (lastPosTime_.elapsed() < 100) {
- updateVelocity(velocityBufferY_, velocityY_);
- updateVelocity(velocityBufferX_, velocityX_);
- } else {
- velocityX_ = 0.0;
- velocityY_ = 0.0;
- }
- int flickTimeY = 0;
- int flickTimeX = 0;
- int flickPixelsX = 0;
- int flickPixelsY = 0;
- if (qAbs(velocityY_) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos_.y()) > FlickThreshold) {
- // calculate Y flick animation values
- qreal acceleration = deceleration_;
- if ((velocityY_ > 0.0f) == (deceleration_ > 0.0f))
- acceleration = acceleration * -1.0f;
- flickTimeY = static_cast<int>(-1000 * velocityY_ / acceleration);
- flickPixelsY = (flickTimeY * velocityY_) / (1000.0 * 2);
- //qDebug() << "---=== would flick Y, velocity (pix/sec), flick duration (msec): ===---" << velocityY_ << flickTimeY;
- } else {
- // reset
- //qDebug() << "---=== would NOT flick Y, velocity (pix/sec): ===---" << velocityY_;
- }
- if (qAbs(velocityX_) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos_.x()) > FlickThreshold) {
- // calculate X flick animation values
- qreal acceleration = deceleration_;
- if ((velocityX_ > 0.0f) == (deceleration_ > 0.0f))
- acceleration = acceleration * -1.0f;
- flickTimeX = static_cast<int>(-1000 * velocityX_ / acceleration);
- flickPixelsX = (flickTimeX * velocityX_) / (1000.0 * 2);
- //qDebug() << "---=== would flick X, velocity (pix/sec), flick duration (msec), pixels: ===---" << velocityX_ << flickTimeX << "pixels: " << flickPixelsX;
- } else {
- // reset
- //qDebug() << "---=== would NOT flick X, velocity (pix/sec) ===---" << velocityX_;
- }
- int flickTime = qMax(flickTimeY, flickTimeX);
- updateCamera(flickPixelsX, flickPixelsY, flickTime);
-
- if (flickTime == 0 && moving_) {
- emit movementEnded();
- moving_ = false;
- }
- velocityBufferX_.clear();
- velocityBufferY_.clear();
- velocityX_ = 0.0;
- velocityY_ = 0.0;
- lastPosTime_.invalidate();
- pressTime_.invalidate();
- velocityTime_.invalidate();
- return true;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::flickAnimationFinished()
-{
- //qDebug() << metaObject()->className() << __FUNCTION__;
- //Q_ASSERT(flicking_);
- //Q_ASSERT(moving_);
- flicking_ = false;
- moving_ = false;
- emit flickEnded();
- emit movementEnded();
-}
-
-/*
-void QDeclarativeGeoMapFlickable::flickAnimationValueChanged(const QVariant& value)
-{
- qDebug() << metaObject()->className() << __FUNCTION__;
-}
-*/
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapFlickable::timerEvent(QTimerEvent *event)
-{
- Q_UNUSED(event); // TODO press delay handling
- //qDebug() << metaObject()->className() << __FUNCTION__ ;
-}
-
#include "moc_qdeclarativegeomapflickable_p.cpp"
QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomapflickable_p.h b/src/imports/location/qdeclarativegeomapflickable_p.h
index 1e6ba57f..f5e581e6 100644
--- a/src/imports/location/qdeclarativegeomapflickable_p.h
+++ b/src/imports/location/qdeclarativegeomapflickable_p.h
@@ -49,6 +49,7 @@
#include <QVector>
#include <QObject>
#include <QDebug>
+#include "qdeclarativegeomapgesturearea_p.h"
QT_BEGIN_NAMESPACE
@@ -57,6 +58,8 @@ class QPropertyAnimation;
class QGeoCameraData;
class QGeoMap;
+// Note: this class will be deprecated in future versions, it remains as a wrapper
+// Please use the gesture object instead.
class QDeclarativeGeoMapFlickable: public QObject
{
Q_OBJECT
@@ -64,59 +67,27 @@ class QDeclarativeGeoMapFlickable: public QObject
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged())
public:
- QDeclarativeGeoMapFlickable(QObject *parent = 0);
+ QDeclarativeGeoMapFlickable(QObject *parent, QDeclarativeGeoMapGestureArea *gestureArea_);
~QDeclarativeGeoMapFlickable();
- qreal deceleration() const;
- void setDeceleration(qreal deceleration);
+ qreal deceleration() const { return gestureArea_->flickDeceleration(); }
+ void setDeceleration(qreal deceleration){ gestureArea_->setFlickDeceleration(deceleration); }
- bool enabled() const;
- void setEnabled(bool enabled);
+ bool enabled() const { return gestureArea_->panEnabled(); }
+ void setEnabled(bool enabled){ gestureArea_->setPanEnabled(enabled); }
- void setMap(QGeoMap* map);
-
- bool mousePressEvent(QMouseEvent *event);
- bool mouseMoveEvent(QMouseEvent *event);
- bool mouseReleaseEvent(QMouseEvent *event);
- virtual void timerEvent(QTimerEvent *event);
+ void setMap(QGeoMap* map){ gestureArea_->setMap(map); }
signals:
void decelerationChanged();
void enabledChanged();
- // public (documented) signals:
void movementStarted();
void movementEnded();
void flickStarted();
void flickEnded();
private:
- void addVelocitySample(QVector<qreal>& buffer, qreal sample);
- void updateVelocity(QVector<qreal>& buffer, qreal& velocity);
- void updateCamera(int dx, int dy, int timeMs = 0);
- void stop();
-
-private slots:
- void flickAnimationFinished();
- //void flickAnimationValueChanged(const QVariant&);
-
-private:
- bool pressed_;
- qreal maxVelocity_;
- qreal deceleration_;
- QElapsedTimer lastPosTime_;
- QElapsedTimer pressTime_;
- QElapsedTimer velocityTime_;
- QVector<qreal> velocityBufferX_;
- qreal velocityX_;
- QVector<qreal> velocityBufferY_;
- qreal velocityY_;
- QPointF lastPos_;
- QPointF pressPos_;
- bool flicking_;
- QGeoMap* map_;
- QPropertyAnimation* animation_;
- bool enabled_;
- bool moving_;
+ QDeclarativeGeoMapGestureArea *gestureArea_; // the destination for this wrapper class
};
QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomapgesturearea.cpp b/src/imports/location/qdeclarativegeomapgesturearea.cpp
new file mode 100644
index 00000000..43b392ec
--- /dev/null
+++ b/src/imports/location/qdeclarativegeomapgesturearea.cpp
@@ -0,0 +1,1407 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include "qdeclarativegeomapgesturearea_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "qdeclarativecoordinate_p.h"
+#include <QtGui/qevent.h>
+#include <QtGui/QStyleHints>
+#include <QtQml/qqmlinfo.h>
+#include <QPropertyAnimation>
+#include <QDebug>
+#include "math.h"
+#include "qgeomap_p.h"
+
+#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
+#define QML_MAP_FLICK_MINIMUMDECELERATION 500
+#define QML_MAP_FLICK_DEFAULTDECELERATION 2500
+#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000
+// The number of samples to use in calculating the velocity of a flick
+#define QML_MAP_FLICK_SAMPLEBUFFER 3
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#define QML_MAP_FLICK_DISCARDSAMPLES 1
+
+// FlickThreshold determines how far the "mouse" must have moved
+// before we perform a flick.
+static const int FlickThreshold = 20;
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \qmlclass MapPinchEvent
+ \inqmlmodule QtLocation 5
+
+ \brief MapPinchEvent element provides basic information about pinch event.
+
+ MapPinchEvent element provides basic information about pinch event. They are
+ present in handlers of MapPinch (for example pinchStarted/pinchUpdated). Events are only
+ guaranteed to be valid for the duration of the handler.
+
+ Except for the \l accepted property, all properties are read-only.
+
+ \section2 Example Usage
+
+ The following example enables the pinch gesture on a map and reacts to the
+ finished event.
+
+ \code
+ Map {
+ id: map
+ gesture.enabled: true
+ gesture.onPinchFinished:{
+ var coordinate1 = map.toCoordinate(gesture.point1)
+ var coordinate2 = map.toCoordinate(gesture.point2)
+ console.log("Pinch started at:")
+ console.log(" Points (" + gesture.point1.x + ", " + gesture.point1.y + ") - (" + gesture.point2.x + ", " + gesture.point2.y + ")")
+ console.log(" Coordinates (" + coordinate1.latitude + ", " + coordinate1.longitude + ") - (" + coordinate2.latitude + ", " + coordinate2.longitude + ")")
+ }
+ }
+ \endcode
+
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+*/
+
+/*!
+ \qmlproperty QPoint QtLocation5::MapPinchEvent::center
+
+ This read-only property holds the current center point.
+*/
+
+/*!
+ \qmlproperty real QtLocation5::MapPinchEvent::angle
+
+ This read-only property holds the current angle between the two points in
+ the range -180 to 180. Positive values for the angles mean counter-clockwise
+ while negative values mean the clockwise direction. Zero degrees is at the
+ 3 o'clock position.
+*/
+
+/*!
+ \qmlproperty QPoint QtLocation5::MapPinchEvent::point1
+ \qmlproperty QPoint QtLocation5::MapPinchEvent::point2
+
+ These read-only properties hold the actual touch points generating the pinch.
+ The points are not in any particular order.
+*/
+
+/*!
+ \qmlproperty int QtLocation5::MapPinchEvent::pointCount
+
+ This read-only property holds the number of points currently touched.
+ The MapPinch will not react until two touch points have initiated a gesture,
+ but will remain active until all touch points have been released.
+*/
+
+/*!
+ \qmlproperty bool QtLocation5::MapPinchEvent::accepted
+
+ Setting this property to false in the \c MapPinch::onPinchStarted handler
+ will result in no further pinch events being generated, and the gesture
+ ignored.
+*/
+
+/*!
+ \qmlclass MapGestureArea QDeclarativeGeoMapGestureArea
+
+ \inqmlmodule QtLocation 5
+
+ \brief The MapGestureArea element provides Map gesture interaction.
+
+ MapGestureArea elements are used as part of a Map, to provide for panning,
+ flicking and pinch-to-zoom gesture used on touch displays.
+
+ A MapGestureArea is automatically created with a new Map and available with
+ the \l{QtLocation5::Map::pinch}{pinch} property. This is the only way
+ to create a MapGestureArea, and once created this way cannot be destroyed
+ without its parent Map.
+
+ The two most commonly used properties of the MapGestureArea are the \l enabled
+ and \l activeGestures properties. Both of these must be set before a
+ MapGestureArea will have any effect upon interaction with the Map.
+ The \l flickDeceleration property controls how quickly the map pan slows after contact
+ is released while panning the map.
+
+ \section2 Performance
+
+ The MapGestureArea, when enabled, must process all incoming touch events in
+ order to track the shape and size of the "pinch". The overhead added on
+ touch events can be considered constant time.
+
+ \section2 Example Usage
+
+ The following example enables the zoom and pan gestures on the map, but not flicking. So the
+ map scrolling will halt immediately on releasing the mouse button / touch.
+
+ \code
+ Map {
+ gesture.enabled: true
+ gesture.activeGestures: MapGestureArea.ZoomGesture | MapGestureArea.PanGesture
+ }
+ \endcode
+
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+*/
+
+/*!
+ \qmlproperty bool QtLocation5::MapGestureArea::enabled
+
+ This property holds whether the gestures are enabled.
+ Note: disabling gestures during an active gesture does not have effect on
+ the potentially active current gesture.
+*/
+
+
+/*!
+ \qmlproperty bool QtLocation5::MapGestureArea::panEnabled
+
+ This property holds whether the pan gestures are enabled.
+ Note: disabling gestures during an active gesture does not have effect on
+ the potentially active current gesture.
+*/
+
+/*!
+ \qmlproperty bool QtLocation5::MapGestureArea::pinchEnabled
+
+ This property holds whether the pinch gestures are enabled.
+ Note: disabling gestures during an active gesture does not have effect on
+ the potentially active current gesture.
+*/
+
+/*!
+ \qmlproperty bool QtLocation5::MapGestureArea::isPinchActive
+
+ This read-only property holds whether any pinch gesture is active.
+*/
+
+/*!
+ \qmlproperty bool QtLocation5::MapGestureArea::isPanActive
+
+ This read-only property holds whether any pan gesture (panning or flicking) is active.
+*/
+
+/*!
+ \qmlproperty enumeration QtLocation5::MapGestureArea::activeGestures
+
+ This property holds the gestures that will be active. By default
+ the zoom, pan and flick gestures are enabled.
+
+ \list
+ \li GestureArea.NoGesture - Don't support any additional gestures (value: 0x0000).
+ \li GestureArea.ZoomGesture - Support the map zoom gesture (value: 0x0001).
+ \li GestureArea.RotationGesture - Support the map rotation gesture (value: 0x0002).
+ \li GestureArea.TiltGesture - Support the map tilt gesture (value: 0x0004).
+ \li GestureArea.PanGesture - Support the map pan gesture (value: 0x0008).
+ \li GestureArea.FlickGesture - Support the map flick gesture (value: 0x0010).
+ \endlist
+
+ For the extremist, one may OR flag the RotationGesture or TiltGesture
+ but these come with absolutely no warranty or guarantees at the moment
+ (may be removed, changed, moved around)
+
+ \note For the time being, only \l GestureArea.ZoomGesture is supported.
+*/
+
+/*!
+ \qmlproperty real QtLocation5::MapGestureArea::maximumZoomLevelChange
+
+ This property holds the maximum zoom level change per pinch, essentially
+ meant to be used for setting the zoom sensitivity.
+
+ It is an indicative measure calculated from the dimensions of the
+ map area, roughly corresponding how much zoom level could change with
+ maximum pinch zoom. Default value is 2.0, maximum value is 10.0
+*/
+
+/*!
+ \qmlproperty real MapGestureArea::rotationFactor
+
+ This property holds the rotation factor for zoom, essentially meant to be used for setting
+ the rotation sensitivity.
+
+ It is an indicative measure; the default value 1.0 means the map roughly follows the fingers,
+ whereas 2.0 means rotating twice as fast. Maximum value is 5.0.
+*/
+
+/*!
+ \qmlsignal void QtLocation5::MapGestureArea::pinchStarted(PinchEvent event)
+
+ Raised when a pinch gesture is started.
+
+ \sa pinchUpdated pinchFinished
+*/
+
+/*!
+ \qmlsignal void QtLocation5::MapGestureArea::pinchUpdated(PinchEvent event)
+
+ Once a pinch has begun this event gets raised as the user moves her fingers
+ across the map.
+
+ \sa pinchStarted pinchFinished
+*/
+
+/*!
+ \qmlsignal void QtLocation5::MapGestureArea::pinchUpdated(PinchEvent event)
+
+ The end of a pinch gesture is signaled by this event.
+
+ \sa pinchUpdated pinchFinished
+*/
+
+/*!
+ \qmlsignal QtLocation5::MapFlickable::panStarted()
+
+ This handler is called when the view begins moving due to user
+ interaction. Typically this means that the user is dragging a finger -
+ or a mouse with one of more mouse buttons pressed - on the map.
+*/
+
+/*!
+ \qmlsignal QtLocation5::MapFlickable::panFinished()
+
+ This handler is called when the view stops moving due to user
+ interaction. If a flick was generated, this handler will
+ be triggered once the flick stops. If a flick was not
+ generated, the handler will be triggered when the
+ user stops dragging - that is a mouse or touch release.
+
+*/
+
+/*!
+ \qmlsignal QtLocation5::MapFlickable::flickStarted()
+
+ This handler is called when the view is flicked. A flick
+ starts from the point that the mouse or touch is released,
+ while still in motion.
+*/
+
+/*!
+ \qmlsignal QtLocation5::MapFlickable::flickFinished()
+
+ This handler is called when the view stops moving due to a flick.
+ The order of panFinished() and flickFinished() is not specified.
+*/
+
+
+QDeclarativeGeoMapGestureArea::QDeclarativeGeoMapGestureArea(QDeclarativeGeoMap* map, QObject *parent)
+ : QObject(parent),
+ declarativeMap_(map),
+ enabled_(true),
+ pinchEnabled_(true),
+ minimumZoomLevel_(-1.0),
+ maximumZoomLevel_(-1.0),
+ minimumRotation_(0.0),
+ maximumRotation_(0.0),
+ pinchStartDist_(0),
+ pinchStartZoomLevel_(0.0),
+ pinchLastZoomLevel_(0.0),
+ pinchStartRotation_(0.0),
+ pinchLastAngle_(0.0),
+ pinchRotation_(0.0),
+ maximumZoomLevelChange_(2.0),
+ rotationFactor_(1.0),
+ minimumTilt_(0.0),
+ maximumTilt_(90.0),
+ maximumTiltChange_(20.0),
+ pinchLastTilt_(0.0),
+ pinchStartTilt_(0.0),
+ activeGestures_(ZoomGesture | PanGesture | FlickGesture)
+{
+ map_ = 0;
+ pan_.enabled_ = true,
+ pan_.maxVelocity_ = QML_MAP_FLICK_DEFAULTMAXVELOCITY;
+ pan_.deceleration_ = QML_MAP_FLICK_DEFAULTDECELERATION;
+ pan_.animation_ = 0;
+#if defined(TOUCH_EVENT_WORKAROUND)
+ mouseBeingUsed_ = true;
+#endif
+ touchPointState_ = touchPoints0;
+ pinchState_ = pinchInactive;
+ panState_ = panInactive;
+}
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMap(QGeoMap* map)
+{
+ if (map_ || !map)
+ return;
+ map_ = map;
+ pan_.animation_ = new QPropertyAnimation(map_->mapController(), "center", this);
+ pan_.animation_->setEasingCurve(QEasingCurve(QEasingCurve::OutQuad));
+ connect(pan_.animation_, SIGNAL(finished()), this, SLOT(endFlick()));
+}
+
+QDeclarativeGeoMapGestureArea::~QDeclarativeGeoMapGestureArea()
+{
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoMapGestureArea::ActiveGestures QDeclarativeGeoMapGestureArea::activeGestures() const
+{
+ return activeGestures_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setActiveGestures(ActiveGestures activeGestures)
+{
+ if (activeGestures == activeGestures_)
+ return;
+ activeGestures_ = activeGestures;
+ if (activeGestures_ & RotationGesture)
+ qmlInfo(this) << tr("Pinchrotation gesture activated. Note that it is experimental feature.");
+ if (activeGestures_ & TiltGesture)
+ qmlInfo(this) << tr("Pinchtilt gesture activated. Note that it is experimental feature.");
+ emit activeGesturesChanged();
+ emit pinchDep_->activeGesturesChanged();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::isPinchActive() const
+{
+ return pinchState_ == pinchActive;
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::isPanActive() const
+{
+ return panState_ == panActive || panState_ == panFlick;
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::enabled() const
+{
+ return enabled_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setEnabled(bool enabled)
+{
+ if (enabled == enabled_)
+ return;
+ enabled_ = enabled;
+ emit enabledChanged();
+}
+
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::pinchEnabled() const
+{
+ return pinchEnabled_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setPinchEnabled(bool enabled)
+{
+ if (enabled == pinchEnabled_)
+ return;
+ pinchEnabled_ = enabled;
+ emit pinchEnabledChanged();
+ emit pinchDep_->enabledChanged();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::panEnabled() const
+{
+ return pan_.enabled_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setPanEnabled(bool enabled)
+{
+ if (enabled == pan_.enabled_)
+ return;
+ pan_.enabled_ = enabled;
+ emit panEnabledChanged();
+ emit flickableDep_->enabledChanged();
+
+ // unlike the pinch, the pan existing functionality is to stop immediately
+ if (!enabled)
+ stopPan();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::minimumZoomLevel() const
+{
+ return minimumZoomLevel_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMinimumZoomLevel(qreal zoomLevel)
+{
+ if (zoomLevel == minimumZoomLevel_ ||
+ zoomLevel < declarativeMap_->minimumZoomLevel() ||
+ (maximumZoomLevel_ != -1.0 && zoomLevel > maximumZoomLevel_) )
+ return;
+ minimumZoomLevel_ = zoomLevel;
+ emit minimumZoomLevelChanged();
+ emit pinchDep_->minimumZoomLevelChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::maximumZoomLevel() const
+{
+ return maximumZoomLevel_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMaximumZoomLevel(qreal zoomLevel)
+{
+ if (zoomLevel == maximumZoomLevel_ ||
+ zoomLevel > declarativeMap_->maximumZoomLevel() ||
+ (minimumZoomLevel_ != - 1.0 && zoomLevel < minimumZoomLevel_))
+ return;
+ maximumZoomLevel_ = zoomLevel;
+ emit maximumZoomLevelChanged();
+ emit pinchDep_->maximumZoomLevelChanged();
+}
+
+/*!
+ \internal
+ called internally when plugin's limits change. somewhat dodgy but
+ initialization order complicates the zoom limit settings a bit (for example when is
+ it possible to check against mapping plugins' limits)
+*/
+void QDeclarativeGeoMapGestureArea::zoomLevelLimits(qreal min, qreal max)
+{
+ if (minimumZoomLevel_ == -1.0 || min > minimumZoomLevel_)
+ setMinimumZoomLevel(min);
+ if (maximumZoomLevel_ == -1.0 || max < maximumZoomLevel_)
+ setMaximumZoomLevel(max);
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::maximumZoomLevelChange() const
+{
+ return maximumZoomLevelChange_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMaximumZoomLevelChange(qreal maxChange)
+{
+ if (maxChange == maximumZoomLevelChange_ || maxChange < 0.1 || maxChange > 10.0)
+ return;
+ maximumZoomLevelChange_ = maxChange;
+ emit maximumZoomLevelChangeChanged();
+ emit pinchDep_->maximumZoomLevelChangeChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::minimumRotation() const
+{
+ return minimumRotation_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMinimumRotation(qreal rotation)
+{
+ if (rotation == minimumRotation_ ||
+ rotation < 0 ||
+ rotation > maximumRotation_)
+ return;
+ minimumRotation_ = rotation;
+ emit minimumRotationChanged();
+ emit pinchDep_->minimumRotationChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::maximumRotation() const
+{
+ return maximumRotation_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMaximumRotation(qreal rotation)
+{
+ if (rotation == maximumRotation_ ||
+ rotation > 360 ||
+ rotation < minimumRotation_)
+ return;
+ maximumRotation_ = rotation;
+ emit maximumRotationChanged();
+ emit pinchDep_->maximumRotationChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::rotationFactor() const
+{
+ return rotationFactor_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setRotationFactor(qreal factor)
+{
+ if (rotationFactor_ == factor ||
+ factor < 0 ||
+ factor > 5)
+ return;
+ rotationFactor_ = factor;
+ emit rotationFactorChanged();
+ emit pinchDep_->rotationFactorChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::maximumTilt() const
+{
+ return maximumTilt_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMaximumTilt(qreal tilt)
+{
+ if (maximumTilt_ == tilt)
+ return;
+ maximumTilt_ = tilt;
+ emit maximumTiltChanged();
+ emit pinchDep_->maximumTiltChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::minimumTilt() const
+{
+ return minimumTilt_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMinimumTilt(qreal tilt)
+{
+ if (minimumTilt_ == tilt || tilt < 0.1)
+ return;
+ minimumTilt_ = tilt;
+ emit minimumTiltChanged();
+ emit pinchDep_->minimumTiltChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::maximumTiltChange() const
+{
+ return maximumTiltChange_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setMaximumTiltChange(qreal tilt)
+{
+ if (maximumTiltChange_ == tilt || tilt < 0.1)
+ return;
+ maximumTiltChange_ = tilt;
+ emit maximumTiltChangeChanged();
+ emit pinchDep_->maximumTiltChangeChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapGestureArea::flickDeceleration() const
+{
+ return pan_.deceleration_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setFlickDeceleration(qreal deceleration)
+{
+ if (deceleration < QML_MAP_FLICK_MINIMUMDECELERATION)
+ deceleration = QML_MAP_FLICK_MINIMUMDECELERATION;
+ else if (deceleration > QML_MAP_FLICK_MAXIMUMDECELERATION)
+ deceleration = QML_MAP_FLICK_MAXIMUMDECELERATION;
+ if (deceleration == pan_.deceleration_)
+ return;
+ pan_.deceleration_ = deceleration;
+ emit flickDecelerationChanged();
+ emit flickableDep_->decelerationChanged();
+}
+
+/*!
+ \internal
+*/
+QTouchEvent::TouchPoint makeTouchPointFromMouseEvent(QMouseEvent *event, Qt::TouchPointState state)
+{
+ // this is only partially filled. But since it is only partially used it works
+ // more robust would be to store a list of QPointFs rather than TouchPoints
+ QTouchEvent::TouchPoint newPoint;
+ newPoint.setPos(event->localPos());
+ newPoint.setScenePos(event->windowPos());
+ newPoint.setScreenPos(event->screenPos());
+ newPoint.setState(state);
+ newPoint.setId(0);
+ return newPoint;
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::mousePressEvent(QMouseEvent *event)
+{
+#if defined(TOUCH_EVENT_WORKAROUND)
+ if (!mouseBeingUsed_)
+ return true;
+#endif
+ touchPoints_.clear();
+ touchPoints_ << makeTouchPointFromMouseEvent(event, Qt::TouchPointPressed);
+
+ update();
+ return true;
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::mouseMoveEvent(QMouseEvent *event)
+{
+#if defined(TOUCH_EVENT_WORKAROUND)
+ if (!mouseBeingUsed_)
+ return true;
+#endif
+ touchPoints_.clear();
+
+ touchPoints_ << makeTouchPointFromMouseEvent(event, Qt::TouchPointMoved);
+ update();
+ return true;
+}
+
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::mouseReleaseEvent(QMouseEvent */*event*/)
+{
+#if defined(TOUCH_EVENT_WORKAROUND)
+ if (!mouseBeingUsed_)
+ return true;
+#endif
+ touchPoints_.clear();
+ update();
+ return true;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::touchEvent(QTouchEvent *event)
+{
+#if defined(TOUCH_EVENT_WORKAROUND)
+ mouseBeingUsed_ = false;
+#endif
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ touchPoints_.clear();
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ if (!(event->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
+ touchPoints_ << event->touchPoints().at(i);
+ }
+ }
+ update();
+ break;
+ case QEvent::TouchEnd:
+ touchPoints_.clear();
+ update();
+ break;
+ default:
+ // no-op
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::clearTouchData()
+{
+ velocityBufferX_.clear();
+ velocityBufferY_.clear();
+ pressTime_.start();
+ touchCenterCoord_.setLongitude(0);
+ touchCenterCoord_.setLatitude(0);
+ startCoord_.setLongitude(0);
+ startCoord_.setLatitude(0);
+}
+
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::updateVelocityList(const QPointF &pos)
+{
+ // Take velocity samples, used later to determine the flick
+ // duration and speed (when mouse is released).
+ if (!lastPos_.isNull()) {
+ int dyFromLastPos = pos.y() - lastPos_.y();
+ int dxFromLastPos = pos.x() - lastPos_.x();
+
+ qreal elapsed = qreal(lastPosTime_.elapsed()) / 1000.;
+ if (elapsed <= 0) {
+ return;
+ }
+ lastPosTime_.restart();
+ addVelocitySample(velocityBufferY_, double(dyFromLastPos)/elapsed);
+ addVelocitySample(velocityBufferX_, double(dxFromLastPos)/elapsed);
+ }
+}
+
+
+/*!
+ \internal
+ Adds velocity sample to sample buffer. Data is later used to calculate
+ flick speed. By default 3 latest samples are considered.
+*/
+void QDeclarativeGeoMapGestureArea::addVelocitySample(QVector<qreal>& buffer, qreal sample)
+{
+ if (sample > pan_.maxVelocity_)
+ sample = pan_.maxVelocity_;
+ else if (sample < -pan_.maxVelocity_)
+ sample = -pan_.maxVelocity_;
+ buffer.append(sample);
+ if (buffer.count() > QML_MAP_FLICK_SAMPLEBUFFER)
+ buffer.remove(0);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::updateVelocity(QVector<qreal>& buffer, qreal& velocity)
+{
+ if (buffer.count() > QML_MAP_FLICK_DISCARDSAMPLES) {
+ velocity = 0;
+ int count = buffer.count() - QML_MAP_FLICK_DISCARDSAMPLES;
+ for (int i = 0; i < count; ++i) {
+ qreal v = buffer.at(i);
+ velocity += v;
+ }
+ velocity /= count;
+ }
+}
+
+/*!
+ \internal
+*/
+// simplify the gestures by using a state-machine format (easy to move to a future state machine)
+void QDeclarativeGeoMapGestureArea::update()
+{
+ // First state machine is for the number of touch points
+ touchPointStateMachine();
+
+ // Parallel state machine for pinch
+ if (isPinchActive() || (enabled_ && pinchEnabled_ && (activeGestures_ & (ZoomGesture | TiltGesture | RotationGesture))))
+ pinchStateMachine();
+
+ // Parallel state machine for pan (since you can pan at the same time as pinching)
+ // The stopPan function ensures that pan stops immediately when disabled,
+ // but the line below allows pan continue its current gesture if you disable
+ // the whole gesture (enabled_ flag), this keeps the enabled_ consistent with the pinch
+ if (isPanActive() || (enabled_ && pan_.enabled_ && (activeGestures_ & (PanGesture | FlickGesture))))
+ panStateMachine();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::touchPointStateMachine()
+{
+ // Transitions:
+ switch (touchPointState_)
+ {
+ case touchPoints0:{
+ if (touchPoints_.count()==1){
+ clearTouchData();
+ startOneTouchPoint();
+ touchPointState_ = touchPoints1;
+ }
+ else if (touchPoints_.count()==2){
+ clearTouchData();
+ startTwoTouchPoints();
+ touchPointState_ = touchPoints2;
+ }
+ break;
+ }
+ case touchPoints1:{
+ if (touchPoints_.count()==0){
+ touchPointState_ = touchPoints0;
+ }
+ else if (touchPoints_.count()==2){
+ startTwoTouchPoints();
+ touchPointState_ = touchPoints2;
+ }
+ break;
+ }
+ case touchPoints2:{
+ if (touchPoints_.count()==0){
+ touchPointState_ = touchPoints0;
+ }
+ else if (touchPoints_.count()==1){
+ startOneTouchPoint();
+ touchPointState_ = touchPoints1;
+ }
+ break;
+ }
+ };
+
+ // Update
+ switch (touchPointState_)
+ {
+ case touchPoints0:{
+ break; // do nothing if no touch points down
+ }
+ case touchPoints1:{
+ updateOneTouchPoint();
+ break;
+ }
+ case touchPoints2:{
+ updateTwoTouchPoints();
+ break;
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::startOneTouchPoint()
+{
+ sceneCenter_ = QPointF();
+ lastPosTime_.start();
+
+ sceneStartPoint1_ = touchPoints_.at(0).scenePos();
+ QGeoCoordinate startCoord = map_->screenPositionToCoordinate(sceneStartPoint1_, false);
+ // ensures a smooth transition for panning
+ startCoord_.setLongitude(startCoord_.longitude() + startCoord.longitude() -
+ touchCenterCoord_.longitude());
+ startCoord_.setLatitude(startCoord_.latitude() + startCoord.latitude() -
+ touchCenterCoord_.latitude());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::updateOneTouchPoint()
+{
+ lastPos_ = sceneCenter_;
+ sceneCenter_ = touchPoints_.at(0).scenePos();
+ touchCenterCoord_ = map_->screenPositionToCoordinate(sceneCenter_, false);
+
+ updateVelocityList(sceneCenter_);
+}
+
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::startTwoTouchPoints()
+{
+ sceneCenter_ = QPointF();
+ lastPosTime_.start();
+
+ sceneStartPoint1_ = touchPoints_.at(0).scenePos();
+ sceneStartPoint2_ = touchPoints_.at(1).scenePos();
+ QPointF startPos = (sceneStartPoint1_ + sceneStartPoint2_) * 0.5;
+ QGeoCoordinate startCoord = map_->screenPositionToCoordinate(startPos, false);
+ startCoord_.setLongitude(startCoord_.longitude() + startCoord.longitude() -
+ touchCenterCoord_.longitude());
+ startCoord_.setLatitude(startCoord_.latitude() + startCoord.latitude() -
+ touchCenterCoord_.latitude());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::updateTwoTouchPoints()
+{
+ QPointF p1 = touchPoints_.at(0).scenePos();
+ QPointF p2 = touchPoints_.at(1).scenePos();
+ qreal dx = p1.x() - p2.x();
+ qreal dy = p1.y() - p2.y();
+ distanceBetweenTouchPoints_ = sqrt(dx*dx + dy*dy);
+ lastPos_ = sceneCenter_;
+ sceneCenter_ = (p1 + p2)/2;
+ touchCenterCoord_ = map_->screenPositionToCoordinate(sceneCenter_, false);
+
+ updateVelocityList(sceneCenter_);
+
+ twoTouchAngle_ = QLineF(p1, p2).angle();
+ if (twoTouchAngle_ > 180)
+ twoTouchAngle_ -= 360;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::setPinchActive(bool active)
+{
+ if ((active && pinchState_==pinchActive) || (!active && pinchState_!=pinchActive))
+ return;
+ pinchState_ = active ? pinchActive : pinchInactive;
+ emit pinchDep_->activeChanged();
+ emit pinchActiveChanged();
+}
+
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::pinchStateMachine()
+{
+ PinchState lastState = pinchState_;
+ // Transitions:
+ switch (pinchState_)
+ {
+ case pinchInactive:{
+ if (canStartPinch()){
+ startPinch();
+ setPinchActive(true);
+ }
+ break;
+ }
+ case pinchActive:{
+ if (touchPoints_.count() <= 1){
+ endPinch();
+ setPinchActive(false);
+ }
+ break;
+ }
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (pinchState_ != lastState)
+ return;
+ // Update
+ switch (pinchState_)
+ {
+ case pinchInactive:{
+ break; // do nothing
+ }
+ case pinchActive:{
+ updatePinch();
+ break;
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::canStartPinch()
+{
+ const int startDragDistance = qApp->styleHints()->startDragDistance();
+
+ if (touchPoints_.count() >= 2){
+ QPointF p1 = touchPoints_.at(0).scenePos();
+ QPointF p2 = touchPoints_.at(1).scenePos();
+ if (qAbs(p1.x()-sceneStartPoint1_.x()) > startDragDistance
+ || qAbs(p1.y()-sceneStartPoint1_.y()) > startDragDistance
+ || qAbs(p2.x()-sceneStartPoint2_.x()) > startDragDistance
+ || qAbs(p2.y()-sceneStartPoint2_.y()) > startDragDistance) {
+ pinchEvent_.setCenter(declarativeMap_->mapFromScene(sceneCenter_));
+ pinchEvent_.setAngle(twoTouchAngle_);
+ pinchEvent_.setPoint1(p1);
+ pinchEvent_.setPoint2(p2);
+ pinchEvent_.setPointCount(touchPoints_.count());
+ pinchEvent_.setAccepted(true);
+ emit pinchStarted(&pinchEvent_);
+ emit pinchDep_->pinchStarted(&pinchEvent_);
+ return pinchEvent_.accepted();
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::startPinch()
+{
+ pinchStartDist_ = distanceBetweenTouchPoints_;
+ pinchLastZoomLevel_ = 1.0;
+ pinchLastTilt_ = 0.0;
+ pinchLastAngle_ = twoTouchAngle_;
+ pinchRotation_ = 0.0;
+
+ lastPoint1_ = touchPoints_.at(0).scenePos();
+ lastPoint2_ = touchPoints_.at(1).scenePos();
+
+ pinchStartZoomLevel_ = declarativeMap_->zoomLevel();
+ pinchStartRotation_ = declarativeMap_->bearing();
+ pinchStartTilt_ = declarativeMap_->tilt();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::updatePinch()
+{
+ // Calculate the new zoom level if we have distance ( >= 2 touchpoints), otherwise stick with old.
+ qreal newZoomLevel = pinchLastZoomLevel_;
+ if (distanceBetweenTouchPoints_) {
+ newZoomLevel =
+ // How much further/closer the current touchpoints are (in pixels) compared to pinch start
+ ((distanceBetweenTouchPoints_ - pinchStartDist_) *
+ // How much one pixel corresponds in units of zoomlevel (and multiply by above delta)
+ (maximumZoomLevelChange_ / ((declarativeMap_->width() + declarativeMap_->height()) / 2))) +
+ // Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out
+ pinchStartZoomLevel_;
+ }
+ qreal da = pinchLastAngle_ - twoTouchAngle_;
+ if (da > 180)
+ da -= 360;
+ else if (da < -180)
+ da += 360;
+ pinchRotation_ -= da;
+ pinchEvent_.setCenter(declarativeMap_->mapFromScene(sceneCenter_));
+ pinchEvent_.setAngle(twoTouchAngle_);
+
+ lastPoint1_ = touchPoints_.at(0).scenePos();
+ lastPoint2_ = touchPoints_.at(1).scenePos();
+ pinchEvent_.setPoint1(lastPoint1_);
+ pinchEvent_.setPoint2(lastPoint2_);
+ pinchEvent_.setPointCount(touchPoints_.count());
+ pinchEvent_.setAccepted(true);
+
+ pinchLastAngle_ = twoTouchAngle_;
+ emit pinchUpdated(&pinchEvent_);
+ emit pinchDep_->pinchUpdated(&pinchEvent_);
+
+ if (activeGestures_ & ZoomGesture) {
+ // Take maximum and minimumzoomlevel into account
+ qreal perPinchMinimumZoomLevel = qMax(pinchStartZoomLevel_ - maximumZoomLevelChange_, minimumZoomLevel_);
+ qreal perPinchMaximumZoomLevel = qMin(pinchStartZoomLevel_ + maximumZoomLevelChange_, maximumZoomLevel_);
+ newZoomLevel = qMin(qMax(perPinchMinimumZoomLevel, newZoomLevel), perPinchMaximumZoomLevel);
+ declarativeMap_->setZoomLevel(newZoomLevel);
+ }
+ if (activeGestures_ & TiltGesture && minimumZoomLevel_ >= 0 && maximumZoomLevel_ >= 0) {
+ // Note: tilt is not yet supported.
+ qreal newTilt = pinchLastTilt_;
+ if (distanceBetweenTouchPoints_) {
+ newTilt =
+ // How much further/closer the current touchpoints are (in pixels) compared to pinch start
+ ((distanceBetweenTouchPoints_ - pinchStartDist_) *
+ // How much one pixel corresponds in units of tilt degrees (and multiply by above delta)
+ (maximumTiltChange_ / ((declarativeMap_->width() + declarativeMap_->height()) / 2))) +
+ // Add to starting tilt.
+ pinchStartTilt_;
+ }
+ qreal perPinchMinimumTilt = qMax(pinchStartTilt_ - maximumTiltChange_, minimumTilt_);
+ qreal perPinchMaximumTilt = qMin(pinchStartTilt_ + maximumTiltChange_, maximumTilt_);
+ newTilt = qMin(qMax(perPinchMinimumTilt, newTilt), perPinchMaximumTilt);
+ pinchLastTilt_ = newTilt;
+ declarativeMap_->setTilt(newTilt);
+ }
+ if (activeGestures_ & RotationGesture) {
+ bool unlimitedRotation = (minimumRotation_ == 0.0 && maximumRotation_ == 0.0);
+ if ((pinchStartRotation_ >= minimumRotation_ && pinchStartRotation_ <= maximumRotation_) || unlimitedRotation) {
+ qreal r = pinchRotation_ * rotationFactor_ + pinchStartRotation_;
+ if (!unlimitedRotation)
+ r = qMin(qMax(minimumRotation_,r), maximumRotation_);
+ if (r > 360.0)
+ r -= 360;
+ if (r < -360.0)
+ r += 360.0;
+ declarativeMap_->setBearing(r);
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::endPinch()
+{
+ QPointF pinchCenter = declarativeMap_->mapFromScene(sceneCenter_);
+ pinchEvent_.setCenter(pinchCenter);
+ pinchEvent_.setAngle(pinchLastAngle_);
+ pinchEvent_.setPoint1(declarativeMap_->mapFromScene(lastPoint1_));
+ pinchEvent_.setPoint2(declarativeMap_->mapFromScene(lastPoint2_));
+ pinchEvent_.setAccepted(true);
+ pinchEvent_.setPointCount(0);
+ emit pinchFinished(&pinchEvent_);
+ emit pinchDep_->pinchFinished(&pinchEvent_);
+ pinchStartDist_ = 0;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::panStateMachine()
+{
+ PanState lastState = panState_;
+
+ // Transitions
+ switch (panState_)
+ {
+ case panInactive:{
+ if (canStartPan())
+ panState_ = panActive;
+ break;
+ }
+ case panActive:{
+ if (touchPoints_.count()==0){
+ panState_ = panFlick;
+ if (!tryStartFlick())
+ panState_ = panInactive;
+ }
+ break;
+ }
+ case panFlick:{
+ if (touchPoints_.count()>0){ // re touched before movement ended
+ endFlick();
+ panState_ = panActive;
+ }
+ break;
+ }
+ }
+ // Update
+ switch (panState_)
+ {
+ case panInactive:{ // do nothing
+ break;
+ }
+ case panActive:{
+ updatePan();
+ // this ensures 'panStarted' occurs after the pan has actually started
+ if (lastState != panActive){
+ emit panStarted();
+ emit flickableDep_->movementStarted();
+ }
+ break;
+ }
+ case panFlick:{
+ break;
+ }
+ }
+}
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::canStartPan()
+{
+ if (touchPoints_.count() == 0 || (activeGestures_ & PanGesture)==0)
+ return false;
+
+ // Check if thresholds for normal panning are met.
+ // (normal panning vs flicking: flicking will start from mouse release event).
+ const int startDragDistance = qApp->styleHints()->startDragDistance();
+ QPointF p1 = touchPoints_.at(0).scenePos();
+ int dyFromPress = int(p1.y() - sceneStartPoint1_.y());
+ int dxFromPress = int(p1.x() - sceneStartPoint1_.x());
+ if ((qAbs(dyFromPress) > startDragDistance
+ || qAbs(dxFromPress) > startDragDistance
+ || pressTime_.elapsed() > 200) && !lastPos_.isNull())
+ return true;
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::updatePan()
+{
+ QDeclarativeCoordinate *center = declarativeMap_->center();
+ qreal newLat = center->latitude() + startCoord_.latitude() - touchCenterCoord_.latitude();
+ qreal newLong = center->longitude() + startCoord_.longitude() - touchCenterCoord_.longitude();
+ center->setLatitude(newLat);
+ center->setLongitude(newLong);
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMapGestureArea::tryStartFlick()
+{
+ if ((activeGestures_ & FlickGesture)==0)
+ return false;
+ // if we drag then pause before release we should not cause a flick.
+ qreal velocityX = 0.0;
+ qreal velocityY = 0.0;
+ if (lastPosTime_.elapsed() < 100) {
+ updateVelocity(velocityBufferY_, velocityY);
+ updateVelocity(velocityBufferX_, velocityX);
+ }
+ int flickTimeY = 0;
+ int flickTimeX = 0;
+ int flickPixelsX = 0;
+ int flickPixelsY = 0;
+ if (qAbs(velocityY) > MinimumFlickVelocity && qAbs(sceneCenter_.y() - sceneStartPoint1_.y()) > FlickThreshold) {
+ // calculate Y flick animation values
+ qreal acceleration = pan_.deceleration_;
+ if ((velocityY > 0.0f) == (pan_.deceleration_ > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTimeY = static_cast<int>(-1000 * velocityY / acceleration);
+ flickPixelsY = (flickTimeY * velocityY) / (1000.0 * 2);
+ }
+ if (qAbs(velocityX) > MinimumFlickVelocity && qAbs(sceneCenter_.x() - sceneStartPoint1_.x()) > FlickThreshold) {
+ // calculate X flick animation values
+ qreal acceleration = pan_.deceleration_;
+ if ((velocityX > 0.0f) == (pan_.deceleration_ > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTimeX = static_cast<int>(-1000 * velocityX / acceleration);
+ flickPixelsX = (flickTimeX * velocityX) / (1000.0 * 2);
+ }
+ int flickTime = qMax(flickTimeY, flickTimeX);
+ if (flickTime > 0){
+ startFlick(flickPixelsX, flickPixelsY, flickTime);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+// FIXME:
+// - not left right / up down flicking, so if map is rotated, will act unintuitively
+void QDeclarativeGeoMapGestureArea::startFlick(int dx, int dy, int timeMs)
+{
+ if (timeMs < 0)
+ return;
+ AnimatableCoordinate animationStartCoordinate = map_->mapController()->center();
+ QGeoCoordinate coordinate = animationStartCoordinate.coordinate();
+
+ if (pan_.animation_->state() == QPropertyAnimation::Running)
+ pan_.animation_->stop();
+ AnimatableCoordinate animationEndCoordinate = map_->mapController()->center();
+ pan_.animation_->setDuration(timeMs);
+ coordinate.setLongitude(coordinate.longitude() - (dx / pow(2.0, map_->mapController()->zoom())));
+ coordinate.setLatitude(coordinate.latitude() + (dy / pow(2.0, map_->mapController()->zoom())));
+ animationEndCoordinate.setCoordinate(coordinate);
+ pan_.animation_->setStartValue(QVariant::fromValue(animationStartCoordinate));
+ pan_.animation_->setEndValue(QVariant::fromValue(animationEndCoordinate));
+ pan_.animation_->start();
+ emit flickStarted();
+ emit flickableDep_->flickStarted();
+}
+
+void QDeclarativeGeoMapGestureArea::stopPan()
+{
+ velocityBufferX_.clear();
+ velocityBufferY_.clear();
+ if (panState_ == panFlick)
+ endFlick();
+ else if (panState_ == panActive){
+ emit panFinished();
+ flickableDep_->movementEnded();
+ }
+ panState_ = panInactive;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapGestureArea::endFlick()
+{
+ emit panFinished();
+ emit flickableDep_->movementEnded();
+ if (pan_.animation_->state() == QPropertyAnimation::Running)
+ pan_.animation_->stop();
+ emit flickFinished();
+ emit flickableDep_->flickEnded();
+ panState_ = panInactive;
+}
+
+
+
+
+
+
+#include "moc_qdeclarativegeomapgesturearea_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomapgesturearea_p.h b/src/imports/location/qdeclarativegeomapgesturearea_p.h
new file mode 100644
index 00000000..a64b1962
--- /dev/null
+++ b/src/imports/location/qdeclarativegeomapgesturearea_p.h
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPGESTUREAREA_P_H
+#define QDECLARATIVEGEOMAPGESTUREAREA_P_H
+
+#include <QtQml/qqml.h>
+#include <QTouchEvent>
+#include <QObject>
+#include <QDebug>
+#include <QElapsedTimer>
+#include "qgeocoordinate.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsSceneMouseEvent;
+class QDeclarativeGeoMap;
+class QTouchEvent;
+class QGeoMap;
+class QPropertyAnimation;
+class QDeclarativeGeoMapFlickable;
+class QDeclarativeGeoMapPinchArea;
+
+class QDeclarativeGeoMapPinchEvent : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPointF center READ center)
+ Q_PROPERTY(qreal angle READ angle)
+ Q_PROPERTY(QPointF point1 READ point1)
+ Q_PROPERTY(QPointF point2 READ point2)
+ Q_PROPERTY(int pointCount READ pointCount)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+
+public:
+ QDeclarativeGeoMapPinchEvent(QPointF center, qreal angle,
+ QPointF point1, QPointF point2,
+ int pointCount = 0, bool accepted = true)
+ : QObject(), center_(center), angle_(angle),
+ point1_(point1), point2_(point2),
+ pointCount_(pointCount), accepted_(accepted) {}
+ QDeclarativeGeoMapPinchEvent()
+ : QObject(),
+ angle_(0.0),
+ pointCount_(0),
+ accepted_(true) {}
+
+ QPointF center() const { return center_; }
+ void setCenter(QPointF center) { center_ = center; }
+ qreal angle() const { return angle_; }
+ void setAngle(qreal angle) { angle_ = angle; }
+ QPointF point1() const { return point1_; }
+ void setPoint1(QPointF p) { point1_ = p; }
+ QPointF point2() const { return point2_; }
+ void setPoint2(QPointF p) { point2_ = p; }
+ int pointCount() const { return pointCount_; }
+ void setPointCount(int count) { pointCount_ = count; }
+ bool accepted() const { return accepted_; }
+ void setAccepted(bool a) { accepted_ = a; }
+
+private:
+ QPointF center_;
+ qreal angle_;
+ QPointF point1_;
+ QPointF point2_;
+ int pointCount_;
+ bool accepted_;
+};
+
+// tbd: should we have a 'active' / 'moving' boolean attribute when pinch is active?
+
+// class QDeclarativeGeoMapGestureArea: public QObject // supporting pinching, panning, flicking, tilting
+class QDeclarativeGeoMapGestureArea: public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ActiveGesture)
+ Q_FLAGS(ActiveGestures)
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool pinchEnabled READ pinchEnabled WRITE setPinchEnabled NOTIFY pinchEnabledChanged)
+ Q_PROPERTY(bool panEnabled READ panEnabled WRITE setPanEnabled NOTIFY panEnabledChanged)
+ Q_PROPERTY(bool isPinchActive READ isPinchActive WRITE setPinchActive NOTIFY pinchActiveChanged)
+ Q_PROPERTY(bool isPanActive READ isPanActive)
+ Q_PROPERTY(ActiveGestures activeGestures READ activeGestures WRITE setActiveGestures NOTIFY activeGesturesChanged)
+ Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged)
+ Q_PROPERTY(qreal rotationFactor READ rotationFactor WRITE setRotationFactor NOTIFY rotationFactorChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+
+ // need for these is not clear, use-case(s) not yet identified:
+ //Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
+ //Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
+ //Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged)
+ //Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged)
+ // when tilt is supported, these are needed:
+ //Q_PROPERTY(qreal maximumTilt READ maximumTilt WRITE setMaximumTilt NOTIFY maximumTiltChanged)
+ //Q_PROPERTY(qreal minimumTilt READ minimumTilt WRITE setMinimumTilt NOTIFY minimumTiltChanged)
+ //Q_PROPERTY(qreal maximumTiltChange READ maximumTiltChange WRITE setMaximumTiltChange NOTIFY maximumTiltChangeChanged)
+
+public:
+ QDeclarativeGeoMapGestureArea(QDeclarativeGeoMap* map, QObject *parent = 0);
+ ~QDeclarativeGeoMapGestureArea();
+
+ enum ActiveGesture {
+ NoGesture = 0x0000,
+ ZoomGesture = 0x0001,
+ RotationGesture = 0x0002,
+ TiltGesture = 0x0004,
+ PanGesture = 0x0008,
+ FlickGesture = 0x0010
+ };
+ Q_DECLARE_FLAGS(ActiveGestures, ActiveGesture);
+
+ ActiveGestures activeGestures() const;
+ void setActiveGestures(ActiveGestures activeGestures);
+
+ bool isPinchActive() const;
+ void setPinchActive(bool active);
+ bool isPanActive() const;
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ // backwards compatibility
+ bool pinchEnabled() const;
+ void setPinchEnabled(bool enabled);
+ bool panEnabled() const;
+ void setPanEnabled(bool enabled);
+
+ qreal minimumZoomLevel() const;
+ void setMinimumZoomLevel(qreal zoomLevel);
+
+ qreal maximumZoomLevel() const;
+ void setMaximumZoomLevel(qreal zoomLevel);
+
+ qreal maximumZoomLevelChange() const;
+ void setMaximumZoomLevelChange(qreal maxChange);
+
+ qreal minimumRotation() const;
+ void setMinimumRotation(qreal zoomLevel);
+
+ qreal maximumRotation() const;
+ void setMaximumRotation(qreal zoomLevel);
+
+ qreal rotationFactor() const;
+ void setRotationFactor(qreal factor);
+
+ qreal maximumTilt() const;
+ void setMaximumTilt(qreal tilt);
+
+ qreal minimumTilt() const;
+ void setMinimumTilt(qreal tilt);
+
+ qreal maximumTiltChange() const;
+ void setMaximumTiltChange(qreal tilt);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal deceleration);
+
+ void touchEvent(QTouchEvent *event);
+
+ bool mousePressEvent(QMouseEvent *event);
+ bool mouseMoveEvent(QMouseEvent *event);
+ bool mouseReleaseEvent(QMouseEvent *event);
+
+ void zoomLevelLimits(qreal min, qreal max);
+ void setMap(QGeoMap* map);
+
+ // will be removed
+ void registerFlickDeprecated(QDeclarativeGeoMapFlickable *flickable){
+ flickableDep_ = flickable; }
+ void registerPinchDeprecated(QDeclarativeGeoMapPinchArea *pinchArea){
+ pinchDep_ = pinchArea; }
+
+signals:
+ void pinchActiveChanged();
+ void enabledChanged();
+ void minimumZoomLevelChanged();
+ void maximumZoomLevelChanged();
+ void maximumZoomLevelChangeChanged();
+ void minimumRotationChanged();
+ void maximumRotationChanged();
+ void rotationFactorChanged();
+ void activeGesturesChanged();
+ void minimumTiltChanged();
+ void maximumTiltChanged();
+ void maximumTiltChangeChanged();
+ void flickDecelerationChanged();
+
+ // backwards compatibility
+ void pinchEnabledChanged();
+ void panEnabledChanged();
+
+ void pinchStarted(QDeclarativeGeoMapPinchEvent* pinch);
+ void pinchUpdated(QDeclarativeGeoMapPinchEvent* pinch);
+ void pinchFinished(QDeclarativeGeoMapPinchEvent* pinch);
+ void panStarted();
+ void panFinished();
+ void flickStarted();
+ void flickFinished();
+
+private:
+ class QDeclarativeGeoMapFlickable *flickableDep_;
+ class QDeclarativeGeoMapPinchArea *pinchDep_;
+
+ void update();
+
+ // Create general data relating to the touch points
+ void touchPointStateMachine();
+ void startOneTouchPoint();
+ void updateOneTouchPoint();
+ void startTwoTouchPoints();
+ void updateTwoTouchPoints();
+
+ // All pinch related code, which encompasses zoom, rotation and tilt
+ void pinchStateMachine();
+ bool canStartPinch();
+ void startPinch();
+ void updatePinch();
+ void endPinch();
+
+ // Pan related code (regardles of number of touch points),
+ // includes the flick based panning after letting go
+ void panStateMachine();
+ bool canStartPan();
+ void updatePan();
+ bool tryStartFlick();
+ void startFlick(int dx, int dy, int timeMs = 0);
+private slots:
+ void endFlick();
+
+private:
+ void stopPan();
+ void clearTouchData();
+ void updateVelocityList(const QPointF &pos);
+ void addVelocitySample(QVector<qreal>& buffer, qreal sample);
+ void updateVelocity(QVector<qreal>& buffer, qreal& velocity);
+
+private:
+ QGeoMap *map_;
+ QDeclarativeGeoMap *declarativeMap_;
+ bool enabled_;
+ // TODO: put these into a structure for clarity
+ // struct Pinch
+ // {
+ QDeclarativeGeoMapPinchEvent pinchEvent_;
+ bool pinchEnabled_;
+ qreal minimumZoomLevel_;
+ qreal maximumZoomLevel_;
+ qreal minimumRotation_;
+ qreal maximumRotation_;
+ QPointF lastPoint1_;
+ QPointF lastPoint2_;
+ qreal pinchStartDist_;
+ qreal pinchStartZoomLevel_;
+ qreal pinchLastZoomLevel_;
+ qreal pinchStartRotation_;
+ qreal pinchLastAngle_;
+ qreal pinchRotation_;
+ qreal maximumZoomLevelChange_;
+ qreal rotationFactor_;
+ qreal minimumTilt_;
+ qreal maximumTilt_;
+ qreal maximumTiltChange_;
+
+ qreal pinchLastTilt_;
+ qreal pinchStartTilt_;
+ // } pinch_;
+
+ ActiveGestures activeGestures_;
+
+ struct Pan
+ {
+ qreal maxVelocity_;
+ qreal deceleration_;
+ QPropertyAnimation *animation_;
+ bool enabled_;
+ } pan_;
+
+ // these are calculated regardless of gesture or number of touch points
+ QVector<qreal> velocityBufferX_;
+ QVector<qreal> velocityBufferY_;
+ QElapsedTimer lastPosTime_;
+ QPointF lastPos_;
+ QElapsedTimer pressTime_;
+ QList<QTouchEvent::TouchPoint> touchPoints_;
+ QPointF sceneStartPoint1_;
+
+ // only set when two points in contact
+ QPointF sceneStartPoint2_;
+ QGeoCoordinate startCoord_;
+ QGeoCoordinate touchCenterCoord_;
+ qreal twoTouchAngle_;
+ qreal distanceBetweenTouchPoints_;
+ QPointF sceneCenter_;
+
+#if defined(TOUCH_EVENT_WORKAROUND) // will be removed when review change 21896 goes into QML core
+ bool mouseBeingUsed_;
+#endif
+ // prototype state machine...
+ enum TouchPointState
+ {
+ touchPoints0,
+ touchPoints1,
+ touchPoints2
+ } touchPointState_;
+
+ enum PinchState
+ {
+ pinchInactive,
+ pinchActive
+ } pinchState_;
+
+ enum PanState
+ {
+ panInactive,
+ panActive,
+ panFlick
+ } panState_;
+
+ friend class QDeclarativeGeoMapPinchArea;
+ friend class QDeclarativeGeoMapFlickable;
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QDeclarativeGeoMapGestureArea);
+
+#endif // QDECLARATIVEGEOMAPGESTUREAREA_P_H
diff --git a/src/imports/location/qdeclarativegeomappincharea.cpp b/src/imports/location/qdeclarativegeomappincharea.cpp
index fa5aa25a..7d591aeb 100644
--- a/src/imports/location/qdeclarativegeomappincharea.cpp
+++ b/src/imports/location/qdeclarativegeomappincharea.cpp
@@ -42,15 +42,37 @@
#include <QtGui/QGuiApplication>
#include "qdeclarativegeomappincharea_p.h"
#include "qdeclarativegeomap_p.h"
+#include "qdeclarativecoordinate_p.h"
#include <QtGui/qevent.h>
#include <QtGui/QStyleHints>
#include <QtQml/qqmlinfo.h>
+#include <QPropertyAnimation>
#include <QDebug>
#include "math.h"
#include "qgeomap_p.h"
+#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
+#define QML_MAP_FLICK_MINIMUMDECELERATION 500
+#define QML_MAP_FLICK_DEFAULTDECELERATION 2500
+#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000
+// The number of samples to use in calculating the velocity of a flick
+#define QML_MAP_FLICK_SAMPLEBUFFER 3
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#define QML_MAP_FLICK_DISCARDSAMPLES 1
+
+// FlickThreshold determines how far the "mouse" must have moved
+// before we perform a flick.
+static const int FlickThreshold = 20;
+// RetainGrabVelocity is the maxmimum instantaneous velocity that
+// will ensure the Flickable retains the grab on consecutive flicks.
+static const int RetainGrabVelocity = 15;
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
QT_BEGIN_NAMESPACE
+
/*!
\qmlclass MapPinchEvent
\inqmlmodule QtLocation 5
@@ -191,6 +213,7 @@ QT_BEGIN_NAMESPACE
\li PinchArea.ZoomGesture - Support the map zoom gesture (value: 0x0001).
\li PinchArea.RotationGesture - Support the map rotation gesture (value: 0x0002).
\li PinchArea.TiltGesture - Support the map tilt gesture (value: 0x0004).
+ \li PinchArea.PanGesture - Support the map pan gesture while pinching (value: 0x0008).
\endlist
For the extremist, one may OR flag the RotationGesture or TiltGesture
@@ -255,486 +278,18 @@ QT_BEGIN_NAMESPACE
*/
-QDeclarativeGeoMapPinchArea::QDeclarativeGeoMapPinchArea(QDeclarativeGeoMap* map, QObject *parent)
+QDeclarativeGeoMapPinchArea::QDeclarativeGeoMapPinchArea(QObject *parent,
+ QDeclarativeGeoMapGestureArea *gestureArea)
: QObject(parent),
- map_(map),
- enabled_(true),
- active_(false),
- minimumZoomLevel_(-1.0),
- maximumZoomLevel_(-1.0),
- minimumRotation_(0.0),
- maximumRotation_(0.0),
- inPinch_(false),
- pinchRejected_(false),
- pinchActivated_(false),
- pinchStartDist_(0),
- pinchStartZoomLevel_(0.0),
- pinchLastZoomLevel_(0.0),
- pinchStartRotation_(0.0),
- pinchLastAngle_(0.0),
- pinchRotation_(0.0),
- id1_(-1),
- maximumZoomLevelChange_(2.0),
- rotationFactor_(1.0),
- activeGestures_(ZoomGesture),
- minimumTilt_(0.0),
- maximumTilt_(90.0),
- maximumTiltChange_(20.0),
- pinchLastTilt_(0.0),
- pinchStartTilt_(0.0)
+ gestureArea_(gestureArea)
{
+ gestureArea_->registerPinchDeprecated(this);
}
QDeclarativeGeoMapPinchArea::~QDeclarativeGeoMapPinchArea()
{
}
-/*!
- \internal
-*/
-QDeclarativeGeoMapPinchArea::ActiveGestures QDeclarativeGeoMapPinchArea::activeGestures() const
-{
- return activeGestures_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setActiveGestures(ActiveGestures activeGestures)
-{
- if (activeGestures == activeGestures_)
- return;
- activeGestures_ = activeGestures;
- if (activeGestures_ & RotationGesture)
- qmlInfo(this) << tr("Pinchrotation gesture activated. Note that it is experimental feature.");
- if (activeGestures_ & TiltGesture)
- qmlInfo(this) << tr("Pinchtilt gesture activated. Note that it is experimental feature.");
- emit activeGesturesChanged();
-}
-
-/*!
- \internal
-*/
-bool QDeclarativeGeoMapPinchArea::active() const
-{
- return active_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setActive(bool active)
-{
- if (active == active_)
- return;
- active_ = active;
- emit activeChanged();
-}
-
-/*!
- \internal
-*/
-bool QDeclarativeGeoMapPinchArea::enabled() const
-{
- return enabled_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setEnabled(bool enabled)
-{
- if (enabled == enabled_)
- return;
- enabled_ = enabled;
- emit enabledChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::minimumZoomLevel() const
-{
- return minimumZoomLevel_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMinimumZoomLevel(qreal zoomLevel)
-{
- if (zoomLevel == minimumZoomLevel_ ||
- zoomLevel < map_->minimumZoomLevel() ||
- (maximumZoomLevel_ != -1.0 && zoomLevel > maximumZoomLevel_) )
- return;
- minimumZoomLevel_ = zoomLevel;
- emit minimumZoomLevelChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::maximumZoomLevel() const
-{
- return maximumZoomLevel_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMaximumZoomLevel(qreal zoomLevel)
-{
- if (zoomLevel == maximumZoomLevel_ ||
- zoomLevel > map_->maximumZoomLevel() ||
- (minimumZoomLevel_ != - 1.0 && zoomLevel < minimumZoomLevel_))
- return;
- maximumZoomLevel_ = zoomLevel;
- emit maximumZoomLevelChanged();
-}
-
-/*!
- \internal
- called internally when plugin's limits change. somewhat dodgy but
- initialization order complicates the zoom limit settings a bit (for example when is
- it possible to check against mapping plugins' limits)
-*/
-void QDeclarativeGeoMapPinchArea::zoomLevelLimits(qreal min, qreal max)
-{
- if (minimumZoomLevel_ == -1.0 || min > minimumZoomLevel_)
- setMinimumZoomLevel(min);
- if (maximumZoomLevel_ == -1.0 || max < maximumZoomLevel_)
- setMaximumZoomLevel(max);
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::maximumZoomLevelChange() const
-{
- return maximumZoomLevelChange_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMaximumZoomLevelChange(qreal maxChange)
-{
- if (maxChange == maximumZoomLevelChange_ || maxChange < 0.1 || maxChange > 10.0)
- return;
- maximumZoomLevelChange_ = maxChange;
- emit maximumZoomLevelChangeChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::minimumRotation() const
-{
- return minimumRotation_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMinimumRotation(qreal rotation)
-{
- if (rotation == minimumRotation_ ||
- rotation < 0 ||
- rotation > maximumRotation_)
- return;
- minimumRotation_ = rotation;
- emit minimumRotationChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::maximumRotation() const
-{
- return maximumRotation_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMaximumRotation(qreal rotation)
-{
- if (rotation == maximumRotation_ ||
- rotation > 360 ||
- rotation < minimumRotation_)
- return;
- maximumRotation_ = rotation;
- emit maximumRotationChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::rotationFactor() const
-{
- return rotationFactor_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setRotationFactor(qreal factor)
-{
- if (rotationFactor_ == factor ||
- factor < 0 ||
- factor > 5)
- return;
- rotationFactor_ = factor;
- emit rotationFactorChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::maximumTilt() const
-{
- return maximumTilt_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMaximumTilt(qreal tilt)
-{
- if (maximumTilt_ == tilt)
- return;
- maximumTilt_ = tilt;
- emit maximumTiltChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::minimumTilt() const
-{
- return minimumTilt_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMinimumTilt(qreal tilt)
-{
- if (minimumTilt_ == tilt || tilt < 0.1)
- return;
- minimumTilt_ = tilt;
- emit minimumTiltChanged();
-}
-
-/*!
- \internal
-*/
-qreal QDeclarativeGeoMapPinchArea::maximumTiltChange() const
-{
- return maximumTiltChange_;
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::setMaximumTiltChange(qreal tilt)
-{
- if (maximumTiltChange_ == tilt || tilt < 0.1)
- return;
- maximumTiltChange_ = tilt;
- emit maximumTiltChangeChanged();
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::touchEvent(QTouchEvent *event)
-{
- // Keep processing if gesture(s) are in progress. Otherwise we might
- // end up in lock.
- if ((!enabled_ || (activeGestures_ == NoGesture)) && !active())
- return;
- switch (event->type()) {
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- touchPoints_.clear();
- for (int i = 0; i < event->touchPoints().count(); ++i) {
- if (!(event->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
- touchPoints_ << event->touchPoints().at(i);
- }
- }
- updatePinch();
- break;
- case QEvent::TouchEnd:
- touchPoints_.clear();
- updatePinch();
- break;
- default:
- // no-op
- break;
- }
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapPinchArea::updatePinch()
-{
- if (touchPoints_.count() == 0) {
- if (inPinch_) {
- inPinch_ = false;
- QPointF pinchCenter = map_->mapFromScene(sceneLastCenter_);
- pinchEvent_.setCenter(pinchCenter);
- pinchEvent_.setAngle(pinchLastAngle_);
- pinchEvent_.setPoint1(map_->mapFromScene(lastPoint1_));
- pinchEvent_.setPoint2(map_->mapFromScene(lastPoint2_));
- pinchEvent_.setAccepted(true);
- pinchEvent_.setPointCount(0);
- emit pinchFinished(&pinchEvent_);
- pinchStartDist_ = 0;
- pinchActivated_ = false;
- setActive(false);
- }
- return;
- }
- QTouchEvent::TouchPoint touchPoint1 = touchPoints_.at(0);
- QTouchEvent::TouchPoint touchPoint2 = touchPoints_.at(touchPoints_.count() >= 2 ? 1 : 0);
- if (touchPoints_.count() == 2
- && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) {
- id1_ = touchPoint1.id();
- sceneStartPoint1_ = touchPoint1.scenePos();
- sceneStartPoint2_ = touchPoint2.scenePos();
- inPinch_ = false;
- pinchRejected_ = false;
- pinchActivated_ = true;
- } else if (pinchActivated_ && !pinchRejected_){
- const int dragThreshold = qApp->styleHints()->startDragDistance();
- QPointF p1 = touchPoint1.scenePos();
- QPointF p2 = touchPoint2.scenePos();
- qreal dx = p1.x() - p2.x();
- qreal dy = p1.y() - p2.y();
- qreal dist = sqrt(dx*dx + dy*dy);
- QPointF sceneCenter = (p1 + p2)/2;
- qreal angle = QLineF(p1, p2).angle();
- if (touchPoints_.count() == 1) {
- // If we only have one point then just move the center
- if (id1_ == touchPoint1.id())
- sceneCenter = sceneLastCenter_ + touchPoint1.scenePos() - lastPoint1_;
- else
- sceneCenter = sceneLastCenter_ + touchPoint2.scenePos() - lastPoint2_;
- angle = pinchLastAngle_;
- }
- id1_ = touchPoint1.id();
- if (angle > 180)
- angle -= 360;
- if (!inPinch_) {
- if (touchPoints_.count() >= 2
- && (qAbs(p1.x()-sceneStartPoint1_.x()) > dragThreshold
- || qAbs(p1.y()-sceneStartPoint1_.y()) > dragThreshold
- || qAbs(p2.x()-sceneStartPoint2_.x()) > dragThreshold
- || qAbs(p2.y()-sceneStartPoint2_.y()) > dragThreshold)) {
- sceneLastCenter_ = sceneCenter;
- pinchStartDist_ = dist;
- pinchLastZoomLevel_ = 1.0;
- pinchLastTilt_ = 0.0;
- pinchLastAngle_ = angle;
- pinchRotation_ = 0.0;
- lastPoint1_ = p1;
- lastPoint2_ = p2;
-
- pinchEvent_.setCenter(map_->mapFromScene(sceneCenter));
- pinchEvent_.setAngle(angle);
- pinchEvent_.setPoint1(map_->mapFromScene(lastPoint1_));
- pinchEvent_.setPoint2(map_->mapFromScene(lastPoint2_));
- pinchEvent_.setPointCount(touchPoints_.count());
- pinchEvent_.setAccepted(true);
- emit pinchStarted(&pinchEvent_);
-
- if (pinchEvent_.accepted()) {
- inPinch_ = true;
- pinchStartZoomLevel_ = map_->zoomLevel();
- pinchStartRotation_ = map_->bearing();
- pinchStartTilt_ = map_->tilt();
- setActive(true);
- } else {
- pinchRejected_ = true;
- }
- }
- } else if (pinchStartDist_ > 0) {
- // Calculate the new zoom level if we have distance ( >= 2 touchpoints), otherwise stick with old.
- qreal newZoomLevel = pinchLastZoomLevel_;
- if (dist) {
- newZoomLevel =
- // How much further/closer the current touchpoints are (in pixels) compared to pinch start
- ((dist - pinchStartDist_) *
- // How much one pixel corresponds in units of zoomlevel (and multiply by above delta)
- (maximumZoomLevelChange_ / ((map_->width() + map_->height()) / 2))) +
- // Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out
- pinchStartZoomLevel_;
- }
- qreal da = pinchLastAngle_ - angle;
- if (da > 180)
- da -= 360;
- else if (da < -180)
- da += 360;
- pinchRotation_ -= da;
- pinchEvent_.setCenter(map_->mapFromScene(sceneCenter));
- pinchEvent_.setAngle(angle);
- pinchEvent_.setPoint1(touchPoint1.pos());
- pinchEvent_.setPoint2(touchPoint2.pos());
- pinchEvent_.setPointCount(touchPoints_.count());
- pinchEvent_.setAccepted(true);
-
- sceneLastCenter_ = sceneCenter;
- pinchLastAngle_ = angle;
- lastPoint1_ = touchPoint1.scenePos();
- lastPoint2_ = touchPoint2.scenePos();
- emit pinchUpdated(&pinchEvent_);
-
- if (activeGestures_ & ZoomGesture) {
- // Take maximum and minimumzoomlevel into account
- qreal perPinchMinimumZoomLevel = qMax(pinchStartZoomLevel_ - maximumZoomLevelChange_, minimumZoomLevel_);
- qreal perPinchMaximumZoomLevel = qMin(pinchStartZoomLevel_ + maximumZoomLevelChange_, maximumZoomLevel_);
- newZoomLevel = qMin(qMax(perPinchMinimumZoomLevel, newZoomLevel), perPinchMaximumZoomLevel);
- pinchLastZoomLevel_ = newZoomLevel;
- map_->setZoomLevel(newZoomLevel);
- }
- if (activeGestures_ & TiltGesture && minimumZoomLevel_ >= 0 && maximumZoomLevel_ >= 0) {
- // Note: tilt is not yet supported.
- qreal newTilt = pinchLastTilt_;
- if (dist) {
- newTilt =
- // How much further/closer the current touchpoints are (in pixels) compared to pinch start
- ((dist - pinchStartDist_) *
- // How much one pixel corresponds in units of tilt degrees (and multiply by above delta)
- (maximumTiltChange_ / ((map_->width() + map_->height()) / 2))) +
- // Add to starting tilt.
- pinchStartTilt_;
- }
- qreal perPinchMinimumTilt = qMax(pinchStartTilt_ - maximumTiltChange_, minimumTilt_);
- qreal perPinchMaximumTilt = qMin(pinchStartTilt_ + maximumTiltChange_, maximumTilt_);
- newTilt = qMin(qMax(perPinchMinimumTilt, newTilt), perPinchMaximumTilt);
- pinchLastTilt_ = newTilt;
- map_->setTilt(newTilt);
- }
- if (activeGestures_ & RotationGesture) {
- bool unlimitedRotation = (minimumRotation_ == 0.0 && maximumRotation_ == 0.0);
- if ((pinchStartRotation_ >= minimumRotation_ && pinchStartRotation_ <= maximumRotation_) || unlimitedRotation) {
- qreal r = pinchRotation_ * rotationFactor_ + pinchStartRotation_;
- if (!unlimitedRotation)
- r = qMin(qMax(minimumRotation_,r), maximumRotation_);
- if (r > 360.0)
- r -= 360;
- if (r < -360.0)
- r += 360.0;
- map_->setBearing(r);
- }
- }
- }
- }
-}
-
-
#include "moc_qdeclarativegeomappincharea_p.cpp"
QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomappincharea_p.h b/src/imports/location/qdeclarativegeomappincharea_p.h
index 34619aeb..309e735c 100644
--- a/src/imports/location/qdeclarativegeomappincharea_p.h
+++ b/src/imports/location/qdeclarativegeomappincharea_p.h
@@ -46,6 +46,9 @@
#include <QTouchEvent>
#include <QObject>
#include <QDebug>
+#include <QElapsedTimer>
+#include "qgeocoordinate.h"
+#include "qdeclarativegeomapgesturearea_p.h"
QT_BEGIN_NAMESPACE
@@ -53,55 +56,9 @@ class QGraphicsSceneMouseEvent;
class QDeclarativeGeoMap;
class QTouchEvent;
class QGeoMap;
+class QPropertyAnimation;
-class QDeclarativeGeoMapPinchEvent : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(QPointF center READ center)
- Q_PROPERTY(qreal angle READ angle)
- Q_PROPERTY(QPointF point1 READ point1)
- Q_PROPERTY(QPointF point2 READ point2)
- Q_PROPERTY(int pointCount READ pointCount)
- Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
-
-public:
- QDeclarativeGeoMapPinchEvent(QPointF center, qreal angle,
- QPointF point1, QPointF point2,
- int pointCount = 0, bool accepted = true)
- : QObject(), center_(center), angle_(angle),
- point1_(point1), point2_(point2),
- pointCount_(pointCount), accepted_(accepted) {}
- QDeclarativeGeoMapPinchEvent()
- : QObject(),
- angle_(0.0),
- pointCount_(0),
- accepted_(true) {}
-
- QPointF center() const { return center_; }
- void setCenter(QPointF center) { center_ = center; }
- qreal angle() const { return angle_; }
- void setAngle(qreal angle) { angle_ = angle; }
- QPointF point1() const { return point1_; }
- void setPoint1(QPointF p) { point1_ = p; }
- QPointF point2() const { return point2_; }
- void setPoint2(QPointF p) { point2_ = p; }
- int pointCount() const { return pointCount_; }
- void setPointCount(int count) { pointCount_ = count; }
- bool accepted() const { return accepted_; }
- void setAccepted(bool a) { accepted_ = a; }
-
-private:
- QPointF center_;
- qreal angle_;
- QPointF point1_;
- QPointF point2_;
- int pointCount_;
- bool accepted_;
-};
-
-// tbd: should we have a 'active' / 'moving' boolean attribute when pinch is active?
-
+// Note: this class id being deprecated, please use the gestureArea instead
class QDeclarativeGeoMapPinchArea: public QObject
{
Q_OBJECT
@@ -113,18 +70,10 @@ class QDeclarativeGeoMapPinchArea: public QObject
Q_PROPERTY(ActiveGestures activeGestures READ activeGestures WRITE setActiveGestures NOTIFY activeGesturesChanged)
Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged)
Q_PROPERTY(qreal rotationFactor READ rotationFactor WRITE setRotationFactor NOTIFY rotationFactorChanged)
- // need for these is not clear, use-case(s) not yet identified:
- //Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
- //Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
- //Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged)
- //Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged)
- // when tilt is supported, these are needed:
- //Q_PROPERTY(qreal maximumTilt READ maximumTilt WRITE setMaximumTilt NOTIFY maximumTiltChanged)
- //Q_PROPERTY(qreal minimumTilt READ minimumTilt WRITE setMinimumTilt NOTIFY minimumTiltChanged)
- //Q_PROPERTY(qreal maximumTiltChange READ maximumTiltChange WRITE setMaximumTiltChange NOTIFY maximumTiltChangeChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
public:
- QDeclarativeGeoMapPinchArea(QDeclarativeGeoMap* map, QObject *parent = 0);
+ QDeclarativeGeoMapPinchArea(QObject *parent, QDeclarativeGeoMapGestureArea *gestureArea);
~QDeclarativeGeoMapPinchArea();
enum ActiveGesture {
@@ -134,46 +83,73 @@ public:
TiltGesture = 0x0004
};
Q_DECLARE_FLAGS(ActiveGestures, ActiveGesture);
-
- ActiveGestures activeGestures() const;
- void setActiveGestures(ActiveGestures activeGestures);
-
- bool active() const;
- void setActive(bool active);
-
- bool enabled() const;
- void setEnabled(bool enabled);
-
- qreal minimumZoomLevel() const;
- void setMinimumZoomLevel(qreal zoomLevel);
-
- qreal maximumZoomLevel() const;
- void setMaximumZoomLevel(qreal zoomLevel);
-
- qreal maximumZoomLevelChange() const;
- void setMaximumZoomLevelChange(qreal maxChange);
-
- qreal minimumRotation() const;
- void setMinimumRotation(qreal zoomLevel);
-
- qreal maximumRotation() const;
- void setMaximumRotation(qreal zoomLevel);
-
- qreal rotationFactor() const;
- void setRotationFactor(qreal factor);
-
- qreal maximumTilt() const;
- void setMaximumTilt(qreal tilt);
-
- qreal minimumTilt() const;
- void setMinimumTilt(qreal tilt);
-
- qreal maximumTiltChange() const;
- void setMaximumTiltChange(qreal tilt);
-
- void touchEvent(QTouchEvent *event);
-
- void zoomLevelLimits(qreal min, qreal max);
+ ActiveGestures activeGestures()
+ {
+ QDeclarativeGeoMapGestureArea::ActiveGestures gestures = gestureArea_->activeGestures();
+ activeGestures_ &= 0; // reset;
+ if (gestures & QDeclarativeGeoMapGestureArea::ZoomGesture)
+ activeGestures_ |= ZoomGesture;
+ if (gestures & QDeclarativeGeoMapGestureArea::RotationGesture)
+ activeGestures_ |= RotationGesture;
+ if (gestures & QDeclarativeGeoMapGestureArea::TiltGesture)
+ activeGestures_ |= TiltGesture;
+ return activeGestures_;
+ }
+ void setActiveGestures(ActiveGestures activeGestures)
+ {
+ if (activeGestures == activeGestures_)
+ return;
+ activeGestures_ = activeGestures;
+ QDeclarativeGeoMapGestureArea::ActiveGestures &gestures = gestureArea_->activeGestures_;
+ gestures &= ~7; // reset the pinch component;
+ if (activeGestures & ZoomGesture)
+ gestures |= QDeclarativeGeoMapGestureArea::ZoomGesture;
+ if (activeGestures & RotationGesture)
+ gestures |= QDeclarativeGeoMapGestureArea::RotationGesture;
+ if (activeGestures & TiltGesture)
+ gestures |= QDeclarativeGeoMapGestureArea::TiltGesture;
+ emit gestureArea_->activeGesturesChanged();
+ emit activeGesturesChanged();
+ }
+
+ bool active() const { return gestureArea_->isPinchActive(); }
+ void setActive(bool active) { gestureArea_->setPinchActive(active); }
+
+ bool enabled() const { return gestureArea_->pinchEnabled(); }
+ void setEnabled(bool enabled){ gestureArea_->setPinchEnabled(enabled); }
+
+ qreal minimumZoomLevel() const { return gestureArea_->minimumZoomLevel(); }
+ void setMinimumZoomLevel(qreal zoomLevel){ gestureArea_->setMinimumZoomLevel(zoomLevel); }
+
+ qreal maximumZoomLevel() const { return gestureArea_->maximumZoomLevel(); }
+ void setMaximumZoomLevel(qreal zoomLevel){ gestureArea_->setMaximumZoomLevel(zoomLevel); }
+
+ qreal maximumZoomLevelChange() const { return gestureArea_->maximumZoomLevelChange(); }
+ void setMaximumZoomLevelChange(qreal maxChange){ gestureArea_->setMaximumZoomLevelChange(maxChange); }
+
+ qreal minimumRotation() const { return gestureArea_->minimumRotation(); }
+ void setMinimumRotation(qreal zoomLevel){ gestureArea_->setMinimumRotation(zoomLevel); }
+
+ qreal maximumRotation() const { return gestureArea_->maximumRotation(); }
+ void setMaximumRotation(qreal zoomLevel){ gestureArea_->setMaximumRotation(zoomLevel); }
+
+ qreal rotationFactor() const { return gestureArea_->rotationFactor(); }
+ void setRotationFactor(qreal factor){ gestureArea_->setRotationFactor(factor); }
+
+ qreal maximumTilt() const { return gestureArea_->maximumTilt(); }
+ void setMaximumTilt(qreal tilt){ gestureArea_->setMaximumTilt(tilt); }
+
+ qreal minimumTilt() const { return gestureArea_->minimumTilt(); }
+ void setMinimumTilt(qreal tilt){ gestureArea_->setMinimumTilt(tilt); }
+
+ qreal maximumTiltChange() const { return gestureArea_->maximumTiltChange(); }
+ void setMaximumTiltChange(qreal tilt){ gestureArea_->setMaximumTiltChange(tilt); }
+
+ qreal flickDeceleration() const { return gestureArea_->flickDeceleration(); }
+ void setFlickDeceleration(qreal deceleration){ gestureArea_->setFlickDeceleration(deceleration); }
+
+ void zoomLevelLimits(qreal min, qreal max){ gestureArea_->zoomLevelLimits(min, max); }
+ void setMap(QGeoMap* map){ gestureArea_->setMap(map); }
signals:
void activeChanged();
@@ -188,48 +164,15 @@ signals:
void minimumTiltChanged();
void maximumTiltChanged();
void maximumTiltChangeChanged();
+ void flickDecelerationChanged();
void pinchStarted(QDeclarativeGeoMapPinchEvent* pinch);
void pinchUpdated(QDeclarativeGeoMapPinchEvent* pinch);
void pinchFinished(QDeclarativeGeoMapPinchEvent* pinch);
private:
- void updatePinch();
-
-private:
- QDeclarativeGeoMap* map_;
- QDeclarativeGeoMapPinchEvent pinchEvent_;
- bool enabled_;
- bool active_;
- qreal minimumZoomLevel_;
- qreal maximumZoomLevel_;
- qreal minimumRotation_;
- qreal maximumRotation_;
- QList<QTouchEvent::TouchPoint> touchPoints_;
- bool inPinch_;
- bool pinchRejected_;
- bool pinchActivated_;
- QPointF sceneStartPoint1_;
- QPointF sceneStartPoint2_;
- QPointF lastPoint1_;
- QPointF lastPoint2_;
- qreal pinchStartDist_;
- qreal pinchStartZoomLevel_;
- qreal pinchLastZoomLevel_;
- qreal pinchStartRotation_;
- qreal pinchLastAngle_;
- qreal pinchRotation_;
- QPointF sceneLastCenter_;
- int id1_;
- qreal maximumZoomLevelChange_;
- qreal rotationFactor_;
+ QDeclarativeGeoMapGestureArea *gestureArea_; // the destination for this wrapper class
ActiveGestures activeGestures_;
- qreal minimumTilt_;
- qreal maximumTilt_;
- qreal maximumTiltChange_;
-
- qreal pinchLastTilt_;
- qreal pinchStartTilt_;
};
QT_END_NAMESPACE
diff --git a/src/src.pro b/src/src.pro
index b321da3d..3b54b67b 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,3 +1,4 @@
TEMPLATE = subdirs
CONFIG+=ordered
SUBDIRS += location plugins imports
+