2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/text/text-controller.h>
25 #include <dali/integration-api/debug.h>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/markup-processor.h>
30 #include <dali-toolkit/internal/text/text-controller-event-handler.h>
31 #include <dali-toolkit/internal/text/text-controller-impl.h>
32 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
33 #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
34 #include <dali-toolkit/internal/text/text-controller-relayouter.h>
35 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
44 constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
46 const std::string EMPTY_STRING("");
48 int ConvertPixelToPint( float pixel )
50 unsigned int horizontalDpi = 0u;
51 unsigned int verticalDpi = 0u;
52 Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
53 fontClient.GetDpi( horizontalDpi, verticalDpi );
55 return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
69 // public : Constructor.
71 ControllerPtr Controller::New()
73 return ControllerPtr( new Controller() );
76 ControllerPtr Controller::New( ControlInterface* controlInterface )
78 return ControllerPtr( new Controller( controlInterface ) );
81 ControllerPtr Controller::New( ControlInterface* controlInterface,
82 EditableControlInterface* editableControlInterface,
83 SelectableControlInterface* selectableControlInterface )
85 return ControllerPtr( new Controller( controlInterface,
86 editableControlInterface,
87 selectableControlInterface ) );
90 // public : Configure the text controller.
92 void Controller::EnableTextInput( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
96 delete mImpl->mEventData;
97 mImpl->mEventData = NULL;
99 // Nothing else to do.
103 if( NULL == mImpl->mEventData )
105 mImpl->mEventData = new EventData( decorator, inputMethodContext );
109 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
111 // Metrics for bitmap & vector based glyphs are different
112 mImpl->mMetrics->SetGlyphType( glyphType );
114 // Clear the font-specific data
117 mImpl->RequestRelayout();
120 void Controller::SetMarkupProcessorEnabled( bool enable )
122 if( enable != mImpl->mMarkupProcessorEnabled )
124 //If Text was already set, call the SetText again for enabling or disabling markup
125 mImpl->mMarkupProcessorEnabled = enable;
132 bool Controller::IsMarkupProcessorEnabled() const
134 return mImpl->mMarkupProcessorEnabled;
137 void Controller::SetAutoScrollEnabled( bool enable )
139 DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)?"true":"false", this );
141 if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
145 DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
146 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
156 DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
157 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
164 mImpl->mIsAutoScrollEnabled = enable;
165 mImpl->RequestRelayout();
169 DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
170 mImpl->mIsAutoScrollEnabled = false;
174 bool Controller::IsAutoScrollEnabled() const
176 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
178 return mImpl->mIsAutoScrollEnabled;
181 CharacterDirection Controller::GetAutoScrollDirection() const
183 return mImpl->mIsTextDirectionRTL;
186 float Controller::GetAutoScrollLineAlignment() const
190 if( mImpl->mModel->mVisualModel &&
191 ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
193 offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
199 void Controller::SetHorizontalScrollEnabled( bool enable )
201 if( ( NULL != mImpl->mEventData ) &&
202 mImpl->mEventData->mDecorator )
204 mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
207 bool Controller::IsHorizontalScrollEnabled() const
209 if( ( NULL != mImpl->mEventData ) &&
210 mImpl->mEventData->mDecorator )
212 return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
218 void Controller::SetVerticalScrollEnabled( bool enable )
220 if( ( NULL != mImpl->mEventData ) &&
221 mImpl->mEventData->mDecorator )
223 if( mImpl->mEventData->mDecorator )
225 mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
230 bool Controller::IsVerticalScrollEnabled() const
232 if( ( NULL != mImpl->mEventData ) &&
233 mImpl->mEventData->mDecorator )
235 return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
241 void Controller::SetSmoothHandlePanEnabled( bool enable )
243 if( ( NULL != mImpl->mEventData ) &&
244 mImpl->mEventData->mDecorator )
246 mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
250 bool Controller::IsSmoothHandlePanEnabled() const
252 if( ( NULL != mImpl->mEventData ) &&
253 mImpl->mEventData->mDecorator )
255 return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
261 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
263 mImpl->mMaximumNumberOfCharacters = maxCharacters;
266 int Controller::GetMaximumNumberOfCharacters()
268 return mImpl->mMaximumNumberOfCharacters;
271 void Controller::SetEnableCursorBlink( bool enable )
273 DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
275 if( NULL != mImpl->mEventData )
277 mImpl->mEventData->mCursorBlinkEnabled = enable;
280 mImpl->mEventData->mDecorator )
282 mImpl->mEventData->mDecorator->StopCursorBlink();
287 bool Controller::GetEnableCursorBlink() const
289 if( NULL != mImpl->mEventData )
291 return mImpl->mEventData->mCursorBlinkEnabled;
297 void Controller::SetMultiLineEnabled( bool enable )
299 const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
301 if( layout != mImpl->mLayoutEngine.GetLayout() )
303 // Set the layout type.
304 mImpl->mLayoutEngine.SetLayout( layout );
306 // Set the flags to redo the layout operations
307 const OperationsMask layoutOperations = static_cast<OperationsMask>( LAYOUT |
312 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
313 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
315 // Need to recalculate natural size
316 mImpl->mRecalculateNaturalSize = true;
318 mImpl->RequestRelayout();
322 bool Controller::IsMultiLineEnabled() const
324 return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
327 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
329 if( alignment != mImpl->mModel->mHorizontalAlignment )
331 // Set the alignment.
332 mImpl->mModel->mHorizontalAlignment = alignment;
334 // Set the flag to redo the alignment operation.
335 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
337 if( mImpl->mEventData )
339 mImpl->mEventData->mUpdateAlignment = true;
341 // Update the cursor if it's in editing mode
342 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
344 mImpl->ChangeState( EventData::EDITING );
345 mImpl->mEventData->mUpdateCursorPosition = true;
349 mImpl->RequestRelayout();
353 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
355 return mImpl->mModel->mHorizontalAlignment;
358 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
360 if( alignment != mImpl->mModel->mVerticalAlignment )
362 // Set the alignment.
363 mImpl->mModel->mVerticalAlignment = alignment;
365 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
367 mImpl->RequestRelayout();
371 VerticalAlignment::Type Controller::GetVerticalAlignment() const
373 return mImpl->mModel->mVerticalAlignment;
376 bool Controller::IsIgnoreSpacesAfterText() const
378 return mImpl->mModel->mIgnoreSpacesAfterText;
381 void Controller::SetIgnoreSpacesAfterText( bool ignore )
383 mImpl->mModel->mIgnoreSpacesAfterText = ignore;
386 bool Controller::IsMatchSystemLanguageDirection() const
388 return mImpl->mModel->mMatchSystemLanguageDirection;
391 void Controller::SetMatchSystemLanguageDirection( bool match )
393 mImpl->mModel->mMatchSystemLanguageDirection = match;
396 void Controller::SetLayoutDirection( Dali::LayoutDirection::Type layoutDirection )
398 mImpl->mLayoutDirection = layoutDirection;
401 bool Controller::IsShowingRealText() const
403 return mImpl->IsShowingRealText();
407 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
409 if( lineWrapMode != mImpl->mModel->mLineWrapMode )
411 // Set the text wrap mode.
412 mImpl->mModel->mLineWrapMode = lineWrapMode;
415 // Update Text layout for applying wrap mode
416 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
421 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
422 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
423 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
426 mImpl->RequestRelayout();
430 Text::LineWrap::Mode Controller::GetLineWrapMode() const
432 return mImpl->mModel->mLineWrapMode;
435 void Controller::SetTextElideEnabled( bool enabled )
437 mImpl->mModel->mElideEnabled = enabled;
440 bool Controller::IsTextElideEnabled() const
442 return mImpl->mModel->mElideEnabled;
445 void Controller::SetTextFitEnabled(bool enabled)
447 mImpl->mTextFitEnabled = enabled;
450 bool Controller::IsTextFitEnabled() const
452 return mImpl->mTextFitEnabled;
455 void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
461 mImpl->mTextFitMinSize = minSize;
466 mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
472 float Controller::GetTextFitMinSize() const
474 return mImpl->mTextFitMinSize;
477 void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
483 mImpl->mTextFitMaxSize = maxSize;
488 mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
494 float Controller::GetTextFitMaxSize() const
496 return mImpl->mTextFitMaxSize;
499 void Controller::SetTextFitStepSize( float step, FontSizeType type )
505 mImpl->mTextFitStepSize = step;
510 mImpl->mTextFitStepSize = ConvertPixelToPint( step );
516 float Controller::GetTextFitStepSize() const
518 return mImpl->mTextFitStepSize;
521 void Controller::SetTextFitContentSize(Vector2 size)
523 mImpl->mTextFitContentSize = size;
526 Vector2 Controller::GetTextFitContentSize() const
528 return mImpl->mTextFitContentSize;
531 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
533 PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
536 bool Controller::IsPlaceholderTextElideEnabled() const
538 return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
541 void Controller::SetSelectionEnabled( bool enabled )
543 mImpl->mEventData->mSelectionEnabled = enabled;
546 bool Controller::IsSelectionEnabled() const
548 return mImpl->mEventData->mSelectionEnabled;
551 void Controller::SetShiftSelectionEnabled( bool enabled )
553 mImpl->mEventData->mShiftSelectionFlag = enabled;
556 bool Controller::IsShiftSelectionEnabled() const
558 return mImpl->mEventData->mShiftSelectionFlag;
561 void Controller::SetGrabHandleEnabled( bool enabled )
563 mImpl->mEventData->mGrabHandleEnabled = enabled;
566 bool Controller::IsGrabHandleEnabled() const
568 return mImpl->mEventData->mGrabHandleEnabled;
571 void Controller::SetGrabHandlePopupEnabled(bool enabled)
573 mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
576 bool Controller::IsGrabHandlePopupEnabled() const
578 return mImpl->mEventData->mGrabHandlePopupEnabled;
583 void Controller::SetText( const std::string& text )
585 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
587 // Reset keyboard as text changed
588 mImpl->ResetInputMethodContext();
590 // Remove the previously set text and style.
596 CharacterIndex lastCursorIndex = 0u;
598 if( NULL != mImpl->mEventData )
600 // If popup shown then hide it by switching to Editing state
601 if( ( EventData::SELECTING == mImpl->mEventData->mState ) ||
602 ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
603 ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
604 ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
606 mImpl->ChangeState( EventData::EDITING );
612 mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
614 MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
615 mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
616 mImpl->mModel->mLogicalModel->mEmbeddedItems );
618 Length textSize = 0u;
619 const uint8_t* utf8 = NULL;
620 if( mImpl->mMarkupProcessorEnabled )
622 ProcessMarkupString( text, markupProcessData );
623 textSize = markupProcessData.markupProcessedText.size();
625 // This is a bit horrible but std::string returns a (signed) char*
626 utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
630 textSize = text.size();
632 // This is a bit horrible but std::string returns a (signed) char*
633 utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
636 // Convert text into UTF-32
637 Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
638 utf32Characters.Resize( textSize );
640 // Transform a text array encoded in utf8 into an array encoded in utf32.
641 // It returns the actual number of characters.
642 Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
643 utf32Characters.Resize( characterCount );
645 DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
646 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
648 // The characters to be added.
649 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
651 // To reset the cursor position
652 lastCursorIndex = characterCount;
654 // Update the rest of the model during size negotiation
655 mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
657 // The natural size needs to be re-calculated.
658 mImpl->mRecalculateNaturalSize = true;
660 // The text direction needs to be updated.
661 mImpl->mUpdateTextDirection = true;
663 // Apply modifications to the model
664 mImpl->mOperationsPending = ALL_OPERATIONS;
668 ShowPlaceholderText();
671 // Resets the cursor position.
672 ResetCursorPosition( lastCursorIndex );
674 // Scrolls the text to make the cursor visible.
675 ResetScrollPosition();
677 mImpl->RequestRelayout();
679 if( NULL != mImpl->mEventData )
681 // Cancel previously queued events
682 mImpl->mEventData->mEventQueue.clear();
685 // Do this last since it provides callbacks into application code.
686 if( NULL != mImpl->mEditableControlInterface )
688 mImpl->mEditableControlInterface->TextChanged();
692 void Controller::GetText( std::string& text ) const
694 if( !mImpl->IsShowingPlaceholderText() )
696 // Retrieves the text string.
697 mImpl->GetText( 0u, text );
701 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
705 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
707 PlaceholderHandler::SetPlaceholderText(*this, type, text);
710 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
712 PlaceholderHandler::GetPlaceholderText(*this, type, text );
715 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
717 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
719 if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
721 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
722 mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
726 mImpl->RequestRelayout();
730 void Controller::RetrieveSelection( std::string& selectedText ) const
732 mImpl->RetrieveSelection( selectedText, false );
735 void Controller::SetSelection( int start, int end )
737 mImpl->SetSelection( start, end );
740 std::pair< int, int > Controller::GetSelectionIndexes() const
742 return mImpl->GetSelectionIndexes();
745 void Controller::CopyStringToClipboard( const std::string& source )
747 mImpl->CopyStringToClipboard( source );
750 void Controller::SendSelectionToClipboard( bool deleteAfterSending )
752 mImpl->SendSelectionToClipboard( deleteAfterSending );
755 // public : Default style & Input style
757 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
759 if( NULL == mImpl->mFontDefaults )
761 mImpl->mFontDefaults = new FontDefaults();
764 mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
765 DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
766 mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
768 if( mImpl->mEventData )
770 // Update the cursor position if it's in editing mode
771 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
773 mImpl->mEventData->mDecoratorUpdated = true;
774 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font family is updated.
778 // Clear the font-specific data
781 mImpl->RequestRelayout();
784 const std::string& Controller::GetDefaultFontFamily() const
786 if( NULL != mImpl->mFontDefaults )
788 return mImpl->mFontDefaults->mFontDescription.family;
794 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
796 PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
799 const std::string& Controller::GetPlaceholderFontFamily() const
801 return PlaceholderHandler::GetPlaceholderFontFamily(*this);
804 void Controller::SetDefaultFontWeight( FontWeight weight )
806 if( NULL == mImpl->mFontDefaults )
808 mImpl->mFontDefaults = new FontDefaults();
811 mImpl->mFontDefaults->mFontDescription.weight = weight;
812 mImpl->mFontDefaults->weightDefined = true;
814 if( mImpl->mEventData )
816 // Update the cursor position if it's in editing mode
817 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
819 mImpl->mEventData->mDecoratorUpdated = true;
820 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font weight is updated.
824 // Clear the font-specific data
827 mImpl->RequestRelayout();
830 bool Controller::IsDefaultFontWeightDefined() const
832 if( NULL != mImpl->mFontDefaults )
834 return mImpl->mFontDefaults->weightDefined;
840 FontWeight Controller::GetDefaultFontWeight() const
842 if( NULL != mImpl->mFontDefaults )
844 return mImpl->mFontDefaults->mFontDescription.weight;
847 return TextAbstraction::FontWeight::NORMAL;
850 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
852 PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
855 bool Controller::IsPlaceholderTextFontWeightDefined() const
857 return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);;
860 FontWeight Controller::GetPlaceholderTextFontWeight() const
862 return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
865 void Controller::SetDefaultFontWidth( FontWidth width )
867 if( NULL == mImpl->mFontDefaults )
869 mImpl->mFontDefaults = new FontDefaults();
872 mImpl->mFontDefaults->mFontDescription.width = width;
873 mImpl->mFontDefaults->widthDefined = true;
875 if( mImpl->mEventData )
877 // Update the cursor position if it's in editing mode
878 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
880 mImpl->mEventData->mDecoratorUpdated = true;
881 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font width is updated.
885 // Clear the font-specific data
888 mImpl->RequestRelayout();
891 bool Controller::IsDefaultFontWidthDefined() const
893 if( NULL != mImpl->mFontDefaults )
895 return mImpl->mFontDefaults->widthDefined;
901 FontWidth Controller::GetDefaultFontWidth() const
903 if( NULL != mImpl->mFontDefaults )
905 return mImpl->mFontDefaults->mFontDescription.width;
908 return TextAbstraction::FontWidth::NORMAL;
911 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
913 PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
916 bool Controller::IsPlaceholderTextFontWidthDefined() const
918 return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
921 FontWidth Controller::GetPlaceholderTextFontWidth() const
923 return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
926 void Controller::SetDefaultFontSlant( FontSlant slant )
928 if( NULL == mImpl->mFontDefaults )
930 mImpl->mFontDefaults = new FontDefaults();
933 mImpl->mFontDefaults->mFontDescription.slant = slant;
934 mImpl->mFontDefaults->slantDefined = true;
936 if( mImpl->mEventData )
938 // Update the cursor position if it's in editing mode
939 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
941 mImpl->mEventData->mDecoratorUpdated = true;
942 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font slant is updated.
946 // Clear the font-specific data
949 mImpl->RequestRelayout();
952 bool Controller::IsDefaultFontSlantDefined() const
954 if( NULL != mImpl->mFontDefaults )
956 return mImpl->mFontDefaults->slantDefined;
961 FontSlant Controller::GetDefaultFontSlant() const
963 if( NULL != mImpl->mFontDefaults )
965 return mImpl->mFontDefaults->mFontDescription.slant;
968 return TextAbstraction::FontSlant::NORMAL;
971 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
973 PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
976 bool Controller::IsPlaceholderTextFontSlantDefined() const
978 return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
981 FontSlant Controller::GetPlaceholderTextFontSlant() const
983 return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
986 void Controller::SetFontSizeScale( float scale )
988 mImpl->mFontSizeScale = scale;
990 if( mImpl->mEventData )
992 // Update the cursor position if it's in editing mode
993 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
995 mImpl->mEventData->mDecoratorUpdated = true;
996 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
1000 // Clear the font-specific data
1003 mImpl->RequestRelayout();
1006 float Controller::GetFontSizeScale() const
1008 if( nullptr != mImpl->mFontDefaults )
1010 return mImpl->mFontSizeScale;
1016 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
1018 if( NULL == mImpl->mFontDefaults )
1020 mImpl->mFontDefaults = new FontDefaults();
1027 mImpl->mFontDefaults->mDefaultPointSize = fontSize;
1028 mImpl->mFontDefaults->sizeDefined = true;
1033 // Point size = Pixel size * 72.f / DPI
1034 unsigned int horizontalDpi = 0u;
1035 unsigned int verticalDpi = 0u;
1036 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1037 fontClient.GetDpi( horizontalDpi, verticalDpi );
1039 mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
1040 mImpl->mFontDefaults->sizeDefined = true;
1045 if( mImpl->mEventData )
1047 // Update the cursor position if it's in editing mode
1048 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
1050 mImpl->mEventData->mDecoratorUpdated = true;
1051 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
1055 // Clear the font-specific data
1058 mImpl->RequestRelayout();
1061 float Controller::GetDefaultFontSize( FontSizeType type ) const
1064 if( NULL != mImpl->mFontDefaults )
1070 value = mImpl->mFontDefaults->mDefaultPointSize;
1075 // Pixel size = Point size * DPI / 72.f
1076 unsigned int horizontalDpi = 0u;
1077 unsigned int verticalDpi = 0u;
1078 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1079 fontClient.GetDpi( horizontalDpi, verticalDpi );
1081 value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1091 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
1093 PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
1096 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1098 return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
1101 void Controller::SetDefaultColor( const Vector4& color )
1103 mImpl->mTextColor = color;
1105 if( !mImpl->IsShowingPlaceholderText() )
1107 mImpl->mModel->mVisualModel->SetTextColor( color );
1109 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
1111 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1113 mImpl->RequestRelayout();
1117 const Vector4& Controller::GetDefaultColor() const
1119 return mImpl->mTextColor;
1122 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1124 PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
1127 const Vector4& Controller::GetPlaceholderTextColor() const
1129 return PlaceholderHandler::GetPlaceholderTextColor(*this);
1132 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1134 mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1136 mImpl->RequestRelayout();
1139 const Vector2& Controller::GetShadowOffset() const
1141 return mImpl->mModel->mVisualModel->GetShadowOffset();
1144 void Controller::SetShadowColor( const Vector4& shadowColor )
1146 mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1148 mImpl->RequestRelayout();
1151 const Vector4& Controller::GetShadowColor() const
1153 return mImpl->mModel->mVisualModel->GetShadowColor();
1156 void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
1158 if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
1160 mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
1162 mImpl->RequestRelayout();
1166 const float& Controller::GetShadowBlurRadius() const
1168 return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1171 void Controller::SetUnderlineColor( const Vector4& color )
1173 mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1175 mImpl->RequestRelayout();
1178 const Vector4& Controller::GetUnderlineColor() const
1180 return mImpl->mModel->mVisualModel->GetUnderlineColor();
1183 void Controller::SetUnderlineEnabled( bool enabled )
1185 mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1187 mImpl->RequestRelayout();
1190 bool Controller::IsUnderlineEnabled() const
1192 return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1195 void Controller::SetUnderlineHeight( float height )
1197 mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1199 mImpl->RequestRelayout();
1202 float Controller::GetUnderlineHeight() const
1204 return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1207 void Controller::SetOutlineColor( const Vector4& color )
1209 mImpl->mModel->mVisualModel->SetOutlineColor( color );
1211 mImpl->RequestRelayout();
1214 const Vector4& Controller::GetOutlineColor() const
1216 return mImpl->mModel->mVisualModel->GetOutlineColor();
1219 void Controller::SetOutlineWidth( uint16_t width )
1221 mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1223 mImpl->RequestRelayout();
1226 uint16_t Controller::GetOutlineWidth() const
1228 return mImpl->mModel->mVisualModel->GetOutlineWidth();
1231 void Controller::SetBackgroundColor( const Vector4& color )
1233 mImpl->mModel->mVisualModel->SetBackgroundColor( color );
1235 mImpl->RequestRelayout();
1238 const Vector4& Controller::GetBackgroundColor() const
1240 return mImpl->mModel->mVisualModel->GetBackgroundColor();
1243 void Controller::SetBackgroundEnabled( bool enabled )
1245 mImpl->mModel->mVisualModel->SetBackgroundEnabled( enabled );
1247 mImpl->RequestRelayout();
1250 bool Controller::IsBackgroundEnabled() const
1252 return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
1255 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1257 if( NULL == mImpl->mEmbossDefaults )
1259 mImpl->mEmbossDefaults = new EmbossDefaults();
1262 mImpl->mEmbossDefaults->properties = embossProperties;
1265 const std::string& Controller::GetDefaultEmbossProperties() const
1267 if( NULL != mImpl->mEmbossDefaults )
1269 return mImpl->mEmbossDefaults->properties;
1272 return EMPTY_STRING;
1275 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1277 if( NULL == mImpl->mOutlineDefaults )
1279 mImpl->mOutlineDefaults = new OutlineDefaults();
1282 mImpl->mOutlineDefaults->properties = outlineProperties;
1285 const std::string& Controller::GetDefaultOutlineProperties() const
1287 if( NULL != mImpl->mOutlineDefaults )
1289 return mImpl->mOutlineDefaults->properties;
1292 return EMPTY_STRING;
1295 bool Controller::SetDefaultLineSpacing( float lineSpacing )
1297 if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
1299 mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
1300 mImpl->mRecalculateNaturalSize = true;
1306 float Controller::GetDefaultLineSpacing() const
1308 return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1311 bool Controller::SetDefaultLineSize( float lineSize )
1313 if( std::fabs( lineSize - mImpl->mLayoutEngine.GetDefaultLineSize() ) > Math::MACHINE_EPSILON_1000 )
1315 mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
1316 mImpl->mRecalculateNaturalSize = true;
1322 float Controller::GetDefaultLineSize() const
1324 return mImpl->mLayoutEngine.GetDefaultLineSize();
1327 void Controller::SetInputColor( const Vector4& color )
1329 if( NULL != mImpl->mEventData )
1331 mImpl->mEventData->mInputStyle.textColor = color;
1332 mImpl->mEventData->mInputStyle.isDefaultColor = false;
1334 if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1336 const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1338 // Get start and end position of selection
1339 const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1340 const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1342 // Add the color run.
1343 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1344 mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1346 ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1347 colorRun.color = color;
1348 colorRun.characterRun.characterIndex = startOfSelectedText;
1349 colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1351 // Request to relayout.
1352 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1353 mImpl->RequestRelayout();
1355 mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1356 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1357 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1362 const Vector4& Controller::GetInputColor() const
1364 if( NULL != mImpl->mEventData )
1366 return mImpl->mEventData->mInputStyle.textColor;
1369 // Return the default text's color if there is no EventData.
1370 return mImpl->mTextColor;
1374 void Controller::SetInputFontFamily( const std::string& fontFamily )
1376 InputFontHandler::SetInputFontFamily(*this, fontFamily);
1379 const std::string& Controller::GetInputFontFamily() const
1381 return InputFontHandler::GetInputFontFamily(*this);
1384 void Controller::SetInputFontWeight( FontWeight weight )
1386 InputFontHandler::SetInputFontWeight(*this, weight);
1389 bool Controller::IsInputFontWeightDefined() const
1391 return InputFontHandler::IsInputFontWeightDefined(*this);
1394 FontWeight Controller::GetInputFontWeight() const
1396 return InputFontHandler::GetInputFontWeight(*this);
1399 void Controller::SetInputFontWidth( FontWidth width )
1401 InputFontHandler::SetInputFontWidth(*this, width);
1404 bool Controller::IsInputFontWidthDefined() const
1406 return InputFontHandler::IsInputFontWidthDefined(*this);
1409 FontWidth Controller::GetInputFontWidth() const
1411 return InputFontHandler::GetInputFontWidth(*this);
1414 void Controller::SetInputFontSlant( FontSlant slant )
1416 InputFontHandler::SetInputFontSlant(*this, slant);
1419 bool Controller::IsInputFontSlantDefined() const
1421 return InputFontHandler::IsInputFontSlantDefined(*this);
1424 FontSlant Controller::GetInputFontSlant() const
1426 return InputFontHandler::GetInputFontSlant(*this);
1429 void Controller::SetInputFontPointSize( float size )
1431 InputFontHandler::SetInputFontPointSize(*this, size);
1434 float Controller::GetInputFontPointSize() const
1436 return InputFontHandler::GetInputFontPointSize(*this);
1439 void Controller::SetInputLineSpacing( float lineSpacing )
1441 if( NULL != mImpl->mEventData )
1443 mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1444 mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1448 float Controller::GetInputLineSpacing() const
1450 if( NULL != mImpl->mEventData )
1452 return mImpl->mEventData->mInputStyle.lineSpacing;
1458 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1460 if( NULL != mImpl->mEventData )
1462 mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1466 const std::string& Controller::GetInputShadowProperties() const
1468 if( NULL != mImpl->mEventData )
1470 return mImpl->mEventData->mInputStyle.shadowProperties;
1473 return EMPTY_STRING;
1476 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1478 if( NULL != mImpl->mEventData )
1480 mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1484 const std::string& Controller::GetInputUnderlineProperties() const
1486 if( NULL != mImpl->mEventData )
1488 return mImpl->mEventData->mInputStyle.underlineProperties;
1491 return EMPTY_STRING;
1494 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1496 if( NULL != mImpl->mEventData )
1498 mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1502 const std::string& Controller::GetInputEmbossProperties() const
1504 if( NULL != mImpl->mEventData )
1506 return mImpl->mEventData->mInputStyle.embossProperties;
1509 return GetDefaultEmbossProperties();
1512 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1514 if( NULL != mImpl->mEventData )
1516 mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1520 const std::string& Controller::GetInputOutlineProperties() const
1522 if( NULL != mImpl->mEventData )
1524 return mImpl->mEventData->mInputStyle.outlineProperties;
1527 return GetDefaultOutlineProperties();
1530 void Controller::SetInputModePassword( bool passwordInput )
1532 if( NULL != mImpl->mEventData )
1534 mImpl->mEventData->mPasswordInput = passwordInput;
1538 bool Controller::IsInputModePassword()
1540 if( NULL != mImpl->mEventData )
1542 return mImpl->mEventData->mPasswordInput;
1547 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1549 if( NULL != mImpl->mEventData )
1551 mImpl->mEventData->mDoubleTapAction = action;
1555 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1557 NoTextTap::Action action = NoTextTap::NO_ACTION;
1559 if( NULL != mImpl->mEventData )
1561 action = mImpl->mEventData->mDoubleTapAction;
1567 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1569 if( NULL != mImpl->mEventData )
1571 mImpl->mEventData->mLongPressAction = action;
1575 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1577 NoTextTap::Action action = NoTextTap::NO_ACTION;
1579 if( NULL != mImpl->mEventData )
1581 action = mImpl->mEventData->mLongPressAction;
1587 bool Controller::IsUnderlineSetByString()
1589 return mImpl->mUnderlineSetByString;
1592 void Controller::UnderlineSetByString( bool setByString )
1594 mImpl->mUnderlineSetByString = setByString;
1597 bool Controller::IsShadowSetByString()
1599 return mImpl->mShadowSetByString;
1602 void Controller::ShadowSetByString( bool setByString )
1604 mImpl->mShadowSetByString = setByString;
1607 bool Controller::IsOutlineSetByString()
1609 return mImpl->mOutlineSetByString;
1612 void Controller::OutlineSetByString( bool setByString )
1614 mImpl->mOutlineSetByString = setByString;
1617 bool Controller::IsFontStyleSetByString()
1619 return mImpl->mFontStyleSetByString;
1622 void Controller::FontStyleSetByString( bool setByString )
1624 mImpl->mFontStyleSetByString = setByString;
1627 // public : Queries & retrieves.
1629 Layout::Engine& Controller::GetLayoutEngine()
1631 return mImpl->mLayoutEngine;
1634 View& Controller::GetView()
1636 return mImpl->mView;
1639 Vector3 Controller::GetNaturalSize()
1641 return Relayouter::GetNaturalSize(*this);
1644 bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
1646 return Relayouter::CheckForTextFit(*this, pointSize, layoutSize);
1649 void Controller::FitPointSizeforLayout( Size layoutSize )
1651 const OperationsMask operations = mImpl->mOperationsPending;
1652 if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || mImpl->mTextFitContentSize != layoutSize )
1654 bool actualellipsis = mImpl->mModel->mElideEnabled;
1655 float minPointSize = mImpl->mTextFitMinSize;
1656 float maxPointSize = mImpl->mTextFitMaxSize;
1657 float pointInterval = mImpl->mTextFitStepSize;
1659 mImpl->mModel->mElideEnabled = false;
1660 Vector<float> pointSizeArray;
1663 if( pointInterval < 1.f )
1665 mImpl->mTextFitStepSize = pointInterval = 1.0f;
1668 pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
1670 for( float i = minPointSize; i < maxPointSize; i += pointInterval )
1672 pointSizeArray.PushBack( i );
1675 pointSizeArray.PushBack( maxPointSize );
1677 int bestSizeIndex = 0;
1678 int min = bestSizeIndex + 1;
1679 int max = pointSizeArray.Size() - 1;
1682 int destI = ( min + max ) / 2;
1684 if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
1686 bestSizeIndex = min;
1692 bestSizeIndex = max;
1696 mImpl->mModel->mElideEnabled = actualellipsis;
1697 mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
1698 mImpl->mFontDefaults->sizeDefined = true;
1703 float Controller::GetHeightForWidth( float width )
1705 return Relayouter::GetHeightForWidth(*this, width);
1708 int Controller::GetLineCount( float width )
1710 GetHeightForWidth( width );
1711 int numberofLines = mImpl->mModel->GetNumberOfLines();
1712 return numberofLines;
1715 const ModelInterface* const Controller::GetTextModel() const
1717 return mImpl->mModel.Get();
1720 float Controller::GetScrollAmountByUserInput()
1722 float scrollAmount = 0.0f;
1724 if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1726 scrollAmount = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
1727 mImpl->mEventData->mCheckScrollAmount = false;
1729 return scrollAmount;
1732 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1734 const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1737 controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1738 layoutHeight = layout.height;
1739 scrollPosition = mImpl->mModel->mScrollPosition.y;
1740 isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1744 void Controller::SetHiddenInputOption(const Property::Map& options)
1746 if( NULL == mImpl->mHiddenInput )
1748 mImpl->mHiddenInput = new HiddenText( this );
1750 mImpl->mHiddenInput->SetProperties(options);
1753 void Controller::GetHiddenInputOption(Property::Map& options)
1755 if( NULL != mImpl->mHiddenInput )
1757 mImpl->mHiddenInput->GetProperties(options);
1761 void Controller::SetPlaceholderProperty( const Property::Map& map )
1763 PlaceholderHandler::SetPlaceholderProperty(*this, map);
1766 void Controller::GetPlaceholderProperty( Property::Map& map )
1768 PlaceholderHandler::GetPlaceholderProperty(*this, map);
1771 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1773 // Make sure the model is up-to-date before layouting
1774 ProcessModifyEvents();
1776 if ( mImpl->mUpdateTextDirection )
1778 // Operations that can be done only once until the text changes.
1779 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1785 GET_GLYPH_METRICS );
1787 // Set the update info to relayout the whole text.
1788 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1789 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1791 // Make sure the model is up-to-date before layouting
1792 mImpl->UpdateModel( onlyOnceOperations );
1794 Vector3 naturalSize;
1795 DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1796 static_cast<OperationsMask>( onlyOnceOperations |
1797 LAYOUT | REORDER | UPDATE_DIRECTION ),
1798 naturalSize.GetVectorXY() );
1800 // Do not do again the only once operations.
1801 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1803 // Clear the update info. This info will be set the next time the text is updated.
1804 mImpl->mTextUpdateInfo.Clear();
1806 // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1807 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1809 mImpl->mUpdateTextDirection = false;
1812 return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1815 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1817 return mImpl->mModel->GetVerticalLineAlignment();
1820 void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment )
1822 mImpl->mModel->mVerticalLineAlignment = alignment;
1825 // public : Relayout.
1827 Controller::UpdateTextType Controller::Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection )
1829 return Relayouter::Relayout(*this, size, layoutDirection);
1832 void Controller::RequestRelayout()
1834 mImpl->RequestRelayout();
1837 // public : Input style change signals.
1839 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
1841 return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
1844 void Controller::ProcessInputStyleChangedSignals()
1846 if( NULL == mImpl->mEventData )
1852 for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
1853 endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
1857 const InputStyle::Mask mask = *it;
1859 if( NULL != mImpl->mEditableControlInterface )
1861 // Emit the input style changed signal.
1862 mImpl->mEditableControlInterface->InputStyleChanged( mask );
1866 mImpl->mEventData->mInputStyleChangedQueue.Clear();
1869 // public : Text-input Event Queuing.
1871 void Controller::KeyboardFocusGainEvent()
1873 EventHandler::KeyboardFocusGainEvent(*this);
1876 void Controller::KeyboardFocusLostEvent()
1878 EventHandler::KeyboardFocusLostEvent(*this);
1881 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1883 return EventHandler::KeyEvent(*this, keyEvent);
1886 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1888 EventHandler::TapEvent(*this, tapCount, x, y);
1891 void Controller::PanEvent( GestureState state, const Vector2& displacement )
1893 EventHandler::PanEvent(*this, state, displacement);
1896 void Controller::LongPressEvent( GestureState state, float x, float y )
1898 EventHandler::LongPressEvent(*this, state, x, y);
1901 void Controller::SelectEvent( float x, float y, SelectionType selectType )
1903 EventHandler::SelectEvent(*this, x, y, selectType);
1906 void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end)
1908 if( mImpl->mEventData )
1910 mImpl->mEventData->mCheckScrollAmount = true;
1911 mImpl->mEventData->mIsLeftHandleSelected = true;
1912 mImpl->mEventData->mIsRightHandleSelected = true;
1913 mImpl->SetTextSelectionRange(start, end);
1914 mImpl->RequestRelayout();
1915 KeyboardFocusGainEvent();
1919 Uint32Pair Controller::GetTextSelectionRange() const
1921 return mImpl->GetTextSelectionRange();
1924 CharacterIndex Controller::GetPrimaryCursorPosition() const
1926 return mImpl->GetPrimaryCursorPosition();
1929 bool Controller::SetPrimaryCursorPosition( CharacterIndex index )
1931 if( mImpl->mEventData )
1933 mImpl->mEventData->mCheckScrollAmount = true;
1934 mImpl->mEventData->mIsLeftHandleSelected = true;
1935 mImpl->mEventData->mIsRightHandleSelected = true;
1936 mImpl->mEventData->mCheckScrollAmount = true;
1937 if( mImpl->SetPrimaryCursorPosition(index) )
1939 KeyboardFocusGainEvent();
1946 void Controller::SelectWholeText()
1948 SelectEvent( 0.f, 0.f, SelectionType::ALL );
1951 void Controller::SelectNone()
1953 SelectEvent( 0.f, 0.f, SelectionType::NONE );
1956 string Controller::GetSelectedText() const
1959 if( EventData::SELECTING == mImpl->mEventData->mState )
1961 mImpl->RetrieveSelection( text, false );
1966 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
1968 return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
1971 void Controller::PasteClipboardItemEvent()
1973 EventHandler::PasteClipboardItemEvent(*this);
1976 // protected : Inherit from Text::Decorator::ControllerInterface.
1978 void Controller::GetTargetSize( Vector2& targetSize )
1980 targetSize = mImpl->mModel->mVisualModel->mControlSize;
1983 void Controller::AddDecoration( Actor& actor, bool needsClipping )
1985 if( NULL != mImpl->mEditableControlInterface )
1987 mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
1991 bool Controller::IsEditable() const
1993 return mImpl->IsEditable();
1996 void Controller::SetEditable( bool editable )
1998 mImpl->SetEditable( editable );
1999 if(mImpl->mEventData && mImpl->mEventData->mDecorator)
2001 mImpl->mEventData->mDecorator->SetEditable( editable );
2005 void Controller::ScrollBy( Vector2 scroll )
2007 if( mImpl->mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
2009 const Vector2& layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2010 const Vector2 currentScroll = mImpl->mModel->mScrollPosition;
2012 scroll.x = -scroll.x;
2013 scroll.y = -scroll.y;
2015 if( fabs(scroll.x) > Math::MACHINE_EPSILON_0 )
2017 mImpl->mModel->mScrollPosition.x += scroll.x;
2018 mImpl->ClampHorizontalScroll( layoutSize );
2021 if( fabs(scroll.y) > Math::MACHINE_EPSILON_0 )
2023 mImpl->mModel->mScrollPosition.y += scroll.y;
2024 mImpl->ClampVerticalScroll( layoutSize );
2027 if (mImpl->mModel->mScrollPosition != currentScroll)
2029 mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - currentScroll );
2030 mImpl->RequestRelayout();
2035 float Controller::GetHorizontalScrollPosition()
2037 if( mImpl->mEventData )
2039 //scroll values are negative internally so we convert them to positive numbers
2040 return -mImpl->mModel->mScrollPosition.x;
2045 float Controller::GetVerticalScrollPosition()
2047 if( mImpl->mEventData )
2049 //scroll values are negative internally so we convert them to positive numbers
2050 return -mImpl->mModel->mScrollPosition.y;
2055 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2057 EventHandler::DecorationEvent(*this, handleType, state, x, y);
2060 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2062 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2064 EventHandler::TextPopupButtonTouched(*this, button);
2067 void Controller::DisplayTimeExpired()
2069 mImpl->mEventData->mUpdateCursorPosition = true;
2070 // Apply modifications to the model
2071 mImpl->mOperationsPending = ALL_OPERATIONS;
2073 mImpl->RequestRelayout();
2076 // private : Update.
2078 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2080 bool removedPrevious = false;
2081 bool removedSelected = false;
2082 bool maxLengthReached = false;
2084 DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2086 if( NULL == mImpl->mEventData )
2091 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2092 this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2093 mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2095 // TODO: At the moment the underline runs are only for pre-edit.
2096 mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2098 // Remove the previous InputMethodContext pre-edit.
2099 if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2101 removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2102 mImpl->mEventData->mPreEditLength,
2103 DONT_UPDATE_INPUT_STYLE );
2105 mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2106 mImpl->mEventData->mPreEditLength = 0u;
2110 // Remove the previous Selection.
2111 removedSelected = RemoveSelectedText();
2115 Vector<Character> utf32Characters;
2116 Length characterCount = 0u;
2120 // Convert text into UTF-32
2121 utf32Characters.Resize( text.size() );
2123 // This is a bit horrible but std::string returns a (signed) char*
2124 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2126 // Transform a text array encoded in utf8 into an array encoded in utf32.
2127 // It returns the actual number of characters.
2128 characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2129 utf32Characters.Resize( characterCount );
2131 DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2132 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2135 if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2137 // The placeholder text is no longer needed
2138 if( mImpl->IsShowingPlaceholderText() )
2143 mImpl->ChangeState( EventData::EDITING );
2145 // Handle the InputMethodContext (predicitive text) state changes
2146 if( COMMIT == type )
2148 // InputMethodContext is no longer handling key-events
2149 mImpl->ClearPreEditFlag();
2153 if( !mImpl->mEventData->mPreEditFlag )
2155 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2157 // Record the start of the pre-edit text
2158 mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2161 mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2162 mImpl->mEventData->mPreEditFlag = true;
2164 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2167 const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2169 // Restrict new text to fit within Maximum characters setting.
2170 Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2171 maxLengthReached = ( characterCount > maxSizeOfNewText );
2173 // The cursor position.
2174 CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2176 // Update the text's style.
2178 // Updates the text style runs by adding characters.
2179 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2181 // Get the character index from the cursor index.
2182 const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2184 // Retrieve the text's style for the given index.
2186 mImpl->RetrieveDefaultInputStyle( style );
2187 mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
2189 // Whether to add a new text color run.
2190 const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor;
2192 // Whether to add a new font run.
2193 const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined;
2194 const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined;
2195 const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined;
2196 const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined;
2197 const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ;
2202 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2203 mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2205 ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2206 colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2207 colorRun.characterRun.characterIndex = cursorIndex;
2208 colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2211 if( addFontNameRun ||
2217 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2218 mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2220 FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
2222 if( addFontNameRun )
2224 fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2225 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2226 memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
2227 fontDescriptionRun.familyDefined = true;
2229 // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2232 if( addFontWeightRun )
2234 fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2235 fontDescriptionRun.weightDefined = true;
2238 if( addFontWidthRun )
2240 fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2241 fontDescriptionRun.widthDefined = true;
2244 if( addFontSlantRun )
2246 fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2247 fontDescriptionRun.slantDefined = true;
2250 if( addFontSizeRun )
2252 fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * mImpl->mFontSizeScale * 64.f );
2253 fontDescriptionRun.sizeDefined = true;
2256 fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2257 fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2260 // Insert at current cursor position.
2261 Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2263 auto pos = modifyText.End();
2264 if( cursorIndex < numberOfCharactersInModel )
2266 pos = modifyText.Begin() + cursorIndex;
2268 unsigned int realPos = pos - modifyText.Begin();
2269 modifyText.Insert( pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2271 if( NULL != mImpl->mEditableControlInterface )
2273 mImpl->mEditableControlInterface->TextInserted( realPos, maxSizeOfNewText, text );
2276 // Mark the first paragraph to be updated.
2277 if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
2279 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2280 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2281 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
2282 mImpl->mTextUpdateInfo.mClearAll = true;
2286 mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2287 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2290 // Update the cursor index.
2291 cursorIndex += maxSizeOfNewText;
2293 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
2296 if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
2297 mImpl->IsPlaceholderAvailable() )
2299 // Show place-holder if empty after removing the pre-edit text
2300 ShowPlaceholderText();
2301 mImpl->mEventData->mUpdateCursorPosition = true;
2302 mImpl->ClearPreEditFlag();
2304 else if( removedPrevious ||
2306 ( 0 != utf32Characters.Count() ) )
2308 // Queue an inserted event
2309 mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2311 mImpl->mEventData->mUpdateCursorPosition = true;
2312 if( removedSelected )
2314 mImpl->mEventData->mScrollAfterDelete = true;
2318 mImpl->mEventData->mScrollAfterUpdatePosition = true;
2322 if( maxLengthReached )
2324 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
2326 mImpl->ResetInputMethodContext();
2328 if( NULL != mImpl->mEditableControlInterface )
2330 // Do this last since it provides callbacks into application code
2331 mImpl->mEditableControlInterface->MaxLengthReached();
2336 void Controller::PasteText( const std::string& stringToPaste )
2338 InsertText( stringToPaste, Text::Controller::COMMIT );
2339 mImpl->ChangeState( EventData::EDITING );
2340 mImpl->RequestRelayout();
2342 if( NULL != mImpl->mEditableControlInterface )
2344 // Do this last since it provides callbacks into application code
2345 mImpl->mEditableControlInterface->TextChanged();
2349 bool Controller::RemoveText( int cursorOffset,
2350 int numberOfCharacters,
2351 UpdateInputStyleType type )
2353 bool removed = false;
2355 if( NULL == mImpl->mEventData )
2360 DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
2361 this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
2363 if( !mImpl->IsShowingPlaceholderText() )
2365 // Delete at current cursor position
2366 Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
2367 CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2369 CharacterIndex cursorIndex = 0;
2371 // Validate the cursor position & number of characters
2372 if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
2374 cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2377 if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
2379 numberOfCharacters = currentText.Count() - cursorIndex;
2382 if( mImpl->mEventData->mPreEditFlag || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
2383 ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
2385 // Mark the paragraphs to be updated.
2386 if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
2388 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2389 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2390 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
2391 mImpl->mTextUpdateInfo.mClearAll = true;
2395 mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2396 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2399 // Update the input style and remove the text's style before removing the text.
2401 if( UPDATE_INPUT_STYLE == type )
2403 // Keep a copy of the current input style.
2404 InputStyle currentInputStyle;
2405 currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
2407 // Set first the default input style.
2408 mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
2410 // Update the input style.
2411 mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
2413 // Compare if the input style has changed.
2414 const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
2416 if( hasInputStyleChanged )
2418 const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
2419 // Queue the input style changed signal.
2420 mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
2424 // If the number of current text and the number of characters to be deleted are same,
2425 // it means all texts should be removed and all Preedit variables should be initialized.
2426 if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) )
2428 mImpl->ClearPreEditFlag();
2429 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
2432 // Updates the text style runs by removing characters. Runs with no characters are removed.
2433 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
2435 // Remove the characters.
2436 Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2437 Vector<Character>::Iterator last = first + numberOfCharacters;
2439 if( NULL != mImpl->mEditableControlInterface )
2442 Utf32ToUtf8( first, numberOfCharacters, utf8 );
2443 mImpl->mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 );
2446 currentText.Erase( first, last );
2448 // Cursor position retreat
2449 oldCursorIndex = cursorIndex;
2451 mImpl->mEventData->mScrollAfterDelete = true;
2453 if( EventData::INACTIVE == mImpl->mEventData->mState )
2455 mImpl->ChangeState( EventData::EDITING );
2458 DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
2466 bool Controller::RemoveSelectedText()
2468 bool textRemoved( false );
2470 if( EventData::SELECTING == mImpl->mEventData->mState )
2472 std::string removedString;
2473 mImpl->RetrieveSelection( removedString, true );
2475 if( !removedString.empty() )
2478 mImpl->ChangeState( EventData::EDITING );
2485 // private : Relayout.
2487 bool Controller::DoRelayout( const Size& size,
2488 OperationsMask operationsRequired,
2491 return Relayouter::DoRelayout(*this, size, operationsRequired, layoutSize);
2494 void Controller::CalculateVerticalOffset( const Size& controlSize )
2496 Relayouter::CalculateVerticalOffset(*this, controlSize);
2499 // private : Events.
2501 void Controller::ProcessModifyEvents()
2503 EventHandler::ProcessModifyEvents(*this);
2506 void Controller::TextReplacedEvent()
2508 EventHandler::TextReplacedEvent(*this);
2511 void Controller::TextInsertedEvent()
2513 EventHandler::TextInsertedEvent(*this);
2516 void Controller::TextDeletedEvent()
2518 EventHandler::TextDeletedEvent(*this);
2521 bool Controller::DeleteEvent( int keyCode )
2523 return EventHandler::DeleteEvent(*this, keyCode);
2526 // private : Helpers.
2528 void Controller::ResetText()
2531 mImpl->mModel->mLogicalModel->mText.Clear();
2533 // Reset the embedded images buffer.
2534 mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
2536 // We have cleared everything including the placeholder-text
2537 mImpl->PlaceholderCleared();
2539 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2540 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2541 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
2543 // Clear any previous text.
2544 mImpl->mTextUpdateInfo.mClearAll = true;
2546 // The natural size needs to be re-calculated.
2547 mImpl->mRecalculateNaturalSize = true;
2549 // The text direction needs to be updated.
2550 mImpl->mUpdateTextDirection = true;
2552 // Apply modifications to the model
2553 mImpl->mOperationsPending = ALL_OPERATIONS;
2556 void Controller::ShowPlaceholderText()
2558 PlaceholderHandler::ShowPlaceholderText(*this);
2561 void Controller::ClearFontData()
2563 if( mImpl->mFontDefaults )
2565 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2568 // Set flags to update the model.
2569 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2570 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2571 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
2573 mImpl->mTextUpdateInfo.mClearAll = true;
2574 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2575 mImpl->mRecalculateNaturalSize = true;
2577 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2583 UPDATE_LAYOUT_SIZE |
2588 void Controller::ClearStyleData()
2590 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
2591 mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
2594 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
2596 // Reset the cursor position
2597 if( NULL != mImpl->mEventData )
2599 mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
2601 // Update the cursor if it's in editing mode.
2602 if( EventData::IsEditingState( mImpl->mEventData->mState ) )
2604 mImpl->mEventData->mUpdateCursorPosition = true;
2609 CharacterIndex Controller::GetCursorPosition()
2611 if( !mImpl->mEventData )
2614 return mImpl->mEventData->mPrimaryCursorPosition;
2617 void Controller::ResetScrollPosition()
2619 if( NULL != mImpl->mEventData )
2621 // Reset the scroll position.
2622 mImpl->mModel->mScrollPosition = Vector2::ZERO;
2623 mImpl->mEventData->mScrollAfterUpdatePosition = true;
2627 void Controller::SetControlInterface( ControlInterface* controlInterface )
2629 mImpl->mControlInterface = controlInterface;
2632 bool Controller::ShouldClearFocusOnEscape() const
2634 return mImpl->mShouldClearFocusOnEscape;
2637 Actor Controller::CreateBackgroundActor()
2639 return mImpl->CreateBackgroundActor();
2642 // private : Private contructors & copy operator.
2644 Controller::Controller()
2645 : Controller(nullptr, nullptr, nullptr)
2649 Controller::Controller( ControlInterface* controlInterface )
2650 :Controller( controlInterface, nullptr, nullptr)
2654 Controller::Controller( ControlInterface* controlInterface,
2655 EditableControlInterface* editableControlInterface,
2656 SelectableControlInterface* selectableControlInterface )
2657 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface))
2661 // The copy constructor and operator are left unimplemented.
2663 // protected : Destructor.
2665 Controller::~Controller()
2672 } // namespace Toolkit