19 #include <QTimer> |
19 #include <QTimer> |
20 #include "trace.h" |
20 #include "trace.h" |
21 |
21 |
22 const int KTimeDelta(10); |
22 const int KTimeDelta(10); |
23 const qreal KTimeDeltaF(0.01f); |
23 const qreal KTimeDeltaF(0.01f); |
24 //const qreal KVelocitySnap(0.05f); |
24 const qreal KVelocitySnap(0.06f); |
25 const qreal KPositionSnap(0.01f); |
25 const qreal KPositionSnap(0.01f); |
26 const int KTimerInterval(10); |
26 const int KTimerInterval(10); |
27 |
27 |
28 HgSpring::HgSpring() : |
28 HgSpring::HgSpring() : |
29 mStartPos(QPointF(0,0)), |
29 mStartPos(QPointF(0,0)), |
30 mPos(QPointF(0,0)), |
30 mPos(QPointF(0,0)), |
31 mEndPos(QPointF(0,0)), |
31 mEndPos(QPointF(0,0)), |
|
32 mEndPosOverListBoundary(QPointF(0,0)), |
32 mVelocity(QPointF(0,0)), |
33 mVelocity(QPointF(0,0)), |
33 mK(30.1), |
34 mK(30.1), |
34 mDamping(10.1), |
35 mDamping(10.1), |
35 mAccumulator(0.0), |
36 mAccumulator(0.0), |
36 mDoNotUpdate(false) |
37 mDoNotUpdate(false), |
|
38 mEndPosOverListEdge(false) |
37 { |
39 { |
38 mTimer = new QTimer(this); |
40 mTimer = new QTimer(this); |
39 |
41 |
40 QObject::connect( mTimer, SIGNAL( timeout() ), this, SLOT( update() ) ); |
42 QObject::connect( mTimer, SIGNAL( timeout() ), this, SLOT( update() ) ); |
41 |
43 |
54 void HgSpring::setDamping(qreal damping) |
56 void HgSpring::setDamping(qreal damping) |
55 { |
57 { |
56 mDamping = damping; |
58 mDamping = damping; |
57 } |
59 } |
58 |
60 |
|
61 qreal HgSpring::k() const |
|
62 { |
|
63 return mK; |
|
64 } |
|
65 |
|
66 qreal HgSpring::damping() const |
|
67 { |
|
68 return mDamping; |
|
69 } |
|
70 |
|
71 // TODO: Remove this function and use only the animateToPosAfterPanning version? |
59 void HgSpring::animateToPos(const QPointF& pos) |
72 void HgSpring::animateToPos(const QPointF& pos) |
60 { |
73 { |
|
74 if (mPos == pos) { |
|
75 // No need to animate, we are already in correct position. |
|
76 return; |
|
77 } |
|
78 |
61 mStartPos = mPos; |
79 mStartPos = mPos; |
62 mEndPos = pos; |
80 mEndPos = pos; |
|
81 |
|
82 emit started(); |
|
83 |
|
84 if (!mTimer->isActive()) |
|
85 { |
|
86 mTimer->start(KTimerInterval); |
|
87 mPrevTime.start(); |
|
88 } |
|
89 } |
|
90 |
|
91 void HgSpring::animateToPosAfterPanning(const QPointF& pos, qreal worldWidth) |
|
92 { |
|
93 mWorldWidth = worldWidth; |
|
94 mStartPos = mPos; |
|
95 |
|
96 qreal xPos = pos.x(); |
|
97 if( xPos < 0.0 ) |
|
98 { |
|
99 mEndPosOverListEdge = true; |
|
100 mEndPosOverListBoundary = pos; |
|
101 mEndPos = QPointF(0, 0); |
|
102 } |
|
103 else if( xPos > worldWidth ) |
|
104 { |
|
105 mEndPosOverListEdge = true; |
|
106 mEndPosOverListBoundary = pos; |
|
107 mEndPos = QPointF(worldWidth, 0); |
|
108 } |
|
109 else |
|
110 { |
|
111 mEndPosOverListEdge = false; |
|
112 mEndPos = pos; |
|
113 } |
63 |
114 |
64 emit started(); |
115 emit started(); |
65 |
116 |
66 if (!mTimer->isActive()) |
117 if (!mTimer->isActive()) |
67 { |
118 { |
120 mAccumulator += deltaTime; |
171 mAccumulator += deltaTime; |
121 |
172 |
122 bool stopped = false; |
173 bool stopped = false; |
123 while (mAccumulator >= KTimeDelta) |
174 while (mAccumulator >= KTimeDelta) |
124 { |
175 { |
125 QPointF delta = mEndPos - mPos; |
176 QPointF delta; |
|
177 if(mEndPosOverListEdge) |
|
178 { |
|
179 delta = mEndPosOverListBoundary - mPos; |
|
180 |
|
181 if( mPos.x() < KPositionSnap || mPos.x() > mWorldWidth ) |
|
182 { |
|
183 // When list's position goes past the world boundary |
|
184 // we reset our mEndPosOverListEdge boolean flag |
|
185 // -> the passed boundary will be used as end point, |
|
186 // and the K value of this spring will be modified. |
|
187 mEndPosOverListEdge = false; //reset |
|
188 mEndPosOverListBoundary = QPointF(0,0); //reset |
|
189 mWorldWidth = 0.0; //reset |
|
190 mK = 60.0; |
|
191 } |
|
192 |
|
193 } |
|
194 else |
|
195 { |
|
196 delta = mEndPos - mPos; |
|
197 } |
|
198 |
126 QPointF force = delta * mK - mVelocity * mDamping; |
199 QPointF force = delta * mK - mVelocity * mDamping; |
127 mVelocity += force * KTimeDeltaF; |
200 mVelocity += force * KTimeDeltaF; |
128 mPos += mVelocity * KTimeDeltaF; |
201 mPos += mVelocity * KTimeDeltaF; |
|
202 |
129 if ( (qAbs(mPos.x() - mEndPos.x()) < KPositionSnap && |
203 if ( (qAbs(mPos.x() - mEndPos.x()) < KPositionSnap && |
130 qAbs(mPos.y() - mEndPos.y()) < KPositionSnap) ) |
204 qAbs(mPos.y() - mEndPos.y()) < KPositionSnap) |
|
205 && qAbs(mVelocity.x()) < KVelocitySnap ) |
131 { |
206 { |
132 mPos = mEndPos; |
207 mPos = mEndPos; |
133 mAccumulator = 0; |
208 mAccumulator = 0; |
134 mVelocity = QPointF(0,0); |
209 mVelocity = QPointF(0,0); |
135 mTimer->stop(); |
210 mTimer->stop(); |