X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Ftext-controller-impl.cpp;h=d09e1edb91d33002d8dd268560bb54d745282b1b;hb=df8aa451cddeafb67f08cce86b07206d07ca9bc3;hp=85f48ec7ee65404a3fbe1c1ca92598080d9fabd2;hpb=ee431c9e2b342243f9e0e2b6bafca7505d321457;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 85f48ec..d09e1ed 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,6 +83,8 @@ EventData::EventData( DecoratorPtr decorator ) mPreEditStartPosition( 0u ), mPreEditLength( 0u ), mCursorHookPositionX( 0.f ), + mDoubleTapAction( Controller::NoTextTap::NO_ACTION ), + mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ), mIsShowingPlaceholderText( false ), mPreEditFlag( false ), mDecoratorUpdated( false ), @@ -96,11 +98,13 @@ EventData::EventData( DecoratorPtr decorator ) mUpdateLeftSelectionPosition( false ), mUpdateRightSelectionPosition( false ), mIsLeftHandleSelected( false ), + mIsRightHandleSelected( false ), mUpdateHighlightBox( false ), mScrollAfterUpdatePosition( false ), mScrollAfterDelete( false ), mAllTextSelected( false ), - mUpdateInputStyle( false ) + mUpdateInputStyle( false ), + mPasswordInput( false ) { mImfManager = ImfManager::Get(); } @@ -225,10 +229,25 @@ bool Controller::Impl::ProcessInputEvents() if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) ) { - CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo; + if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected ) + { + CursorInfo& infoLeft = leftHandleInfo; + + const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset ); + ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight ); + + CursorInfo& infoRight = rightHandleInfo; + + const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset ); + ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight ); + } + else + { + CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo; - const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset ); - ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight ); + const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset ); + ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight ); + } } } @@ -259,6 +278,8 @@ bool Controller::Impl::ProcessInputEvents() mEventData->mUpdateLeftSelectionPosition = false; mEventData->mUpdateRightSelectionPosition = false; mEventData->mUpdateHighlightBox = false; + mEventData->mIsLeftHandleSelected = false; + mEventData->mIsRightHandleSelected = false; } mEventData->mScrollAfterUpdatePosition = false; @@ -767,8 +788,16 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired ) return false; } - Vector& utf32Characters = mModel->mLogicalModel->mText; + Vector& srcCharacters = mModel->mLogicalModel->mText; + Vector displayCharacters; + bool useHiddenText = false; + if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText) + { + mHiddenInput->Substitute( srcCharacters,displayCharacters ); + useHiddenText = true; + } + Vector& utf32Characters = useHiddenText ? displayCharacters : srcCharacters; const Length numberOfCharacters = utf32Characters.Count(); // Index to the first character of the first paragraph to be updated. @@ -1133,29 +1162,30 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event ) } const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex ); + const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex ); - if( lineIndex > 0u ) - { - // Retrieve the cursor position info. - CursorInfo cursorInfo; - GetCursorPosition( mEventData->mPrimaryCursorPosition, - cursorInfo ); + // Retrieve the cursor position info. + CursorInfo cursorInfo; + GetCursorPosition( mEventData->mPrimaryCursorPosition, + cursorInfo ); - // Get the line above. - const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + ( lineIndex - 1u ) ); + // Get the line above. + const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex ); - // Get the next hit 'y' point. - const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender ); + // Get the next hit 'y' point. + const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender ); - // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index. - mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel, - mModel->mLogicalModel, - mMetrics, - mEventData->mCursorHookPositionX, - hitPointY ); - } + // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index. + bool matchedCharacter = false; + mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel, + mModel->mLogicalModel, + mMetrics, + mEventData->mCursorHookPositionX, + hitPointY, + CharacterHitTest::TAP, + matchedCharacter ); } - else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) + else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) { // Get first the line index of the current cursor position index. CharacterIndex characterIndex = 0u; @@ -1181,11 +1211,14 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event ) const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender ); // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index. + bool matchedCharacter = false; mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, mEventData->mCursorHookPositionX, - hitPointY ); + hitPointY, + CharacterHitTest::TAP, + matchedCharacter ); } } @@ -1211,11 +1244,15 @@ void Controller::Impl::OnTapEvent( const Event& event ) // Keep the tap 'x' position. Used to move the cursor. mEventData->mCursorHookPositionX = xPosition; + // Whether to touch point hits on a glyph. + bool matchedCharacter = false; mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, xPosition, - yPosition ); + yPosition, + CharacterHitTest::TAP, + matchedCharacter ); // When the cursor position is changing, delay cursor blinking mEventData->mDecorator->DelayCursorBlink(); @@ -1237,6 +1274,20 @@ void Controller::Impl::OnTapEvent( const Event& event ) mEventData->mImfManager.NotifyCursorPosition(); } } + else if( 2u == tapCount ) + { + if( mEventData->mSelectionEnabled ) + { + // Convert from control's coords to text's coords. + const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x; + const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y; + + // Calculates the logical position from the x,y coords. + RepositionSelectionHandles( xPosition, + yPosition, + mEventData->mDoubleTapAction ); + } + } } } @@ -1307,12 +1358,26 @@ void Controller::Impl::OnLongPressEvent( const Event& event ) { DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" ); - if( EventData::EDITING == mEventData->mState ) + if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) ) { - ChangeState ( EventData::EDITING_WITH_POPUP ); + ChangeState( EventData::EDITING_WITH_POPUP ); mEventData->mDecoratorUpdated = true; mEventData->mUpdateInputStyle = true; } + else + { + if( mEventData->mSelectionEnabled ) + { + // Convert from control's coords to text's coords. + const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x; + const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y; + + // Calculates the logical position from the x,y coords. + RepositionSelectionHandles( xPosition, + yPosition, + mEventData->mLongPressAction ); + } + } } void Controller::Impl::OnHandleEvent( const Event& event ) @@ -1334,11 +1399,14 @@ void Controller::Impl::OnHandleEvent( const Event& event ) const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y; // Need to calculate the handle's new position. + bool matchedCharacter = false; const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, xPosition, - yPosition ); + yPosition, + CharacterHitTest::SCROLL, + matchedCharacter ); if( Event::GRAB_HANDLE_EVENT == event.type ) { @@ -1375,6 +1443,7 @@ void Controller::Impl::OnHandleEvent( const Event& event ) // Will define the order to scroll the text to match the handle position. mEventData->mIsLeftHandleSelected = true; + mEventData->mIsRightHandleSelected = false; } else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type ) { @@ -1395,6 +1464,7 @@ void Controller::Impl::OnHandleEvent( const Event& event ) // Will define the order to scroll the text to match the handle position. mEventData->mIsLeftHandleSelected = false; + mEventData->mIsRightHandleSelected = true; } } // end ( HANDLE_PRESSED == state ) else if( ( HANDLE_RELEASED == state ) || @@ -1407,11 +1477,14 @@ void Controller::Impl::OnHandleEvent( const Event& event ) const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x; const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y; + bool matchedCharacter = false; handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, xPosition, - yPosition ); + yPosition, + CharacterHitTest::SCROLL, + matchedCharacter ); } if( Event::GRAB_HANDLE_EVENT == event.type ) @@ -1523,11 +1596,14 @@ void Controller::Impl::OnHandleEvent( const Event& event ) // Get the new handle position. // The grab handle's position is in decorator's coords. Need to transforms to text's coords. + bool matchedCharacter = false; const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, position.x - mModel->mScrollPosition.x, - position.y - mModel->mScrollPosition.y ); + position.y - mModel->mScrollPosition.y, + CharacterHitTest::SCROLL, + matchedCharacter ); if( mEventData->mPrimaryCursorPosition != handlePosition ) { @@ -1564,11 +1640,14 @@ void Controller::Impl::OnHandleEvent( const Event& event ) // Get the new handle position. // The selection handle's position is in decorator's coords. Need to transform to text's coords. + bool matchedCharacter = false; const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, position.x - mModel->mScrollPosition.x, - position.y - mModel->mScrollPosition.y ); + position.y - mModel->mScrollPosition.y, + CharacterHitTest::SCROLL, + matchedCharacter ); if( leftSelectionHandleEvent ) { @@ -1621,7 +1700,8 @@ void Controller::Impl::OnSelectEvent( const Event& event ) // Calculates the logical position from the x,y coords. RepositionSelectionHandles( xPosition, - yPosition ); + yPosition, + Controller::NoTextTap::HIGHLIGHT ); } } @@ -1946,15 +2026,15 @@ void Controller::Impl::RepositionSelectionHandles() // Whether to retrieve the next line. if( index == lastGlyphOfLine ) { - // Retrieve the next line. - ++lineRun; - - // Get the last glyph of the new line. - lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u; - ++lineIndex; if( lineIndex < firstLineIndex + numberOfLines ) { + // Retrieve the next line. + ++lineRun; + + // Get the last glyph of the new line. + lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u; + // Keep the offset and height of the current selection box. const float currentLineOffset = selectionBoxInfo->lineOffset; const float currentLineHeight = selectionBoxInfo->lineHeight; @@ -2152,7 +2232,7 @@ void Controller::Impl::RepositionSelectionHandles() mEventData->mDecoratorUpdated = true; } -void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY ) +void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action ) { if( NULL == mEventData ) { @@ -2178,16 +2258,18 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY // Find which word was selected CharacterIndex selectionStart( 0 ); CharacterIndex selectionEnd( 0 ); - const bool indicesFound = FindSelectionIndices( mModel->mVisualModel, + CharacterIndex noTextHitIndex( 0 ); + const bool characterHit = FindSelectionIndices( mModel->mVisualModel, mModel->mLogicalModel, mMetrics, visualX, visualY, selectionStart, - selectionEnd ); + selectionEnd, + noTextHitIndex ); DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd ); - if( indicesFound ) + if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) ) { ChangeState( EventData::SELECTING ); @@ -2198,14 +2280,30 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY mEventData->mUpdateRightSelectionPosition = true; mEventData->mUpdateHighlightBox = true; + // It may happen an IMF commit event arrives before the selection event + // if the IMF manager is in pre-edit state. The commit event will set the + // mEventData->mUpdateCursorPosition flag to true. If it's not set back + // to false, the highlight box won't be updated. + mEventData->mUpdateCursorPosition = false; + mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ); } - else + else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action ) { // Nothing to select. i.e. a white space, out of bounds - ChangeState( EventData::EDITING ); + ChangeState( EventData::EDITING_WITH_POPUP ); + + mEventData->mPrimaryCursorPosition = noTextHitIndex; - mEventData->mPrimaryCursorPosition = selectionEnd; + mEventData->mUpdateCursorPosition = true; + mEventData->mUpdateGrabHandlePosition = true; + mEventData->mScrollAfterUpdatePosition = true; + mEventData->mUpdateInputStyle = true; + } + else if( Controller::NoTextTap::NO_ACTION == action ) + { + // Nothing to select. i.e. a white space, out of bounds + mEventData->mPrimaryCursorPosition = noTextHitIndex; mEventData->mUpdateCursorPosition = true; mEventData->mUpdateGrabHandlePosition = true; @@ -2556,7 +2654,7 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const Script script = mModel->mLogicalModel->GetScript( index ); if( HasLigatureMustBreak( script ) ) { - // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ... + // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ... numberOfCharacters = 1u; } } @@ -2668,13 +2766,13 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType, void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize ) { - // Clamp between -space & 0. + // Clamp between -space & -alignment offset. if( layoutSize.width > mModel->mVisualModel->mControlSize.width ) { - const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ); + const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset; mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x; - mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > 0.f ) ? 0.f : mModel->mScrollPosition.x; + mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x; mEventData->mDecoratorUpdated = true; }