Changed indicator bg color.
[platform/framework/native/uifw.git] / src / ui / controls / FUiCtrl_FlickAnimation.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FUiCtrl_FlickAnimation.cpp
20  * @brief   This is the implementation file for _FlickAnimation class.
21  *
22  * This file contains the implementation of _FlickAnimation class.
23  */
24
25 #include <FBaseSysLog.h>
26 #include "FUiCtrl_FlickAnimation.h"
27
28 #ifdef MEMORY_LEAK_CHECK
29 #include "mem_leak_check.h"
30 #endif
31
32 namespace Tizen { namespace Ui { namespace Controls
33 {
34 // Defined Parameter
35 const int FLK_REF_RESOL_PXL[2] = {480, 800};    // Reference Pixel
36
37 enum
38 {
39         _X = 0,
40         _Y = 1
41 };
42
43
44 _FlickAnimation::_FlickAnimation(void)
45 {
46         __flickDirection = FD_VERTICAL;
47
48         __dimension[_X] = 0;    // 42
49         __dimension[_Y] = 0;    // 70
50
51         __resolution[_X] = 240;
52         __resolution[_Y] = 320;
53
54         __align[_X] = __resolution[_X] / FLK_ANI_DEFAULT_ALIGN_RATIO;
55         __align[_Y] = __resolution[_Y] / FLK_ANI_DEFAULT_ALIGN_RATIO;
56
57         __margin[_X] = 0;
58         __margin[_Y] = 0;
59
60         __flickAnimationFPS = 25;
61         __flickAnimationFPSRef = 20;
62         __flickAnimaionTimeMin = FLK_ANI_TIME_MIN_MSEC * __flickAnimationFPS / 1000;
63         __flickAnimationTimeMax = FLK_ANI_TIME_MAX_MSEC * __flickAnimationFPS / 1000;
64
65         __friction[_X] = 10;
66         __friction[_Y] = 10;
67         __velocity[_X] = 0;
68         __velocity[_Y] = 0;
69
70         __frictionMin[_X] = 5;
71         __frictionMin[_Y] = 5;
72         __velocityMin[_X] = 0;
73         __velocityMin[_Y] = 0;
74
75         __acceleration[_X] = 0;
76         __acceleration[_Y] = 0;
77         __drawCount = 0;
78
79         __tensionStatus[_X] = TENSION_DONE;
80         __tensionStatus[_Y] = TENSION_DONE;
81         __tensionDistMax[_X] = 0;
82         __tensionDistMax[_Y] = 0;
83 }
84
85 _FlickAnimation::~_FlickAnimation(void)
86 {
87 }
88
89 void
90 _FlickAnimation::SetSizeInformation(int resW, int resH, int mmW, int mmH)
91 {
92         if (resW > 0 && resH > 0 && mmW > 0 && mmH > 0)
93         {
94                 __resolution[_X] = resW;
95                 __resolution[_Y] = resH;
96
97                 __dimension[_X] = mmW;
98                 __dimension[_Y] = mmH;
99         }
100 }
101
102 void
103 _FlickAnimation::SetAlignInformation(int alignW, int alignH)
104 {
105         // Align Value < 0 then Resolution * 1/n
106         if (alignW > 0)
107         {
108                 __align[_X] = alignW;
109         }
110         else
111         {
112                 __align[_X] = __resolution[_X] / FLK_ANI_DEFAULT_ALIGN_RATIO;
113         }
114
115         if (alignH > 0)
116         {
117                 __align[_Y] = alignH;
118         }
119         else
120         {
121                 __align[_Y] = __resolution[_Y] / FLK_ANI_DEFAULT_ALIGN_RATIO;
122         }
123
124         // set Margin
125         __margin[_X] = __align[_X] / 20;
126         __margin[_Y] = __align[_Y] / 20;
127 }
128
129 // sensitivity increases, the larger the distance but, less than fps.
130 void
131 _FlickAnimation::SetSensitivity(int fps, int sensitivity)
132 {
133         if (fps > 0)
134         {
135                 __flickAnimationFPS = fps;
136
137                 // max sensitivity is fps
138                 if (0 < sensitivity && sensitivity < fps)
139                 {
140                         __flickAnimationFPSRef = sensitivity;
141                 }
142                 else
143                 {
144                         __flickAnimationFPSRef = fps;
145                 }
146
147                 // Update
148                 __flickAnimaionTimeMin = FLK_ANI_TIME_MIN_MSEC * __flickAnimationFPS / 1000;
149                 __flickAnimationTimeMax = FLK_ANI_TIME_MAX_MSEC * __flickAnimationFPS / 1000;
150         }
151 }
152
153 void
154 _FlickAnimation::SetDirection(int dir)
155 {
156         __flickDirection = dir;
157 }
158
159 void
160 _FlickAnimation::SetTensionEnable(bool enableX, bool enableY)
161 {
162         if (enableX)
163         {
164                 __tensionStatus[_X] = TENSION_DONE;
165         }
166         else
167         {
168                 __tensionStatus[_X] = TENSION_NA;
169         }
170
171         if (enableY)
172         {
173                 __tensionStatus[_Y] = TENSION_DONE;
174         }
175         else
176         {
177                 __tensionStatus[_Y] = TENSION_NA;
178         }
179 }
180
181 bool
182 _FlickAnimation::IsItemExecutable(int flickX, int flickY)
183 {
184         bool returnValue = (__velocity[_X] == 0 && __velocity[_Y] == 0 && flickX == 0 && flickY == 0);
185
186         return returnValue;
187 }
188
189 void
190 _FlickAnimation::CalculateInitializeVelocity(int flickX, int flickY, int flickTime, int* pFlkVelX, int* pFlkVelY)
191 {
192         if (flickTime < 1)  // {{110726 lsw2000}} Prevent 'Divide by 0'
193         {
194                 flickTime = 1;
195         }
196
197         // Calculateulate Velocity
198         int velX = flickX * 1000 / flickTime;                             // in pixel unit
199         int velY = flickY * 1000 / flickTime;                             // in pixel unit
200 //  int velX = flickX * 1000/flickTime * m_nMmW/m_nResW;        // in mm unit
201 //  int velY = flickY * 1000/flickTime * m_nMmH/m_nResH;        // in mm unit
202
203         // Calculateulate Flick Amount using velocity and distance
204         // (input in mm) = (input in pixel) * (mm/resolution)
205         // (output in pixel) = (input in mm) * (alpha * resolution) <= (alpha = pixel output per mm input depends on resoultion)
206         // then (output in pixel) = (input in pixel) * (mm) * (alpha)
207 //  *pFlkVelX = (velX*FLK_WEIGHT_VEL + flickX*FLK_WEIGHT_DIST)*m_nMmW/FLK_ALPHA_PER_MM;
208 //  *pFlkVelY = (velY*FLK_WEIGHT_VEL + flickY*FLK_WEIGHT_DIST)*m_nMmH/FLK_ALPHA_PER_MM;
209         *pFlkVelX = (velX * FLK_WEIGHT_VEL + flickX * FLK_WEIGHT_DIST) / FLK_ALPHA_PER_PIXEL;
210         *pFlkVelY = (velY * FLK_WEIGHT_VEL + flickY * FLK_WEIGHT_DIST) / FLK_ALPHA_PER_PIXEL;
211 }
212
213 int
214 _FlickAnimation::EstimateInitializeVelocity(int totalDist, int idx)
215 {
216         int flkVel = 0;
217         int vel = 0;
218         bool minusFlag = (totalDist < 0);
219         totalDist = ((totalDist < 0) ? (-totalDist) : (totalDist));
220
221         // totalDist => vel => FlkVel
222         int velMax = __align[idx] * 2 / 3 * __flickAnimationFPSRef;
223         int distMax = velMax / __flickAnimationFPS;
224         int thres1 = distMax * __flickAnimaionTimeMin / 2;
225         int thres2 = distMax * __flickAnimationTimeMax / 2;
226
227         if (totalDist < thres1)
228         {
229                 int velMin = velMax / FLK_ANI_SPEED_MIN_RATIO;
230                 vel = totalDist * __flickAnimationFPS * 2 / __flickAnimaionTimeMin;
231                 flkVel = (vel - velMin) * (FLK_SPEED_THRES1 - FLK_SPEED_MIN) / (velMax - velMin) + FLK_SPEED_MIN;
232         }
233         else if (totalDist < thres2)
234         {
235                 flkVel = (totalDist * 2 / distMax - __flickAnimaionTimeMin)
236                                  * (FLK_SPEED_THRES2 - FLK_SPEED_THRES1) / (__flickAnimationTimeMax - __flickAnimaionTimeMin) + FLK_SPEED_THRES1;
237         }
238         else
239         {
240                 int totalDistRemain = totalDist - thres2;
241                 int alpha = __align[idx] * (FLK_ANI_OVERSPEED_END_CNT - FLK_ANI_OVERSPEED_START_CNT - 1);
242                 int accel = (totalDistRemain + alpha / 2) / alpha;
243                 flkVel = FLK_SPEED_THRES2 + accel * FLK_OVERSPEED_STEP;
244         }
245
246         if (minusFlag)
247         {
248                 flkVel *= -1;
249         }
250
251         return flkVel;
252 }
253
254 // Set Flick Animation Variables from Flick Algorithm result
255 void
256 _FlickAnimation::InitializeFlickAmount(int flkVelX, int flkVelY)
257 {
258         InitializeFlick(flkVelX, flkVelY);
259 }
260
261 void
262 _FlickAnimation::InitializeFlickAmount(int flkVel)
263 {
264         switch (__flickDirection)
265         {
266         case FD_VERTICAL:
267                 InitializeFlick(0, flkVel);
268                 break;
269
270         case FD_HORIZONTAL:
271                 InitializeFlick(flkVel, 0);
272                 break;
273
274         default:
275                 // Error!!!
276                 break;
277         }
278 }
279
280 void
281 _FlickAnimation::InitializeFlick(int flkVelX, int flkVelY)
282 {
283         InitializeTension();
284
285         __acceleration[_X] = 0;
286         __acceleration[_Y] = 0;
287         __drawCount = 0;
288
289         if (flkVelX == 0 && flkVelY == 0)
290         {
291                 __velocity[_X] = 0;
292                 __velocity[_Y] = 0;
293                 return;
294         }
295
296         if (flkVelY == 0)
297         {
298                 __velocity[_Y] = 0;
299                 if (__flickDirection == FD_VERTICAL)
300                 {
301                         return;
302                 }
303         }
304         else
305         {
306                 InitializeFlickXY(flkVelY, _Y);
307         }
308
309         if (flkVelX == 0)
310         {
311                 __velocity[_X] = 0;
312
313                 if (__flickDirection == FD_HORIZONTAL)
314                 {
315                         return;
316                 }
317         }
318         else
319         {
320                 InitializeFlickXY(flkVelX, _X);
321         }
322 }
323
324 void
325 _FlickAnimation::InitializeFlickXY(int flkVel, int idx)
326 {
327         bool minusFlag = (flkVel < 0);
328         flkVel = ((flkVel < 0) ? (-flkVel) : (flkVel));
329
330         if (flkVel < FLK_SPEED_MIN)
331         {
332                 flkVel = FLK_SPEED_MIN;
333         }
334
335         //  calculate __velocity & __friction based on FlkVel
336         /**************************************************************************
337           FlkVel                        |   Vmin ~ Vth1 |   Vth1 ~ Vth2 |   > Vth2
338           __velocity            |   0 ~ velMax  |   velMax      |   velMax + Accel
339           Time                          |   Tmin                |   Tmin ~ Tmax |   Tmax
340           __acceleration        |   0                   |   0                   |   (flkVel-Vth2)/Step
341          **************************************************************************/
342         int velMax = __align[idx] * 2 / 3 * __flickAnimationFPSRef;
343
344         if (flkVel < FLK_SPEED_THRES1)
345         {
346                 int velMin = velMax / FLK_ANI_SPEED_MIN_RATIO;
347                 __velocity[idx] = (flkVel - FLK_SPEED_MIN) * (velMax - velMin) / (FLK_SPEED_THRES1 - FLK_SPEED_MIN) + velMin;
348                 __friction[idx] = __velocity[idx] / __flickAnimaionTimeMin;
349         }
350         else if (flkVel < FLK_SPEED_THRES2)
351         {
352                 __velocity[idx] = velMax;
353                 __friction[idx] = velMax /
354                                                   ((__flickAnimationTimeMax -
355                                                         __flickAnimaionTimeMin) *
356                                                    (flkVel - FLK_SPEED_THRES1) / (FLK_SPEED_THRES2 - FLK_SPEED_THRES1) + __flickAnimaionTimeMin);
357         }
358         else
359         {
360                 __velocity[idx] = velMax;
361                 __friction[idx] = velMax / __flickAnimationTimeMax;
362                 __acceleration[idx] = (flkVel - FLK_SPEED_THRES2 + FLK_OVERSPEED_STEP / 2) / FLK_OVERSPEED_STEP;
363         }
364
365         if (minusFlag)
366         {
367                 __velocity[idx] *= -1;
368                 __acceleration[idx] *= -1;
369         }
370
371         // calculate Minimum Velocity, Friction for slowdown
372         int deltaMin = 8 * __flickAnimationFPSRef / __flickAnimationFPS * __resolution[idx] / FLK_REF_RESOL_PXL[idx];
373         __velocityMin[idx] = deltaMin * __flickAnimationFPS;
374         __frictionMin[idx] = velMax / __flickAnimationTimeMax * 1 / 2;
375
376         if (__frictionMin[idx] > __friction[idx])
377         {
378                 __frictionMin[idx] = __friction[idx];
379         }
380
381         if (__friction[idx] == 0)
382         {
383                 __friction[idx] = 1;
384         }
385 }
386
387 // Return next step distance and update Velocity.
388 int
389 _FlickAnimation::CalculateNextMove(int* pMoveX, int* pMoveY)
390 {
391         *pMoveX = CalculateNextMoveXY(_X);
392         *pMoveY = CalculateNextMoveXY(_Y);
393
394         __drawCount++;
395
396         if (*pMoveX == 0 && *pMoveY == 0)
397         {
398                 return 0;
399         }
400         else
401         {
402                 return 1;
403         }
404 }
405
406 int
407 _FlickAnimation::CalculateNextMove(void)
408 {
409         int moved = 0;
410
411         switch (__flickDirection)
412         {
413         case FD_VERTICAL:
414                 moved = CalculateNextMoveXY(_Y);
415                 break;
416
417         case FD_HORIZONTAL:
418                 moved = CalculateNextMoveXY(_X);
419                 break;
420
421         default:
422                 // Error!!!
423                 return 0;
424         }
425         __drawCount++;
426
427         return moved;
428 }
429
430 int
431 _FlickAnimation::CalculateNextMoveXY(int idx)
432 {
433         if (__velocity[idx] == 0)
434         {
435                 return 0;
436         }
437
438         int delta = __velocity[idx] / __flickAnimationFPS;
439
440         // removal reverse Flick effect
441         if (delta >= __align[idx] / 2 - __margin[idx])
442         {
443                 delta = __align[idx] / 2 - __margin[idx];
444         }
445         else if (delta <= -(__align[idx] / 2 - __margin[idx]))
446         {
447                 delta = -(__align[idx] / 2 - __margin[idx]);
448         }
449
450         // adding start accelerate effect when fast Flick
451         if (__acceleration[idx] && __drawCount > FLK_ANI_OVERSPEED_START_CNT && __drawCount < FLK_ANI_OVERSPEED_END_CNT)
452         {
453                 delta += __align[idx] * __acceleration[idx];
454         }
455         else
456         {
457                 int deltaNew = delta;
458
459 //      if (deltaNew > 10 && deltaNew%(m_alignH/12))
460 //              deltaNew = (deltaNew/(m_alignH/12)+1)*(m_alignH/12);
461
462 //      if (__velocity && delta == 0)
463 //              deltaNew = m_alignH/24;
464
465                 delta = deltaNew;
466         }
467
468         // ceiling RoundOff for smooth stop
469         if (delta == 0)
470         {
471                 if (__velocity[idx] > 0)
472                 {
473                         delta = 1;
474                 }
475                 else if (__velocity[idx] < 0)
476                 {
477                         delta = -1;
478                 }
479         }
480
481 //  if (delta == 1 && m_nSlowStopCnt < __flickAnimationFPS)
482 //  {
483 //      return delta;
484 //  }
485
486         // Velocity Decrease according to Friction Coefficient
487         // V(i+1)= V(i) - u*g*dT
488         if (__velocity[idx] > __velocityMin[idx] + __friction[idx])
489         {
490                 __velocity[idx] -= __friction[idx];
491         }
492         else if (__velocity[idx] > __velocityMin[idx])
493         {
494                 __velocity[idx] = __velocityMin[idx];
495                 __friction[idx] = __frictionMin[idx];
496         }
497         else if (__velocity[idx] > __friction[idx])
498         {
499                 __velocity[idx] -= __friction[idx];
500         }
501         else if (__velocity[idx] < -__velocityMin[idx] - __friction[idx])
502         {
503                 __velocity[idx] += __friction[idx];
504         }
505         else if (__velocity[idx] < -__velocityMin[idx])
506         {
507                 __velocity[idx] = -__velocityMin[idx];
508                 __friction[idx] = __frictionMin[idx];
509         }
510         else if (__velocity[idx] < -__friction[idx])
511         {
512                 __velocity[idx] += __friction[idx];
513         }
514         else
515         {
516                 __velocity[idx] = 0;
517         }
518
519         return delta;
520 }
521
522 void
523 _FlickAnimation::InitializeTension(void)
524 {
525         if (__tensionStatus[_X] != TENSION_NA)
526         {
527                 __tensionStatus[_X] = TENSION_DONE;
528         }
529
530         if (__tensionStatus[_Y] != TENSION_NA)
531         {
532                 __tensionStatus[_Y] = TENSION_DONE;
533         }
534 }
535
536 // start Tension effect and return true upon reaching the end of both.
537 bool
538 _FlickAnimation::StartTensionEffect(int pos, int end, int idx)
539 {
540         if (__tensionStatus[idx] == TENSION_NA)
541         {
542                 return false;
543         }
544
545         bool reachEndFlag = false;
546         int vel = 0;
547
548         if (pos > 0)
549         {
550                 switch (__tensionStatus[idx])
551                 {
552                 case TENSION_DONE:
553                         // Tension start => calculate final distance (max : Resolution * 1/3)
554                         __tensionDistMax[idx] = __resolution[idx] / 3 * __velocity[idx] / (__align[idx] * 2 / 3 * __flickAnimationFPSRef);
555                         __acceleration[idx] = 0;
556                         __tensionStatus[idx] = TENSION_COMPRESS;
557                         // fall through
558
559                 case TENSION_COMPRESS:
560                         vel = (__tensionDistMax[idx] - pos) * __flickAnimationFPS;
561
562                         if (vel < __velocity[idx])
563                         {
564                                 __velocity[idx] = vel;
565                         }
566
567                         // Before Reaching End (delta > 0)
568                         if (__velocity[idx] / __flickAnimationFPS > 0)
569                         {
570                                 break;
571                         }
572
573                         // After Reaching End, Tension Release Start
574                         __tensionStatus[idx] = TENSION_RELEASE;
575                         reachEndFlag = true;
576                         // fall through
577
578                 case TENSION_RELEASE:
579                         __velocity[idx] = -(pos * __flickAnimationFPS / 2);
580
581                         if (__velocity[idx] > -__flickAnimationFPS)
582                         {
583                                 __velocity[idx] = -__flickAnimationFPS; // Adjust final position is 0.
584                         }
585                         break;
586
587                 default:
588                         break;
589                 }
590         }
591         else if (pos < end && pos < 0)
592         {
593                 int delta = 0;
594
595                 if (end > 0)
596                 {
597                         delta = pos;
598                 }
599                 else
600                 {
601                         delta = pos - end;
602                 }
603
604                 switch (__tensionStatus[idx])
605                 {
606                 case TENSION_DONE:
607                         __tensionDistMax[idx] = __resolution[idx] / 3 * __velocity[idx] / (__align[idx] * 2 / 3 * __flickAnimationFPSRef);
608                         __acceleration[idx] = 0;
609                         __tensionStatus[idx] = TENSION_COMPRESS;
610                         // fall through
611
612                 case TENSION_COMPRESS:
613                         vel = (__tensionDistMax[idx] - delta) * __flickAnimationFPS;
614
615                         if (vel > __velocity[idx])
616                         {
617                                 __velocity[idx] = vel;
618                         }
619
620                         // Before Reaching End (delta > 0)
621                         if (__velocity[idx] / __flickAnimationFPS < 0)
622                         {
623                                 break;
624                         }
625
626                         // After Reaching End, Tension Release Start
627                         __tensionStatus[idx] = TENSION_RELEASE;
628                         reachEndFlag = true;
629                         // fall through
630
631                 case TENSION_RELEASE:
632                         __velocity[idx] = -(delta * __flickAnimationFPS / 2);
633
634                         if (__velocity[idx] < __flickAnimationFPS)
635                         {
636                                 __velocity[idx] = __flickAnimationFPS;
637                         }
638                         break;
639
640                 default:
641                         break;
642                 }
643         }
644
645         if (__velocity[idx] == 0)
646         {
647                 __tensionStatus[idx] = TENSION_DONE;
648         }
649
650         return reachEndFlag;
651 }
652
653 int
654 _FlickAnimation::GetCurVelocity(int idx) const
655 {
656         return __velocity[idx];
657 }
658
659 int
660 _FlickAnimation::GetCurFriction(int idx) const
661 {
662         return __friction[idx];
663 }
664
665 }}} // Tizen::Ui::Controls
666