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