Merge "Make cursor invisible when exceeds the boundaries of the Text Control." into...
authorPaul Wisbey <p.wisbey@samsung.com>
Thu, 23 Apr 2015 13:33:39 +0000 (06:33 -0700)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Thu, 23 Apr 2015 13:33:39 +0000 (06:33 -0700)
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/decorator/text-decorator.h
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp

index 6ae1821..32e3bec 100644 (file)
@@ -200,7 +200,9 @@ struct Decorator::Impl : public ConnectionTracker
     mActiveGrabHandle( false ),
     mActiveSelection( false ),
     mActiveCopyPastePopup( false ),
-    mCursorBlinkStatus( true )
+    mCursorBlinkStatus( true ),
+    mPrimaryCursorVisible( false ),
+    mSecondaryCursorVisible( false )
   {
   }
 
@@ -217,26 +219,42 @@ struct Decorator::Impl : public ConnectionTracker
     CreateCursors();
     if( mPrimaryCursor )
     {
-      mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].position.x,
-                                  mCursor[PRIMARY_CURSOR].position.y );
-      mPrimaryCursor.SetSize( Size( 1.0f, mCursor[PRIMARY_CURSOR].cursorHeight ) );
+      mPrimaryCursorVisible = ( mCursor[PRIMARY_CURSOR].position.x <= size.width ) && ( mCursor[PRIMARY_CURSOR].position.x >= 0.f );
+      if( mPrimaryCursorVisible )
+      {
+        mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].position.x,
+                                    mCursor[PRIMARY_CURSOR].position.y );
+        mPrimaryCursor.SetSize( Size( 1.0f, mCursor[PRIMARY_CURSOR].cursorHeight ) );
+      }
+      mPrimaryCursor.SetVisible( mPrimaryCursorVisible );
     }
     if( mSecondaryCursor )
     {
-      mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].position.x,
-                                    mCursor[SECONDARY_CURSOR].position.y );
-      mSecondaryCursor.SetSize( Size( 1.0f, mCursor[SECONDARY_CURSOR].cursorHeight ) );
+      mSecondaryCursorVisible = ( mCursor[SECONDARY_CURSOR].position.x <= size.width ) && ( mCursor[SECONDARY_CURSOR].position.x >= 0.f );
+      if( mSecondaryCursorVisible )
+      {
+        mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].position.x,
+                                      mCursor[SECONDARY_CURSOR].position.y );
+        mSecondaryCursor.SetSize( Size( 1.0f, mCursor[SECONDARY_CURSOR].cursorHeight ) );
+      }
+      mSecondaryCursor.SetVisible( mSecondaryCursorVisible );
     }
 
     // Show or hide the grab handle
     if( mActiveGrabHandle )
     {
-      SetupTouchEvents();
+      const bool isVisible = ( mCursor[PRIMARY_CURSOR].position.x <= size.width ) && ( mCursor[PRIMARY_CURSOR].position.x >= 0.f );
+
+      if( isVisible )
+      {
+        SetupTouchEvents();
 
-      CreateGrabHandle();
+        CreateGrabHandle();
 
-      mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].position.x,
-                               mCursor[PRIMARY_CURSOR].position.y + mCursor[PRIMARY_CURSOR].lineHeight );
+        mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].position.x,
+                                 mCursor[PRIMARY_CURSOR].position.y + mCursor[PRIMARY_CURSOR].lineHeight );
+      }
+      mGrabHandle.SetVisible( isVisible );
     }
     else if( mGrabHandle )
     {
@@ -371,11 +389,11 @@ struct Decorator::Impl : public ConnectionTracker
     // Cursor blinking
     if ( mPrimaryCursor )
     {
-      mPrimaryCursor.SetVisible( mCursorBlinkStatus );
+      mPrimaryCursor.SetVisible( mPrimaryCursorVisible && mCursorBlinkStatus );
     }
     if ( mSecondaryCursor )
     {
-      mSecondaryCursor.SetVisible( mCursorBlinkStatus );
+      mSecondaryCursor.SetVisible( mSecondaryCursorVisible && mCursorBlinkStatus );
     }
 
     mCursorBlinkStatus = !mCursorBlinkStatus;
@@ -826,10 +844,12 @@ struct Decorator::Impl : public ConnectionTracker
   float               mGrabDisplacementX;
   float               mGrabDisplacementY;
 
-  bool                mActiveGrabHandle:1;
-  bool                mActiveSelection:1;
-  bool                mActiveCopyPastePopup:1;
-  bool                mCursorBlinkStatus:1;       ///< Flag to switch between blink on and blink off
+  bool                mActiveGrabHandle       : 1;
+  bool                mActiveSelection        : 1;
+  bool                mActiveCopyPastePopup   : 1;
+  bool                mCursorBlinkStatus      : 1; ///< Flag to switch between blink on and blink off.
+  bool                mPrimaryCursorVisible   : 1; ///< Whether the primary cursor is visible.
+  bool                mSecondaryCursorVisible : 1; ///< Whether the secondary cursor is visible.
 };
 
 DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
@@ -872,8 +892,11 @@ unsigned int Decorator::GetActiveCursor() const
 void Decorator::SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight )
 {
   // Adjust grab handle displacement
-  mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].position.x;
-  mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].position.y;
+  if( PRIMARY_CURSOR == cursor )
+  {
+    mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].position.x;
+    mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].position.y;
+  }
 
   mImpl->mCursor[cursor].position.x = x;
   mImpl->mCursor[cursor].position.y = y;
@@ -889,6 +912,11 @@ void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& cursorHei
   lineHeight = mImpl->mCursor[cursor].lineHeight;
 }
 
+const Vector2& Decorator::GetPosition( Cursor cursor ) const
+{
+  return mImpl->mCursor[cursor].position;
+}
+
 void Decorator::SetColor( Cursor cursor, const Dali::Vector4& color )
 {
   mImpl->mCursor[cursor].color = color;
index a5f329a..14e1212 100644 (file)
@@ -215,6 +215,15 @@ public:
   void GetPosition( Cursor cursor, float& x, float& y, float& cursorHeight, float& lineHeight ) const;
 
   /**
+   * @brief Retrieves the position of a cursor.
+   *
+   * @param[in] cursor The cursor to get.
+   *
+   * @return The position.
+   */
+  const Vector2& GetPosition( Cursor cursor ) const;
+
+  /**
    * @brief Sets the color for a cursor.
    *
    * @param[in] cursor Whether this color is for the primary or secondary cursor.
index 07e647c..1b68f13 100644 (file)
@@ -109,7 +109,8 @@ EventData::EventData( DecoratorPtr decorator )
   mSelectionEnabled( true ),
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
-  mUpdateCursorPosition( false )
+  mUpdateCursorPosition( false ),
+  mScrollAfterUpdateCursorPosition( false )
 {}
 
 EventData::~EventData()
@@ -170,7 +171,16 @@ bool Controller::Impl::ProcessInputEvents()
   // The cursor must also be repositioned after inserts into the model
   if( mEventData->mUpdateCursorPosition )
   {
+    // Updates the cursor position and scrolls the text to make it visible.
+
     UpdateCursorPosition();
+
+    if( mEventData->mScrollAfterUpdateCursorPosition )
+    {
+      ScrollToMakeCursorVisible();
+      mEventData->mScrollAfterUpdateCursorPosition = false;
+    }
+
     mEventData->mUpdateCursorPosition = false;
   }
 
@@ -230,7 +240,8 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
     // TODO
   }
 
-  UpdateCursorPosition();
+  mEventData->mUpdateCursorPosition = true;
+  mEventData->mScrollAfterUpdateCursorPosition = true;
 }
 
 void Controller::Impl::HandleCursorKey( int keyCode )
@@ -263,7 +274,8 @@ void Controller::Impl::OnTapEvent( const Event& event )
     mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
                                                                 yPosition );
 
-    UpdateCursorPosition();
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mScrollAfterUpdateCursorPosition = true;
   }
   else if( mEventData->mSelectionEnabled &&
            ( 2u == tapCount ) )
@@ -295,19 +307,7 @@ void Controller::Impl::OnPanEvent( const Event& event )
       const float displacementX = event.p2.mFloat;
       mEventData->mScrollPosition.x += displacementX;
 
-      // Clamp between -space & 0 (and the text alignment).
-      if( actualSize.width > mControlSize.width )
-      {
-        const float space = ( actualSize.width - mControlSize.width ) + mAlignmentOffset.x;
-        mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
-        mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
-
-        mEventData->mDecoratorUpdated = true;
-      }
-      else
-      {
-        mEventData->mScrollPosition.x = 0.f;
-      }
+      ClampHorizontalScroll( actualSize );
     }
 
     if( mEventData->mVerticalScrollingEnabled )
@@ -315,19 +315,7 @@ void Controller::Impl::OnPanEvent( const Event& event )
       const float displacementY = event.p3.mFloat;
       mEventData->mScrollPosition.y += displacementY;
 
-      // Clamp between -space & 0 (and the text alignment).
-      if( actualSize.height > mControlSize.height )
-      {
-        const float space = ( actualSize.height - mControlSize.height ) + mAlignmentOffset.y;
-        mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
-        mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
-
-        mEventData->mDecoratorUpdated = true;
-      }
-      else
-      {
-        mEventData->mScrollPosition.y = 0.f;
-      }
+      ClampVerticalScroll( actualSize );
     }
 
     if( mEventData->mDecorator )
@@ -353,18 +341,23 @@ void Controller::Impl::OnGrabHandleEvent( const Event& event )
     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 );
-
-    UpdateCursorPosition();
-
     //mDecorator->HidePopup();
     ChangeState ( EventData::EDITING );
+
+    const CharacterIndex newCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+
+    if( newCursorPosition != mEventData->mPrimaryCursorPosition )
+    {
+      mEventData->mPrimaryCursorPosition = newCursorPosition;
+      mEventData->mUpdateCursorPosition = true;
+    }
   }
   else if( mEventData->mGrabHandlePopupEnabled &&
            ( GRAB_HANDLE_RELEASED == state ) )
   {
     //mDecorator->ShowPopup();
     ChangeState ( EventData::EDITING_WITH_POPUP );
+    mEventData->mUpdateCursorPosition = true;
     mEventData->mDecoratorUpdated = true;
   }
 }
@@ -851,6 +844,73 @@ void Controller::Impl::UpdateCursorPosition()
   mEventData->mDecoratorUpdated = true;
 }
 
+void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
+{
+  // Clamp between -space & 0 (and the text alignment).
+  if( actualSize.width > mControlSize.width )
+  {
+    const float space = ( actualSize.width - mControlSize.width ) + mAlignmentOffset.x;
+    mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
+    mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
+
+    mEventData->mDecoratorUpdated = true;
+  }
+  else
+  {
+    mEventData->mScrollPosition.x = 0.f;
+  }
+}
+
+void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
+{
+  // Clamp between -space & 0 (and the text alignment).
+  if( actualSize.height > mControlSize.height )
+  {
+    const float space = ( actualSize.height - mControlSize.height ) + mAlignmentOffset.y;
+    mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
+    mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
+
+    mEventData->mDecoratorUpdated = true;
+  }
+  else
+  {
+    mEventData->mScrollPosition.y = 0.f;
+  }
+}
+
+void Controller::Impl::ScrollToMakeCursorVisible()
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+  Vector2 offset;
+  bool updateDecorator = false;
+  if( primaryCursorPosition.x < 0.f )
+  {
+    offset.x = -primaryCursorPosition.x;
+    mEventData->mScrollPosition.x += offset.x;
+    updateDecorator = true;
+  }
+  else if( primaryCursorPosition.x > mControlSize.width )
+  {
+    offset.x = mControlSize.width - primaryCursorPosition.x;
+    mEventData->mScrollPosition.x += offset.x;
+    updateDecorator = true;
+  }
+
+  if( updateDecorator && mEventData->mDecorator )
+  {
+    mEventData->mDecorator->UpdatePositions( offset );
+  }
+
+  // TODO : calculate the Y scroll.
+}
+
 void Controller::Impl::RequestRelayout()
 {
   mControlInterface.RequestTextRelayout();
index 06e9463..34ea828 100644 (file)
@@ -105,34 +105,35 @@ struct EventData
 
   ~EventData();
 
-  DecoratorPtr mDecorator;
-  std::string  mPlaceholderText;
+  DecoratorPtr       mDecorator;               ///< Pointer to the decorator
+  std::string        mPlaceholderText;         ///< The plaxe holder text
 
   /**
    * This is used to delay handling events until after the model has been updated.
    * The number of updates to the model is minimized to improve performance.
    */
-  std::vector<Event> mEventQueue; ///< The queue of touch events etc.
+  std::vector<Event> mEventQueue;              ///< The queue of touch events etc.
 
   /**
    * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control.
    * Typically this will have a negative value with scrolling occurs.
    */
-  Vector2 mScrollPosition; ///< The text is offset by this position when scrolling.
-
-  State mState; ///< Selection mode, edit mode etc.
-
-  CharacterIndex mPrimaryCursorPosition;   ///< Index into logical model for primary cursor
-  CharacterIndex mSecondaryCursorPosition; ///< Index into logical model for secondary cursor
-
-  bool mDecoratorUpdated           : 1; ///< True if the decorator was updated during event processing
-  bool mCursorBlinkEnabled         : 1; ///< True if cursor should blink when active
-  bool mGrabHandleEnabled          : 1; ///< True if grab handle is enabled
-  bool mGrabHandlePopupEnabled     : 1; ///< True if the grab handle popu-up should be shown
-  bool mSelectionEnabled           : 1; ///< True if selection handles, highlight etc. are enabled
-  bool mHorizontalScrollingEnabled : 1; ///< True if horizontal scrolling is enabled
-  bool mVerticalScrollingEnabled   : 1; ///< True if vertical scrolling is enabled
-  bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
+  Vector2            mScrollPosition;          ///< The text is offset by this position when scrolling.
+
+  State              mState;                   ///< Selection mode, edit mode etc.
+
+  CharacterIndex     mPrimaryCursorPosition;   ///< Index into logical model for primary cursor.
+  CharacterIndex     mSecondaryCursorPosition; ///< Index into logical model for secondary cursor.
+
+  bool mDecoratorUpdated                : 1;   ///< True if the decorator was updated during event processing.
+  bool mCursorBlinkEnabled              : 1;   ///< True if cursor should blink when active.
+  bool mGrabHandleEnabled               : 1;   ///< True if grab handle is enabled.
+  bool mGrabHandlePopupEnabled          : 1;   ///< True if the grab handle popu-up should be shown.
+  bool mSelectionEnabled                : 1;   ///< True if selection handles, highlight etc. are enabled.
+  bool mHorizontalScrollingEnabled      : 1;   ///< True if horizontal scrolling is enabled.
+  bool mVerticalScrollingEnabled        : 1;   ///< True if vertical scrolling is enabled.
+  bool mUpdateCursorPosition            : 1;   ///< True if the visual position of the cursor must be recalculated.
+  bool mScrollAfterUpdateCursorPosition : 1;   ///< Whether to scroll after the cursor position is updated.
 };
 
 struct ModifyEvent
@@ -274,8 +275,36 @@ struct Controller::Impl
    */
   CharacterIndex CalculateNewCursorIndex( CharacterIndex index ) const;
 
+  /**
+   * @brief Updates the cursor position.
+   *
+   * Retrieves the x,y position of the cursor logical position and sets it into the decorator.
+   * It sets the position of the secondary cursor if it's a valid one.
+   * Sets which cursors are active.
+   */
   void UpdateCursorPosition();
 
+  /**
+   * @biref Clamps the horizontal scrolling to get the control always filled with text.
+   *
+   * @param[in] actualSize The size of the laid out text.
+   */
+  void ClampHorizontalScroll( const Vector2& actualSize );
+
+  /**
+   * @biref Clamps the vertical scrolling to get the control always filled with text.
+   *
+   * @param[in] actualSize The size of the laid out text.
+   */
+  void ClampVerticalScroll( const Vector2& actualSize );
+
+  /**
+   * @brief Scrolls the text to make the cursor visible.
+   *
+   * This method is called after inserting, deleting or moving the cursor with the keypad.
+   */
+  void ScrollToMakeCursorVisible();
+
   ControlInterface& mControlInterface;     ///< Reference to the text controller.
   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
   VisualModelPtr  mVisualModel;            ///< Pointer to the visual model.
index 02486bf..abbc2e7 100644 (file)
@@ -626,6 +626,7 @@ void Controller::InsertTextEvent( const std::string& text )
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
   mImpl->mEventData->mUpdateCursorPosition = true;
+  mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
 }
 
 void Controller::DeleteTextEvent()
@@ -677,6 +678,7 @@ void Controller::DeleteTextEvent()
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
   mImpl->mEventData->mUpdateCursorPosition = true;
+  mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
 }
 
 void Controller::UpdateModel( OperationsMask operationsRequired )