Added test cases and removed dead code
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / item-view-impl.cpp
index 972d04f..b7c1e57 100644 (file)
@@ -26,9 +26,9 @@
 #include <dali/devel-api/common/set-wrapper.h>
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/events/wheel-event.h>
-#include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/events/touch-data.h>
 #include <dali/public-api/object/type-registry.h>
-#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry-helper.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
@@ -42,19 +42,6 @@ using namespace Dali;
 namespace // Unnamed namespace
 {
 
-//Type registration
-
-DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL)
-
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout-position",     FLOAT,    LAYOUT_POSITION)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-speed",        FLOAT,    SCROLL_SPEED)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "overshoot",           FLOAT,    OVERSHOOT)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-direction",    VECTOR2,  SCROLL_DIRECTION)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout-orientation",  INTEGER,  LAYOUT_ORIENTATION)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-content-size", FLOAT,    SCROLL_CONTENT_SIZE)
-
-DALI_TYPE_REGISTRATION_END()
-
 const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f;
 const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f;
 const float DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f;
@@ -69,7 +56,6 @@ const float DEFAULT_ANCHORING_DURATION = 1.0f;  // 1 second
 
 const float MILLISECONDS_PER_SECONDS = 1000.0f;
 
-const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f );
 const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
 const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f);
 const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f;
@@ -88,23 +74,33 @@ float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout)
 }
 
 // Overshoot overlay constraints
-void OvershootOverlaySizeConstraint( Vector3& current, const PropertyInputContainer& inputs )
+struct OvershootOverlaySizeConstraint
 {
-  const Vector2& parentScrollDirection = inputs[0]->GetVector2();
-  const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
-  const Vector3& parentSize = inputs[2]->GetVector3();
-
-  if(Toolkit::IsVertical(layoutOrientation))
+  OvershootOverlaySizeConstraint( float height )
+  : mOvershootHeight( height )
   {
-    current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
   }
-  else
+
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
   {
-    current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
+    const Vector2& parentScrollDirection = inputs[0]->GetVector2();
+    const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
+    const Vector3& parentSize = inputs[2]->GetVector3();
+
+    if(Toolkit::IsVertical(layoutOrientation))
+    {
+      current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
+    }
+    else
+    {
+      current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
+    }
+
+    current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? mOvershootHeight : mOvershootHeight*0.5f;
   }
 
-  current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height*0.5f;
-}
+  float mOvershootHeight;
+};
 
 void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInputContainer& inputs )
 {
@@ -245,6 +241,29 @@ namespace Internal
 namespace // unnamed namespace
 {
 
+//Type registration
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL)
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeSpeed",          FLOAT,     MINIMUM_SWIPE_SPEED          )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeDistance",       FLOAT,     MINIMUM_SWIPE_DISTANCE       )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "wheelScrollDistanceStep",    FLOAT,     WHEEL_SCROLL_DISTANCE_STEP   )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "snapToItemEnabled",          BOOLEAN,   SNAP_TO_ITEM_ENABLED         )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "refreshInterval",            FLOAT,     REFRESH_INTERVAL             )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutPosition",      FLOAT,    LAYOUT_POSITION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollSpeed",         FLOAT,    SCROLL_SPEED)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "overshoot",           FLOAT,    OVERSHOOT)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollDirection",     VECTOR2,  SCROLL_DIRECTION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutOrientation",   INTEGER,  LAYOUT_ORIENTATION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollContentSize",   FLOAT,    SCROLL_CONTENT_SIZE)
+
+DALI_SIGNAL_REGISTRATION(              Toolkit, ItemView, "layoutActivated",     LAYOUT_ACTIVATED_SIGNAL )
+
+DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "stopScrolling",       ACTION_STOP_SCROLLING   )
+
+DALI_TYPE_REGISTRATION_END()
+
 bool FindById( const ItemContainer& items, ItemId id )
 {
   for( ConstItemIter iter = items.begin(); items.end() != iter; ++iter )
@@ -278,26 +297,27 @@ Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory)
 ItemView::ItemView(ItemFactory& factory)
 : Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | REQUIRES_WHEEL_EVENTS | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ),
   mItemFactory(factory),
+  mItemsParentOrigin(ParentOrigin::CENTER),
+  mItemsAnchorPoint(AnchorPoint::CENTER),
+  mTotalPanDisplacement(Vector2::ZERO),
   mActiveLayout(NULL),
-  mAnimatingOvershootOn(false),
-  mAnimateOvershootOff(false),
-  mAnchoringEnabled(false),
   mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
   mRefreshIntervalLayoutPositions(0.0f),
-  mRefreshOrderHint(true/*Refresh item 0 first*/),
   mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
   mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
   mWheelScrollDistanceStep(0.0f),
   mScrollDistance(0.0f),
   mScrollSpeed(0.0f),
-  mTotalPanDisplacement(Vector2::ZERO),
   mScrollOvershoot(0.0f),
-  mIsFlicking(false),
   mGestureState(Gesture::Clear),
+  mAnimatingOvershootOn(false),
+  mAnimateOvershootOff(false),
+  mAnchoringEnabled(false),
+  mRefreshOrderHint(true/*Refresh item 0 first*/),
+  mIsFlicking(false),
   mAddingItems(false),
   mRefreshEnabled(true),
-  mItemsParentOrigin( ParentOrigin::CENTER),
-  mItemsAnchorPoint( AnchorPoint::CENTER)
+  mInAnimation(false)
 {
 }
 
@@ -305,11 +325,10 @@ void ItemView::OnInitialize()
 {
   Actor self = Self();
 
-  SetOvershootEnabled(true);
-
   Vector2 stageSize = Stage::GetCurrent().GetSize();
   mWheelScrollDistanceStep = stageSize.y * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
 
+  self.TouchSignal().Connect( this, &ItemView::OnTouch );
   EnableGestureDetection(Gesture::Type(Gesture::Pan));
 
   mWheelEventFinishedTimer = Timer::New( WHEEL_EVENT_FINISHED_TIME_OUT );
@@ -422,6 +441,11 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz
     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnLayoutActivationScrollFinished);
     mScrollAnimation.Play();
   }
+  else
+  {
+    // Emit the layout activated signal
+    mLayoutActivatedSignal.Emit();
+  }
 
   AnimateScrollOvershoot(0.0f);
   mScrollOvershoot = 0.0f;
@@ -450,11 +474,14 @@ void ItemView::DeactivateCurrentLayout()
 
 void ItemView::OnRefreshNotification(PropertyNotification& source)
 {
-  if(mRefreshEnabled || mScrollAnimation)
+  // Cancel scroll animation to prevent any fighting of setting the scroll position property by scroll bar during fast scroll.
+  if(!mRefreshEnabled && mScrollAnimation)
   {
-    // Only refresh the cache during normal scrolling
-    DoRefresh(GetCurrentLayoutPosition(0), true);
+    RemoveAnimation(mScrollAnimation);
   }
+
+  // Only cache extra items when it is not a fast scroll
+  DoRefresh(GetCurrentLayoutPosition(0), mRefreshEnabled || mScrollAnimation);
 }
 
 void ItemView::Refresh()
@@ -950,42 +977,10 @@ void ItemView::OnChildAdd(Actor& child)
                                         Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y,
                                         Toolkit::Scrollable::Property::SCROLL_POSITION_MAX_Y,
                                         Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE);
-      scrollBar.ScrollPositionIntervalReachedSignal().Connect( this, &ItemView::OnScrollPositionChanged );
     }
   }
 }
 
-bool ItemView::OnTouchEvent(const TouchEvent& event)
-{
-  // Ignore events with multiple-touch points
-  if (event.GetPointCount() != 1)
-  {
-    return false;
-  }
-
-  if (event.GetPoint(0).state == TouchPoint::Down)
-  {
-    // Cancel ongoing scrolling etc.
-    mGestureState = Gesture::Clear;
-
-    mScrollDistance = 0.0f;
-    mScrollSpeed = 0.0f;
-    Self().SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed);
-
-    mScrollOvershoot = 0.0f;
-    AnimateScrollOvershoot(0.0f);
-
-    if(mScrollAnimation)
-    {
-      mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
-    }
-
-    RemoveAnimation(mScrollAnimation);
-  }
-
-  return true; // consume since we're potentially scrolling
-}
-
 bool ItemView::OnWheelEvent(const WheelEvent& event)
 {
   // Respond the wheel event to scroll
@@ -1063,17 +1058,52 @@ void ItemView::OnItemsRemoved()
   }
 }
 
-float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout)
+float ItemView::ClampFirstItemPosition( float targetPosition, const Vector3& targetSize, ItemLayout& layout, bool updateOvershoot )
 {
   Actor self = Self();
   float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize);
   float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, targetPosition));
-  mScrollOvershoot = targetPosition - clamppedPosition;
   self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition));
 
+  if( updateOvershoot )
+  {
+    mScrollOvershoot = targetPosition - clamppedPosition;
+  }
+
   return clamppedPosition;
 }
 
+bool ItemView::OnTouch( Actor actor, const TouchData& touch )
+{
+  // Ignore events with multiple-touch points
+  if (touch.GetPointCount() != 1)
+  {
+    return false;
+  }
+
+  if ( touch.GetState( 0 ) == PointState::DOWN )
+  {
+    // Cancel ongoing scrolling etc.
+    mGestureState = Gesture::Clear;
+
+    mScrollDistance = 0.0f;
+    mScrollSpeed = 0.0f;
+    Self().SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed);
+
+    mScrollOvershoot = 0.0f;
+    AnimateScrollOvershoot(0.0f);
+
+    if(mScrollAnimation)
+    {
+      mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
+    }
+
+    RemoveAnimation(mScrollAnimation);
+  }
+
+  return true; // consume since we're potentially scrolling
+}
+
 void ItemView::OnPan( const PanGesture& gesture )
 {
   Actor self = Self();
@@ -1168,13 +1198,39 @@ void ItemView::OnPan( const PanGesture& gesture )
 
       self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
 
-      if( (firstItemScrollPosition >= 0.0f && currentOvershoot < 1.0f) || (firstItemScrollPosition >= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) && currentOvershoot > -1.0f) )
+      if( ( firstItemScrollPosition >= 0.0f &&
+            currentOvershoot < 1.0f ) ||
+          ( firstItemScrollPosition <= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) &&
+            currentOvershoot > -1.0f ) )
       {
         mTotalPanDisplacement += gesture.displacement;
       }
 
       mScrollOvershoot = CalculateScrollOvershoot();
-      self.SetProperty( Toolkit::ItemView::Property::OVERSHOOT, mScrollOvershoot );
+
+      // If the view is moved in a direction against the overshoot indicator, then the indicator should be animated off.
+      // First make sure we are not in an animation, otherwise a previously started
+      // off-animation will be overwritten as the user continues scrolling.
+      if( !mInAnimation )
+      {
+        // Check if the movement is against the current overshoot amount (if we are currently displaying the indicator).
+        if( ( ( mScrollOvershoot > Math::MACHINE_EPSILON_0 ) && ( mScrollDistance < -Math::MACHINE_EPSILON_0 ) ) ||
+          ( ( mScrollOvershoot < Math::MACHINE_EPSILON_0 ) && ( mScrollDistance > Math::MACHINE_EPSILON_0 ) ) )
+        {
+          // The user has moved against the indicator direction.
+          // First, we reset the total displacement. This means the overshoot amount will become zero the next frame,
+          // and if the user starts dragging in the overshoot direction again, the indicator will appear once more.
+          mTotalPanDisplacement = Vector2::ZERO;
+          // Animate the overshoot indicator off.
+          AnimateScrollOvershoot( 0.0f, false );
+        }
+        else
+        {
+          // Only set the property directly if we are not animating the overshoot away,
+          // as otherwise this will overwrite the animation generated value.
+          self.SetProperty( Toolkit::ItemView::Property::OVERSHOOT, mScrollOvershoot );
+        }
+      }
     }
     break;
 
@@ -1201,7 +1257,7 @@ bool ItemView::OnAccessibilityPan(PanGesture gesture)
   return true;
 }
 
-Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
+Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
 {
   Actor nextFocusActor;
   if(mActiveLayout)
@@ -1298,6 +1354,9 @@ void ItemView::OnLayoutActivationScrollFinished(Animation& source)
   RemoveAnimation(mScrollAnimation);
   mRefreshEnabled = true;
   DoRefresh(GetCurrentLayoutPosition(0), true);
+
+  // Emit the layout activated signal
+  mLayoutActivatedSignal.Emit();
 }
 
 void ItemView::OnOvershootOnFinished(Animation& animation)
@@ -1309,6 +1368,7 @@ void ItemView::OnOvershootOnFinished(Animation& animation)
   {
     AnimateScrollOvershoot(0.0f);
   }
+  mInAnimation = false;
 }
 
 void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
@@ -1321,7 +1381,7 @@ void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
   {
     RemoveAnimation(mScrollAnimation);
     mScrollAnimation = Animation::New(durationSeconds);
-    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, AlphaFunction::EASE_OUT );
+    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, mScrollToAlphaFunction );
     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
     mScrollAnimation.Play();
   }
@@ -1381,23 +1441,13 @@ void ItemView::CalculateDomainSize(const Vector3& layoutSize)
   }
 }
 
-Vector2 ItemView::GetDomainSize() const
-{
-  Actor self = Self();
-
-  float minScrollPosition = self.GetProperty<float>(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y);
-  float maxScrollPosition = self.GetProperty<float>(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX_Y);
-
-  return Vector2(0.0f, fabs(GetScrollPosition(minScrollPosition, self.GetCurrentSize()) - GetScrollPosition(-maxScrollPosition, self.GetCurrentSize())));
-}
-
 bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
 {
   Actor self = Self();
 
-  float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout );
-  float forwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition + 1.0, layoutSize, *mActiveLayout);
-  float backwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition - 1.0, layoutSize, *mActiveLayout);
+  float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout, false );
+  float forwardClampedPosition = ClampFirstItemPosition( currentLayoutPosition + 1.0, layoutSize, *mActiveLayout, false );
+  float backwardClampedPosition = ClampFirstItemPosition( currentLayoutPosition - 1.0, layoutSize, *mActiveLayout, false );
 
   return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0);
 }
@@ -1415,6 +1465,7 @@ Vector2 ItemView::GetCurrentScrollPosition() const
 
 void ItemView::AddOverlay(Actor actor)
 {
+  actor.SetDrawMode( DrawMode::OVERLAY_2D );
   Self().Add(actor);
 }
 
@@ -1434,7 +1485,7 @@ void ItemView::ScrollTo(const Vector2& position, float duration)
   {
     RemoveAnimation(mScrollAnimation);
     mScrollAnimation = Animation::New(duration);
-    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, AlphaFunction::EASE_OUT );
+    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, mScrollToAlphaFunction );
     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
     mScrollAnimation.Play();
   }
@@ -1462,42 +1513,45 @@ void ItemView::EnableScrollOvershoot( bool enable )
   Actor self = Self();
   if( enable )
   {
-    Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX;
-    mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex );
-    mOvershootOverlay.SetColor(mOvershootEffectColor);
-    mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
-    mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
-    mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
-    self.Add(mOvershootOverlay);
-
-    Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
-    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
-    constraint.Apply();
-
-    mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
-
-    constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
-    constraint.Apply();
-
-    constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::POSITION, OvershootOverlayPositionConstraint );
-    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
-    constraint.Apply();
-
-    constraint = Constraint::New<bool>( mOvershootOverlay, Actor::Property::VISIBLE, OvershootOverlayVisibilityConstraint );
-    constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) );
-    constraint.Apply();
-
-    constraint = Constraint::New<float>( mOvershootOverlay, effectOvershootPropertyIndex, EqualToConstraint() );
-    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
-    constraint.Apply();
+    if( !mOvershootOverlay )
+    {
+      Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX;
+      mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex );
+      mOvershootOverlay.SetColor(mOvershootEffectColor);
+      mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
+      mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+      mOvershootOverlay.SetDrawMode( DrawMode::OVERLAY_2D );
+      self.Add(mOvershootOverlay);
+
+      Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint(mOvershootSize.height) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+      constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+      constraint.Apply();
+
+      mOvershootOverlay.SetSize(mOvershootSize.width, mOvershootSize.height);
+
+      constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
+      constraint.Apply();
+
+      constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::POSITION, OvershootOverlayPositionConstraint );
+      constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
+      constraint.Apply();
+
+      constraint = Constraint::New<bool>( mOvershootOverlay, Actor::Property::VISIBLE, OvershootOverlayVisibilityConstraint );
+      constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) );
+      constraint.Apply();
+
+      constraint = Constraint::New<float>( mOvershootOverlay, effectOvershootPropertyIndex, EqualToConstraint() );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
+      constraint.Apply();
+    }
   }
   else
   {
@@ -1554,13 +1608,14 @@ void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
       duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed;
     }
 
+    // Mark the animation as in progress to prevent manual property sets overwriting it.
+    mInAnimation = true;
+    mAnimatingOvershootOn = animatingOn;
     RemoveAnimation(mScrollOvershootAnimation);
     mScrollOvershootAnimation = Animation::New(duration);
     mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished);
     mScrollOvershootAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) );
     mScrollOvershootAnimation.Play();
-
-    mAnimatingOvershootOn = animatingOn;
   }
   else
   {
@@ -1616,13 +1671,129 @@ void ItemView::GetItemsRange(ItemRange& range)
   }
 }
 
-void ItemView::OnScrollPositionChanged( float position )
+bool ItemView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
 {
-  // Cancel scroll animation to prevent any fighting of setting the scroll position property.
-  RemoveAnimation(mScrollAnimation);
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle );
 
-  // Refresh the cache immediately when the scroll position is changed.
-  DoRefresh(position, false); // No need to cache extra items.
+  if( 0 == strcmp( signalName.c_str(), LAYOUT_ACTIVATED_SIGNAL ) )
+  {
+    itemView.LayoutActivatedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void ItemView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) );
+
+  if( itemView )
+  {
+    ItemView& itemViewImpl( GetImpl( itemView ) );
+    switch( index )
+    {
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED:
+      {
+        itemViewImpl.SetMinimumSwipeSpeed( value.Get<float>() );
+        break;
+      }
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
+      {
+        itemViewImpl.SetMinimumSwipeDistance( value.Get<float>() );
+        break;
+      }
+      case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        itemViewImpl.SetWheelScrollDistanceStep( value.Get<float>() );
+        break;
+      }
+      case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
+      {
+        itemViewImpl.SetAnchoring( value.Get<bool>() );
+        break;
+      }
+      case Toolkit::ItemView::Property::REFRESH_INTERVAL:
+      {
+        itemViewImpl.SetRefreshInterval( value.Get<float>() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value ItemView::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) );
+
+  if( itemView )
+  {
+    ItemView& itemViewImpl( GetImpl( itemView ) );
+    switch( index )
+    {
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED:
+      {
+        value = itemViewImpl.GetMinimumSwipeSpeed();
+        break;
+      }
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
+      {
+        value = itemViewImpl.GetMinimumSwipeDistance();
+        break;
+      }
+      case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        value = itemViewImpl.GetWheelScrollDistanceStep();
+        break;
+      }
+      case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
+      {
+        value = itemViewImpl.GetAnchoring();
+        break;
+      }
+      case Toolkit::ItemView::Property::REFRESH_INTERVAL:
+      {
+        value = itemViewImpl.GetRefreshInterval();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+bool ItemView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  Dali::BaseHandle handle( object );
+
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle );
+
+  DALI_ASSERT_ALWAYS( itemView );
+
+  if( 0 == strcmp( actionName.c_str(), ACTION_STOP_SCROLLING ) )
+  {
+    GetImpl( itemView ).DoStopScrolling();
+  }
+
+  return true;
+}
+
+void ItemView::DoStopScrolling()
+{
+  if( mScrollAnimation )
+  {
+    mScrollAnimation.Stop();
+    mScrollAnimation.Reset();
+  }
 }
 
 } // namespace Internal