bff54c77ff9ce5582cb4a57e6b984f2b92b8e50e
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // INTERNAL INCLUDES
18 #include <dali/public-api/events/mouse-wheel-event.h>
19
20 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
21 #include <dali-toolkit/public-api/controls/scrollable/scroll-component-impl.h>
22 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
23 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
24 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
25
26 // TODO: Change to two class system:
27 // 1. DraggableActor (is an actor which can be dragged anywhere/scaled/rotated, can be set to range using the ruler)
28 // 2. ScrollView (contains a draggable actor that can a) be dragged in the negative X, and Y domain, b) has a hitArea for touches)
29 // TODO: Rotation
30 // TODO: Asymetrical scaling
31 // TODO: external components (page and status overlays).
32 // TODO: Orientation.
33 // TODO: upgrade Vector2/3 to support returning Unit vectors, normals, & cross product (dot product is already provided)
34
35 using namespace Dali;
36
37 namespace
38 {
39
40 const int DEFAULT_REFRESH_INTERVAL_MILLISECONDS = 50;                                     ///< Refresh rate TODO: Animation should have an update signal (and see item-view-impl)
41 const float FLICK_SPEED_THRESHOLD = 500.0f;                                               ///< Flick threshold in pixels/ms
42 const float FREE_FLICK_SPEED_THRESHOLD = 200.0f;                                          ///< Free-Flick threshold in pixels/ms
43 const float AUTOLOCK_AXIS_MINIMUM_DISTANCE2 = 100.0f;                                     ///< Auto-lock axis after minimum distance squared.
44 const float FLICK_ORTHO_ANGLE_RANGE = 60.0f;                                              ///< degrees. (if >45, then supports diagonal flicking)
45 const unsigned int MAXIMUM_NUMBER_OF_VALUES = 5;                                          ///< Number of values to use for weighted pan calculation.
46 const Vector2 DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = Vector2(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each mouse wheel event received.
47 const unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET( 150u );
48
49 // predefined effect values
50 const Vector3 ANGLE_CAROUSEL_ROTATE(Math::PI * 0.5f, Math::PI * 0.5f, 0.0f);
51 const Vector3 ANGLE_CUBE_PAGE_ROTATE(Math::PI * 0.2f, Math::PI * 0.2f, 0.0f);  ///< Cube page rotates as if it has ten sides with the camera positioned inside
52 const Vector2 ANGLE_CUSTOM_CUBE_SWING(-Math::PI * 0.45f, -Math::PI * 0.45f);  ///< outer cube pages swing 90 degrees as they pan offscreen
53 const Vector2 ANGLE_SPIRAL_SWING_IN(Math::PI * 0.5f, Math::PI * 0.5f);
54 const Vector2 ANGLE_SPIRAL_SWING_OUT(Math::PI * 0.35f, Math::PI * 0.35f);
55 const Vector2 ANGLE_OUTER_CUBE_SWING(Math::PI * 0.5f, Math::PI * 0.5f);  ///< outer cube pages swing 90 degrees as they pan offscreen
56
57 // Helpers ////////////////////////////////////////////////////////////////////////////////////////
58
59 // TODO: GetAngle for Vector2 can be moved.
60 // GetAngle for Vector3 needs to be measured against a normal/plane.
61
62 /**
63  * @param[in] vector The 3D vector to be measured
64  * @return angle in radians from 0 to 2PI
65  */
66 float GetAngle(const Vector3& vector)
67 {
68   return atan2(vector.y, vector.x) + Math::PI;
69 }
70
71 /**
72  * @param[in] vector The 2D vector to be measured
73  * @return angle in radians from 0 to 2PI
74  */
75 float GetAngle(const Vector2& vector)
76 {
77   return atan2(vector.y, vector.x) + Math::PI;
78 }
79
80 /**
81  * Find the vector (distance) from (a) to (b)
82  * in domain (start) to (end)
83  * (\ / start)               (\ / end)
84  *   |-a                 b<----|
85  *
86  * @note assumes both (a) and (b) are already with the domain
87  * (start) to (end)
88  *
89  * @param[in] a the current point
90  * @param[in] b the target point
91  * @param[in] start the start of the domain
92  * @param[in] end the end of the domain
93  * @param[in] bias whether to only take the right direction or the left direction,
94  * or the shortest direction.
95  * @return the shortest direction and distance
96  */
97 float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::DirectionBias bias)
98 {
99   if(bias == Dali::Toolkit::DirectionBiasNone)
100   {
101     return ShortestDistanceInDomain( a, b, start, end );
102   }
103   //  (a-start + end-b)
104   float size = end-start;
105   float vect = b-a;
106
107   if(vect > 0)
108   {
109     // +ve vector
110     if(bias == Dali::Toolkit::DirectionBiasRight) // going right, take the vector.
111     {
112       return vect;
113     }
114     else
115     {
116       float aRight = a+size;
117       return b-aRight;
118     }
119   }
120   else
121   {
122     // -ve vector
123     if(bias == Dali::Toolkit::DirectionBiasLeft) // going left, take the vector.
124     {
125       return vect;
126     }
127     else
128     {
129       float aLeft = a-size;
130       return b-aLeft;
131     }
132   }
133 }
134
135 /**
136  * Returns the position of the anchor within actor
137  *
138  * @param actor The Actor
139  * @param anchor The Anchor point of interest.
140  * @return The position of the Anchor
141  */
142 Vector3 GetPositionOfAnchor(Actor &actor, const Vector3 &anchor)
143 {
144   Vector3 childPosition = actor.GetCurrentPosition();
145   Vector3 childAnchor = - actor.GetCurrentAnchorPoint() + anchor;
146   Vector3 childSize = actor.GetCurrentSize();
147
148   return childPosition + childAnchor * childSize;
149 }
150
151 // AlphaFunctions /////////////////////////////////////////////////////////////////////////////////
152
153 float FinalDefaultAlphaFunction(float offset)
154 {
155   return offset * 0.5f;
156 }
157
158 /**
159  * ConstantDecelerationAlphaFunction
160  * Newtoninan distance for constant deceleration
161  * v = 1 - t, s = t - 1/2 t^2
162  * when t = 0, s = 0.0 (min distance)
163  * when t = 1, s = 0.5 (max distance)
164  * progress = s / (max-min) = 2t - t^2
165  *
166  * @param[in] offset The input progress
167  * @return The output progress
168  */
169 float ConstantDecelerationAlphaFunction(float progress)
170 {
171   return progress * 2.0f - progress * progress;
172 }
173
174 // Internal Constraints ///////////////////////////////////////////////////////////////////////////
175
176 /**
177  * Internal Relative position Constraint
178  * Generates the relative position value of the scroll view
179  * based on the absolute position, and it's relation to the
180  * scroll domain. This is a value from 0.0f to 1.0f in each
181  * scroll position axis.
182  */
183 Vector3 InternalRelativePositionConstraint(const Vector3&    current,
184                                            const PropertyInput& scrollPositionProperty,
185                                            const PropertyInput& scrollMinProperty,
186                                            const PropertyInput& scrollMaxProperty,
187                                            const PropertyInput& scrollSizeProperty)
188 {
189   const Vector3& position = -scrollPositionProperty.GetVector3();
190   const Vector3& min = scrollMinProperty.GetVector3();
191   const Vector3& max = scrollMaxProperty.GetVector3();
192   const Vector3& size = scrollSizeProperty.GetVector3();
193
194   Vector3 relativePosition;
195   Vector3 domainSize = (max - min) - size;
196
197   relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
198   relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
199
200   return relativePosition;
201 }
202
203 } // unnamed namespace
204
205 namespace Dali
206 {
207
208 namespace Toolkit
209 {
210
211 namespace Internal
212 {
213
214 namespace
215 {
216
217 /**
218  * Internal Pre-Position Property Constraint.
219  *
220  * Generates position property based on current position + gesture displacement.
221  * Or generates position property based on positionX/Y.
222  * Note: This is the position prior to any clamping at scroll boundaries.
223  * TODO: Scale & Rotation Transforms.
224  */
225 struct InternalPrePositionConstraint
226 {
227   InternalPrePositionConstraint(const Vector2& initialPanMask,
228                                 bool axisAutoLock,
229                                 float axisAutoLockGradient)
230   : mInitialPanMask(initialPanMask),
231     mAxisAutoLock(axisAutoLock),
232     mLockAxis(ScrollView::LockPossible),
233     mAxisAutoLockGradient(axisAutoLockGradient),
234     mPrePosition(Vector3::ZERO),
235     mWasPanning(false)
236   {
237   }
238
239   Vector3 operator()(const Vector3&    current,
240                      const PropertyInput& gesturePositionProperty,
241                      const PropertyInput& gestureDisplacementProperty,
242                      const PropertyInput& scrollPositionXProperty,
243                      const PropertyInput& scrollPositionYProperty,
244                      const PropertyInput& panningProperty)
245   {
246     const bool panning = panningProperty.GetBoolean();
247     Vector3 scrollPostPosition;
248
249     if(panning)
250     {
251       // Check if panning has just started...
252       if(!mWasPanning)
253       {
254         mLocalStart = gesturePositionProperty.GetVector2() - gestureDisplacementProperty.GetVector2();
255         mPrePosition = current;
256         mLockAxis = ScrollView::LockPossible;
257
258         mCurrentPanMask = mInitialPanMask;
259       }
260
261       // Calculate Deltas...
262       Vector2 currentPosition = gesturePositionProperty.GetVector2();
263       Vector2 panDelta( currentPosition - mLocalStart );
264
265       // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
266       // appears mostly horizontal or mostly vertical respectively...
267       AxisAutoLock(panDelta);
268
269       // Restrict deltas based on ruler enable/disable and axis-lock state...
270       panDelta *= mCurrentPanMask;
271
272       // Perform Position transform based on input deltas...
273       scrollPostPosition = mPrePosition;
274       scrollPostPosition.GetVectorXY() += panDelta;
275     }
276     else
277     {
278       scrollPostPosition.x = scrollPositionXProperty.GetFloat();
279       scrollPostPosition.y = scrollPositionYProperty.GetFloat();
280     }
281
282     mWasPanning = panning;
283     return scrollPostPosition;
284   }
285
286   void AxisAutoLock(Vector2& panDelta)
287   {
288     if(mAxisAutoLock)
289     {
290       if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
291           mLockAxis == ScrollView::LockPossible)
292       {
293         float dx = fabsf(panDelta.x);
294         float dy = fabsf(panDelta.y);
295         if(dx * mAxisAutoLockGradient >= dy)
296         {
297           // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
298           mLockAxis = ScrollView::LockVertical;
299           mCurrentPanMask.y = 0.0f;
300         }
301         else if(dy * mAxisAutoLockGradient > dx)
302         {
303           // 0.36:1 gradient to the vertical (deviate < 20 degrees)
304           mLockAxis = ScrollView::LockHorizontal;
305           mCurrentPanMask.x = 0.0f;
306         }
307         else
308         {
309           mLockAxis = ScrollView::LockNone;
310         }
311       }
312     } // end if mAxisAutoLock
313   }
314
315   Vector2 mLocalStart;
316   Vector2 mInitialPanMask;              ///< Initial pan mask (based on ruler settings)
317   Vector2 mCurrentPanMask;              ///< Current pan mask that can be altered by axis lock mode.
318
319   bool mAxisAutoLock;                   ///< Set by ScrollView
320   ScrollView::LockAxis mLockAxis;
321   float mAxisAutoLockGradient;          ///< Set by ScrollView
322   Vector3 mPrePosition;
323   bool mWasPanning;
324 };
325
326 /**
327  * Internal Position Property Constraint.
328  *
329  * Generates position property based on pre-position
330  * Note: This is the position after clamping.
331  * (uses result of InternalPrePositionConstraint)
332  */
333 struct InternalPositionConstraint
334 {
335   InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY)
336   : mDomainMin( -domainX.min, -domainY.min ),
337     mDomainMax( -domainX.max, -domainY.max ),
338     mClampX( domainX.enabled ),
339     mClampY( domainY.enabled )
340   {
341   }
342
343   Vector3 operator()(const Vector3&    current,
344                      const PropertyInput& scrollPositionProperty,
345                      const PropertyInput& scrollSizeProperty)
346   {
347     Vector3 position = scrollPositionProperty.GetVector3();
348     const Vector2& size = scrollSizeProperty.GetVector3().GetVectorXY();
349
350     position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x ) : position.x;
351     position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y ) : position.y;
352
353     return position;
354   }
355
356   Vector2 mDomainMin;
357   Vector2 mDomainMax;
358   bool mClampX;
359   bool mClampY;
360
361 };
362
363 /**
364  * This constraint updates the X overshoot property using the difference
365  * mPropertyPrePosition.x and mPropertyPosition.x, returning a relative value between 0.0f and 1.0f
366  */
367 struct OvershootXConstraint
368 {
369   OvershootXConstraint(float maxOvershoot) : mLastOvershoot(0.0f), mMaxOvershoot(maxOvershoot) {}
370
371   float operator()(const float&    current,
372       const PropertyInput& scrollPrePositionProperty,
373       const PropertyInput& scrollPostPositionProperty)
374   {
375     Vector3 scrollPrePosition = scrollPrePositionProperty.GetVector3();
376     Vector3 scrollPostPosition = scrollPostPositionProperty.GetVector3();
377     float newOvershoot = scrollPrePosition.x - scrollPostPosition.x;
378     return (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
379   }
380
381   float mLastOvershoot;
382   float mMaxOvershoot;
383 };
384
385 /**
386  * This constraint updates the Y overshoot property using the difference
387  * mPropertyPrePosition.y and mPropertyPosition.y, returning a relative value between 0.0f and 1.0f
388  */
389 struct OvershootYConstraint
390 {
391   OvershootYConstraint(float maxOvershoot) : mLastOvershoot(0.0f), mMaxOvershoot(maxOvershoot) {}
392
393   float operator()(const float&    current,
394       const PropertyInput& scrollPrePositionProperty,
395       const PropertyInput& scrollPostPositionProperty)
396   {
397     Vector3 scrollPrePosition = scrollPrePositionProperty.GetVector3();
398     Vector3 scrollPostPosition = scrollPostPositionProperty.GetVector3();
399     float newOvershoot = scrollPrePosition.y - scrollPostPosition.y;
400     return (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
401   }
402
403   float mLastOvershoot;
404   float mMaxOvershoot;
405 };
406
407 /**
408  * When panning, this constraint updates the X property, otherwise
409  * it has no effect on the X property.
410  */
411 float InternalXConstraint(const float&    current,
412                           const PropertyInput& scrollPosition,
413                           const PropertyInput& panningProperty)
414 {
415   return scrollPosition.GetVector3().x;
416 }
417
418 /**
419  * When panning, this constraint updates the Y property, otherwise
420  * it has no effect on the Y property.
421  */
422 float InternalYConstraint(const float&    current,
423                           const PropertyInput& scrollPosition,
424                           const PropertyInput& panningProperty)
425 {
426   return scrollPosition.GetVector3().y;
427 }
428
429 /**
430  * Internal Position-Delta Property Constraint.
431  *
432  * Generates position-delta property based on scroll-position + scroll-offset properties.
433  */
434 Vector3 InternalPositionDeltaConstraint(const Vector3&    current,
435                                         const PropertyInput& scrollPositionProperty,
436                                         const PropertyInput& scrollOffsetProperty)
437 {
438   const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
439   const Vector3& scrollOffset = scrollOffsetProperty.GetVector3();
440
441   return scrollPosition + scrollOffset;
442 }
443
444 /**
445  * Internal Final Position Constraint
446  * The position of content is:
447  * of scroll-position + f(scroll-overshoot)
448  * where f(...) function defines how overshoot
449  * should affect final-position.
450  */
451 struct InternalFinalConstraint
452 {
453   InternalFinalConstraint(AlphaFunction functionX,
454                           AlphaFunction functionY)
455   : mFunctionX(functionX),
456     mFunctionY(functionY)
457   {
458   }
459
460   Vector3 operator()(const Vector3&    current,
461                      const PropertyInput& scrollPositionProperty,
462                      const PropertyInput& scrollOvershootXProperty,
463                      const PropertyInput& scrollOvershootYProperty)
464   {
465     const float& overshootx = scrollOvershootXProperty.GetFloat();
466     const float& overshooty = scrollOvershootYProperty.GetFloat();
467     Vector3 offset( mFunctionX(overshootx),
468                     mFunctionY(overshooty),
469                     0.0f);
470
471     return scrollPositionProperty.GetVector3() - offset;
472   }
473
474   AlphaFunction mFunctionX;
475   AlphaFunction mFunctionY;
476 };
477
478
479 BaseHandle Create()
480 {
481   return Toolkit::ScrollView::New();
482 }
483
484 TypeRegistration typeRegistration( typeid(Toolkit::ScrollView), typeid(Toolkit::Scrollable), Create );
485
486 SignalConnectorType signalConnector1( typeRegistration, Toolkit::ScrollView::SIGNAL_SNAP_STARTED, &ScrollView::DoConnectSignal );
487
488 }
489
490
491 ///////////////////////////////////////////////////////////////////////////////////////////////////
492 // ScrollView
493 ///////////////////////////////////////////////////////////////////////////////////////////////////
494
495 Dali::Toolkit::ScrollView ScrollView::New()
496 {
497   // Create the implementation
498   ScrollViewPtr scrollView(new ScrollView());
499
500   // Pass ownership to CustomActor via derived handle
501   Dali::Toolkit::ScrollView handle(*scrollView);
502
503   // Second-phase init of the implementation
504   // This can only be done after the CustomActor connection has been made...
505   scrollView->Initialize();
506
507   return handle;
508 }
509
510 ScrollView::ScrollView()
511 : ScrollBase(),
512   mInitialized(false),
513   mScrolling(false),
514   mScrollInterrupted(false),
515   mTouchDownTime(0u),
516   mSensitive(true),
517   mGestureStackDepth(0),
518   mRotationDelta(0.0f),
519   mScrollPreRotation(0.0f),
520   mScrollPostRotation(0.0f),
521   mTouchDownReceived(false),
522   mActorAutoSnapEnabled(false),
523   mAutoResizeContainerEnabled(false),
524   mWrapMode(false),
525   mAxisAutoLock(false),
526   mMinTouchesForPanning(1),
527   mMaxTouchesForPanning(1),
528   mLockAxis(LockPossible),
529   mRefreshIntervalMilliseconds(DEFAULT_REFRESH_INTERVAL_MILLISECONDS),
530   mAlterChild(false),
531   mOvershootDelay(1.0f),
532   mMaxOvershoot(Toolkit::ScrollView::DEFAULT_MAX_OVERSHOOT, Toolkit::ScrollView::DEFAULT_MAX_OVERSHOOT),
533   mDefaultMaxOvershoot(true),
534   mSnapOvershootDuration(Toolkit::ScrollView::DEFAULT_SNAP_OVERSHOOT_DURATION),
535   mSnapOvershootAlphaFunction(AlphaFunctions::EaseOut),
536   mSnapDuration(Toolkit::ScrollView::DEFAULT_SLOW_SNAP_ANIMATION_DURATION),
537   mSnapAlphaFunction(AlphaFunctions::EaseOut),
538   mFlickDuration(Toolkit::ScrollView::DEFAULT_FAST_SNAP_ANIMATION_DURATION),
539   mFlickAlphaFunction(AlphaFunctions::EaseOut),
540   mAxisAutoLockGradient(Toolkit::ScrollView::DEFAULT_AXIS_AUTO_LOCK_GRADIENT),
541   mFrictionCoefficient(Toolkit::ScrollView::DEFAULT_FRICTION_COEFFICIENT),
542   mFlickSpeedCoefficient(Toolkit::ScrollView::DEFAULT_FLICK_SPEED_COEFFICIENT),
543   mMaxFlickSpeed(Toolkit::ScrollView::DEFAULT_MAX_FLICK_SPEED),
544   mInAccessibilityPan(false)
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   Vector3 positionSnap = mScrollPostPosition;
1362
1363   // Flick logic X Axis
1364
1365   if(mRulerX->IsEnabled())
1366   {
1367     horizontal = All;
1368
1369     if( speed2 > flickSpeedThreshold2 || // exceeds flick threshold
1370         mInAccessibilityPan ) // With AccessibilityPan its easier to move between snap positions
1371     {
1372       if((angle >= -orthoAngleRange) && (angle < orthoAngleRange)) // Swiping East
1373       {
1374         biasX = 0.0f, horizontal = Left;
1375
1376         // This guards against an error where no movement occurs, due to the flick finishing
1377         // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
1378         positionSnap.x += 1.0f;
1379       }
1380       else if((angle >= M_PI-orthoAngleRange) || (angle < -M_PI+orthoAngleRange)) // Swiping West
1381       {
1382         biasX = 1.0f, horizontal = Right;
1383
1384         // This guards against an error where no movement occurs, due to the flick finishing
1385         // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
1386         positionSnap.x -= 1.0f;
1387       }
1388     }
1389   }
1390
1391   // Flick logic Y Axis
1392
1393   if(mRulerY->IsEnabled())
1394   {
1395     vertical = All;
1396
1397     if( speed2 > flickSpeedThreshold2 || // exceeds flick threshold
1398         mInAccessibilityPan ) // With AccessibilityPan its easier to move between snap positions
1399     {
1400       if((angle >= M_PI_2-orthoAngleRange) && (angle < M_PI_2+orthoAngleRange)) // Swiping South
1401       {
1402         biasY = 0.0f, vertical = Up;
1403       }
1404       else if((angle >= -M_PI_2-orthoAngleRange) && (angle < -M_PI_2+orthoAngleRange)) // Swiping North
1405       {
1406         biasY = 1.0f, vertical = Down;
1407       }
1408     }
1409   }
1410
1411   // isFlick: Whether this gesture is a flick or not.
1412   bool isFlick = (horizontal != All || vertical != All);
1413   // isFreeFlick: Whether this gesture is a flick under free panning criteria.
1414   bool isFreeFlick = velocity.LengthSquared() > (FREE_FLICK_SPEED_THRESHOLD*FREE_FLICK_SPEED_THRESHOLD);
1415
1416   if(isFlick || isFreeFlick)
1417   {
1418     positionDuration = Vector3::ONE * mFlickDuration;
1419     alphaFunction = mFlickAlphaFunction;
1420   }
1421
1422   // Calculate next positionSnap ////////////////////////////////////////////////////////////
1423
1424   if(mActorAutoSnapEnabled)
1425   {
1426     Vector3 size = Self().GetCurrentSize();
1427
1428     Actor child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f), horizontal, vertical );
1429
1430     if(!child && isFlick )
1431     {
1432       // If we conducted a direction limited search and found no actor, then just snap to the closest actor.
1433       child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f) );
1434     }
1435
1436     if(child)
1437     {
1438       Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
1439
1440       // Get center-point of the Actor.
1441       Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
1442
1443       if(mRulerX->IsEnabled())
1444       {
1445         positionSnap.x = position.x - childPosition.x + size.width * 0.5f;
1446       }
1447       if(mRulerY->IsEnabled())
1448       {
1449         positionSnap.y = position.y - childPosition.y + size.height * 0.5f;
1450       }
1451     }
1452   }
1453
1454   Vector3 startPosition = positionSnap;
1455   positionSnap.x = -mRulerX->Snap(-positionSnap.x, biasX);  // NOTE: X & Y rulers think in -ve coordinate system.
1456   positionSnap.y = -mRulerY->Snap(-positionSnap.y, biasY);  // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
1457
1458   Vector3 clampDelta(Vector3::ZERO);
1459   ClampPosition(positionSnap);
1460
1461   if( (mRulerX->GetType() == Ruler::Free || mRulerY->GetType() == Ruler::Free)
1462       && isFreeFlick && !mActorAutoSnapEnabled)
1463   {
1464     // Calculate target position based on velocity of flick.
1465
1466     // a = Deceleration (Set to diagonal stage length * friction coefficient)
1467     // u = Initial Velocity (Flick velocity)
1468     // v = 0 (Final Velocity)
1469     // t = Time (Velocity / Deceleration)
1470     Vector2 stageSize = Stage::GetCurrent().GetSize();
1471     float stageLength = Vector3(stageSize.x, stageSize.y, 0.0f).Length();
1472     float a = (stageLength * mFrictionCoefficient);
1473     Vector3 u = Vector3(velocity.x, velocity.y, 0.0f) * mFlickSpeedCoefficient;
1474     float speed = u.Length();
1475     u/= speed;
1476
1477     // TODO: Change this to a decay function. (faster you flick, the slower it should be)
1478     speed = std::min(speed, stageLength * mMaxFlickSpeed );
1479     u*= speed;
1480     alphaFunction = ConstantDecelerationAlphaFunction;
1481
1482     float t = speed / a;
1483
1484     if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
1485     {
1486       positionSnap.x += t*u.x*0.5f;
1487     }
1488
1489     if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
1490     {
1491       positionSnap.y += t*u.y*0.5f;
1492     }
1493
1494     clampDelta = positionSnap;
1495     ClampPosition(positionSnap);
1496     if((positionSnap - startPosition).LengthSquared() > Math::MACHINE_EPSILON_0)
1497     {
1498       clampDelta -= positionSnap;
1499       clampDelta.x = clampDelta.x > 0.0f ? std::min(clampDelta.x, mMaxOvershoot.x) : std::max(clampDelta.x, -mMaxOvershoot.x);
1500       clampDelta.y = clampDelta.y > 0.0f ? std::min(clampDelta.y, mMaxOvershoot.y) : std::max(clampDelta.y, -mMaxOvershoot.y);
1501     }
1502     else
1503     {
1504       clampDelta = Vector3::ZERO;
1505     }
1506
1507     // If Axis is Free and has velocity, then calculate time taken
1508     // to reach target based on velocity in axis.
1509     if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
1510     {
1511       float deltaX = fabsf(startPosition.x - positionSnap.x);
1512
1513       if(fabsf(u.x) > Math::MACHINE_EPSILON_1)
1514       {
1515         positionDuration.x = fabsf(deltaX / u.x);
1516       }
1517       else
1518       {
1519         positionDuration.x = 0;
1520       }
1521     }
1522
1523     if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
1524     {
1525       float deltaY = fabsf(startPosition.y - positionSnap.y);
1526
1527       if(fabsf(u.y) > Math::MACHINE_EPSILON_1)
1528       {
1529         positionDuration.y = fabsf(deltaY / u.y);
1530       }
1531       else
1532       {
1533         positionDuration.y = 0;
1534       }
1535     }
1536   }
1537   positionSnap += clampDelta;
1538
1539   // Scale Snap ///////////////////////////////////////////////////////////////
1540   Vector3 scaleSnap = mScrollPostScale;
1541
1542   scaleSnap.x = mRulerScaleX->Snap(scaleSnap.x);
1543   scaleSnap.y = mRulerScaleY->Snap(scaleSnap.y);
1544
1545   ClampScale(scaleSnap);
1546
1547   // Rotation Snap ////////////////////////////////////////////////////////////
1548   float rotationSnap = mScrollPostRotation;
1549   // TODO: implement rotation snap
1550
1551   bool animating = AnimateTo(positionSnap, positionDuration,
1552                              scaleSnap, scaleDuration,
1553                              rotationSnap, rotationDuration,
1554                              alphaFunction, false,
1555                              DirectionBiasNone, DirectionBiasNone,
1556                              isFlick || isFreeFlick ? Flick : Snap);
1557
1558   if(animating)
1559   {
1560     AnimateOvershootToOrigin(positionDuration.x, positionDuration.y);
1561   }
1562
1563   return animating;
1564 }
1565
1566 void ScrollView::StopAnimation(void)
1567 {
1568   // Clear Snap animation if exists.
1569   if(mSnapAnimation)
1570   {
1571     mSnapAnimation.Stop();
1572     mSnapAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapAnimationFinished);
1573     mSnapAnimation.Clear();
1574     mSnapAnimation = NULL;
1575   }
1576   if(mSnapXAnimation)
1577   {
1578     mSnapXAnimation.Stop();
1579     mSnapXAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapXAnimationFinished);
1580     mSnapXAnimation.Clear();
1581     mSnapXAnimation = NULL;
1582   }
1583   if(mSnapYAnimation)
1584   {
1585     mSnapYAnimation.Stop();
1586     mSnapYAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapYAnimationFinished);
1587     mSnapYAnimation.Clear();
1588     mSnapYAnimation = NULL;
1589   }
1590   if(mSnapOvershootAnimation)
1591   {
1592     mSnapOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapOvershootAnimationFinished);
1593     mSnapOvershootAnimation.Stop();
1594     mSnapOvershootAnimation.Clear();
1595     mSnapOvershootAnimation = NULL;
1596   }
1597   HandleStoppedAnimation();
1598 }
1599
1600 bool ScrollView::AnimateTo(const Vector3& position, const Vector3& positionDuration,
1601                            const Vector3& scale, const Vector3& scaleDuration,
1602                            float rotation, float rotationDuration,
1603                            AlphaFunction alpha, bool findShortcuts,
1604                            DirectionBias horizontalBias, DirectionBias verticalBias,
1605                            SnapType snapType)
1606 {
1607   // Here we perform an animation on a number of properties (depending on which have changed)
1608   // The animation is applied to all ScrollBases
1609   Actor self = Self();
1610   bool startAnimation = false;
1611   Vector3 positionTransformed = position;
1612   float totalDuration = 0.0f;
1613
1614   bool positionChanged = (positionTransformed != mScrollPostPosition);
1615   bool scaleChanged = (scale != mScrollPostScale);
1616   bool rotationChanged = fabsf(rotation - mScrollPostRotation) > Math::MACHINE_EPSILON_0;
1617
1618   if(positionChanged)
1619   {
1620     totalDuration = std::max(totalDuration, positionDuration.x);
1621     totalDuration = std::max(totalDuration, positionDuration.y);
1622   }
1623
1624   if(scaleChanged)
1625   {
1626     totalDuration = std::max(totalDuration, scaleDuration.x);
1627     totalDuration = std::max(totalDuration, scaleDuration.y);
1628   }
1629
1630   if(rotationChanged)
1631   {
1632     totalDuration = std::max(totalDuration, rotationDuration);
1633   }
1634
1635   if(totalDuration > Math::MACHINE_EPSILON_1)
1636   {
1637     StopAnimation();
1638     mSnapAnimation = Animation::New(totalDuration);
1639     mSnapAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapAnimationFinished);
1640     mSnapXAnimation = Animation::New(positionDuration.x);
1641     mSnapXAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapXAnimationFinished);
1642     mSnapYAnimation = Animation::New(positionDuration.y);
1643     mSnapYAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapYAnimationFinished);
1644     startAnimation = true;
1645
1646     // Position Delta ///////////////////////////////////////////////////////
1647     if(positionChanged)
1648     {
1649       if(mWrapMode && findShortcuts)
1650       {
1651         // In Wrap Mode, the shortest distance is a little less intuitive...
1652         const RulerDomain rulerDomainX = mRulerX->GetDomain();
1653         const RulerDomain rulerDomainY = mRulerY->GetDomain();
1654
1655         if(mRulerX->IsEnabled())
1656         {
1657           float dir = VectorInDomain(-mScrollPostPosition.x, -positionTransformed.x, rulerDomainX.min, rulerDomainX.max, horizontalBias);
1658           positionTransformed.x = mScrollPostPosition.x + -dir;
1659         }
1660
1661         if(mRulerY->IsEnabled())
1662         {
1663           float dir = VectorInDomain(-mScrollPostPosition.y, -positionTransformed.y, rulerDomainY.min, rulerDomainY.max, verticalBias);
1664           positionTransformed.y = mScrollPostPosition.y + -dir;
1665         }
1666       }
1667
1668       // note we have two separate animations for X & Y, this deals with sliding diagonally and hitting
1669       // a horizonal/vertical wall.delay
1670       mSnapXAnimation.AnimateTo( Property(self, mPropertyX), positionTransformed.x, alpha, TimePeriod(0.0f, positionDuration.x));
1671       mSnapYAnimation.AnimateTo( Property(self, mPropertyY), positionTransformed.y, alpha, TimePeriod(0.0f, positionDuration.y));
1672     }
1673
1674     // Scale Delta ///////////////////////////////////////////////////////
1675     if(scaleChanged)
1676     {
1677       // TODO: for non-uniform scaling to different bounds e.g. scaling a square to a 4:3 aspect ratio screen with a velocity
1678       // the height will hit first, and then the width, so that would require two different animation times just like position.
1679       mSnapAnimation.AnimateTo( Property(self, mPropertyScale), scale, alpha, TimePeriod(0.0f, scaleDuration.x));
1680     }
1681
1682     mSnapAnimation.AnimateTo( Property(self, mPropertyTime), totalDuration, AlphaFunctions::Linear );
1683
1684     mSnapAnimation.Play();
1685     mSnapXAnimation.Play();
1686     mSnapYAnimation.Play();
1687     StartRefreshTimer();
1688   } // end if(totalDuration > Math::MACHINE_EPSILON_1)
1689   else // totalDuration == 0
1690   {
1691     // instantly set transform.
1692     if(positionChanged)
1693     {
1694       self.SetProperty(mPropertyX, positionTransformed.x);
1695       self.SetProperty(mPropertyY, positionTransformed.y);
1696
1697       mScrollPrePosition = mScrollPostPosition = positionTransformed;
1698     }
1699
1700     if(scaleChanged)
1701     {
1702       self.SetProperty(mPropertyScale, scale);
1703
1704       mScrollPreScale = mScrollPostScale = scale;
1705     }
1706   }
1707
1708   // Always send a snap event when AnimateTo is called.
1709   Toolkit::ScrollView::SnapEvent snapEvent;
1710   snapEvent.type = snapType;
1711   snapEvent.position = positionTransformed;
1712   snapEvent.scale = scale;
1713   snapEvent.rotation = rotation;
1714   snapEvent.duration = totalDuration;
1715
1716   mSnapStartedSignalV2.Emit( snapEvent );
1717
1718   return startAnimation;
1719 }
1720
1721 void ScrollView::SetOvershootEnabled(bool enabled)
1722 {
1723   if(enabled && !mOvershootIndicator)
1724   {
1725     mOvershootIndicator = ScrollOvershootIndicator::New(*this);
1726   }
1727   mOvershootIndicator->Enable(enabled);
1728 }
1729
1730 void ScrollView::AddOverlay(Actor actor)
1731 {
1732   mInternalActor.Add( actor );
1733 }
1734
1735 void ScrollView::RemoveOverlay(Actor actor)
1736 {
1737   mInternalActor.Remove( actor );
1738 }
1739
1740 void ScrollView::SetScrollingDirection( Radian direction, Radian threshold )
1741 {
1742   PanGestureDetector panGesture( GetPanGestureDetector() );
1743
1744   // First remove just in case we have some set, then add.
1745   panGesture.RemoveDirection( direction );
1746   panGesture.AddDirection( direction, threshold );
1747 }
1748
1749 void ScrollView::RemoveScrollingDirection( Radian direction )
1750 {
1751   PanGestureDetector panGesture( GetPanGestureDetector() );
1752   panGesture.RemoveDirection( direction );
1753 }
1754
1755 Toolkit::ScrollView::SnapStartedSignalV2& ScrollView::SnapStartedSignal()
1756 {
1757   return mSnapStartedSignalV2;
1758 }
1759
1760 void ScrollView::FindAndUnbindActor(Actor child)
1761 {
1762   UnbindActor(child);
1763 }
1764
1765 Vector3 ScrollView::GetPropertyPrePosition() const
1766 {
1767   Vector3 position(Self().GetProperty<float>(mPropertyX), Self().GetProperty<float>(mPropertyY), 0.0f);
1768   WrapPosition(position);
1769
1770   return position;
1771 }
1772
1773 Vector3 ScrollView::GetPropertyPosition() const
1774 {
1775   Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
1776   WrapPosition(position);
1777
1778   return position;
1779 }
1780
1781 Vector3 ScrollView::GetPropertyScale() const
1782 {
1783   return Self().GetProperty<Vector3>(mPropertyScale);
1784 }
1785
1786 void ScrollView::HandleStoppedAnimation()
1787 {
1788   // Animation has stopped, so stop sending the scroll-update signal.
1789   CancelRefreshTimer();
1790
1791   // cement transform now, and allow interactivity to resume.
1792   mScrollPostPosition = GetPropertyPosition();
1793
1794   mScrollPostScale = GetPropertyScale();
1795
1796   // Update Actor position with this wrapped value.
1797
1798   Self().SetProperty(mPropertyX, mScrollPostPosition.x);
1799   Self().SetProperty(mPropertyY, mScrollPostPosition.y);
1800   // TODO Rotation
1801
1802   mScrollPrePosition = mScrollPostPosition;
1803   mScrollPreScale = mScrollPostScale;
1804   mScrollPreRotation = mScrollPostRotation;
1805 }
1806
1807 void ScrollView::HandleSnapAnimationFinished()
1808 {
1809   // Emit Signal that scrolling has completed.
1810   mScrolling = false;
1811   Self().SetProperty(mPropertyScrolling, false);
1812
1813   Vector3 deltaPosition(Self().GetProperty<float>(mPropertyX),
1814                         Self().GetProperty<float>(mPropertyY),
1815                         0.0f);
1816
1817   Vector3 currentScrollPosition = GetCurrentScrollPosition();
1818   mScrollCompletedSignalV2.Emit( currentScrollPosition );
1819
1820   mDomainOffset += deltaPosition - mScrollPostPosition;
1821   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
1822   HandleStoppedAnimation();
1823 }
1824
1825 bool ScrollView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1826 {
1827   Dali::BaseHandle handle( object );
1828
1829   bool connected( true );
1830   Toolkit::ScrollView view = Toolkit::ScrollView::DownCast( handle );
1831
1832   if( Toolkit::ScrollView::SIGNAL_SNAP_STARTED == signalName )
1833   {
1834     view.SnapStartedSignal().Connect( tracker, functor );
1835   }
1836   else
1837   {
1838     // signalName does not match any signal
1839     connected = false;
1840   }
1841
1842   return connected;
1843 }
1844
1845 void ScrollView::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
1846 {
1847   // need to update domain properties for new size
1848   UpdatePropertyDomain(targetSize);
1849 }
1850
1851 void ScrollView::OnControlSizeSet( const Vector3& size )
1852 {
1853   // need to update domain properties for new size
1854   if( mDefaultMaxOvershoot )
1855   {
1856     mMaxOvershoot.x = size.x * 0.5f;
1857     mMaxOvershoot.y = size.y * 0.5f;
1858   }
1859   UpdatePropertyDomain(size);
1860   UpdateMainInternalConstraint();
1861   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
1862   {
1863     mOvershootIndicator->Reset();
1864   }
1865 }
1866
1867 void ScrollView::OnChildAdd(Actor& child)
1868 {
1869   if(mAlterChild)
1870   {
1871     BindActor(child);
1872   }
1873 }
1874
1875 void ScrollView::OnChildRemove(Actor& child)
1876 {
1877   // TODO: Actor needs a RemoveConstraint method to take out an individual constraint.
1878   UnbindActor(child);
1879 }
1880
1881 bool ScrollView::OnTouchEvent(const TouchEvent& event)
1882 {
1883   if(!mSensitive)
1884   {
1885     // Ignore this touch event, if scrollview is insensitive.
1886     return false;
1887   }
1888
1889   // Ignore events with multiple-touch points
1890   if (event.GetPointCount() != 1)
1891   {
1892     return false;
1893   }
1894
1895   if (event.GetPoint(0).state == TouchPoint::Down)
1896   {
1897     mTouchDownTime = event.time;
1898     mTouchDownReceived = true;
1899     mTouchDownPosition = event.GetPoint(0).local;
1900
1901     if( mSnapAnimation || mSnapXAnimation || mSnapYAnimation || mSnapOvershootAnimation )
1902     {
1903       mScrollInterrupted = true;
1904       StopAnimation();
1905     }
1906
1907     if(mScrolling) // are we interrupting a current scroll?
1908     {
1909       // reset domain offset as scrolling from original plane.
1910       mDomainOffset = Vector3::ZERO;
1911       Self().SetProperty(mPropertyDomainOffset, Vector3::ZERO);
1912
1913       mScrolling = false;
1914       Vector3 currentScrollPosition = GetCurrentScrollPosition();
1915       mScrollCompletedSignalV2.Emit( currentScrollPosition );
1916     }
1917   }
1918   else if(event.GetPoint(0).state == TouchPoint::Up)
1919   {
1920     // if the user touches and releases without enough movement to go
1921     // into a gesture state, then we should snap to nearest point.
1922     // otherwise our scroll could be stopped (interrupted) half way through an animation.
1923     if(mGestureStackDepth==0 && mTouchDownReceived)
1924     {
1925       unsigned timeDelta( event.time - mTouchDownTime );
1926       if ( timeDelta >= MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET )
1927       {
1928         // Reset the velocity only if down was received a while ago
1929         mLastVelocity = Vector2( 0.0f, 0.0f );
1930       }
1931       else
1932       {
1933         Vector2 positionDelta( mTouchDownPosition - event.GetPoint(0).local );
1934         mLastVelocity = positionDelta / timeDelta;
1935       }
1936
1937       // Only finish the transform if scrolling was interrupted on down or if we are scrolling
1938       if ( mSnapAnimation || mSnapXAnimation || mSnapYAnimation || mSnapOvershootAnimation || mScrollInterrupted || mScrolling )
1939       {
1940         FinishTransform();
1941       }
1942     }
1943     mTouchDownReceived = false;
1944     mScrollInterrupted = false;
1945   }
1946
1947   return true; // consume since we're potentially scrolling
1948 }
1949
1950 bool ScrollView::OnMouseWheelEvent(const MouseWheelEvent& event)
1951 {
1952   if(!mSensitive)
1953   {
1954     // Ignore this mouse wheel event, if scrollview is insensitive.
1955     return false;
1956   }
1957
1958   Vector3 targetScrollPosition = GetPropertyPosition();
1959
1960   if(mRulerX->IsEnabled() && !mRulerY->IsEnabled())
1961   {
1962     // If only the ruler in the X axis is enabled, scroll in the X axis.
1963     if(mRulerX->GetType() == Ruler::Free)
1964     {
1965       // Free panning mode
1966       targetScrollPosition.x -= event.z * mMouseWheelScrollDistanceStep.x;
1967       ClampPosition(targetScrollPosition);
1968       ScrollTo(-targetScrollPosition);
1969     }
1970     else if(!mScrolling)
1971     {
1972       // Snap mode, only respond to the event when the previous snap animation is finished.
1973       ScrollTo(GetCurrentPage() + event.z);
1974     }
1975   }
1976   else
1977   {
1978     // If the ruler in the Y axis is enabled, scroll in the Y axis.
1979     if(mRulerY->GetType() == Ruler::Free)
1980     {
1981       // Free panning mode
1982       targetScrollPosition.y -= event.z * mMouseWheelScrollDistanceStep.y;
1983       ClampPosition(targetScrollPosition);
1984       ScrollTo(-targetScrollPosition);
1985     }
1986     else if(!mScrolling)
1987     {
1988       // Snap mode, only respond to the event when the previous snap animation is finished.
1989       ScrollTo(GetCurrentPage() + event.z * mRulerX->GetTotalPages());
1990     }
1991   }
1992
1993   return true;
1994 }
1995
1996 void ScrollView::OnSnapAnimationFinished( Animation& source )
1997 {
1998   mSnapAnimation.FinishedSignal().Disconnect( this, &ScrollView::OnSnapAnimationFinished );
1999   mSnapAnimation = NULL;
2000 }
2001
2002 void ScrollView::OnSnapXAnimationFinished( Animation& source )
2003 {
2004   // Guard against destruction during signal emission
2005   // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
2006   Toolkit::ScrollView handle( GetOwner() );
2007
2008   if(!mSnapYAnimation)
2009   {
2010     HandleSnapAnimationFinished();
2011   }
2012   if(mScrollMainInternalOvershootXConstraint)
2013   {
2014     Self().RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2015     mScrollMainInternalOvershootXConstraint.Reset();
2016     mScrollMainInternalOvershootXConstraint = 0;
2017   }
2018   mSnapXAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapXAnimationFinished);
2019   mSnapXAnimation.Reset();
2020   mSnapXAnimation = NULL;
2021   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2022   {
2023     // kick start animation to 0
2024     Self().SetProperty(mPropertyOvershootX, 0.0f);
2025   }
2026 }
2027
2028 void ScrollView::OnSnapYAnimationFinished( Animation& source )
2029 {
2030   // Guard against destruction during signal emission
2031   // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
2032   Toolkit::ScrollView handle( GetOwner() );
2033
2034   if(!mSnapXAnimation)
2035   {
2036     HandleSnapAnimationFinished();
2037   }
2038   if(mScrollMainInternalOvershootYConstraint)
2039   {
2040     Self().RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2041     mScrollMainInternalOvershootYConstraint.Reset();
2042     mScrollMainInternalOvershootYConstraint = 0;
2043   }
2044   mSnapYAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapYAnimationFinished);
2045   mSnapYAnimation.Reset();
2046   mSnapYAnimation = NULL;
2047   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2048   {
2049     // kick start animation to 0
2050     Self().SetProperty(mPropertyOvershootY, 0.0f);
2051   }
2052 }
2053
2054 void ScrollView::GestureStarted()
2055 {
2056   // we handle the first gesture.
2057   // if we're currently doing a gesture and receive another
2058   // we continue and combine the effects of the gesture instead of reseting.
2059   if(mGestureStackDepth++==0)
2060   {
2061     StopAnimation();
2062     mPanDelta = Vector3::ZERO;
2063     mScaleDelta = Vector3::ONE;
2064     mRotationDelta = 0.0f;
2065     mLastVelocity = Vector2(0.0f, 0.0f);
2066     mLockAxis = LockPossible;
2067
2068     if(mScrolling) // are we interrupting a current scroll?
2069     {
2070       // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
2071       mScrolling = false;
2072       Vector3 currentScrollPosition = GetCurrentScrollPosition();
2073       mScrollCompletedSignalV2.Emit( currentScrollPosition );
2074     }
2075   }
2076 }
2077
2078 void ScrollView::GestureContinuing(Vector2 panDelta, Vector2 scaleDelta, float rotationDelta)
2079 {
2080   mPanDelta.x+= panDelta.x;
2081   mPanDelta.y+= panDelta.y;
2082   mScaleDelta.x*= scaleDelta.x;
2083   mScaleDelta.y*= scaleDelta.y;
2084   mRotationDelta+= rotationDelta;
2085
2086   // Save the velocity, there is a bug in PanGesture
2087   // Whereby the Gesture::Finished's velocity is either:
2088   // NaN (due to time delta of zero between the last two events)
2089   // or 0 (due to position being the same between the last two events)
2090
2091   // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
2092   // appears mostly horizontal or mostly vertical respectively.
2093   if(mAxisAutoLock)
2094   {
2095     if(mPanDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
2096         mLockAxis == LockPossible)
2097     {
2098       float dx = fabsf(mPanDelta.x);
2099       float dy = fabsf(mPanDelta.y);
2100       if(dx * mAxisAutoLockGradient >= dy)
2101       {
2102         // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
2103         mLockAxis = LockVertical;
2104       }
2105       else if(dy * mAxisAutoLockGradient > dx)
2106       {
2107         // 0.36:1 gradient to the vertical (deviate < 20 degrees)
2108         mLockAxis = LockHorizontal;
2109       }
2110       else
2111       {
2112         mLockAxis = LockNone;
2113       }
2114     }
2115   } // end if mAxisAutoLock
2116 }
2117
2118 // TODO: Upgrade to use a more powerful gesture detector (one that supports multiple touches on pan - so works as pan and flick gesture)
2119 // TODO: Reimplement Scaling (pinching 2+ points)
2120 // TODO: Reimplment Rotation (pinching 2+ points)
2121 // BUG: Gesture::Finished doesn't always return velocity on release (due to
2122 // timeDelta between last two events being 0 sometimes, or posiiton being the same)
2123 void ScrollView::OnPan(PanGesture gesture)
2124 {
2125   // Guard against destruction during signal emission
2126   // Note that Emit() methods are called indirectly e.g. from within ScrollView::OnGestureEx()
2127   Actor self( Self() );
2128
2129   if(!mSensitive)
2130   {
2131     // If another callback on the same original signal disables sensitivity,
2132     // this callback will still be called, so we must suppress it.
2133     return;
2134   }
2135
2136   // translate Gesture input to get useful data...
2137   switch(gesture.state)
2138   {
2139     case Gesture::Started:
2140     {
2141       GestureStarted();
2142       self.SetProperty( mPropertyPanning, true );
2143       self.SetProperty( mPropertyScrollStartPagePosition, GetCurrentScrollPosition() );
2144
2145       //  Update property: X & Y = Position (only when in panning mode - in snapping mode, X & Y are animated).
2146       Constraint constraint = Constraint::New<float>( mPropertyX,
2147                                            LocalSource( mPropertyPosition ),
2148                                            Source( self, mPropertyPanning ),
2149                                            InternalXConstraint );
2150       mScrollMainInternalXConstraint = self.ApplyConstraint(constraint);
2151
2152       constraint = Constraint::New<float>( mPropertyY,
2153                                            LocalSource( mPropertyPosition ),
2154                                            Source( self, mPropertyPanning ),
2155                                            InternalYConstraint );
2156       mScrollMainInternalYConstraint = self.ApplyConstraint(constraint);
2157       // When panning we want to make sure overshoot values are affected by pre position and post position
2158       SetOvershootConstraintsEnabled(true);
2159       break;
2160     }
2161
2162     case Gesture::Continuing:
2163     {
2164       // Nothing to do, handled in constraint.
2165       break;
2166     }
2167
2168     case Gesture::Finished:
2169     case Gesture::Cancelled:
2170     {
2171       mLastVelocity = gesture.velocity;
2172       self.SetProperty( mPropertyPanning, false );
2173
2174       // Remove X & Y position constraints as they are not required when we are not panning.
2175       self.RemoveConstraint(mScrollMainInternalXConstraint);
2176       self.RemoveConstraint(mScrollMainInternalYConstraint);
2177       break;
2178     }
2179
2180     case Gesture::Possible:
2181     case Gesture::Clear:
2182     {
2183       // Nothing to do, not needed.
2184       break;
2185     }
2186
2187   } // end switch(gesture.state)
2188
2189   OnGestureEx(gesture.state);
2190 }
2191
2192 void ScrollView::OnGestureEx(Gesture::State state)
2193 {
2194   // call necessary signals for application developer
2195
2196   if(state == Gesture::Started)
2197   {
2198     Vector3 currentScrollPosition = GetCurrentScrollPosition();
2199     Self().SetProperty(mPropertyScrolling, true);
2200     mScrolling = true;
2201     mScrollStartedSignalV2.Emit( currentScrollPosition );
2202   }
2203   else if( (state == Gesture::Finished) ||
2204            (state == Gesture::Cancelled) ) // Finished/default
2205   {
2206     // when all the gestures have finished, we finish the transform.
2207     // so if a user decides to pan (1 gesture), and then pan+zoom (2 gestures)
2208     // then stop panning (back to 1 gesture), and then stop zooming (0 gestures).
2209     // this is the point we end, and perform necessary snapping.
2210     mGestureStackDepth--;
2211     if(mGestureStackDepth==0)
2212     {
2213       FinishTransform();
2214     }
2215   }
2216 }
2217
2218 void ScrollView::UpdateTransform()
2219 {
2220 // TODO: notify clamps using property notifications (or see if we need this, can deprecate it)
2221 }
2222
2223 void ScrollView::FinishTransform()
2224 {
2225   const Vector3& scrollPosition = Self().GetProperty<Vector3>(mPropertyPosition);
2226
2227   mScrollPostPosition.x = scrollPosition.x;
2228   mScrollPostPosition.y = scrollPosition.y;
2229
2230   Vector3 deltaPosition(mScrollPostPosition);
2231   // Cement PRE transform (PRE = POST), and Begin Snap Animation if necessary.
2232   WrapPosition(mScrollPostPosition);
2233
2234   mDomainOffset += deltaPosition - mScrollPostPosition;
2235   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
2236
2237   bool animating = SnapWithVelocity(mLastVelocity * 1000.0f);
2238
2239   if(!animating)
2240   {
2241     AnimateOvershootToOrigin(0.0f, 0.0f);
2242     // if not animating, then this pan has completed right now.
2243     mScrolling = false;
2244     Self().SetProperty(mPropertyScrolling, false);
2245     Vector3 currentScrollPosition = GetCurrentScrollPosition();
2246     mScrollCompletedSignalV2.Emit( currentScrollPosition );
2247   }
2248 }
2249
2250 Vector3 ScrollView::GetOvershoot(Vector3& position) const
2251 {
2252   Vector3 size = Self().GetCurrentSize();
2253   Vector3 overshoot;
2254
2255   const RulerDomain rulerDomainX = mRulerX->GetDomain();
2256   const RulerDomain rulerDomainY = mRulerY->GetDomain();
2257
2258   if(mRulerX->IsEnabled() && rulerDomainX.enabled)
2259   {
2260     const float left = rulerDomainX.min - position.x;
2261     const float right = size.width - rulerDomainX.max - position.x;
2262     if(left<0)
2263     {
2264       overshoot.x = left;
2265     }
2266     else if(right>0)
2267     {
2268       overshoot.x = right;
2269     }
2270   }
2271
2272   if(mRulerY->IsEnabled() && rulerDomainY.enabled)
2273   {
2274     const float top = rulerDomainY.min - position.y;
2275     const float bottom = size.height - rulerDomainY.max - position.y;
2276     if(top<0)
2277     {
2278       overshoot.y = top;
2279     }
2280     else if(bottom>0)
2281     {
2282       overshoot.y = bottom;
2283     }
2284   }
2285
2286   return overshoot;
2287 }
2288
2289 bool ScrollView::OnAccessibilityPan(PanGesture gesture)
2290 {
2291   // Keep track of whether this is an AccessibilityPan
2292   mInAccessibilityPan = true;
2293   OnPan(gesture);
2294   mInAccessibilityPan = false;
2295
2296   return true;
2297 }
2298
2299 void ScrollView::ClampPosition(Vector3& position) const
2300 {
2301   ClampState3 clamped;
2302   ClampPosition(position, clamped);
2303 }
2304
2305 void ScrollView::ClampPosition(Vector3& position, ClampState3 &clamped) const
2306 {
2307   Vector3 size = Self().GetCurrentSize();
2308
2309   // determine size of viewport relative to current scaled size.
2310   // e.g. if you're zoomed in 200%, then each pixel on screen is only 0.5 pixels on subject.
2311   if(fabsf(mScrollPostScale.x) > Math::MACHINE_EPSILON_0)
2312   {
2313     size.x /= mScrollPostScale.x;
2314   }
2315
2316   if(fabsf(mScrollPostScale.y) > Math::MACHINE_EPSILON_0)
2317   {
2318     size.y /= mScrollPostScale.y;
2319   }
2320
2321   position.x = -mRulerX->Clamp(-position.x, size.width, 1.0f, clamped.x);    // NOTE: X & Y rulers think in -ve coordinate system.
2322   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.
2323
2324   clamped.z = NotClamped;
2325 }
2326
2327 void ScrollView::WrapPosition(Vector3& position) const
2328 {
2329   if(mWrapMode)
2330   {
2331     const RulerDomain rulerDomainX = mRulerX->GetDomain();
2332     const RulerDomain rulerDomainY = mRulerY->GetDomain();
2333
2334     if(mRulerX->IsEnabled())
2335     {
2336       position.x = -WrapInDomain(-position.x, rulerDomainX.min, rulerDomainX.max);
2337     }
2338
2339     if(mRulerY->IsEnabled())
2340     {
2341       position.y = -WrapInDomain(-position.y, rulerDomainY.min, rulerDomainY.max);
2342     }
2343   }
2344 }
2345
2346 void ScrollView::ClampScale(Vector3& scale) const
2347 {
2348   ClampState3 clamped;
2349   ClampScale(scale, clamped);
2350 }
2351
2352 void ScrollView::ClampScale(Vector3& scale, ClampState3 &clamped) const
2353 {
2354   scale.x = mRulerScaleX->Clamp(scale.x, 0.0f, 1.0f, clamped.x);
2355   scale.y = mRulerScaleY->Clamp(scale.y, 0.0f, 1.0f, clamped.y);
2356   clamped.z = NotClamped;
2357 }
2358
2359 void ScrollView::UpdateMainInternalConstraint()
2360 {
2361   // TODO: Only update the constraints which have changed, rather than remove all and add all again.
2362   // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
2363   Actor self = Self();
2364   PanGestureDetector detector( GetPanGestureDetector() );
2365
2366   if(mScrollMainInternalPrePositionConstraint)
2367   {
2368     self.RemoveConstraint(mScrollMainInternalPrePositionConstraint);
2369     self.RemoveConstraint(mScrollMainInternalPositionConstraint);
2370     self.RemoveConstraint(mScrollMainInternalDeltaConstraint);
2371     self.RemoveConstraint(mScrollMainInternalFinalConstraint);
2372     self.RemoveConstraint(mScrollMainInternalRelativeConstraint);
2373   }
2374
2375   // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
2376   // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
2377
2378   // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
2379   Vector2 initialPanMask = Vector2(mRulerX->IsEnabled() ? 1.0f : 0.0f, mRulerY->IsEnabled() ? 1.0f : 0.0f);
2380
2381   Constraint constraint = Constraint::New<Vector3>( mPropertyPrePosition,
2382                                                     Source( detector, PanGestureDetector::LOCAL_POSITION ),
2383                                                     Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
2384                                                     LocalSource( mPropertyX ),
2385                                                     LocalSource( mPropertyY ),
2386                                                     Source( self, mPropertyPanning ),
2387                                                     InternalPrePositionConstraint( initialPanMask, mAxisAutoLock, mAxisAutoLockGradient ) );
2388   mScrollMainInternalPrePositionConstraint = self.ApplyConstraint(constraint);
2389
2390   // 2. Second calculate the clamped position (actual position)
2391   constraint = Constraint::New<Vector3>( mPropertyPosition,
2392                                          LocalSource( mPropertyPrePosition ),
2393                                          Source( self, Actor::SIZE ),
2394                                          InternalPositionConstraint( mRulerX->GetDomain(),
2395                                                                      mRulerY->GetDomain()) );
2396   mScrollMainInternalPositionConstraint = self.ApplyConstraint(constraint);
2397
2398   constraint = Constraint::New<Vector3>( mPropertyPositionDelta,
2399                                          LocalSource( mPropertyPosition ),
2400                                          LocalSource( mPropertyDomainOffset ),
2401                                          InternalPositionDeltaConstraint );
2402   mScrollMainInternalDeltaConstraint = self.ApplyConstraint(constraint);
2403
2404   constraint = Constraint::New<Vector3>( mPropertyFinal,
2405                                          LocalSource( mPropertyPosition ),
2406                                          LocalSource( mPropertyOvershootX ),
2407                                          LocalSource( mPropertyOvershootY ),
2408                                          InternalFinalConstraint( FinalDefaultAlphaFunction,
2409                                                                   FinalDefaultAlphaFunction ) );
2410   mScrollMainInternalFinalConstraint = self.ApplyConstraint(constraint);
2411
2412   constraint = Constraint::New<Vector3>( mPropertyRelativePosition,
2413                                          LocalSource( mPropertyPosition ),
2414                                          LocalSource( mPropertyPositionMin ),
2415                                          LocalSource( mPropertyPositionMax ),
2416                                          LocalSource( Actor::SIZE ),
2417                                          InternalRelativePositionConstraint );
2418   mScrollMainInternalRelativeConstraint = self.ApplyConstraint(constraint);
2419
2420   if(mScrollMainInternalOvershootXConstraint)
2421   {
2422     // reset these constraints in correct order
2423     self.RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2424     mScrollMainInternalOvershootXConstraint.Reset();
2425
2426     Constraint constraint = Constraint::New<float>( mPropertyOvershootX,
2427                                            LocalSource( mPropertyPrePosition ),
2428                                            LocalSource( mPropertyPosition ),
2429                                            OvershootXConstraint(mMaxOvershoot.x) );
2430     mScrollMainInternalOvershootXConstraint = self.ApplyConstraint(constraint);
2431   }
2432
2433   if(mScrollMainInternalOvershootYConstraint)
2434   {
2435     // reset these constraints in correct order
2436     self.RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2437     mScrollMainInternalOvershootYConstraint.Reset();
2438
2439     Constraint constraint = Constraint::New<float>( mPropertyOvershootY,
2440                                            LocalSource( mPropertyPrePosition ),
2441                                            LocalSource( mPropertyPosition ),
2442                                            OvershootXConstraint(mMaxOvershoot.y) );
2443     mScrollMainInternalOvershootYConstraint = self.ApplyConstraint(constraint);
2444   }
2445 }
2446
2447 void ScrollView::SetOvershootConstraintsEnabled(bool enabled)
2448 {
2449   Actor self( Self() );
2450   // remove and reset, it may now be in wrong order with the main internal constraints
2451   if(mScrollMainInternalOvershootXConstraint)
2452   {
2453     self.RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2454     mScrollMainInternalOvershootXConstraint.Reset();
2455   }
2456   if(mScrollMainInternalOvershootYConstraint)
2457   {
2458     self.RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2459     mScrollMainInternalOvershootYConstraint.Reset();
2460   }
2461   if(enabled)
2462   {
2463     Constraint constraint = Constraint::New<float>( mPropertyOvershootX,
2464                                            LocalSource( mPropertyPrePosition ),
2465                                            LocalSource( mPropertyPosition ),
2466                                            OvershootXConstraint(mMaxOvershoot.x) );
2467     mScrollMainInternalOvershootXConstraint = self.ApplyConstraint(constraint);
2468     constraint = Constraint::New<float>( mPropertyOvershootY,
2469                                            LocalSource( mPropertyPrePosition ),
2470                                            LocalSource( mPropertyPosition ),
2471                                            OvershootYConstraint(mMaxOvershoot.y) );
2472     mScrollMainInternalOvershootYConstraint = self.ApplyConstraint(constraint);
2473   }
2474 }
2475
2476 void ScrollView::SetInternalConstraints()
2477 {
2478   // Internal constraints (applied to target ScrollBase Actor itself) /////////
2479   UpdateMainInternalConstraint();
2480
2481   // User definable constraints to apply to all child actors //////////////////
2482   Actor self = Self();
2483
2484   // LocalSource - The Actors to be moved.
2485   // self - The ScrollView
2486
2487   // Apply some default constraints to ScrollView.
2488   // Movement + Scaling + Wrap function
2489
2490   Constraint constraint;
2491
2492   // MoveScaledActor (scrolling/zooming)
2493   constraint = Constraint::New<Vector3>( Actor::POSITION,
2494                                          Source( self, mPropertyPosition ),
2495                                          Source( self, mPropertyScale ),
2496                                          MoveScaledActorConstraint );
2497   constraint.SetRemoveAction(Constraint::Discard);
2498   ApplyConstraintToBoundActors(constraint);
2499
2500   // ScaleActor (scrolling/zooming)
2501   constraint = Constraint::New<Vector3>( Actor::SCALE,
2502                                          Source( self, mPropertyScale ),
2503                                          ScaleActorConstraint );
2504   constraint.SetRemoveAction(Constraint::Discard);
2505   ApplyConstraintToBoundActors(constraint);
2506
2507   // WrapActor (wrap functionality)
2508   constraint = Constraint::New<Vector3>( Actor::POSITION,
2509                                                  LocalSource( Actor::SCALE ),
2510                                                  LocalSource( Actor::ANCHOR_POINT ),
2511                                                  LocalSource( Actor::SIZE ),
2512                                                  Source( self, mPropertyPositionMin ),
2513                                                  Source( self, mPropertyPositionMax ),
2514                                                  Source( self, mPropertyWrap ),
2515                                                  WrapActorConstraint );
2516   constraint.SetRemoveAction(Constraint::Discard);
2517   ApplyConstraintToBoundActors(constraint);
2518 }
2519
2520 void ScrollView::SetOvershootToOrigin()
2521 {
2522   // Clear Snap animation if exists.
2523   if(mSnapOvershootAnimation)
2524   {
2525     mSnapOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollView::OnSnapOvershootAnimationFinished);
2526     mSnapOvershootAnimation.Stop();
2527     mSnapOvershootAnimation.Clear();
2528     mSnapOvershootAnimation = NULL;
2529   }
2530   SetOvershootConstraintsEnabled(false);
2531   Self().SetProperty(mPropertyOvershootX, 0.0f);
2532   Self().SetProperty(mPropertyOvershootY, 0.0f);
2533 }
2534
2535 void ScrollView::AnimateOvershootToOrigin(float xDelay, float yDelay)
2536 {
2537   if( IsScrollComponentEnabled(Toolkit::Scrollable::OvershootIndicator) )
2538   {
2539     if(xDelay < Math::MACHINE_EPSILON_1)
2540     {
2541       // kick start animation to 0
2542       Self().SetProperty(mPropertyOvershootX, 0.0f);
2543     }
2544     if(yDelay < Math::MACHINE_EPSILON_1)
2545     {
2546       // kick start animation to 0
2547       Self().SetProperty(mPropertyOvershootY, 0.0f);
2548     }
2549     return;
2550   }
2551   // When we need to animate overshoot to 0
2552   if(mSnapOvershootDuration > Math::MACHINE_EPSILON_1)
2553   {
2554     Actor self = Self();
2555     // Clear Snap animation if exists.
2556     if(mSnapOvershootAnimation)
2557     {
2558       mSnapOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollView::OnSnapOvershootAnimationFinished );
2559       mSnapOvershootAnimation.Stop();
2560       mSnapOvershootAnimation.Clear();
2561       mSnapOvershootAnimation = NULL;
2562     }
2563     if(!mSnapXAnimation && mScrollMainInternalOvershootXConstraint)
2564     {
2565       // need to remove the x overshoot constraint now or it will override animation to 0
2566       Self().RemoveConstraint(mScrollMainInternalOvershootXConstraint);
2567       mScrollMainInternalOvershootXConstraint.Reset();
2568       mScrollMainInternalOvershootXConstraint = 0;
2569     }
2570     if(!mSnapYAnimation && mScrollMainInternalOvershootYConstraint)
2571     {
2572       // need to remove the y overshoot constraint now or it will override animation to 0
2573       Self().RemoveConstraint(mScrollMainInternalOvershootYConstraint);
2574       mScrollMainInternalOvershootYConstraint.Reset();
2575       mScrollMainInternalOvershootYConstraint = 0;
2576     }
2577     // setup the new overshoot to 0 animation
2578     float totalDuration = (xDelay > yDelay ? xDelay : yDelay) + mSnapOvershootDuration;
2579     mSnapOvershootAnimation = Animation::New(totalDuration);
2580     mSnapOvershootAnimation.FinishedSignal().Connect( this, &ScrollView::OnSnapOvershootAnimationFinished );
2581
2582     mSnapOvershootAnimation.AnimateTo( Property(self, mPropertyOvershootX), 0.0f, mSnapOvershootAlphaFunction, TimePeriod(xDelay, mSnapOvershootDuration) );
2583     mSnapOvershootAnimation.AnimateTo( Property(self, mPropertyOvershootY), 0.0f, mSnapOvershootAlphaFunction, TimePeriod(yDelay, mSnapOvershootDuration) );
2584
2585     mSnapOvershootAnimation.SetDuration(totalDuration);
2586     mSnapOvershootAnimation.Play();
2587   }
2588   else
2589   {
2590     SetOvershootToOrigin();
2591   }
2592 }
2593
2594 void ScrollView::OnSnapOvershootAnimationFinished( Animation& source )
2595 {
2596   mSnapOvershootAnimation = NULL;
2597 }
2598
2599 void ScrollView::StartRefreshTimer()
2600 {
2601   if(mRefreshIntervalMilliseconds > 0)
2602   {
2603     if (!mRefreshTimer)
2604     {
2605       mRefreshTimer = Timer::New( mRefreshIntervalMilliseconds );
2606       mRefreshTimer.TickSignal().Connect( this, &ScrollView::OnRefreshTick );
2607     }
2608
2609     if (!mRefreshTimer.IsRunning())
2610     {
2611       mRefreshTimer.Start();
2612     }
2613   }
2614 }
2615
2616 void ScrollView::CancelRefreshTimer()
2617 {
2618   if (mRefreshTimer)
2619   {
2620     mRefreshTimer.Stop();
2621   }
2622 }
2623
2624 bool ScrollView::OnRefreshTick()
2625 {
2626   // Guard against destruction during signal emission
2627   Toolkit::ScrollView handle( GetOwner() );
2628
2629   Vector3 currentScrollPosition = GetCurrentScrollPosition();
2630   mScrollUpdatedSignalV2.Emit( currentScrollPosition );
2631
2632   return true;
2633 }
2634
2635 } // namespace Internal
2636
2637 } // namespace Toolkit
2638
2639 } // namespace Dali