Cursor Scrolling. 03/38603/5
authorVictor Cebollada <v.cebollada@samsung.com>
Wed, 15 Apr 2015 12:56:53 +0000 (13:56 +0100)
committerVictor Cebollada <v.cebollada@samsung.com>
Thu, 23 Apr 2015 09:51:27 +0000 (10:51 +0100)
Change-Id: Ief97436d85ea16e4af852468785e40bdecb1a160
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/decorator/text-decorator.h
dali-toolkit/internal/text/text-controller-impl.cpp

index 32e3becd14020deb9c8b53dceee3550f510d3ba2..2098a5fa7fbf828c613434b61c114fec221b4ee7 100644 (file)
@@ -83,10 +83,14 @@ const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
 
 const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
 const float TO_MILLISECONDS = 1000.f;
-const float TO_SECONDS = 1.f / 1000.f;
+const float TO_SECONDS = 1.f / TO_MILLISECONDS;
 
 const float DISPLAYED_HIGHLIGHT_Z_OFFSET( -0.05f );
 
+const float SCROLL_THRESHOLD = 10.f;
+const float SCROLL_SPEED = 15.f;
+const unsigned int SCROLL_TICK_INTERVAL = 50u;
+
 /**
  * structure to hold coordinates of each quad, which will make up the mesh.
  */
@@ -151,6 +155,15 @@ namespace Text
 
 struct Decorator::Impl : public ConnectionTracker
 {
+  enum ScrollDirection
+  {
+    SCROLL_NONE,
+    SCROLL_RIGHT,
+    SCROLL_LEFT,
+    SCROLL_TOP,
+    SCROLL_BOTTOM
+  };
+
   struct CursorImpl
   {
     CursorImpl()
@@ -197,6 +210,10 @@ struct Decorator::Impl : public ConnectionTracker
     mCursorBlinkDuration( 0.0f ),
     mGrabDisplacementX( 0.0f ),
     mGrabDisplacementY( 0.0f ),
+    mScrollDirection( SCROLL_NONE ),
+    mScrollThreshold( SCROLL_THRESHOLD ),
+    mScrollSpeed( SCROLL_SPEED ),
+    mScrollInterval( SCROLL_TICK_INTERVAL ),
     mActiveGrabHandle( false ),
     mActiveSelection( false ),
     mActiveCopyPastePopup( false ),
@@ -690,12 +707,38 @@ struct Decorator::Impl : public ConnectionTracker
       if( Gesture::Started    == gesture.state ||
           Gesture::Continuing == gesture.state )
       {
-        mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y );
+        if( x < mScrollThreshold )
+        {
+          mScrollDirection = SCROLL_RIGHT;
+          mGrabDisplacementX -= x;
+          mCursor[PRIMARY_CURSOR].position.x = 0.f;
+          StartScrollTimer();
+        }
+        else if( x > mTextControlParent.GetControlSize().width - mScrollThreshold )
+        {
+          mScrollDirection = SCROLL_LEFT;
+          mGrabDisplacementX += ( mTextControlParent.GetControlSize().width - x );
+          mCursor[PRIMARY_CURSOR].position.x = mTextControlParent.GetControlSize().width;
+          StartScrollTimer();
+        }
+        else
+        {
+          StopScrollTimer();
+          mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y );
+        }
       }
       else if( Gesture::Finished  == gesture.state ||
                Gesture::Cancelled == gesture.state )
       {
-        mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y );
+        if( mScrollTimer && mScrollTimer.IsRunning() )
+        {
+          StopScrollTimer();
+          mObserver.GrabHandleEvent( GRAB_HANDLE_STOP_SCROLLING, x, y );
+        }
+        else
+        {
+          mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y );
+        }
       }
     }
   }
@@ -810,12 +853,86 @@ struct Decorator::Impl : public ConnectionTracker
     requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds;
   }
 
+  void SetScrollThreshold( float threshold )
+  {
+    mScrollThreshold = threshold;
+  }
+
+  float GetScrollThreshold() const
+  {
+    return mScrollThreshold;
+  }
+
+  void SetScrollSpeed( float speed )
+  {
+    mScrollSpeed = speed;
+  }
+
+  float GetScrollSpeed() const
+  {
+    return mScrollSpeed;
+  }
+
+  void SetScrollTickInterval( float seconds )
+  {
+    mScrollInterval = static_cast<unsigned int>( seconds * TO_MILLISECONDS );
+  }
+
+  float GetScrollTickInterval() const
+  {
+    return static_cast<float>( mScrollInterval ) * TO_SECONDS;
+  }
+
+  /**
+   * Creates and starts a timer to scroll the text when handles are close to the edges of the text.
+   *
+   * It only starts the timer if it's already created.
+   */
+  void StartScrollTimer()
+  {
+    if( !mScrollTimer )
+    {
+      mScrollTimer = Timer::New( mScrollInterval );
+      mScrollTimer.TickSignal().Connect( this, &Decorator::Impl::OnScrollTimerTick );
+    }
+
+    if( !mScrollTimer.IsRunning() )
+    {
+      mScrollTimer.Start();
+    }
+  }
+
+  /**
+   * Stops the timer used to scroll the text.
+   */
+  void StopScrollTimer()
+  {
+    if( mScrollTimer )
+    {
+      mScrollTimer.Stop();
+    }
+  }
+
+  /**
+   * Callback called by the timer used to scroll the text.
+   *
+   * It calculates and sets a new scroll position.
+   */
+  bool OnScrollTimerTick()
+  {
+    mObserver.GrabHandleEvent( GRAB_HANDLE_SCROLLING,
+                               mScrollDirection == SCROLL_RIGHT ? mScrollSpeed : -mScrollSpeed,
+                               0.f );
+    return true;
+  }
+
   Internal::Control&  mTextControlParent;
   Observer&           mObserver;
 
   TapGestureDetector  mTapDetector;
   PanGestureDetector  mPanGestureDetector;
   Timer               mCursorBlinkTimer;          ///< Timer to signal cursor to blink
+  Timer               mScrollTimer;               ///< Timer used to scroll the text when the grab handle is moved close to the edges.
 
   Layer               mActiveLayer;               ///< Layer for active handles and alike that ensures they are above all else.
   ImageActor          mPrimaryCursor;
@@ -843,6 +960,10 @@ struct Decorator::Impl : public ConnectionTracker
   float               mCursorBlinkDuration;
   float               mGrabDisplacementX;
   float               mGrabDisplacementY;
+  ScrollDirection     mScrollDirection;         ///< The direction of the scroll.
+  float               mScrollThreshold;         ///< Defines a square area inside the control, close to the edge. A cursor entering this area will trigger scroll events.
+  float               mScrollSpeed;             ///< Distance the text scrolls during a scroll interval.
+  unsigned int        mScrollInterval;          ///< Time in milliseconds of a scroll interval.
 
   bool                mActiveGrabHandle       : 1;
   bool                mActiveSelection        : 1;
@@ -1059,6 +1180,38 @@ bool Decorator::IsPopupActive() const
   return mImpl->mActiveCopyPastePopup ;
 }
 
+/** Scroll **/
+
+void Decorator::SetScrollThreshold( float threshold )
+{
+  mImpl->SetScrollThreshold( threshold );
+}
+
+float Decorator::GetScrollThreshold() const
+{
+  return mImpl->GetScrollThreshold();
+}
+
+void Decorator::SetScrollSpeed( float speed )
+{
+  mImpl->SetScrollSpeed( speed );
+}
+
+float Decorator::GetScrollSpeed() const
+{
+  return mImpl->GetScrollSpeed();
+}
+
+void Decorator::SetScrollTickInterval( float seconds )
+{
+  mImpl->SetScrollTickInterval( seconds );
+}
+
+float Decorator::GetScrollTickInterval() const
+{
+  return mImpl->GetScrollTickInterval();
+}
+
 Decorator::~Decorator()
 {
   delete mImpl;
index 14e121285e8918caea061ec332a4c13b8ec8c78e..588d224375b95f8b5899377ad010dfa69406f5f5 100644 (file)
@@ -66,7 +66,9 @@ enum GrabHandleState
 {
   GRAB_HANDLE_TAPPED,
   GRAB_HANDLE_PRESSED,
-  GRAB_HANDLE_RELEASED
+  GRAB_HANDLE_RELEASED,
+  GRAB_HANDLE_SCROLLING,
+  GRAB_HANDLE_STOP_SCROLLING
 };
 
 // The set the selection-handle positions etc.
@@ -386,6 +388,53 @@ public:
    */
   bool IsPopupActive() const;
 
+  /**
+   * @brief Sets the scroll threshold.
+   *
+   * It defines a square area inside the control, close to the edge.
+   * When the cursor enters this area, the decorator starts to send scroll events.
+   *
+   * @param[in] threshold The scroll threshold.
+   */
+  void SetScrollThreshold( float threshold );
+
+  /**
+   * @brief Retrieves the scroll threshold.
+   *
+   * @retunr The scroll threshold.
+   */
+  float GetScrollThreshold() const;
+
+  /**
+   * @brief Sets the scroll speed.
+   *
+   * Is the distance the text is going to be scrolled during a scroll interval.
+   *
+   * @param[in] speed The scroll speed.
+   */
+  void SetScrollSpeed( float speed );
+
+  /**
+   * @brief Retrieves the scroll speed.
+   *
+   * @return The scroll speed.
+   */
+  float GetScrollSpeed() const;
+
+  /**
+   * @brief Sets the scroll interval.
+   *
+   * @param[in] seconds The scroll interval in seconds.
+   */
+  void SetScrollTickInterval( float seconds );
+
+  /**
+   * @brief Retrieves the scroll interval.
+   *
+   * @return The scroll interval.
+   */
+  float GetScrollTickInterval() const;
+
 protected:
 
   /**
index 1b68f138e078f7dcd88c665981b1a85f2deec627..74d9abf3344a062d23c2bf1061b4a5cdf4e0d083 100644 (file)
@@ -353,12 +353,33 @@ void Controller::Impl::OnGrabHandleEvent( const Event& event )
     }
   }
   else if( mEventData->mGrabHandlePopupEnabled &&
-           ( GRAB_HANDLE_RELEASED == state ) )
+           ( ( GRAB_HANDLE_RELEASED == state ) ||
+             ( GRAB_HANDLE_STOP_SCROLLING == state ) ) )
   {
     //mDecorator->ShowPopup();
     ChangeState ( EventData::EDITING_WITH_POPUP );
     mEventData->mUpdateCursorPosition = true;
     mEventData->mDecoratorUpdated = true;
+
+    if( GRAB_HANDLE_STOP_SCROLLING == state )
+    {
+      // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+      const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
+      const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+
+      mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+
+      mEventData->mScrollAfterUpdateCursorPosition = true;
+    }
+  }
+  else if( GRAB_HANDLE_SCROLLING == state )
+  {
+    const float xSpeed = event.p2.mFloat;
+    const Vector2& actualSize = mVisualModel->GetActualSize();
+
+    mEventData->mScrollPosition.x += xSpeed;
+
+    ClampHorizontalScroll( actualSize );
   }
 }
 
@@ -908,7 +929,7 @@ void Controller::Impl::ScrollToMakeCursorVisible()
     mEventData->mDecorator->UpdatePositions( offset );
   }
 
-  // TODO : calculate the Y scroll.
+  // TODO : calculate the vertical scroll.
 }
 
 void Controller::Impl::RequestRelayout()