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.cpp;h=b18767b2f29509452782274855211821910b7a86;hp=a992541e2d89e03779262aa8dc7d25dc53dd80cb;hb=9f742473929c8fafbf689ac7b8b23f3064c4b008;hpb=8b3dac6e167dd77d6db17c019d1e9778d79f198e diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp old mode 100644 new mode 100755 index a992541..b18767b --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -25,8 +25,10 @@ #include #include #include +#include // INTERNAL INCLUDES +#include #include #include #include @@ -47,13 +49,18 @@ const float MAX_FLOAT = std::numeric_limits::max(); const std::string EMPTY_STRING(""); -const char * const PLACEHOLDER_TEXT = "placeholderText"; -const char * const PLACEHOLDER_TEXT_FOCUSED = "placeholderTextFocused"; -const char * const PLACEHOLDER_COLOR = "placeholderColor"; -const char * const PLACEHOLDER_FONT_FAMILY = "placeholderFontFamily"; -const char * const PLACEHOLDER_FONT_STYLE = "placeholderFontStyle"; -const char * const PLACEHOLDER_POINT_SIZE = "placeholderPointSize"; -const char * const PLACEHOLDER_PIXEL_SIZE = "placeholderPixelSize"; +const std::string KEY_C_NAME = "c"; +const std::string KEY_V_NAME = "v"; +const std::string KEY_X_NAME = "x"; + +const char * const PLACEHOLDER_TEXT = "text"; +const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused"; +const char * const PLACEHOLDER_COLOR = "color"; +const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily"; +const char * const PLACEHOLDER_FONT_STYLE = "fontStyle"; +const char * const PLACEHOLDER_POINT_SIZE = "pointSize"; +const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize"; +const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; float ConvertToEven( float value ) { @@ -215,7 +222,7 @@ bool Controller::IsAutoScrollEnabled() const CharacterDirection Controller::GetAutoScrollDirection() const { - return mImpl->mAutoScrollDirectionRTL; + return mImpl->mIsTextDirectionRTL; } float Controller::GetAutoScrollLineAlignment() const @@ -344,6 +351,7 @@ void Controller::SetMultiLineEnabled( bool enable ) ALIGN | REORDER ); + mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true; mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | layoutOperations ); mImpl->RequestRelayout(); @@ -355,7 +363,7 @@ bool Controller::IsMultiLineEnabled() const return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout(); } -void Controller::SetHorizontalAlignment( Layout::HorizontalAlignment alignment ) +void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment ) { if( alignment != mImpl->mModel->mHorizontalAlignment ) { @@ -369,12 +377,12 @@ void Controller::SetHorizontalAlignment( Layout::HorizontalAlignment alignment ) } } -Layout::HorizontalAlignment Controller::GetHorizontalAlignment() const +Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const { return mImpl->mModel->mHorizontalAlignment; } -void Controller::SetVerticalAlignment( Layout::VerticalAlignment alignment ) +void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment ) { if( alignment != mImpl->mModel->mVerticalAlignment ) { @@ -387,12 +395,12 @@ void Controller::SetVerticalAlignment( Layout::VerticalAlignment alignment ) } } -Layout::VerticalAlignment Controller::GetVerticalAlignment() const +VerticalAlignment::Type Controller::GetVerticalAlignment() const { return mImpl->mModel->mVerticalAlignment; } -void Controller::SetLineWrapMode( Layout::LineWrap::Mode lineWrapMode ) +void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode ) { if( lineWrapMode != mImpl->mModel->mLineWrapMode ) { @@ -415,7 +423,7 @@ void Controller::SetLineWrapMode( Layout::LineWrap::Mode lineWrapMode ) } } -Layout::LineWrap::Mode Controller::GetLineWrapMode() const +Text::LineWrap::Mode Controller::GetLineWrapMode() const { return mImpl->mModel->mLineWrapMode; } @@ -430,6 +438,24 @@ bool Controller::IsTextElideEnabled() const return mImpl->mModel->mElideEnabled; } +void Controller::SetPlaceholderTextElideEnabled( bool enabled ) +{ + mImpl->mEventData->mIsPlaceholderElideEnabled = enabled; + mImpl->mEventData->mPlaceholderEllipsisFlag = true; + + // Update placeholder if there is no text + if( mImpl->IsShowingPlaceholderText() || + ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) ) + { + ShowPlaceholderText(); + } +} + +bool Controller::IsPlaceholderTextElideEnabled() const +{ + return mImpl->mEventData->mIsPlaceholderElideEnabled; +} + void Controller::SetSelectionEnabled( bool enabled ) { mImpl->mEventData->mSelectionEnabled = enabled; @@ -440,6 +466,26 @@ bool Controller::IsSelectionEnabled() const return mImpl->mEventData->mSelectionEnabled; } +void Controller::SetShiftSelectionEnabled( bool enabled ) +{ + mImpl->mEventData->mShiftSelectionFlag = enabled; +} + +bool Controller::IsShiftSelectionEnabled() const +{ + return mImpl->mEventData->mShiftSelectionFlag; +} + +void Controller::SetGrabHandleEnabled( bool enabled ) +{ + mImpl->mEventData->mGrabHandleEnabled = enabled; +} + +bool Controller::IsGrabHandleEnabled() const +{ + return mImpl->mEventData->mGrabHandleEnabled; +} + // public : Update void Controller::SetText( const std::string& text ) @@ -518,6 +564,9 @@ void Controller::SetText( const std::string& text ) // The natural size needs to be re-calculated. mImpl->mRecalculateNaturalSize = true; + // The text direction needs to be updated. + mImpl->mUpdateTextDirection = true; + // Apply modifications to the model mImpl->mOperationsPending = ALL_OPERATIONS; } @@ -686,7 +735,12 @@ void Controller::SetDefaultFontWeight( FontWeight weight ) bool Controller::IsDefaultFontWeightDefined() const { - return mImpl->mFontDefaults->weightDefined; + if( NULL != mImpl->mFontDefaults ) + { + return mImpl->mFontDefaults->weightDefined; + } + + return false; } FontWeight Controller::GetDefaultFontWeight() const @@ -752,7 +806,12 @@ void Controller::SetDefaultFontWidth( FontWidth width ) bool Controller::IsDefaultFontWidthDefined() const { - return mImpl->mFontDefaults->widthDefined; + if( NULL != mImpl->mFontDefaults ) + { + return mImpl->mFontDefaults->widthDefined; + } + + return false; } FontWidth Controller::GetDefaultFontWidth() const @@ -818,7 +877,11 @@ void Controller::SetDefaultFontSlant( FontSlant slant ) bool Controller::IsDefaultFontSlantDefined() const { - return mImpl->mFontDefaults->slantDefined; + if( NULL != mImpl->mFontDefaults ) + { + return mImpl->mFontDefaults->slantDefined; + } + return false; } FontSlant Controller::GetDefaultFontSlant() const @@ -1079,6 +1142,21 @@ const Vector4& Controller::GetShadowColor() const return mImpl->mModel->mVisualModel->GetShadowColor(); } +void Controller::SetShadowBlurRadius( const float& shadowBlurRadius ) +{ + if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 ) + { + mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius ); + + mImpl->RequestRelayout(); + } +} + +const float& Controller::GetShadowBlurRadius() const +{ + return mImpl->mModel->mVisualModel->GetShadowBlurRadius(); +} + void Controller::SetUnderlineColor( const Vector4& color ) { mImpl->mModel->mVisualModel->SetUnderlineColor( color ); @@ -1115,6 +1193,54 @@ float Controller::GetUnderlineHeight() const return mImpl->mModel->mVisualModel->GetUnderlineHeight(); } +void Controller::SetOutlineColor( const Vector4& color ) +{ + mImpl->mModel->mVisualModel->SetOutlineColor( color ); + + mImpl->RequestRelayout(); +} + +const Vector4& Controller::GetOutlineColor() const +{ + return mImpl->mModel->mVisualModel->GetOutlineColor(); +} + +void Controller::SetOutlineWidth( unsigned int width ) +{ + mImpl->mModel->mVisualModel->SetOutlineWidth( width ); + + mImpl->RequestRelayout(); +} + +unsigned int Controller::GetOutlineWidth() const +{ + return mImpl->mModel->mVisualModel->GetOutlineWidth(); +} + +void Controller::SetBackgroundColor( const Vector4& color ) +{ + mImpl->mModel->mVisualModel->SetBackgroundColor( color ); + + mImpl->RequestRelayout(); +} + +const Vector4& Controller::GetBackgroundColor() const +{ + return mImpl->mModel->mVisualModel->GetBackgroundColor(); +} + +void Controller::SetBackgroundEnabled( bool enabled ) +{ + mImpl->mModel->mVisualModel->SetBackgroundEnabled( enabled ); + + mImpl->RequestRelayout(); +} + +bool Controller::IsBackgroundEnabled() const +{ + return mImpl->mModel->mVisualModel->IsBackgroundEnabled(); +} + void Controller::SetDefaultEmbossProperties( const std::string& embossProperties ) { if( NULL == mImpl->mEmbossDefaults ) @@ -1155,10 +1281,15 @@ const std::string& Controller::GetDefaultOutlineProperties() const return EMPTY_STRING; } -void Controller::SetDefaultLineSpacing( float lineSpacing ) +bool Controller::SetDefaultLineSpacing( float lineSpacing ) { - //TODO finish implementation - mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing ); + if( std::abs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000 ) + { + mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing); + mImpl->mRecalculateNaturalSize = true; + return true; + } + return false; } float Controller::GetDefaultLineSpacing() const @@ -1693,6 +1824,16 @@ void Controller::ShadowSetByString( bool setByString ) mImpl->mShadowSetByString = setByString; } +bool Controller::IsOutlineSetByString() +{ + return mImpl->mOutlineSetByString; +} + +void Controller::OutlineSetByString( bool setByString ) +{ + mImpl->mOutlineSetByString = setByString; +} + bool Controller::IsFontStyleSetByString() { return mImpl->mFontStyleSetByString; @@ -1743,14 +1884,14 @@ Vector3 Controller::GetNaturalSize() mImpl->UpdateModel( onlyOnceOperations ); // Layout the text for the new width. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | LAYOUT ); + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | LAYOUT | REORDER ); // Store the actual control's size to restore later. const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize; DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ), static_cast( onlyOnceOperations | - LAYOUT ), + LAYOUT | REORDER ), naturalSize.GetVectorXY() ); // Do not do again the only once operations. @@ -1770,6 +1911,7 @@ Vector3 Controller::GetNaturalSize() // Clear the update info. This info will be set the next time the text is updated. mImpl->mTextUpdateInfo.Clear(); + mImpl->mTextUpdateInfo.mClearAll = true; // Restore the actual control's size. mImpl->mModel->mVisualModel->mControlSize = actualControlSize; @@ -1919,19 +2061,19 @@ void Controller::SetPlaceholderProperty( const Property::Map& map ) Property::Key& key = keyValue.first; Property::Value& value = keyValue.second; - if( key == PLACEHOLDER_TEXT ) + if( key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT ) { std::string text = ""; value.Get( text ); SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text ); } - else if( key == PLACEHOLDER_TEXT_FOCUSED ) + else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED ) { std::string text = ""; value.Get( text ); SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text ); } - else if( key == PLACEHOLDER_COLOR ) + else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR ) { Vector4 textColor; value.Get( textColor ); @@ -1940,17 +2082,17 @@ void Controller::SetPlaceholderProperty( const Property::Map& map ) SetPlaceholderTextColor( textColor ); } } - else if( key == PLACEHOLDER_FONT_FAMILY ) + else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY ) { std::string fontFamily = ""; value.Get( fontFamily ); SetPlaceholderFontFamily( fontFamily ); } - else if( key == PLACEHOLDER_FONT_STYLE ) + else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE ) { SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER ); } - else if( key == PLACEHOLDER_POINT_SIZE ) + else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE ) { float pointSize; value.Get( pointSize ); @@ -1959,7 +2101,7 @@ void Controller::SetPlaceholderProperty( const Property::Map& map ) SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE ); } } - else if( key == PLACEHOLDER_PIXEL_SIZE ) + else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE ) { float pixelSize; value.Get( pixelSize ); @@ -1968,6 +2110,12 @@ void Controller::SetPlaceholderProperty( const Property::Map& map ) SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE ); } } + else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS ) + { + bool ellipsis; + value.Get( ellipsis ); + SetPlaceholderTextElideEnabled( ellipsis ); + } } } @@ -1977,32 +2125,85 @@ void Controller::GetPlaceholderProperty( Property::Map& map ) { if( !mImpl->mEventData->mPlaceholderTextActive.empty() ) { - map[ PLACEHOLDER_TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive; + map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive; } if( !mImpl->mEventData->mPlaceholderTextInactive.empty() ) { - map[ PLACEHOLDER_TEXT ] = mImpl->mEventData->mPlaceholderTextInactive; + map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive; } - map[ PLACEHOLDER_COLOR ] = mImpl->mEventData->mPlaceholderTextColor; - map[ PLACEHOLDER_FONT_FAMILY ] = GetPlaceholderFontFamily(); + map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor; + map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily(); Property::Value fontStyleMapGet; GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER ); - map[ PLACEHOLDER_FONT_STYLE ] = fontStyleMapGet; + map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet; // Choose font size : POINT_SIZE or PIXEL_SIZE if( !mImpl->mEventData->mIsPlaceholderPixelSize ) { - map[ PLACEHOLDER_POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ); + map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ); } else { - map[ PLACEHOLDER_PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ); + map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ); + } + + if( mImpl->mEventData->mPlaceholderEllipsisFlag ) + { + map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(); } } } +Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection() +{ + // Make sure the model is up-to-date before layouting + ProcessModifyEvents(); + + if ( mImpl->mUpdateTextDirection ) + { + // Operations that can be done only once until the text changes. + const OperationsMask onlyOnceOperations = static_cast( GET_SCRIPTS | + VALIDATE_FONTS | + GET_LINE_BREAKS | + GET_WORD_BREAKS | + BIDI_INFO | + SHAPE_TEXT | + GET_GLYPH_METRICS ); + + // Set the update info to relayout the whole text. + mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u; + mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count(); + + // Make sure the model is up-to-date before layouting + mImpl->UpdateModel( onlyOnceOperations ); + + Vector3 naturalSize; + DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ), + static_cast( onlyOnceOperations | + LAYOUT | REORDER | UPDATE_DIRECTION ), + naturalSize.GetVectorXY() ); + + // Clear the update info. This info will be set the next time the text is updated. + mImpl->mTextUpdateInfo.Clear(); + + mImpl->mUpdateTextDirection = false; + } + + return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT; +} + +Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const +{ + return mImpl->mModel->GetVerticalLineAlignment(); +} + +void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment ) +{ + mImpl->mModel->mVerticalLineAlignment = alignment; +} + // public : Relayout. Controller::UpdateTextType Controller::Relayout( const Size& size ) @@ -2035,6 +2236,13 @@ Controller::UpdateTextType Controller::Relayout( const Size& size ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height ); + if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) && + ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) && + ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) ) + { + mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); + } + // Layout operations that need to be done if the size changes. mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | LAYOUT | @@ -2057,6 +2265,20 @@ Controller::UpdateTextType Controller::Relayout( const Size& size ) COLOR ); } + // Set the update info to elide the text. + if( mImpl->mModel->mElideEnabled || + ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) ) + { + // Update Text layout for applying elided + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | + ALIGN | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER ); + mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true; + mImpl->mTextUpdateInfo.mCharacterIndex = 0u; + } + // Make sure the model is up-to-date before layouting. ProcessModifyEvents(); bool updated = mImpl->UpdateModel( mImpl->mOperationsPending ); @@ -2212,6 +2434,7 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) { int keyCode = keyEvent.keyCode; const std::string& keyString = keyEvent.keyPressed; + const std::string keyName = keyEvent.keyPressedName; const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() ); @@ -2222,13 +2445,10 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) // Do nothing. return false; } - else if( Dali::DALI_KEY_ESCAPE == keyCode ) + else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode ) { - // Escape key is a special case which causes focus loss - KeyboardFocusLostEvent(); - - // Will request for relayout. - relayoutNeeded = true; + // Do nothing + return false; } else if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode ) || ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) || @@ -2247,27 +2467,71 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines(); // Logic to determine whether this text control will lose focus or not. - if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) || - ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) || + if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) || + ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) || ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) || ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) || ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) || ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) ) { + // Release the active highlight. + if( mImpl->mEventData->mState == EventData::SELECTING ) + { + mImpl->ChangeState( EventData::EDITING ); + + // Update selection position. + mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; + mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; + mImpl->mEventData->mUpdateCursorPosition = true; + mImpl->RequestRelayout(); + } return false; } mImpl->mEventData->mCheckScrollAmount = true; Event event( Event::CURSOR_KEY_EVENT ); event.p1.mInt = keyCode; + event.p2.mBool = keyEvent.IsShiftModifier(); mImpl->mEventData->mEventQueue.push_back( event ); // Will request for relayout. relayoutNeeded = true; } - else if( Dali::DALI_KEY_BACKSPACE == keyCode ) + else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode ) { - textChanged = BackspaceKeyEvent(); + // Left or Right Control key event is received before Ctrl-C/V/X key event is received + // If not handle it here, any selected text will be deleted + + // Do nothing + return false; + } + else if ( keyEvent.IsCtrlModifier() ) + { + bool consumed = false; + if (keyName == KEY_C_NAME) + { + // Ctrl-C to copy the selected text + TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY ); + consumed = true; + } + else if (keyName == KEY_V_NAME) + { + // Ctrl-V to paste the copied text + TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE ); + consumed = true; + } + else if (keyName == KEY_X_NAME) + { + // Ctrl-X to cut the selected text + TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT ); + consumed = true; + } + return consumed; + } + else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) || + ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) ) + { + textChanged = DeleteEvent( keyCode ); // Will request for relayout. relayoutNeeded = true; @@ -2581,7 +2845,17 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons if( retrieveText ) { - mImpl->GetText( numberOfWhiteSpaces, text ); + if( !mImpl->IsShowingPlaceholderText() ) + { + // Retrieves the normal text string. + mImpl->GetText( numberOfWhiteSpaces, text ); + } + else + { + // When the current text is Placeholder Text, the surrounding text should be empty string. + // It means DALi should send empty string ("") to IME. + text = ""; + } } ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); @@ -3192,6 +3466,22 @@ bool Controller::DoRelayout( const Size& size, const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u ); const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex; + + // Make sure the index is not out of bound + if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() || + requestedNumberOfCharacters > charactersToGlyph.Count() || + ( lastIndex >= charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) ) + { + std::string currentText; + GetText( currentText ); + + DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" ); + DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() ); + DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count()); + + return false; + } + const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u; const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count(); @@ -3214,9 +3504,11 @@ bool Controller::DoRelayout( const Size& size, const Vector& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters; const Vector& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph; const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin(); + const float outlineWidth = static_cast( mImpl->mModel->GetOutlineWidth() ); // Set the layout parameters. - Layout::Parameters layoutParameters( size, + const Vector2 sizeOffset = Vector2(outlineWidth * 2.0f, outlineWidth * 2.0f); // The outline should be fit into the bounding box + Layout::Parameters layoutParameters( size - sizeOffset, textBuffer, lineBreakInfo.Begin(), wordBreakInfo.Begin(), @@ -3228,7 +3520,8 @@ bool Controller::DoRelayout( const Size& size, glyphsPerCharacterBuffer, totalNumberOfGlyphs, mImpl->mModel->mHorizontalAlignment, - mImpl->mModel->mLineWrapMode ); + mImpl->mModel->mLineWrapMode, + outlineWidth ); // Resize the vector of positions to have the same size than the vector of glyphs. Vector& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions; @@ -3244,13 +3537,35 @@ bool Controller::DoRelayout( const Size& size, layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex; layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines; + // Update the ellipsis + bool elideTextEnabled = mImpl->mModel->mElideEnabled; + + if( NULL != mImpl->mEventData ) + { + if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() ) + { + elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled; + } + else if( EventData::INACTIVE != mImpl->mEventData->mState ) + { + // Disable ellipsis when editing + elideTextEnabled = false; + } + + // Reset the scroll position in inactive state + if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) ) + { + ResetScrollPosition(); + } + } + // Update the visual model. Size newLayoutSize; viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters, glyphPositions, mImpl->mModel->mVisualModel->mLines, newLayoutSize, - mImpl->mModel->mElideEnabled ); + elideTextEnabled ); viewUpdated = viewUpdated || ( newLayoutSize != layoutSize ); @@ -3260,7 +3575,7 @@ bool Controller::DoRelayout( const Size& size, if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) { - mImpl->mAutoScrollDirectionRTL = false; + mImpl->mIsTextDirectionRTL = false; } // Reorder the lines @@ -3298,7 +3613,7 @@ bool Controller::DoRelayout( const Size& size, const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin(); if ( firstline ) { - mImpl->mAutoScrollDirectionRTL = firstline->direction; + mImpl->mIsTextDirectionRTL = firstline->direction; } } } @@ -3331,7 +3646,7 @@ bool Controller::DoRelayout( const Size& size, #if defined(DEBUG_ENABLED) std::string currentText; GetText( currentText ); - DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false", currentText.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false", currentText.c_str() ); #endif DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) ); return viewUpdated; @@ -3349,17 +3664,17 @@ void Controller::CalculateVerticalOffset( const Size& controlSize ) switch( mImpl->mModel->mVerticalAlignment ) { - case Layout::VERTICAL_ALIGN_TOP: + case VerticalAlignment::TOP: { mImpl->mModel->mScrollPosition.y = 0.f; break; } - case Layout::VERTICAL_ALIGN_CENTER: + case VerticalAlignment::CENTER: { mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment. break; } - case Layout::VERTICAL_ALIGN_BOTTOM: + case VerticalAlignment::BOTTOM: { mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height; break; @@ -3411,6 +3726,10 @@ void Controller::ProcessModifyEvents() { // When the text is being modified, delay cursor blinking mImpl->mEventData->mDecorator->DelayCursorBlink(); + + // Update selection position after modifying the text + mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; + mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; } // Discard temporary text @@ -3422,6 +3741,9 @@ void Controller::TextReplacedEvent() // The natural size needs to be re-calculated. mImpl->mRecalculateNaturalSize = true; + // The text direction needs to be updated. + mImpl->mUpdateTextDirection = true; + // Apply modifications to the model mImpl->mOperationsPending = ALL_OPERATIONS; } @@ -3440,6 +3762,9 @@ void Controller::TextInsertedEvent() // The natural size needs to be re-calculated. mImpl->mRecalculateNaturalSize = true; + // The text direction needs to be updated. + mImpl->mUpdateTextDirection = true; + // Apply modifications to the model; TODO - Optimize this mImpl->mOperationsPending = ALL_OPERATIONS; } @@ -3458,6 +3783,9 @@ void Controller::TextDeletedEvent() // The natural size needs to be re-calculated. mImpl->mRecalculateNaturalSize = true; + // The text direction needs to be updated. + mImpl->mUpdateTextDirection = true; + // Apply modifications to the model; TODO - Optimize this mImpl->mOperationsPending = ALL_OPERATIONS; } @@ -3488,9 +3816,9 @@ void Controller::SelectEvent( float x, float y, bool selectAll ) } } -bool Controller::BackspaceKeyEvent() +bool Controller::DeleteEvent( int keyCode ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode ); bool removed = false; @@ -3506,13 +3834,20 @@ bool Controller::BackspaceKeyEvent() { removed = RemoveSelectedText(); } - else if( mImpl->mEventData->mPrimaryCursorPosition > 0 ) + else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) ) { // Remove the character before the current cursor position removed = RemoveText( -1, 1, UPDATE_INPUT_STYLE ); } + else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) + { + // Remove the character after the current cursor position + removed = RemoveText( 0, + 1, + UPDATE_INPUT_STYLE ); + } if( removed ) { @@ -3552,6 +3887,9 @@ void Controller::ResetText() // The natural size needs to be re-calculated. mImpl->mRecalculateNaturalSize = true; + // The text direction needs to be updated. + mImpl->mUpdateTextDirection = true; + // Apply modifications to the model mImpl->mOperationsPending = ALL_OPERATIONS; } @@ -3618,6 +3956,9 @@ void Controller::ShowPlaceholderText() // The natural size needs to be re-calculated. mImpl->mRecalculateNaturalSize = true; + // The text direction needs to be updated. + mImpl->mUpdateTextDirection = true; + // Apply modifications to the model mImpl->mOperationsPending = ALL_OPERATIONS; @@ -3645,6 +3986,7 @@ void Controller::ClearFontData() mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | VALIDATE_FONTS | SHAPE_TEXT | + BIDI_INFO | GET_GLYPH_METRICS | LAYOUT | UPDATE_LAYOUT_SIZE | @@ -3683,6 +4025,16 @@ void Controller::ResetScrollPosition() } } +void Controller::SetControlInterface( ControlInterface* controlInterface ) +{ + mImpl->mControlInterface = controlInterface; +} + +bool Controller::ShouldClearFocusOnEscape() const +{ + return mImpl->mShouldClearFocusOnEscape; +} + // private : Private contructors & copy operator. Controller::Controller()