ganeswidgets/src/hgspring.cpp
changeset 13 8bf920201dea
parent 5 4fa04caf0f43
child 19 31a1a9e11046
--- a/ganeswidgets/src/hgspring.cpp	Tue Jul 06 15:29:26 2010 +0300
+++ b/ganeswidgets/src/hgspring.cpp	Wed Aug 18 10:52:49 2010 +0300
@@ -21,7 +21,7 @@
 
 const int KTimeDelta(10);
 const qreal KTimeDeltaF(0.01f);
-//const qreal KVelocitySnap(0.05f);
+const qreal KVelocitySnap(0.06f);
 const qreal KPositionSnap(0.01f);
 const int KTimerInterval(10);
 
@@ -29,11 +29,13 @@
 mStartPos(QPointF(0,0)),
 mPos(QPointF(0,0)),
 mEndPos(QPointF(0,0)),
+mEndPosOverListBoundary(QPointF(0,0)),
 mVelocity(QPointF(0,0)),
 mK(30.1),
 mDamping(10.1),
 mAccumulator(0.0),
-mDoNotUpdate(false)
+mDoNotUpdate(false),
+mEndPosOverListEdge(false)
 {
     mTimer = new QTimer(this);
 
@@ -56,8 +58,24 @@
     mDamping = damping;
 }
 
+qreal HgSpring::k() const
+{
+    return mK;
+}
+
+qreal HgSpring::damping() const
+{
+    return mDamping;
+}
+
+// TODO: Remove this function and use only the animateToPosAfterPanning version?
 void HgSpring::animateToPos(const QPointF& pos)
-{
+{    
+    if (mPos == pos) {
+        // No need to animate, we are already in correct position.
+        return;
+    }
+            
     mStartPos = mPos;
     mEndPos = pos;
 
@@ -70,6 +88,39 @@
     }
 }
 
+void HgSpring::animateToPosAfterPanning(const QPointF& pos, qreal worldWidth)
+{    
+    mWorldWidth = worldWidth;
+    mStartPos = mPos;
+    
+    qreal xPos = pos.x();
+    if( xPos < 0.0 )
+    {
+        mEndPosOverListEdge = true;
+        mEndPosOverListBoundary = pos;
+        mEndPos = QPointF(0, 0);
+    }
+    else if( xPos > worldWidth )
+    {
+        mEndPosOverListEdge = true;
+        mEndPosOverListBoundary = pos;
+        mEndPos = QPointF(worldWidth, 0);
+    }
+    else
+    {
+        mEndPosOverListEdge = false;
+        mEndPos = pos;
+    }
+
+    emit started();
+
+    if (!mTimer->isActive())
+    {
+        mTimer->start(KTimerInterval);
+        mPrevTime.start();
+    }
+}
+
 void HgSpring::gotoPos(const QPointF& pos)
 {
     if (mTimer->isActive())
@@ -122,12 +173,36 @@
     bool stopped = false;
     while (mAccumulator >= KTimeDelta)
     {
-        QPointF delta = mEndPos - mPos;
+        QPointF delta;
+        if(mEndPosOverListEdge)
+        {
+            delta = mEndPosOverListBoundary - mPos;
+            
+            if( mPos.x() < KPositionSnap || mPos.x() > mWorldWidth )
+            {
+                // When list's position goes past the world boundary
+                // we reset our mEndPosOverListEdge boolean flag
+                // -> the passed boundary will be used as end point,
+                // and the K value of this spring will be modified.
+                mEndPosOverListEdge = false; //reset
+                mEndPosOverListBoundary = QPointF(0,0); //reset
+                mWorldWidth = 0.0; //reset
+                mK = 60.0;
+            }
+            
+        }
+        else
+        {
+            delta = mEndPos - mPos;
+        }
+        
         QPointF force = delta * mK - mVelocity * mDamping;
         mVelocity += force * KTimeDeltaF;
         mPos += mVelocity * KTimeDeltaF;
+        
         if ( (qAbs(mPos.x() - mEndPos.x()) < KPositionSnap &&
-              qAbs(mPos.y() - mEndPos.y()) < KPositionSnap) )
+                  qAbs(mPos.y() - mEndPos.y()) < KPositionSnap)
+             && qAbs(mVelocity.x()) < KVelocitySnap )
         {
             mPos = mEndPos;
             mAccumulator = 0;
@@ -139,7 +214,7 @@
 
         mAccumulator -= KTimeDelta;
     }
-
+    
     if (!mDoNotUpdate)
         emit updated();