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