From: Agnelo Vaz Date: Tue, 10 Nov 2015 17:31:20 +0000 (+0000) Subject: TextSelection Popup to be aware of requirement to Paste and whitespace selectable X-Git-Tag: dali_1.1.11~10 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=2039784e7811f5f68ffdfb13c6aa1bc39f2ab950;hp=76dead7c21ac57622ca1a70c156efddc017059cf TextSelection Popup to be aware of requirement to Paste and whitespace selectable * This shows the [PASTE][CLIPBOARD] buttons when a tap occurs in edit mode (if something to paste) * To see [select][select all] longpress or double tap text * Whitespace can be selected by double tap or longpress * TextAtlasRenderer returns a renderable actor even when all text is whitespace Change-Id: I1ac5cd1f76e554b1c9d59ef8b8f64fe741aa6855 Signed-off-by: Agnelo Vaz --- diff --git a/dali-toolkit/internal/text/decorator/text-decorator.cpp b/dali-toolkit/internal/text/decorator/text-decorator.cpp index 5d3976c..757eb4e 100644 --- a/dali-toolkit/internal/text/decorator/text-decorator.cpp +++ b/dali-toolkit/internal/text/decorator/text-decorator.cpp @@ -435,6 +435,7 @@ struct Decorator::Impl : public ConnectionTracker if( mActiveCopyPastePopup ) { ShowPopup(); + mPopupSetNewPosition = true; } else { @@ -1872,7 +1873,7 @@ const Vector4& Decorator::GetHandleColor() const void Decorator::SetPosition( HandleType handleType, float x, float y, float height ) { - // Adjust grab handle displacement + // Adjust handle's displacement Impl::HandleImpl& handle = mImpl->mHandle[handleType]; handle.grabDisplacementX -= x - handle.position.x; diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp index 5592589..4cb19ed 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -720,6 +720,13 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth ) positions, glyphs, depth ); + + /* In the case where AddGlyphs does not create a renderable Actor for example when glyphs are all whitespace create a new Actor. */ + /* This renderable actor is used to position the text, other "decorations" can rely on there always being an Actor regardless of it is whitespace or regular text*/ + if ( !mImpl->mActor ) + { + mImpl->mActor = Actor::New(); + } } return mImpl->mActor; diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index b262e99..ccd64db 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -485,7 +485,7 @@ void Controller::Impl::GetDefaultFonts( Vector& fonts, Length numberOfC { if( mFontDefaults ) { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::GetDefaultFonts font family(%s)\n", mFontDefaults->mFontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::GetDefaultFonts font family(%s)\n", mFontDefaults->mFontDescription.family.c_str() ); FontRun fontRun; fontRun.characterRun.characterIndex = 0; fontRun.characterRun.numberOfCharacters = numberOfCharacters; @@ -630,6 +630,8 @@ void Controller::Impl::OnPanEvent( const Event& event ) void Controller::Impl::OnLongPressEvent( const Event& event ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" ); + if ( EventData::EDITING == mEventData->mState ) { ChangeState ( EventData::EDITING_WITH_POPUP ); @@ -708,7 +710,10 @@ void Controller::Impl::OnHandleEvent( const Event& event ) { mEventData->mUpdateCursorPosition = true; - ChangeState( EventData::EDITING_WITH_POPUP ); + if ( !IsClipboardEmpty() ) + { + ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup + } if( handleStopScrolling ) { @@ -865,6 +870,8 @@ void Controller::Impl::OnSelectEvent( const Event& event ) void Controller::Impl::OnSelectAllEvent() { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false"); + if( NULL == mEventData ) { // Nothing to do if there is no text. @@ -1179,7 +1186,7 @@ void Controller::Impl::SetPopupButtons() buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) ); } } - else if ( EventData::EDITING_WITH_POPUP == mEventData->mState ) + else if ( EventData::EDITING_WITH_POPUP == mEventData->mState ) { if ( mLogicalModel->mText.Count() && !IsShowingPlaceholderText()) { @@ -1192,6 +1199,14 @@ void Controller::Impl::SetPopupButtons() buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) ); } } + else if ( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState ) + { + if ( !IsClipboardEmpty() ) + { + buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) ); + buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) ); + } + } mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow ); } @@ -1204,6 +1219,8 @@ void Controller::Impl::ChangeState( EventData::State newState ) return; } + DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d newstate:%d\n", mEventData->mState, newState ); + if( mEventData->mState != newState ) { mEventData->mState = newState; @@ -1262,6 +1279,8 @@ void Controller::Impl::ChangeState( EventData::State newState ) } else if( EventData::EDITING_WITH_POPUP == mEventData->mState ) { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState ); + mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY ); if( mEventData->mCursorBlinkEnabled ) { @@ -1286,6 +1305,8 @@ void Controller::Impl::ChangeState( EventData::State newState ) } else if( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState ) { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState ); + mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY ); if( mEventData->mCursorBlinkEnabled ) { @@ -1317,6 +1338,8 @@ void Controller::Impl::ChangeState( EventData::State newState ) } else if ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState ); + mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY ); if( mEventData->mCursorBlinkEnabled ) { @@ -1331,6 +1354,28 @@ void Controller::Impl::ChangeState( EventData::State newState ) } mEventData->mDecoratorUpdated = true; } + else if ( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState ) + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState ); + + mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY ); + if( mEventData->mCursorBlinkEnabled ) + { + mEventData->mDecorator->StartCursorBlink(); + } + + mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true ); + mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false ); + mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false ); + + if( mEventData->mGrabHandlePopupEnabled ) + { + SetPopupButtons(); + mEventData->mDecorator->SetPopupActive( true ); + } + HideClipboard(); + mEventData->mDecoratorUpdated = true; + } } } @@ -1386,26 +1431,22 @@ void Controller::Impl::FindSelectionIndices( float visualX, float visualY, Chara startIndex = hitCharacter; endIndex = hitCharacter; + bool isHitCharacterWhitespace = TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] ); - if( !TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] ) ) + // Find the start and end of the text + for( startIndex = hitCharacter; startIndex > 0; --startIndex ) { - // Find the start and end of the text - for( startIndex = hitCharacter; startIndex > 0; --startIndex ) + if( isHitCharacterWhitespace != TextAbstraction::IsWhiteSpace( mLogicalModel->mText[ startIndex-1 ] ) ) { - Character charCode = mLogicalModel->mText[ startIndex-1 ]; - if( TextAbstraction::IsWhiteSpace( charCode ) ) - { - break; - } + break; } - const CharacterIndex pastTheEnd = mLogicalModel->mText.Count(); - for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex ) + } + const CharacterIndex pastTheEnd = mLogicalModel->mText.Count(); + for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex ) + { + if( isHitCharacterWhitespace != TextAbstraction::IsWhiteSpace( mLogicalModel->mText[ endIndex ] ) ) { - Character charCode = mLogicalModel->mText[ endIndex ]; - if( TextAbstraction::IsWhiteSpace( charCode ) ) - { - break; - } + break; } } } @@ -1858,10 +1899,7 @@ void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo ) } // Set which cursors are active according the state. - if( ( EventData::EDITING == mEventData->mState ) || - ( EventData::EDITING_WITH_POPUP == mEventData->mState ) || - ( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState ) || - ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) ) + if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) ) { if( cursorInfo.isSecondaryCursor ) { @@ -1891,7 +1929,7 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType, const Vector2 cursorPosition = cursorInfo.primaryPosition + mEventData->mScrollPosition + mAlignmentOffset; - // Sets the grab handle position. + // Sets the handle's position. mEventData->mDecorator->SetPosition( handleType, cursorPosition.x, cursorPosition.y, diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h index 2e2c240..0f5149d 100644 --- a/dali-toolkit/internal/text/text-controller-impl.h +++ b/dali-toolkit/internal/text/text-controller-impl.h @@ -107,6 +107,7 @@ struct EventData EDITING, EDITING_WITH_POPUP, EDITING_WITH_GRAB_HANDLE, + EDITING_WITH_PASTE_POPUP, GRAB_HANDLE_PANNING, SELECTION_HANDLE_PANNING }; @@ -115,6 +116,11 @@ struct EventData ~EventData(); + static bool IsEditingState( State stateToCheck ) + { + return ( stateToCheck == EDITING || stateToCheck == EDITING_WITH_POPUP || stateToCheck == EDITING_WITH_GRAB_HANDLE || stateToCheck == EDITING_WITH_PASTE_POPUP ); + } + DecoratorPtr mDecorator; ///< Pointer to the decorator. ImfManager mImfManager; ///< The Input Method Framework Manager. std::string mPlaceholderTextActive; ///< The text to display when the TextField is empty with key-input focus. @@ -506,6 +512,7 @@ struct Controller::Impl bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated. bool mUserDefinedFontFamily:1; ///< Whether the Font family was set by the user instead of being left as sytem default. + }; } // namespace Text diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index f7958ff..592bc12 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -90,7 +90,8 @@ void Controller::SetText( const std::string& text ) // If popup shown then hide it by switching to Editing state if( ( EventData::SELECTING == mImpl->mEventData->mState ) || ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ) + ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) || + ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) ) { mImpl->ChangeState( EventData::EDITING ); } @@ -843,9 +844,7 @@ void Controller::ResetCursorPosition( CharacterIndex cursorIndex ) mImpl->mEventData->mPrimaryCursorPosition = cursorIndex; // Update the cursor if it's in editing mode. - if( ( EventData::EDITING == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ) + if ( EventData::IsEditingState( mImpl->mEventData->mState ) ) { mImpl->mEventData->mUpdateCursorPosition = true; } @@ -898,9 +897,7 @@ void Controller::TextInsertedEvent() REORDER ); // Queue a cursor reposition event; this must wait until after DoRelayout() - if( ( EventData::EDITING == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ) + if ( EventData::IsEditingState( mImpl->mEventData->mState ) ) { mImpl->mEventData->mUpdateCursorPosition = true; mImpl->mEventData->mScrollAfterUpdatePosition = true; @@ -1505,33 +1502,48 @@ void Controller::TapEvent( unsigned int tapCount, float x, float y ) if( NULL != mImpl->mEventData ) { + DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState ); + if( 1u == tapCount ) { // This is to avoid unnecessary relayouts when tapping an empty text-field bool relayoutNeeded( false ); - if( mImpl->IsShowingRealText() && - EventData::EDITING == mImpl->mEventData->mState ) + if ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState || EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) + { + mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE); // If Popup shown hide it here so can be shown again if required. + } + + if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != mImpl->mEventData->mState ) ) { - // Show grab handle on second tap - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); + // Already in an active state so show a popup + if ( !mImpl->IsClipboardEmpty() ) + { + // Shows Paste popup but could show full popup with Selection options. ( EDITING_WITH_POPUP ) + mImpl->ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); + } + else + { + mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); + } relayoutNeeded = true; } - else if( EventData::EDITING != mImpl->mEventData->mState && - EventData::EDITING_WITH_GRAB_HANDLE != mImpl->mEventData->mState ) + else { if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() ) { // Hide placeholder text ResetText(); } - // Show cursor on first tap - mImpl->ChangeState( EventData::EDITING ); - relayoutNeeded = true; - } - else if( mImpl->IsShowingRealText() ) - { - // Move the cursor + + if ( EventData::INACTIVE == mImpl->mEventData->mState ) + { + mImpl->ChangeState( EventData::EDITING ); + } + else if ( !mImpl->IsClipboardEmpty() ) + { + mImpl->ChangeState( EventData::EDITING_WITH_POPUP ); + } relayoutNeeded = true; } @@ -1562,6 +1574,7 @@ void Controller::TapEvent( unsigned int tapCount, float x, float y ) } void Controller::PanEvent( Gesture::State state, const Vector2& displacement ) + // Show cursor and grabhandle on first tap, this matches the behaviour of tapping when already editing { DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" ); @@ -1619,6 +1632,8 @@ void Controller::LongPressEvent( Gesture::State state, float x, float y ) void Controller::SelectEvent( float x, float y, bool selectAll ) { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); + if( mImpl->mEventData ) { mImpl->ChangeState( EventData::SELECTING );