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