summaryrefslogtreecommitdiffstats
path: root/src/declarative/fx/qfxpathview.cpp
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2009-04-22 04:47:24 (GMT)
committerMichael Brasser <michael.brasser@nokia.com>2009-04-22 04:47:24 (GMT)
commit2366667fc97eb6a56203b2dd7dac776ff4164abd (patch)
treeb2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/fx/qfxpathview.cpp
parent2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff)
downloadQt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip
Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz
Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/fx/qfxpathview.cpp')
-rw-r--r--src/declarative/fx/qfxpathview.cpp841
1 files changed, 841 insertions, 0 deletions
diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp
new file mode 100644
index 0000000..79b0f8e
--- /dev/null
+++ b/src/declarative/fx/qfxpathview.cpp
@@ -0,0 +1,841 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <math.h>
+#include <QDebug>
+#include <QPen>
+#include <QEvent>
+#include <gfxeasing.h>
+#include "qmlbindablevalue.h"
+#include "qmlstate.h"
+#include "qlistmodelinterface.h"
+#include "qmlopenmetaobject.h"
+
+#include "qfxpathview.h"
+#include "qfxpathview_p.h"
+#include <QGraphicsSceneEvent>
+#include <QTimer>
+
+static const int FlickThreshold = 5;
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(QFxPathView,PathView);
+
+class QFxPathViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QFxPathViewAttached(QObject *parent)
+ : QObject(parent), mo(new QmlOpenMetaObject(this))
+ {
+ }
+
+ QVariant value(const QByteArray &name) const
+ {
+ return mo->value(name);
+ }
+ void setValue(const QByteArray &name, const QVariant &val)
+ {
+ mo->setValue(name, val);
+ }
+
+private:
+ QmlOpenMetaObject *mo;
+};
+
+
+/*!
+ \internal
+ \class QFxPathView
+ \brief The QFxPathView class lays out items provided by a model on a path.
+
+ \ingroup views
+
+ The model must be a \l QListModelInterface subclass.
+
+ \sa QFxPath
+*/
+
+/*!
+ \qmlclass PathView
+ \brief The PathView element lays out model-provided items on a path.
+ \inherits Item
+
+ The model is typically provided by a QAbstractListModel "C++ model object", but can also be created directly in XML.
+
+ The items are laid out along a path defined by a \l Path and may be flicked to scroll.
+
+ \code
+ <PathView id="pathview" delegate="{contactDelegate}">
+ <resources><Component id="contactDelegate">...</Component></resources>
+ <model>...</model>
+ <path>...</path>
+ </PathView>
+ \endcode
+
+ \image pathview.gif
+
+ \sa Path
+*/
+
+QFxPathView::QFxPathView(QFxItem *parent)
+ : QFxItem(*(new QFxPathViewPrivate), parent)
+{
+ Q_D(QFxPathView);
+ d->init();
+}
+
+QFxPathView::QFxPathView(QFxPathViewPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxPathView);
+ d->init();
+}
+
+QFxPathView::~QFxPathView()
+{
+}
+
+/*!
+ \qmlproperty model PathView::model
+ This property holds the model providing data for the view.
+
+ The model provides a set of data that is used to create the items for the view.
+ For large or dynamic datasets the model is usually provided by a C++ model object.
+ However, models can also be created directly in XML, for example:
+ \code
+<model>
+ <ListModel>
+ <Contact>
+ <portrait>pics/john.png</portrait>
+ <firstName>John</firstName>
+ <lastName>Smith</lastName>
+ </Contact>
+ <Contact>
+ <portrait>pics/bill.png</portrait>
+ <firstName>Bill</firstName>
+ <lastName>Jones</lastName>
+ </Contact>
+ <Contact>
+ <portrait>pics/jane.png</portrait>
+ <firstName>Jane</firstName>
+ <lastName>Doe</lastName>
+ </Contact>
+ </ListModel>
+</model>
+ \endcode
+*/
+
+/*!
+ \property QFxPathView::model
+ \brief the model providing data for the view.
+
+ The model must be either a \l QListModelInterface or
+ \l QFxVisualItemModel subclass.
+*/
+QVariant QFxPathView::model() const
+{
+ Q_D(const QFxPathView);
+ return d->model ? d->model->model() : QVariant();
+}
+
+void QFxPathView::setModel(const QVariant &model)
+{
+ Q_D(QFxPathView);
+ if (QFxVisualItemModel *m = qvariant_cast<QFxVisualItemModel*>(model)) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = m;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel;
+ d->ownModel = true;
+ }
+ d->model->setModel(model);
+ }
+ d->regenerate();
+ d->fixOffset();
+}
+
+/*!
+ \qmlproperty int PathView::count
+ This property holds the number of items in the model.
+*/
+int QFxPathView::count() const
+{
+ Q_D(const QFxPathView);
+ return d->model ? d->model->count() : 0;
+}
+
+/*!
+ \qmlproperty Path PathView::path
+ \default
+ This property holds the path used to lay out the items.
+ For more information see the \l Path documentation.
+*/
+QFxPath *QFxPathView::path() const
+{
+ Q_D(const QFxPathView);
+ return d->path;
+}
+
+void QFxPathView::setPath(QFxPath *path)
+{
+ Q_D(QFxPathView);
+ d->path = path;
+ connect(d->path, SIGNAL(changed()), this, SLOT(refill()));
+ d->regenerate();
+}
+
+/*!
+ \qmlproperty int PathView::currentIndex
+ This property holds the index of the current item.
+*/
+int QFxPathView::currentIndex() const
+{
+ Q_D(const QFxPathView);
+ return d->currentIndex;
+}
+
+void QFxPathView::setCurrentIndex(int idx)
+{
+ Q_D(QFxPathView);
+ if (d->model && d->model->count())
+ idx = qAbs(idx % d->model->count());
+ if (d->model && idx != d->currentIndex) {
+ d->currentIndex = idx;
+ d->snapToCurrent();
+ int itemIndex = (idx - d->firstIndex + d->model->count()) % d->model->count();
+ if(itemIndex < d->items.count())
+ d->items.at(itemIndex)->setFocus(true);
+ emit currentIndexChanged();
+ }
+}
+
+/*!
+ \qmlproperty real PathView::offset
+
+ The offset specifies how far along the path the items are from their initial positions.
+*/
+qreal QFxPathView::offset() const
+{
+ Q_D(const QFxPathView);
+ return d->_offset;
+}
+
+void QFxPathView::setOffset(qreal offset)
+{
+ Q_D(QFxPathView);
+ d->setOffset(offset);
+ d->updateCurrent();
+}
+
+void QFxPathViewPrivate::setOffset(qreal o)
+{
+ Q_Q(QFxPathView);
+ if (_offset != o) {
+ _offset = fmod(o, 100.0);
+ if (_offset < 0)
+ _offset = 100.0 + _offset;
+ q->refill();
+ }
+}
+
+/*!
+ \qmlproperty real PathView::snapPosition
+ This property holds the position (0-100) the current item snaps to.
+*/
+
+/*!
+ \property QFxPathView::snapPosition
+ \brief sets the position (0-100) the current item snaps to.
+
+ This property determines the position the nearest item will snap to.
+*/
+qreal QFxPathView::snapPosition() const
+{
+ Q_D(const QFxPathView);
+ return d->snapPos;
+}
+
+void QFxPathView::setSnapPosition(qreal pos)
+{
+ Q_D(QFxPathView);
+ d->snapPos = pos/100;
+ d->fixOffset();
+}
+
+/*!
+ \qmlproperty real PathView::dragMargin
+ This property holds the maximum distance from the path that initiate mouse dragging.
+
+ By default the path can only be dragged by clicking on an item. If
+ dragMargin is greater than zero, a drag can be initiated by clicking
+ within dragMargin pixels of the path.
+*/
+qreal QFxPathView::dragMargin() const
+{
+ Q_D(const QFxPathView);
+ return d->dragMargin;
+}
+
+void QFxPathView::setDragMargin(qreal dragMargin)
+{
+ Q_D(QFxPathView);
+ d->dragMargin = dragMargin;
+}
+
+/*!
+ \qmlproperty component PathView::delegate
+
+ The delegate provides a template describing what each item in the view should look and act like.
+
+ Here is an example delegate:
+ \code
+ <PathView delegate="{contactDelegate}" ...>
+ <resources>
+ <Component id="contactDelegate">
+ <Item id="wrapper" scale="{PathView.sc}" opacity="{PathView.op}" z="{PathView.z}">
+ <Image id="pic" width="100" height="100" file="{portrait}"
+ anchors.horizontalCenter="{parent.horizontalCenter}"/>
+ <Text id="name" text="{firstName + ' ' + lastName}"
+ font.size="20"
+ anchors.top="{pic.bottom}" anchors.topMargin="5"
+ anchors.horizontalCenter="{parent.horizontalCenter}"/>
+ </Item>
+ </Component>
+ </resources>
+ ...
+ </PathView>
+ \endcode
+*/
+
+/*!
+ \property QFxPathView::delegate
+ \brief the component to use to render the items.
+
+ The delegate is a component that the view will instantiate and destroy
+ as needed to display the items.
+
+*/
+QmlComponent *QFxPathView::delegate() const
+{
+ Q_D(const QFxPathView);
+ return d->model ? d->model->delegate() : 0;
+}
+
+void QFxPathView::setDelegate(QmlComponent *c)
+{
+ Q_D(QFxPathView);
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel;
+ d->ownModel = true;
+ }
+ d->model->setDelegate(c);
+ d->regenerate();
+}
+
+/*!
+ \property QFxPathView::pathItemCount
+ \brief the number of items visible on the path at any one time
+ */
+/*!
+ \qmlproperty int PathView::pathItemCount
+ This property holds the number of items visible on the path at any one time
+*/
+int QFxPathView::pathItemCount() const
+{
+ Q_D(const QFxPathView);
+ return d->pathItems;
+}
+
+void QFxPathView::setPathItemCount(int i)
+{
+ Q_D(QFxPathView);
+ if(i == d->pathItems)
+ return;
+ d->pathItems = i;
+ d->regenerate();
+}
+
+QPointF QFxPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
+{
+ //XXX maybe do recursively at increasing resolution.
+ 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);
+ QPointF diff = pt - point;
+ qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
+ if (dist < mindist) {
+ nearPoint = pt;
+ nearPc = i;
+ mindist = dist;
+ }
+ }
+
+ if (nearPercent)
+ *nearPercent = nearPc / 10.0;
+
+ return nearPoint;
+}
+
+
+void QFxPathView::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxPathView);
+ QPointF scenePoint = mapToScene(event->pos());
+ int idx = 0;
+ for (; idx < d->items.count(); ++idx) {
+ QRectF rect = d->items.at(idx)->boundingRect();
+ rect = d->items.at(idx)->mapToScene(rect);
+ if (rect.contains(scenePoint))
+ break;
+ }
+ if (idx == d->items.count() && d->dragMargin == 0.) // didn't click on an item
+ return;
+
+ d->startPoint = d->pointNear(event->pos(), &d->startPc);
+ if (idx == d->items.count()) {
+ qreal distance = qAbs(event->pos().x() - d->startPoint.x()) + qAbs(event->pos().y() - d->startPoint.y());
+ if (distance > d->dragMargin)
+ return;
+ }
+
+ d->stealMouse = false;
+ d->lastElapsed = 0;
+ d->lastDist = 0;
+ d->lastPosTime.start();
+ d->tl.clear();
+}
+
+void QFxPathView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxPathView);
+ if (d->lastPosTime.isNull())
+ return;
+
+ if (!d->stealMouse) {
+ QPointF delta = event->pos() - d->startPoint;
+ if (qAbs(delta.x()) > FlickThreshold && qAbs(delta.y()) > FlickThreshold)
+ d->stealMouse = true;
+ }
+
+ if (d->stealMouse) {
+ d->moveReason = QFxPathViewPrivate::Mouse;
+ qreal newPc;
+ d->pointNear(event->pos(), &newPc);
+ qreal diff = newPc - d->startPc;
+ if (diff) {
+ setOffset(d->_offset + diff);
+
+ if (diff > 50)
+ diff -= 100;
+ else if (diff < -50)
+ diff += 100;
+
+ d->lastElapsed = d->lastPosTime.restart();
+ d->lastDist = diff;
+ d->startPc = newPc;
+ }
+ }
+}
+
+void QFxPathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_D(QFxPathView);
+ if (d->lastPosTime.isNull())
+ return;
+
+ qreal elapsed = qreal(d->lastElapsed + d->lastPosTime.elapsed()) / 1000.;
+ qreal velocity = elapsed > 0. ? d->lastDist / elapsed : 0;
+ if (d->model && d->model->count() && qAbs(velocity) > 5) {
+ if (velocity > 100)
+ velocity = 100;
+ else if (velocity < -100)
+ velocity = -100;
+ qreal inc = fmod(d->_offset - d->snapPos, 100.0 / d->model->count());
+ qreal dist = qAbs(velocity/2 - fmod(velocity/2, 100.0 / d->model->count()) - inc);
+ d->moveOffset.setValue(d->_offset);
+ d->tl.accel(d->moveOffset, velocity, 10, dist);
+ d->tl.execute(d->fixupOffsetEvent);
+ } else {
+ d->fixOffset();
+ }
+
+ d->lastPosTime = QTime();
+ d->stealMouse = false;
+}
+
+bool QFxPathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxPathView);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height()));
+ QFxItem *grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if ((d->stealMouse || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if (grabber && d->stealMouse && !grabber->keepMouseGrab())
+ mouseGrabberItem()->ungrabMouse();
+
+ return d->stealMouse;
+ } else if (!d->lastPosTime.isNull()) {
+ d->lastPosTime = QTime();
+ }
+ return false;
+}
+
+bool QFxPathView::mouseFilter(QGraphicsSceneMouseEvent *e)
+{
+ if(!isVisible())
+ return false;
+
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ {
+ bool ret = sendMouseEvent(e);
+ if (e->type() == QEvent::GraphicsSceneMouseRelease)
+ return ret;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void QFxPathViewPrivate::regenerate()
+{
+ Q_Q(QFxPathView);
+ if (!model || model->count() <= 0 || !model->delegate() || !path)
+ return;
+
+ for(int i=0; i<items.count(); i++){
+ QFxItem *p = items[i];
+ q->attachedProperties.remove(p);
+ model->release(p);
+ }
+ items.clear();
+
+ firstIndex = 0;
+ pathOffset = 0;
+
+ int numItems = (pathItems>=0 ? pathItems : model->count());
+ qreal minDiff = 1e9;
+ int minI = -1;
+ for(int i=0; i<numItems; i++){
+ QFxItem *item = model->item(i);
+ items.append(item);
+ item->setZ(i);
+ item->setParent(q);
+ qreal percent = i * (100.0 / (numItems));
+ percent /= 100.0;
+ updateItem(items.last(), percent);
+ qreal diff = qAbs(percent - snapPos);
+ if(diff < minDiff){
+ minDiff = diff;
+ minI = i;
+ }
+ }
+ q->setCurrentIndex(minI);
+
+ q->refill();
+}
+
+void QFxPathViewPrivate::updateItem(QFxItem *item, qreal percent)
+{
+ if(QObject *obj = QFxPathView::attachedProperties.value(item)) {
+ foreach(QString attr, path->attributes())
+ static_cast<QFxPathViewAttached *>(obj)->setValue(attr.toLatin1(), path->attributeAt(attr, percent));
+ }
+
+ QPointF pf = path->pointAt(percent);
+ item->setX(pf.x() - item->width()*item->scale()/2);
+ item->setY(pf.y() - item->height()*item->scale()/2);
+}
+
+void QFxPathView::refill()
+{
+ Q_D(QFxPathView);
+ if (!d->model || d->model->count() <= 0)
+ return;
+
+ QList<qreal> positions;
+ for(int i=0; i<d->items.count(); i++){
+ qreal percent = i * (100. / d->items.count());
+ percent = percent + d->_offset;
+ percent = fmod(percent,100.);
+ positions << qAbs(percent/100.0);
+ }
+
+ if(d->pathItems==-1){
+ for(int i=0; i<positions.count(); i++){
+ d->updateItem(d->items.at(i), positions[i]);
+ }
+ return;
+ }
+
+ QList<qreal> rotatedPositions;
+ for(int i=0; i<d->items.count(); i++)
+ rotatedPositions << positions[(i + d->pathOffset + d->items.count()) % d->items.count()];
+
+ int firstFind = -1;
+ int i;
+ for(i=0; i<d->items.count()-1; i++)
+ {
+ if(rotatedPositions[i] > rotatedPositions[i+1]){
+ firstFind = i;
+ break;
+ }
+ }
+ if(firstFind!=-1 ){
+ //A wraparound has occured
+ if(firstFind<(d->items.count()/2)){
+ while(firstFind-- >= 0){
+ QFxItem* p = d->items.takeFirst();
+ attachedProperties.remove(p);
+ d->model->release(p);
+ d->firstIndex++;
+ d->firstIndex%=d->model->count();
+ int index = (d->firstIndex + d->items.count())%d->model->count();
+ d->items << d->model->item(index);
+ d->items.last()->setZ(i);
+ d->items.last()->setParent(this);
+ d->pathOffset++;
+ d->pathOffset=d->pathOffset % d->items.count();
+ }
+ }else{
+ while(firstFind++ < (d->items.count()-1)){
+ QFxItem* p = d->items.takeLast();
+ attachedProperties.remove(p);
+ d->model->release(p);
+ d->firstIndex--;
+ if(d->firstIndex<0)
+ d->firstIndex = d->model->count() - 1;
+ d->items.prepend(d->model->item(d->firstIndex));
+ d->items.first()->setZ(d->firstIndex);
+ d->items.first()->setParent(this);
+ d->pathOffset--;
+ if(d->pathOffset<0)
+ d->pathOffset = d->items.count() - 1;
+ }
+ }
+ for(int i=0; i<d->items.count(); i++)
+ rotatedPositions[i] = positions[(i + d->pathOffset + d->items.count())
+ % d->items.count()];
+ }
+ for(int i=0; i<d->items.count(); i++){
+ d->updateItem(d->items.at(i), rotatedPositions[i]);
+ }
+}
+
+void QFxPathView::ticked()
+{
+ Q_D(QFxPathView);
+ d->updateCurrent();
+}
+
+// find the item closest to the snap position
+int QFxPathViewPrivate::calcCurrentIndex()
+{
+ int current = -1;
+ if (model && items.count()) {
+ _offset = fmod(_offset, 100.0);
+ if(_offset < 0)
+ _offset += 100.0;
+
+ if(pathItems == -1){
+ qreal delta = fmod(_offset - snapPos, 100.0);
+ if (delta < 0)
+ delta = 100.0 + delta;
+ int ii = model->count() - qRound(delta * model->count() / 100);
+ if(ii < 0)
+ ii = 0;
+ current = ii;
+ }else{
+ qreal bestDiff=1e9;
+ int bestI=-1;
+ for(int i=0; i<items.count(); i++){
+ qreal percent = i * (100. / items.count());
+ percent = percent + _offset;
+ percent = fmod(percent,100.);
+ qreal diff = qAbs(snapPos - (percent/100.0));
+ if(diff < bestDiff){
+ bestDiff = diff;
+ bestI = i;
+ }
+ }
+ int modelIndex = (bestI - pathOffset + items.count())%items.count();
+ modelIndex += firstIndex;
+ current = modelIndex;
+ }
+ current = qAbs(current % model->count());
+ }
+
+ return current;
+}
+
+void QFxPathViewPrivate::updateCurrent()
+{
+ Q_Q(QFxPathView);
+ if (moveReason != Mouse)
+ return;
+ int idx = calcCurrentIndex();
+ if (model && idx != currentIndex) {
+ currentIndex = idx;
+ int itemIndex = (idx - firstIndex + model->count()) % model->count();
+ if(itemIndex < items.count())
+ items.at(itemIndex)->setFocus(true);
+ emit q->currentIndexChanged();
+ }
+}
+
+void QFxPathViewPrivate::fixOffset()
+{
+ Q_Q(QFxPathView);
+ if (model && items.count()) {
+ int curr = calcCurrentIndex();
+ if (curr != currentIndex)
+ q->setCurrentIndex(curr);
+ else
+ snapToCurrent();
+ }
+}
+
+void QFxPathViewPrivate::snapToCurrent()
+{
+ if (!model || model->count() <= 0)
+ return;
+
+ int itemIndex = (currentIndex - firstIndex + model->count())%model->count();
+
+ //Rounds is the number of times round to make the current item visible
+ int rounds = itemIndex / items.count();
+ int otherWayRounds = (model->count() - (itemIndex))/items.count() + 1;
+ if(otherWayRounds < rounds)
+ rounds = -otherWayRounds;
+
+ itemIndex += pathOffset;
+ itemIndex %= items.count();
+ qreal targetOffset = fmod(100 + (snapPos*100) - 100.0 * itemIndex / items.count(), 100);
+
+ if (targetOffset < 0)
+ targetOffset = 100.0 + targetOffset;
+ if (targetOffset == _offset && rounds==0)
+ return;
+
+ moveReason = Other;
+ tl.clear();
+ moveOffset.setValue(_offset);
+
+ if(rounds!=0){
+ //Compensate if the targetOffset would bring the target it from off the screen
+ qreal distance = targetOffset - _offset;
+ if(distance <= -50)
+ rounds--;
+ if(distance > 50)
+ rounds++;
+ tl.move(moveOffset, targetOffset + 100.0*(-rounds), GfxEasing(GfxEasing::InOutQuad),
+ int(100*items.count()*qMax((qreal)(2.0/items.count()),(qreal)qAbs(rounds))));
+ tl.execute(fixupOffsetEvent);
+ return;
+ }
+
+ if (targetOffset - _offset > 50.0) {
+ qreal distance = 100 - targetOffset + _offset;
+ tl.move(moveOffset, 0.0, GfxEasing(GfxEasing::OutQuad), int(200 * _offset / distance));
+ tl.set(moveOffset, 100.0);
+ tl.move(moveOffset, targetOffset, GfxEasing(GfxEasing::InQuad), int(200 * (100-targetOffset) / distance));
+ } else if (targetOffset - _offset <= -50.0) {
+ qreal distance = 100 - _offset + targetOffset;
+ tl.move(moveOffset, 100.0, GfxEasing(GfxEasing::OutQuad), int(200 * (100-_offset) / distance));
+ tl.set(moveOffset, 0.0);
+ tl.move(moveOffset, targetOffset, GfxEasing(GfxEasing::InQuad), int(200 * targetOffset / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, GfxEasing(GfxEasing::InOutQuad), 200);
+ }
+}
+
+QHash<QObject*, QObject*> QFxPathView::attachedProperties;
+QObject *QFxPathView::qmlAttachedProperties(QObject *obj)
+{
+ if(!attachedProperties.contains(obj)) {
+ QFxPathViewAttached *rv = new QFxPathViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return attachedProperties.value(obj);
+}
+
+QT_END_NAMESPACE
+
+#include "qfxpathview.moc"