From: Victor Cebollada Date: Wed, 22 Apr 2015 08:02:23 +0000 (+0100) Subject: Make cursor invisible when exceeds the boundaries of the Text Control. X-Git-Tag: dali_1.0.40~10^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=6c8205c3864658abbd163f61e27e9a7609dd4cbb Make cursor invisible when exceeds the boundaries of the Text Control. Change-Id: I1a038bb45d6e7d5fca388aac6e1d1202a7874b9a Signed-off-by: Victor Cebollada --- diff --git a/dali-toolkit/internal/text/decorator/text-decorator.cpp b/dali-toolkit/internal/text/decorator/text-decorator.cpp index 6ae1821..32e3bec 100644 --- a/dali-toolkit/internal/text/decorator/text-decorator.cpp +++ b/dali-toolkit/internal/text/decorator/text-decorator.cpp @@ -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; diff --git a/dali-toolkit/internal/text/decorator/text-decorator.h b/dali-toolkit/internal/text/decorator/text-decorator.h index a5f329a..14e1212 100644 --- a/dali-toolkit/internal/text/decorator/text-decorator.h +++ b/dali-toolkit/internal/text/decorator/text-decorator.h @@ -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. diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 07e647c..1b68f13 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -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(); diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h index 06e9463..34ea828 100644 --- a/dali-toolkit/internal/text/text-controller-impl.h +++ b/dali-toolkit/internal/text/text-controller-impl.h @@ -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 mEventQueue; ///< The queue of touch events etc. + std::vector 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. diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 02486bf..abbc2e7 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -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 )