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