16b54aeede66871ee3046adfcff39c516ac1c3c7
[platform/core/uifw/dali-toolkit.git] / 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     mSensitive = sensitive;
927     panGesture.Detach(self);
928
929     mGestureStackDepth = 0;
930     self.SetProperty(mPropertyPanning, false);
931
932     // Remove X & Y position constraints as they are not required when we are not panning.
933     self.RemoveConstraint(mScrollMainInternalXConstraint);
934     self.RemoveConstraint(mScrollMainInternalYConstraint);
935   }
936 }
937
938 void ScrollView::SetMaxOvershoot(float overshootX, float overshootY)
939 {
940   mMaxOvershoot.x = overshootX;
941   mMaxOvershoot.y = overshootY;
942   mDefaultMaxOvershoot = false;
943   UpdateMainInternalConstraint();
944 }
945
946 void ScrollView::SetSnapOvershootAlphaFunction(AlphaFunction alpha)
947 {
948   mSnapOvershootAlphaFunction = alpha;
949 }
950
951 void ScrollView::SetSnapOvershootDuration(float duration)
952 {
953   mSnapOvershootDuration = duration;
954 }
955
956 void ScrollView::SetTouchesRequiredForPanning(unsigned int minTouches, unsigned int maxTouches, bool endOutside)
957 {
958   PanGestureDetector panGesture( GetPanGestureDetector() );
959
960   mMinTouchesForPanning = minTouches;
961   mMaxTouchesForPanning = maxTouches;
962
963   if(endOutside)
964   {
965     panGesture.SetMinimumTouchesRequired(minTouches);
966     panGesture.SetMaximumTouchesRequired(maxTouches);
967   }
968   else
969   {
970     panGesture.SetMinimumTouchesRequired(1);
971     panGesture.SetMaximumTouchesRequired(UINT_MAX);
972   }
973 }
974
975 void ScrollView::SetActorAutoSnap(bool enable)
976 {
977   mActorAutoSnapEnabled = enable;
978 }
979
980 void ScrollView::SetAutoResize(bool enable)
981 {
982   mAutoResizeContainerEnabled = enable;
983   // TODO: This needs a lot of issues to be addressed before working.
984 }
985
986 bool ScrollView::GetWrapMode() const
987 {
988   return mWrapMode;
989 }
990
991 void ScrollView::SetWrapMode(bool enable)
992 {
993   mWrapMode = enable;
994   Self().SetProperty(mPropertyWrap, enable);
995 }
996
997 int ScrollView::GetRefreshInterval() const
998 {
999   return mRefreshIntervalMilliseconds;
1000 }
1001
1002 void ScrollView::SetRefreshInterval(int milliseconds)
1003 {
1004   mRefreshIntervalMilliseconds = milliseconds;
1005 }
1006
1007 bool ScrollView::GetAxisAutoLock() const
1008 {
1009   return mAxisAutoLock;
1010 }
1011
1012 void ScrollView::SetAxisAutoLock(bool enable)
1013 {
1014   mAxisAutoLock = enable;
1015   UpdateMainInternalConstraint();
1016 }
1017
1018 float ScrollView::GetAxisAutoLockGradient() const
1019 {
1020   return mAxisAutoLockGradient;
1021 }
1022
1023 void ScrollView::SetAxisAutoLockGradient(float gradient)
1024 {
1025   DALI_ASSERT_DEBUG( gradient >= 0.0f && gradient <= 1.0f );
1026   mAxisAutoLockGradient = gradient;
1027   UpdateMainInternalConstraint();
1028 }
1029
1030 float ScrollView::GetFrictionCoefficient() const
1031 {
1032   return mFrictionCoefficient;
1033 }
1034
1035 void ScrollView::SetFrictionCoefficient(float friction)
1036 {
1037   DALI_ASSERT_DEBUG( friction > 0.0f );
1038   mFrictionCoefficient = friction;
1039 }
1040
1041 float ScrollView::GetFlickSpeedCoefficient() const
1042 {
1043   return mFlickSpeedCoefficient;
1044 }
1045
1046 void ScrollView::SetFlickSpeedCoefficient(float speed)
1047 {
1048   mFlickSpeedCoefficient = speed;
1049 }
1050
1051 float ScrollView::GetMaxFlickSpeed() const
1052 {
1053   return mMaxFlickSpeed;
1054 }
1055
1056 void ScrollView::SetMaxFlickSpeed(float speed)
1057 {
1058   mMaxFlickSpeed = speed;
1059 }
1060
1061 void ScrollView::SetMouseWheelScrollDistanceStep(Vector2 step)
1062 {
1063   mMouseWheelScrollDistanceStep = step;
1064 }
1065
1066 Vector2 ScrollView::GetMouseWheelScrollDistanceStep() const
1067 {
1068   return mMouseWheelScrollDistanceStep;
1069 }
1070
1071 unsigned int ScrollView::GetCurrentPage() const
1072 {
1073   // in case animation is currently taking place.
1074   Vector3 position = GetPropertyPrePosition();
1075
1076   Actor self = Self();
1077   unsigned int page = 0;
1078   unsigned int pagesPerVolume = 1;
1079   unsigned int volume = 0;
1080
1081   // if rulerX is enabled, then get page count (columns)
1082   page = mRulerX->GetPageFromPosition(-position.x, mWrapMode);
1083   volume = mRulerY->GetPageFromPosition(-position.y, mWrapMode);
1084   pagesPerVolume = mRulerX->GetTotalPages();
1085
1086   return volume * pagesPerVolume + page;
1087 }
1088
1089 Vector3 ScrollView::GetCurrentScrollPosition() const
1090 {
1091   // in case animation is currently taking place.
1092   return -GetPropertyPrePosition();
1093 }
1094
1095 Vector3 ScrollView::GetCurrentScrollScale() const
1096 {
1097   // in case animation is currently taking place.
1098   return GetPropertyScale();
1099 }
1100
1101 Vector3 ScrollView::GetDomainSize() const
1102 {
1103   Vector3 size = Self().GetCurrentSize();
1104
1105   const RulerDomain& xDomain = GetRulerX()->GetDomain();
1106   const RulerDomain& yDomain = GetRulerY()->GetDomain();
1107
1108   Vector3 domainSize = Vector3( xDomain.max - xDomain.min, yDomain.max - yDomain.min, 0.0f ) - size;
1109   return domainSize;
1110 }
1111
1112 void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, float rotation,
1113                              DirectionBias horizontalBias, DirectionBias verticalBias)
1114 {
1115   TransformTo(position, scale, rotation, mSnapDuration, horizontalBias, verticalBias);
1116 }
1117
1118 void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, float rotation, float duration,
1119                              DirectionBias horizontalBias, DirectionBias verticalBias)
1120 {
1121   // Guard against destruction during signal emission
1122   // Note that Emit() methods are called indirectly e.g. from within ScrollView::AnimateTo()
1123   Toolkit::ScrollView handle( GetOwner() );
1124
1125   Vector3 currentScrollPosition = GetCurrentScrollPosition();
1126   Self().SetProperty( mPropertyScrollStartPagePosition, currentScrollPosition );
1127
1128   if(mScrolling) // are we interrupting a current scroll?
1129   {
1130     // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
1131     mScrolling = false;
1132     mScrollCompletedSignalV2.Emit( currentScrollPosition );
1133   }
1134
1135   Self().SetProperty(mPropertyScrolling, true);
1136   mScrolling = true;
1137   mScrollStartedSignalV2.Emit( currentScrollPosition );
1138   bool animating = AnimateTo(-position,
1139                              Vector3::ONE * duration,
1140                              scale,
1141                              Vector3::ONE * duration,
1142                              rotation,
1143                              duration,
1144                              mSnapAlphaFunction,
1145                              true,
1146                              horizontalBias,
1147                              verticalBias,
1148                              Snap);
1149
1150   if(!animating)
1151   {
1152     // if not animating, then this pan has completed right now.
1153     Self().SetProperty(mPropertyScrolling, false);
1154     mScrolling = false;
1155     mScrollCompletedSignalV2.Emit( currentScrollPosition );
1156   }
1157 }
1158
1159 void ScrollView::ScrollTo(const Vector3& position)
1160 {
1161   ScrollTo(position, mSnapDuration );
1162 }
1163
1164 void ScrollView::ScrollTo(const Vector3& position, float duration)
1165 {
1166   ScrollTo(position, duration, DirectionBiasNone, DirectionBiasNone);
1167 }
1168
1169 void ScrollView::ScrollTo(const Vector3& position, float duration,
1170                           DirectionBias horizontalBias, DirectionBias verticalBias)
1171 {
1172   TransformTo(position, mScrollPostScale, mScrollPostRotation, duration, horizontalBias, verticalBias);
1173 }
1174
1175 void ScrollView::ScrollTo(unsigned int page)
1176 {
1177   ScrollTo(page, mSnapDuration);
1178 }
1179
1180 void ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
1181 {
1182   Vector3 position;
1183   unsigned int volume;
1184   unsigned int libraries;
1185
1186   // The position to scroll to is continuous and linear
1187   // unless a domain has been enabled on the X axis.
1188   // or if WrapMode has been enabled.
1189   bool carryX = mRulerX->GetDomain().enabled | mWrapMode;
1190   bool carryY = mRulerY->GetDomain().enabled | mWrapMode;
1191
1192   position.x = mRulerX->GetPositionFromPage(page, volume, carryX);
1193   position.y = mRulerY->GetPositionFromPage(volume, libraries, carryY);
1194
1195   ScrollTo(position, duration, bias, bias);
1196 }
1197
1198 void ScrollView::ScrollTo(Actor &actor)
1199 {
1200   ScrollTo(actor, mSnapDuration);
1201 }
1202
1203 void ScrollView::ScrollTo(Actor &actor, float duration)
1204 {
1205   DALI_ASSERT_ALWAYS(actor.GetParent() == Self());
1206
1207   Actor self = Self();
1208   Vector3 size = self.GetCurrentSize();
1209   Vector3 position = actor.GetCurrentPosition();
1210   position -= GetPropertyPrePosition();
1211
1212   ScrollTo(Vector3(position.x - size.width * 0.5f, position.y - size.height * 0.5f, 0.0f), duration);
1213 }
1214
1215 Actor ScrollView::FindClosestActor()
1216 {
1217   Actor self = Self();
1218   Vector3 size = self.GetCurrentSize();
1219
1220   return FindClosestActorToPosition(Vector3(size.width * 0.5f,size.height * 0.5f,0.0f));
1221 }
1222
1223 Actor ScrollView::FindClosestActorToPosition(const Vector3& position, FindDirection dirX, FindDirection dirY, FindDirection dirZ)
1224 {
1225   Actor closestChild;
1226   float closestDistance2 = 0.0f;
1227   Vector3 actualPosition = position;
1228
1229   unsigned int numChildren = Self().GetChildCount();
1230
1231   for(unsigned int i = 0; i < numChildren; ++i)
1232   {
1233     Actor child = Self().GetChildAt(i);
1234
1235     if(mInternalActor == child) // ignore internal actor.
1236     {
1237       continue;
1238     }
1239
1240     Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
1241
1242     Vector3 delta = childPosition - actualPosition;
1243
1244     // X-axis checking (only find Actors to the [dirX] of actualPosition)
1245     if(dirX > All) // != All,None
1246     {
1247       FindDirection deltaH = delta.x > 0 ? Right : Left;
1248       if(dirX != deltaH)
1249       {
1250         continue;
1251       }
1252     }
1253
1254     // Y-axis checking (only find Actors to the [dirY] of actualPosition)
1255     if(dirY > All) // != All,None
1256     {
1257       FindDirection deltaV = delta.y > 0 ? Down : Up;
1258       if(dirY  != deltaV)
1259       {
1260         continue;
1261       }
1262     }
1263
1264     // Z-axis checking (only find Actors to the [dirZ] of actualPosition)
1265     if(dirZ > All) // != All,None
1266     {
1267       FindDirection deltaV = delta.y > 0 ? In : Out;
1268       if(dirZ  != deltaV)
1269       {
1270         continue;
1271       }
1272     }
1273
1274     // compare child to closest child in terms of distance.
1275     float distance2 = 0.0f;
1276
1277     // distance2 = the Square of the relevant dimensions of delta
1278     if(dirX != None)
1279     {
1280       distance2 += delta.x * delta.x;
1281     }
1282
1283     if(dirY != None)
1284     {
1285       distance2 += delta.y * delta.y;
1286     }
1287
1288     if(dirZ != None)
1289     {
1290       distance2 += delta.z * delta.z;
1291     }
1292
1293     if(closestChild) // Next time.
1294     {
1295       if(distance2 < closestDistance2)
1296       {
1297         closestChild = child;
1298         closestDistance2 = distance2;
1299       }
1300     }
1301     else // First time.
1302     {
1303       closestChild = child;
1304       closestDistance2 = distance2;
1305     }
1306   }
1307
1308   return closestChild;
1309 }
1310
1311 bool ScrollView::ScrollToSnapPoint()
1312 {
1313   Vector2 stationaryVelocity = Vector2(0.0f, 0.0f);
1314   return SnapWithVelocity( stationaryVelocity );
1315 }
1316
1317 void ScrollView::ScaleTo(const Vector3& scale)
1318 {
1319   ScaleTo(scale, mSnapDuration);
1320 }
1321
1322 void ScrollView::ScaleTo(const Vector3& scale, float duration)
1323 {
1324   TransformTo(mScrollPostPosition, scale, mScrollPostRotation, duration);
1325 }
1326
1327
1328 // TODO: In situations where axes are different (X snap, Y free)
1329 // Each axis should really have their own independent animation (time and equation)
1330 // Consider, X axis snapping to nearest grid point (EaseOut over fixed time)
1331 // Consider, Y axis simulating physics to arrive at a point (Physics equation over variable time)
1332 // Currently, the axes have been split however, they both use the same EaseOut equation.
1333 bool ScrollView::SnapWithVelocity(Vector2 velocity)
1334 {
1335   // Animator takes over now, touches are assumed not to interfere.
1336   // And if touches do interfere, then we'll stop animation, update PrePosition
1337   // to current mScroll's properties, and then resume.
1338   // Note: For Flicking this may work a bit different...
1339
1340   float angle = atan2(velocity.y, velocity.x);
1341   float speed2 = velocity.LengthSquared();
1342   AlphaFunction alphaFunction = mSnapAlphaFunction;
1343   Vector3 positionDuration = Vector3::ONE * mSnapDuration;
1344   Vector3 scaleDuration = Vector3::ONE * mSnapDuration;
1345   float rotationDuration = mSnapDuration;
1346   float biasX = 0.5f;
1347   float biasY = 0.5f;
1348   FindDirection horizontal = None;
1349   FindDirection vertical = None;
1350
1351   // orthoAngleRange = Angle tolerance within the Exact N,E,S,W direction
1352   // that will be accepted as a general N,E,S,W flick direction.
1353
1354   const float orthoAngleRange = FLICK_ORTHO_ANGLE_RANGE * M_PI / 180.0f;
1355   const float flickSpeedThreshold2 = FLICK_SPEED_THRESHOLD*FLICK_SPEED_THRESHOLD;
1356
1357   // Flick logic X Axis
1358
1359   if(mRulerX->IsEnabled())
1360   {
1361     horizontal = All;
1362
1363     if(speed2 > flickSpeedThreshold2) // exceeds flick threshold
1364     {
1365       if((angle >= -orthoAngleRange) && (angle < orthoAngleRange)) // Swiping East
1366       {
1367         biasX = 0.0f, horizontal = Left;
1368       }
1369       else if((angle >= M_PI-orthoAngleRange) || (angle < -M_PI+orthoAngleRange)) // Swiping West
1370       {
1371         biasX = 1.0f, horizontal = Right;
1372       }
1373     }
1374   }
1375
1376   // Flick logic Y Axis
1377
1378   if(mRulerY->IsEnabled())
1379   {
1380     vertical = All;
1381
1382     if(speed2 > flickSpeedThreshold2) // exceeds flick threshold
1383     {
1384       if((angle >= M_PI_2-orthoAngleRange) && (angle < M_PI_2+orthoAngleRange)) // Swiping South
1385       {
1386         biasY = 0.0f, vertical = Up;
1387       }
1388       else if((angle >= -M_PI_2-orthoAngleRange) && (angle < -M_PI_2+orthoAngleRange)) // Swiping North
1389       {
1390         biasY = 1.0f, vertical = Down;
1391       }
1392     }
1393   }
1394
1395   // isFlick: Whether this gesture is a flick or not.
1396   bool isFlick = (horizontal != All || vertical != All);
1397   // isFreeFlick: Whether this gesture is a flick under free panning criteria.
1398   bool isFreeFlick = velocity.LengthSquared() > (FREE_FLICK_SPEED_THRESHOLD*FREE_FLICK_SPEED_THRESHOLD);
1399
1400   if(isFlick || isFreeFlick)
1401   {
1402     positionDuration = Vector3::ONE * mFlickDuration;
1403     alphaFunction = mFlickAlphaFunction;
1404   }
1405
1406   // Position Snap ////////////////////////////////////////////////////////////
1407   Vector3 positionSnap = mScrollPostPosition;
1408
1409   if(mActorAutoSnapEnabled)
1410   {
1411     Vector3 size = Self().GetCurrentSize();
1412
1413     Actor child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f), horizontal, vertical );
1414
1415     if(!child && isFlick )
1416     {
1417       // If we conducted a direction limited search and found no actor, then just snap to the closest actor.
1418       child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f) );
1419     }
1420
1421     if(child)
1422     {
1423       Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
1424
1425       // Get center-point of the Actor.
1426       Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
1427
1428       if(mRulerX->IsEnabled())
1429       {
1430         positionSnap.x = position.x - childPosition.x + size.width * 0.5f;
1431       }
1432       if(mRulerY->IsEnabled())
1433       {
1434         positionSnap.y = position.y - childPosition.y + size.height * 0.5f;
1435       }
1436     }
1437   }
1438
1439   Vector3 startPosition = positionSnap;
1440   positionSnap.x = -mRulerX->Snap(-positionSnap.x, biasX);  // NOTE: X & Y rulers think in -ve coordinate system.
1441   positionSnap.y = -mRulerY->Snap(-positionSnap.y, biasY);  // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
1442
1443   Vector3 clampDelta(Vector3::ZERO);
1444   ClampPosition(positionSnap);
1445
1446   if( (mRulerX->GetType() == Ruler::Free || mRulerY->GetType() == Ruler::Free)
1447       && isFreeFlick && !mActorAutoSnapEnabled)
1448   {
1449     // Calculate target position based on velocity of flick.
1450
1451     // a = Deceleration (Set to diagonal stage length * friction coefficient)
1452     // u = Initial Velocity (Flick velocity)
1453     // v = 0 (Final Velocity)
1454     // t = Time (Velocity / Deceleration)
1455     Vector2 stageSize = Stage::GetCurrent().GetSize();
1456     float stageLength = Vector3(stageSize.x, stageSize.y, 0.0f).Length();
1457     float a = (stageLength * mFrictionCoefficient);
1458     Vector3 u = Vector3(velocity.x, velocity.y, 0.0f) * mFlickSpeedCoefficient;
1459     float speed = u.Length();
1460     u/= speed;
1461
1462     // TODO: Change this to a decay function. (faster you flick, the slower it should be)
1463     speed = std::min(speed, stageLength * mMaxFlickSpeed );
1464     u*= speed;
1465     alphaFunction = ConstantDecelerationAlphaFunction;
1466
1467     float t = speed / a;
1468
1469     if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
1470     {
1471       positionSnap.x += t*u.x*0.5f;
1472     }
1473
1474     if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
1475     {
1476       positionSnap.y += t*u.y*0.5f;
1477     }
1478
1479     clampDelta = positionSnap;
1480     ClampPosition(positionSnap);
1481     if((positionSnap - startPosition).LengthSquared() > Math::MACHINE_EPSILON_0)
1482     {
1483       clampDelta -= positionSnap;
1484       clampDelta.x = clampDelta.x > 0.0f ? std::min(clampDelta.x, mMaxOvershoot.x) : std::max(clampDelta.x, -mMaxOvershoot.x);
1485       clampDelta.y = clampDelta.y > 0.0f ? std::min(clampDelta.y, mMaxOvershoot.y) : std::max(clampDelta.y, -mMaxOvershoot.y);
1486     }
1487     else
1488     {
1489       clampDelta = Vector3::ZERO;
1490     }
1491
1492     // If Axis is Free and has velocity, then calculate time taken
1493     // to reach target based on velocity in axis.
1494     if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
1495     {
1496       float deltaX = fabsf(startPosition.x - positionSnap.x);
1497
1498       if(fabsf(u.x) > Math::MACHINE_EPSILON_1)
1499       {
1500         positionDuration.x = fabsf(deltaX / u.x);
1501       }
1502       else
1503       {
1504         positionDuration.x = 0;
1505       }
1506     }
1507
1508     if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
1509     {
1510       float deltaY = fabsf(startPosition.y - positionSnap.y);
1511
1512       if(fabsf(u.y) > Math::MACHINE_EPSILON_1)
1513       {
1514         positionDuration.y = fabsf(deltaY / u.y);
1515       }
1516       else
1517       {
1518         positionDuration.y = 0;
1519       }
1520     }
1521   }
1522   positionSnap += clampDelta;
1523
1524   // Scale Snap ///////////////////////////////////////////////////////////////
1525   Vector3 scaleSnap = mScrollPostScale;
1526
1527   scaleSnap.x = mRulerScaleX->Snap(scaleSnap.x);
1528   scaleSnap.y = mRulerScaleY->Snap(scaleSnap.y);
1529
1530   ClampScale(scaleSnap);
1531
1532   // Rotation Snap ////////////////////////////////////////////////////////////
1533   float rotationSnap = mScrollPostRotation;
1534   // TODO: implement rotation snap
1535
1536   bool animating = AnimateTo(positionSnap, positionDuration,
1537                              scaleSnap, scaleDuration,
1538                              rotationSnap, rotationDuration,
1539                              alphaFunction, false,
1540                              DirectionBiasNone, DirectionBiasNone,
1541                              isFlick || isFreeFlick ? Flick : Snap);
1542
1543   if(animating)
1544   {
1545     AnimateOvershootToOrigin(positionDuration.x, positionDuration.y);
1546   }
1547
1548   return animating;
1549 }
1550
1551 void ScrollView::StopAnimation(void)
1552 {
1553   // Clear Snap animation if exists.
1554   if(mSnapAnimation)
1555   {
1556     mSnapAnimation.Stop();
1557     mSnapAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapAnimationFinished);
1558     mSnapAnimation.Clear();
1559     mSnapAnimation = NULL;
1560   }
1561   if(mSnapXAnimation)
1562   {
1563     mSnapXAnimation.Stop();
1564     mSnapXAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapXAnimationFinished);
1565     mSnapXAnimation.Clear();
1566     mSnapXAnimation = NULL;
1567   }
1568   if(mSnapYAnimation)
1569   {
1570     mSnapYAnimation.Stop();
1571     mSnapYAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapYAnimationFinished);
1572     mSnapYAnimation.Clear();
1573     mSnapYAnimation = NULL;
1574   }
1575   if(mSnapOvershootAnimation)
1576   {
1577     mSnapOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapOvershootAnimationFinished);
1578     mSnapOvershootAnimation.Stop();
1579     mSnapOvershootAnimation.Clear();
1580     mSnapOvershootAnimation = NULL;
1581   }
1582   HandleStoppedAnimation();
1583 }
1584
1585 bool ScrollView::AnimateTo(const Vector3& position, const Vector3& positionDuration,
1586                            const Vector3& scale, const Vector3& scaleDuration,
1587                            float rotation, float rotationDuration,
1588                            AlphaFunction alpha, bool findShortcuts,
1589                            DirectionBias horizontalBias, DirectionBias verticalBias,
1590                            SnapType snapType)
1591 {
1592   // Here we perform an animation on a number of properties (depending on which have changed)
1593   // The animation is applied to all ScrollBases
1594   Actor self = Self();
1595   bool startAnimation = false;
1596   Vector3 positionTransformed = position;
1597   float totalDuration = 0.0f;
1598
1599   bool positionChanged = (positionTransformed != mScrollPostPosition);
1600   bool scaleChanged = (scale != mScrollPostScale);
1601   bool rotationChanged = fabsf(rotation - mScrollPostRotation) > Math::MACHINE_EPSILON_0;
1602
1603   if(positionChanged)
1604   {
1605     totalDuration = std::max(totalDuration, positionDuration.x);
1606     totalDuration = std::max(totalDuration, positionDuration.y);
1607   }
1608
1609   if(scaleChanged)
1610   {
1611     totalDuration = std::max(totalDuration, scaleDuration.x);
1612     totalDuration = std::max(totalDuration, scaleDuration.y);
1613   }
1614
1615   if(rotationChanged)
1616   {
1617     totalDuration = std::max(totalDuration, rotationDuration);
1618   }
1619
1620   if(totalDuration > Math::MACHINE_EPSILON_1)
1621   {
1622     StopAnimation();
1623     mSnapAnimation = Animation::New(totalDuration);
1624     mSnapAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapAnimationFinished);
1625     mSnapXAnimation = Animation::New(positionDuration.x);
1626     mSnapXAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapXAnimationFinished);
1627     mSnapYAnimation = Animation::New(positionDuration.y);
1628     mSnapYAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapYAnimationFinished);
1629     startAnimation = true;
1630
1631     // Position Delta ///////////////////////////////////////////////////////
1632     if(positionChanged)
1633     {
1634       if(mWrapMode && findShortcuts)
1635       {
1636         // In Wrap Mode, the shortest distance is a little less intuitive...
1637         const RulerDomain rulerDomainX = mRulerX->GetDomain();
1638         const RulerDomain rulerDomainY = mRulerY->GetDomain();
1639
1640         if(mRulerX->IsEnabled())
1641         {
1642           float dir = VectorInDomain(-mScrollPostPosition.x, -positionTransformed.x, rulerDomainX.min, rulerDomainX.max, horizontalBias);
1643           positionTransformed.x = mScrollPostPosition.x + -dir;
1644         }
1645
1646         if(mRulerY->IsEnabled())
1647         {
1648           float dir = VectorInDomain(-mScrollPostPosition.y, -positionTransformed.y, rulerDomainY.min, rulerDomainY.max, verticalBias);
1649           positionTransformed.y = mScrollPostPosition.y + -dir;
1650         }
1651       }
1652
1653       // note we have two separate animations for X & Y, this deals with sliding diagonally and hitting
1654       // a horizonal/vertical wall.delay
1655       mSnapXAnimation.AnimateTo( Property(self, mPropertyX), positionTransformed.x, alpha, TimePeriod(0.0f, positionDuration.x));
1656       mSnapYAnimation.AnimateTo( Property(self, mPropertyY), positionTransformed.y, alpha, TimePeriod(0.0f, positionDuration.y));
1657     }
1658
1659     // Scale Delta ///////////////////////////////////////////////////////
1660     if(scaleChanged)
1661     {
1662       // TODO: for non-uniform scaling to different bounds e.g. scaling a square to a 4:3 aspect ratio screen with a velocity
1663       // the height will hit first, and then the width, so that would require two different animation times just like position.
1664       mSnapAnimation.AnimateTo( Property(self, mPropertyScale), scale, alpha, TimePeriod(0.0f, scaleDuration.x));
1665     }
1666
1667     mSnapAnimation.AnimateTo( Property(self, mPropertyTime), totalDuration, AlphaFunctions::Linear );
1668
1669     mSnapAnimation.Play();
1670     mSnapXAnimation.Play();
1671     mSnapYAnimation.Play();
1672     StartRefreshTimer();
1673   } // end if(totalDuration > Math::MACHINE_EPSILON_1)
1674   else // totalDuration == 0
1675   {
1676     // instantly set transform.
1677     if(positionChanged)
1678     {
1679       self.SetProperty(mPropertyX, positionTransformed.x);
1680       self.SetProperty(mPropertyY, positionTransformed.y);
1681
1682       mScrollPrePosition = mScrollPostPosition = positionTransformed;
1683     }
1684
1685     if(scaleChanged)
1686     {
1687       self.SetProperty(mPropertyScale, scale);
1688
1689       mScrollPreScale = mScrollPostScale = scale;
1690     }
1691   }
1692
1693   // Always send a snap event when AnimateTo is called.
1694   Toolkit::ScrollView::SnapEvent snapEvent;
1695   snapEvent.type = snapType;
1696   snapEvent.position = positionTransformed;
1697   snapEvent.scale = scale;
1698   snapEvent.rotation = rotation;
1699   snapEvent.duration = totalDuration;
1700
1701   mSnapStartedSignalV2.Emit( snapEvent );
1702
1703   return startAnimation;
1704 }
1705
1706 void ScrollView::SetOvershootEnabled(bool enabled)
1707 {
1708   if(enabled && !mOvershootIndicator)
1709   {
1710     mOvershootIndicator = ScrollOvershootIndicator::New(*this);
1711   }
1712   mOvershootIndicator->Enable(enabled);
1713 }
1714
1715 void ScrollView::AddOverlay(Actor actor)
1716 {
1717   mInternalActor.Add( actor );
1718 }
1719
1720 void ScrollView::RemoveOverlay(Actor actor)
1721 {
1722   mInternalActor.Remove( actor );
1723 }
1724
1725 void ScrollView::SetScrollingDirection( Radian direction, Radian threshold )
1726 {
1727   PanGestureDetector panGesture( GetPanGestureDetector() );
1728
1729   // First remove just in case we have some set, then add.
1730   panGesture.RemoveDirection( direction );
1731   panGesture.AddDirection( direction, threshold );
1732 }
1733
1734 void ScrollView::RemoveScrollingDirection( Radian direction )
1735 {
1736   PanGestureDetector panGesture( GetPanGestureDetector() );
1737   panGesture.RemoveDirection( direction );
1738 }
1739
1740 Toolkit::ScrollView::SnapStartedSignalV2& ScrollView::SnapStartedSignal()
1741 {
1742   return mSnapStartedSignalV2;
1743 }
1744
1745 void ScrollView::FindAndUnbindActor(Actor child)
1746 {
1747   UnbindActor(child);
1748 }
1749
1750 Vector3 ScrollView::GetPropertyPrePosition() const
1751 {
1752   Vector3 position(Self().GetProperty<float>(mPropertyX), Self().GetProperty<float>(mPropertyY), 0.0f);
1753   WrapPosition(position);
1754
1755   return position;
1756 }
1757
1758 Vector3 ScrollView::GetPropertyPosition() const
1759 {
1760   Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
1761   WrapPosition(position);
1762
1763   return position;
1764 }
1765
1766 Vector3 ScrollView::GetPropertyScale() const
1767 {
1768   return Self().GetProperty<Vector3>(mPropertyScale);
1769 }
1770
1771 void ScrollView::HandleStoppedAnimation()
1772 {
1773   // Animation has stopped, so stop sending the scroll-update signal.
1774   CancelRefreshTimer();
1775
1776   // cement transform now, and allow interactivity to resume.
1777   mScrollPostPosition = GetPropertyPosition();
1778
1779   mScrollPostScale = GetPropertyScale();
1780
1781   // Update Actor position with this wrapped value.
1782
1783   Self().SetProperty(mPropertyX, mScrollPostPosition.x);
1784   Self().SetProperty(mPropertyY, mScrollPostPosition.y);
1785   // TODO Rotation
1786
1787   mScrollPrePosition = mScrollPostPosition;
1788   mScrollPreScale = mScrollPostScale;
1789   mScrollPreRotation = mScrollPostRotation;
1790 }
1791
1792 void ScrollView::HandleSnapAnimationFinished()
1793 {
1794   // Emit Signal that scrolling has completed.
1795   mScrolling = false;
1796   Self().SetProperty(mPropertyScrolling, false);
1797
1798   Vector3 deltaPosition(Self().GetProperty<float>(mPropertyX),
1799                         Self().GetProperty<float>(mPropertyY),
1800                         0.0f);
1801
1802   Vector3 currentScrollPosition = GetCurrentScrollPosition();
1803   mScrollCompletedSignalV2.Emit( currentScrollPosition );
1804
1805   mDomainOffset += deltaPosition - mScrollPostPosition;
1806   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
1807   HandleStoppedAnimation();
1808 }
1809
1810 bool ScrollView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1811 {
1812   Dali::BaseHandle handle( object );
1813
1814   bool connected( true );
1815   Toolkit::ScrollView view = Toolkit::ScrollView::DownCast( handle );
1816
1817   if( Toolkit::ScrollView::SIGNAL_SNAP_STARTED == signalName )
1818   {
1819     view.SnapStartedSignal().Connect( tracker, functor );
1820   }
1821   else
1822   {
1823     // signalName does not match any signal
1824     connected = false;
1825   }
1826
1827   return connected;
1828 }
1829
1830 void ScrollView::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
1831 {
1832   // need to update domain properties for new size
1833   UpdatePropertyDomain(targetSize);
1834 }
1835
1836 void ScrollView::OnControlSizeSet( const Vector3& size )
1837 {
1838   // need to update domain properties for new size
1839   if( mDefaultMaxOvershoot )
1840   {
1841     mMaxOvershoot.x = size.x * 0.5f;
1842     mMaxOvershoot.y = size.y * 0.5f;
1843   }
1844   UpdatePropertyDomain(size);
1845   UpdateMainInternalConstraint();
1846   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
1847   {
1848     mOvershootIndicator->Reset();
1849   }
1850 }
1851
1852 void ScrollView::OnChildAdd(Actor& child)
1853 {
1854   if(mAlterChild)
1855   {
1856     BindActor(child);
1857   }
1858 }
1859
1860 void ScrollView::OnChildRemove(Actor& child)
1861 {
1862   // TODO: Actor needs a RemoveConstraint method to take out an individual constraint.
1863   UnbindActor(child);
1864 }
1865
1866 bool ScrollView::OnTouchEvent(const TouchEvent& event)
1867 {
1868   if(!mSensitive)
1869   {
1870     // Ignore this touch event, if scrollview is insensitive.
1871     return false;
1872   }
1873
1874   // Ignore events with multiple-touch points
1875   if (event.GetPointCount() != 1)
1876   {
1877     return false;
1878   }
1879
1880   if (event.GetPoint(0).state == TouchPoint::Down)
1881   {
1882     mTouchDownTime = event.time;
1883     mTouchDownReceived = true;
1884     mTouchDownPosition = event.GetPoint(0).local;
1885
1886     if( mSnapAnimation || mSnapXAnimation || mSnapYAnimation || mSnapOvershootAnimation )
1887     {
1888       mScrollInterrupted = true;
1889       StopAnimation();
1890     }
1891
1892     if(mScrolling) // are we interrupting a current scroll?
1893     {
1894       // reset domain offset as scrolling from original plane.
1895       mDomainOffset = Vector3::ZERO;
1896       Self().SetProperty(mPropertyDomainOffset, Vector3::ZERO);
1897
1898       mScrolling = false;
1899       Vector3 currentScrollPosition = GetCurrentScrollPosition();
1900       mScrollCompletedSignalV2.Emit( currentScrollPosition );
1901     }
1902   }
1903   else if(event.GetPoint(0).state == TouchPoint::Up)
1904   {
1905     // if the user touches and releases without enough movement to go
1906     // into a gesture state, then we should snap to nearest point.
1907     // otherwise our scroll could be stopped (interrupted) half way through an animation.
1908     if(mGestureStackDepth==0 && mTouchDownReceived)
1909     {
1910       unsigned timeDelta( event.time - mTouchDownTime );
1911       if ( timeDelta >= MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET )
1912       {
1913         // Reset the velocity only if down was received a while ago
1914         mLastVelocity = Vector2( 0.0f, 0.0f );
1915       }
1916       else
1917       {
1918         Vector2 positionDelta( mTouchDownPosition - event.GetPoint(0).local );
1919         mLastVelocity = positionDelta / timeDelta;
1920       }
1921
1922       // Only finish the transform if scrolling was interrupted on down or if we are scrolling
1923       if ( mSnapAnimation || mSnapXAnimation || mSnapYAnimation || mSnapOvershootAnimation || mScrollInterrupted || mScrolling )
1924       {
1925         FinishTransform();
1926       }
1927     }
1928     mTouchDownReceived = false;
1929     mScrollInterrupted = false;
1930   }
1931
1932   return true; // consume since we're potentially scrolling
1933 }
1934
1935 bool ScrollView::OnMouseWheelEvent(const MouseWheelEvent& event)
1936 {
1937   if(!mSensitive)
1938   {
1939     // Ignore this mouse wheel event, if scrollview is insensitive.
1940     return false;
1941   }
1942
1943   Vector3 targetScrollPosition = GetPropertyPosition();
1944
1945   if(mRulerX->IsEnabled() && !mRulerY->IsEnabled())
1946   {
1947     // If only the ruler in the X axis is enabled, scroll in the X axis.
1948     if(mRulerX->GetType() == Ruler::Free)
1949     {
1950       // Free panning mode
1951       targetScrollPosition.x -= event.z * mMouseWheelScrollDistanceStep.x;
1952       ClampPosition(targetScrollPosition);
1953       ScrollTo(-targetScrollPosition);
1954     }
1955     else if(!mScrolling)
1956     {
1957       // Snap mode, only respond to the event when the previous snap animation is finished.
1958       ScrollTo(GetCurrentPage() + event.z);
1959     }
1960   }
1961   else
1962   {
1963     // If the ruler in the Y axis is enabled, scroll in the Y axis.
1964     if(mRulerY->GetType() == Ruler::Free)
1965     {
1966       // Free panning mode
1967       targetScrollPosition.y -= event.z * mMouseWheelScrollDistanceStep.y;
1968       ClampPosition(targetScrollPosition);
1969       ScrollTo(-targetScrollPosition);
1970     }
1971     else if(!mScrolling)
1972     {
1973       // Snap mode, only respond to the event when the previous snap animation is finished.
1974       ScrollTo(GetCurrentPage() + event.z * mRulerX->GetTotalPages());
1975     }
1976   }
1977
1978   return true;
1979 }
1980
1981 void ScrollView::OnSnapAnimationFinished( Animation& source )
1982 {
1983   mSnapAnimation.FinishedSignal().Disconnect( this, &ScrollView::OnSnapAnimationFinished );
1984   mSnapAnimation = NULL;
1985 }
1986
1987 void ScrollView::OnSnapXAnimationFinished( Animation& source )
1988 {
1989   // Guard against destruction during signal emission
1990   // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
1991   Toolkit::ScrollView handle( GetOwner() );
1992
1993   if(!mSnapYAnimation)
1994   {
1995     HandleSnapAnimationFinished();
1996   }
1997   if(mScrollMainInternalOvershootXConstraint)
1998   {
1999     Self().RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2000     mScrollMainInternalOvershootXConstraint.Reset();
2001     mScrollMainInternalOvershootXConstraint = 0;
2002   }
2003   mSnapXAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapXAnimationFinished);
2004   mSnapXAnimation.Reset();
2005   mSnapXAnimation = NULL;
2006   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2007   {
2008     // kick start animation to 0
2009     Self().SetProperty(mPropertyOvershootX, 0.0f);
2010   }
2011 }
2012
2013 void ScrollView::OnSnapYAnimationFinished( Animation& source )
2014 {
2015   // Guard against destruction during signal emission
2016   // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
2017   Toolkit::ScrollView handle( GetOwner() );
2018
2019   if(!mSnapXAnimation)
2020   {
2021     HandleSnapAnimationFinished();
2022   }
2023   if(mScrollMainInternalOvershootYConstraint)
2024   {
2025     Self().RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2026     mScrollMainInternalOvershootYConstraint.Reset();
2027     mScrollMainInternalOvershootYConstraint = 0;
2028   }
2029   mSnapYAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapYAnimationFinished);
2030   mSnapYAnimation.Reset();
2031   mSnapYAnimation = NULL;
2032   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2033   {
2034     // kick start animation to 0
2035     Self().SetProperty(mPropertyOvershootY, 0.0f);
2036   }
2037 }
2038
2039 void ScrollView::GestureStarted()
2040 {
2041   // we handle the first gesture.
2042   // if we're currently doing a gesture and receive another
2043   // we continue and combine the effects of the gesture instead of reseting.
2044   if(mGestureStackDepth++==0)
2045   {
2046     StopAnimation();
2047     mPanDelta = Vector3::ZERO;
2048     mScaleDelta = Vector3::ONE;
2049     mRotationDelta = 0.0f;
2050     mLastVelocity = Vector2(0.0f, 0.0f);
2051     mLockAxis = LockPossible;
2052
2053     if(mScrolling) // are we interrupting a current scroll?
2054     {
2055       // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
2056       mScrolling = false;
2057       Vector3 currentScrollPosition = GetCurrentScrollPosition();
2058       mScrollCompletedSignalV2.Emit( currentScrollPosition );
2059     }
2060   }
2061 }
2062
2063 void ScrollView::GestureContinuing(Vector2 panDelta, Vector2 scaleDelta, float rotationDelta)
2064 {
2065   mPanDelta.x+= panDelta.x;
2066   mPanDelta.y+= panDelta.y;
2067   mScaleDelta.x*= scaleDelta.x;
2068   mScaleDelta.y*= scaleDelta.y;
2069   mRotationDelta+= rotationDelta;
2070
2071   // Save the velocity, there is a bug in PanGesture
2072   // Whereby the Gesture::Finished's velocity is either:
2073   // NaN (due to time delta of zero between the last two events)
2074   // or 0 (due to position being the same between the last two events)
2075
2076   // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
2077   // appears mostly horizontal or mostly vertical respectively.
2078   if(mAxisAutoLock)
2079   {
2080     if(mPanDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
2081         mLockAxis == LockPossible)
2082     {
2083       float dx = fabsf(mPanDelta.x);
2084       float dy = fabsf(mPanDelta.y);
2085       if(dx * mAxisAutoLockGradient >= dy)
2086       {
2087         // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
2088         mLockAxis = LockVertical;
2089       }
2090       else if(dy * mAxisAutoLockGradient > dx)
2091       {
2092         // 0.36:1 gradient to the vertical (deviate < 20 degrees)
2093         mLockAxis = LockHorizontal;
2094       }
2095       else
2096       {
2097         mLockAxis = LockNone;
2098       }
2099     }
2100   } // end if mAxisAutoLock
2101 }
2102
2103 // TODO: Upgrade to use a more powerful gesture detector (one that supports multiple touches on pan - so works as pan and flick gesture)
2104 // TODO: Reimplement Scaling (pinching 2+ points)
2105 // TODO: Reimplment Rotation (pinching 2+ points)
2106 // BUG: Gesture::Finished doesn't always return velocity on release (due to
2107 // timeDelta between last two events being 0 sometimes, or posiiton being the same)
2108 void ScrollView::OnPan(PanGesture gesture)
2109 {
2110   // Guard against destruction during signal emission
2111   // Note that Emit() methods are called indirectly e.g. from within ScrollView::OnGestureEx()
2112   Actor self( Self() );
2113
2114   if(!mSensitive)
2115   {
2116     // If another callback on the same original signal disables sensitivity,
2117     // this callback will still be called, so we must suppress it.
2118     return;
2119   }
2120
2121   // translate Gesture input to get useful data...
2122   switch(gesture.state)
2123   {
2124     case Gesture::Started:
2125     {
2126       GestureStarted();
2127       self.SetProperty( mPropertyPanning, true );
2128       self.SetProperty( mPropertyScrollStartPagePosition, GetCurrentScrollPosition() );
2129
2130       //  Update property: X & Y = Position (only when in panning mode - in snapping mode, X & Y are animated).
2131       Constraint constraint = Constraint::New<float>( mPropertyX,
2132                                            LocalSource( mPropertyPosition ),
2133                                            Source( self, mPropertyPanning ),
2134                                            InternalXConstraint );
2135       mScrollMainInternalXConstraint = self.ApplyConstraint(constraint);
2136
2137       constraint = Constraint::New<float>( mPropertyY,
2138                                            LocalSource( mPropertyPosition ),
2139                                            Source( self, mPropertyPanning ),
2140                                            InternalYConstraint );
2141       mScrollMainInternalYConstraint = self.ApplyConstraint(constraint);
2142       // When panning we want to make sure overshoot values are affected by pre position and post position
2143       SetOvershootConstraintsEnabled(true);
2144       break;
2145     }
2146
2147     case Gesture::Continuing:
2148     {
2149       // Nothing to do, handled in constraint.
2150       break;
2151     }
2152
2153     case Gesture::Finished:
2154     case Gesture::Cancelled:
2155     {
2156       mLastVelocity = gesture.velocity;
2157       self.SetProperty( mPropertyPanning, false );
2158
2159       // Remove X & Y position constraints as they are not required when we are not panning.
2160       self.RemoveConstraint(mScrollMainInternalXConstraint);
2161       self.RemoveConstraint(mScrollMainInternalYConstraint);
2162       break;
2163     }
2164
2165     case Gesture::Possible:
2166     case Gesture::Clear:
2167     {
2168       // Nothing to do, not needed.
2169       break;
2170     }
2171
2172   } // end switch(gesture.state)
2173
2174   OnGestureEx(gesture.state);
2175 }
2176
2177 void ScrollView::OnGestureEx(Gesture::State state)
2178 {
2179   // call necessary signals for application developer
2180
2181   if(state == Gesture::Started)
2182   {
2183     Vector3 currentScrollPosition = GetCurrentScrollPosition();
2184     Self().SetProperty(mPropertyScrolling, true);
2185     mScrolling = true;
2186     mScrollStartedSignalV2.Emit( currentScrollPosition );
2187   }
2188   else if( (state == Gesture::Finished) ||
2189            (state == Gesture::Cancelled) ) // Finished/default
2190   {
2191     // when all the gestures have finished, we finish the transform.
2192     // so if a user decides to pan (1 gesture), and then pan+zoom (2 gestures)
2193     // then stop panning (back to 1 gesture), and then stop zooming (0 gestures).
2194     // this is the point we end, and perform necessary snapping.
2195     mGestureStackDepth--;
2196     if(mGestureStackDepth==0)
2197     {
2198       FinishTransform();
2199     }
2200   }
2201 }
2202
2203 void ScrollView::UpdateTransform()
2204 {
2205 // TODO: notify clamps using property notifications (or see if we need this, can deprecate it)
2206 }
2207
2208 void ScrollView::FinishTransform()
2209 {
2210   const Vector3& scrollPosition = Self().GetProperty<Vector3>(mPropertyPosition);
2211
2212   mScrollPostPosition.x = scrollPosition.x;
2213   mScrollPostPosition.y = scrollPosition.y;
2214
2215   Vector3 deltaPosition(mScrollPostPosition);
2216   // Cement PRE transform (PRE = POST), and Begin Snap Animation if necessary.
2217   WrapPosition(mScrollPostPosition);
2218
2219   mDomainOffset += deltaPosition - mScrollPostPosition;
2220   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
2221
2222   bool animating = SnapWithVelocity(mLastVelocity * 1000.0f);
2223
2224   if(!animating)
2225   {
2226     AnimateOvershootToOrigin(0.0f, 0.0f);
2227     // if not animating, then this pan has completed right now.
2228     mScrolling = false;
2229     Self().SetProperty(mPropertyScrolling, false);
2230     Vector3 currentScrollPosition = GetCurrentScrollPosition();
2231     mScrollCompletedSignalV2.Emit( currentScrollPosition );
2232   }
2233 }
2234
2235 Vector3 ScrollView::GetOvershoot(Vector3& position) const
2236 {
2237   Vector3 size = Self().GetCurrentSize();
2238   Vector3 overshoot;
2239
2240   const RulerDomain rulerDomainX = mRulerX->GetDomain();
2241   const RulerDomain rulerDomainY = mRulerY->GetDomain();
2242
2243   if(mRulerX->IsEnabled() && rulerDomainX.enabled)
2244   {
2245     const float left = rulerDomainX.min - position.x;
2246     const float right = size.width - rulerDomainX.max - position.x;
2247     if(left<0)
2248     {
2249       overshoot.x = left;
2250     }
2251     else if(right>0)
2252     {
2253       overshoot.x = right;
2254     }
2255   }
2256
2257   if(mRulerY->IsEnabled() && rulerDomainY.enabled)
2258   {
2259     const float top = rulerDomainY.min - position.y;
2260     const float bottom = size.height - rulerDomainY.max - position.y;
2261     if(top<0)
2262     {
2263       overshoot.y = top;
2264     }
2265     else if(bottom>0)
2266     {
2267       overshoot.y = bottom;
2268     }
2269   }
2270
2271   return overshoot;
2272 }
2273
2274 bool ScrollView::OnAccessibilityPan(PanGesture gesture)
2275 {
2276   OnPan(gesture);
2277   return true;
2278 }
2279
2280 void ScrollView::ClampPosition(Vector3& position) const
2281 {
2282   ClampState3 clamped;
2283   ClampPosition(position, clamped);
2284 }
2285
2286 void ScrollView::ClampPosition(Vector3& position, ClampState3 &clamped) const
2287 {
2288   Vector3 size = Self().GetCurrentSize();
2289
2290   // determine size of viewport relative to current scaled size.
2291   // e.g. if you're zoomed in 200%, then each pixel on screen is only 0.5 pixels on subject.
2292   if(fabsf(mScrollPostScale.x) > Math::MACHINE_EPSILON_0)
2293   {
2294     size.x /= mScrollPostScale.x;
2295   }
2296
2297   if(fabsf(mScrollPostScale.y) > Math::MACHINE_EPSILON_0)
2298   {
2299     size.y /= mScrollPostScale.y;
2300   }
2301
2302   position.x = -mRulerX->Clamp(-position.x, size.width, 1.0f, clamped.x);    // NOTE: X & Y rulers think in -ve coordinate system.
2303   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.
2304
2305   clamped.z = NotClamped;
2306 }
2307
2308 void ScrollView::WrapPosition(Vector3& position) const
2309 {
2310   if(mWrapMode)
2311   {
2312     const RulerDomain rulerDomainX = mRulerX->GetDomain();
2313     const RulerDomain rulerDomainY = mRulerY->GetDomain();
2314
2315     if(mRulerX->IsEnabled())
2316     {
2317       position.x = -WrapInDomain(-position.x, rulerDomainX.min, rulerDomainX.max);
2318     }
2319
2320     if(mRulerY->IsEnabled())
2321     {
2322       position.y = -WrapInDomain(-position.y, rulerDomainY.min, rulerDomainY.max);
2323     }
2324   }
2325 }
2326
2327 void ScrollView::ClampScale(Vector3& scale) const
2328 {
2329   ClampState3 clamped;
2330   ClampScale(scale, clamped);
2331 }
2332
2333 void ScrollView::ClampScale(Vector3& scale, ClampState3 &clamped) const
2334 {
2335   scale.x = mRulerScaleX->Clamp(scale.x, 0.0f, 1.0f, clamped.x);
2336   scale.y = mRulerScaleY->Clamp(scale.y, 0.0f, 1.0f, clamped.y);
2337   clamped.z = NotClamped;
2338 }
2339
2340 void ScrollView::UpdateMainInternalConstraint()
2341 {
2342   // TODO: Only update the constraints which have changed, rather than remove all and add all again.
2343   // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
2344   Actor self = Self();
2345   PanGestureDetector detector( GetPanGestureDetector() );
2346
2347   if(mScrollMainInternalPrePositionConstraint)
2348   {
2349     self.RemoveConstraint(mScrollMainInternalPrePositionConstraint);
2350     self.RemoveConstraint(mScrollMainInternalPositionConstraint);
2351     self.RemoveConstraint(mScrollMainInternalDeltaConstraint);
2352     self.RemoveConstraint(mScrollMainInternalFinalConstraint);
2353     self.RemoveConstraint(mScrollMainInternalRelativeConstraint);
2354   }
2355
2356   // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
2357   // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
2358
2359   // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
2360   Vector2 initialPanMask = Vector2(mRulerX->IsEnabled() ? 1.0f : 0.0f, mRulerY->IsEnabled() ? 1.0f : 0.0f);
2361
2362   Constraint constraint = Constraint::New<Vector3>( mPropertyPrePosition,
2363                                                     Source( detector, PanGestureDetector::LOCAL_POSITION ),
2364                                                     Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
2365                                                     LocalSource( mPropertyX ),
2366                                                     LocalSource( mPropertyY ),
2367                                                     Source( self, mPropertyPanning ),
2368                                                     InternalPrePositionConstraint( initialPanMask, mAxisAutoLock, mAxisAutoLockGradient ) );
2369   mScrollMainInternalPrePositionConstraint = self.ApplyConstraint(constraint);
2370
2371   // 2. Second calculate the clamped position (actual position)
2372   constraint = Constraint::New<Vector3>( mPropertyPosition,
2373                                          LocalSource( mPropertyPrePosition ),
2374                                          Source( self, Actor::SIZE ),
2375                                          InternalPositionConstraint( mRulerX->GetDomain(),
2376                                                                      mRulerY->GetDomain()) );
2377   mScrollMainInternalPositionConstraint = self.ApplyConstraint(constraint);
2378
2379   constraint = Constraint::New<Vector3>( mPropertyPositionDelta,
2380                                          LocalSource( mPropertyPosition ),
2381                                          LocalSource( mPropertyDomainOffset ),
2382                                          InternalPositionDeltaConstraint );
2383   mScrollMainInternalDeltaConstraint = self.ApplyConstraint(constraint);
2384
2385   constraint = Constraint::New<Vector3>( mPropertyFinal,
2386                                          LocalSource( mPropertyPosition ),
2387                                          LocalSource( mPropertyOvershootX ),
2388                                          LocalSource( mPropertyOvershootY ),
2389                                          InternalFinalConstraint( FinalDefaultAlphaFunction,
2390                                                                   FinalDefaultAlphaFunction ) );
2391   mScrollMainInternalFinalConstraint = self.ApplyConstraint(constraint);
2392
2393   constraint = Constraint::New<Vector3>( mPropertyRelativePosition,
2394                                          LocalSource( mPropertyPosition ),
2395                                          LocalSource( mPropertyPositionMin ),
2396                                          LocalSource( mPropertyPositionMax ),
2397                                          LocalSource( Actor::SIZE ),
2398                                          InternalRelativePositionConstraint );
2399   mScrollMainInternalRelativeConstraint = self.ApplyConstraint(constraint);
2400
2401   if(mScrollMainInternalOvershootXConstraint)
2402   {
2403     // reset these constraints in correct order
2404     self.RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2405     mScrollMainInternalOvershootXConstraint.Reset();
2406
2407     Constraint constraint = Constraint::New<float>( mPropertyOvershootX,
2408                                            LocalSource( mPropertyPrePosition ),
2409                                            LocalSource( mPropertyPosition ),
2410                                            OvershootXConstraint(mMaxOvershoot.x) );
2411     mScrollMainInternalOvershootXConstraint = self.ApplyConstraint(constraint);
2412   }
2413
2414   if(mScrollMainInternalOvershootYConstraint)
2415   {
2416     // reset these constraints in correct order
2417     self.RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2418     mScrollMainInternalOvershootYConstraint.Reset();
2419
2420     Constraint constraint = Constraint::New<float>( mPropertyOvershootY,
2421                                            LocalSource( mPropertyPrePosition ),
2422                                            LocalSource( mPropertyPosition ),
2423                                            OvershootXConstraint(mMaxOvershoot.y) );
2424     mScrollMainInternalOvershootYConstraint = self.ApplyConstraint(constraint);
2425   }
2426 }
2427
2428 void ScrollView::SetOvershootConstraintsEnabled(bool enabled)
2429 {
2430   Actor self( Self() );
2431   // remove and reset, it may now be in wrong order with the main internal constraints
2432   if(mScrollMainInternalOvershootXConstraint)
2433   {
2434     self.RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2435     mScrollMainInternalOvershootXConstraint.Reset();
2436   }
2437   if(mScrollMainInternalOvershootYConstraint)
2438   {
2439     self.RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2440     mScrollMainInternalOvershootYConstraint.Reset();
2441   }
2442   if(enabled)
2443   {
2444     Constraint constraint = Constraint::New<float>( mPropertyOvershootX,
2445                                            LocalSource( mPropertyPrePosition ),
2446                                            LocalSource( mPropertyPosition ),
2447                                            OvershootXConstraint(mMaxOvershoot.x) );
2448     mScrollMainInternalOvershootXConstraint = self.ApplyConstraint(constraint);
2449     constraint = Constraint::New<float>( mPropertyOvershootY,
2450                                            LocalSource( mPropertyPrePosition ),
2451                                            LocalSource( mPropertyPosition ),
2452                                            OvershootYConstraint(mMaxOvershoot.y) );
2453     mScrollMainInternalOvershootYConstraint = self.ApplyConstraint(constraint);
2454   }
2455 }
2456
2457 void ScrollView::SetInternalConstraints()
2458 {
2459   // Internal constraints (applied to target ScrollBase Actor itself) /////////
2460   UpdateMainInternalConstraint();
2461
2462   // User definable constraints to apply to all child actors //////////////////
2463   Actor self = Self();
2464
2465   // LocalSource - The Actors to be moved.
2466   // self - The ScrollView
2467
2468   // Apply some default constraints to ScrollView.
2469   // Movement + Scaling + Wrap function
2470
2471   Constraint constraint;
2472
2473   // MoveScaledActor (scrolling/zooming)
2474   constraint = Constraint::New<Vector3>( Actor::POSITION,
2475                                          Source( self, mPropertyPosition ),
2476                                          Source( self, mPropertyScale ),
2477                                          MoveScaledActorConstraint );
2478   constraint.SetRemoveAction(Constraint::Discard);
2479   ApplyConstraintToBoundActors(constraint);
2480
2481   // ScaleActor (scrolling/zooming)
2482   constraint = Constraint::New<Vector3>( Actor::SCALE,
2483                                          Source( self, mPropertyScale ),
2484                                          ScaleActorConstraint );
2485   constraint.SetRemoveAction(Constraint::Discard);
2486   ApplyConstraintToBoundActors(constraint);
2487
2488   // WrapActor (wrap functionality)
2489   constraint = Constraint::New<Vector3>( Actor::POSITION,
2490                                                  LocalSource( Actor::SCALE ),
2491                                                  LocalSource( Actor::ANCHOR_POINT ),
2492                                                  LocalSource( Actor::SIZE ),
2493                                                  Source( self, mPropertyPositionMin ),
2494                                                  Source( self, mPropertyPositionMax ),
2495                                                  Source( self, mPropertyWrap ),
2496                                                  WrapActorConstraint );
2497   constraint.SetRemoveAction(Constraint::Discard);
2498   ApplyConstraintToBoundActors(constraint);
2499 }
2500
2501 void ScrollView::SetOvershootToOrigin()
2502 {
2503   // Clear Snap animation if exists.
2504   if(mSnapOvershootAnimation)
2505   {
2506     mSnapOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapOvershootAnimationFinished);
2507     mSnapOvershootAnimation.Stop();
2508     mSnapOvershootAnimation.Clear();
2509     mSnapOvershootAnimation = NULL;
2510   }
2511   SetOvershootConstraintsEnabled(false);
2512   Self().SetProperty(mPropertyOvershootX, 0.0f);
2513   Self().SetProperty(mPropertyOvershootY, 0.0f);
2514 }
2515
2516 void ScrollView::AnimateOvershootToOrigin(float xDelay, float yDelay)
2517 {
2518   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2519   {
2520     if(xDelay < Math::MACHINE_EPSILON_1)
2521     {
2522       // kick start animation to 0
2523       Self().SetProperty(mPropertyOvershootX, 0.0f);
2524     }
2525     if(yDelay < Math::MACHINE_EPSILON_1)
2526     {
2527       // kick start animation to 0
2528       Self().SetProperty(mPropertyOvershootY, 0.0f);
2529     }
2530     return;
2531   }
2532   // When we need to animate overshoot to 0
2533   if(mSnapOvershootDuration > Math::MACHINE_EPSILON_1)
2534   {
2535     Actor self = Self();
2536     // Clear Snap animation if exists.
2537     if(mSnapOvershootAnimation)
2538     {
2539       mSnapOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollView::OnSnapOvershootAnimationFinished );
2540       mSnapOvershootAnimation.Stop();
2541       mSnapOvershootAnimation.Clear();
2542       mSnapOvershootAnimation = NULL;
2543     }
2544     if(!mSnapXAnimation && mScrollMainInternalOvershootXConstraint)
2545     {
2546       // need to remove the x overshoot constraint now or it will override animation to 0
2547       Self().RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2548       mScrollMainInternalOvershootXConstraint.Reset();
2549       mScrollMainInternalOvershootXConstraint = 0;
2550     }
2551     if(!mSnapYAnimation && mScrollMainInternalOvershootYConstraint)
2552     {
2553       // need to remove the y overshoot constraint now or it will override animation to 0
2554       Self().RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2555       mScrollMainInternalOvershootYConstraint.Reset();
2556       mScrollMainInternalOvershootYConstraint = 0;
2557     }
2558     // setup the new overshoot to 0 animation
2559     float totalDuration = (xDelay > yDelay ? xDelay : yDelay) + mSnapOvershootDuration;
2560     mSnapOvershootAnimation = Animation::New(totalDuration);
2561     mSnapOvershootAnimation.FinishedSignal().Connect( this, &ScrollView::OnSnapOvershootAnimationFinished );
2562
2563     mSnapOvershootAnimation.AnimateTo( Property(self, mPropertyOvershootX), 0.0f, mSnapOvershootAlphaFunction, TimePeriod(xDelay, mSnapOvershootDuration) );
2564     mSnapOvershootAnimation.AnimateTo( Property(self, mPropertyOvershootY), 0.0f, mSnapOvershootAlphaFunction, TimePeriod(yDelay, mSnapOvershootDuration) );
2565
2566     mSnapOvershootAnimation.SetDuration(totalDuration);
2567     mSnapOvershootAnimation.Play();
2568   }
2569   else
2570   {
2571     SetOvershootToOrigin();
2572   }
2573 }
2574
2575 void ScrollView::OnSnapOvershootAnimationFinished( Animation& source )
2576 {
2577   mSnapOvershootAnimation = NULL;
2578 }
2579
2580 void ScrollView::StartRefreshTimer()
2581 {
2582   if(mRefreshIntervalMilliseconds > 0)
2583   {
2584     if (!mRefreshTimer)
2585     {
2586       mRefreshTimer = Timer::New( mRefreshIntervalMilliseconds );
2587       mRefreshTimer.TickSignal().Connect( this, &ScrollView::OnRefreshTick );
2588     }
2589
2590     if (!mRefreshTimer.IsRunning())
2591     {
2592       mRefreshTimer.Start();
2593     }
2594   }
2595 }
2596
2597 void ScrollView::CancelRefreshTimer()
2598 {
2599   if (mRefreshTimer)
2600   {
2601     mRefreshTimer.Stop();
2602   }
2603 }
2604
2605 bool ScrollView::OnRefreshTick()
2606 {
2607   // Guard against destruction during signal emission
2608   Toolkit::ScrollView handle( GetOwner() );
2609
2610   Vector3 currentScrollPosition = GetCurrentScrollPosition();
2611   mScrollUpdatedSignalV2.Emit( currentScrollPosition );
2612
2613   return true;
2614 }
2615
2616 } // namespace Internal
2617
2618 } // namespace Toolkit
2619
2620 } // namespace Dali