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