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