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=d683c7f8ce83127c31dfe1f599fdf1f7eb714dbc;hp=9d56a0ec06b5b6f27836fe8081f1e41a3d94556f;hb=8a647e87a01c5c78451653c1264a9eea81ac9b20;hpb=35b4e8c9457acbbbb80ec297140aac9a7ade07b8 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 9d56a0e..d683c7f --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -22,48 +22,29 @@ #include #include #include -#include #include -#include -#include -#include // INTERNAL INCLUDES -#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(); 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 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"; -const unsigned int MAX_TEXT_LENGTH = 1024u * 32u; - float ConvertToEven( float value ) { int intValue(static_cast( value )); @@ -91,44 +72,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() @@ -142,10 +85,12 @@ ControllerPtr Controller::New( ControlInterface* controlInterface ) } ControllerPtr Controller::New( ControlInterface* controlInterface, - EditableControlInterface* editableControlInterface ) + EditableControlInterface* editableControlInterface, + SelectableControlInterface* selectableControlInterface ) { return ControllerPtr( new Controller( controlInterface, - editableControlInterface ) ); + editableControlInterface, + selectableControlInterface ) ); } // public : Configure the text controller. @@ -321,7 +266,7 @@ bool Controller::IsSmoothHandlePanEnabled() const void Controller::SetMaximumNumberOfCharacters( Length maxCharacters ) { - mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH ); + mImpl->mMaximumNumberOfCharacters = maxCharacters; } int Controller::GetMaximumNumberOfCharacters() @@ -591,20 +536,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 ) @@ -702,13 +639,6 @@ void Controller::SetText( const std::string& text ) utf8 = reinterpret_cast( text.c_str() ); } - // Limit the text size. If the text size is too large, crash or deadlock will occur. - if( textSize > MAX_TEXT_LENGTH ) - { - DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize ); - textSize = MAX_TEXT_LENGTH; - } - // Convert text into UTF-32 Vector& utf32Characters = mImpl->mModel->mLogicalModel->mText; utf32Characters.Resize( textSize ); @@ -780,39 +710,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 ) @@ -830,6 +733,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 ) @@ -843,6 +771,16 @@ void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily ) DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str()); mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty(); + if( mImpl->mEventData ) + { + // 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 family is updated. + } + } + // Clear the font-specific data ClearFontData(); @@ -861,29 +799,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 ) @@ -896,6 +817,16 @@ void Controller::SetDefaultFontWeight( FontWeight weight ) mImpl->mFontDefaults->mFontDescription.weight = weight; mImpl->mFontDefaults->weightDefined = true; + if( mImpl->mEventData ) + { + // 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 weight is updated. + } + } + // Clear the font-specific data ClearFontData(); @@ -924,37 +855,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 ) @@ -967,6 +878,16 @@ void Controller::SetDefaultFontWidth( FontWidth width ) mImpl->mFontDefaults->mFontDescription.width = width; mImpl->mFontDefaults->widthDefined = true; + if( mImpl->mEventData ) + { + // 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 width is updated. + } + } + // Clear the font-specific data ClearFontData(); @@ -995,37 +916,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 ) @@ -1038,6 +939,16 @@ void Controller::SetDefaultFontSlant( FontSlant slant ) mImpl->mFontDefaults->mFontDescription.slant = slant; mImpl->mFontDefaults->slantDefined = true; + if( mImpl->mEventData ) + { + // 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 slant is updated. + } + } + // Clear the font-specific data ClearFontData(); @@ -1065,37 +976,17 @@ FontSlant Controller::GetDefaultFontSlant() const void Controller::SetPlaceholderTextFontSlant( FontSlant slant ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant; - mImpl->mEventData->mPlaceholderFont->slantDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant); } bool Controller::IsPlaceholderTextFontSlantDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->slantDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this); } FontSlant Controller::GetPlaceholderTextFontSlant() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant; - } - - return TextAbstraction::FontSlant::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontSlant(*this); } void Controller::SetDefaultFontSize( float fontSize, FontSizeType type ) @@ -1127,6 +1018,16 @@ void Controller::SetDefaultFontSize( float fontSize, FontSizeType type ) } } + if( mImpl->mEventData ) + { + // 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. + } + } + // Clear the font-specific data ClearFontData(); @@ -1165,85 +1066,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 ) @@ -1269,26 +1097,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 ) @@ -1470,6 +1284,22 @@ float Controller::GetDefaultLineSpacing() const return mImpl->mLayoutEngine.GetDefaultLineSpacing(); } +bool Controller::SetDefaultLineSize( float lineSize ) +{ + if( std::fabs( lineSize - mImpl->mLayoutEngine.GetDefaultLineSize() ) > Math::MACHINE_EPSILON_1000 ) + { + mImpl->mLayoutEngine.SetDefaultLineSize(lineSize); + mImpl->mRecalculateNaturalSize = true; + return true; + } + return false; +} + +float Controller::GetDefaultLineSize() const +{ + return mImpl->mLayoutEngine.GetDefaultLineSize(); +} + void Controller::SetInputColor( const Vector4& color ) { if( NULL != mImpl->mEventData ) @@ -1519,314 +1349,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; + InputFontHandler::SetInputFontFamily(*this, fontFamily); +} - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); +const std::string& Controller::GetInputFontFamily() const +{ + return InputFontHandler::GetInputFontFamily(*this); +} - fontDescriptionRun.familyLength = fontFamily.size(); - fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; - memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength ); - fontDescriptionRun.familyDefined = true; +void Controller::SetInputFontWeight( FontWeight weight ) +{ + InputFontHandler::SetInputFontWeight(*this, weight); +} - // The memory allocated for the font family name is freed when the font description is removed from the logical model. +bool Controller::IsInputFontWeightDefined() const +{ + return InputFontHandler::IsInputFontWeightDefined(*this); +} - // 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(); +FontWeight Controller::GetInputFontWeight() const +{ + return InputFontHandler::GetInputFontWeight(*this); +} - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; +void Controller::SetInputFontWidth( FontWidth width ) +{ + InputFontHandler::SetInputFontWidth(*this, width); +} - // 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; - } - } +bool Controller::IsInputFontWidthDefined() const +{ + return InputFontHandler::IsInputFontWidthDefined(*this); } -const std::string& Controller::GetInputFontFamily() const +FontWidth Controller::GetInputFontWidth() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.familyName; - } + return InputFontHandler::GetInputFontWidth(*this); +} - // Return the default font's family if there is no EventData. - return GetDefaultFontFamily(); +void Controller::SetInputFontSlant( FontSlant slant ) +{ + InputFontHandler::SetInputFontSlant(*this, slant); } -void Controller::SetInputFontWeight( FontWeight weight ) +bool Controller::IsInputFontSlantDefined() const { - 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; - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.weight = weight; - fontDescriptionRun.weightDefined = true; - - // 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(); - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - - // 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; - } - } -} - -bool Controller::IsInputFontWeightDefined() const -{ - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isWeightDefined; - } - - return defined; -} - -FontWeight Controller::GetInputFontWeight() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.weight; - } - - return GetDefaultFontWeight(); -} - -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; - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.width = width; - fontDescriptionRun.widthDefined = true; - - // 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(); - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - - // 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; - } - } -} - -bool Controller::IsInputFontWidthDefined() const -{ - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isWidthDefined; - } - - return defined; -} - -FontWidth Controller::GetInputFontWidth() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.width; - } - - return GetDefaultFontWidth(); -} - -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; - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.slant = slant; - fontDescriptionRun.slantDefined = true; - - // 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(); - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - - // 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; - } - } -} - -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; - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.size = static_cast( size * 64.f ); - fontDescriptionRun.sizeDefined = true; - - // 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(); - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - - // 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 ) @@ -2143,7 +1726,7 @@ bool Controller::CheckForTextFit( float pointSize, Size& layoutSize ) void Controller::FitPointSizeforLayout( Size layoutSize ) { const OperationsMask operations = mImpl->mOperationsPending; - if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) ) + if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || mImpl->mTextFitContentSize != layoutSize ) { bool actualellipsis = mImpl->mModel->mElideEnabled; float minPointSize = mImpl->mTextFitMinSize; @@ -2316,107 +1899,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() @@ -2640,571 +2128,111 @@ bool Controller::IsInputStyleChangedSignalsQueueEmpty() void Controller::ProcessInputStyleChangedSignals() { if( NULL == mImpl->mEventData ) - { - // Nothing to do. - return; - } - - for( Vector::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(), - endIt = mImpl->mEventData->mInputStyleChangedQueue.End(); - it != endIt; - ++it ) - { - const InputStyle::Mask mask = *it; - - if( NULL != mImpl->mEditableControlInterface ) - { - // Emit the input style changed signal. - mImpl->mEditableControlInterface->InputStyleChanged( mask ); - } - } - - mImpl->mEventData->mInputStyleChangedQueue.Clear(); -} - -// public : Text-input Event Queuing. - -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(); - } -} - -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(); -} - -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.state == KeyEvent::Down ) ) - { - int keyCode = keyEvent.keyCode; - const std::string& keyString = keyEvent.keyPressed; - const std::string keyName = keyEvent.keyPressedName; - - 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() ) - { - 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; - } - 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( !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; -} - -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(); -} - -void Controller::PanEvent( Gesture::State state, const Vector2& displacement ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" ); - - if( NULL != mImpl->mEventData ) - { - Event event( Event::PAN_EVENT ); - event.p1.mInt = state; - event.p2.mFloat = displacement.x; - event.p3.mFloat = displacement.y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } -} - -void Controller::LongPressEvent( Gesture::State state, float x, float y ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" ); - - if( ( state == Gesture::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 = 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 = 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; - } - } -} - -void Controller::SelectEvent( float x, float y, bool selectAll ) -{ - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); - - if( NULL != mImpl->mEventData ) - { - if( selectAll ) - { - Event event( Event::SELECT_ALL ); - 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(); - } -} - -InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) -{ - // 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(); + { + // Nothing to do. + return; } - std::string text; - CharacterIndex cursorPosition = 0u; - Length numberOfWhiteSpaces = 0u; - - if( retrieveCursor ) + for( Vector::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(), + endIt = mImpl->mEventData->mInputStyleChangedQueue.End(); + it != endIt; + ++it ) { - numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u ); - - cursorPosition = mImpl->GetLogicalCursorPosition(); + const InputStyle::Mask mask = *it; - if( cursorPosition < numberOfWhiteSpaces ) - { - cursorPosition = 0u; - } - else + if( NULL != mImpl->mEditableControlInterface ) { - cursorPosition -= numberOfWhiteSpaces; + // Emit the input style changed signal. + mImpl->mEditableControlInterface->InputStyleChanged( mask ); } } - 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 = ""; - } - } + mImpl->mEventData->mInputStyleChangedQueue.Clear(); +} + +// public : Text-input Event Queuing. + +void Controller::KeyboardFocusGainEvent() +{ + EventHandler::KeyboardFocusGainEvent(*this); +} + +void Controller::KeyboardFocusLostEvent() +{ + EventHandler::KeyboardFocusLostEvent(*this); +} + +bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) +{ + return EventHandler::KeyEvent(*this, keyEvent); +} + +void Controller::TapEvent( unsigned int tapCount, float x, float y ) +{ + EventHandler::TapEvent(*this, tapCount, x, y); +} + +void Controller::PanEvent( GestureState state, const Vector2& displacement ) +{ + EventHandler::PanEvent(*this, state, displacement); +} + +void Controller::LongPressEvent( GestureState state, float x, float y ) +{ + EventHandler::LongPressEvent(*this, state, x, y); +} - InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); +void Controller::SelectEvent( float x, float y, SelectionType selectType ) +{ + EventHandler::SelectEvent(*this, x, y, selectType); +} - if( requestRelayout && - ( NULL != mImpl->mEditableControlInterface ) ) +void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end) +{ + if( mImpl->mEventData ) { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); + mImpl->mEventData->mCheckScrollAmount = true; + mImpl->mEventData->mIsLeftHandleSelected = true; + mImpl->mEventData->mIsRightHandleSelected = true; + mImpl->SetTextSelectionRange(start, end); + mImpl->RequestRelayout(); + KeyboardFocusGainEvent(); } +} - return callbackData; +Uint32Pair Controller::GetTextSelectionRange() const +{ + return mImpl->GetTextSelectionRange(); } -void Controller::PasteClipboardItemEvent() +void Controller::SelectWholeText() { - // Retrieve the clipboard contents first - ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); - std::string stringToPaste( notifier.GetContent() ); + SelectEvent( 0.f, 0.f, SelectionType::ALL ); +} - // Commit the current pre-edit text; the contents of the clipboard should be appended - mImpl->ResetInputMethodContext(); +void Controller::SelectNone() +{ + SelectEvent( 0.f, 0.f, SelectionType::NONE ); +} - // Temporary disable hiding clipboard - mImpl->SetClipboardHideEnable( false ); +string Controller::GetSelectedText() const +{ + string text; + if( EventData::SELECTING == mImpl->mEventData->mState ) + { + mImpl->RetrieveSelection( text, false ); + } + return text; +} - // Paste - PasteText( stringToPaste ); +InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) +{ + return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent); +} - mImpl->SetClipboardHideEnable( true ); +void Controller::PasteClipboardItemEvent() +{ + EventHandler::PasteClipboardItemEvent(*this); } // protected : Inherit from Text::Decorator::ControllerInterface. @@ -3222,139 +2250,30 @@ void Controller::AddDecoration( Actor& actor, bool needsClipping ) } } -void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y ) +bool Controller::IsEditable() const { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" ); + return mImpl->IsEditable(); +} - if( NULL != mImpl->mEventData ) +void Controller::SetEditable( bool editable ) +{ + mImpl->SetEditable( editable ); + if(mImpl->mEventData && mImpl->mEventData->mDecorator) { - switch( handleType ) - { - case GRAB_HANDLE: - { - Event event( Event::GRAB_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - 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; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case RIGHT_SELECTION_HANDLE: - { - 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; - } - case LEFT_SELECTION_HANDLE_MARKER: - case RIGHT_SELECTION_HANDLE_MARKER: - { - // Markers do not move the handles. - break; - } - case HANDLE_TYPE_COUNT: - { - DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" ); - } - } - - mImpl->RequestRelayout(); + mImpl->mEventData->mDecorator->SetEditable( editable ); } } +void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y ) +{ + EventHandler::DecorationEvent(*this, handleType, state, x, y); +} + // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface. void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button ) { - if( NULL == mImpl->mEventData ) - { - return; - } - - switch( button ) - { - case Toolkit::TextSelectionPopup::CUT: - { - 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 - - mImpl->mEventData->mUpdateCursorPosition = true; - - 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 ); - - if( mImpl->mEventData->mSelectionEnabled ) - { - // Creates a SELECT event. - SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false ); - } - break; - } - case Toolkit::TextSelectionPopup::SELECT_ALL: - { - // Creates a SELECT_ALL event - SelectEvent( 0.f, 0.f, true ); - break; - } - case Toolkit::TextSelectionPopup::CLIPBOARD: - { - mImpl->ShowClipboard(); - break; - } - case Toolkit::TextSelectionPopup::NONE: - { - // Nothing to do. - break; - } - } + EventHandler::TextPopupButtonTouched(*this, button); } void Controller::DisplayTimeExpired() @@ -3553,13 +2472,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. @@ -3714,11 +2637,8 @@ bool Controller::RemoveText( int cursorOffset, // it means all texts should be removed and all Preedit variables should be initialized. if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) ) { - if( mImpl->mEventData ) - { - mImpl->mEventData->mPreEditStartPosition = 0; - mImpl->mEventData->mPreEditLength = 0; - } + mImpl->ClearPreEditFlag(); + mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0; } // Updates the text style runs by removing characters. Runs with no characters are removed. @@ -3730,6 +2650,13 @@ bool Controller::RemoveText( int cursorOffset, currentText.Erase( first, last ); + if( NULL != mImpl->mEditableControlInterface ) + { + std::string utf8; + Utf32ToUtf8( first, numberOfCharacters, utf8 ); + mImpl->mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 ); + } + // Cursor position retreat oldCursorIndex = cursorIndex; @@ -3979,159 +2906,27 @@ void Controller::CalculateVerticalOffset( const Size& controlSize ) 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; - } - - 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; - } - - // 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. @@ -4285,6 +3080,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 ) @@ -4313,21 +3116,20 @@ Actor Controller::CreateBackgroundActor() // private : Private contructors & copy operator. Controller::Controller() -: mImpl( NULL ) +: Controller(nullptr, nullptr, nullptr) { - mImpl = new Controller::Impl( NULL, NULL ); } Controller::Controller( ControlInterface* controlInterface ) +:Controller( controlInterface, nullptr, nullptr) { - mImpl = new Controller::Impl( controlInterface, NULL ); } Controller::Controller( ControlInterface* controlInterface, - EditableControlInterface* editableControlInterface ) + EditableControlInterface* editableControlInterface, + SelectableControlInterface* selectableControlInterface ) +: mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface)) { - mImpl = new Controller::Impl( controlInterface, - editableControlInterface ); } // The copy constructor and operator are left unimplemented.