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