Prevent fighting of setting scroll position property by ItemView and ScrollBar 90/24190/1
authorRichard Huang <r.huang@samsung.com>
Wed, 25 Jun 2014 17:33:38 +0000 (18:33 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 8 Jul 2014 17:47:49 +0000 (18:47 +0100)
[problem]      When ItemView is still scrolling, touch and drag the fast scroll bar,
               the fast scroll bar is not responsive for some time and ItemView scrolls
               to the wrong position sometimes.
[cause]        When scroll position property is being animated by ItemView, if something
               else (e.g. ScrollBar) tries to modify the scroll position property at the
               same time, there is a fighting of setting the same property between the two.
[solution]     Cancel scroll animation when it is in fast scroll mode.

Change-Id: I3de03d7b21b929fe527b907e58464896b774c489
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
base/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp
base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h
base/dali-toolkit/internal/controls/scrollable/scroll-connector-impl.cpp
base/dali-toolkit/internal/controls/scrollable/scroll-connector-impl.h
base/dali-toolkit/public-api/controls/scrollable/scroll-connector.cpp
capi/dali-toolkit/public-api/controls/scrollable/scroll-connector.h

index 2a4db69634a006f892dec03dec87dabae17f22c1..6298e7dbb96b61233f726c7481f7efcf5a865989 100755 (executable)
@@ -284,7 +284,7 @@ void ScrollBar::SetPositionNotifications( const std::vector<float>& positions )
 void ScrollBar::OnScrollPositionNotified(PropertyNotification& source)
 {
   // Emit the signal to notify the scroll position crossing
-  mScrollPositionNotifiedSignal.Emit(mScrollPositionObject.GetProperty<float>( Toolkit::ScrollConnector::SCROLL_POSITION ));
+  mScrollPositionNotifiedSignal.Emit(mScrollConnector.GetScrollPosition());
 }
 
 void ScrollBar::Show()
@@ -318,13 +318,9 @@ void ScrollBar::Hide()
 bool ScrollBar::OnPanGestureProcessTick()
 {
   // Update the scroll position property.
-  mScrollPositionObject.SetProperty( Toolkit::ScrollConnector::SCROLL_POSITION, mCurrentScrollPosition );
-
-  Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(Self().GetParent());
-  if(itemView)
+  if( mScrollConnector )
   {
-    // Refresh ItemView immediately when the scroll position is changed.
-    GetImpl(itemView).DoRefresh(mCurrentScrollPosition, false); // No need to cache extra items.
+    mScrollConnector.SetScrollPosition(mCurrentScrollPosition);
   }
 
   return true;
@@ -332,8 +328,10 @@ bool ScrollBar::OnPanGestureProcessTick()
 
 void ScrollBar::OnPan( PanGesture gesture )
 {
-  if(mScrollPositionObject)
+  if(mScrollConnector)
   {
+    Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(Self().GetParent());
+
     switch(gesture.state)
     {
       case Gesture::Started:
@@ -347,7 +345,7 @@ void ScrollBar::OnPan( PanGesture gesture )
         }
 
         Show();
-        mScrollStart = mScrollPositionObject.GetProperty<float>( Toolkit::ScrollConnector::SCROLL_POSITION );
+        mScrollStart = mScrollConnector.GetScrollPosition();
         mGestureDisplacement = Vector3::ZERO;
         mIsPanning = true;
 
@@ -377,11 +375,16 @@ void ScrollBar::OnPan( PanGesture gesture )
           mTimer.Reset();
         }
 
+        if(itemView)
+        {
+          // Refresh the ItemView cache with extra items
+          GetImpl(itemView).DoRefresh(mCurrentScrollPosition, true);
+        }
+
         break;
       }
     }
 
-    Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(Self().GetParent());
     if(itemView)
     {
       // Disable automatic refresh in ItemView during fast scrolling
index 14bd8fced39d3b0b2d564b46161a75a7b431a87f..fdb1d88e0fd7654106f8ba7a1cf40805d9c7b149 100644 (file)
@@ -433,6 +433,7 @@ void ItemView::OnInitialize()
 
   mScrollConnector = Dali::Toolkit::ScrollConnector::New();
   mScrollPositionObject = mScrollConnector.GetScrollPositionObject();
+  mScrollConnector.ScrollPositionChangedSignal().Connect( this, &ItemView::OnScrollPositionChanged );
 
   mPropertyMinimumLayoutPosition = self.RegisterProperty(MINIMUM_LAYOUT_POSITION_PROPERTY_NAME, 0.0f);
   mPropertyPosition = self.RegisterProperty(POSITION_PROPERTY_NAME, 0.0f);
@@ -502,7 +503,7 @@ ItemLayoutPtr ItemView::GetActiveLayout() const
 
 float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
 {
-  return mScrollPositionObject.GetProperty<float>( ScrollConnector::SCROLL_POSITION ) + static_cast<float>( itemId );
+  return mScrollConnector.GetScrollPosition() + static_cast<float>( itemId );
 }
 
 void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds)
@@ -1836,6 +1837,15 @@ void ItemView::GetItemsRange(ItemRange& range)
   range.end = mItemPool.rbegin()->first + 1;
 }
 
+void ItemView::OnScrollPositionChanged( float position )
+{
+  // Cancel scroll animation to prevent any fighting of setting the scroll position property.
+  RemoveAnimation(mScrollAnimation);
+
+  // Refresh the cache immediately when the scroll position is changed.
+  DoRefresh(position, false); // No need to cache extra items.
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 1f33626811b40009ae0ba35031751e325b3ac3c2..442d760c6253100fd76b7811f08929fcd064ea03 100644 (file)
@@ -548,6 +548,12 @@ private:
    */
   void OnRefreshNotification(PropertyNotification& source);
 
+  /**
+   * This is called when scroll position has been changed by ScrollConnector::SetScrollPosition.
+   * @param[in] position The new scroll position
+   */
+  void OnScrollPositionChanged( float position );
+
 private:
 
   ItemFactory& mItemFactory;
index 659e67bdb73fa97b6ab69ddb493aeb5379a67dd0..a84a41989c541bb37dcf8aceee63be9860b2a320 100644 (file)
@@ -47,6 +47,12 @@ void ScrollConnector::SetScrollDomain( float min, float max, float length )
   mDomainChangedSignal.Emit( mMinLimit, mMaxLimit, mContentLength );
 }
 
+void ScrollConnector::SetScrollPosition( float position )
+{
+  mScrollPositionObject.SetProperty( Toolkit::ScrollConnector::SCROLL_POSITION, position );
+  mScrollPositionChangedSignal.Emit( position );
+}
+
 ScrollConnector::ScrollConnector()
 : mMinLimit( 0.0f ),
   mMaxLimit( 0.0f ),
index 45616f4395d49aa00d494010ade5b4249eb7ef7a..e9d8679c2eaf41bd79d760c11f03fb89cb1d8a46 100644 (file)
@@ -38,6 +38,7 @@ class ScrollConnector : public Dali::BaseObject
 public:
 
   typedef Toolkit::ScrollConnector::DomainChangedSignalType DomainChangedSignalType;
+  typedef Toolkit::ScrollConnector::ScrollPositionChangedSignalType ScrollPositionChangedSignalType;
 
   static const Property::Index SCROLL_POSITION;
   static const Property::Index OVERSHOOT;
@@ -77,6 +78,27 @@ public:
     return mContentLength;
   }
 
+  /**
+   * @copydoc Toolkit::ScrollConnector::SetScrollPosition()
+   */
+  void SetScrollPosition( float position );
+
+  /**
+   * @copydoc Toolkit::ScrollConnector::GetScrollPosition()
+   */
+  float GetScrollPosition() const
+  {
+    return mScrollPositionObject.GetProperty<float>( Toolkit::ScrollConnector::SCROLL_POSITION );
+  }
+
+  /**
+   * Signal emitted after the SetScrollPosition() method has been called.
+   */
+  ScrollPositionChangedSignalType& ScrollPositionChangedSignal()
+  {
+    return mScrollPositionChangedSignal;
+  }
+
   /**
    * Signal emitted after the SetScrollDomain() method has been called.
    */
@@ -117,6 +139,7 @@ private:
   Constrainable mScrollPositionObject;
 
   DomainChangedSignalType mDomainChangedSignal;
+  ScrollPositionChangedSignalType mScrollPositionChangedSignal;
 
   float mMinLimit;
   float mMaxLimit;
index 8827738b231da02ad0ed6a12a96ade5a1f23bdef..c89dfab6d82a83f2292fb33beb404b3cf370551f 100644 (file)
@@ -33,6 +33,7 @@ const Property::Index ScrollConnector::SCROLL_POSITION = Internal::ScrollConnect
 const Property::Index ScrollConnector::OVERSHOOT       = Internal::ScrollConnector::OVERSHOOT;
 
 const char* const ScrollConnector::DOMAIN_CHANGED_SIGNAL_NAME    = "domain-changed";
+const char* const ScrollConnector::SCROLL_POSITION_CHANGED_SIGNAL_NAME    = "scroll-position-changed";
 
 ScrollConnector ScrollConnector::New()
 {
@@ -82,6 +83,21 @@ Constrainable ScrollConnector::GetScrollPositionObject() const
   return GetImpl(*this).GetScrollPositionObject();
 }
 
+void ScrollConnector::SetScrollPosition( float position )
+{
+  GetImpl(*this).SetScrollPosition( position );
+}
+
+float ScrollConnector::GetScrollPosition() const
+{
+  return GetImpl(*this).GetScrollPosition();
+}
+
+ScrollConnector::ScrollPositionChangedSignalType& ScrollConnector::ScrollPositionChangedSignal()
+{
+  return GetImpl(*this).ScrollPositionChangedSignal();
+}
+
 ScrollConnector::DomainChangedSignalType& ScrollConnector::DomainChangedSignal()
 {
   return GetImpl(*this).DomainChangedSignal();
index 6960b4b1f52d4cc52656e100be57616a34186704..1e64e7e9438c7af70e46a6f5dff425a504741ad5 100644 (file)
@@ -70,6 +70,9 @@ public:
   static const char* const DOMAIN_CHANGED_SIGNAL_NAME;    ///< "domain-changed" signal name
   typedef SignalV2< void ( float min, float max, float size ) > DomainChangedSignalType;
 
+  static const char* const SCROLL_POSITION_CHANGED_SIGNAL_NAME;    ///< "scroll-position-changed" signal name
+  typedef SignalV2< void ( float position ) > ScrollPositionChangedSignalType;
+
   /**
    * Create a ScrollConnector.
    * @return A handle to a newly allocated ScrollConnector.
@@ -100,13 +103,13 @@ public:
   ~ScrollConnector();
 
   /**
-   * Downcast a BaseHandle to ScrollConnector handle.
+   * @brief Downcast a BaseHandle to ScrollConnector handle.
    * @return A handle to a ScrollConnector or an empty handle.
    */
   static ScrollConnector DownCast( BaseHandle handle );
 
   /**
-   * Set the scroll domain, corresponding to the start & end position, and size of the scrollable content in actor coordinates.
+   * @brief Set the scroll domain, corresponding to the start & end position, and size of the scrollable content in actor coordinates.
    * @param[in] min The minimum scroll position limit.
    * @param[in] max The maximum scroll position limit.
    * @param[in] length The length of the scrollable content in actor coordinates.
@@ -114,30 +117,50 @@ public:
   void SetScrollDomain( float min, float max, float length );
 
   /**
-   * Retrieve the min limit.
+   * @brief Retrieve the min limit.
    * @return The minimum value.
    */
   float GetMinLimit() const;
 
   /**
-   * Retrieve the max limit.
+   * @brief Retrieve the max limit.
    * @return The maximum value.
    */
   float GetMaxLimit() const;
 
   /**
-   * Retrieve the length of the scrollable content in actor coordinates.
+   * @brief Retrieve the length of the scrollable content in actor coordinates.
    * @return The length of the scrollable content.
    */
   float GetContentLength() const;
 
   /**
-   * Signal emitted after the SetScrollDomain() method has been called.
+   * @brief Set the scroll position.
+   *
+   * This will set the "scroll-position" property and emit the ScrollPositionChanged signal.
+   *
+   * @param[in] position The scroll position.
+   */
+  void SetScrollPosition( float position );
+
+  /**
+   * @brief Retrieve the scroll position.
+   * @return The scroll position.
+   */
+  float GetScrollPosition() const;
+
+  /**
+   * @brief Signal emitted after the SetScrollPosition() method has been called.
+   */
+  ScrollConnector::ScrollPositionChangedSignalType& ScrollPositionChangedSignal();
+
+  /**
+   * @brief Signal emitted after the SetScrollDomain() method has been called.
    */
   ScrollConnector::DomainChangedSignalType& DomainChangedSignal();
 
   /**
-   * Retrieve the object which provides the "scroll-position" property.
+   * @brief Retrieve the object which provides the "scroll-position" property.
    * @return The scroll-position object.
    */
   Constrainable GetScrollPositionObject() const;