Split dali-toolkit into Base & Optional
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-overshoot-indicator-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
18
19 // EXTERNAL INCLUDES
20 #include <boost/bind.hpp>
21
22 #include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
23 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
24
25 using namespace Dali;
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 const char* OVERSHOOT_OVERLAY_IMAGE_PATH = DALI_IMAGE_DIR "scroll_overshoot.png";
37 const char* OVERSHOOT_OVERLAY_RIPPLE_IMAGE_PATH = DALI_IMAGE_DIR "overshoot_ripple.png";
38 const float DEFAULT_MAX_OVERSHOOT_HEIGHT = 36.0f;  // 36 pixels
39 const Rect<int> OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA( 0, 0, 720, 58 );
40 const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.35f;  // time in seconds
41
42 ScrollOvershootIndicator::ScrollOvershootIndicator(Scrollable& scrollable) :
43   mScrollable(scrollable),
44   mEffectX(NULL),
45   mEffectY(NULL)
46 {
47 }
48
49 ScrollOvershootIndicator::~ScrollOvershootIndicator()
50 {
51
52 }
53
54 ScrollOvershootIndicator* ScrollOvershootIndicator::New(Scrollable& scrollable)
55 {
56   ScrollOvershootIndicator* scrollOvershootPtr = new ScrollOvershootIndicator(scrollable);
57   return scrollOvershootPtr;
58 }
59
60 void ScrollOvershootIndicator::Enable(bool enable)
61 {
62   if(enable)
63   {
64     Actor scrollableActor = mScrollable.Self();
65     if(!mEffectX)
66     {
67       mEffectX = ScrollOvershootEffectRipple::New(false);
68     }
69     mEffectX->Apply(mScrollable);
70     if(!mEffectY)
71     {
72       mEffectY = ScrollOvershootEffectRipple::New(true);
73     }
74     mEffectY->Apply(mScrollable);
75     mEffectY->SetPropertyNotifications(scrollableActor);
76   }
77   else
78   {
79     if(mEffectX)
80     {
81       mEffectX->Remove(mScrollable);
82     }
83     if(mEffectY)
84     {
85       mEffectY->Remove(mScrollable);
86     }
87   }
88 }
89
90 void ScrollOvershootIndicator::Reset()
91 {
92   mEffectX->Reset();
93   mEffectY->Reset();
94 }
95
96 ScrollOvershootEffect::ScrollOvershootEffect(bool vertical) :
97     mVertical(vertical)
98 {
99
100 }
101
102 ScrollOvershootEffectGradient::ScrollOvershootEffectGradient(bool vertical) :
103     ScrollOvershootEffect(vertical),
104     mMaxOvershootImageSize(DEFAULT_MAX_OVERSHOOT_HEIGHT)
105 {
106   Image overshootImage = Image::New( OVERSHOOT_OVERLAY_IMAGE_PATH );
107   mOvershootImage = ImageActor::New( overshootImage );
108   mOvershootImage.SetParentOrigin(ParentOrigin::TOP_LEFT);
109   mOvershootImage.SetAnchorPoint(AnchorPoint::TOP_LEFT);
110   mOvershootImage.SetDrawMode(DrawMode::OVERLAY);
111 }
112
113 void ScrollOvershootEffectGradient::Apply(Scrollable& scrollable)
114 {
115   Actor scrollableActor = scrollable.Self();
116   int overshootXPropertyIndex = scrollableActor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
117   int overshootYPropertyIndex = scrollableActor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME);
118
119   Constraint constraint = Constraint::New<Vector3>( Actor::SIZE,
120                                                     Source( scrollableActor, overshootXPropertyIndex ),
121                                                     Source( scrollableActor, overshootYPropertyIndex ),
122                                                     Source( scrollableActor, Actor::SIZE ),
123                                                     boost::bind( &ScrollOvershootEffectGradient::SizeConstraint, this, _1, _2, _3, _4) );
124   mSizeConstraint = mOvershootImage.ApplyConstraint(constraint);
125
126   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
127                                             Source( scrollableActor, overshootXPropertyIndex ),
128                                             Source( scrollableActor, overshootYPropertyIndex ),
129                                             boost::bind( &ScrollOvershootEffectGradient::RotationConstraint, this, _1, _2, _3) );
130   mRotationConstraint = mOvershootImage.ApplyConstraint(constraint);
131
132   constraint = Constraint::New<Vector3>( Actor::POSITION,
133                                          Source( scrollableActor, Actor::SIZE ),
134                                          Source( scrollableActor, overshootXPropertyIndex ),
135                                          Source( scrollableActor, overshootYPropertyIndex ),
136                                          boost::bind( &ScrollOvershootEffectGradient::PositionConstraint, this, _1, _2, _3, _4) );
137   mPositionConstraint = mOvershootImage.ApplyConstraint(constraint);
138
139   constraint = Constraint::New<bool>( Actor::VISIBLE,
140                                       Source( scrollableActor, IsVertical() ? scrollableActor.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL) : scrollableActor.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL)),
141                                       boost::bind( &ScrollOvershootEffectGradient::VisibilityConstraint, this, _1, _2) );
142   mVisibilityConstraint = mOvershootImage.ApplyConstraint(constraint);
143   scrollable.AddOverlay(mOvershootImage);
144   SetPropertyNotifications(scrollableActor);
145 }
146
147 void ScrollOvershootEffectGradient::Remove(Scrollable& scrollable)
148 {
149   if(mOvershootImage)
150   {
151     if(mSizeConstraint)
152     {
153       mOvershootImage.RemoveConstraint(mSizeConstraint);
154       mSizeConstraint = NULL;
155     }
156     if(mRotationConstraint)
157     {
158       mOvershootImage.RemoveConstraint(mRotationConstraint);
159       mRotationConstraint = NULL;
160     }
161     if(mPositionConstraint)
162     {
163       mOvershootImage.RemoveConstraint(mPositionConstraint);
164       mPositionConstraint = NULL;
165     }
166     if(mVisibilityConstraint)
167     {
168       mOvershootImage.RemoveConstraint(mVisibilityConstraint);
169       mVisibilityConstraint = NULL;
170     }
171     scrollable.RemoveOverlay(mOvershootImage);
172   }
173 }
174
175 Vector3 ScrollOvershootEffectGradient::SizeConstraint(const Vector3& current,
176     const PropertyInput& overshootPropertyX, const PropertyInput& overshootPropertyY,
177     const PropertyInput& parentSizeProperty)
178 {
179   float overshootx = overshootPropertyX.GetFloat();
180   float overshooty = overshootPropertyY.GetFloat();
181   const Vector3 parentSize = parentSizeProperty.GetVector3();
182
183   float overlayWidth = IsVertical() ? parentSize.x : parentSize.y;
184   float overlayHeight = mMaxOvershootImageSize * fabsf(IsVertical() ? overshooty : overshootx);
185
186   return Vector3(overlayWidth, overlayHeight, current.z);
187 }
188
189 Quaternion ScrollOvershootEffectGradient::RotationConstraint(const Quaternion& current,
190     const PropertyInput& overshootPropertyX, const PropertyInput& overshootPropertyY)
191 {
192   float overshootx = overshootPropertyX.GetFloat();
193   float overshooty = overshootPropertyY.GetFloat();
194
195   Quaternion rotation;
196
197   if(IsVertical())
198   {
199     if(overshooty < -Math::MACHINE_EPSILON_0)
200     {
201       rotation = Quaternion(Math::PI, Vector3::ZAXIS);
202     }
203     else if(overshooty > Math::MACHINE_EPSILON_0)
204     {
205       rotation = Quaternion(0.0f, Vector3::ZAXIS);
206     }
207   }
208   else
209   {
210     if(overshootx < -Math::MACHINE_EPSILON_0)
211     {
212       rotation = Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
213     }
214     else if(overshootx > Math::MACHINE_EPSILON_0)
215     {
216       rotation = Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
217     }
218   }
219
220   return rotation;
221 }
222
223 Vector3 ScrollOvershootEffectGradient::PositionConstraint(const Vector3&    current,
224     const PropertyInput& parentSizeProperty,
225     const PropertyInput& overshootPropertyX, const PropertyInput& overshootPropertyY)
226 {
227   float overshootx = overshootPropertyX.GetFloat();
228   float overshooty = overshootPropertyY.GetFloat();
229   const Vector3 parentSize = parentSizeProperty.GetVector3();
230
231   Vector3 relativeOffset = Vector3::ZERO;
232
233   if(IsVertical())
234   {
235     if(overshooty > Math::MACHINE_EPSILON_0)
236     {
237       relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
238     }
239     else if (overshooty < -Math::MACHINE_EPSILON_0)
240     {
241       relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
242     }
243   }
244   else
245   {
246     if(overshootx > Math::MACHINE_EPSILON_0)
247     {
248       relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
249     }
250     else if (overshootx < -Math::MACHINE_EPSILON_0)
251     {
252       relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
253     }
254   }
255
256   return relativeOffset * parentSize;
257 }
258
259 bool ScrollOvershootEffectGradient::VisibilityConstraint(const bool& current,
260     const PropertyInput& canScrollProperty)
261 {
262   return canScrollProperty.GetBoolean();
263 }
264
265 ScrollOvershootEffectGradientPtr ScrollOvershootEffectGradient::New(bool vertical)
266 {
267   return new ScrollOvershootEffectGradient(vertical);
268 }
269
270 namespace
271 {
272
273 const std::string OVERSHOOT_PROPERTY_NAME( "uOvershoot" );
274 const std::string OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME( "uOvershootImageCount" );
275
276 } // namespace
277
278 OvershootRippleEffect::OvershootRippleEffect()
279 {
280 }
281
282 //Call the Parent copy constructor to add reference to the implementation for this object
283 OvershootRippleEffect::OvershootRippleEffect(ShaderEffect handle)
284 :ShaderEffect(handle)
285 {
286 }
287
288 OvershootRippleEffect::~OvershootRippleEffect()
289 {
290 }
291
292 OvershootRippleEffect OvershootRippleEffect::New()
293 {
294   std::string vertextShader(
295       "precision mediump float;                     \n"
296       "uniform  float  uOvershoot;                  \n"
297       "uniform  float  uOvershootImageCount;        \n"
298       "void main()                                  \n"
299       "{                                            \n"
300       "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0); \n"
301       "  vTexCoord = aTexCoord;                     \n"
302       "  vTexCoord.y += (1.0 / uOvershootImageCount) * min(floor((abs(uOvershoot) * (uOvershootImageCount - 1.0)) + 0.5), (uOvershootImageCount - 1.0)); \n"
303       "}                                            \n" );
304
305   std::string fragmentShader(
306       "void main()                                  \n"
307       "{                                            \n"
308       "  gl_FragColor = texture2D(sTexture, vTexCoord);    \n"
309       "}                                            \n" );
310
311   // Create the implementation, temporarily owned on stack,
312   Dali::ShaderEffect shaderEffectCustom =  Dali::ShaderEffect::New(
313       vertextShader,
314       fragmentShader);
315
316   /* Pass ownership to OvershootRippleEffect through overloaded constructor, So that it now has access to the
317      Dali::ShaderEffect implementation */
318   OvershootRippleEffect handle( shaderEffectCustom );
319   handle.SetUniform(OVERSHOOT_PROPERTY_NAME, 0.0f);
320   handle.SetUniform(OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME, 10.0f);
321   return handle;
322 }
323
324 void OvershootRippleEffect::SetOvershoot( float overshoot )
325 {
326   SetUniform( OVERSHOOT_PROPERTY_NAME, overshoot );
327 }
328
329 void OvershootRippleEffect::SetOvershootImageCount( float imageCount )
330 {
331   SetUniform( OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME, imageCount );
332 }
333
334 const std::string& OvershootRippleEffect::GetOvershootPropertyName() const
335 {
336   return OVERSHOOT_PROPERTY_NAME;
337 }
338
339 const std::string& OvershootRippleEffect::GetOvershootImageCountPropertyName() const
340 {
341   return OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME;
342 }
343
344 ScrollOvershootEffectRipple::ScrollOvershootEffectRipple(bool vertical) :
345     ScrollOvershootEffect(vertical),
346     mMaxOvershootImageSize(DEFAULT_MAX_OVERSHOOT_HEIGHT)
347 {
348   mRippleEffect = OvershootRippleEffect::New();
349   Image overshootImage = Image::New( OVERSHOOT_OVERLAY_RIPPLE_IMAGE_PATH );
350   mOvershootImage = ImageActor::New( overshootImage );
351   mOvershootImage.SetParentOrigin(ParentOrigin::TOP_LEFT);
352   mOvershootImage.SetAnchorPoint(AnchorPoint::TOP_LEFT);
353   mOvershootImage.SetDrawMode(DrawMode::OVERLAY);
354   mOvershootImage.SetShaderEffect(mRippleEffect);
355   mOvershootImage.SetPixelArea(OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA);
356   mOvershootImage.SetVisible(false);
357   mAnimatingOvershootOn = false;
358   mAnimateOvershootOff = false;
359 }
360
361 void ScrollOvershootEffectRipple::Apply(Scrollable& scrollable)
362 {
363   Actor scrollableActor = scrollable.Self();
364
365   // make sure height is set, since we only create a constraint for image width
366   mOvershootImage.SetSize(OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA.width, OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA.height);
367
368   UpdateConstraints(scrollableActor);
369   scrollable.AddOverlay(mOvershootImage);
370
371   SetPropertyNotifications(scrollableActor);
372 }
373
374 void ScrollOvershootEffectRipple::Remove(Scrollable& scrollable)
375 {
376   if(mOvershootImage)
377   {
378     if(mSizeConstraint)
379     {
380       mOvershootImage.RemoveConstraint(mSizeConstraint);
381       mSizeConstraint = NULL;
382     }
383     if(mPositionConstraint)
384     {
385       mOvershootImage.RemoveConstraint(mPositionConstraint);
386       mPositionConstraint = NULL;
387     }
388     scrollable.RemoveOverlay(mOvershootImage);
389   }
390 }
391
392 void ScrollOvershootEffectRipple::Reset()
393 {
394   mAnimatingOvershootOn = false;
395   mAnimateOvershootOff = false;
396   mOvershootImage.SetVisible(false);
397   mRippleEffect.SetUniform(mRippleEffect.GetOvershootPropertyName(), 0.0f);
398   if(mScrollOvershootAnimation)
399   {
400     mScrollOvershootAnimation.Clear();
401     mScrollOvershootAnimation.Reset();
402   }
403 }
404
405 void ScrollOvershootEffectRipple::UpdateConstraints(Actor& scrollable)
406 {
407   int overshootPropertyIndex = mRippleEffect.GetPropertyIndex(mRippleEffect.GetOvershootPropertyName());
408   Constraint constraint;
409   if(!mSizeConstraint)
410   {
411     constraint = Constraint::New<float>( Actor::SIZE_WIDTH,
412                                                       Source( scrollable, IsVertical() ? Actor::SIZE_WIDTH : Actor::SIZE_HEIGHT),
413                                                       EqualToConstraint() );
414     mSizeConstraint = mOvershootImage.ApplyConstraint(constraint);
415   }
416
417   if(!mPositionConstraint)
418   {
419     constraint = Constraint::New<Vector3>( Actor::POSITION,
420                                            Source( scrollable, Actor::SIZE ),
421                                            Source( mRippleEffect, overshootPropertyIndex ),
422                                            boost::bind( &ScrollOvershootEffectRipple::PositionConstraint, this, _1, _2, _3) );
423     mPositionConstraint = mOvershootImage.ApplyConstraint(constraint);
424   }
425 }
426
427 void ScrollOvershootEffectRipple::SetPropertyNotifications(Actor& scrollable)
428 {
429   int overshootXPropertyIndex = scrollable.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
430   int overshootYPropertyIndex = scrollable.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME);
431   mCanScrollPropertyIndex = scrollable.GetPropertyIndex(IsVertical() ? Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL : Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL);
432   if(scrollable.OnStage())
433   {
434     if(!mOvershootNegativeNotification)
435     {
436       mOvershootNegativeNotification = scrollable.AddPropertyNotification(IsVertical() ? overshootYPropertyIndex : overshootXPropertyIndex, LessThanCondition(-Math::MACHINE_EPSILON_1));
437       mOvershootNegativeNotification.SetNotifyMode(PropertyNotification::NotifyOnChanged);
438       mOvershootNegativeNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnNegativeOvershootNotification);
439     }
440
441     if(!mOvershootPositiveNotification)
442     {
443       mOvershootPositiveNotification = scrollable.AddPropertyNotification(IsVertical() ? overshootYPropertyIndex : overshootXPropertyIndex, GreaterThanCondition(Math::MACHINE_EPSILON_1));
444       mOvershootPositiveNotification.SetNotifyMode(PropertyNotification::NotifyOnChanged);
445       mOvershootPositiveNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnPositiveOvershootNotification);
446     }
447   }
448 }
449
450 Vector3 ScrollOvershootEffectRipple::PositionConstraint(const Vector3& current,
451     const PropertyInput& parentSizeProperty, const PropertyInput& overshootProperty)
452 {
453   float overshoot = overshootProperty.GetFloat();
454   const Vector3 parentSize = parentSizeProperty.GetVector3();
455
456   Vector3 relativeOffset = Vector3::ZERO;
457
458   if(IsVertical())
459   {
460     if(overshoot > Math::MACHINE_EPSILON_0)
461     {
462       relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
463     }
464     else if (overshoot < -Math::MACHINE_EPSILON_0)
465     {
466       relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
467     }
468   }
469   else
470   {
471     if(overshoot > Math::MACHINE_EPSILON_0)
472     {
473       relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
474     }
475     else if (overshoot < -Math::MACHINE_EPSILON_0)
476     {
477       relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
478     }
479   }
480
481   return relativeOffset * parentSize;
482 }
483
484 void ScrollOvershootEffectRipple::OnPositiveOvershootNotification(PropertyNotification& source)
485 {
486   Actor delegate = Actor::DownCast(source.GetTarget());
487   float overshoot = delegate.GetProperty<float>(source.GetTargetProperty());
488   bool canScroll = delegate.GetProperty<bool>(mCanScrollPropertyIndex);
489   if(!canScroll)
490   {
491     mOvershootImage.SetVisible(false);
492     return;
493   }
494   mOvershootImage.SetVisible(true);
495
496   if (fabsf(overshoot) < Math::MACHINE_EPSILON_1)
497   {
498     AnimateScrollOvershoot(0.0f);
499     return;
500   }
501   if(overshoot > 0.0f)
502   {
503     const Vector3 imageSize = mOvershootImage.GetCurrentSize();
504     Vector3 relativeOffset = Vector3::ZERO;
505     const Vector3 parentSize = delegate.GetCurrentSize();
506     AnimateScrollOvershoot(1.0f);
507     if(IsVertical())
508     {
509       mOvershootImage.SetRotation(Quaternion(0.0f, Vector3::ZAXIS));
510       mOvershootImage.SetSize(parentSize.width, imageSize.height, imageSize.depth);
511       relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
512     }
513     else
514     {
515       mOvershootImage.SetRotation(Quaternion(1.5f * Math::PI, Vector3::ZAXIS));
516       mOvershootImage.SetSize(parentSize.height, imageSize.height, imageSize.depth);
517       relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
518     }
519     mOvershootImage.SetPosition(relativeOffset * parentSize);
520   }
521 }
522
523 void ScrollOvershootEffectRipple::OnNegativeOvershootNotification(PropertyNotification& source)
524 {
525   Actor delegate = Actor::DownCast(source.GetTarget());
526   float overshoot = delegate.GetProperty<float>(source.GetTargetProperty());
527   bool canScroll = delegate.GetProperty<bool>(mCanScrollPropertyIndex);
528   if(!canScroll)
529   {
530     mOvershootImage.SetVisible(false);
531     return;
532   }
533   mOvershootImage.SetVisible(true);
534
535   if (fabsf(overshoot) < Math::MACHINE_EPSILON_1)
536   {
537     AnimateScrollOvershoot(0.0f);
538     return;
539   }
540
541   if(overshoot < 0.0f)
542   {
543     const Vector3 imageSize = mOvershootImage.GetCurrentSize();
544     Vector3 relativeOffset = Vector3::ZERO;
545     const Vector3 parentSize = delegate.GetCurrentSize();
546     AnimateScrollOvershoot(-1.0f);
547     if(IsVertical())
548     {
549       mOvershootImage.SetRotation(Quaternion(Math::PI, Vector3::ZAXIS));
550       mOvershootImage.SetSize(parentSize.width, imageSize.height, imageSize.depth);
551       relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
552     }
553     else
554     {
555       mOvershootImage.SetRotation(Quaternion(0.5f * Math::PI, Vector3::ZAXIS));
556       mOvershootImage.SetSize(parentSize.height, imageSize.height, imageSize.depth);
557       relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
558     }
559     mOvershootImage.SetPosition(relativeOffset * parentSize);
560   }
561 }
562
563 void ScrollOvershootEffectRipple::AnimateScrollOvershoot(float overshootAmount)
564 {
565   bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
566
567   // make sure we animate back if needed
568   mAnimateOvershootOff = (!animatingOn && mAnimatingOvershootOn);
569
570   int overShootProperty = mRippleEffect.GetPropertyIndex(mRippleEffect.GetOvershootPropertyName());
571   float currentOvershoot = mRippleEffect.GetProperty<float>(overShootProperty);
572   if(((currentOvershoot < 0.0f && overshootAmount > 0.0f)
573       || (currentOvershoot > 0.0f && overshootAmount < 0.0f)))
574   {
575     // cancel current animation
576     mAnimatingOvershootOn = false;
577     // reset currentOvershoot to 0.0f
578     mRippleEffect.SetProperty(overShootProperty, 0.0f);
579     currentOvershoot = 0.0f;
580   }
581   if( mAnimatingOvershootOn )
582   {
583     // animating on in same direction, do not allow animate off
584     return;
585   }
586   float duration = DEFAULT_OVERSHOOT_ANIMATION_DURATION * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot));
587
588   if(mScrollOvershootAnimation)
589   {
590     mScrollOvershootAnimation.Clear();
591     mScrollOvershootAnimation.Reset();
592   }
593   mScrollOvershootAnimation = Animation::New(duration);
594   mScrollOvershootAnimation.FinishedSignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished);
595   mScrollOvershootAnimation.AnimateTo( Property(mRippleEffect, overShootProperty), overshootAmount, TimePeriod(0.0f, duration) );
596   mScrollOvershootAnimation.Play();
597
598   mOvershootImage.SetVisible(true);
599
600   mAnimatingOvershootOn = animatingOn;
601 }
602
603 void ScrollOvershootEffectRipple::OnOvershootAnimFinished(Animation& animation)
604 {
605   if(!mAnimatingOvershootOn && !mAnimateOvershootOff)
606   {
607     // just finished animating overshoot to 0
608     mOvershootImage.SetVisible(false);
609   }
610   mAnimatingOvershootOn = false;
611   mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished);
612   mScrollOvershootAnimation.Clear();
613   mScrollOvershootAnimation.Reset();
614   if(mAnimateOvershootOff)
615   {
616     AnimateScrollOvershoot(0.0f);
617   }
618 }
619
620 ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New(bool vertical)
621 {
622   return new ScrollOvershootEffectRipple(vertical);
623 }
624
625 } // namespace Internal
626
627 } // namespace Toolkit
628
629 } // namespace Dali