- if( mTextUpdateInfo.mClearAll ||
- ( ( 0u == startIndex ) &&
- ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
- {
- ClearFullModelData( operations );
- }
- else
- {
- // Clear the model data related with characters.
- ClearCharacterModelData( startIndex, endIndex, operations );
-
- // Clear the model data related with glyphs.
- ClearGlyphModelData( startIndex, endIndex, operations );
- }
-
- // The estimated number of lines. Used to avoid reallocations when layouting.
- mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
-
- mModel->mVisualModel->ClearCaches();
-}
-
-bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
-
- // Calculate the operations to be done.
- const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
-
- if( NO_OPERATION == operations )
- {
- // Nothing to do if no operations are pending and required.
- return false;
- }
-
- Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
- Vector<Character> displayCharacters;
- bool useHiddenText = false;
- if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
- {
- mHiddenInput->Substitute( srcCharacters,displayCharacters );
- useHiddenText = true;
- }
-
- Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
- const Length numberOfCharacters = utf32Characters.Count();
-
- // Index to the first character of the first paragraph to be updated.
- CharacterIndex startIndex = 0u;
- // Number of characters of the paragraphs to be removed.
- Length paragraphCharacters = 0u;
-
- CalculateTextUpdateIndices( paragraphCharacters );
-
- // Check whether the indices for updating the text is valid
- if ( numberOfCharacters > 0u &&
- ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
- mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
- {
- std::string currentText;
- Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
-
- DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
- DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
-
- // Dump mTextUpdateInfo
- DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
- DALI_LOG_ERROR( " mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
- DALI_LOG_ERROR( " mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
- DALI_LOG_ERROR( " mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
- DALI_LOG_ERROR( " mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
- DALI_LOG_ERROR( " mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
- DALI_LOG_ERROR( " mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
- DALI_LOG_ERROR( " mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
- DALI_LOG_ERROR( " mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
- DALI_LOG_ERROR( " mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
- DALI_LOG_ERROR( " mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
- DALI_LOG_ERROR( " mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
- DALI_LOG_ERROR( " mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
-
- return false;
- }
-
- startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
-
- if( mTextUpdateInfo.mClearAll ||
- ( 0u != paragraphCharacters ) )
- {
- ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
- }
-
- mTextUpdateInfo.mClearAll = false;
-
- // Whether the model is updated.
- bool updated = false;
-
- Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
- const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
-
- if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
- {
- // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
- // calculate the bidirectional info for each 'paragraph'.
- // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
- // is not shaped together).
- lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
-
- SetLineBreakInfo( utf32Characters,
- startIndex,
- requestedNumberOfCharacters,
- lineBreakInfo );
-
- // Create the paragraph info.
- mModel->mLogicalModel->CreateParagraphInfo( startIndex,
- requestedNumberOfCharacters );
- updated = true;
- }
-
- const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
- const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
-
- Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
- Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
-
- if( getScripts || validateFonts )
- {
- // Validates the fonts assigned by the application or assigns default ones.
- // It makes sure all the characters are going to be rendered by the correct font.
- MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-
- if( getScripts )
- {
- // Retrieves the scripts used in the text.
- multilanguageSupport.SetScripts( utf32Characters,
- startIndex,
- requestedNumberOfCharacters,
- scripts );
- }
-
- if( validateFonts )
- {
- // Validate the fonts set through the mark-up string.
- Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
-
- // Get the default font's description.
- TextAbstraction::FontDescription defaultFontDescription;
- TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
-
- if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
- {
- // If the placeholder font is set specifically, only placeholder font is changed.
- defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
- if( mEventData->mPlaceholderFont->sizeDefined )
- {
- defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
- }
- }
- else if( NULL != mFontDefaults )
- {
- // Set the normal font and the placeholder font.
- defaultFontDescription = mFontDefaults->mFontDescription;
-
- if( mTextFitEnabled )
- {
- defaultPointSize = mFontDefaults->mFitPointSize * 64u;
- }
- else
- {
- defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
- }
- }
-
- // Validates the fonts. If there is a character with no assigned font it sets a default one.
- // After this call, fonts are validated.
- multilanguageSupport.ValidateFonts( utf32Characters,
- scripts,
- fontDescriptionRuns,
- defaultFontDescription,
- defaultPointSize,
- startIndex,
- requestedNumberOfCharacters,
- validFonts );
- }
- updated = true;
- }
-
- Vector<Character> mirroredUtf32Characters;
- bool textMirrored = false;
- const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
- if( NO_OPERATION != ( BIDI_INFO & operations ) )
- {
- Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
- bidirectionalInfo.Reserve( numberOfParagraphs );
-
- // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
- SetBidirectionalInfo( utf32Characters,
- scripts,
- lineBreakInfo,
- startIndex,
- requestedNumberOfCharacters,
- bidirectionalInfo,
- mModel->mMatchSystemLanguageDirection,
- mLayoutDirection );
-
- if( 0u != bidirectionalInfo.Count() )
- {
- // Only set the character directions if there is right to left characters.
- Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
- GetCharactersDirection( bidirectionalInfo,
- numberOfCharacters,
- startIndex,
- requestedNumberOfCharacters,
- directions );
-
- // This paragraph has right to left text. Some characters may need to be mirrored.
- // TODO: consider if the mirrored string can be stored as well.
-
- textMirrored = GetMirroredText( utf32Characters,
- directions,
- bidirectionalInfo,
- startIndex,
- requestedNumberOfCharacters,
- mirroredUtf32Characters );
- }
- else
- {
- // There is no right to left characters. Clear the directions vector.
- mModel->mLogicalModel->mCharacterDirections.Clear();
- }
- updated = true;
- }
-
- Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
- Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
- Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
- Vector<GlyphIndex> newParagraphGlyphs;
- newParagraphGlyphs.Reserve( numberOfParagraphs );
-
- const Length currentNumberOfGlyphs = glyphs.Count();
- if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
- {
- const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
- // Shapes the text.
- ShapeText( textToShape,
- lineBreakInfo,
- scripts,
- validFonts,
- startIndex,
- mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- glyphs,
- glyphsToCharactersMap,
- charactersPerGlyph,
- newParagraphGlyphs );
-
- // Create the 'number of glyphs' per character and the glyph to character conversion tables.
- mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
- mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
- updated = true;
- }
-
- const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
-
- if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
- {
- GlyphInfo* glyphsBuffer = glyphs.Begin();
- mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
-
- // Update the width and advance of all new paragraph characters.
- for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
- {
- const GlyphIndex index = *it;
- GlyphInfo& glyph = *( glyphsBuffer + index );
-
- glyph.xBearing = 0.f;
- glyph.width = 0.f;
- glyph.advance = 0.f;
- }
- updated = true;
- }
-
- if( ( NULL != mEventData ) &&
- mEventData->mPreEditFlag &&
- ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
- {
- Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
- mEventData->mInputMethodContext.GetPreeditStyle( attrs );
- Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
-
- // Check the type of preedit and run it.
- for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
- {
- Dali::InputMethodContext::PreeditAttributeData attrData = *it;
- DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex );
- type = attrData.preeditType;
-
- // Check the number of commit characters for the start position.
- unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
- Length numberOfIndices = attrData.endIndex - attrData.startIndex;
-
- switch( type )
- {
- case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
- {
- // Add the underline for the pre-edit text.
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::REVERSE:
- {
- Vector4 textColor = mModel->mVisualModel->GetTextColor();
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = textColor;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
-
- Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
- Vector<ColorRun> colorRuns;
- colorRuns.Resize( 1u );
- ColorRun& colorRun = *( colorRuns.Begin() );
- colorRun.color = backgroundColor;
- colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- colorRun.characterRun.numberOfCharacters = numberOfIndices;
-
- mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
- {
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = LIGHT_BLUE;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
- {
- // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB4;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
- {
- // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB5;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
- {
- // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB6;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
- {
- // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB7;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::NONE:
- default:
- {
- break;
- }
- }
- }
- attrs.Clear();
- updated = true;
- }
-
- if( NO_OPERATION != ( COLOR & operations ) )
- {
- // Set the color runs in glyphs.
- SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
- mModel->mVisualModel->mCharactersToGlyph,
- mModel->mVisualModel->mGlyphsPerCharacter,
- startIndex,
- mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- mModel->mVisualModel->mColors,
- mModel->mVisualModel->mColorIndices );
-
- // Set the background color runs in glyphs.
- SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
- mModel->mVisualModel->mCharactersToGlyph,
- mModel->mVisualModel->mGlyphsPerCharacter,
- startIndex,
- mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- mModel->mVisualModel->mBackgroundColors,
- mModel->mVisualModel->mBackgroundColorIndices );
-
- updated = true;
- }
-
-
- // The estimated number of lines. Used to avoid reallocations when layouting.
- mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
-
- // Set the previous number of characters for the next time the text is updated.
- mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
-
- return updated;
-}
-
-void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
-{
- // Sets the default text's color.
- inputStyle.textColor = mTextColor;
- inputStyle.isDefaultColor = true;
-
- inputStyle.familyName.clear();
- inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
- inputStyle.width = TextAbstraction::FontWidth::NORMAL;
- inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
- inputStyle.size = 0.f;
-
- inputStyle.lineSpacing = 0.f;
-
- inputStyle.underlineProperties.clear();
- inputStyle.shadowProperties.clear();
- inputStyle.embossProperties.clear();
- inputStyle.outlineProperties.clear();
-
- inputStyle.isFamilyDefined = false;
- inputStyle.isWeightDefined = false;
- inputStyle.isWidthDefined = false;
- inputStyle.isSlantDefined = false;
- inputStyle.isSizeDefined = false;
-
- inputStyle.isLineSpacingDefined = false;
-
- inputStyle.isUnderlineDefined = false;
- inputStyle.isShadowDefined = false;
- inputStyle.isEmbossDefined = false;
- inputStyle.isOutlineDefined = false;
-
- // Sets the default font's family name, weight, width, slant and size.
- if( mFontDefaults )
- {
- if( mFontDefaults->familyDefined )
- {
- inputStyle.familyName = mFontDefaults->mFontDescription.family;
- inputStyle.isFamilyDefined = true;
- }
-
- if( mFontDefaults->weightDefined )
- {
- inputStyle.weight = mFontDefaults->mFontDescription.weight;
- inputStyle.isWeightDefined = true;
- }
-
- if( mFontDefaults->widthDefined )
- {
- inputStyle.width = mFontDefaults->mFontDescription.width;
- inputStyle.isWidthDefined = true;
- }
-
- if( mFontDefaults->slantDefined )
- {
- inputStyle.slant = mFontDefaults->mFontDescription.slant;
- inputStyle.isSlantDefined = true;
- }
-
- if( mFontDefaults->sizeDefined )
- {
- inputStyle.size = mFontDefaults->mDefaultPointSize;
- inputStyle.isSizeDefined = true;
- }
- }
-}
-
-float Controller::Impl::GetDefaultFontLineHeight()
-{
- FontId defaultFontId = 0u;
- if( NULL == mFontDefaults )
- {
- TextAbstraction::FontDescription fontDescription;
- defaultFontId = mFontClient.GetFontId( fontDescription );
- }
- else
- {
- defaultFontId = mFontDefaults->GetFontId( mFontClient );
- }
-
- Text::FontMetrics fontMetrics;
- mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
-
- return( fontMetrics.ascender - fontMetrics.descender );
-}
-
-void Controller::Impl::OnCursorKeyEvent( const Event& event )
-{
- if( NULL == mEventData || !IsShowingRealText() )
- {
- // Nothing to do if there is no text input.
- return;
- }
-
- int keyCode = event.p1.mInt;
- bool isShiftModifier = event.p2.mBool;
-
- CharacterIndex previousPrimaryCursorPosition = mEventData->mPrimaryCursorPosition;
-
- if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
- {
- if( mEventData->mPrimaryCursorPosition > 0u )
- {
- if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
- {
- mEventData->mPrimaryCursorPosition = std::min(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
- }
- else
- {
- mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
- }
- }
- }
- else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
- {
- if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
- {
- if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
- {
- mEventData->mPrimaryCursorPosition = std::max(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
- }
- else
- {
- mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
- }
- }
- }
- else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
- {
- // Ignore Shift-Up for text selection for now.
-
- // Get first the line index of the current cursor position index.
- CharacterIndex characterIndex = 0u;
-
- if( mEventData->mPrimaryCursorPosition > 0u )
- {
- characterIndex = mEventData->mPrimaryCursorPosition - 1u;
- }
-
- const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
- const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
-
- // Retrieve the cursor position info.
- CursorInfo cursorInfo;
- GetCursorPosition( mEventData->mPrimaryCursorPosition,
- cursorInfo );
-
- // 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 );
-
- // 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 && !isShiftModifier )
- {
- // Ignore Shift-Down for text selection for now.
-
- // Get first the line index of the current cursor position index.
- CharacterIndex characterIndex = 0u;
-
- if( mEventData->mPrimaryCursorPosition > 0u )
- {
- characterIndex = mEventData->mPrimaryCursorPosition - 1u;
- }
-
- const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
-
- if( lineIndex + 1u < mModel->mVisualModel->mLines.Count() )
- {
- // Retrieve the cursor position info.
- CursorInfo cursorInfo;
- GetCursorPosition( mEventData->mPrimaryCursorPosition,
- cursorInfo );
-
- // Get the line below.
- const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + lineIndex + 1u );
-
- // Get the next hit 'y' point.
- 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,
- CharacterHitTest::TAP,
- matchedCharacter );
- }
- }
-
- if ( !isShiftModifier && mEventData->mState != EventData::SELECTING )
- {
- // Update selection position after moving the cursor
- mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
- mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
- }
-
- if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
- {
- // Handle text selection
- bool selecting = false;
-
- if ( Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
- {
- // Shift-Left/Right to select the text
- int cursorPositionDelta = mEventData->mPrimaryCursorPosition - previousPrimaryCursorPosition;
- if ( cursorPositionDelta > 0 || mEventData->mRightSelectionPosition > 0u ) // Check the boundary
- {
- mEventData->mRightSelectionPosition += cursorPositionDelta;
- }
- selecting = true;
- }
- else if ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition )
- {
- // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
- selecting = true;
- }
-
- if ( selecting )
- {
- // Notify the cursor position to the InputMethodContext.
- if( mEventData->mInputMethodContext )
- {
- mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
- mEventData->mInputMethodContext.NotifyCursorPosition();
- }
-
- ChangeState( EventData::SELECTING );
-
- mEventData->mUpdateLeftSelectionPosition = true;
- mEventData->mUpdateRightSelectionPosition = true;
- mEventData->mUpdateGrabHandlePosition = true;
- mEventData->mUpdateHighlightBox = true;
-
- // Hide the text selection popup if select the text using keyboard instead of moving grab handles
- if( mEventData->mGrabHandlePopupEnabled )
- {
- mEventData->mDecorator->SetPopupActive( false );
- }
- }
- }
- else
- {
- // Handle normal cursor move
- ChangeState( EventData::EDITING );
- mEventData->mUpdateCursorPosition = true;
- }
-
- mEventData->mUpdateInputStyle = true;
- mEventData->mScrollAfterUpdatePosition = true;
-}
-
-void Controller::Impl::OnTapEvent( const Event& event )
-{
- if( NULL != mEventData )
- {
- const unsigned int tapCount = event.p1.mUint;
-
- if( 1u == tapCount )
- {
- if( IsShowingRealText() )
- {
- // 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;
-
- // 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,
- CharacterHitTest::TAP,
- matchedCharacter );
-
- // When the cursor position is changing, delay cursor blinking
- mEventData->mDecorator->DelayCursorBlink();
- }
- else
- {
- mEventData->mPrimaryCursorPosition = 0u;
- }
-
- // Update selection position after tapping
- mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
- mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
-
- mEventData->mUpdateCursorPosition = true;
- mEventData->mUpdateGrabHandlePosition = true;
- mEventData->mScrollAfterUpdatePosition = true;
- mEventData->mUpdateInputStyle = true;
-
- // Notify the cursor position to the InputMethodContext.
- if( mEventData->mInputMethodContext )
- {
- mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
- mEventData->mInputMethodContext.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 );
- }
- }
- }
-}
-
-void Controller::Impl::OnPanEvent( const Event& event )
-{
- if( NULL == mEventData )
- {
- // Nothing to do if there is no text input.
- return;
- }
-
- const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
- const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
-
- if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
- {
- // Nothing to do if scrolling is not enabled.
- return;
- }
-
- const GestureState state = static_cast<GestureState>( event.p1.mInt );
- switch( state )
- {
- case GestureState::STARTED:
- {
- // Will remove the cursor, handles or text's popup, ...
- ChangeState( EventData::TEXT_PANNING );
- break;
- }
- case GestureState::CONTINUING:
- {
- const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
- const Vector2 currentScroll = mModel->mScrollPosition;
-
- if( isHorizontalScrollEnabled )
- {
- const float displacementX = event.p2.mFloat;
- mModel->mScrollPosition.x += displacementX;
-
- ClampHorizontalScroll( layoutSize );
- }
-
- if( isVerticalScrollEnabled )
- {
- const float displacementY = event.p3.mFloat;
- mModel->mScrollPosition.y += displacementY;
-
- ClampVerticalScroll( layoutSize );
- }
-
- mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
- break;
- }
- case GestureState::FINISHED:
- case GestureState::CANCELLED: // FALLTHROUGH
- {
- // Will go back to the previous state to show the cursor, handles, the text's popup, ...
- ChangeState( mEventData->mPreviousState );
- break;
- }
- default:
- break;
- }
-}
-
-void Controller::Impl::OnLongPressEvent( const Event& event )
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
-
- if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
- {
- 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 )
-{
- if( NULL == mEventData )
- {
- // Nothing to do if there is no text input.
- return;
- }
-
- const unsigned int state = event.p1.mUint;
- const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
- const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
-
- if( HANDLE_PRESSED == state )
- {
- // Convert from decorator's coords to text's coords.
- const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
- 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,
- CharacterHitTest::SCROLL,
- matchedCharacter );
-
- if( Event::GRAB_HANDLE_EVENT == event.type )
- {
- ChangeState ( EventData::GRAB_HANDLE_PANNING );
-
- if( handleNewPosition != mEventData->mPrimaryCursorPosition )
- {
- // Updates the cursor position if the handle's new position is different than the current one.
- mEventData->mUpdateCursorPosition = true;
- // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
- mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
- mEventData->mPrimaryCursorPosition = handleNewPosition;
- }
-
- // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
- mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
- }
- else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
- {
- ChangeState ( EventData::SELECTION_HANDLE_PANNING );
-
- if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
- ( handleNewPosition != mEventData->mRightSelectionPosition ) )
- {
- // Updates the highlight box if the handle's new position is different than the current one.
- mEventData->mUpdateHighlightBox = true;
- // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
- mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
- mEventData->mLeftSelectionPosition = handleNewPosition;
- }
-
- // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
- mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
-
- // 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 )
- {
- ChangeState ( EventData::SELECTION_HANDLE_PANNING );
-
- if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
- ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
- {
- // Updates the highlight box if the handle's new position is different than the current one.
- mEventData->mUpdateHighlightBox = true;
- // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
- mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
- mEventData->mRightSelectionPosition = handleNewPosition;
- }
-
- // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
- mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
-
- // 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 ) ||
- handleStopScrolling )
- {
- CharacterIndex handlePosition = 0u;
- if( handleStopScrolling || isSmoothHandlePanEnabled )
- {
- // Convert from decorator's coords to text's coords.
- 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,
- CharacterHitTest::SCROLL,
- matchedCharacter );
- }
-
- if( Event::GRAB_HANDLE_EVENT == event.type )
- {
- mEventData->mUpdateCursorPosition = true;
- mEventData->mUpdateGrabHandlePosition = true;
- mEventData->mUpdateInputStyle = true;
-
- if( !IsClipboardEmpty() )
- {
- ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
- }
-
- if( handleStopScrolling || isSmoothHandlePanEnabled )
- {
- mEventData->mScrollAfterUpdatePosition = true;
- mEventData->mPrimaryCursorPosition = handlePosition;
- }
- }
- else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
- {
- ChangeState( EventData::SELECTING );
-
- mEventData->mUpdateHighlightBox = true;
- mEventData->mUpdateLeftSelectionPosition = true;
- mEventData->mUpdateRightSelectionPosition = true;
-
- if( handleStopScrolling || isSmoothHandlePanEnabled )
- {
- mEventData->mScrollAfterUpdatePosition = true;
-
- if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
- ( handlePosition != mEventData->mLeftSelectionPosition ) )
- {
- mEventData->mLeftSelectionPosition = handlePosition;
- }
- }
- }
- else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
- {
- ChangeState( EventData::SELECTING );
-
- mEventData->mUpdateHighlightBox = true;
- mEventData->mUpdateRightSelectionPosition = true;
- mEventData->mUpdateLeftSelectionPosition = true;
-
- if( handleStopScrolling || isSmoothHandlePanEnabled )
- {
- mEventData->mScrollAfterUpdatePosition = true;
- if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
- ( handlePosition != mEventData->mLeftSelectionPosition ) )
- {
- mEventData->mRightSelectionPosition = handlePosition;
- }
- }
- }
-
- mEventData->mDecoratorUpdated = true;
- } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
- else if( HANDLE_SCROLLING == state )
- {
- const float xSpeed = event.p2.mFloat;
- const float ySpeed = event.p3.mFloat;
- const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
- const Vector2 currentScrollPosition = mModel->mScrollPosition;
-
- mModel->mScrollPosition.x += xSpeed;
- mModel->mScrollPosition.y += ySpeed;
-
- ClampHorizontalScroll( layoutSize );
- ClampVerticalScroll( layoutSize );
-
- bool endOfScroll = false;
- if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
- {
- // Notify the decorator there is no more text to scroll.
- // The decorator won't send more scroll events.
- mEventData->mDecorator->NotifyEndOfScroll();
- // Still need to set the position of the handle.
- endOfScroll = true;
- }
-
- // Set the position of the handle.
- const bool scrollRightDirection = xSpeed > 0.f;
- const bool scrollBottomDirection = ySpeed > 0.f;
- const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
- const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
-
- if( Event::GRAB_HANDLE_EVENT == event.type )
- {
- ChangeState( EventData::GRAB_HANDLE_PANNING );
-
- // Get the grab handle position in decorator coords.
- Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
-
- if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
- {
- // Position the grag handle close to either the left or right edge.
- position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
- }
-
- if( mEventData->mDecorator->IsVerticalScrollEnabled() )
- {
- position.x = mEventData->mCursorHookPositionX;
-
- // Position the grag handle close to either the top or bottom edge.
- position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
- }
-
- // 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,
- CharacterHitTest::SCROLL,
- matchedCharacter );
-
- if( mEventData->mPrimaryCursorPosition != handlePosition )
- {
- mEventData->mUpdateCursorPosition = true;
- mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
- mEventData->mScrollAfterUpdatePosition = true;
- mEventData->mPrimaryCursorPosition = handlePosition;
- }
- mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
-
- // Updates the decorator if the soft handle panning is enabled.
- mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
- }
- else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
- {
- ChangeState( EventData::SELECTION_HANDLE_PANNING );
-
- // Get the selection handle position in decorator coords.
- Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
-
- if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
- {
- // Position the selection handle close to either the left or right edge.
- position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
- }
-
- if( mEventData->mDecorator->IsVerticalScrollEnabled() )
- {
- position.x = mEventData->mCursorHookPositionX;
-
- // Position the grag handle close to either the top or bottom edge.
- position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
- }
-
- // 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,
- CharacterHitTest::SCROLL,
- matchedCharacter );
-
- if( leftSelectionHandleEvent )
- {
- const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
-
- if( differentHandles || endOfScroll )
- {
- mEventData->mUpdateHighlightBox = true;
- mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
- mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
- mEventData->mLeftSelectionPosition = handlePosition;
- }
- }
- else
- {
- const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
- if( differentHandles || endOfScroll )
- {
- mEventData->mUpdateHighlightBox = true;
- mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
- mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
- mEventData->mRightSelectionPosition = handlePosition;
- }
- }
-
- if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
- {
- RepositionSelectionHandles();
-
- mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
- }
- }
- mEventData->mDecoratorUpdated = true;
- } // end ( HANDLE_SCROLLING == state )
-}
-
-void Controller::Impl::OnSelectEvent( const Event& event )
-{
- if( NULL == mEventData )
- {
- // Nothing to do if there is no text.
- return;
- }
-
- 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,
- Controller::NoTextTap::HIGHLIGHT );
- }
-}
-
-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.
- return;