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=0fd084c84ecd0aa45f985578095fe9a6c4939a10;hp=ca02bac96fcaa685955626e931ed1964a04de8cc;hb=5075ccc3be07ba0da557493efc026ecb2a5373fe;hpb=f11be450471738b68f98fa4c552b3a22482ae4de diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp old mode 100755 new mode 100644 index ca02bac..0fd084c --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -22,55 +22,29 @@ #include #include #include -#include #include -#include -#include -#include // INTERNAL INCLUDES -#include -#include #include -#include #include -#include +#include #include +#include +#include +#include #include -#include namespace { #if defined(DEBUG_ENABLED) - Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); #endif -const float MAX_FLOAT = std::numeric_limits::max(); +constexpr float MAX_FLOAT = std::numeric_limits::max(); const std::string EMPTY_STRING(""); -const std::string KEY_C_NAME = "c"; -const std::string KEY_V_NAME = "v"; -const std::string KEY_X_NAME = "x"; -const std::string KEY_A_NAME = "a"; -const std::string KEY_INSERT_NAME = "Insert"; - -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 ) -{ - int intValue(static_cast( value )); - return static_cast( intValue + ( intValue & 1 ) ); -} - int ConvertPixelToPint( float pixel ) { unsigned int horizontalDpi = 0u; @@ -92,44 +66,6 @@ namespace Toolkit namespace Text { -/** - * @brief Adds a new font description run for the selected text. - * - * The new font parameters are added after the call to this method. - * - * @param[in] eventData The event data pointer. - * @param[in] logicalModel The logical model where to add the new font description run. - * @param[out] startOfSelectedText Index to the first selected character. - * @param[out] lengthOfSelectedText Number of selected characters. - */ -FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData, - LogicalModelPtr logicalModel, - CharacterIndex& startOfSelectedText, - Length& lengthOfSelectedText ) -{ - const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition; - - // Get start and end position of selection - startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition; - lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText; - - // Add the font run. - const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count(); - logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); - - FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); - - fontDescriptionRun.characterRun.characterIndex = startOfSelectedText; - fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText; - - // Recalculate the selection highlight as the metrics may have changed. - eventData->mUpdateLeftSelectionPosition = true; - eventData->mUpdateRightSelectionPosition = true; - eventData->mUpdateHighlightBox = true; - - return fontDescriptionRun; -} - // public : Constructor. ControllerPtr Controller::New() @@ -594,20 +530,12 @@ Vector2 Controller::GetTextFitContentSize() const 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(); - } + PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled); } bool Controller::IsPlaceholderTextElideEnabled() const { - return mImpl->mEventData->mIsPlaceholderElideEnabled; + return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this); } void Controller::SetSelectionEnabled( bool enabled ) @@ -776,39 +704,12 @@ void Controller::GetText( std::string& text ) const void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text ) { - if( NULL != mImpl->mEventData ) - { - if( PLACEHOLDER_TYPE_INACTIVE == type ) - { - mImpl->mEventData->mPlaceholderTextInactive = text; - } - else - { - mImpl->mEventData->mPlaceholderTextActive = text; - } - - // Update placeholder if there is no text - if( mImpl->IsShowingPlaceholderText() || - ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) ) - { - ShowPlaceholderText(); - } - } + PlaceholderHandler::SetPlaceholderText(*this, type, text); } void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const { - if( NULL != mImpl->mEventData ) - { - if( PLACEHOLDER_TYPE_INACTIVE == type ) - { - text = mImpl->mEventData->mPlaceholderTextInactive; - } - else - { - text = mImpl->mEventData->mPlaceholderTextActive; - } - } + PlaceholderHandler::GetPlaceholderText(*this, type, text ); } void Controller::UpdateAfterFontChange( const std::string& newDefaultFont ) @@ -826,6 +727,31 @@ void Controller::UpdateAfterFontChange( const std::string& newDefaultFont ) } } +void Controller::RetrieveSelection( std::string& selectedText ) const +{ + mImpl->RetrieveSelection( selectedText, false ); +} + +void Controller::SetSelection( int start, int end ) +{ + mImpl->SetSelection( start, end ); +} + +std::pair< int, int > Controller::GetSelectionIndexes() const +{ + return mImpl->GetSelectionIndexes(); +} + +void Controller::CopyStringToClipboard( const std::string& source ) +{ + mImpl->CopyStringToClipboard( source ); +} + +void Controller::SendSelectionToClipboard( bool deleteAfterSending ) +{ + mImpl->SendSelectionToClipboard( deleteAfterSending ); +} + // public : Default style & Input style void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily ) @@ -867,29 +793,12 @@ const std::string& Controller::GetDefaultFontFamily() const void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily; - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str()); - mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty(); - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily); } const std::string& Controller::GetPlaceholderFontFamily() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.family; - } - - return EMPTY_STRING; + return PlaceholderHandler::GetPlaceholderFontFamily(*this); } void Controller::SetDefaultFontWeight( FontWeight weight ) @@ -940,37 +849,17 @@ FontWeight Controller::GetDefaultFontWeight() const void Controller::SetPlaceholderTextFontWeight( FontWeight weight ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight; - mImpl->mEventData->mPlaceholderFont->weightDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight); } bool Controller::IsPlaceholderTextFontWeightDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->weightDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);; } FontWeight Controller::GetPlaceholderTextFontWeight() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight; - } - - return TextAbstraction::FontWeight::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontWeight(*this); } void Controller::SetDefaultFontWidth( FontWidth width ) @@ -1021,37 +910,17 @@ FontWidth Controller::GetDefaultFontWidth() const void Controller::SetPlaceholderTextFontWidth( FontWidth width ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width; - mImpl->mEventData->mPlaceholderFont->widthDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width); } bool Controller::IsPlaceholderTextFontWidthDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->widthDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this); } FontWidth Controller::GetPlaceholderTextFontWidth() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.width; - } - - return TextAbstraction::FontWidth::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontWidth(*this); } void Controller::SetDefaultFontSlant( FontSlant slant ) @@ -1101,37 +970,47 @@ FontSlant Controller::GetDefaultFontSlant() const void Controller::SetPlaceholderTextFontSlant( FontSlant slant ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } + PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant); +} - mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant; - mImpl->mEventData->mPlaceholderFont->slantDefined = true; +bool Controller::IsPlaceholderTextFontSlantDefined() const +{ + return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this); +} - mImpl->RequestRelayout(); - } +FontSlant Controller::GetPlaceholderTextFontSlant() const +{ + return PlaceholderHandler::GetPlaceholderTextFontSlant(*this); } -bool Controller::IsPlaceholderTextFontSlantDefined() const +void Controller::SetFontSizeScale( float scale ) { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) + mImpl->mFontSizeScale = scale; + + if( mImpl->mEventData ) { - return mImpl->mEventData->mPlaceholderFont->slantDefined; + // Update the cursor position if it's in editing mode + if( EventData::IsEditingState( mImpl->mEventData->mState ) ) + { + mImpl->mEventData->mDecoratorUpdated = true; + mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated. + } } - return false; + + // Clear the font-specific data + ClearFontData(); + + mImpl->RequestRelayout(); } -FontSlant Controller::GetPlaceholderTextFontSlant() const +float Controller::GetFontSizeScale() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) + if( nullptr != mImpl->mFontDefaults ) { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant; + return mImpl->mFontSizeScale; } - return TextAbstraction::FontSlant::NORMAL; + return 1.f; } void Controller::SetDefaultFontSize( float fontSize, FontSizeType type ) @@ -1211,85 +1090,12 @@ float Controller::GetDefaultFontSize( FontSizeType type ) const void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - switch( type ) - { - case POINT_SIZE: - { - mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize; - mImpl->mEventData->mPlaceholderFont->sizeDefined = true; - mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag - break; - } - case PIXEL_SIZE: - { - // Point size = Pixel size * 72.f / DPI - unsigned int horizontalDpi = 0u; - unsigned int verticalDpi = 0u; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - fontClient.GetDpi( horizontalDpi, verticalDpi ); - - mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi ); - mImpl->mEventData->mPlaceholderFont->sizeDefined = true; - mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag - break; - } - } - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type); } float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const { - float value = 0.0f; - if( NULL != mImpl->mEventData ) - { - switch( type ) - { - case POINT_SIZE: - { - if( NULL != mImpl->mEventData->mPlaceholderFont ) - { - value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize; - } - else - { - // If the placeholder text font size is not set, then return the default font size. - value = GetDefaultFontSize( POINT_SIZE ); - } - break; - } - case PIXEL_SIZE: - { - if( NULL != mImpl->mEventData->mPlaceholderFont ) - { - // Pixel size = Point size * DPI / 72.f - unsigned int horizontalDpi = 0u; - unsigned int verticalDpi = 0u; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - fontClient.GetDpi( horizontalDpi, verticalDpi ); - - value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f; - } - else - { - // If the placeholder text font size is not set, then return the default font size. - value = GetDefaultFontSize( PIXEL_SIZE ); - } - break; - } - } - return value; - } - - return value; + return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type); } void Controller::SetDefaultColor( const Vector4& color ) @@ -1315,26 +1121,12 @@ const Vector4& Controller::GetDefaultColor() const void Controller::SetPlaceholderTextColor( const Vector4& textColor ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mPlaceholderTextColor = textColor; - } - - if( mImpl->IsShowingPlaceholderText() ) - { - mImpl->mModel->mVisualModel->SetTextColor( textColor ); - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextColor(*this, textColor); } const Vector4& Controller::GetPlaceholderTextColor() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mPlaceholderTextColor; - } - - return Color::BLACK; + return PlaceholderHandler::GetPlaceholderTextColor(*this); } void Controller::SetShadowOffset( const Vector2& shadowOffset ) @@ -1581,369 +1373,67 @@ const Vector4& Controller::GetInputColor() const void Controller::SetInputFontFamily( const std::string& fontFamily ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.familyName = fontFamily; - mImpl->mEventData->mInputStyle.isFamilyDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.familyLength = fontFamily.size(); - fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; - memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength ); - fontDescriptionRun.familyDefined = true; - - // The memory allocated for the font family name is freed when the font description is removed from the logical model. - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font changes, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } + InputFontHandler::SetInputFontFamily(*this, fontFamily); } const std::string& Controller::GetInputFontFamily() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.familyName; - } - - // Return the default font's family if there is no EventData. - return GetDefaultFontFamily(); + return InputFontHandler::GetInputFontFamily(*this); } void Controller::SetInputFontWeight( FontWeight weight ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.weight = weight; - mImpl->mEventData->mInputStyle.isWeightDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.weight = weight; - fontDescriptionRun.weightDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } + InputFontHandler::SetInputFontWeight(*this, weight); } bool Controller::IsInputFontWeightDefined() const { - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isWeightDefined; - } - - return defined; + return InputFontHandler::IsInputFontWeightDefined(*this); } FontWeight Controller::GetInputFontWeight() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.weight; - } - - return GetDefaultFontWeight(); + return InputFontHandler::GetInputFontWeight(*this); } void Controller::SetInputFontWidth( FontWidth width ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.width = width; - mImpl->mEventData->mInputStyle.isWidthDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.width = width; - fontDescriptionRun.widthDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } + InputFontHandler::SetInputFontWidth(*this, width); } bool Controller::IsInputFontWidthDefined() const { - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isWidthDefined; - } - - return defined; + return InputFontHandler::IsInputFontWidthDefined(*this); } FontWidth Controller::GetInputFontWidth() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.width; - } - - return GetDefaultFontWidth(); + return InputFontHandler::GetInputFontWidth(*this); } void Controller::SetInputFontSlant( FontSlant slant ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.slant = slant; - mImpl->mEventData->mInputStyle.isSlantDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.slant = slant; - fontDescriptionRun.slantDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } + InputFontHandler::SetInputFontSlant(*this, slant); } bool Controller::IsInputFontSlantDefined() const { - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isSlantDefined; - } - - return defined; + return InputFontHandler::IsInputFontSlantDefined(*this); } FontSlant Controller::GetInputFontSlant() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.slant; - } - - return GetDefaultFontSlant(); + return InputFontHandler::GetInputFontSlant(*this); } void Controller::SetInputFontPointSize( float size ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.size = size; - mImpl->mEventData->mInputStyle.isSizeDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.size = static_cast( size * 64.f ); - fontDescriptionRun.sizeDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } + InputFontHandler::SetInputFontPointSize(*this, size); } float Controller::GetInputFontPointSize() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.size; - } - - // Return the default font's point size if there is no EventData. - return GetDefaultFontSize( Text::Controller::POINT_SIZE ); + return InputFontHandler::GetInputFontPointSize(*this); } void Controller::SetInputLineSpacing( float lineSpacing ) @@ -2148,113 +1638,12 @@ View& Controller::GetView() Vector3 Controller::GetNaturalSize() { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" ); - Vector3 naturalSize; - - // Make sure the model is up-to-date before layouting - ProcessModifyEvents(); - - if( mImpl->mRecalculateNaturalSize ) - { - // Operations that can be done only once until the text changes. - const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | - GET_SCRIPTS | - VALIDATE_FONTS | - GET_LINE_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 ); - - // Layout the text for the new width. - 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 | REORDER ), - naturalSize.GetVectorXY() ); - - // Do not do again the only once operations. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending & ~onlyOnceOperations ); - - // Do the size related operations again. - const OperationsMask sizeOperations = static_cast( LAYOUT | - ALIGN | - REORDER ); - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | sizeOperations ); - - // Stores the natural size to avoid recalculate it again - // unless the text/style changes. - mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() ); - - mImpl->mRecalculateNaturalSize = false; - - // 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; - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z ); - } - else - { - naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize(); - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z ); - } - - naturalSize.x = ConvertToEven( naturalSize.x ); - naturalSize.y = ConvertToEven( naturalSize.y ); - - return naturalSize; + return Relayouter::GetNaturalSize(*this); } bool Controller::CheckForTextFit( float pointSize, Size& layoutSize ) { - Size textSize; - mImpl->mFontDefaults->mFitPointSize = pointSize; - mImpl->mFontDefaults->sizeDefined = true; - ClearFontData(); - - // Operations that can be done only once until the text changes. - const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | - GET_SCRIPTS | - VALIDATE_FONTS | - GET_LINE_BREAKS | - BIDI_INFO | - SHAPE_TEXT| - GET_GLYPH_METRICS ); - - 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 ); - - DoRelayout( Size( layoutSize.width, MAX_FLOAT ), - static_cast( onlyOnceOperations | LAYOUT), - textSize); - - // Clear the update info. This info will be set the next time the text is updated. - mImpl->mTextUpdateInfo.Clear(); - mImpl->mTextUpdateInfo.mClearAll = true; - - if( textSize.width > layoutSize.width || textSize.height > layoutSize.height ) - { - return false; - } - return true; + return Relayouter::CheckForTextFit(*this, pointSize, layoutSize); } void Controller::FitPointSizeforLayout( Size layoutSize ) @@ -2313,69 +1702,7 @@ void Controller::FitPointSizeforLayout( Size layoutSize ) float Controller::GetHeightForWidth( float width ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width ); - // Make sure the model is up-to-date before layouting - ProcessModifyEvents(); - - Size layoutSize; - if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 || - mImpl->mTextUpdateInfo.mFullRelayoutNeeded || - mImpl->mTextUpdateInfo.mClearAll ) - { - // Operations that can be done only once until the text changes. - const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | - GET_SCRIPTS | - VALIDATE_FONTS | - GET_LINE_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 ); - - - // Layout the text for the new width. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | LAYOUT ); - - // Store the actual control's width. - const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width; - - DoRelayout( Size( width, MAX_FLOAT ), - static_cast( onlyOnceOperations | - LAYOUT ), - layoutSize ); - - // Do not do again the only once operations. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending & ~onlyOnceOperations ); - - // Do the size related operations again. - const OperationsMask sizeOperations = static_cast( LAYOUT | - ALIGN | - REORDER ); - - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | sizeOperations ); - - // 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 width. - mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth; - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height ); - } - else - { - layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize(); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height ); - } - - return layoutSize.height; + return Relayouter::GetHeightForWidth(*this, width); } int Controller::GetLineCount( float width ) @@ -2414,7 +1741,7 @@ bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, return isScrolled; } -void Controller::SetHiddenInputOption(const Property::Map& options ) +void Controller::SetHiddenInputOption(const Property::Map& options) { if( NULL == mImpl->mHiddenInput ) { @@ -2423,7 +1750,7 @@ void Controller::SetHiddenInputOption(const Property::Map& options ) mImpl->mHiddenInput->SetProperties(options); } -void Controller::GetHiddenInputOption(Property::Map& options ) +void Controller::GetHiddenInputOption(Property::Map& options) { if( NULL != mImpl->mHiddenInput ) { @@ -2433,107 +1760,12 @@ void Controller::GetHiddenInputOption(Property::Map& options ) void Controller::SetPlaceholderProperty( const Property::Map& map ) { - const Property::Map::SizeType count = map.Count(); - - for( Property::Map::SizeType position = 0; position < count; ++position ) - { - KeyValuePair keyValue = map.GetKeyValue( position ); - Property::Key& key = keyValue.first; - Property::Value& value = keyValue.second; - - 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 == 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 == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR ) - { - Vector4 textColor; - value.Get( textColor ); - if( GetPlaceholderTextColor() != textColor ) - { - SetPlaceholderTextColor( textColor ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY ) - { - std::string fontFamily = ""; - value.Get( fontFamily ); - SetPlaceholderFontFamily( fontFamily ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE ) - { - SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE ) - { - float pointSize; - value.Get( pointSize ); - if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) ) - { - SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE ) - { - float pixelSize; - value.Get( pixelSize ); - if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) ) - { - SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS ) - { - bool ellipsis; - value.Get( ellipsis ); - SetPlaceholderTextElideEnabled( ellipsis ); - } - } + PlaceholderHandler::SetPlaceholderProperty(*this, map); } void Controller::GetPlaceholderProperty( Property::Map& map ) { - if( NULL != mImpl->mEventData ) - { - if( !mImpl->mEventData->mPlaceholderTextActive.empty() ) - { - map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive; - } - if( !mImpl->mEventData->mPlaceholderTextInactive.empty() ) - { - map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive; - } - - 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[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet; - - // Choose font size : POINT_SIZE or PIXEL_SIZE - if( !mImpl->mEventData->mIsPlaceholderPixelSize ) - { - map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ); - } - else - { - map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ); - } - - if( mImpl->mEventData->mPlaceholderEllipsisFlag ) - { - map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(); - } - } + PlaceholderHandler::GetPlaceholderProperty(*this, map); } Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection() @@ -2594,165 +1826,20 @@ void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlign Controller::UpdateTextType Controller::Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false" ); - - UpdateTextType updateTextType = NONE_UPDATED; - - if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) ) - { - if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() ) - { - mImpl->mModel->mVisualModel->mGlyphPositions.Clear(); - updateTextType = MODEL_UPDATED; - } + return Relayouter::Relayout(*this, size, layoutDirection); +} - // Clear the update info. This info will be set the next time the text is updated. - mImpl->mTextUpdateInfo.Clear(); +void Controller::RequestRelayout() +{ + mImpl->RequestRelayout(); +} - // Not worth to relayout if width or height is equal to zero. - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" ); +// public : Input style change signals. - return updateTextType; - } - - // Whether a new size has been set. - const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize ); - - if( newSize ) - { - 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 | - ALIGN | - UPDATE_LAYOUT_SIZE | - REORDER ); - // Set the update info to relayout the whole text. - mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true; - mImpl->mTextUpdateInfo.mCharacterIndex = 0u; - - // Store the size used to layout the text. - mImpl->mModel->mVisualModel->mControlSize = size; - } - - // Whether there are modify events. - if( 0u != mImpl->mModifyEvents.Count() ) - { - // Style operations that need to be done if the text is modified. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - 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; - } - - if( mImpl->mModel->mMatchSystemLanguageDirection && mImpl->mLayoutDirection != layoutDirection ) - { - // Clear the update info. This info will be set the next time the text is updated. - mImpl->mTextUpdateInfo.mClearAll = true; - // Apply modifications to the model - // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - GET_GLYPH_METRICS | - SHAPE_TEXT | - UPDATE_DIRECTION | - LAYOUT | - BIDI_INFO | - REORDER ); - mImpl->mLayoutDirection = layoutDirection; - } - - // Make sure the model is up-to-date before layouting. - ProcessModifyEvents(); - bool updated = mImpl->UpdateModel( mImpl->mOperationsPending ); - - // Layout the text. - Size layoutSize; - updated = DoRelayout( size, - mImpl->mOperationsPending, - layoutSize ) || updated; - - - if( updated ) - { - updateTextType = MODEL_UPDATED; - } - - // Do not re-do any operation until something changes. - mImpl->mOperationsPending = NO_OPERATION; - mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition; - - // Whether the text control is editable - const bool isEditable = NULL != mImpl->mEventData; - - // Keep the current offset as it will be used to update the decorator's positions (if the size changes). - Vector2 offset; - if( newSize && isEditable ) - { - offset = mImpl->mModel->mScrollPosition; - } - - if( !isEditable || !IsMultiLineEnabled() ) - { - // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated. - CalculateVerticalOffset( size ); - } - - if( isEditable ) - { - if( newSize ) - { - // If there is a new size, the scroll position needs to be clamped. - mImpl->ClampHorizontalScroll( layoutSize ); - - // Update the decorator's positions is needed if there is a new size. - mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset ); - } - - // Move the cursor, grab handle etc. - if( mImpl->ProcessInputEvents() ) - { - updateTextType = static_cast( updateTextType | DECORATOR_UPDATED ); - } - } - - // Clear the update info. This info will be set the next time the text is updated. - mImpl->mTextUpdateInfo.Clear(); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" ); - - return updateTextType; -} - -void Controller::RequestRelayout() -{ - mImpl->RequestRelayout(); -} - -// public : Input style change signals. - -bool Controller::IsInputStyleChangedSignalsQueueEmpty() -{ - return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() ); -} +bool Controller::IsInputStyleChangedSignalsQueueEmpty() +{ + return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() ); +} void Controller::ProcessInputStyleChangedSignals() { @@ -2783,417 +1870,37 @@ void Controller::ProcessInputStyleChangedSignals() void Controller::KeyboardFocusGainEvent() { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" ); - - if( NULL != mImpl->mEventData ) - { - if( ( EventData::INACTIVE == mImpl->mEventData->mState ) || - ( EventData::INTERRUPTED == mImpl->mEventData->mState ) ) - { - mImpl->ChangeState( EventData::EDITING ); - mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered. - mImpl->mEventData->mUpdateInputStyle = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - mImpl->NotifyInputMethodContextMultiLineStatus(); - if( mImpl->IsShowingPlaceholderText() ) - { - // Show alternative placeholder-text when editing - ShowPlaceholderText(); - } - - mImpl->RequestRelayout(); - } + EventHandler::KeyboardFocusGainEvent(*this); } void Controller::KeyboardFocusLostEvent() { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" ); - - if( NULL != mImpl->mEventData ) - { - if( EventData::INTERRUPTED != mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::INACTIVE ); - - if( !mImpl->IsShowingRealText() ) - { - // Revert to regular placeholder-text when not editing - ShowPlaceholderText(); - } - } - } - mImpl->RequestRelayout(); + EventHandler::KeyboardFocusLostEvent(*this); } bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" ); - - bool textChanged = false; - bool relayoutNeeded = false; - - if( ( NULL != mImpl->mEventData ) && - ( keyEvent.GetState() == KeyEvent::DOWN ) ) - { - int keyCode = keyEvent.GetKeyCode(); - const std::string& keyString = keyEvent.GetKeyString(); - const std::string keyName = keyEvent.GetKeyName(); - - const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() ); - - // Pre-process to separate modifying events from non-modifying input events. - if( isNullKey ) - { - // In some platforms arrive key events with no key code. - // Do nothing. - return false; - } - else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode ) - { - // Do nothing - return false; - } - else if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode ) || - ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) ) - { - // If don't have any text, do nothing. - if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) - { - return false; - } - - uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition; - uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition ); - 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 && !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::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode ) - { - // 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() && !keyEvent.IsShiftModifier()) - { - bool consumed = false; - if (keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME) - { - // Ctrl-C or Ctrl+Insert 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; - } - else if (keyName == KEY_A_NAME) - { - // Ctrl-A to select All the text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::SELECT_ALL ); - 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; - } - else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) || - IsKey( keyEvent, Dali::DALI_KEY_MENU ) || - IsKey( keyEvent, Dali::DALI_KEY_HOME ) ) - { - // Power key/Menu/Home key behaviour does not allow edit mode to resume. - mImpl->ChangeState( EventData::INACTIVE ); - - // Will request for relayout. - relayoutNeeded = true; - - // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. - } - else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) ) - { - // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled - // and a character is typed after the type of a upper case latin character. - - // Do nothing. - return false; - } - else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) ) - { - // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. - // Do nothing. - return false; - } - else - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() ); - if (!IsEditable()) return false; - - if( !keyString.empty() ) - { - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - - InsertText( keyString, COMMIT ); - - textChanged = true; - - // Will request for relayout. - relayoutNeeded = true; - } - - } - - if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) && - ( mImpl->mEventData->mState != EventData::INACTIVE ) && - ( !isNullKey ) && - ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) && - ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) && - ( Dali::DALI_KEY_VOLUME_UP != keyCode ) && - ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) ) - { - // Should not change the state if the key is the shift send by the InputMethodContext. - // Otherwise, when the state is SELECTING the text controller can't send the right - // surrounding info to the InputMethodContext. - mImpl->ChangeState( EventData::EDITING ); - - // Will request for relayout. - relayoutNeeded = true; - } - - if( relayoutNeeded ) - { - mImpl->RequestRelayout(); - } - } - - if( textChanged && - ( NULL != mImpl->mEditableControlInterface ) ) - { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); - } - - return true; + return EventHandler::KeyEvent(*this, keyEvent); } void Controller::TapEvent( unsigned int tapCount, float x, float y ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" ); - - if( NULL != mImpl->mEventData ) - { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState ); - EventData::State state( mImpl->mEventData->mState ); - bool relayoutNeeded( false ); // to avoid unnecessary relayouts when tapping an empty text-field - - if( mImpl->IsClipboardVisible() ) - { - if( EventData::INACTIVE == state || EventData::EDITING == state) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); - } - relayoutNeeded = true; - } - else if( 1u == tapCount ) - { - if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state ) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); // If Popup shown hide it here so can be shown again if required. - } - - if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) ) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); - relayoutNeeded = true; - } - else - { - if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() ) - { - // Hide placeholder text - ResetText(); - } - - if( EventData::INACTIVE == state ) - { - mImpl->ChangeState( EventData::EDITING ); - } - else if( !mImpl->IsClipboardEmpty() ) - { - mImpl->ChangeState( EventData::EDITING_WITH_POPUP ); - } - relayoutNeeded = true; - } - } - else if( 2u == tapCount ) - { - if( mImpl->mEventData->mSelectionEnabled && - mImpl->IsShowingRealText() ) - { - relayoutNeeded = true; - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - } - } - - // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated - if( relayoutNeeded ) - { - Event event( Event::TAP_EVENT ); - event.p1.mUint = tapCount; - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } - } - - // Reset keyboard as tap event has occurred. - mImpl->ResetInputMethodContext(); + EventHandler::TapEvent(*this, tapCount, x, y); } void Controller::PanEvent( GestureState state, const Vector2& displacement ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" ); - - if( NULL != mImpl->mEventData ) - { - Event event( Event::PAN_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = displacement.x; - event.p3.mFloat = displacement.y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } + EventHandler::PanEvent(*this, state, displacement); } -void Controller::LongPressEvent( GestureState state, float x, float y ) +void Controller::LongPressEvent( GestureState state, float x, float y ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" ); - - if( ( state == GestureState::STARTED ) && - ( NULL != mImpl->mEventData ) ) - { - // The 1st long-press on inactive text-field is treated as tap - if( EventData::INACTIVE == mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::EDITING ); - - Event event( Event::TAP_EVENT ); - event.p1.mUint = 1; - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } - else if( !mImpl->IsShowingRealText() ) - { - Event event( Event::LONG_PRESS_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - mImpl->RequestRelayout(); - } - else if( !mImpl->IsClipboardVisible() ) - { - // Reset the InputMethodContext to commit the pre-edit before selecting the text. - mImpl->ResetInputMethodContext(); - - Event event( Event::LONG_PRESS_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - mImpl->RequestRelayout(); - - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - } - } + EventHandler::LongPressEvent(*this, state, x, y); } void Controller::SelectEvent( float x, float y, SelectionType selectType ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); - - if( NULL != mImpl->mEventData ) - { - if( selectType == SelectionType::ALL ) - { - Event event( Event::SELECT_ALL ); - mImpl->mEventData->mEventQueue.push_back( event ); - } - else if( selectType == SelectionType::NONE ) - { - Event event( Event::SELECT_NONE ); - mImpl->mEventData->mEventQueue.push_back( event ); - } - else - { - Event event( Event::SELECT ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - } - - mImpl->mEventData->mCheckScrollAmount = true; - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - mImpl->RequestRelayout(); - } + EventHandler::SelectEvent(*this, x, y, selectType); } void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end) @@ -3214,144 +1921,56 @@ Uint32Pair Controller::GetTextSelectionRange() const return mImpl->GetTextSelectionRange(); } -InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) +CharacterIndex Controller::GetPrimaryCursorPosition() const { - // Whether the text needs to be relaid-out. - bool requestRelayout = false; - - // Whether to retrieve the text and cursor position to be sent to the InputMethodContext. - bool retrieveText = false; - bool retrieveCursor = false; - - switch( inputMethodContextEvent.eventName ) - { - case InputMethodContext::COMMIT: - { - InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT ); - requestRelayout = true; - retrieveCursor = true; - break; - } - case InputMethodContext::PRE_EDIT: - { - InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT ); - requestRelayout = true; - retrieveCursor = true; - break; - } - case InputMethodContext::DELETE_SURROUNDING: - { - const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset, - inputMethodContextEvent.numberOfChars, - DONT_UPDATE_INPUT_STYLE ); - - if( textDeleted ) - { - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - - requestRelayout = true; - } - break; - } - case InputMethodContext::GET_SURROUNDING: - { - retrieveText = true; - retrieveCursor = true; - break; - } - case InputMethodContext::PRIVATE_COMMAND: - { - // PRIVATECOMMAND event is just for getting the private command message - retrieveText = true; - retrieveCursor = true; - break; - } - case InputMethodContext::VOID: - { - // do nothing - break; - } - } // end switch - - if( requestRelayout ) - { - mImpl->mOperationsPending = ALL_OPERATIONS; - mImpl->RequestRelayout(); - } - - std::string text; - CharacterIndex cursorPosition = 0u; - Length numberOfWhiteSpaces = 0u; + return mImpl->GetPrimaryCursorPosition(); +} - if( retrieveCursor ) +bool Controller::SetPrimaryCursorPosition( CharacterIndex index ) +{ + if( mImpl->mEventData ) { - numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u ); - - cursorPosition = mImpl->GetLogicalCursorPosition(); - - if( cursorPosition < numberOfWhiteSpaces ) - { - cursorPosition = 0u; - } - else + mImpl->mEventData->mCheckScrollAmount = true; + mImpl->mEventData->mIsLeftHandleSelected = true; + mImpl->mEventData->mIsRightHandleSelected = true; + mImpl->mEventData->mCheckScrollAmount = true; + if( mImpl->SetPrimaryCursorPosition(index) ) { - cursorPosition -= numberOfWhiteSpaces; + KeyboardFocusGainEvent(); + return true; } } + return false; +} - if( retrieveText ) - { - 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 = ""; - } - } +void Controller::SelectWholeText() +{ + SelectEvent( 0.f, 0.f, SelectionType::ALL ); +} - InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); +void Controller::SelectNone() +{ + SelectEvent( 0.f, 0.f, SelectionType::NONE ); +} - if( requestRelayout && - ( NULL != mImpl->mEditableControlInterface ) ) +string Controller::GetSelectedText() const +{ + string text; + if( EventData::SELECTING == mImpl->mEventData->mState ) { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); + mImpl->RetrieveSelection( text, false ); } + return text; +} - return callbackData; +InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) +{ + return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent); } void Controller::PasteClipboardItemEvent() { - // Retrieve the clipboard contents first - ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); - std::string stringToPaste( notifier.GetContent() ); - - // Commit the current pre-edit text; the contents of the clipboard should be appended - mImpl->ResetInputMethodContext(); - - // Temporary disable hiding clipboard - mImpl->SetClipboardHideEnable( false ); - - // Paste - PasteText( stringToPaste ); - - mImpl->SetClipboardHideEnable( true ); + EventHandler::PasteClipboardItemEvent(*this); } // protected : Inherit from Text::Decorator::ControllerInterface. @@ -3383,140 +2002,66 @@ void Controller::SetEditable( bool editable ) } } -void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y ) +void Controller::ScrollBy( Vector2 scroll ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" ); - - if( NULL != mImpl->mEventData ) + if( mImpl->mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0)) { - switch( handleType ) - { - case GRAB_HANDLE: - { - Event event( Event::GRAB_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; + const Vector2& layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize(); + const Vector2 currentScroll = mImpl->mModel->mScrollPosition; - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case LEFT_SELECTION_HANDLE: - { - Event event( Event::LEFT_SELECTION_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; + scroll.x = -scroll.x; + scroll.y = -scroll.y; - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case RIGHT_SELECTION_HANDLE: + if( fabs(scroll.x) > Math::MACHINE_EPSILON_0 ) { - Event event( Event::RIGHT_SELECTION_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; + mImpl->mModel->mScrollPosition.x += scroll.x; + mImpl->ClampHorizontalScroll( layoutSize ); } - case LEFT_SELECTION_HANDLE_MARKER: - case RIGHT_SELECTION_HANDLE_MARKER: + + if( fabs(scroll.y) > Math::MACHINE_EPSILON_0 ) { - // Markers do not move the handles. - break; + mImpl->mModel->mScrollPosition.y += scroll.y; + mImpl->ClampVerticalScroll( layoutSize ); } - case HANDLE_TYPE_COUNT: + + if (mImpl->mModel->mScrollPosition != currentScroll) { - DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" ); + mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - currentScroll ); + mImpl->RequestRelayout(); } - } - - mImpl->RequestRelayout(); } } -// protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface. - -void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button ) +float Controller::GetHorizontalScrollPosition() { - if( NULL == mImpl->mEventData ) + if( mImpl->mEventData ) { - return; + //scroll values are negative internally so we convert them to positive numbers + return -mImpl->mModel->mScrollPosition.x; } + return 0; +} - switch( button ) - { - case Toolkit::TextSelectionPopup::CUT: - { - if (!IsEditable()) return; - mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text - mImpl->mOperationsPending = ALL_OPERATIONS; - - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - - mImpl->RequestRelayout(); - - if( NULL != mImpl->mEditableControlInterface ) - { - mImpl->mEditableControlInterface->TextChanged(); - } - break; - } - case Toolkit::TextSelectionPopup::COPY: - { - mImpl->SendSelectionToClipboard( false ); // Text not modified +float Controller::GetVerticalScrollPosition() +{ + if( mImpl->mEventData ) + { + //scroll values are negative internally so we convert them to positive numbers + return -mImpl->mModel->mScrollPosition.y; + } + return 0; +} - mImpl->mEventData->mUpdateCursorPosition = true; +void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y ) +{ + EventHandler::DecorationEvent(*this, handleType, state, x, y); +} - mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup - break; - } - case Toolkit::TextSelectionPopup::PASTE: - { - mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item - break; - } - case Toolkit::TextSelectionPopup::SELECT: - { - const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR ); +// protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface. - if( mImpl->mEventData->mSelectionEnabled ) - { - // Creates a SELECT event. - SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE ); - } - break; - } - case Toolkit::TextSelectionPopup::SELECT_ALL: - { - // Creates a SELECT_ALL event - SelectEvent( 0.f, 0.f, SelectionType::ALL ); - break; - } - case Toolkit::TextSelectionPopup::CLIPBOARD: - { - mImpl->ShowClipboard(); - break; - } - case Toolkit::TextSelectionPopup::NONE: - { - // Nothing to do. - break; - } - } +void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button ) +{ + EventHandler::TextPopupButtonTouched(*this, button); } void Controller::DisplayTimeExpired() @@ -3704,7 +2249,7 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ if( addFontSizeRun ) { - fontDescriptionRun.size = static_cast( mImpl->mEventData->mInputStyle.size * 64.f ); + fontDescriptionRun.size = static_cast( mImpl->mEventData->mInputStyle.size * mImpl->mFontSizeScale * 64.f ); fontDescriptionRun.sizeDefined = true; } @@ -3715,13 +2260,17 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ // Insert at current cursor position. Vector& modifyText = mImpl->mModel->mLogicalModel->mText; + auto pos = modifyText.End(); if( cursorIndex < numberOfCharactersInModel ) { - modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + pos = modifyText.Begin() + cursorIndex; } - else + unsigned int realPos = pos - modifyText.Begin(); + modifyText.Insert( pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + + if( NULL != mImpl->mEditableControlInterface ) { - modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + mImpl->mEditableControlInterface->TextInserted( realPos, maxSizeOfNewText, text ); } // Mark the first paragraph to be updated. @@ -3887,6 +2436,13 @@ bool Controller::RemoveText( int cursorOffset, Vector::Iterator first = currentText.Begin() + cursorIndex; Vector::Iterator last = first + numberOfCharacters; + if( NULL != mImpl->mEditableControlInterface ) + { + std::string utf8; + Utf32ToUtf8( first, numberOfCharacters, utf8 ); + mImpl->mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 ); + } + currentText.Erase( first, last ); // Cursor position retreat @@ -3926,385 +2482,45 @@ bool Controller::RemoveSelectedText() return textRemoved; } -std::string Controller::GetSelectedText() -{ - std::string text; - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - mImpl->RetrieveSelection( text, false ); - } - return text; -} - // private : Relayout. bool Controller::DoRelayout( const Size& size, OperationsMask operationsRequired, Size& layoutSize ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height ); - bool viewUpdated( false ); - - // Calculate the operations to be done. - const OperationsMask operations = static_cast( mImpl->mOperationsPending & operationsRequired ); - - const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex; - const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters; - - // Get the current layout size. - layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize(); - - if( NO_OPERATION != ( LAYOUT & operations ) ) - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n"); - - // Some vectors with data needed to layout and reorder may be void - // after the first time the text has been laid out. - // Fill the vectors again. - - // Calculate the number of glyphs to layout. - const Vector& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph; - const Vector& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter; - const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin(); - const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin(); - - 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(); - - if( 0u == totalNumberOfGlyphs ) - { - if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) ) - { - mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO ); - } - - // Nothing else to do if there is no glyphs. - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" ); - return true; - } - - // Set the layout parameters. - Layout::Parameters layoutParameters( size, - mImpl->mModel); - - // Resize the vector of positions to have the same size than the vector of glyphs. - Vector& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions; - glyphPositions.Resize( totalNumberOfGlyphs ); - - // Whether the last character is a new paragraph character. - const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin(); - mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) ); - layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph; - - // The initial glyph and the number of glyphs to layout. - layoutParameters.startGlyphIndex = startGlyphIndex; - layoutParameters.numberOfGlyphs = numberOfGlyphs; - 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. - bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled; - Size newLayoutSize; - viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters, - newLayoutSize, - elideTextEnabled, - isAutoScrollEnabled ); - mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled; - - viewUpdated = viewUpdated || ( newLayoutSize != layoutSize ); - - if( viewUpdated ) - { - layoutSize = newLayoutSize; - - if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) - { - mImpl->mIsTextDirectionRTL = false; - } - - if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && !mImpl->mModel->mVisualModel->mLines.Empty() ) - { - mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction; - } - - // Sets the layout size. - if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) ) - { - mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize ); - } - } // view updated - } - - if( NO_OPERATION != ( ALIGN & operations ) ) - { - // The laid-out lines. - Vector& lines = mImpl->mModel->mVisualModel->mLines; - - CharacterIndex alignStartIndex = startIndex; - Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters; - - // the whole text needs to be full aligned. - // If you do not do a full aligned, only the last line of the multiline input is aligned. - if( mImpl->mEventData && mImpl->mEventData->mUpdateAlignment ) - { - alignStartIndex = 0u; - alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count(); - mImpl->mEventData->mUpdateAlignment = false; - } - - // Need to align with the control's size as the text may contain lines - // starting either with left to right text or right to left. - mImpl->mLayoutEngine.Align( size, - alignStartIndex, - alignRequestedNumberOfCharacters, - mImpl->mModel->mHorizontalAlignment, - lines, - mImpl->mModel->mAlignmentOffset, - mImpl->mLayoutDirection, - mImpl->mModel->mMatchSystemLanguageDirection ); - - viewUpdated = true; - } -#if defined(DEBUG_ENABLED) - std::string currentText; - GetText( currentText ); - 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; + return Relayouter::DoRelayout(*this, size, operationsRequired, layoutSize); } void Controller::CalculateVerticalOffset( const Size& controlSize ) { - Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize(); - - if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 ) - { - // Get the line height of the default font. - layoutSize.height = mImpl->GetDefaultFontLineHeight(); - } - - switch( mImpl->mModel->mVerticalAlignment ) - { - case VerticalAlignment::TOP: - { - mImpl->mModel->mScrollPosition.y = 0.f; - break; - } - case VerticalAlignment::CENTER: - { - mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment. - break; - } - case VerticalAlignment::BOTTOM: - { - mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height; - break; - } - } + Relayouter::CalculateVerticalOffset(*this, controlSize); } // private : Events. void Controller::ProcessModifyEvents() { - Vector& events = mImpl->mModifyEvents; - - if( 0u == events.Count() ) - { - // Nothing to do. - return; - } - - for( Vector::ConstIterator it = events.Begin(), - endIt = events.End(); - it != endIt; - ++it ) - { - const ModifyEvent& event = *it; - - if( ModifyEvent::TEXT_REPLACED == event.type ) - { - // A (single) replace event should come first, otherwise we wasted time processing NOOP events - DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" ); - - TextReplacedEvent(); - } - else if( ModifyEvent::TEXT_INSERTED == event.type ) - { - TextInsertedEvent(); - } - else if( ModifyEvent::TEXT_DELETED == event.type ) - { - // Placeholder-text cannot be deleted - if( !mImpl->IsShowingPlaceholderText() ) - { - TextDeletedEvent(); - } - } - } - - if( NULL != mImpl->mEventData ) - { - // 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 - events.Clear(); + EventHandler::ProcessModifyEvents(*this); } 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; + EventHandler::TextReplacedEvent(*this); } void Controller::TextInsertedEvent() { - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - mImpl->mEventData->mCheckScrollAmount = true; - - // 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; + EventHandler::TextInsertedEvent(*this); } void Controller::TextDeletedEvent() { - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - if (!IsEditable()) return; - - mImpl->mEventData->mCheckScrollAmount = true; - - // 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; + EventHandler::TextDeletedEvent(*this); } bool Controller::DeleteEvent( int keyCode ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode ); - - bool removed = false; - - if( NULL == mImpl->mEventData ) - { - return removed; - } - - if (!IsEditable()) return false; - - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - removed = RemoveSelectedText(); - } - 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 ) - { - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - } - - return removed; + return EventHandler::DeleteEvent(*this, keyCode); } // private : Helpers. @@ -4339,75 +2555,7 @@ void Controller::ResetText() void Controller::ShowPlaceholderText() { - if( mImpl->IsPlaceholderAvailable() ) - { - DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - mImpl->mEventData->mIsShowingPlaceholderText = true; - - // Disable handles when showing place-holder text - mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false ); - mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false ); - mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false ); - - const char* text( NULL ); - size_t size( 0 ); - - // TODO - Switch Placeholder text when changing state - if( ( EventData::INACTIVE != mImpl->mEventData->mState ) && - ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) ) - { - text = mImpl->mEventData->mPlaceholderTextActive.c_str(); - size = mImpl->mEventData->mPlaceholderTextActive.size(); - } - else - { - text = mImpl->mEventData->mPlaceholderTextInactive.c_str(); - size = mImpl->mEventData->mPlaceholderTextInactive.size(); - } - - mImpl->mTextUpdateInfo.mCharacterIndex = 0u; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - - // Reset model for showing placeholder. - mImpl->mModel->mLogicalModel->mText.Clear(); - mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor ); - - // Convert text into UTF-32 - Vector& utf32Characters = mImpl->mModel->mLogicalModel->mText; - utf32Characters.Resize( size ); - - // This is a bit horrible but std::string returns a (signed) char* - const uint8_t* utf8 = reinterpret_cast( text ); - - // Transform a text array encoded in utf8 into an array encoded in utf32. - // It returns the actual number of characters. - const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() ); - utf32Characters.Resize( characterCount ); - - // The characters to be added. - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount; - - // Reset the cursor position - mImpl->mEventData->mPrimaryCursorPosition = 0; - - // 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; - - // Update the rest of the model during size negotiation - mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED ); - } + PlaceholderHandler::ShowPlaceholderText(*this); } void Controller::ClearFontData() @@ -4458,6 +2606,14 @@ void Controller::ResetCursorPosition( CharacterIndex cursorIndex ) } } +CharacterIndex Controller::GetCursorPosition() +{ + if( !mImpl->mEventData ) + return 0; + + return mImpl->mEventData->mPrimaryCursorPosition; +} + void Controller::ResetScrollPosition() { if( NULL != mImpl->mEventData ) @@ -4486,23 +2642,20 @@ Actor Controller::CreateBackgroundActor() // private : Private contructors & copy operator. Controller::Controller() -: mImpl( NULL ) +: Controller(nullptr, nullptr, nullptr) { - mImpl = new Controller::Impl( nullptr, nullptr, nullptr ); } Controller::Controller( ControlInterface* controlInterface ) +:Controller( controlInterface, nullptr, nullptr) { - mImpl = new Controller::Impl( controlInterface, NULL, NULL ); } Controller::Controller( ControlInterface* controlInterface, EditableControlInterface* editableControlInterface, SelectableControlInterface* selectableControlInterface ) +: mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface)) { - mImpl = new Controller::Impl( controlInterface, - editableControlInterface, - selectableControlInterface ); } // The copy constructor and operator are left unimplemented.