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