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