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