X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Ftext-controller-impl.cpp;h=aad550c1514cfa390eba1a00c72ddd6b4a9106cc;hb=283c6129b00dfdbc1badbf809b4257784820bb30;hp=7938931613878724ff42bd46e55a877ca80b2115;hpb=ded447ca28a294ce011a4c1f25f481b1cc04eefd;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 7938931..aad550c 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -21,6 +21,7 @@ // EXTERNAL INCLUDES #include #include +#include // INTERNAL INCLUDES #include @@ -35,10 +36,25 @@ namespace { +/** + * @brief Struct used to calculate the selection box. + */ +struct SelectionBoxInfo +{ + float lineOffset; + float lineHeight; + float minX; + float maxX; +}; + #if defined(DEBUG_ENABLED) Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); #endif +const float MAX_FLOAT = std::numeric_limits::max(); +const float MIN_FLOAT = std::numeric_limits::min(); +const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction + } // namespace namespace Dali @@ -57,7 +73,6 @@ EventData::EventData( DecoratorPtr decorator ) mPlaceholderTextInactive(), mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), mEventQueue(), - mScrollPosition(), mState( INACTIVE ), mPrimaryCursorPosition( 0u ), mLeftSelectionPosition( 0u ), @@ -146,6 +161,13 @@ bool Controller::Impl::ProcessInputEvents() } } + if( mEventData->mUpdateCursorPosition || + mEventData->mUpdateLeftSelectionPosition || + mEventData->mUpdateRightSelectionPosition ) + { + NotifyImfManager(); + } + // The cursor must also be repositioned after inserts into the model if( mEventData->mUpdateCursorPosition ) { @@ -154,16 +176,19 @@ bool Controller::Impl::ProcessInputEvents() GetCursorPosition( mEventData->mPrimaryCursorPosition, cursorInfo ); - if( mEventData->mScrollAfterUpdatePosition ) + // Scroll first the text after delete ... + if( mEventData->mScrollAfterDelete ) { - ScrollToMakePositionVisible( cursorInfo.primaryPosition ); - mEventData->mScrollAfterUpdatePosition = false; + ScrollTextToMatchCursor( cursorInfo ); } - else if( mEventData->mScrollAfterDelete ) + + // ... then, text can be scrolled to make the cursor visible. + if( mEventData->mScrollAfterUpdatePosition ) { - ScrollTextToMatchCursor( cursorInfo ); - mEventData->mScrollAfterDelete = false; + ScrollToMakePositionVisible( cursorInfo.primaryPosition ); } + mEventData->mScrollAfterUpdatePosition = false; + mEventData->mScrollAfterDelete = false; UpdateCursorPosition( cursorInfo ); @@ -258,6 +283,80 @@ bool Controller::Impl::ProcessInputEvents() return decoratorUpdated; } +void Controller::Impl::NotifyImfManager() +{ + if( mEventData && mEventData->mImfManager ) + { + CharacterIndex cursorPosition = GetLogicalCursorPosition(); + + const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u ); + + // Update the cursor position by removing the initial white spaces. + if( cursorPosition < numberOfWhiteSpaces ) + { + cursorPosition = 0u; + } + else + { + cursorPosition -= numberOfWhiteSpaces; + } + + mEventData->mImfManager.SetCursorPosition( cursorPosition ); + mEventData->mImfManager.NotifyCursorPosition(); + } +} + +CharacterIndex Controller::Impl::GetLogicalCursorPosition() const +{ + CharacterIndex cursorPosition = 0u; + + if( mEventData ) + { + if( ( EventData::SELECTING == mEventData->mState ) || + ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) ) + { + cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition ); + } + else + { + cursorPosition = mEventData->mPrimaryCursorPosition; + } + } + + return cursorPosition; +} + +Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const +{ + Length numberOfWhiteSpaces = 0u; + + // Get the buffer to the text. + Character* utf32CharacterBuffer = mLogicalModel->mText.Begin(); + + const Length totalNumberOfCharacters = mLogicalModel->mText.Count(); + for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces ) + { + if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) ) + { + break; + } + } + + return numberOfWhiteSpaces; +} + +void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const +{ + // Get the total number of characters. + Length numberOfCharacters = mLogicalModel->mText.Count(); + + // Retrieve the text. + if( 0u != numberOfCharacters ) + { + Utf32ToUtf8( mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text ); + } +} + void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters ) { mTextUpdateInfo.mParagraphCharacterIndex = 0u; @@ -998,8 +1097,9 @@ void Controller::Impl::OnTapEvent( const Event& event ) { if( IsShowingRealText() ) { - const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x; - const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y; + // Convert from control's coords to text's coords. + const float xPosition = event.p2.mFloat - mScrollPosition.x; + const float yPosition = event.p3.mFloat - mScrollPosition.y; mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel, mLogicalModel, @@ -1039,16 +1139,16 @@ void Controller::Impl::OnPanEvent( const Event& event ) int state = event.p1.mInt; - if( Gesture::Started == state || - Gesture::Continuing == state ) + if( ( Gesture::Started == state ) || + ( Gesture::Continuing == state ) ) { const Vector2& actualSize = mVisualModel->GetLayoutSize(); - const Vector2 currentScroll = mEventData->mScrollPosition; + const Vector2 currentScroll = mScrollPosition; if( mEventData->mHorizontalScrollingEnabled ) { const float displacementX = event.p2.mFloat; - mEventData->mScrollPosition.x += displacementX; + mScrollPosition.x += displacementX; ClampHorizontalScroll( actualSize ); } @@ -1056,14 +1156,14 @@ void Controller::Impl::OnPanEvent( const Event& event ) if( mEventData->mVerticalScrollingEnabled ) { const float displacementY = event.p3.mFloat; - mEventData->mScrollPosition.y += displacementY; + mScrollPosition.y += displacementY; ClampVerticalScroll( actualSize ); } if( mEventData->mDecorator ) { - mEventData->mDecorator->UpdatePositions( mEventData->mScrollPosition - currentScroll ); + mEventData->mDecorator->UpdatePositions( mScrollPosition - currentScroll ); } } } @@ -1092,9 +1192,9 @@ void Controller::Impl::OnHandleEvent( const Event& event ) if( HANDLE_PRESSED == 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; + // Convert from decorator's coords to text's coords. + const float xPosition = event.p2.mFloat - mScrollPosition.x; + const float yPosition = event.p3.mFloat - mScrollPosition.y; const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mVisualModel, mLogicalModel, @@ -1143,9 +1243,9 @@ void Controller::Impl::OnHandleEvent( const Event& event ) CharacterIndex handlePosition = 0u; if( handleStopScrolling ) { - // 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; + // Convert from decorator's coords to text's coords. + const float xPosition = event.p2.mFloat - mScrollPosition.x; + const float yPosition = event.p3.mFloat - mScrollPosition.y; handlePosition = Text::GetClosestCursorIndex( mVisualModel, mLogicalModel, @@ -1206,14 +1306,14 @@ void Controller::Impl::OnHandleEvent( const Event& event ) { const float xSpeed = event.p2.mFloat; const Vector2& actualSize = mVisualModel->GetLayoutSize(); - const Vector2 currentScrollPosition = mEventData->mScrollPosition; + const Vector2 currentScrollPosition = mScrollPosition; - mEventData->mScrollPosition.x += xSpeed; + mScrollPosition.x += xSpeed; ClampHorizontalScroll( actualSize ); bool endOfScroll = false; - if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) ) + if( Vector2::ZERO == ( currentScrollPosition - mScrollPosition ) ) { // Notify the decorator there is no more text to scroll. // The decorator won't send more scroll events. @@ -1237,12 +1337,12 @@ void Controller::Impl::OnHandleEvent( const Event& event ) position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width; // Get the new handle position. - // The grab handle's position is in decorator coords. Need to transforms to text coords. + // The grab handle's position is in decorator's coords. Need to transforms to text's coords. const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel, mLogicalModel, mMetrics, - position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x, - position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y ); + position.x - mScrollPosition.x, + position.y - mScrollPosition.y ); mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition; mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition; @@ -1262,12 +1362,12 @@ void Controller::Impl::OnHandleEvent( const Event& event ) position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width; // Get the new handle position. - // The selection handle's position is in decorator coords. Need to transforms to text coords. + // The selection handle's position is in decorator's coords. Need to transform to text's coords. const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel, mLogicalModel, mMetrics, - position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x, - position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y ); + position.x - mScrollPosition.x, + position.y - mScrollPosition.y ); if( leftSelectionHandleEvent ) { @@ -1309,9 +1409,9 @@ void Controller::Impl::OnSelectEvent( const Event& event ) if( mEventData->mSelectionEnabled ) { - // 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; + // Convert from control's coords to text's coords. + const float xPosition = event.p2.mFloat - mScrollPosition.x; + const float yPosition = event.p3.mFloat - mScrollPosition.y; // Calculates the logical position from the x,y coords. RepositionSelectionHandles( xPosition, @@ -1319,6 +1419,7 @@ void Controller::Impl::OnSelectEvent( const Event& event ) mEventData->mUpdateLeftSelectionPosition = true; mEventData->mUpdateRightSelectionPosition = true; + mEventData->mUpdateCursorPosition = false; mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ); } @@ -1387,12 +1488,7 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete // Scroll after delete. mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition; - mEventData->mScrollAfterDelete = true; } - // Udpade the cursor position and the decorator. - // Scroll after the position is updated if is not scrolling after delete. - mEventData->mUpdateCursorPosition = true; - mEventData->mScrollAfterUpdatePosition = !mEventData->mScrollAfterDelete; mEventData->mDecoratorUpdated = true; } } @@ -1462,16 +1558,10 @@ void Controller::Impl::RepositionSelectionHandles() const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL; // TODO: Better algorithm to create the highlight box. - // TODO: Multi-line. - - // Get the height of the line. - const Vector& lines = mVisualModel->mLines; - const LineRun& firstLine = *lines.Begin(); - const float height = firstLine.ascender + -firstLine.descender; const bool isLastCharacter = selectionEnd >= mLogicalModel->mText.Count(); - const bool startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) ); - const bool endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) ); + const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) ); + const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) ); // Swap the indices if the start is greater than the end. const bool indicesSwapped = selectionStart > selectionEnd; @@ -1490,6 +1580,38 @@ void Controller::Impl::RepositionSelectionHandles() const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne ); const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u ); + // Get the lines where the glyphs are laid-out. + const LineRun* lineRun = mVisualModel->mLines.Begin(); + + LineIndex lineIndex = 0u; + Length numberOfLines = 0u; + mVisualModel->GetNumberOfLines( glyphStart, + 1u + glyphEnd - glyphStart, + lineIndex, + numberOfLines ); + const LineIndex firstLineIndex = lineIndex; + + // Create the structure to store some selection box info. + Vector selectionBoxLinesInfo; + selectionBoxLinesInfo.Resize( numberOfLines ); + + SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin(); + selectionBoxInfo->minX = MAX_FLOAT; + selectionBoxInfo->maxX = MIN_FLOAT; + + // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph. + + // The line's vertical offset of all the lines before the line where the first glyph is laid-out. + selectionBoxInfo->lineOffset = CalculateLineOffset( mVisualModel->mLines, + firstLineIndex ); + lineRun += firstLineIndex; + + // The line height is the addition of the line ascender and the line descender. + // However, the line descender has a negative value, hence the subtraction. + selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender; + + GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u; + // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code. const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart ); bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionStart ) ); @@ -1498,8 +1620,6 @@ void Controller::Impl::RepositionSelectionHandles() const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd ); bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionEndMinusOne ) ); - const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset; - // Traverse the glyphs. for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index ) { @@ -1523,12 +1643,18 @@ void Controller::Impl::RepositionSelectionHandles() // Calculate the number of characters selected. const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex ); - const float xPosition = position.x - glyph.xBearing + offset.x + glyphAdvance * static_cast( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex ); + const float xPosition = lineRun->alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x + glyphAdvance * static_cast( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex ); + const float xPositionAdvance = xPosition + static_cast( numberOfCharacters ) * glyphAdvance; + const float yPosition = selectionBoxInfo->lineOffset + mScrollPosition.y; + + // Store the min and max 'x' for each line. + selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, xPosition ); + selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, xPositionAdvance ); mEventData->mDecorator->AddHighlight( xPosition, - offset.y, - xPosition + static_cast( numberOfCharacters ) * glyphAdvance, - offset.y + height ); + yPosition, + xPositionAdvance, + yPosition + selectionBoxInfo->lineHeight ); splitStartGlyph = false; continue; @@ -1549,23 +1675,143 @@ void Controller::Impl::RepositionSelectionHandles() const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex; - const float xPosition = position.x - glyph.xBearing + offset.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast( numberOfCharacters ) ) : 0.f ); + const float xPosition = lineRun->alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast( numberOfCharacters ) ) : 0.f ); + const float xPositionAdvance = xPosition + static_cast( interGlyphIndex ) * glyphAdvance; + const float yPosition = selectionBoxInfo->lineOffset + mScrollPosition.y; + + // Store the min and max 'x' for each line. + selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, xPosition ); + selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, xPositionAdvance ); + mEventData->mDecorator->AddHighlight( xPosition, - offset.y, - xPosition + static_cast( interGlyphIndex ) * glyphAdvance, - offset.y + height ); + yPosition, + xPositionAdvance, + yPosition + selectionBoxInfo->lineHeight ); splitEndGlyph = false; continue; } - const float xPosition = position.x - glyph.xBearing + offset.x; + const float xPosition = lineRun->alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x; + const float xPositionAdvance = xPosition + glyph.advance; + const float yPosition = selectionBoxInfo->lineOffset + mScrollPosition.y; + + // Store the min and max 'x' for each line. + selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, xPosition ); + selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, xPositionAdvance ); + mEventData->mDecorator->AddHighlight( xPosition, - offset.y, - xPosition + glyph.advance, - offset.y + height ); + yPosition, + xPositionAdvance, + yPosition + selectionBoxInfo->lineHeight ); + + // 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 ) + { + // Get the selection box info for the next line. + const float currentLineOffset = selectionBoxInfo->lineOffset; + ++selectionBoxInfo; + + selectionBoxInfo->minX = MAX_FLOAT; + selectionBoxInfo->maxX = MIN_FLOAT; + + // The line height is the addition of the line ascender and the line descender. + // However, the line descender has a negative value, hence the subtraction. + selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender; + + // Update the line's vertical offset. + selectionBoxInfo->lineOffset = currentLineOffset + selectionBoxInfo->lineHeight; + } + } + } + + // Add extra geometry to 'boxify' the selection. + + if( 1u < numberOfLines ) + { + // Boxify the first line. + lineRun = mVisualModel->mLines.Begin() + firstLineIndex; + const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() ); + + bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection ); + bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection ); + + if( boxifyBegin ) + { + // Boxify at the beginning of the line. + mEventData->mDecorator->AddHighlight( 0.f, + firstSelectionBoxLineInfo.lineOffset, + firstSelectionBoxLineInfo.minX, + firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight ); + } + + if( boxifyEnd ) + { + // Boxify at the end of the line. + mEventData->mDecorator->AddHighlight( firstSelectionBoxLineInfo.maxX, + firstSelectionBoxLineInfo.lineOffset, + mVisualModel->mControlSize.width, + firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight ); + } + + // Boxify the central lines. + if( 2u < numberOfLines ) + { + for( Vector::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u, + endIt = selectionBoxLinesInfo.End() - 1u; + it != endIt; + ++it ) + { + const SelectionBoxInfo& info = *it; + + mEventData->mDecorator->AddHighlight( 0.f, + info.lineOffset, + info.minX, + info.lineOffset + info.lineHeight ); + + mEventData->mDecorator->AddHighlight( info.maxX, + info.lineOffset, + mVisualModel->mControlSize.width, + info.lineOffset + info.lineHeight ); + } + } + + // Boxify the last line. + lineRun = mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u; + const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u ); + + boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection ); + boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection ); + + if( boxifyBegin ) + { + // Boxify at the beginning of the line. + mEventData->mDecorator->AddHighlight( 0.f, + lastSelectionBoxLineInfo.lineOffset, + lastSelectionBoxLineInfo.minX, + lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight ); + } + + if( boxifyEnd ) + { + // Boxify at the end of the line. + mEventData->mDecorator->AddHighlight( lastSelectionBoxLineInfo.maxX, + lastSelectionBoxLineInfo.lineOffset, + mVisualModel->mControlSize.width, + lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight ); + } } + CursorInfo primaryCursorInfo; GetCursorPosition( mEventData->mLeftSelectionPosition, primaryCursorInfo ); @@ -1574,17 +1820,17 @@ void Controller::Impl::RepositionSelectionHandles() GetCursorPosition( mEventData->mRightSelectionPosition, secondaryCursorInfo ); - const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + offset; - const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + offset; + const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mScrollPosition; + const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mScrollPosition; mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE, primaryPosition.x, - primaryCursorInfo.lineOffset + offset.y, + primaryCursorInfo.lineOffset + mScrollPosition.y, primaryCursorInfo.lineHeight ); mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryPosition.x, - secondaryCursorInfo.lineOffset + offset.y, + secondaryCursorInfo.lineOffset + mScrollPosition.y, secondaryCursorInfo.lineHeight ); // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection @@ -1894,25 +2140,6 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical, } } - switch( mLayoutEngine.GetVerticalAlignment() ) - { - case LayoutEngine::VERTICAL_ALIGN_TOP: - { - cursorInfo.primaryPosition.y = 0.f; - break; - } - case LayoutEngine::VERTICAL_ALIGN_CENTER: - { - cursorInfo.primaryPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - cursorInfo.lineHeight ) ); - break; - } - case LayoutEngine::VERTICAL_ALIGN_BOTTOM: - { - cursorInfo.primaryPosition.y = mVisualModel->mControlSize.height - cursorInfo.lineHeight; - break; - } - } - // Nothing else to do. return; } @@ -1999,8 +2226,7 @@ void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo ) return; } - const Vector2 offset = mEventData->mScrollPosition + ( IsShowingRealText() ? mAlignmentOffset : Vector2::ZERO ); - const Vector2 cursorPosition = cursorInfo.primaryPosition + offset; + const Vector2 cursorPosition = cursorInfo.primaryPosition + mScrollPosition; // Sets the cursor position. mEventData->mDecorator->SetPosition( PRIMARY_CURSOR, @@ -2013,17 +2239,17 @@ void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo ) // Sets the grab handle position. mEventData->mDecorator->SetPosition( GRAB_HANDLE, cursorPosition.x, - cursorInfo.lineOffset + offset.y, + cursorInfo.lineOffset + mScrollPosition.y, cursorInfo.lineHeight ); if( cursorInfo.isSecondaryCursor ) { mEventData->mDecorator->SetPosition( SECONDARY_CURSOR, - cursorInfo.secondaryPosition.x + offset.x, - cursorInfo.secondaryPosition.y + offset.y, + cursorInfo.secondaryPosition.x + mScrollPosition.x, + cursorInfo.secondaryPosition.y + mScrollPosition.y, cursorInfo.secondaryCursorHeight, cursorInfo.lineHeight ); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mScrollPosition.x, cursorInfo.secondaryPosition.y + mScrollPosition.y ); } // Set which cursors are active according the state. @@ -2055,13 +2281,12 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType, return; } - const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset; - const Vector2 cursorPosition = cursorInfo.primaryPosition + offset; + const Vector2 cursorPosition = cursorInfo.primaryPosition + mScrollPosition; // Sets the handle's position. mEventData->mDecorator->SetPosition( handleType, cursorPosition.x, - cursorInfo.lineOffset + offset.y, + cursorInfo.lineOffset + mScrollPosition.y, cursorInfo.lineHeight ); // If selection handle at start of the text and other at end of the text then all text is selected. @@ -2072,57 +2297,57 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType, void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize ) { - // Clamp between -space & 0 (and the text alignment). + // Clamp between -space & 0. if( actualSize.width > mVisualModel->mControlSize.width ) { - const float space = ( actualSize.width - mVisualModel->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; + const float space = ( actualSize.width - mVisualModel->mControlSize.width ); + mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x; + mScrollPosition.x = ( mScrollPosition.x > 0.f ) ? 0.f : mScrollPosition.x; mEventData->mDecoratorUpdated = true; } else { - mEventData->mScrollPosition.x = 0.f; + mScrollPosition.x = 0.f; } } void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize ) { - // Clamp between -space & 0 (and the text alignment). + // Clamp between -space & 0. if( actualSize.height > mVisualModel->mControlSize.height ) { - const float space = ( actualSize.height - mVisualModel->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; + const float space = ( actualSize.height - mVisualModel->mControlSize.height ); + mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y; + mScrollPosition.y = ( mScrollPosition.y > 0.f ) ? 0.f : mScrollPosition.y; mEventData->mDecoratorUpdated = true; } else { - mEventData->mScrollPosition.y = 0.f; + mScrollPosition.y = 0.f; } } void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position ) { + const float cursorWidth = mEventData->mDecorator ? mEventData->mDecorator->GetCursorWidth() : 0.f; + // position is in actor's coords. - const float positionEnd = position.x + ( mEventData->mDecorator ? mEventData->mDecorator->GetCursorWidth() : 0.f ); + const float positionEnd = position.x + cursorWidth; // Transform the position to decorator coords. - const float alignment = IsShowingRealText() ? mAlignmentOffset.x : 0.f; - const float offset = mEventData->mScrollPosition.x + alignment; - const float decoratorPositionBegin = position.x + offset; - const float decoratorPositionEnd = positionEnd + offset; + const float decoratorPositionBegin = position.x + mScrollPosition.x; + const float decoratorPositionEnd = positionEnd + mScrollPosition.x; if( decoratorPositionBegin < 0.f ) { - mEventData->mScrollPosition.x = -position.x - alignment; + mScrollPosition.x = -position.x; } else if( decoratorPositionEnd > mVisualModel->mControlSize.width ) { - mEventData->mScrollPosition.x = mVisualModel->mControlSize.width - positionEnd - alignment; + mScrollPosition.x = mVisualModel->mControlSize.width - positionEnd; } } @@ -2132,9 +2357,12 @@ void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo ) const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR ); // Calculate the offset to match the cursor position before the character was deleted. - mEventData->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x - mAlignmentOffset.x; + mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x; ClampHorizontalScroll( mVisualModel->GetLayoutSize() ); + + // Makes the new cursor position visible if needed. + ScrollToMakePositionVisible( cursorInfo.primaryPosition ); } void Controller::Impl::RequestRelayout()