(ScrollOvershoot) Removed OnStage checks now that issue has been fixed in PropertyNot...
[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
433   if(!mOvershootNegativeNotification)
434   {
435     mOvershootNegativeNotification = scrollable.AddPropertyNotification(IsVertical() ? overshootYPropertyIndex : overshootXPropertyIndex, LessThanCondition(-Math::MACHINE_EPSILON_1));
436     mOvershootNegativeNotification.SetNotifyMode(PropertyNotification::NotifyOnChanged);
437     mOvershootNegativeNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnNegativeOvershootNotification);
438   }
439
440   if(!mOvershootPositiveNotification)
441   {
442     mOvershootPositiveNotification = scrollable.AddPropertyNotification(IsVertical() ? overshootYPropertyIndex : overshootXPropertyIndex, GreaterThanCondition(Math::MACHINE_EPSILON_1));
443     mOvershootPositiveNotification.SetNotifyMode(PropertyNotification::NotifyOnChanged);
444     mOvershootPositiveNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnPositiveOvershootNotification);
445   }
446 }
447
448 Vector3 ScrollOvershootEffectRipple::PositionConstraint(const Vector3& current,
449     const PropertyInput& parentSizeProperty, const PropertyInput& overshootProperty)
450 {
451   float overshoot = overshootProperty.GetFloat();
452   const Vector3 parentSize = parentSizeProperty.GetVector3();
453
454   Vector3 relativeOffset = Vector3::ZERO;
455
456   if(IsVertical())
457   {
458     if(overshoot > Math::MACHINE_EPSILON_0)
459     {
460       relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
461     }
462     else if (overshoot < -Math::MACHINE_EPSILON_0)
463     {
464       relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
465     }
466   }
467   else
468   {
469     if(overshoot > Math::MACHINE_EPSILON_0)
470     {
471       relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
472     }
473     else if (overshoot < -Math::MACHINE_EPSILON_0)
474     {
475       relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
476     }
477   }
478
479   return relativeOffset * parentSize;
480 }
481
482 void ScrollOvershootEffectRipple::OnPositiveOvershootNotification(PropertyNotification& source)
483 {
484   Actor delegate = Actor::DownCast(source.GetTarget());
485   float overshoot = delegate.GetProperty<float>(source.GetTargetProperty());
486   bool canScroll = delegate.GetProperty<bool>(mCanScrollPropertyIndex);
487   if(!canScroll)
488   {
489     mOvershootImage.SetVisible(false);
490     return;
491   }
492   mOvershootImage.SetVisible(true);
493
494   if (fabsf(overshoot) < Math::MACHINE_EPSILON_1)
495   {
496     AnimateScrollOvershoot(0.0f);
497     return;
498   }
499   if(overshoot > 0.0f)
500   {
501     const Vector3 imageSize = mOvershootImage.GetCurrentSize();
502     Vector3 relativeOffset = Vector3::ZERO;
503     const Vector3 parentSize = delegate.GetCurrentSize();
504     AnimateScrollOvershoot(1.0f);
505     if(IsVertical())
506     {
507       mOvershootImage.SetRotation(Quaternion(0.0f, Vector3::ZAXIS));
508       mOvershootImage.SetSize(parentSize.width, imageSize.height, imageSize.depth);
509       relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
510     }
511     else
512     {
513       mOvershootImage.SetRotation(Quaternion(1.5f * Math::PI, Vector3::ZAXIS));
514       mOvershootImage.SetSize(parentSize.height, imageSize.height, imageSize.depth);
515       relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
516     }
517     mOvershootImage.SetPosition(relativeOffset * parentSize);
518   }
519 }
520
521 void ScrollOvershootEffectRipple::OnNegativeOvershootNotification(PropertyNotification& source)
522 {
523   Actor delegate = Actor::DownCast(source.GetTarget());
524   float overshoot = delegate.GetProperty<float>(source.GetTargetProperty());
525   bool canScroll = delegate.GetProperty<bool>(mCanScrollPropertyIndex);
526   if(!canScroll)
527   {
528     mOvershootImage.SetVisible(false);
529     return;
530   }
531   mOvershootImage.SetVisible(true);
532
533   if (fabsf(overshoot) < Math::MACHINE_EPSILON_1)
534   {
535     AnimateScrollOvershoot(0.0f);
536     return;
537   }
538
539   if(overshoot < 0.0f)
540   {
541     const Vector3 imageSize = mOvershootImage.GetCurrentSize();
542     Vector3 relativeOffset = Vector3::ZERO;
543     const Vector3 parentSize = delegate.GetCurrentSize();
544     AnimateScrollOvershoot(-1.0f);
545     if(IsVertical())
546     {
547       mOvershootImage.SetRotation(Quaternion(Math::PI, Vector3::ZAXIS));
548       mOvershootImage.SetSize(parentSize.width, imageSize.height, imageSize.depth);
549       relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
550     }
551     else
552     {
553       mOvershootImage.SetRotation(Quaternion(0.5f * Math::PI, Vector3::ZAXIS));
554       mOvershootImage.SetSize(parentSize.height, imageSize.height, imageSize.depth);
555       relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
556     }
557     mOvershootImage.SetPosition(relativeOffset * parentSize);
558   }
559 }
560
561 void ScrollOvershootEffectRipple::AnimateScrollOvershoot(float overshootAmount)
562 {
563   bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
564
565   // make sure we animate back if needed
566   mAnimateOvershootOff = (!animatingOn && mAnimatingOvershootOn);
567
568   int overShootProperty = mRippleEffect.GetPropertyIndex(mRippleEffect.GetOvershootPropertyName());
569   float currentOvershoot = mRippleEffect.GetProperty<float>(overShootProperty);
570   if(((currentOvershoot < 0.0f && overshootAmount > 0.0f)
571       || (currentOvershoot > 0.0f && overshootAmount < 0.0f)))
572   {
573     // cancel current animation
574     mAnimatingOvershootOn = false;
575     // reset currentOvershoot to 0.0f
576     mRippleEffect.SetProperty(overShootProperty, 0.0f);
577     currentOvershoot = 0.0f;
578   }
579   if( mAnimatingOvershootOn )
580   {
581     // animating on in same direction, do not allow animate off
582     return;
583   }
584   float duration = DEFAULT_OVERSHOOT_ANIMATION_DURATION * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot));
585
586   if(mScrollOvershootAnimation)
587   {
588     mScrollOvershootAnimation.Clear();
589     mScrollOvershootAnimation.Reset();
590   }
591   mScrollOvershootAnimation = Animation::New(duration);
592   mScrollOvershootAnimation.FinishedSignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished);
593   mScrollOvershootAnimation.AnimateTo( Property(mRippleEffect, overShootProperty), overshootAmount, TimePeriod(0.0f, duration) );
594   mScrollOvershootAnimation.Play();
595
596   mOvershootImage.SetVisible(true);
597
598   mAnimatingOvershootOn = animatingOn;
599 }
600
601 void ScrollOvershootEffectRipple::OnOvershootAnimFinished(Animation& animation)
602 {
603   if(!mAnimatingOvershootOn && !mAnimateOvershootOff)
604   {
605     // just finished animating overshoot to 0
606     mOvershootImage.SetVisible(false);
607   }
608   mAnimatingOvershootOn = false;
609   mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished);
610   mScrollOvershootAnimation.Clear();
611   mScrollOvershootAnimation.Reset();
612   if(mAnimateOvershootOff)
613   {
614     AnimateScrollOvershoot(0.0f);
615   }
616 }
617
618 ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New(bool vertical)
619 {
620   return new ScrollOvershootEffectRipple(vertical);
621 }
622
623 } // namespace Internal
624
625 } // namespace Toolkit
626
627 } // namespace Dali