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