aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickpathview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickpathview.cpp')
-rw-r--r--src/quick/items/qquickpathview.cpp75
1 files changed, 64 insertions, 11 deletions
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index aa8ddfbec0..afc336fa04 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -55,6 +55,17 @@
#include <QtCore/qmath.h>
#include <math.h>
+// The number of samples to use in calculating the velocity of a flick
+#ifndef QML_FLICK_SAMPLEBUFFER
+#define QML_FLICK_SAMPLEBUFFER 3
+#endif
+
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#ifndef QML_FLICK_DISCARDSAMPLES
+#define QML_FLICK_DISCARDSAMPLES 1
+#endif
+
QT_BEGIN_NAMESPACE
inline qreal qmlMod(qreal x, qreal y)
@@ -377,8 +388,8 @@ void QQuickPathViewPrivate::updateItem(QQuickItem *item, qreal percent)
att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
}
QPointF pf = path->pointAt(percent);
- item->setX(qRound(pf.x() - item->width()/2));
- item->setY(qRound(pf.y() - item->height()/2));
+ item->setX(pf.x() - item->width()/2);
+ item->setY(pf.y() - item->height()/2);
}
void QQuickPathViewPrivate::regenerate()
@@ -1118,12 +1129,29 @@ void QQuickPathView::setPathItemCount(int i)
QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
{
- //XXX maybe do recursively at increasing resolution.
+ qreal samples = qMin(path->path().length()/5, qreal(500.0));
+ qreal res = path->path().length()/samples;
+
qreal mindist = 1e10; // big number
QPointF nearPoint = path->pointAt(0);
qreal nearPc = 0;
- for (qreal i=1; i < 1000; i++) {
- QPointF pt = path->pointAt(i/1000.0);
+
+ // get rough pos
+ for (qreal i=1; i < samples; i++) {
+ QPointF pt = path->pointAt(i/samples);
+ QPointF diff = pt - point;
+ qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
+ if (dist < mindist) {
+ nearPoint = pt;
+ nearPc = i;
+ mindist = dist;
+ }
+ }
+
+ // now refine
+ qreal approxPc = nearPc;
+ for (qreal i = approxPc-1.0; i < approxPc+1.0; i += 1/(2*res)) {
+ QPointF pt = path->pointAt(i/samples);
QPointF diff = pt - point;
qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
if (dist < mindist) {
@@ -1134,11 +1162,32 @@ QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercen
}
if (nearPercent)
- *nearPercent = nearPc / 1000.0;
+ *nearPercent = nearPc / samples;
return nearPoint;
}
+void QQuickPathViewPrivate::addVelocitySample(qreal v)
+{
+ velocityBuffer.append(v);
+ if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
+ velocityBuffer.remove(0);
+}
+
+qreal QQuickPathViewPrivate::calcVelocity() const
+{
+ qreal velocity = 0;
+ if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
+ int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
+ for (int i = 0; i < count; ++i) {
+ qreal v = velocityBuffer.at(i);
+ velocity += v;
+ }
+ velocity /= count;
+ }
+ return velocity;
+}
+
void QQuickPathView::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickPathView);
@@ -1155,6 +1204,7 @@ void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
Q_Q(QQuickPathView);
if (!interactive || !items.count())
return;
+ velocityBuffer.clear();
QPointF scenePoint = q->mapToScene(event->localPos());
int idx = 0;
for (; idx < items.count(); ++idx) {
@@ -1227,6 +1277,7 @@ void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
lastElapsed = QQuickItemPrivate::restart(lastPosTime);
lastDist = diff;
startPc = newPc;
+ addVelocitySample(diff / (qreal(lastElapsed) / 1000.));
}
if (!moving) {
moving = true;
@@ -1256,18 +1307,18 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
if (!interactive || !lastPosTime.isValid())
return;
- qreal elapsed = qreal(lastElapsed + QQuickItemPrivate::elapsed(lastPosTime)) / 1000.;
- qreal velocity = elapsed > 0. ? lastDist / elapsed : 0;
- if (model && modelCount && qAbs(velocity) > 1.) {
+ qreal velocity = calcVelocity();
+ if (model && modelCount && qAbs(velocity) > 0.5) {
qreal count = pathItems == -1 ? modelCount : pathItems;
if (qAbs(velocity) > count * 2) // limit velocity
velocity = (velocity > 0 ? count : -count) * 2;
// Calculate the distance to be travelled
qreal v2 = velocity*velocity;
qreal accel = deceleration/10;
- // + 0.25 to encourage moving at least one item in the flick direction
- qreal dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
+ qreal dist = 0;
if (haveHighlightRange && highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
+ // + 0.25 to encourage moving at least one item in the flick direction
+ dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
// round to nearest item.
if (velocity > 0.)
dist = qRound(dist + offset) - offset;
@@ -1280,6 +1331,8 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
} else {
accel = v2 / (2.0f * qAbs(dist));
}
+ } else {
+ dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0)));
}
offsetAdj = 0.0;
moveOffset.setValue(offset);