395a3cb8771adfa766ce41c4323a512b327387e8
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // INTERNAL INCLUDES
18 #include <dali/public-api/events/mouse-wheel-event.h>
19
20 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
21 #include <dali-toolkit/public-api/controls/scrollable/scroll-component-impl.h>
22 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
23 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
24 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
25
26 // TODO: Change to two class system:
27 // 1. DraggableActor (is an actor which can be dragged anywhere/scaled/rotated, can be set to range using the ruler)
28 // 2. ScrollView (contains a draggable actor that can a) be dragged in the negative X, and Y domain, b) has a hitArea for touches)
29 // TODO: Rotation
30 // TODO: Asymetrical scaling
31 // TODO: external components (page and status overlays).
32 // TODO: Orientation.
33 // TODO: upgrade Vector2/3 to support returning Unit vectors, normals, & cross product (dot product is already provided)
34
35 using namespace Dali;
36
37 namespace
38 {
39
40 const int DEFAULT_REFRESH_INTERVAL_MILLISECONDS = 50;                                     ///< Refresh rate TODO: Animation should have an update signal (and see item-view-impl)
41 const float FLICK_SPEED_THRESHOLD = 500.0f;                                               ///< Flick threshold in pixels/ms
42 const float FREE_FLICK_SPEED_THRESHOLD = 200.0f;                                          ///< Free-Flick threshold in pixels/ms
43 const float AUTOLOCK_AXIS_MINIMUM_DISTANCE2 = 100.0f;                                     ///< Auto-lock axis after minimum distance squared.
44 const float FLICK_ORTHO_ANGLE_RANGE = 60.0f;                                              ///< degrees. (if >45, then supports diagonal flicking)
45 const unsigned int MAXIMUM_NUMBER_OF_VALUES = 5;                                          ///< Number of values to use for weighted pan calculation.
46 const Vector2 DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = Vector2(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each mouse wheel event received.
47 const unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET( 150u );
48
49 // predefined effect values
50 const Vector3 ANGLE_CAROUSEL_ROTATE(Math::PI * 0.5f, Math::PI * 0.5f, 0.0f);
51 const Vector3 ANGLE_CUBE_PAGE_ROTATE(Math::PI * 0.2f, Math::PI * 0.2f, 0.0f);  ///< Cube page rotates as if it has ten sides with the camera positioned inside
52 const Vector2 ANGLE_CUSTOM_CUBE_SWING(-Math::PI * 0.45f, -Math::PI * 0.45f);  ///< outer cube pages swing 90 degrees as they pan offscreen
53 const Vector2 ANGLE_SPIRAL_SWING_IN(Math::PI * 0.5f, Math::PI * 0.5f);
54 const Vector2 ANGLE_SPIRAL_SWING_OUT(Math::PI * 0.35f, Math::PI * 0.35f);
55 const Vector2 ANGLE_OUTER_CUBE_SWING(Math::PI * 0.5f, Math::PI * 0.5f);  ///< outer cube pages swing 90 degrees as they pan offscreen
56
57 // Helpers ////////////////////////////////////////////////////////////////////////////////////////
58
59 // TODO: GetAngle for Vector2 can be moved.
60 // GetAngle for Vector3 needs to be measured against a normal/plane.
61
62 /**
63  * @param[in] vector The 3D vector to be measured
64  * @return angle in radians from 0 to 2PI
65  */
66 float GetAngle(const Vector3& vector)
67 {
68   return atan2(vector.y, vector.x) + Math::PI;
69 }
70
71 /**
72  * @param[in] vector The 2D vector to be measured
73  * @return angle in radians from 0 to 2PI
74  */
75 float GetAngle(const Vector2& vector)
76 {
77   return atan2(vector.y, vector.x) + Math::PI;
78 }
79
80 /**
81  * Find the vector (distance) from (a) to (b)
82  * in domain (start) to (end)
83  * (\ / start)               (\ / end)
84  *   |-a                 b<----|
85  *
86  * @note assumes both (a) and (b) are already with the domain
87  * (start) to (end)
88  *
89  * @param[in] a the current point
90  * @param[in] b the target point
91  * @param[in] start the start of the domain
92  * @param[in] end the end of the domain
93  * @param[in] bias whether to only take the right direction or the left direction,
94  * or the shortest direction.
95  * @return the shortest direction and distance
96  */
97 float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::DirectionBias bias)
98 {
99   if(bias == Dali::Toolkit::DirectionBiasNone)
100   {
101     return ShortestDistanceInDomain( a, b, start, end );
102   }
103   //  (a-start + end-b)
104   float size = end-start;
105   float vect = b-a;
106
107   if(vect > 0)
108   {
109     // +ve vector
110     if(bias == Dali::Toolkit::DirectionBiasRight) // going right, take the vector.
111     {
112       return vect;
113     }
114     else
115     {
116       float aRight = a+size;
117       return b-aRight;
118     }
119   }
120   else
121   {
122     // -ve vector
123     if(bias == Dali::Toolkit::DirectionBiasLeft) // going left, take the vector.
124     {
125       return vect;
126     }
127     else
128     {
129       float aLeft = a-size;
130       return b-aLeft;
131     }
132   }
133 }
134
135 /**
136  * Returns the position of the anchor within actor
137  *
138  * @param actor The Actor
139  * @param anchor The Anchor point of interest.
140  * @return The position of the Anchor
141  */
142 Vector3 GetPositionOfAnchor(Actor &actor, const Vector3 &anchor)
143 {
144   Vector3 childPosition = actor.GetCurrentPosition();
145   Vector3 childAnchor = - actor.GetCurrentAnchorPoint() + anchor;
146   Vector3 childSize = actor.GetCurrentSize();
147
148   return childPosition + childAnchor * childSize;
149 }
150
151 // AlphaFunctions /////////////////////////////////////////////////////////////////////////////////
152
153 float FinalDefaultAlphaFunction(float offset)
154 {
155   return offset * 0.5f;
156 }
157
158 /**
159  * ConstantDecelerationAlphaFunction
160  * Newtoninan distance for constant deceleration
161  * v = 1 - t, s = t - 1/2 t^2
162  * when t = 0, s = 0.0 (min distance)
163  * when t = 1, s = 0.5 (max distance)
164  * progress = s / (max-min) = 2t - t^2
165  *
166  * @param[in] offset The input progress
167  * @return The output progress
168  */
169 float ConstantDecelerationAlphaFunction(float progress)
170 {
171   return progress * 2.0f - progress * progress;
172 }
173
174 // Internal Constraints ///////////////////////////////////////////////////////////////////////////
175
176 /**
177  * Internal Relative position Constraint
178  * Generates the relative position value of the scroll view
179  * based on the absolute position, and it's relation to the
180  * scroll domain. This is a value from 0.0f to 1.0f in each
181  * scroll position axis.
182  */
183 Vector3 InternalRelativePositionConstraint(const Vector3&    current,
184                                            const PropertyInput& scrollPositionProperty,
185                                            const PropertyInput& scrollMinProperty,
186                                            const PropertyInput& scrollMaxProperty,
187                                            const PropertyInput& scrollSizeProperty)
188 {
189   const Vector3& position = -scrollPositionProperty.GetVector3();
190   const Vector3& min = scrollMinProperty.GetVector3();
191   const Vector3& max = scrollMaxProperty.GetVector3();
192   const Vector3& size = scrollSizeProperty.GetVector3();
193
194   Vector3 relativePosition;
195   Vector3 domainSize = (max - min) - size;
196
197   relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
198   relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
199
200   return relativePosition;
201 }
202
203 } // unnamed namespace
204
205 namespace Dali
206 {
207
208 namespace Toolkit
209 {
210
211 namespace Internal
212 {
213
214 namespace
215 {
216
217 /**
218  * Internal Pre-Position Property Constraint.
219  *
220  * Generates position property based on current position + gesture displacement.
221  * Or generates position property based on positionX/Y.
222  * Note: This is the position prior to any clamping at scroll boundaries.
223  * TODO: Scale & Rotation Transforms.
224  */
225 struct InternalPrePositionConstraint
226 {
227   InternalPrePositionConstraint(const Vector2& initialPanMask,
228                                 bool axisAutoLock,
229                                 float axisAutoLockGradient)
230   : mInitialPanMask(initialPanMask),
231     mAxisAutoLock(axisAutoLock),
232     mLockAxis(ScrollView::LockPossible),
233     mAxisAutoLockGradient(axisAutoLockGradient),
234     mPrePosition(Vector3::ZERO),
235     mWasPanning(false)
236   {
237   }
238
239   Vector3 operator()(const Vector3&    current,
240                      const PropertyInput& gesturePositionProperty,
241                      const PropertyInput& gestureDisplacementProperty,
242                      const PropertyInput& scrollPositionXProperty,
243                      const PropertyInput& scrollPositionYProperty,
244                      const PropertyInput& panningProperty)
245   {
246     const bool panning = panningProperty.GetBoolean();
247     Vector3 scrollPostPosition;
248
249     if(panning)
250     {
251       // Check if panning has just started...
252       if(!mWasPanning)
253       {
254         mLocalStart = gesturePositionProperty.GetVector2() - gestureDisplacementProperty.GetVector2();
255         mPrePosition = current;
256         mLockAxis = ScrollView::LockPossible;
257
258         mCurrentPanMask = mInitialPanMask;
259       }
260
261       // Calculate Deltas...
262       Vector2 currentPosition = gesturePositionProperty.GetVector2();
263       Vector2 panDelta( currentPosition - mLocalStart );
264
265       // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
266       // appears mostly horizontal or mostly vertical respectively...
267       AxisAutoLock(panDelta);
268
269       // Restrict deltas based on ruler enable/disable and axis-lock state...
270       panDelta *= mCurrentPanMask;
271
272       // Perform Position transform based on input deltas...
273       scrollPostPosition = mPrePosition;
274       scrollPostPosition.GetVectorXY() += panDelta;
275     }
276     else
277     {
278       scrollPostPosition.x = scrollPositionXProperty.GetFloat();
279       scrollPostPosition.y = scrollPositionYProperty.GetFloat();
280     }
281
282     mWasPanning = panning;
283     return scrollPostPosition;
284   }
285
286   void AxisAutoLock(Vector2& panDelta)
287   {
288     if(mAxisAutoLock)
289     {
290       if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
291           mLockAxis == ScrollView::LockPossible)
292       {
293         float dx = fabsf(panDelta.x);
294         float dy = fabsf(panDelta.y);
295         if(dx * mAxisAutoLockGradient >= dy)
296         {
297           // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
298           mLockAxis = ScrollView::LockVertical;
299           mCurrentPanMask.y = 0.0f;
300         }
301         else if(dy * mAxisAutoLockGradient > dx)
302         {
303           // 0.36:1 gradient to the vertical (deviate < 20 degrees)
304           mLockAxis = ScrollView::LockHorizontal;
305           mCurrentPanMask.x = 0.0f;
306         }
307         else
308         {
309           mLockAxis = ScrollView::LockNone;
310         }
311       }
312     } // end if mAxisAutoLock
313   }
314
315   Vector2 mLocalStart;
316   Vector2 mInitialPanMask;              ///< Initial pan mask (based on ruler settings)
317   Vector2 mCurrentPanMask;              ///< Current pan mask that can be altered by axis lock mode.
318
319   bool mAxisAutoLock;                   ///< Set by ScrollView
320   ScrollView::LockAxis mLockAxis;
321   float mAxisAutoLockGradient;          ///< Set by ScrollView
322   Vector3 mPrePosition;
323   bool mWasPanning;
324 };
325
326 /**
327  * Internal Position Property Constraint.
328  *
329  * Generates position property based on pre-position
330  * Note: This is the position after clamping.
331  * (uses result of InternalPrePositionConstraint)
332  */
333 struct InternalPositionConstraint
334 {
335   InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY)
336   : mDomainMin( -domainX.min, -domainY.min ),
337     mDomainMax( -domainX.max, -domainY.max ),
338     mClampX( domainX.enabled ),
339     mClampY( domainY.enabled )
340   {
341   }
342
343   Vector3 operator()(const Vector3&    current,
344                      const PropertyInput& scrollPositionProperty,
345                      const PropertyInput& scrollSizeProperty)
346   {
347     Vector3 position = scrollPositionProperty.GetVector3();
348     const Vector2& size = scrollSizeProperty.GetVector3().GetVectorXY();
349
350     position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x ) : position.x;
351     position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y ) : position.y;
352
353     return position;
354   }
355
356   Vector2 mDomainMin;
357   Vector2 mDomainMax;
358   bool mClampX;
359   bool mClampY;
360
361 };
362
363 /**
364  * This constraint updates the X overshoot property using the difference
365  * mPropertyPrePosition.x and mPropertyPosition.x, returning a relative value between 0.0f and 1.0f
366  */
367 struct OvershootXConstraint
368 {
369   OvershootXConstraint(float maxOvershoot) : mLastOvershoot(0.0f), mMaxOvershoot(maxOvershoot) {}
370
371   float operator()(const float&    current,
372       const PropertyInput& scrollPrePositionProperty,
373       const PropertyInput& scrollPostPositionProperty)
374   {
375     Vector3 scrollPrePosition = scrollPrePositionProperty.GetVector3();
376     Vector3 scrollPostPosition = scrollPostPositionProperty.GetVector3();
377     float newOvershoot = scrollPrePosition.x - scrollPostPosition.x;
378     return (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
379   }
380
381   float mLastOvershoot;
382   float mMaxOvershoot;
383 };
384
385 /**
386  * This constraint updates the Y overshoot property using the difference
387  * mPropertyPrePosition.y and mPropertyPosition.y, returning a relative value between 0.0f and 1.0f
388  */
389 struct OvershootYConstraint
390 {
391   OvershootYConstraint(float maxOvershoot) : mLastOvershoot(0.0f), mMaxOvershoot(maxOvershoot) {}
392
393   float operator()(const float&    current,
394       const PropertyInput& scrollPrePositionProperty,
395       const PropertyInput& scrollPostPositionProperty)
396   {
397     Vector3 scrollPrePosition = scrollPrePositionProperty.GetVector3();
398     Vector3 scrollPostPosition = scrollPostPositionProperty.GetVector3();
399     float newOvershoot = scrollPrePosition.y - scrollPostPosition.y;
400     return (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
401   }
402
403   float mLastOvershoot;
404   float mMaxOvershoot;
405 };
406
407 /**
408  * When panning, this constraint updates the X property, otherwise
409  * it has no effect on the X property.
410  */
411 float InternalXConstraint(const float&    current,
412                           const PropertyInput& scrollPosition,
413                           const PropertyInput& panningProperty)
414 {
415   return scrollPosition.GetVector3().x;
416 }
417
418 /**
419  * When panning, this constraint updates the Y property, otherwise
420  * it has no effect on the Y property.
421  */
422 float InternalYConstraint(const float&    current,
423                           const PropertyInput& scrollPosition,
424                           const PropertyInput& panningProperty)
425 {
426   return scrollPosition.GetVector3().y;
427 }
428
429 /**
430  * Internal Position-Delta Property Constraint.
431  *
432  * Generates position-delta property based on scroll-position + scroll-offset properties.
433  */
434 Vector3 InternalPositionDeltaConstraint(const Vector3&    current,
435                                         const PropertyInput& scrollPositionProperty,
436                                         const PropertyInput& scrollOffsetProperty)
437 {
438   const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
439   const Vector3& scrollOffset = scrollOffsetProperty.GetVector3();
440
441   return scrollPosition + scrollOffset;
442 }
443
444 /**
445  * Internal Final Position Constraint
446  * The position of content is:
447  * of scroll-position + f(scroll-overshoot)
448  * where f(...) function defines how overshoot
449  * should affect final-position.
450  */
451 struct InternalFinalConstraint
452 {
453   InternalFinalConstraint(AlphaFunction functionX,
454                           AlphaFunction functionY)
455   : mFunctionX(functionX),
456     mFunctionY(functionY)
457   {
458   }
459
460   Vector3 operator()(const Vector3&    current,
461                      const PropertyInput& scrollPositionProperty,
462                      const PropertyInput& scrollOvershootXProperty,
463                      const PropertyInput& scrollOvershootYProperty)
464   {
465     const float& overshootx = scrollOvershootXProperty.GetFloat();
466     const float& overshooty = scrollOvershootYProperty.GetFloat();
467     Vector3 offset( mFunctionX(overshootx),
468                     mFunctionY(overshooty),
469                     0.0f);
470
471     return scrollPositionProperty.GetVector3() - offset;
472   }
473
474   AlphaFunction mFunctionX;
475   AlphaFunction mFunctionY;
476 };
477
478
479 BaseHandle Create()
480 {
481   return Toolkit::ScrollView::New();
482 }
483
484 TypeRegistration typeRegistration( typeid(Toolkit::ScrollView), typeid(Toolkit::Scrollable), Create );
485
486 SignalConnectorType signalConnector1( typeRegistration, Toolkit::ScrollView::SIGNAL_SNAP_STARTED, &ScrollView::DoConnectSignal );
487
488 }
489
490
491 ///////////////////////////////////////////////////////////////////////////////////////////////////
492 // ScrollView
493 ///////////////////////////////////////////////////////////////////////////////////////////////////
494
495 Dali::Toolkit::ScrollView ScrollView::New()
496 {
497   // Create the implementation
498   ScrollViewPtr scrollView(new ScrollView());
499
500   // Pass ownership to CustomActor via derived handle
501   Dali::Toolkit::ScrollView handle(*scrollView);
502
503   // Second-phase init of the implementation
504   // This can only be done after the CustomActor connection has been made...
505   scrollView->Initialize();
506
507   return handle;
508 }
509
510 ScrollView::ScrollView()
511 : ScrollBase(),
512   mInitialized(false),
513   mScrolling(false),
514   mScrollInterrupted(false),
515   mTouchDownTime(0u),
516   mSensitive(true),
517   mGestureStackDepth(0),
518   mRotationDelta(0.0f),
519   mScrollPreRotation(0.0f),
520   mScrollPostRotation(0.0f),
521   mTouchDownReceived(false),
522   mActorAutoSnapEnabled(false),
523   mAutoResizeContainerEnabled(false),
524   mWrapMode(false),
525   mAxisAutoLock(false),
526   mMinTouchesForPanning(1),
527   mMaxTouchesForPanning(1),
528   mLockAxis(LockPossible),
529   mRefreshIntervalMilliseconds(DEFAULT_REFRESH_INTERVAL_MILLISECONDS),
530   mAlterChild(false),
531   mOvershootDelay(1.0f),
532   mMaxOvershoot(Toolkit::ScrollView::DEFAULT_MAX_OVERSHOOT, Toolkit::ScrollView::DEFAULT_MAX_OVERSHOOT),
533   mDefaultMaxOvershoot(true),
534   mSnapOvershootDuration(Toolkit::ScrollView::DEFAULT_SNAP_OVERSHOOT_DURATION),
535   mSnapOvershootAlphaFunction(AlphaFunctions::EaseOut),
536   mSnapDuration(Toolkit::ScrollView::DEFAULT_SLOW_SNAP_ANIMATION_DURATION),
537   mSnapAlphaFunction(AlphaFunctions::EaseOut),
538   mFlickDuration(Toolkit::ScrollView::DEFAULT_FAST_SNAP_ANIMATION_DURATION),
539   mFlickAlphaFunction(AlphaFunctions::EaseOut),
540   mAxisAutoLockGradient(Toolkit::ScrollView::DEFAULT_AXIS_AUTO_LOCK_GRADIENT),
541   mFrictionCoefficient(Toolkit::ScrollView::DEFAULT_FRICTION_COEFFICIENT),
542   mFlickSpeedCoefficient(Toolkit::ScrollView::DEFAULT_FLICK_SPEED_COEFFICIENT),
543   mMaxFlickSpeed(Toolkit::ScrollView::DEFAULT_MAX_FLICK_SPEED)
544 {
545   SetRequiresMouseWheelEvents(true);
546 }
547
548 void ScrollView::OnInitialize()
549 {
550   Actor self = Self();
551   self.SetLeaveRequired(true);
552
553   // Internal Actor, used to hide actors from enumerations.
554   // Also actors added to Internal actor appear as overlays e.g. ScrollBar components.
555   mInternalActor = Actor::New();
556   mInternalActor.SetDrawMode(DrawMode::OVERLAY);
557   self.Add(mInternalActor);
558   mInternalActor.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
559   mInternalActor.SetParentOrigin(ParentOrigin::CENTER);
560   mInternalActor.SetAnchorPoint(AnchorPoint::CENTER);
561
562   mAlterChild = true;
563
564   // Register Scroll Properties.
565   RegisterProperties();
566
567   mScrollPostPosition = mScrollPrePosition = Vector3::ZERO;
568   mScrollPostScale = mScrollPreScale = Vector3::ONE;
569   mScrollPostRotation = mScrollPreRotation = 0.0f;
570
571   mMouseWheelScrollDistanceStep = Stage::GetCurrent().GetSize() * DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
572
573   mInitialized = true;
574
575   mGestureStackDepth = 0;
576
577   EnableGestureDetection( Gesture::Type( Gesture::Pan ) );
578
579   // For pan, default to only 1 touch required, ignoring touches outside this range.
580   SetTouchesRequiredForPanning(1, 1, false);
581
582   // By default we'll allow the user to freely drag the scroll view,
583   // while disabling the other rulers.
584   RulerPtr ruler = new DefaultRuler();
585   RulerPtr rulerDisabled = new DefaultRuler();
586   rulerDisabled->Disable();
587   mRulerX = ruler;
588   mRulerY = ruler;
589   mRulerScaleX = rulerDisabled;
590   mRulerScaleY = rulerDisabled;
591   mRulerRotation = rulerDisabled;
592
593   EnableScrollComponent(Toolkit::Scrollable::OvershootIndicator);
594
595   Vector3 size = GetControlSize();
596   UpdatePropertyDomain(size);
597   SetInternalConstraints();
598 }
599
600 void ScrollView::OnControlStageConnection()
601 {
602   if ( mSensitive )
603   {
604     SetScrollSensitive( false );
605     SetScrollSensitive( true );
606   }
607   if(IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator))
608   {
609     // try and make sure property notifications are set
610     EnableScrollComponent(Toolkit::Scrollable::OvershootIndicator);
611   }
612 }
613
614 void ScrollView::OnControlStageDisconnection()
615 {
616   if ( mSnapOvershootAnimation )
617   {
618     SetOvershootToOrigin();
619   }
620
621   StopAnimation();
622 }
623
624 ScrollView::~ScrollView()
625 {
626 }
627
628 AlphaFunction ScrollView::GetScrollSnapAlphaFunction() const
629 {
630   return mSnapAlphaFunction;
631 }
632
633 void ScrollView::SetScrollSnapAlphaFunction(AlphaFunction alpha)
634 {
635   mSnapAlphaFunction = alpha;
636 }
637
638 AlphaFunction ScrollView::GetScrollFlickAlphaFunction() const
639 {
640   return mFlickAlphaFunction;
641 }
642
643 void ScrollView::SetScrollFlickAlphaFunction(AlphaFunction alpha)
644 {
645   mFlickAlphaFunction = alpha;
646 }
647
648 float ScrollView::GetScrollSnapDuration() const
649 {
650   return mSnapDuration;
651 }
652
653 void ScrollView::SetScrollSnapDuration(float time)
654 {
655   mSnapDuration = time;
656 }
657
658 float ScrollView::GetScrollFlickDuration() const
659 {
660   return mFlickDuration;
661 }
662
663 void ScrollView::SetScrollFlickDuration(float time)
664 {
665   mFlickDuration = time;
666 }
667
668 void ScrollView::ApplyEffect(Toolkit::ScrollViewEffect effect)
669 {
670   Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
671
672   // Assertion check to ensure effect doesn't already exist in this scrollview
673   bool effectAlreadyExistsInScrollView(false);
674   for (ScrollViewEffectIter iter = mEffects.begin(); iter != mEffects.end(); ++iter)
675   {
676     if(*iter==effect)
677     {
678       effectAlreadyExistsInScrollView = true;
679       break;
680     }
681   }
682
683   DALI_ASSERT_ALWAYS(!effectAlreadyExistsInScrollView);
684
685   // add effect to effects list
686   mEffects.push_back(effect);
687
688   // invoke Attachment request to ScrollView first
689   GetImpl(effect).Attach(self);
690 }
691
692 Toolkit::ScrollViewEffect ScrollView::ApplyEffect(Toolkit::ScrollView::PageEffect effect)
693 {
694   Toolkit::ScrollViewEffect scrollEffect;
695   switch(effect)
696   {
697     case Toolkit::ScrollView::PageEffectNone:
698     {
699       break;
700     }
701     case Toolkit::ScrollView::PageEffectOuterCube:
702     {
703       Toolkit::ScrollViewCustomEffect customEffect;
704       scrollEffect = customEffect = Toolkit::ScrollViewCustomEffect::New();
705       Vector2 pageSize = Stage::GetCurrent().GetSize();
706       // set the page translation to the slide off distance, also add an extra value to space the pages, having a smaller spacing on translationOut will allow the spacing to reduce over time
707       // the page moving onto screen will start 50.0f further out (1.0f * 50.0f) and the spacing will reduce as its position reaches the centre (0.0f * 50.0f)
708       // the page moving off screen will slowly build a spacing from 0.0f to 20.0f
709       // the spacing from each page is added together for the final spacing between the two pages.
710       customEffect.SetPageTranslation(Vector3(pageSize.x, pageSize.y, 0) + Vector3(50.0f, 50.0f, 0.0f), Vector3(pageSize.x, pageSize.y, 0) + Vector3(20.0f, 20.0f, 0.0f));
711       customEffect.SetSwingAngleOut(ANGLE_CUSTOM_CUBE_SWING.x, Vector3(0.0f, -1.0f, 0.0f));
712       customEffect.SetSwingAnchor(AnchorPoint::CENTER, AnchorPoint::CENTER_LEFT);
713       customEffect.SetOpacityThreshold(0.7f);
714       break;
715     }
716     case Toolkit::ScrollView::PageEffectDepth:
717     {
718       Toolkit::ScrollViewCustomEffect customEffect;
719       scrollEffect = customEffect = Toolkit::ScrollViewCustomEffect::New();
720       break;
721     }
722     case Toolkit::ScrollView::PageEffectInnerCube:
723     {
724       Toolkit::ScrollViewCustomEffect customEffect;
725       scrollEffect = customEffect = Toolkit::ScrollViewCustomEffect::New();
726       customEffect.SetPageSpacing(Vector2(30.0f, 30.0f));
727       customEffect.SetAngledOriginPageRotation(ANGLE_CUBE_PAGE_ROTATE);
728       customEffect.SetSwingAngle(ANGLE_CUBE_PAGE_ROTATE.x, Vector3(0,-1,0));
729       customEffect.SetOpacityThreshold(0.5f);
730       break;
731     }
732     case Toolkit::ScrollView::PageEffectCarousel:
733     {
734       Toolkit::ScrollViewCustomEffect customEffect;
735       scrollEffect = customEffect = Toolkit::ScrollViewCustomEffect::New();
736       customEffect.SetPageTranslation(Vector3(0,0,0), Vector3(-30, 0, 0));
737       customEffect.SetPageSpacing(Vector2(60.0f, 60.0f));
738       customEffect.SetAngledOriginPageRotation(-ANGLE_CUBE_PAGE_ROTATE);
739       customEffect.SetOpacityThreshold(0.2f, 0.6f);
740       break;
741     }
742     case Toolkit::ScrollView::PageEffectSpiral:
743     {
744       Toolkit::ScrollViewCustomEffect customEffect;
745       scrollEffect = customEffect = Toolkit::ScrollViewCustomEffect::New();
746
747       Vector2 pageSize = Stage::GetCurrent().GetSize();
748       customEffect.SetSwingAngle(-ANGLE_SPIRAL_SWING_IN.x, Vector3(0.0f, -1.0f, 0.0f), ANGLE_SPIRAL_SWING_OUT.x, Vector3(0.0f, -1.0f, 0.0f));
749       //customEffect.SetSwingAngleAlphaFunctionOut(AlphaFunctions::EaseOut);
750       customEffect.SetSwingAnchor(AnchorPoint::CENTER_RIGHT);
751       customEffect.SetPageTranslation(Vector3(pageSize.x, pageSize.y, 0) + Vector3(100.0f, 100.0f, 0.0f), Vector3(pageSize.x, pageSize.y, -pageSize.y * 2.0f) * 0.33f);
752       //customEffect.SetPageTranslateAlphaFunctionOut(AlphaFunctions::EaseOut);
753       customEffect.SetOpacityThreshold(0.75f, 0.6f);
754       customEffect.SetOpacityAlphaFunctionIn(AlphaFunctions::EaseInOut);
755       break;
756     }
757     default:
758     {
759       DALI_ASSERT_DEBUG(0 && "unknown scroll view effect");
760     }
761   }
762   RemoveConstraintsFromChildren();
763   if(scrollEffect)
764   {
765     ApplyEffect(scrollEffect);
766   }
767   return scrollEffect;
768 }
769
770 void ScrollView::RemoveEffect(Toolkit::ScrollViewEffect effect)
771 {
772   Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
773
774   // remove effect from effects list
775   bool effectExistedInScrollView(false);
776   for (ScrollViewEffectIter iter = mEffects.begin(); iter != mEffects.end(); ++iter)
777   {
778     if(*iter==effect)
779     {
780       mEffects.erase(iter);
781       effectExistedInScrollView = true;
782       break;
783     }
784   }
785
786   // Assertion check to ensure effect existed.
787   DALI_ASSERT_ALWAYS(effectExistedInScrollView);
788
789   // invoke Detachment request to ScrollView last
790   GetImpl(effect).Detach(self);
791 }
792
793 void ScrollView::RemoveAllEffects()
794 {
795   Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
796
797   for (ScrollViewEffectIter effectIter = mEffects.begin(); effectIter != mEffects.end(); ++effectIter)
798   {
799     Toolkit::ScrollViewEffect effect = *effectIter;
800
801     // invoke Detachment request to ScrollView last
802     GetImpl(effect).Detach(self);
803   }
804
805   mEffects.clear();
806 }
807
808 void ScrollView::ApplyConstraintToChildren(Constraint constraint)
809 {
810   ApplyConstraintToBoundActors(constraint);
811 }
812
813 void ScrollView::RemoveConstraintsFromChildren()
814 {
815   RemoveConstraintsFromBoundActors();
816 }
817
818 const RulerPtr ScrollView::GetRulerX() const
819 {
820   return mRulerX;
821 }
822
823 const RulerPtr ScrollView::GetRulerY() const
824 {
825   return mRulerY;
826 }
827
828 void ScrollView::SetRulerX(RulerPtr ruler)
829 {
830   mRulerX = ruler;
831
832   Vector3 size = GetControlSize();
833   UpdatePropertyDomain(size);
834   UpdateMainInternalConstraint();
835 }
836
837 void ScrollView::SetRulerY(RulerPtr ruler)
838 {
839   mRulerY = ruler;
840
841   Vector3 size = GetControlSize();
842   UpdatePropertyDomain(size);
843   UpdateMainInternalConstraint();
844 }
845
846 void ScrollView::UpdatePropertyDomain(const Vector3& size)
847 {
848   Vector3 min;
849   Vector3 max;
850
851   bool canScrollVertical = false;
852   bool canScrollHorizontal = false;
853   Actor self = Self();
854   if(mRulerX->IsEnabled())
855   {
856     const Toolkit::RulerDomain& rulerDomain = mRulerX->GetDomain();
857     min.x = rulerDomain.min;
858     max.x = rulerDomain.max;
859
860     // make sure new scroll value is within new domain
861     float newScroll = min.x;
862     int scrollXPropertyIndex = self.GetPropertyIndex(Toolkit::ScrollView::SCROLL_X_PROPERTY_NAME);
863     if((fabsf(max.x - min.x) - size.x) > Math::MACHINE_EPSILON_1)
864     {
865       canScrollHorizontal = true;
866       float currentScroll = self.GetProperty<float>(scrollXPropertyIndex);
867       newScroll = Clamp(currentScroll, -(max.x - size.x), -min.x);
868     }
869     self.SetProperty(scrollXPropertyIndex, newScroll);
870   }
871
872   if(mRulerY->IsEnabled())
873   {
874     const Toolkit::RulerDomain& rulerDomain = mRulerY->GetDomain();
875     min.y = rulerDomain.min;
876     max.y = rulerDomain.max;
877
878     // make sure new scroll value is within new domain
879     float newScroll = min.y;
880     int scrollYPropertyIndex = self.GetPropertyIndex(Toolkit::ScrollView::SCROLL_Y_PROPERTY_NAME);
881     if((fabsf(max.y - min.y) - size.y) > Math::MACHINE_EPSILON_1)
882     {
883       canScrollVertical = true;
884       float currentScroll = self.GetProperty<float>(scrollYPropertyIndex);
885       newScroll = Clamp(currentScroll, -(max.y - size.y), -min.y);
886     }
887     self.SetProperty(scrollYPropertyIndex, newScroll);
888   }
889   self.SetProperty(mPropertyCanScrollVertical, canScrollVertical);
890   self.SetProperty(mPropertyCanScrollHorizontal, canScrollHorizontal);
891
892   self.SetProperty(mPropertyPositionMin, min );
893   self.SetProperty(mPropertyPositionMax, max );
894 }
895
896 void ScrollView::SetRulerScaleX(RulerPtr ruler)
897 {
898   mRulerScaleX = ruler;
899   UpdateMainInternalConstraint();
900 }
901
902 void ScrollView::SetRulerScaleY(RulerPtr ruler)
903 {
904   mRulerScaleY = ruler;
905   UpdateMainInternalConstraint();
906 }
907
908 void ScrollView::SetRulerRotation(RulerPtr ruler)
909 {
910   mRulerRotation = ruler;
911   UpdateMainInternalConstraint();
912 }
913
914 void ScrollView::SetScrollSensitive(bool sensitive)
915 {
916   Actor self = Self();
917   PanGestureDetector panGesture( GetPanGestureDetector() );
918
919   if((!mSensitive) && (sensitive))
920   {
921     mSensitive = sensitive;
922     panGesture.Attach(self);
923   }
924   else if((mSensitive) && (!sensitive))
925   {
926     // while the scroll view is panning, the state needs to be reset.
927     bool isPanning = self.GetProperty<bool>( mPropertyPanning );
928     if ( isPanning )
929     {
930       PanGesture cancelGesture( Gesture::Cancelled );
931       OnPan( cancelGesture );
932     }
933
934     panGesture.Detach(self);
935     mSensitive = sensitive;
936
937     mGestureStackDepth = 0;
938   }
939 }
940
941 void ScrollView::SetMaxOvershoot(float overshootX, float overshootY)
942 {
943   mMaxOvershoot.x = overshootX;
944   mMaxOvershoot.y = overshootY;
945   mDefaultMaxOvershoot = false;
946   UpdateMainInternalConstraint();
947 }
948
949 void ScrollView::SetSnapOvershootAlphaFunction(AlphaFunction alpha)
950 {
951   mSnapOvershootAlphaFunction = alpha;
952 }
953
954 void ScrollView::SetSnapOvershootDuration(float duration)
955 {
956   mSnapOvershootDuration = duration;
957 }
958
959 void ScrollView::SetTouchesRequiredForPanning(unsigned int minTouches, unsigned int maxTouches, bool endOutside)
960 {
961   PanGestureDetector panGesture( GetPanGestureDetector() );
962
963   mMinTouchesForPanning = minTouches;
964   mMaxTouchesForPanning = maxTouches;
965
966   if(endOutside)
967   {
968     panGesture.SetMinimumTouchesRequired(minTouches);
969     panGesture.SetMaximumTouchesRequired(maxTouches);
970   }
971   else
972   {
973     panGesture.SetMinimumTouchesRequired(1);
974     panGesture.SetMaximumTouchesRequired(UINT_MAX);
975   }
976 }
977
978 void ScrollView::SetActorAutoSnap(bool enable)
979 {
980   mActorAutoSnapEnabled = enable;
981 }
982
983 void ScrollView::SetAutoResize(bool enable)
984 {
985   mAutoResizeContainerEnabled = enable;
986   // TODO: This needs a lot of issues to be addressed before working.
987 }
988
989 bool ScrollView::GetWrapMode() const
990 {
991   return mWrapMode;
992 }
993
994 void ScrollView::SetWrapMode(bool enable)
995 {
996   mWrapMode = enable;
997   Self().SetProperty(mPropertyWrap, enable);
998 }
999
1000 int ScrollView::GetRefreshInterval() const
1001 {
1002   return mRefreshIntervalMilliseconds;
1003 }
1004
1005 void ScrollView::SetRefreshInterval(int milliseconds)
1006 {
1007   mRefreshIntervalMilliseconds = milliseconds;
1008 }
1009
1010 bool ScrollView::GetAxisAutoLock() const
1011 {
1012   return mAxisAutoLock;
1013 }
1014
1015 void ScrollView::SetAxisAutoLock(bool enable)
1016 {
1017   mAxisAutoLock = enable;
1018   UpdateMainInternalConstraint();
1019 }
1020
1021 float ScrollView::GetAxisAutoLockGradient() const
1022 {
1023   return mAxisAutoLockGradient;
1024 }
1025
1026 void ScrollView::SetAxisAutoLockGradient(float gradient)
1027 {
1028   DALI_ASSERT_DEBUG( gradient >= 0.0f && gradient <= 1.0f );
1029   mAxisAutoLockGradient = gradient;
1030   UpdateMainInternalConstraint();
1031 }
1032
1033 float ScrollView::GetFrictionCoefficient() const
1034 {
1035   return mFrictionCoefficient;
1036 }
1037
1038 void ScrollView::SetFrictionCoefficient(float friction)
1039 {
1040   DALI_ASSERT_DEBUG( friction > 0.0f );
1041   mFrictionCoefficient = friction;
1042 }
1043
1044 float ScrollView::GetFlickSpeedCoefficient() const
1045 {
1046   return mFlickSpeedCoefficient;
1047 }
1048
1049 void ScrollView::SetFlickSpeedCoefficient(float speed)
1050 {
1051   mFlickSpeedCoefficient = speed;
1052 }
1053
1054 float ScrollView::GetMaxFlickSpeed() const
1055 {
1056   return mMaxFlickSpeed;
1057 }
1058
1059 void ScrollView::SetMaxFlickSpeed(float speed)
1060 {
1061   mMaxFlickSpeed = speed;
1062 }
1063
1064 void ScrollView::SetMouseWheelScrollDistanceStep(Vector2 step)
1065 {
1066   mMouseWheelScrollDistanceStep = step;
1067 }
1068
1069 Vector2 ScrollView::GetMouseWheelScrollDistanceStep() const
1070 {
1071   return mMouseWheelScrollDistanceStep;
1072 }
1073
1074 unsigned int ScrollView::GetCurrentPage() const
1075 {
1076   // in case animation is currently taking place.
1077   Vector3 position = GetPropertyPrePosition();
1078
1079   Actor self = Self();
1080   unsigned int page = 0;
1081   unsigned int pagesPerVolume = 1;
1082   unsigned int volume = 0;
1083
1084   // if rulerX is enabled, then get page count (columns)
1085   page = mRulerX->GetPageFromPosition(-position.x, mWrapMode);
1086   volume = mRulerY->GetPageFromPosition(-position.y, mWrapMode);
1087   pagesPerVolume = mRulerX->GetTotalPages();
1088
1089   return volume * pagesPerVolume + page;
1090 }
1091
1092 Vector3 ScrollView::GetCurrentScrollPosition() const
1093 {
1094   // in case animation is currently taking place.
1095   return -GetPropertyPrePosition();
1096 }
1097
1098 Vector3 ScrollView::GetCurrentScrollScale() const
1099 {
1100   // in case animation is currently taking place.
1101   return GetPropertyScale();
1102 }
1103
1104 Vector3 ScrollView::GetDomainSize() const
1105 {
1106   Vector3 size = Self().GetCurrentSize();
1107
1108   const RulerDomain& xDomain = GetRulerX()->GetDomain();
1109   const RulerDomain& yDomain = GetRulerY()->GetDomain();
1110
1111   Vector3 domainSize = Vector3( xDomain.max - xDomain.min, yDomain.max - yDomain.min, 0.0f ) - size;
1112   return domainSize;
1113 }
1114
1115 void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, float rotation,
1116                              DirectionBias horizontalBias, DirectionBias verticalBias)
1117 {
1118   TransformTo(position, scale, rotation, mSnapDuration, horizontalBias, verticalBias);
1119 }
1120
1121 void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, float rotation, float duration,
1122                              DirectionBias horizontalBias, DirectionBias verticalBias)
1123 {
1124   // Guard against destruction during signal emission
1125   // Note that Emit() methods are called indirectly e.g. from within ScrollView::AnimateTo()
1126   Toolkit::ScrollView handle( GetOwner() );
1127
1128   Vector3 currentScrollPosition = GetCurrentScrollPosition();
1129   Self().SetProperty( mPropertyScrollStartPagePosition, currentScrollPosition );
1130
1131   if(mScrolling) // are we interrupting a current scroll?
1132   {
1133     // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
1134     mScrolling = false;
1135     mScrollCompletedSignalV2.Emit( currentScrollPosition );
1136   }
1137
1138   Self().SetProperty(mPropertyScrolling, true);
1139   mScrolling = true;
1140   mScrollStartedSignalV2.Emit( currentScrollPosition );
1141   bool animating = AnimateTo(-position,
1142                              Vector3::ONE * duration,
1143                              scale,
1144                              Vector3::ONE * duration,
1145                              rotation,
1146                              duration,
1147                              mSnapAlphaFunction,
1148                              true,
1149                              horizontalBias,
1150                              verticalBias,
1151                              Snap);
1152
1153   if(!animating)
1154   {
1155     // if not animating, then this pan has completed right now.
1156     Self().SetProperty(mPropertyScrolling, false);
1157     mScrolling = false;
1158     mScrollCompletedSignalV2.Emit( currentScrollPosition );
1159   }
1160 }
1161
1162 void ScrollView::ScrollTo(const Vector3& position)
1163 {
1164   ScrollTo(position, mSnapDuration );
1165 }
1166
1167 void ScrollView::ScrollTo(const Vector3& position, float duration)
1168 {
1169   ScrollTo(position, duration, DirectionBiasNone, DirectionBiasNone);
1170 }
1171
1172 void ScrollView::ScrollTo(const Vector3& position, float duration,
1173                           DirectionBias horizontalBias, DirectionBias verticalBias)
1174 {
1175   TransformTo(position, mScrollPostScale, mScrollPostRotation, duration, horizontalBias, verticalBias);
1176 }
1177
1178 void ScrollView::ScrollTo(unsigned int page)
1179 {
1180   ScrollTo(page, mSnapDuration);
1181 }
1182
1183 void ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
1184 {
1185   Vector3 position;
1186   unsigned int volume;
1187   unsigned int libraries;
1188
1189   // The position to scroll to is continuous and linear
1190   // unless a domain has been enabled on the X axis.
1191   // or if WrapMode has been enabled.
1192   bool carryX = mRulerX->GetDomain().enabled | mWrapMode;
1193   bool carryY = mRulerY->GetDomain().enabled | mWrapMode;
1194
1195   position.x = mRulerX->GetPositionFromPage(page, volume, carryX);
1196   position.y = mRulerY->GetPositionFromPage(volume, libraries, carryY);
1197
1198   ScrollTo(position, duration, bias, bias);
1199 }
1200
1201 void ScrollView::ScrollTo(Actor &actor)
1202 {
1203   ScrollTo(actor, mSnapDuration);
1204 }
1205
1206 void ScrollView::ScrollTo(Actor &actor, float duration)
1207 {
1208   DALI_ASSERT_ALWAYS(actor.GetParent() == Self());
1209
1210   Actor self = Self();
1211   Vector3 size = self.GetCurrentSize();
1212   Vector3 position = actor.GetCurrentPosition();
1213   position -= GetPropertyPrePosition();
1214
1215   ScrollTo(Vector3(position.x - size.width * 0.5f, position.y - size.height * 0.5f, 0.0f), duration);
1216 }
1217
1218 Actor ScrollView::FindClosestActor()
1219 {
1220   Actor self = Self();
1221   Vector3 size = self.GetCurrentSize();
1222
1223   return FindClosestActorToPosition(Vector3(size.width * 0.5f,size.height * 0.5f,0.0f));
1224 }
1225
1226 Actor ScrollView::FindClosestActorToPosition(const Vector3& position, FindDirection dirX, FindDirection dirY, FindDirection dirZ)
1227 {
1228   Actor closestChild;
1229   float closestDistance2 = 0.0f;
1230   Vector3 actualPosition = position;
1231
1232   unsigned int numChildren = Self().GetChildCount();
1233
1234   for(unsigned int i = 0; i < numChildren; ++i)
1235   {
1236     Actor child = Self().GetChildAt(i);
1237
1238     if(mInternalActor == child) // ignore internal actor.
1239     {
1240       continue;
1241     }
1242
1243     Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
1244
1245     Vector3 delta = childPosition - actualPosition;
1246
1247     // X-axis checking (only find Actors to the [dirX] of actualPosition)
1248     if(dirX > All) // != All,None
1249     {
1250       FindDirection deltaH = delta.x > 0 ? Right : Left;
1251       if(dirX != deltaH)
1252       {
1253         continue;
1254       }
1255     }
1256
1257     // Y-axis checking (only find Actors to the [dirY] of actualPosition)
1258     if(dirY > All) // != All,None
1259     {
1260       FindDirection deltaV = delta.y > 0 ? Down : Up;
1261       if(dirY  != deltaV)
1262       {
1263         continue;
1264       }
1265     }
1266
1267     // Z-axis checking (only find Actors to the [dirZ] of actualPosition)
1268     if(dirZ > All) // != All,None
1269     {
1270       FindDirection deltaV = delta.y > 0 ? In : Out;
1271       if(dirZ  != deltaV)
1272       {
1273         continue;
1274       }
1275     }
1276
1277     // compare child to closest child in terms of distance.
1278     float distance2 = 0.0f;
1279
1280     // distance2 = the Square of the relevant dimensions of delta
1281     if(dirX != None)
1282     {
1283       distance2 += delta.x * delta.x;
1284     }
1285
1286     if(dirY != None)
1287     {
1288       distance2 += delta.y * delta.y;
1289     }
1290
1291     if(dirZ != None)
1292     {
1293       distance2 += delta.z * delta.z;
1294     }
1295
1296     if(closestChild) // Next time.
1297     {
1298       if(distance2 < closestDistance2)
1299       {
1300         closestChild = child;
1301         closestDistance2 = distance2;
1302       }
1303     }
1304     else // First time.
1305     {
1306       closestChild = child;
1307       closestDistance2 = distance2;
1308     }
1309   }
1310
1311   return closestChild;
1312 }
1313
1314 bool ScrollView::ScrollToSnapPoint()
1315 {
1316   Vector2 stationaryVelocity = Vector2(0.0f, 0.0f);
1317   return SnapWithVelocity( stationaryVelocity );
1318 }
1319
1320 void ScrollView::ScaleTo(const Vector3& scale)
1321 {
1322   ScaleTo(scale, mSnapDuration);
1323 }
1324
1325 void ScrollView::ScaleTo(const Vector3& scale, float duration)
1326 {
1327   TransformTo(mScrollPostPosition, scale, mScrollPostRotation, duration);
1328 }
1329
1330
1331 // TODO: In situations where axes are different (X snap, Y free)
1332 // Each axis should really have their own independent animation (time and equation)
1333 // Consider, X axis snapping to nearest grid point (EaseOut over fixed time)
1334 // Consider, Y axis simulating physics to arrive at a point (Physics equation over variable time)
1335 // Currently, the axes have been split however, they both use the same EaseOut equation.
1336 bool ScrollView::SnapWithVelocity(Vector2 velocity)
1337 {
1338   // Animator takes over now, touches are assumed not to interfere.
1339   // And if touches do interfere, then we'll stop animation, update PrePosition
1340   // to current mScroll's properties, and then resume.
1341   // Note: For Flicking this may work a bit different...
1342
1343   float angle = atan2(velocity.y, velocity.x);
1344   float speed2 = velocity.LengthSquared();
1345   AlphaFunction alphaFunction = mSnapAlphaFunction;
1346   Vector3 positionDuration = Vector3::ONE * mSnapDuration;
1347   Vector3 scaleDuration = Vector3::ONE * mSnapDuration;
1348   float rotationDuration = mSnapDuration;
1349   float biasX = 0.5f;
1350   float biasY = 0.5f;
1351   FindDirection horizontal = None;
1352   FindDirection vertical = None;
1353
1354   // orthoAngleRange = Angle tolerance within the Exact N,E,S,W direction
1355   // that will be accepted as a general N,E,S,W flick direction.
1356
1357   const float orthoAngleRange = FLICK_ORTHO_ANGLE_RANGE * M_PI / 180.0f;
1358   const float flickSpeedThreshold2 = FLICK_SPEED_THRESHOLD*FLICK_SPEED_THRESHOLD;
1359
1360   // Flick logic X Axis
1361
1362   if(mRulerX->IsEnabled())
1363   {
1364     horizontal = All;
1365
1366     if(speed2 > flickSpeedThreshold2) // exceeds flick threshold
1367     {
1368       if((angle >= -orthoAngleRange) && (angle < orthoAngleRange)) // Swiping East
1369       {
1370         biasX = 0.0f, horizontal = Left;
1371       }
1372       else if((angle >= M_PI-orthoAngleRange) || (angle < -M_PI+orthoAngleRange)) // Swiping West
1373       {
1374         biasX = 1.0f, horizontal = Right;
1375       }
1376     }
1377   }
1378
1379   // Flick logic Y Axis
1380
1381   if(mRulerY->IsEnabled())
1382   {
1383     vertical = All;
1384
1385     if(speed2 > flickSpeedThreshold2) // exceeds flick threshold
1386     {
1387       if((angle >= M_PI_2-orthoAngleRange) && (angle < M_PI_2+orthoAngleRange)) // Swiping South
1388       {
1389         biasY = 0.0f, vertical = Up;
1390       }
1391       else if((angle >= -M_PI_2-orthoAngleRange) && (angle < -M_PI_2+orthoAngleRange)) // Swiping North
1392       {
1393         biasY = 1.0f, vertical = Down;
1394       }
1395     }
1396   }
1397
1398   // isFlick: Whether this gesture is a flick or not.
1399   bool isFlick = (horizontal != All || vertical != All);
1400   // isFreeFlick: Whether this gesture is a flick under free panning criteria.
1401   bool isFreeFlick = velocity.LengthSquared() > (FREE_FLICK_SPEED_THRESHOLD*FREE_FLICK_SPEED_THRESHOLD);
1402
1403   if(isFlick || isFreeFlick)
1404   {
1405     positionDuration = Vector3::ONE * mFlickDuration;
1406     alphaFunction = mFlickAlphaFunction;
1407   }
1408
1409   // Position Snap ////////////////////////////////////////////////////////////
1410   Vector3 positionSnap = mScrollPostPosition;
1411
1412   if(mActorAutoSnapEnabled)
1413   {
1414     Vector3 size = Self().GetCurrentSize();
1415
1416     Actor child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f), horizontal, vertical );
1417
1418     if(!child && isFlick )
1419     {
1420       // If we conducted a direction limited search and found no actor, then just snap to the closest actor.
1421       child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f) );
1422     }
1423
1424     if(child)
1425     {
1426       Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
1427
1428       // Get center-point of the Actor.
1429       Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
1430
1431       if(mRulerX->IsEnabled())
1432       {
1433         positionSnap.x = position.x - childPosition.x + size.width * 0.5f;
1434       }
1435       if(mRulerY->IsEnabled())
1436       {
1437         positionSnap.y = position.y - childPosition.y + size.height * 0.5f;
1438       }
1439     }
1440   }
1441
1442   Vector3 startPosition = positionSnap;
1443   positionSnap.x = -mRulerX->Snap(-positionSnap.x, biasX);  // NOTE: X & Y rulers think in -ve coordinate system.
1444   positionSnap.y = -mRulerY->Snap(-positionSnap.y, biasY);  // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
1445
1446   Vector3 clampDelta(Vector3::ZERO);
1447   ClampPosition(positionSnap);
1448
1449   if( (mRulerX->GetType() == Ruler::Free || mRulerY->GetType() == Ruler::Free)
1450       && isFreeFlick && !mActorAutoSnapEnabled)
1451   {
1452     // Calculate target position based on velocity of flick.
1453
1454     // a = Deceleration (Set to diagonal stage length * friction coefficient)
1455     // u = Initial Velocity (Flick velocity)
1456     // v = 0 (Final Velocity)
1457     // t = Time (Velocity / Deceleration)
1458     Vector2 stageSize = Stage::GetCurrent().GetSize();
1459     float stageLength = Vector3(stageSize.x, stageSize.y, 0.0f).Length();
1460     float a = (stageLength * mFrictionCoefficient);
1461     Vector3 u = Vector3(velocity.x, velocity.y, 0.0f) * mFlickSpeedCoefficient;
1462     float speed = u.Length();
1463     u/= speed;
1464
1465     // TODO: Change this to a decay function. (faster you flick, the slower it should be)
1466     speed = std::min(speed, stageLength * mMaxFlickSpeed );
1467     u*= speed;
1468     alphaFunction = ConstantDecelerationAlphaFunction;
1469
1470     float t = speed / a;
1471
1472     if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
1473     {
1474       positionSnap.x += t*u.x*0.5f;
1475     }
1476
1477     if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
1478     {
1479       positionSnap.y += t*u.y*0.5f;
1480     }
1481
1482     clampDelta = positionSnap;
1483     ClampPosition(positionSnap);
1484     if((positionSnap - startPosition).LengthSquared() > Math::MACHINE_EPSILON_0)
1485     {
1486       clampDelta -= positionSnap;
1487       clampDelta.x = clampDelta.x > 0.0f ? std::min(clampDelta.x, mMaxOvershoot.x) : std::max(clampDelta.x, -mMaxOvershoot.x);
1488       clampDelta.y = clampDelta.y > 0.0f ? std::min(clampDelta.y, mMaxOvershoot.y) : std::max(clampDelta.y, -mMaxOvershoot.y);
1489     }
1490     else
1491     {
1492       clampDelta = Vector3::ZERO;
1493     }
1494
1495     // If Axis is Free and has velocity, then calculate time taken
1496     // to reach target based on velocity in axis.
1497     if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
1498     {
1499       float deltaX = fabsf(startPosition.x - positionSnap.x);
1500
1501       if(fabsf(u.x) > Math::MACHINE_EPSILON_1)
1502       {
1503         positionDuration.x = fabsf(deltaX / u.x);
1504       }
1505       else
1506       {
1507         positionDuration.x = 0;
1508       }
1509     }
1510
1511     if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
1512     {
1513       float deltaY = fabsf(startPosition.y - positionSnap.y);
1514
1515       if(fabsf(u.y) > Math::MACHINE_EPSILON_1)
1516       {
1517         positionDuration.y = fabsf(deltaY / u.y);
1518       }
1519       else
1520       {
1521         positionDuration.y = 0;
1522       }
1523     }
1524   }
1525   positionSnap += clampDelta;
1526
1527   // Scale Snap ///////////////////////////////////////////////////////////////
1528   Vector3 scaleSnap = mScrollPostScale;
1529
1530   scaleSnap.x = mRulerScaleX->Snap(scaleSnap.x);
1531   scaleSnap.y = mRulerScaleY->Snap(scaleSnap.y);
1532
1533   ClampScale(scaleSnap);
1534
1535   // Rotation Snap ////////////////////////////////////////////////////////////
1536   float rotationSnap = mScrollPostRotation;
1537   // TODO: implement rotation snap
1538
1539   bool animating = AnimateTo(positionSnap, positionDuration,
1540                              scaleSnap, scaleDuration,
1541                              rotationSnap, rotationDuration,
1542                              alphaFunction, false,
1543                              DirectionBiasNone, DirectionBiasNone,
1544                              isFlick || isFreeFlick ? Flick : Snap);
1545
1546   if(animating)
1547   {
1548     AnimateOvershootToOrigin(positionDuration.x, positionDuration.y);
1549   }
1550
1551   return animating;
1552 }
1553
1554 void ScrollView::StopAnimation(void)
1555 {
1556   // Clear Snap animation if exists.
1557   if(mSnapAnimation)
1558   {
1559     mSnapAnimation.Stop();
1560     mSnapAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapAnimationFinished);
1561     mSnapAnimation.Clear();
1562     mSnapAnimation = NULL;
1563   }
1564   if(mSnapXAnimation)
1565   {
1566     mSnapXAnimation.Stop();
1567     mSnapXAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapXAnimationFinished);
1568     mSnapXAnimation.Clear();
1569     mSnapXAnimation = NULL;
1570   }
1571   if(mSnapYAnimation)
1572   {
1573     mSnapYAnimation.Stop();
1574     mSnapYAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapYAnimationFinished);
1575     mSnapYAnimation.Clear();
1576     mSnapYAnimation = NULL;
1577   }
1578   if(mSnapOvershootAnimation)
1579   {
1580     mSnapOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapOvershootAnimationFinished);
1581     mSnapOvershootAnimation.Stop();
1582     mSnapOvershootAnimation.Clear();
1583     mSnapOvershootAnimation = NULL;
1584   }
1585   HandleStoppedAnimation();
1586 }
1587
1588 bool ScrollView::AnimateTo(const Vector3& position, const Vector3& positionDuration,
1589                            const Vector3& scale, const Vector3& scaleDuration,
1590                            float rotation, float rotationDuration,
1591                            AlphaFunction alpha, bool findShortcuts,
1592                            DirectionBias horizontalBias, DirectionBias verticalBias,
1593                            SnapType snapType)
1594 {
1595   // Here we perform an animation on a number of properties (depending on which have changed)
1596   // The animation is applied to all ScrollBases
1597   Actor self = Self();
1598   bool startAnimation = false;
1599   Vector3 positionTransformed = position;
1600   float totalDuration = 0.0f;
1601
1602   bool positionChanged = (positionTransformed != mScrollPostPosition);
1603   bool scaleChanged = (scale != mScrollPostScale);
1604   bool rotationChanged = fabsf(rotation - mScrollPostRotation) > Math::MACHINE_EPSILON_0;
1605
1606   if(positionChanged)
1607   {
1608     totalDuration = std::max(totalDuration, positionDuration.x);
1609     totalDuration = std::max(totalDuration, positionDuration.y);
1610   }
1611
1612   if(scaleChanged)
1613   {
1614     totalDuration = std::max(totalDuration, scaleDuration.x);
1615     totalDuration = std::max(totalDuration, scaleDuration.y);
1616   }
1617
1618   if(rotationChanged)
1619   {
1620     totalDuration = std::max(totalDuration, rotationDuration);
1621   }
1622
1623   if(totalDuration > Math::MACHINE_EPSILON_1)
1624   {
1625     StopAnimation();
1626     mSnapAnimation = Animation::New(totalDuration);
1627     mSnapAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapAnimationFinished);
1628     mSnapXAnimation = Animation::New(positionDuration.x);
1629     mSnapXAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapXAnimationFinished);
1630     mSnapYAnimation = Animation::New(positionDuration.y);
1631     mSnapYAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapYAnimationFinished);
1632     startAnimation = true;
1633
1634     // Position Delta ///////////////////////////////////////////////////////
1635     if(positionChanged)
1636     {
1637       if(mWrapMode && findShortcuts)
1638       {
1639         // In Wrap Mode, the shortest distance is a little less intuitive...
1640         const RulerDomain rulerDomainX = mRulerX->GetDomain();
1641         const RulerDomain rulerDomainY = mRulerY->GetDomain();
1642
1643         if(mRulerX->IsEnabled())
1644         {
1645           float dir = VectorInDomain(-mScrollPostPosition.x, -positionTransformed.x, rulerDomainX.min, rulerDomainX.max, horizontalBias);
1646           positionTransformed.x = mScrollPostPosition.x + -dir;
1647         }
1648
1649         if(mRulerY->IsEnabled())
1650         {
1651           float dir = VectorInDomain(-mScrollPostPosition.y, -positionTransformed.y, rulerDomainY.min, rulerDomainY.max, verticalBias);
1652           positionTransformed.y = mScrollPostPosition.y + -dir;
1653         }
1654       }
1655
1656       // note we have two separate animations for X & Y, this deals with sliding diagonally and hitting
1657       // a horizonal/vertical wall.delay
1658       mSnapXAnimation.AnimateTo( Property(self, mPropertyX), positionTransformed.x, alpha, TimePeriod(0.0f, positionDuration.x));
1659       mSnapYAnimation.AnimateTo( Property(self, mPropertyY), positionTransformed.y, alpha, TimePeriod(0.0f, positionDuration.y));
1660     }
1661
1662     // Scale Delta ///////////////////////////////////////////////////////
1663     if(scaleChanged)
1664     {
1665       // TODO: for non-uniform scaling to different bounds e.g. scaling a square to a 4:3 aspect ratio screen with a velocity
1666       // the height will hit first, and then the width, so that would require two different animation times just like position.
1667       mSnapAnimation.AnimateTo( Property(self, mPropertyScale), scale, alpha, TimePeriod(0.0f, scaleDuration.x));
1668     }
1669
1670     mSnapAnimation.AnimateTo( Property(self, mPropertyTime), totalDuration, AlphaFunctions::Linear );
1671
1672     mSnapAnimation.Play();
1673     mSnapXAnimation.Play();
1674     mSnapYAnimation.Play();
1675     StartRefreshTimer();
1676   } // end if(totalDuration > Math::MACHINE_EPSILON_1)
1677   else // totalDuration == 0
1678   {
1679     // instantly set transform.
1680     if(positionChanged)
1681     {
1682       self.SetProperty(mPropertyX, positionTransformed.x);
1683       self.SetProperty(mPropertyY, positionTransformed.y);
1684
1685       mScrollPrePosition = mScrollPostPosition = positionTransformed;
1686     }
1687
1688     if(scaleChanged)
1689     {
1690       self.SetProperty(mPropertyScale, scale);
1691
1692       mScrollPreScale = mScrollPostScale = scale;
1693     }
1694   }
1695
1696   // Always send a snap event when AnimateTo is called.
1697   Toolkit::ScrollView::SnapEvent snapEvent;
1698   snapEvent.type = snapType;
1699   snapEvent.position = positionTransformed;
1700   snapEvent.scale = scale;
1701   snapEvent.rotation = rotation;
1702   snapEvent.duration = totalDuration;
1703
1704   mSnapStartedSignalV2.Emit( snapEvent );
1705
1706   return startAnimation;
1707 }
1708
1709 void ScrollView::SetOvershootEnabled(bool enabled)
1710 {
1711   if(enabled && !mOvershootIndicator)
1712   {
1713     mOvershootIndicator = ScrollOvershootIndicator::New(*this);
1714   }
1715   mOvershootIndicator->Enable(enabled);
1716 }
1717
1718 void ScrollView::AddOverlay(Actor actor)
1719 {
1720   mInternalActor.Add( actor );
1721 }
1722
1723 void ScrollView::RemoveOverlay(Actor actor)
1724 {
1725   mInternalActor.Remove( actor );
1726 }
1727
1728 void ScrollView::SetScrollingDirection( Radian direction, Radian threshold )
1729 {
1730   PanGestureDetector panGesture( GetPanGestureDetector() );
1731
1732   // First remove just in case we have some set, then add.
1733   panGesture.RemoveDirection( direction );
1734   panGesture.AddDirection( direction, threshold );
1735 }
1736
1737 void ScrollView::RemoveScrollingDirection( Radian direction )
1738 {
1739   PanGestureDetector panGesture( GetPanGestureDetector() );
1740   panGesture.RemoveDirection( direction );
1741 }
1742
1743 Toolkit::ScrollView::SnapStartedSignalV2& ScrollView::SnapStartedSignal()
1744 {
1745   return mSnapStartedSignalV2;
1746 }
1747
1748 void ScrollView::FindAndUnbindActor(Actor child)
1749 {
1750   UnbindActor(child);
1751 }
1752
1753 Vector3 ScrollView::GetPropertyPrePosition() const
1754 {
1755   Vector3 position(Self().GetProperty<float>(mPropertyX), Self().GetProperty<float>(mPropertyY), 0.0f);
1756   WrapPosition(position);
1757
1758   return position;
1759 }
1760
1761 Vector3 ScrollView::GetPropertyPosition() const
1762 {
1763   Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
1764   WrapPosition(position);
1765
1766   return position;
1767 }
1768
1769 Vector3 ScrollView::GetPropertyScale() const
1770 {
1771   return Self().GetProperty<Vector3>(mPropertyScale);
1772 }
1773
1774 void ScrollView::HandleStoppedAnimation()
1775 {
1776   // Animation has stopped, so stop sending the scroll-update signal.
1777   CancelRefreshTimer();
1778
1779   // cement transform now, and allow interactivity to resume.
1780   mScrollPostPosition = GetPropertyPosition();
1781
1782   mScrollPostScale = GetPropertyScale();
1783
1784   // Update Actor position with this wrapped value.
1785
1786   Self().SetProperty(mPropertyX, mScrollPostPosition.x);
1787   Self().SetProperty(mPropertyY, mScrollPostPosition.y);
1788   // TODO Rotation
1789
1790   mScrollPrePosition = mScrollPostPosition;
1791   mScrollPreScale = mScrollPostScale;
1792   mScrollPreRotation = mScrollPostRotation;
1793 }
1794
1795 void ScrollView::HandleSnapAnimationFinished()
1796 {
1797   // Emit Signal that scrolling has completed.
1798   mScrolling = false;
1799   Self().SetProperty(mPropertyScrolling, false);
1800
1801   Vector3 deltaPosition(Self().GetProperty<float>(mPropertyX),
1802                         Self().GetProperty<float>(mPropertyY),
1803                         0.0f);
1804
1805   Vector3 currentScrollPosition = GetCurrentScrollPosition();
1806   mScrollCompletedSignalV2.Emit( currentScrollPosition );
1807
1808   mDomainOffset += deltaPosition - mScrollPostPosition;
1809   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
1810   HandleStoppedAnimation();
1811 }
1812
1813 bool ScrollView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1814 {
1815   Dali::BaseHandle handle( object );
1816
1817   bool connected( true );
1818   Toolkit::ScrollView view = Toolkit::ScrollView::DownCast( handle );
1819
1820   if( Toolkit::ScrollView::SIGNAL_SNAP_STARTED == signalName )
1821   {
1822     view.SnapStartedSignal().Connect( tracker, functor );
1823   }
1824   else
1825   {
1826     // signalName does not match any signal
1827     connected = false;
1828   }
1829
1830   return connected;
1831 }
1832
1833 void ScrollView::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
1834 {
1835   // need to update domain properties for new size
1836   UpdatePropertyDomain(targetSize);
1837 }
1838
1839 void ScrollView::OnControlSizeSet( const Vector3& size )
1840 {
1841   // need to update domain properties for new size
1842   if( mDefaultMaxOvershoot )
1843   {
1844     mMaxOvershoot.x = size.x * 0.5f;
1845     mMaxOvershoot.y = size.y * 0.5f;
1846   }
1847   UpdatePropertyDomain(size);
1848   UpdateMainInternalConstraint();
1849   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
1850   {
1851     mOvershootIndicator->Reset();
1852   }
1853 }
1854
1855 void ScrollView::OnChildAdd(Actor& child)
1856 {
1857   if(mAlterChild)
1858   {
1859     BindActor(child);
1860   }
1861 }
1862
1863 void ScrollView::OnChildRemove(Actor& child)
1864 {
1865   // TODO: Actor needs a RemoveConstraint method to take out an individual constraint.
1866   UnbindActor(child);
1867 }
1868
1869 bool ScrollView::OnTouchEvent(const TouchEvent& event)
1870 {
1871   if(!mSensitive)
1872   {
1873     // Ignore this touch event, if scrollview is insensitive.
1874     return false;
1875   }
1876
1877   // Ignore events with multiple-touch points
1878   if (event.GetPointCount() != 1)
1879   {
1880     return false;
1881   }
1882
1883   if (event.GetPoint(0).state == TouchPoint::Down)
1884   {
1885     mTouchDownTime = event.time;
1886     mTouchDownReceived = true;
1887     mTouchDownPosition = event.GetPoint(0).local;
1888
1889     if( mSnapAnimation || mSnapXAnimation || mSnapYAnimation || mSnapOvershootAnimation )
1890     {
1891       mScrollInterrupted = true;
1892       StopAnimation();
1893     }
1894
1895     if(mScrolling) // are we interrupting a current scroll?
1896     {
1897       // reset domain offset as scrolling from original plane.
1898       mDomainOffset = Vector3::ZERO;
1899       Self().SetProperty(mPropertyDomainOffset, Vector3::ZERO);
1900
1901       mScrolling = false;
1902       Vector3 currentScrollPosition = GetCurrentScrollPosition();
1903       mScrollCompletedSignalV2.Emit( currentScrollPosition );
1904     }
1905   }
1906   else if(event.GetPoint(0).state == TouchPoint::Up)
1907   {
1908     // if the user touches and releases without enough movement to go
1909     // into a gesture state, then we should snap to nearest point.
1910     // otherwise our scroll could be stopped (interrupted) half way through an animation.
1911     if(mGestureStackDepth==0 && mTouchDownReceived)
1912     {
1913       unsigned timeDelta( event.time - mTouchDownTime );
1914       if ( timeDelta >= MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET )
1915       {
1916         // Reset the velocity only if down was received a while ago
1917         mLastVelocity = Vector2( 0.0f, 0.0f );
1918       }
1919       else
1920       {
1921         Vector2 positionDelta( mTouchDownPosition - event.GetPoint(0).local );
1922         mLastVelocity = positionDelta / timeDelta;
1923       }
1924
1925       // Only finish the transform if scrolling was interrupted on down or if we are scrolling
1926       if ( mSnapAnimation || mSnapXAnimation || mSnapYAnimation || mSnapOvershootAnimation || mScrollInterrupted || mScrolling )
1927       {
1928         FinishTransform();
1929       }
1930     }
1931     mTouchDownReceived = false;
1932     mScrollInterrupted = false;
1933   }
1934
1935   return true; // consume since we're potentially scrolling
1936 }
1937
1938 bool ScrollView::OnMouseWheelEvent(const MouseWheelEvent& event)
1939 {
1940   if(!mSensitive)
1941   {
1942     // Ignore this mouse wheel event, if scrollview is insensitive.
1943     return false;
1944   }
1945
1946   Vector3 targetScrollPosition = GetPropertyPosition();
1947
1948   if(mRulerX->IsEnabled() && !mRulerY->IsEnabled())
1949   {
1950     // If only the ruler in the X axis is enabled, scroll in the X axis.
1951     if(mRulerX->GetType() == Ruler::Free)
1952     {
1953       // Free panning mode
1954       targetScrollPosition.x -= event.z * mMouseWheelScrollDistanceStep.x;
1955       ClampPosition(targetScrollPosition);
1956       ScrollTo(-targetScrollPosition);
1957     }
1958     else if(!mScrolling)
1959     {
1960       // Snap mode, only respond to the event when the previous snap animation is finished.
1961       ScrollTo(GetCurrentPage() + event.z);
1962     }
1963   }
1964   else
1965   {
1966     // If the ruler in the Y axis is enabled, scroll in the Y axis.
1967     if(mRulerY->GetType() == Ruler::Free)
1968     {
1969       // Free panning mode
1970       targetScrollPosition.y -= event.z * mMouseWheelScrollDistanceStep.y;
1971       ClampPosition(targetScrollPosition);
1972       ScrollTo(-targetScrollPosition);
1973     }
1974     else if(!mScrolling)
1975     {
1976       // Snap mode, only respond to the event when the previous snap animation is finished.
1977       ScrollTo(GetCurrentPage() + event.z * mRulerX->GetTotalPages());
1978     }
1979   }
1980
1981   return true;
1982 }
1983
1984 void ScrollView::OnSnapAnimationFinished( Animation& source )
1985 {
1986   mSnapAnimation.FinishedSignal().Disconnect( this, &ScrollView::OnSnapAnimationFinished );
1987   mSnapAnimation = NULL;
1988 }
1989
1990 void ScrollView::OnSnapXAnimationFinished( Animation& source )
1991 {
1992   // Guard against destruction during signal emission
1993   // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
1994   Toolkit::ScrollView handle( GetOwner() );
1995
1996   if(!mSnapYAnimation)
1997   {
1998     HandleSnapAnimationFinished();
1999   }
2000   if(mScrollMainInternalOvershootXConstraint)
2001   {
2002     Self().RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2003     mScrollMainInternalOvershootXConstraint.Reset();
2004     mScrollMainInternalOvershootXConstraint = 0;
2005   }
2006   mSnapXAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapXAnimationFinished);
2007   mSnapXAnimation.Reset();
2008   mSnapXAnimation = NULL;
2009   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2010   {
2011     // kick start animation to 0
2012     Self().SetProperty(mPropertyOvershootX, 0.0f);
2013   }
2014 }
2015
2016 void ScrollView::OnSnapYAnimationFinished( Animation& source )
2017 {
2018   // Guard against destruction during signal emission
2019   // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
2020   Toolkit::ScrollView handle( GetOwner() );
2021
2022   if(!mSnapXAnimation)
2023   {
2024     HandleSnapAnimationFinished();
2025   }
2026   if(mScrollMainInternalOvershootYConstraint)
2027   {
2028     Self().RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2029     mScrollMainInternalOvershootYConstraint.Reset();
2030     mScrollMainInternalOvershootYConstraint = 0;
2031   }
2032   mSnapYAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapYAnimationFinished);
2033   mSnapYAnimation.Reset();
2034   mSnapYAnimation = NULL;
2035   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2036   {
2037     // kick start animation to 0
2038     Self().SetProperty(mPropertyOvershootY, 0.0f);
2039   }
2040 }
2041
2042 void ScrollView::GestureStarted()
2043 {
2044   // we handle the first gesture.
2045   // if we're currently doing a gesture and receive another
2046   // we continue and combine the effects of the gesture instead of reseting.
2047   if(mGestureStackDepth++==0)
2048   {
2049     StopAnimation();
2050     mPanDelta = Vector3::ZERO;
2051     mScaleDelta = Vector3::ONE;
2052     mRotationDelta = 0.0f;
2053     mLastVelocity = Vector2(0.0f, 0.0f);
2054     mLockAxis = LockPossible;
2055
2056     if(mScrolling) // are we interrupting a current scroll?
2057     {
2058       // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
2059       mScrolling = false;
2060       Vector3 currentScrollPosition = GetCurrentScrollPosition();
2061       mScrollCompletedSignalV2.Emit( currentScrollPosition );
2062     }
2063   }
2064 }
2065
2066 void ScrollView::GestureContinuing(Vector2 panDelta, Vector2 scaleDelta, float rotationDelta)
2067 {
2068   mPanDelta.x+= panDelta.x;
2069   mPanDelta.y+= panDelta.y;
2070   mScaleDelta.x*= scaleDelta.x;
2071   mScaleDelta.y*= scaleDelta.y;
2072   mRotationDelta+= rotationDelta;
2073
2074   // Save the velocity, there is a bug in PanGesture
2075   // Whereby the Gesture::Finished's velocity is either:
2076   // NaN (due to time delta of zero between the last two events)
2077   // or 0 (due to position being the same between the last two events)
2078
2079   // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
2080   // appears mostly horizontal or mostly vertical respectively.
2081   if(mAxisAutoLock)
2082   {
2083     if(mPanDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
2084         mLockAxis == LockPossible)
2085     {
2086       float dx = fabsf(mPanDelta.x);
2087       float dy = fabsf(mPanDelta.y);
2088       if(dx * mAxisAutoLockGradient >= dy)
2089       {
2090         // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
2091         mLockAxis = LockVertical;
2092       }
2093       else if(dy * mAxisAutoLockGradient > dx)
2094       {
2095         // 0.36:1 gradient to the vertical (deviate < 20 degrees)
2096         mLockAxis = LockHorizontal;
2097       }
2098       else
2099       {
2100         mLockAxis = LockNone;
2101       }
2102     }
2103   } // end if mAxisAutoLock
2104 }
2105
2106 // TODO: Upgrade to use a more powerful gesture detector (one that supports multiple touches on pan - so works as pan and flick gesture)
2107 // TODO: Reimplement Scaling (pinching 2+ points)
2108 // TODO: Reimplment Rotation (pinching 2+ points)
2109 // BUG: Gesture::Finished doesn't always return velocity on release (due to
2110 // timeDelta between last two events being 0 sometimes, or posiiton being the same)
2111 void ScrollView::OnPan(PanGesture gesture)
2112 {
2113   // Guard against destruction during signal emission
2114   // Note that Emit() methods are called indirectly e.g. from within ScrollView::OnGestureEx()
2115   Actor self( Self() );
2116
2117   if(!mSensitive)
2118   {
2119     // If another callback on the same original signal disables sensitivity,
2120     // this callback will still be called, so we must suppress it.
2121     return;
2122   }
2123
2124   // translate Gesture input to get useful data...
2125   switch(gesture.state)
2126   {
2127     case Gesture::Started:
2128     {
2129       GestureStarted();
2130       self.SetProperty( mPropertyPanning, true );
2131       self.SetProperty( mPropertyScrollStartPagePosition, GetCurrentScrollPosition() );
2132
2133       //  Update property: X & Y = Position (only when in panning mode - in snapping mode, X & Y are animated).
2134       Constraint constraint = Constraint::New<float>( mPropertyX,
2135                                            LocalSource( mPropertyPosition ),
2136                                            Source( self, mPropertyPanning ),
2137                                            InternalXConstraint );
2138       mScrollMainInternalXConstraint = self.ApplyConstraint(constraint);
2139
2140       constraint = Constraint::New<float>( mPropertyY,
2141                                            LocalSource( mPropertyPosition ),
2142                                            Source( self, mPropertyPanning ),
2143                                            InternalYConstraint );
2144       mScrollMainInternalYConstraint = self.ApplyConstraint(constraint);
2145       // When panning we want to make sure overshoot values are affected by pre position and post position
2146       SetOvershootConstraintsEnabled(true);
2147       break;
2148     }
2149
2150     case Gesture::Continuing:
2151     {
2152       // Nothing to do, handled in constraint.
2153       break;
2154     }
2155
2156     case Gesture::Finished:
2157     case Gesture::Cancelled:
2158     {
2159       mLastVelocity = gesture.velocity;
2160       self.SetProperty( mPropertyPanning, false );
2161
2162       // Remove X & Y position constraints as they are not required when we are not panning.
2163       self.RemoveConstraint(mScrollMainInternalXConstraint);
2164       self.RemoveConstraint(mScrollMainInternalYConstraint);
2165       break;
2166     }
2167
2168     case Gesture::Possible:
2169     case Gesture::Clear:
2170     {
2171       // Nothing to do, not needed.
2172       break;
2173     }
2174
2175   } // end switch(gesture.state)
2176
2177   OnGestureEx(gesture.state);
2178 }
2179
2180 void ScrollView::OnGestureEx(Gesture::State state)
2181 {
2182   // call necessary signals for application developer
2183
2184   if(state == Gesture::Started)
2185   {
2186     Vector3 currentScrollPosition = GetCurrentScrollPosition();
2187     Self().SetProperty(mPropertyScrolling, true);
2188     mScrolling = true;
2189     mScrollStartedSignalV2.Emit( currentScrollPosition );
2190   }
2191   else if( (state == Gesture::Finished) ||
2192            (state == Gesture::Cancelled) ) // Finished/default
2193   {
2194     // when all the gestures have finished, we finish the transform.
2195     // so if a user decides to pan (1 gesture), and then pan+zoom (2 gestures)
2196     // then stop panning (back to 1 gesture), and then stop zooming (0 gestures).
2197     // this is the point we end, and perform necessary snapping.
2198     mGestureStackDepth--;
2199     if(mGestureStackDepth==0)
2200     {
2201       FinishTransform();
2202     }
2203   }
2204 }
2205
2206 void ScrollView::UpdateTransform()
2207 {
2208 // TODO: notify clamps using property notifications (or see if we need this, can deprecate it)
2209 }
2210
2211 void ScrollView::FinishTransform()
2212 {
2213   const Vector3& scrollPosition = Self().GetProperty<Vector3>(mPropertyPosition);
2214
2215   mScrollPostPosition.x = scrollPosition.x;
2216   mScrollPostPosition.y = scrollPosition.y;
2217
2218   Vector3 deltaPosition(mScrollPostPosition);
2219   // Cement PRE transform (PRE = POST), and Begin Snap Animation if necessary.
2220   WrapPosition(mScrollPostPosition);
2221
2222   mDomainOffset += deltaPosition - mScrollPostPosition;
2223   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
2224
2225   bool animating = SnapWithVelocity(mLastVelocity * 1000.0f);
2226
2227   if(!animating)
2228   {
2229     AnimateOvershootToOrigin(0.0f, 0.0f);
2230     // if not animating, then this pan has completed right now.
2231     mScrolling = false;
2232     Self().SetProperty(mPropertyScrolling, false);
2233     Vector3 currentScrollPosition = GetCurrentScrollPosition();
2234     mScrollCompletedSignalV2.Emit( currentScrollPosition );
2235   }
2236 }
2237
2238 Vector3 ScrollView::GetOvershoot(Vector3& position) const
2239 {
2240   Vector3 size = Self().GetCurrentSize();
2241   Vector3 overshoot;
2242
2243   const RulerDomain rulerDomainX = mRulerX->GetDomain();
2244   const RulerDomain rulerDomainY = mRulerY->GetDomain();
2245
2246   if(mRulerX->IsEnabled() && rulerDomainX.enabled)
2247   {
2248     const float left = rulerDomainX.min - position.x;
2249     const float right = size.width - rulerDomainX.max - position.x;
2250     if(left<0)
2251     {
2252       overshoot.x = left;
2253     }
2254     else if(right>0)
2255     {
2256       overshoot.x = right;
2257     }
2258   }
2259
2260   if(mRulerY->IsEnabled() && rulerDomainY.enabled)
2261   {
2262     const float top = rulerDomainY.min - position.y;
2263     const float bottom = size.height - rulerDomainY.max - position.y;
2264     if(top<0)
2265     {
2266       overshoot.y = top;
2267     }
2268     else if(bottom>0)
2269     {
2270       overshoot.y = bottom;
2271     }
2272   }
2273
2274   return overshoot;
2275 }
2276
2277 bool ScrollView::OnAccessibilityPan(PanGesture gesture)
2278 {
2279   OnPan(gesture);
2280   return true;
2281 }
2282
2283 void ScrollView::ClampPosition(Vector3& position) const
2284 {
2285   ClampState3 clamped;
2286   ClampPosition(position, clamped);
2287 }
2288
2289 void ScrollView::ClampPosition(Vector3& position, ClampState3 &clamped) const
2290 {
2291   Vector3 size = Self().GetCurrentSize();
2292
2293   // determine size of viewport relative to current scaled size.
2294   // e.g. if you're zoomed in 200%, then each pixel on screen is only 0.5 pixels on subject.
2295   if(fabsf(mScrollPostScale.x) > Math::MACHINE_EPSILON_0)
2296   {
2297     size.x /= mScrollPostScale.x;
2298   }
2299
2300   if(fabsf(mScrollPostScale.y) > Math::MACHINE_EPSILON_0)
2301   {
2302     size.y /= mScrollPostScale.y;
2303   }
2304
2305   position.x = -mRulerX->Clamp(-position.x, size.width, 1.0f, clamped.x);    // NOTE: X & Y rulers think in -ve coordinate system.
2306   position.y = -mRulerY->Clamp(-position.y, size.height, 1.0f, clamped.y);   // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
2307
2308   clamped.z = NotClamped;
2309 }
2310
2311 void ScrollView::WrapPosition(Vector3& position) const
2312 {
2313   if(mWrapMode)
2314   {
2315     const RulerDomain rulerDomainX = mRulerX->GetDomain();
2316     const RulerDomain rulerDomainY = mRulerY->GetDomain();
2317
2318     if(mRulerX->IsEnabled())
2319     {
2320       position.x = -WrapInDomain(-position.x, rulerDomainX.min, rulerDomainX.max);
2321     }
2322
2323     if(mRulerY->IsEnabled())
2324     {
2325       position.y = -WrapInDomain(-position.y, rulerDomainY.min, rulerDomainY.max);
2326     }
2327   }
2328 }
2329
2330 void ScrollView::ClampScale(Vector3& scale) const
2331 {
2332   ClampState3 clamped;
2333   ClampScale(scale, clamped);
2334 }
2335
2336 void ScrollView::ClampScale(Vector3& scale, ClampState3 &clamped) const
2337 {
2338   scale.x = mRulerScaleX->Clamp(scale.x, 0.0f, 1.0f, clamped.x);
2339   scale.y = mRulerScaleY->Clamp(scale.y, 0.0f, 1.0f, clamped.y);
2340   clamped.z = NotClamped;
2341 }
2342
2343 void ScrollView::UpdateMainInternalConstraint()
2344 {
2345   // TODO: Only update the constraints which have changed, rather than remove all and add all again.
2346   // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
2347   Actor self = Self();
2348   PanGestureDetector detector( GetPanGestureDetector() );
2349
2350   if(mScrollMainInternalPrePositionConstraint)
2351   {
2352     self.RemoveConstraint(mScrollMainInternalPrePositionConstraint);
2353     self.RemoveConstraint(mScrollMainInternalPositionConstraint);
2354     self.RemoveConstraint(mScrollMainInternalDeltaConstraint);
2355     self.RemoveConstraint(mScrollMainInternalFinalConstraint);
2356     self.RemoveConstraint(mScrollMainInternalRelativeConstraint);
2357   }
2358
2359   // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
2360   // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
2361
2362   // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
2363   Vector2 initialPanMask = Vector2(mRulerX->IsEnabled() ? 1.0f : 0.0f, mRulerY->IsEnabled() ? 1.0f : 0.0f);
2364
2365   Constraint constraint = Constraint::New<Vector3>( mPropertyPrePosition,
2366                                                     Source( detector, PanGestureDetector::LOCAL_POSITION ),
2367                                                     Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
2368                                                     LocalSource( mPropertyX ),
2369                                                     LocalSource( mPropertyY ),
2370                                                     Source( self, mPropertyPanning ),
2371                                                     InternalPrePositionConstraint( initialPanMask, mAxisAutoLock, mAxisAutoLockGradient ) );
2372   mScrollMainInternalPrePositionConstraint = self.ApplyConstraint(constraint);
2373
2374   // 2. Second calculate the clamped position (actual position)
2375   constraint = Constraint::New<Vector3>( mPropertyPosition,
2376                                          LocalSource( mPropertyPrePosition ),
2377                                          Source( self, Actor::SIZE ),
2378                                          InternalPositionConstraint( mRulerX->GetDomain(),
2379                                                                      mRulerY->GetDomain()) );
2380   mScrollMainInternalPositionConstraint = self.ApplyConstraint(constraint);
2381
2382   constraint = Constraint::New<Vector3>( mPropertyPositionDelta,
2383                                          LocalSource( mPropertyPosition ),
2384                                          LocalSource( mPropertyDomainOffset ),
2385                                          InternalPositionDeltaConstraint );
2386   mScrollMainInternalDeltaConstraint = self.ApplyConstraint(constraint);
2387
2388   constraint = Constraint::New<Vector3>( mPropertyFinal,
2389                                          LocalSource( mPropertyPosition ),
2390                                          LocalSource( mPropertyOvershootX ),
2391                                          LocalSource( mPropertyOvershootY ),
2392                                          InternalFinalConstraint( FinalDefaultAlphaFunction,
2393                                                                   FinalDefaultAlphaFunction ) );
2394   mScrollMainInternalFinalConstraint = self.ApplyConstraint(constraint);
2395
2396   constraint = Constraint::New<Vector3>( mPropertyRelativePosition,
2397                                          LocalSource( mPropertyPosition ),
2398                                          LocalSource( mPropertyPositionMin ),
2399                                          LocalSource( mPropertyPositionMax ),
2400                                          LocalSource( Actor::SIZE ),
2401                                          InternalRelativePositionConstraint );
2402   mScrollMainInternalRelativeConstraint = self.ApplyConstraint(constraint);
2403
2404   if(mScrollMainInternalOvershootXConstraint)
2405   {
2406     // reset these constraints in correct order
2407     self.RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2408     mScrollMainInternalOvershootXConstraint.Reset();
2409
2410     Constraint constraint = Constraint::New<float>( mPropertyOvershootX,
2411                                            LocalSource( mPropertyPrePosition ),
2412                                            LocalSource( mPropertyPosition ),
2413                                            OvershootXConstraint(mMaxOvershoot.x) );
2414     mScrollMainInternalOvershootXConstraint = self.ApplyConstraint(constraint);
2415   }
2416
2417   if(mScrollMainInternalOvershootYConstraint)
2418   {
2419     // reset these constraints in correct order
2420     self.RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2421     mScrollMainInternalOvershootYConstraint.Reset();
2422
2423     Constraint constraint = Constraint::New<float>( mPropertyOvershootY,
2424                                            LocalSource( mPropertyPrePosition ),
2425                                            LocalSource( mPropertyPosition ),
2426                                            OvershootXConstraint(mMaxOvershoot.y) );
2427     mScrollMainInternalOvershootYConstraint = self.ApplyConstraint(constraint);
2428   }
2429 }
2430
2431 void ScrollView::SetOvershootConstraintsEnabled(bool enabled)
2432 {
2433   Actor self( Self() );
2434   // remove and reset, it may now be in wrong order with the main internal constraints
2435   if(mScrollMainInternalOvershootXConstraint)
2436   {
2437     self.RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2438     mScrollMainInternalOvershootXConstraint.Reset();
2439   }
2440   if(mScrollMainInternalOvershootYConstraint)
2441   {
2442     self.RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2443     mScrollMainInternalOvershootYConstraint.Reset();
2444   }
2445   if(enabled)
2446   {
2447     Constraint constraint = Constraint::New<float>( mPropertyOvershootX,
2448                                            LocalSource( mPropertyPrePosition ),
2449                                            LocalSource( mPropertyPosition ),
2450                                            OvershootXConstraint(mMaxOvershoot.x) );
2451     mScrollMainInternalOvershootXConstraint = self.ApplyConstraint(constraint);
2452     constraint = Constraint::New<float>( mPropertyOvershootY,
2453                                            LocalSource( mPropertyPrePosition ),
2454                                            LocalSource( mPropertyPosition ),
2455                                            OvershootYConstraint(mMaxOvershoot.y) );
2456     mScrollMainInternalOvershootYConstraint = self.ApplyConstraint(constraint);
2457   }
2458 }
2459
2460 void ScrollView::SetInternalConstraints()
2461 {
2462   // Internal constraints (applied to target ScrollBase Actor itself) /////////
2463   UpdateMainInternalConstraint();
2464
2465   // User definable constraints to apply to all child actors //////////////////
2466   Actor self = Self();
2467
2468   // LocalSource - The Actors to be moved.
2469   // self - The ScrollView
2470
2471   // Apply some default constraints to ScrollView.
2472   // Movement + Scaling + Wrap function
2473
2474   Constraint constraint;
2475
2476   // MoveScaledActor (scrolling/zooming)
2477   constraint = Constraint::New<Vector3>( Actor::POSITION,
2478                                          Source( self, mPropertyPosition ),
2479                                          Source( self, mPropertyScale ),
2480                                          MoveScaledActorConstraint );
2481   constraint.SetRemoveAction(Constraint::Discard);
2482   ApplyConstraintToBoundActors(constraint);
2483
2484   // ScaleActor (scrolling/zooming)
2485   constraint = Constraint::New<Vector3>( Actor::SCALE,
2486                                          Source( self, mPropertyScale ),
2487                                          ScaleActorConstraint );
2488   constraint.SetRemoveAction(Constraint::Discard);
2489   ApplyConstraintToBoundActors(constraint);
2490
2491   // WrapActor (wrap functionality)
2492   constraint = Constraint::New<Vector3>( Actor::POSITION,
2493                                                  LocalSource( Actor::SCALE ),
2494                                                  LocalSource( Actor::ANCHOR_POINT ),
2495                                                  LocalSource( Actor::SIZE ),
2496                                                  Source( self, mPropertyPositionMin ),
2497                                                  Source( self, mPropertyPositionMax ),
2498                                                  Source( self, mPropertyWrap ),
2499                                                  WrapActorConstraint );
2500   constraint.SetRemoveAction(Constraint::Discard);
2501   ApplyConstraintToBoundActors(constraint);
2502 }
2503
2504 void ScrollView::SetOvershootToOrigin()
2505 {
2506   // Clear Snap animation if exists.
2507   if(mSnapOvershootAnimation)
2508   {
2509     mSnapOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapOvershootAnimationFinished);
2510     mSnapOvershootAnimation.Stop();
2511     mSnapOvershootAnimation.Clear();
2512     mSnapOvershootAnimation = NULL;
2513   }
2514   SetOvershootConstraintsEnabled(false);
2515   Self().SetProperty(mPropertyOvershootX, 0.0f);
2516   Self().SetProperty(mPropertyOvershootY, 0.0f);
2517 }
2518
2519 void ScrollView::AnimateOvershootToOrigin(float xDelay, float yDelay)
2520 {
2521   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2522   {
2523     if(xDelay < Math::MACHINE_EPSILON_1)
2524     {
2525       // kick start animation to 0
2526       Self().SetProperty(mPropertyOvershootX, 0.0f);
2527     }
2528     if(yDelay < Math::MACHINE_EPSILON_1)
2529     {
2530       // kick start animation to 0
2531       Self().SetProperty(mPropertyOvershootY, 0.0f);
2532     }
2533     return;
2534   }
2535   // When we need to animate overshoot to 0
2536   if(mSnapOvershootDuration > Math::MACHINE_EPSILON_1)
2537   {
2538     Actor self = Self();
2539     // Clear Snap animation if exists.
2540     if(mSnapOvershootAnimation)
2541     {
2542       mSnapOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollView::OnSnapOvershootAnimationFinished );
2543       mSnapOvershootAnimation.Stop();
2544       mSnapOvershootAnimation.Clear();
2545       mSnapOvershootAnimation = NULL;
2546     }
2547     if(!mSnapXAnimation && mScrollMainInternalOvershootXConstraint)
2548     {
2549       // need to remove the x overshoot constraint now or it will override animation to 0
2550       Self().RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2551       mScrollMainInternalOvershootXConstraint.Reset();
2552       mScrollMainInternalOvershootXConstraint = 0;
2553     }
2554     if(!mSnapYAnimation && mScrollMainInternalOvershootYConstraint)
2555     {
2556       // need to remove the y overshoot constraint now or it will override animation to 0
2557       Self().RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2558       mScrollMainInternalOvershootYConstraint.Reset();
2559       mScrollMainInternalOvershootYConstraint = 0;
2560     }
2561     // setup the new overshoot to 0 animation
2562     float totalDuration = (xDelay > yDelay ? xDelay : yDelay) + mSnapOvershootDuration;
2563     mSnapOvershootAnimation = Animation::New(totalDuration);
2564     mSnapOvershootAnimation.FinishedSignal().Connect( this, &ScrollView::OnSnapOvershootAnimationFinished );
2565
2566     mSnapOvershootAnimation.AnimateTo( Property(self, mPropertyOvershootX), 0.0f, mSnapOvershootAlphaFunction, TimePeriod(xDelay, mSnapOvershootDuration) );
2567     mSnapOvershootAnimation.AnimateTo( Property(self, mPropertyOvershootY), 0.0f, mSnapOvershootAlphaFunction, TimePeriod(yDelay, mSnapOvershootDuration) );
2568
2569     mSnapOvershootAnimation.SetDuration(totalDuration);
2570     mSnapOvershootAnimation.Play();
2571   }
2572   else
2573   {
2574     SetOvershootToOrigin();
2575   }
2576 }
2577
2578 void ScrollView::OnSnapOvershootAnimationFinished( Animation& source )
2579 {
2580   mSnapOvershootAnimation = NULL;
2581 }
2582
2583 void ScrollView::StartRefreshTimer()
2584 {
2585   if(mRefreshIntervalMilliseconds > 0)
2586   {
2587     if (!mRefreshTimer)
2588     {
2589       mRefreshTimer = Timer::New( mRefreshIntervalMilliseconds );
2590       mRefreshTimer.TickSignal().Connect( this, &ScrollView::OnRefreshTick );
2591     }
2592
2593     if (!mRefreshTimer.IsRunning())
2594     {
2595       mRefreshTimer.Start();
2596     }
2597   }
2598 }
2599
2600 void ScrollView::CancelRefreshTimer()
2601 {
2602   if (mRefreshTimer)
2603   {
2604     mRefreshTimer.Stop();
2605   }
2606 }
2607
2608 bool ScrollView::OnRefreshTick()
2609 {
2610   // Guard against destruction during signal emission
2611   Toolkit::ScrollView handle( GetOwner() );
2612
2613   Vector3 currentScrollPosition = GetCurrentScrollPosition();
2614   mScrollUpdatedSignalV2.Emit( currentScrollPosition );
2615
2616   return true;
2617 }
2618
2619 } // namespace Internal
2620
2621 } // namespace Toolkit
2622
2623 } // namespace Dali