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