Conversion to Apache 2.0 license
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-slide-effect-impl.cpp
1
2 /*
3  * Copyright (c) 2014 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 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
20 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-slide-effect-impl.h>
21
22 using namespace Dali;
23
24 typedef Dali::Toolkit::Internal::ScrollSlideInfo ScrollSlideInfo;
25 typedef Dali::Toolkit::Internal::ScrollSlideInfoPtr ScrollSlideInfoPtr;
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 /**
37  * ScrollSlideInfo structure contains
38  * common info that is shared amongst the constraints applied to Actors.
39  * The constraints + effect all share ownership of this info struct.
40  * The info is written to by the ScrollSlideInfoUpdate constraint. While
41  * the other constraints read from by the other constraints. Due to the order
42  * in which the constraints are applied, all constraints will get the current
43  * property values for these properties.
44  * The advantage of doing this is that:
45  * A) Constraints are not restricted by the 6 property limit. to function.
46  * B) Properties which rarely change or only change when another property changes
47  * (e.g. time), such as scroll position, scroll domain, size, wrap mode don't need
48  * to be checked for each constraint to apply.
49  */
50 class ScrollSlideInfo : public RefObject
51 {
52
53 public:
54
55   /**
56    * Constructor
57    */
58   ScrollSlideInfo()
59   {
60   }
61
62   /**
63    * Destructor
64    */
65   virtual ~ScrollSlideInfo()
66   {
67   }
68
69 public:
70
71   Vector3 mScrollPosition;
72   Vector3 mEffectReference;
73   Vector3 mScrollSize;
74   Vector3 mScrollPositionMin;
75   Vector3 mScrollPositionMax;
76   bool mScrollWrap;
77   bool mVertical;
78
79 };
80
81 } // namespace Internal
82
83 } // namespace Toolkit
84
85 } // namespace Dali
86
87
88 namespace // unnamed namespace
89 {
90
91 const float SLIDEEFFECT_ANIMATION_MAX_TIME = 60.0f;      ///< Animation time (every time finishes, checks if it needs to go again)
92 const float COMPLETION_START_DURATION = 0.25f;           ///< Maximum time for completion of effect after scroll-view initially completes (due to delay effect)
93 const float COMPLETION_END_DURATION = 5.0f;              ///< Maximum time for completion of effect after scroll-view initially completes (due to delay effect)
94 const float ANIMATION_BLEND_COEFFICIENT = 0.05f;         ///< Animation blending coefficient (blends between target value e.g. 5% and current value 9%)
95 const float INV_ANIMATION_BLEND_COEFFICIENT = (1.0f - ANIMATION_BLEND_COEFFICIENT);
96 const float DEFAULT_MAX_DELAY_DURATION = 0.25f;          ///< Default maximum delay duration of the effect after scroll completes is 0.25f
97 const float EFFECT_SNAP_GROW_DURATION = 0.33f;           ///< Take 1/3rd of a second for the snap effect property to grow
98 const float EFFECT_SNAP_DECAY_DURATION = 0.667f;         ///< Take 2/3rds of a second for the snap effect property to decay
99
100 /**
101  * Gets a property index. If the property doesn't already exist, then
102  * it will create the property.
103  * @param[in] handle The handle that owns or will own the property
104  * @param[in] name The name for this property
105  * @param[in] propertyValue The initial value for this property
106  * @return The property index for this property is returned.
107  */
108 Property::Index SafeRegisterProperty( Handle& handle, const std::string& name, Property::Value propertyValue )
109 {
110   Property::Index index = handle.GetPropertyIndex( name );
111
112   if(index == Property::INVALID_INDEX)
113   {
114     index = handle.RegisterProperty( name, propertyValue );
115   }
116
117   return index;
118 }
119
120 /**
121  * Re-scales input value x from x0 - x1, to linearly map
122  * over the values y0 - y1. Values outside of this range
123  * will also conform to the trend (gradient) set.
124  * @param[in] y0 output minimum bound
125  * @param[in] y1 output maximum bound
126  * @param[in] x input X value
127  * @param[in] x0 (optional) input minimum bound (default 0.0)
128  * @param[in] x1 (optional) input maximum bound (default 1.0)
129  * @return The result of the mapping is returned.
130  */
131 float Mix(float y0, float y1, float x, float x0 = 0.0f, float x1 = 1.0f)
132 {
133   return y0 + (y1 - y0) * (x - x0) / (x1-x0);
134 }
135
136 /**
137  * Returns the value of x chasing target.
138  * returns a value of x which is closer to target.
139  * but limited by maxDelta. #
140  * For example:
141  * x = 10.0f
142  * target = 50.0f
143  * maxDelta = 20.0f
144  * result is 30.0f (x is 20.0f units closer to target)
145  * However, if x is already within maxDelta units
146  * of target, x will equal target.
147  * For example:
148  * x = 55.0f
149  * target = 50.0f
150  * maxDelta = 20.0f
151  * result is 50.0f (x was already within 20.0f units of target)
152  */
153 float Chase( float x, float target, float maxDelta )
154 {
155   float delta = target - x;
156
157   if(delta > 0.0f)
158   {
159     x = std::min( x + maxDelta, target );
160   }
161   else
162   {
163     x = std::max( x - maxDelta, target );
164   }
165
166   return x;
167 }
168
169 // constraints ////////////////////////////////////////////////////////////////
170
171 /**
172  * ScrollSlideInfoUpdate
173  *
174  * Info constraint updates an info struct with property info,
175  * so that constraints can use this instead of having it passed through
176  * as parameters.
177  */
178 struct ScrollSlideInfoUpdate
179 {
180   /**
181    * Constraint constructor
182    */
183   ScrollSlideInfoUpdate(ScrollSlideInfoPtr scrollInfo)
184   : mScrollSlideInfo(scrollInfo)
185   {
186   }
187
188   /**
189    * @param[in] current The current value
190    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
191    * @param[in] effectReferenceProperty The point in the scroll-view where the user touched the screen
192    * @param[in] effectTimeProperty The current timer. Starting from 0.0 when scroll animation/dragging
193    * commences. Ensures that constraint is applied and processed every frame (to achieve the delay effect)
194    * @param[in] sizeProperty The size of the ScrollView.
195    * @return The new position of this Actor.
196    */
197   float operator()(const float& current,
198                      const PropertyInput& scrollPositionProperty,
199                      const PropertyInput& effectReferenceProperty,
200                      const PropertyInput& scrollSizeProperty,
201                      const PropertyInput& scrollPositionMinProperty,
202                      const PropertyInput& scrollPositionMaxProperty,
203                      const PropertyInput& scrollWrapProperty)
204   {
205     mScrollSlideInfo->mScrollPosition = scrollPositionProperty.GetVector3();
206     mScrollSlideInfo->mEffectReference = effectReferenceProperty.GetVector3();
207     mScrollSlideInfo->mScrollSize = scrollSizeProperty.GetVector3();
208     mScrollSlideInfo->mScrollPositionMin = scrollPositionMinProperty.GetVector3();
209     mScrollSlideInfo->mScrollPositionMax = scrollPositionMaxProperty.GetVector3();
210     mScrollSlideInfo->mScrollWrap = scrollWrapProperty.GetBoolean();
211
212     return current;
213   }
214
215 private:
216
217   ScrollSlideInfoPtr mScrollSlideInfo;
218
219 };
220
221
222 /**
223  * ScrollSlidePositionConstraint
224  *
225  * Position constraint adjusts the position of the Actors
226  * based on their parent page's position relative to the middle of the screen.
227  * When at middle of the screen the position is not altered.
228  * When one screen away from middle the position is rotated about it's origin + mAnchor
229  */
230 struct ScrollSlidePositionConstraint
231 {
232   /**
233    * Constraint constructor
234    */
235   ScrollSlidePositionConstraint(ScrollSlideInfoPtr scrollInfo, float delayMin, float delayMax)
236   : mScrollSlideInfo(scrollInfo),
237     mScrollPosition(scrollInfo->mScrollPosition),
238     mDelayMin(delayMin),
239     mDelayMax(delayMax),
240     mAverageSpeed(0.0f)
241   {
242   }
243
244   /**
245    * @param[in] current The current position
246    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
247    * @param[in] effectReferenceProperty The point in the scroll-view where the user touched the screen
248    * @param[in] effectTimeProperty The current timer. Starting from 0.0 when scroll animation/dragging
249    * commences. Ensures that constraint is applied and processed every frame (to achieve the delay effect)
250    * @param[in] sizeProperty The size of the ScrollView.
251    * @return The new position of this Actor.
252    */
253   Vector3 operator()(const Vector3& current,
254                      const PropertyInput& pagePositionProperty,
255                      const PropertyInput& effectTimeProperty,
256                      const PropertyInput& deltaPositionProperty,
257                      const PropertyInput& snapProperty)
258   {
259     const float complete = snapProperty.GetFloat();
260     bool activate = (complete > Math::MACHINE_EPSILON_1);
261     const Vector3& pagePosition = pagePositionProperty.GetVector3();
262     const Vector3& scrollPosition = mScrollSlideInfo->mScrollPosition;
263
264     // Get position of page.
265     Vector2 relativePosition(pagePosition + scrollPosition);
266
267     // short circuit: for orthognal view and when the blending has been deactivated.
268     if( (!activate) &&
269         (fabsf(relativePosition.x) < Math::MACHINE_EPSILON_1) &&
270         (fabsf(relativePosition.y) < Math::MACHINE_EPSILON_1) )
271     {
272       Vector3 actorPosition(current + scrollPosition);
273       return actorPosition;
274     }
275
276     const Vector3& referencePoint = mScrollSlideInfo->mEffectReference;
277     const Vector3& scrollSize = mScrollSlideInfo->mScrollSize;
278     const Vector3& deltaPosition = deltaPositionProperty.GetVector3();
279
280     // 1. Determine the relative position of the actor from the scrolling reference point.
281     // (the further away from the reference, the longer the delay should be)
282     const Vector3& min = mScrollSlideInfo->mScrollPositionMin;
283     const Vector3& max = mScrollSlideInfo->mScrollPositionMax;
284
285     relativePosition.y = (pagePosition.y + current.y - referencePoint.y) / scrollSize.height;
286
287     // Smoothen the relativePosition value by averaging with mRelativePosition (avoids sudden jerk when
288     // user touche different points)
289     float shortestDirection = ShortestDistanceInDomain(mRelativePosition.y, relativePosition.y, min.y, max.y);
290     mRelativePosition.y += activate ? shortestDirection * ANIMATION_BLEND_COEFFICIENT : shortestDirection;
291
292     // f represents this absolute distance. Get as a relative distance and inverse exponential
293     // (as delay equation has an exponential effect i.e. the closer delayFactor to 1.0f,
294     // the longer the delay would appear exponentially)
295     float f = fabsf(mRelativePosition.y) * complete;
296     f = std::min(f, 1.0f);
297     f = 1.0f - powf(ANIMATION_BLEND_COEFFICIENT, f);
298
299     // at center delay factor is mDelayMin, at maximum (1.0) it is mDelayMax
300     f = Mix(mDelayMin, mDelayMax, f);
301
302     // 2. Now that f (delay factor) has been determined for this Actor,
303     // move mScrollPosition towards the actual scroll position, at rate determined by f.
304     float shortest = ShortestDistanceInDomain(mScrollPosition.x, WrapInDomain(scrollPosition.x, -min.x, -max.x), min.x, max.x);
305     mScrollPosition.x += activate ? shortest * (1.0f-f) : shortest;
306     mScrollPosition.x = WrapInDomain(mScrollPosition.x, -min.x, -max.x);
307     mScrollPosition.y = scrollPosition.y;
308
309     Vector3 actorPosition(current + pagePosition + mScrollPosition);
310
311     // Get position of actor.
312     bool wrap = mScrollSlideInfo->mScrollWrap;
313
314     if(wrap)
315     {
316       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
317       {
318         // WRAP X (based on the position of the right side)
319         actorPosition.x = WrapInDomain(actorPosition.x + scrollSize.x, min.x, max.x) - scrollSize.width;
320       }
321     }
322
323     const float targetRelativePositionX = (referencePoint.x + deltaPosition.x);
324
325     float blend(Mix(1.0f, ANIMATION_BLEND_COEFFICIENT, 1.0f - (1.0f - complete) * (1.0f - complete) ));
326     float invBlend(1.0f - blend);
327
328     mRelativePosition.x = activate ? mRelativePosition.x * invBlend + targetRelativePositionX * blend : targetRelativePositionX;
329     mRelativePosition.x = Chase( mRelativePosition.x, targetRelativePositionX, 1.0f );
330
331     relativePosition.x = (actorPosition.x - mRelativePosition.x) / scrollSize.width;
332
333     float difference = fabsf(ShortestDistanceInDomain(mScrollPosition.x, scrollPosition.x, -max.x, -min.x));
334     mAverageSpeed = activate ? mAverageSpeed * invBlend + difference * blend : 0.0f;
335
336     actorPosition.x += relativePosition.x * mAverageSpeed;
337
338     return actorPosition - pagePosition;
339   }
340
341 private:
342
343   ScrollSlideInfoPtr mScrollSlideInfo;
344   Vector3 mScrollPosition;              ///< The current scroll position
345   float mDelayMin;                      ///< Minimum delay rate (at closest position to touch)
346   float mDelayMax;                      ///< Maximum delay rate (at furthest position from touch - 1 page away)
347   Vector2 mRelativePosition;
348   float mAverageSpeed;                  ///< The Average speed of the Actor (proportional to mScrollPosition - scrollPosition)
349
350 };
351
352 /**
353  * ScrollSlideScaleConstraint
354  *
355  */
356 struct ScrollSlideScaleConstraint
357 {
358   /**
359    * Constraint constructor
360    */
361   ScrollSlideScaleConstraint()
362   {
363   }
364
365   /**
366    * @param[in] current The current position
367    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
368    * @param[in] effectReferenceProperty The point in the scroll-view where the user touched the screen
369    * @param[in] effectTimeProperty The current timer. Starting from 0.0 when scroll animation/dragging
370    * commences. Ensures that constraint is applied and processed every frame (to achieve the delay effect)
371    * @param[in] sizeProperty The size of the ScrollView.
372    * @return The new position of this Actor.
373    */
374   Vector3 operator()(const Vector3& current,
375                      const PropertyInput& snapProperty)
376   {
377     float scale = 1.0f + snapProperty.GetFloat() * 0.008f;
378     return Vector3( current.x * scale, current.y * scale, current.z);
379   }
380
381 };
382
383 /**
384  * Applies the slide constraints to the child actor for overshoot effect.
385  *
386  * @param[in] scrollView The ScrollView containing the pages.
387  * @param[in] child The child to be affected with the slide effect.
388  * @param[in] angleSwing The maximum amount the child actor should
389  * rotate in radians for each axis (X and Y) as the page is scrolled.
390  * move for each axis (X and Y) as the page is scrolled.
391  */
392 void ApplyScrollSlideConstraints(ScrollSlideInfoPtr scrollSlideInfo,
393                                 Toolkit::ScrollView scrollView,
394                                 Actor child,
395                                 float delayMin,
396                                 float delayMax)
397 {
398   // Apply constraints to these actors //
399   Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
400                                          ParentSource(Actor::POSITION),
401                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewSlideEffect::EFFECT_TIME ) ),
402                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_DELTA_PROPERTY_NAME ) ),
403                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewSlideEffect::EFFECT_ACTIVE ) ),
404                                          ScrollSlidePositionConstraint(scrollSlideInfo, delayMin, delayMax) );
405   constraint.SetRemoveAction( Constraint::Discard );
406   child.ApplyConstraint( constraint );
407
408   constraint = Constraint::New<Vector3>( Actor::SCALE,
409                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewSlideEffect::EFFECT_ACTIVE ) ),
410                                          ScrollSlideScaleConstraint() );
411   constraint.SetRemoveAction( Constraint::Discard );
412   child.ApplyConstraint( constraint );
413 }
414
415 } // unnamed namespace
416
417 namespace Dali
418 {
419
420 namespace Toolkit
421 {
422
423 namespace Internal
424 {
425
426 ScrollViewSlideEffect::ScrollViewSlideEffect()
427 : mScrollSlideInfo(new ScrollSlideInfo()),
428   mPropertyTime(Property::INVALID_INDEX),
429   mPropertyReference(Property::INVALID_INDEX),
430   mPropertyActive(Property::INVALID_INDEX),
431   mDelayReferenceOffset(Vector3::ZERO),
432   mMaxDelayDuration(DEFAULT_MAX_DELAY_DURATION)
433 {
434 }
435
436 ScrollViewSlideEffect::~ScrollViewSlideEffect()
437 {
438 }
439
440 bool ScrollViewSlideEffect::GetSlideDirection() const
441 {
442   return mScrollSlideInfo->mVertical;
443 }
444
445 void ScrollViewSlideEffect::SetSlideDirection(bool vertical)
446 {
447   mScrollSlideInfo->mVertical = vertical;
448 }
449
450 const Vector3& ScrollViewSlideEffect::GetDelayReferenceOffset() const
451 {
452   return mDelayReferenceOffset;
453 }
454
455 void ScrollViewSlideEffect::SetDelayReferenceOffset(const Vector3& offset)
456 {
457   mDelayReferenceOffset = offset;
458 }
459
460 float ScrollViewSlideEffect::GetMaxDelayDuration() const
461 {
462   return mMaxDelayDuration;
463 }
464
465 void ScrollViewSlideEffect::SetMaxDelayDuration(float duration)
466 {
467   mMaxDelayDuration = duration;
468 }
469
470 void ScrollViewSlideEffect::ApplyToActor(Actor child,
471                                          float delayMin,
472                                          float delayMax)
473 {
474   ApplyScrollSlideConstraints( mScrollSlideInfo,
475                                GetScrollView(),
476                                child,
477                                delayMin,
478                                delayMax );
479 }
480
481 void ScrollViewSlideEffect::OnAttach(Toolkit::ScrollView& scrollView)
482 {
483   mScrollSlideInfo->mScrollPosition = scrollView.GetProperty<Vector3>( scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) );
484   mScrollSlideInfo->mScrollSize = scrollView.GetProperty<Vector3>( Actor::SIZE );
485   mScrollSlideInfo->mScrollPositionMin = scrollView.GetProperty<Vector3>( scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) );
486   mScrollSlideInfo->mScrollPositionMax = scrollView.GetProperty<Vector3>( scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) );
487   mScrollSlideInfo->mScrollWrap = scrollView.GetProperty<bool>( scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) );
488   mScrollSlideInfo->mVertical = false;
489
490   // Create effect-time property if not already created.
491   if(mPropertyTime == Property::INVALID_INDEX)
492   {
493     mPropertyTime = SafeRegisterProperty( scrollView, Toolkit::ScrollViewSlideEffect::EFFECT_TIME, 0.0f );
494     mPropertyReference = SafeRegisterProperty( scrollView, Toolkit::ScrollViewSlideEffect::EFFECT_REFERENCE, Vector3::ZERO );
495     mPropertyActive = SafeRegisterProperty( scrollView, Toolkit::ScrollViewSlideEffect::EFFECT_ACTIVE, 0.0f );
496   }
497
498   // Create constraint to update ScrollSlideInfo
499   // Doesn't matter what this is applied to and on what property.
500   // Just needs to update mScrollSlideInfo values as properties change.
501   // The minor constraints (applied to the Actors) can use this mScrollSlideInfo.
502   Constraint constraint = Constraint::New<float>( mPropertyTime,
503                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
504                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewSlideEffect::EFFECT_REFERENCE ) ),
505                                          Source(scrollView, Actor::SIZE),
506                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
507                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
508                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
509                                          ScrollSlideInfoUpdate(mScrollSlideInfo) );
510   constraint.SetRemoveAction( Constraint::Discard );
511   mInfoUpdateConstraint = scrollView.ApplyConstraint( constraint );
512
513   // Connect to the scroll view signals
514   scrollView.ScrollStartedSignal().Connect(this, &ScrollViewSlideEffect::OnScrollStart);
515   scrollView.SnapStartedSignal().Connect(this, &ScrollViewSlideEffect::OnScrollSnapStarted);
516   scrollView.TouchedSignal().Connect(this, &ScrollViewSlideEffect::OnScrollTouched);
517
518   AttachActor(scrollView);
519 }
520
521 bool ScrollViewSlideEffect::OnScrollTouched(Actor actor, const TouchEvent& event)
522 {
523   // Ignore events with multiple-touch points
524   if (event.GetPointCount() != 1)
525   {
526     return false;
527   }
528
529   if (event.GetPoint(0).state == TouchPoint::Down)
530   {
531     const TouchPoint& point = event.GetPoint(0);
532     Vector3 touchPosition(point.local - Stage::GetCurrent().GetSize() * 0.5f);
533
534     Vector3 scrollPosition = GetScrollView().GetCurrentScrollPosition();
535     GetScrollView().SetProperty(mPropertyReference, scrollPosition + touchPosition + mDelayReferenceOffset);
536   }
537
538   return false;
539 }
540
541 void ScrollViewSlideEffect::OnDetach(Toolkit::ScrollView& scrollView)
542 {
543   scrollView.ScrollStartedSignal().Disconnect(this, &ScrollViewSlideEffect::OnScrollStart);
544   scrollView.SnapStartedSignal().Disconnect(this, &ScrollViewSlideEffect::OnScrollSnapStarted);
545   scrollView.TouchedSignal().Disconnect(this, &ScrollViewSlideEffect::OnScrollTouched);
546   scrollView.RemoveConstraint( mInfoUpdateConstraint );
547
548   if(mAnimation)
549   {
550     mAnimation.FinishedSignal().Disconnect(this, &ScrollViewSlideEffect::OnAnimationFinished);
551     mAnimation.Clear();
552     mAnimation.Reset();
553   }
554
555   if(mAnimationSnap)
556   {
557     mAnimationSnap.FinishedSignal().Disconnect(this, &ScrollViewSlideEffect::OnAnimationSnapFinished);
558     mAnimationSnap.Clear();
559     mAnimationSnap.Reset();
560   }
561 }
562
563 void ScrollViewSlideEffect::AttachActor(Actor actor)
564 {
565
566 }
567
568 void ScrollViewSlideEffect::DetachActor(Actor actor)
569 {
570   // TODO: remove the specific constraint defined in AttachActor (and possibly
571   // unregister property) - neither functionality exists in Dali.
572 }
573
574 void ScrollViewSlideEffect::ContinueAnimation(float endTime)
575 {
576   // continue animating
577   if(mAnimation)
578   {
579     mAnimation.FinishedSignal().Disconnect(this, &ScrollViewSlideEffect::OnAnimationFinished);
580     mAnimation.Clear();
581   }
582
583   Actor scrollView = GetScrollView();
584
585   mAnimation = Animation::New(SLIDEEFFECT_ANIMATION_MAX_TIME);
586   mAnimation.AnimateTo( Property(scrollView, mPropertyTime), endTime, AlphaFunctions::Linear );
587   mAnimation.FinishedSignal().Connect(this, &ScrollViewSlideEffect::OnAnimationFinished);
588   mAnimation.Play();
589 }
590
591 void ScrollViewSlideEffect::OnScrollStart( const Vector3& position )
592 {
593   Actor scrollView = GetScrollView();
594   GetScrollView().SetProperty(mPropertyTime, 0.0f);
595
596   ContinueAnimation(SLIDEEFFECT_ANIMATION_MAX_TIME);
597
598   if(mAnimationSnap)
599   {
600     mAnimationSnap.FinishedSignal().Disconnect(this, &ScrollViewSlideEffect::OnAnimationSnapFinished);
601     mAnimationSnap.Clear();
602   }
603
604   mAnimationSnap = Animation::New( EFFECT_SNAP_GROW_DURATION );
605   mAnimationSnap.AnimateTo( Property(scrollView, mPropertyActive), 1.0f, AlphaFunctions::Linear );
606   mAnimationSnap.FinishedSignal().Connect(this, &ScrollViewSlideEffect::OnAnimationSnapFinished);
607   mAnimationSnap.Play();
608 }
609
610 void ScrollViewSlideEffect::OnScrollSnapStarted(const Toolkit::ScrollView::SnapEvent& event)
611 {
612   if(mAnimationSnap)
613   {
614     mAnimationSnap.Clear();
615   }
616
617   Actor scrollView = GetScrollView();
618   mAnimationSnap = Animation::New(EFFECT_SNAP_DECAY_DURATION );
619   mAnimationSnap.AnimateTo( Property(scrollView, mPropertyActive), 0.0f, AlphaFunctions::Linear );
620   mAnimationSnap.FinishedSignal().Connect(this, &ScrollViewSlideEffect::OnAnimationSnapFinished);
621   mAnimationSnap.Play();
622 }
623
624 void ScrollViewSlideEffect::OnAnimationSnapFinished( Animation& animation )
625 {
626   mAnimationSnap.FinishedSignal().Disconnect(this, &ScrollViewSlideEffect::OnAnimationSnapFinished);
627   mAnimationSnap.Clear();
628
629   // stop time animation
630   if(mAnimation)
631   {
632     mAnimation.FinishedSignal().Disconnect(this, &ScrollViewSlideEffect::OnAnimationFinished);
633     mAnimation.Clear();
634   }
635 }
636
637 void ScrollViewSlideEffect::OnAnimationFinished( Animation& animation )
638 {
639   // still unstable, so continue animating.
640   // TODO: Requires an instability check to ensure time animation finishes when delay is
641   // less noticeable. i.e. all present scrollPositions are approx the same as mScrollPosition in constraints.
642   // best solution for this is to switch to a single history vector of scroll position, and compare if
643   // position has not deviated >= 0.5 pixel for the past 1 second.
644   float endTime = GetScrollView().GetProperty<float>(mPropertyTime) + SLIDEEFFECT_ANIMATION_MAX_TIME;
645   ContinueAnimation(endTime);
646 }
647
648 } // namespace Internal
649
650 } // namespace Toolkit
651
652 } // namespace Dali