X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Ftext-controller-impl.cpp;h=aad550c1514cfa390eba1a00c72ddd6b4a9106cc;hp=187c3f71cde9dcae80b004703733b58b9a7dd557;hb=6f990775daf7adf6170db59f0b99e00ae25fceed;hpb=aeef40d5dd70c7d878c7664986913ef2c6675a03 diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 187c3f7..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 @@ -145,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 ) { @@ -260,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; @@ -1461,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; @@ -1489,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 ) ); @@ -1520,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 = firstLine.alignmentOffset + position.x - glyph.xBearing + mScrollPosition.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, - mScrollPosition.y, - xPosition + static_cast( numberOfCharacters ) * glyphAdvance, - mScrollPosition.y + height ); + yPosition, + xPositionAdvance, + yPosition + selectionBoxInfo->lineHeight ); splitStartGlyph = false; continue; @@ -1546,23 +1675,143 @@ void Controller::Impl::RepositionSelectionHandles() const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex; - const float xPosition = firstLine.alignmentOffset + position.x - glyph.xBearing + mScrollPosition.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, - mScrollPosition.y, - xPosition + static_cast( interGlyphIndex ) * glyphAdvance, - mScrollPosition.y + height ); + yPosition, + xPositionAdvance, + yPosition + selectionBoxInfo->lineHeight ); splitEndGlyph = false; continue; } - const float xPosition = firstLine.alignmentOffset + position.x - glyph.xBearing + mScrollPosition.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, - mScrollPosition.y, - xPosition + glyph.advance, - mScrollPosition.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 );