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