New Bouncing Effect
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-impl.cpp
index 97f4145..0c761fb 100644 (file)
@@ -611,7 +611,6 @@ ScrollView::ScrollView()
   mFrictionCoefficient(Toolkit::ScrollView::DEFAULT_FRICTION_COEFFICIENT),
   mFlickSpeedCoefficient(Toolkit::ScrollView::DEFAULT_FLICK_SPEED_COEFFICIENT),
   mMaxFlickSpeed(Toolkit::ScrollView::DEFAULT_MAX_FLICK_SPEED),
-  mPropertiesUpdated(false),
   mInAccessibilityPan(false),
   mInitialized(false),
   mScrolling(false),
@@ -1052,7 +1051,7 @@ void ScrollView::SetScrollSensitive(bool sensitive)
   Actor self = Self();
   PanGestureDetector panGesture( GetPanGestureDetector() );
 
-  DALI_LOG_SCROLL_STATE("[0x%X] sensitive[%d]", this, int(sensitive));
+  DALI_LOG_SCROLL_STATE("[0x%X] sensitive: before:[%d] setting[%d]", this, int(mSensitive), int(sensitive));
 
   if((!mSensitive) && (sensitive))
   {
@@ -1062,8 +1061,7 @@ void ScrollView::SetScrollSensitive(bool sensitive)
   else if((mSensitive) && (!sensitive))
   {
     // while the scroll view is panning, the state needs to be reset.
-    bool isPanning = self.GetProperty<bool>( mPropertyPanning );
-    if ( isPanning )
+    if ( mPanning )
     {
       PanGesture cancelGesture( Gesture::Cancelled );
       OnPan( cancelGesture );
@@ -1223,7 +1221,7 @@ Vector2 ScrollView::GetMouseWheelScrollDistanceStep() const
 unsigned int ScrollView::GetCurrentPage() const
 {
   // in case animation is currently taking place.
-  Vector3 position = GetCurrentScrollPosition();
+  Vector3 position = GetPropertyPosition();
 
   Actor self = Self();
   unsigned int page = 0;
@@ -1231,8 +1229,8 @@ unsigned int ScrollView::GetCurrentPage() const
   unsigned int volume = 0;
 
   // if rulerX is enabled, then get page count (columns)
-  page = mRulerX->GetPageFromPosition(position.x, mWrapMode);
-  volume = mRulerY->GetPageFromPosition(position.y, mWrapMode);
+  page = mRulerX->GetPageFromPosition(-position.x, mWrapMode);
+  volume = mRulerY->GetPageFromPosition(-position.y, mWrapMode);
   pagesPerVolume = mRulerX->GetTotalPages();
 
   return volume * pagesPerVolume + page;
@@ -1240,10 +1238,6 @@ unsigned int ScrollView::GetCurrentPage() const
 
 Vector3 ScrollView::GetCurrentScrollPosition() const
 {
-  if( mPropertiesUpdated )
-  {
-    return -mScrollPostPosition;
-  }
   return -GetPropertyPosition();
 }
 
@@ -1278,17 +1272,43 @@ void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, floa
 void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, float rotation, float duration,
                              DirectionBias horizontalBias, DirectionBias verticalBias)
 {
+  Actor self( Self() );
+
   // Guard against destruction during signal emission
   // Note that Emit() methods are called indirectly e.g. from within ScrollView::AnimateTo()
   Toolkit::ScrollView handle( GetOwner() );
 
+  DALI_LOG_SCROLL_STATE("[0x%X] pos[%.2f,%.2f], scale[%.2f,%.2f], rot[%.2f], duration[%.2f] bias[%d, %d]",
+    this, position.x, position.y, scale.x, scale.y, rotation, duration, int(horizontalBias), int(verticalBias));
+
   Vector3 currentScrollPosition = GetCurrentScrollPosition();
-  Self().SetProperty( mPropertyScrollStartPagePosition, currentScrollPosition );
+  self.SetProperty( mPropertyScrollStartPagePosition, currentScrollPosition );
 
-  PreAnimatedScrollSetup();
+  if( mScrolling ) // are we interrupting a current scroll?
+  {
+    // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
+    mScrolling = false;
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 1 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+    mScrollCompletedSignalV2.Emit( currentScrollPosition );
+  }
+
+  if( mPanning ) // are we interrupting a current pan?
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Interrupting Pan, set to false", this );
+    mPanning = false;
+    self.SetProperty( mPropertyPanning, false );
+
+    if( mScrollMainInternalPrePositionConstraint )
+    {
+      self.RemoveConstraint(mScrollMainInternalPrePositionConstraint);
+    }
+  }
 
-  Vector3 scrollStartPosition = GetCurrentScrollPosition();
+  self.SetProperty(mPropertyScrolling, true);
+  mScrolling = true;
 
+  DALI_LOG_SCROLL_STATE("[0x%X] mScrollStartedSignalV2 1 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+  mScrollStartedSignalV2.Emit( currentScrollPosition );
   bool animating = AnimateTo(-position,
                              Vector3::ONE * duration,
                              scale,
@@ -1301,16 +1321,23 @@ void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, floa
                              verticalBias,
                              Snap);
 
-  if( !mScrolling )
-  {
-    DALI_LOG_SCROLL_STATE("[0x%X] mScrollStartedSignalV2 1 [%.2f, %.2f]", this, scrollStartPosition.x, scrollStartPosition.y);
-    ScrollingStarted(scrollStartPosition);
-  }
-
   if(!animating)
   {
-    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 1 [%.2f, %.2f]", this, -mScrollPostPosition.x, -mScrollPostPosition.y);
-    ScrollingStopped(-mScrollPostPosition);
+    // if not animating, then this pan has completed right now.
+    self.SetProperty(mPropertyScrolling, false);
+    mScrolling = false;
+
+    // If we have no duration, then in the next update frame, we will be at the position specified as we just set.
+    // In this scenario, we cannot return the currentScrollPosition as this is out-of-date and should instead return the requested final position
+    Vector3 completedPosition( currentScrollPosition );
+    if( duration <= Math::MACHINE_EPSILON_10 )
+    {
+      completedPosition = position;
+    }
+
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 2 [%.2f, %.2f]", this, completedPosition.x, completedPosition.y);
+    SetScrollUpdateNotification(false);
+    mScrollCompletedSignalV2.Emit( completedPosition );
   }
 }
 
@@ -1327,6 +1354,9 @@ void ScrollView::ScrollTo(const Vector3& position, float duration)
 void ScrollView::ScrollTo(const Vector3& position, float duration,
                           DirectionBias horizontalBias, DirectionBias verticalBias)
 {
+  DALI_LOG_SCROLL_STATE("[0x%X] position[%.2f, %.2f] duration[%.2f]",
+    this, position.x, position.y, duration, int(horizontalBias), int(verticalBias));
+
   TransformTo(position, mScrollPostScale, mScrollPostRotation, duration, horizontalBias, verticalBias);
 }
 
@@ -1718,10 +1748,7 @@ void ScrollView::StopAnimation(void)
   StopAnimation(mSnapAnimation);
   StopAnimation(mInternalXAnimation);
   StopAnimation(mInternalYAnimation);
-
-  // clear scrolling flags
   mScrollStateFlags = 0;
-
   // remove scroll animation flags
   HandleStoppedAnimation();
 }
@@ -1757,6 +1784,12 @@ bool ScrollView::AnimateTo(const Vector3& position, const Vector3& positionDurat
     totalDuration = std::max(totalDuration, positionDuration.x);
     totalDuration = std::max(totalDuration, positionDuration.y);
   }
+  else
+  {
+    // try to animate for a frame, on some occasions update will be changing scroll value while event side thinks it hasnt changed
+    totalDuration = 0.01f;
+    positionChanged = true;
+  }
 
   if(scaleChanged)
   {
@@ -1796,14 +1829,14 @@ bool ScrollView::AnimateTo(const Vector3& position, const Vector3& positionDurat
     // a horizonal/vertical wall.delay
     AnimateInternalXTo(mScrollTargetPosition.x, positionDuration.x, alpha);
     AnimateInternalYTo(mScrollTargetPosition.y, positionDuration.y, alpha);
-  }
 
-  if( !(mScrollStateFlags & SCROLL_ANIMATION_FLAGS) )
-  {
-    mScrollTargetPosition = position;
-    WrapPosition(mScrollTargetPosition);
-    self.SetProperty(mPropertyPrePosition, mScrollTargetPosition);
-    mScrollPrePosition = mScrollPostPosition = mScrollTargetPosition;
+    if( !(mScrollStateFlags & SCROLL_ANIMATION_FLAGS) )
+    {
+      self.SetProperty(mPropertyPrePosition, mScrollTargetPosition);
+      mScrollPrePosition = mScrollTargetPosition;
+      mScrollPostPosition = mScrollTargetPosition;
+      WrapPosition(mScrollPostPosition);
+    }
   }
 
   // Scale Delta ///////////////////////////////////////////////////////
@@ -1872,6 +1905,15 @@ void ScrollView::RemoveOverlay(Actor actor)
   mInternalActor.Remove( actor );
 }
 
+void ScrollView::SetOvershootEffectColor( const Vector4& color )
+{
+  mOvershootEffectColor = color;
+  if( mOvershootIndicator )
+  {
+    mOvershootIndicator->SetOvershootEffectColor( color );
+  }
+}
+
 void ScrollView::SetScrollingDirection( Radian direction, Radian threshold )
 {
   PanGestureDetector panGesture( GetPanGestureDetector() );
@@ -1899,12 +1941,17 @@ void ScrollView::FindAndUnbindActor(Actor child)
 
 Vector3 ScrollView::GetPropertyPrePosition() const
 {
-  return Self().GetProperty<Vector3>(mPropertyPrePosition);
+  Vector3 position = Self().GetProperty<Vector3>(mPropertyPrePosition);
+  WrapPosition(position);
+  return position;
 }
 
 Vector3 ScrollView::GetPropertyPosition() const
 {
-  return Self().GetProperty<Vector3>(mPropertyPosition);
+  Vector3 position = Self().GetProperty<Vector3>(mPropertyPosition);
+  WrapPosition(position);
+
+  return position;
 }
 
 Vector3 ScrollView::GetPropertyScale() const
@@ -1920,20 +1967,23 @@ void ScrollView::HandleStoppedAnimation()
 void ScrollView::HandleSnapAnimationFinished()
 {
   // Emit Signal that scrolling has completed.
+  mScrolling = false;
   Actor self = Self();
   self.SetProperty(mPropertyScrolling, false);
 
   Vector3 deltaPosition(mScrollPrePosition);
 
+  UpdateLocalScrollProperties();
   WrapPosition(mScrollPrePosition);
   self.SetProperty(mPropertyPrePosition, mScrollPrePosition);
 
+  Vector3 currentScrollPosition = GetCurrentScrollPosition();
+  DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 3 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+  mScrollCompletedSignalV2.Emit( currentScrollPosition );
+
   mDomainOffset += deltaPosition - mScrollPostPosition;
   self.SetProperty(mPropertyDomainOffset, mDomainOffset);
   HandleStoppedAnimation();
-
-  DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 2 [%.2f, %.2f]", this, GetCurrentScrollPosition().x, GetCurrentScrollPosition().y);
-  ScrollingStopped(GetCurrentScrollPosition());
 }
 
 void ScrollView::SetScrollUpdateNotification( bool enabled )
@@ -1970,12 +2020,8 @@ void ScrollView::OnScrollUpdateNotification(Dali::PropertyNotification& source)
   // Guard against destruction during signal emission
   Toolkit::ScrollView handle( GetOwner() );
 
-  // sometimes notification isnt removed quickly enough, dont emit signal if not scrolling
-  if( mScrolling )
-  {
-    Vector3 currentScrollPosition = GetCurrentScrollPosition();
-    mScrollUpdatedSignalV2.Emit( currentScrollPosition );
-  }
+  Vector3 currentScrollPosition = GetCurrentScrollPosition();
+  mScrollUpdatedSignalV2.Emit( currentScrollPosition );
 }
 
 bool ScrollView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
@@ -2094,12 +2140,9 @@ bool ScrollView::OnTouchDownTimeout()
       Self().SetProperty(mPropertyDomainOffset, Vector3::ZERO);
 
       UpdateLocalScrollProperties();
-      mPropertiesUpdated = true;
-      DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 3 [%.2f, %.2f]", this, GetCurrentScrollPosition().x, GetCurrentScrollPosition().y);
-      ScrollingStopped(GetCurrentScrollPosition());
-
-      // make sure scroll view returns actual property value and not locally stored value once we return from this function
-      mPropertiesUpdated = false;
+      Vector3 currentScrollPosition = GetCurrentScrollPosition();
+      DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 4 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+      mScrollCompletedSignalV2.Emit( currentScrollPosition );
     }
   }
 
@@ -2120,9 +2163,6 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event)
     return false;
   }
 
-  UpdateLocalScrollProperties();
-  mPropertiesUpdated = true;
-
   if( event.GetPoint(0).state == TouchPoint::Down )
   {
     if(mGestureStackDepth==0)
@@ -2150,6 +2190,7 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event)
         mLastVelocity = Vector2( 0.0f, 0.0f );
       }
 
+      UpdateLocalScrollProperties();
       // Only finish the transform if scrolling was interrupted on down or if we are scrolling
       if ( mScrollInterrupted || mScrolling )
       {
@@ -2160,9 +2201,6 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event)
     mScrollInterrupted = false;
   }
 
-  // no longer guarantee local properties are up to date
-  mPropertiesUpdated = false;
-
   return true;
 }
 
@@ -2212,15 +2250,19 @@ bool ScrollView::OnMouseWheelEvent(const MouseWheelEvent& event)
   return true;
 }
 
+void ScrollView::ResetScrolling()
+{
+  Actor self = Self();
+  self.GetProperty(mPropertyPosition).Get(mScrollPostPosition);
+  mScrollPrePosition = mScrollPostPosition;
+  self.SetProperty(mPropertyPrePosition, mScrollPostPosition);
+}
+
 void ScrollView::UpdateLocalScrollProperties()
 {
-  if( !mPropertiesUpdated )
-  {
-    // only update local properties if we are not currently handler an event originating from this scroll view
-    Actor self = Self();
-    self.GetProperty(mPropertyPrePosition).Get(mScrollPrePosition);
-    self.GetProperty(mPropertyPosition).Get(mScrollPostPosition);
-  }
+  Actor self = Self();
+  self.GetProperty(mPropertyPrePosition).Get(mScrollPrePosition);
+  self.GetProperty(mPropertyPosition).Get(mScrollPostPosition);
 }
 
 // private functions
@@ -2232,10 +2274,24 @@ void ScrollView::PreAnimatedScrollSetup()
 
   Actor self = Self();
 
-  Vector3 deltaPosition(mScrollPrePosition);
+  Vector3 deltaPosition(mScrollPostPosition);
+  WrapPosition(mScrollPostPosition);
   mDomainOffset += deltaPosition - mScrollPostPosition;
   Self().SetProperty(mPropertyDomainOffset, mDomainOffset);
-  StopAnimation();
+
+  if( mScrollStateFlags & SCROLL_X_STATE_MASK )
+  {
+    // already performing animation on internal x position
+    StopAnimation(mInternalXAnimation);
+  }
+
+  if( mScrollStateFlags & SCROLL_Y_STATE_MASK )
+  {
+    // already performing animation on internal y position
+    StopAnimation(mInternalYAnimation);
+  }
+
+  mScrollStateFlags = 0;
 
   mScrollPostScale = GetPropertyScale();
 
@@ -2244,9 +2300,6 @@ void ScrollView::PreAnimatedScrollSetup()
 
   mScrollPreScale = mScrollPostScale;
   mScrollPreRotation = mScrollPostRotation;
-
-  // animated scroll needs update notification
-  SetScrollUpdateNotification(true);
 }
 
 void ScrollView::FinaliseAnimatedScroll()
@@ -2302,7 +2355,6 @@ void ScrollView::OnScrollAnimationFinished( Animation& source )
 
   // update our local scroll positions
   UpdateLocalScrollProperties();
-  mPropertiesUpdated = true;
 
   if( source == mSnapAnimation )
   {
@@ -2348,7 +2400,6 @@ void ScrollView::OnScrollAnimationFinished( Animation& source )
   {
     HandleSnapAnimationFinished();
   }
-  mPropertiesUpdated = false;
 }
 
 void ScrollView::OnSnapInternalPositionFinished( Animation& source )
@@ -2430,15 +2481,30 @@ void ScrollView::GestureStarted()
     mScaleDelta = Vector3::ONE;
     mRotationDelta = 0.0f;
     mLastVelocity = Vector2(0.0f, 0.0f);
+    if( !mScrolling )
+    {
+      mLockAxis = LockPossible;
+    }
+
+    if( mScrollStateFlags & SCROLL_X_STATE_MASK )
+    {
+      StopAnimation(mInternalXAnimation);
+    }
+    if( mScrollStateFlags & SCROLL_Y_STATE_MASK )
+    {
+      StopAnimation(mInternalYAnimation);
+    }
+    mScrollStateFlags = 0;
 
-    // inform application that animated scroll has been interrupted
-    if( mScrolling )
+    if(mScrolling) // are we interrupting a current scroll?
     {
-      DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 4 [%.2f, %.2f]", this, GetCurrentScrollPosition().x, GetCurrentScrollPosition().y);
-      ScrollingStopped(GetCurrentScrollPosition());
+      // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
+      mScrolling = false;
+      // send negative scroll position since scroll internal scroll position works as an offset for actors,
+      // give applications the position within the domain from the scroll view's anchor position
+      DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 5 [%.2f, %.2f]", this, -mScrollPostPosition.x, -mScrollPostPosition.y);
+      mScrollCompletedSignalV2.Emit( -mScrollPostPosition );
     }
-    DALI_LOG_SCROLL_STATE("[0x%X] mScrollStartedSignalV2 2 [%.2f, %.2f]", this, GetCurrentScrollPosition().x, GetCurrentScrollPosition().y);
-    ScrollingStarted(GetCurrentScrollPosition());
   }
 }
 
@@ -2463,24 +2529,6 @@ void ScrollView::GestureContinuing(const Vector2& panDelta, const Vector2& scale
   } // end if mAxisAutoLock
 }
 
-void ScrollView::ScrollingStarted( const Vector3& position )
-{
-  Self().SetProperty(mPropertyScrolling, true);
-  mScrolling = true;
-  mLockAxis = LockPossible;
-
-  mScrollStartedSignalV2.Emit( position );
-}
-
-void ScrollView::ScrollingStopped( const Vector3& position )
-{
-  Self().SetProperty(mPropertyScrolling, false);
-  mScrolling = false;
-  SetScrollUpdateNotification(false);
-
-  mScrollCompletedSignalV2.Emit( position );
-}
-
 // TODO: Upgrade to use a more powerful gesture detector (one that supports multiple touches on pan - so works as pan and flick gesture)
 // TODO: Reimplement Scaling (pinching 2+ points)
 // TODO: Reimplment Rotation (pinching 2+ points)
@@ -2494,18 +2542,20 @@ void ScrollView::OnPan(PanGesture gesture)
 
   if(!mSensitive)
   {
+    DALI_LOG_SCROLL_STATE("[0x%X] Pan Ignored, Insensitive", this);
+
     // If another callback on the same original signal disables sensitivity,
     // this callback will still be called, so we must suppress it.
     return;
   }
-  UpdateLocalScrollProperties();
-  mPropertiesUpdated = true;
 
   // translate Gesture input to get useful data...
   switch(gesture.state)
   {
     case Gesture::Started:
     {
+      DALI_LOG_SCROLL_STATE("[0x%X] Pan Started", this);
+      UpdateLocalScrollProperties();
       GestureStarted();
       mPanning = true;
       self.SetProperty( mPropertyPanning, true );
@@ -2517,25 +2567,45 @@ void ScrollView::OnPan(PanGesture gesture)
 
     case Gesture::Continuing:
     {
-      GestureContinuing(gesture.screenDisplacement, Vector2::ZERO, 0.0f);
+      if ( mPanning )
+      {
+        DALI_LOG_SCROLL_STATE("[0x%X] Pan Continuing", this);
+        GestureContinuing(gesture.screenDisplacement, Vector2::ZERO, 0.0f);
+      }
+      else
+      {
+        // If we do not think we are panning, then we should not do anything here
+        return;
+      }
       break;
     }
 
     case Gesture::Finished:
     case Gesture::Cancelled:
     {
-      mLastVelocity = gesture.velocity;
-      mPanning = false;
-      self.SetProperty( mPropertyPanning, false );
-
-      if( mScrollMainInternalPrePositionConstraint )
+      if ( mPanning )
       {
-        self.RemoveConstraint(mScrollMainInternalPrePositionConstraint);
+        DALI_LOG_SCROLL_STATE("[0x%X] Pan %s", this, ( ( gesture.state == Gesture::Finished ) ? "Finished" : "Cancelled" ) );
+
+        UpdateLocalScrollProperties();
+        mLastVelocity = gesture.velocity;
+        mPanning = false;
+        self.SetProperty( mPropertyPanning, false );
+
+        if( mScrollMainInternalPrePositionConstraint )
+        {
+          self.RemoveConstraint(mScrollMainInternalPrePositionConstraint);
+        }
+
+        if( mOvershootIndicator )
+        {
+          mOvershootIndicator->ClearOvershoot();
+        }
       }
-      mGestureStackDepth--;
-      if(mGestureStackDepth==0)
+      else
       {
-        FinishTransform();
+        // If we do not think we are panning, then we should not do anything here
+        return;
       }
       break;
     }
@@ -2546,10 +2616,37 @@ void ScrollView::OnPan(PanGesture gesture)
       // Nothing to do, not needed.
       break;
     }
+
   } // end switch(gesture.state)
 
-  // can no longer guarantee local properties are latest
-  mPropertiesUpdated = false;
+  OnGestureEx(gesture.state);
+}
+
+void ScrollView::OnGestureEx(Gesture::State state)
+{
+  // call necessary signals for application developer
+
+  if(state == Gesture::Started)
+  {
+    Vector3 currentScrollPosition = GetCurrentScrollPosition();
+    Self().SetProperty(mPropertyScrolling, true);
+    mScrolling = true;
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollStartedSignalV2 2 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+    mScrollStartedSignalV2.Emit( currentScrollPosition );
+  }
+  else if( (state == Gesture::Finished) ||
+           (state == Gesture::Cancelled) ) // Finished/default
+  {
+    // when all the gestures have finished, we finish the transform.
+    // so if a user decides to pan (1 gesture), and then pan+zoom (2 gestures)
+    // then stop panning (back to 1 gesture), and then stop zooming (0 gestures).
+    // this is the point we end, and perform necessary snapping.
+    mGestureStackDepth--;
+    if(mGestureStackDepth==0)
+    {
+      FinishTransform();
+    }
+  }
 }
 
 void ScrollView::UpdateTransform()
@@ -2581,15 +2678,9 @@ void ScrollView::FinishTransform()
     {
       SnapInternalYTo(mScrollTargetPosition.y);
     }
-    if( !(mScrollStateFlags & SNAP_ANIMATION_FLAGS) )
-    {
-      // set final position
-      WrapPosition(mScrollTargetPosition);
-      mScrollPrePosition = mScrollTargetPosition;
-      self.SetProperty(mPropertyPrePosition, mScrollPrePosition);
-    }
-    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 5 [%.2f, %.2f]", this, GetCurrentScrollPosition().x, GetCurrentScrollPosition().y);
-    ScrollingStopped(GetCurrentScrollPosition());
+    Vector3 currentScrollPosition = GetCurrentScrollPosition();
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 6 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+    mScrollCompletedSignalV2.Emit( currentScrollPosition );
   }
 }