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