88940b5487ed6e9e4a99b259bade6cea995f40f6
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <memory.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
27 #include <dali/devel-api/text-abstraction/font-client.h>
28 #include <dali/devel-api/adaptor-framework/key-devel.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
32 #include <dali-toolkit/internal/text/bidirectional-support.h>
33 #include <dali-toolkit/internal/text/character-set-conversion.h>
34 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
35 #include <dali-toolkit/internal/text/markup-processor.h>
36 #include <dali-toolkit/internal/text/multi-language-support.h>
37 #include <dali-toolkit/internal/text/text-controller-impl.h>
38 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
39 #include <dali-toolkit/internal/text/text-font-style.h>
40
41 namespace
42 {
43
44 #if defined(DEBUG_ENABLED)
45   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
46 #endif
47
48 const int MAX_NUMBER_OF_CHARACTERS = 200000;
49
50 const float MAX_FLOAT = std::numeric_limits<float>::max();
51
52 const std::string EMPTY_STRING("");
53
54 const std::string KEY_C_NAME = "c";
55 const std::string KEY_V_NAME = "v";
56 const std::string KEY_X_NAME = "x";
57
58 const char * const PLACEHOLDER_TEXT = "text";
59 const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
60 const char * const PLACEHOLDER_COLOR = "color";
61 const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily";
62 const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
63 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
64 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
65 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
66
67 float ConvertToEven( float value )
68 {
69   int intValue(static_cast<int>( value ));
70   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
71 }
72
73 } // namespace
74
75 namespace Dali
76 {
77
78 namespace Toolkit
79 {
80
81 namespace Text
82 {
83
84 /**
85  * @brief Adds a new font description run for the selected text.
86  *
87  * The new font parameters are added after the call to this method.
88  *
89  * @param[in] eventData The event data pointer.
90  * @param[in] logicalModel The logical model where to add the new font description run.
91  * @param[out] startOfSelectedText Index to the first selected character.
92  * @param[out] lengthOfSelectedText Number of selected characters.
93  */
94 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
95                                                  LogicalModelPtr logicalModel,
96                                                  CharacterIndex& startOfSelectedText,
97                                                  Length& lengthOfSelectedText )
98 {
99   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
100
101   // Get start and end position of selection
102   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
103   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
104
105   // Add the font run.
106   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
107   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
108
109   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
110
111   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
112   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
113
114   // Recalculate the selection highlight as the metrics may have changed.
115   eventData->mUpdateLeftSelectionPosition = true;
116   eventData->mUpdateRightSelectionPosition = true;
117   eventData->mUpdateHighlightBox = true;
118
119   return fontDescriptionRun;
120 }
121
122 // public : Constructor.
123
124 ControllerPtr Controller::New()
125 {
126   return ControllerPtr( new Controller() );
127 }
128
129 ControllerPtr Controller::New( ControlInterface* controlInterface )
130 {
131   return ControllerPtr( new Controller( controlInterface ) );
132 }
133
134 ControllerPtr Controller::New( ControlInterface* controlInterface,
135                                EditableControlInterface* editableControlInterface )
136 {
137   return ControllerPtr( new Controller( controlInterface,
138                                         editableControlInterface ) );
139 }
140
141 // public : Configure the text controller.
142
143 void Controller::EnableTextInput( DecoratorPtr decorator )
144 {
145   if( !decorator )
146   {
147     delete mImpl->mEventData;
148     mImpl->mEventData = NULL;
149
150     // Nothing else to do.
151     return;
152   }
153
154   if( NULL == mImpl->mEventData )
155   {
156     mImpl->mEventData = new EventData( decorator );
157   }
158 }
159
160 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
161 {
162   // Metrics for bitmap & vector based glyphs are different
163   mImpl->mMetrics->SetGlyphType( glyphType );
164
165   // Clear the font-specific data
166   ClearFontData();
167
168   mImpl->RequestRelayout();
169 }
170
171 void Controller::SetMarkupProcessorEnabled( bool enable )
172 {
173   mImpl->mMarkupProcessorEnabled = enable;
174   if( enable )
175   {
176     //If Text was already set, call the SetText again for enabling markup
177     std::string text;
178     GetText( text );
179     SetText( text );
180   }
181 }
182
183 bool Controller::IsMarkupProcessorEnabled() const
184 {
185   return mImpl->mMarkupProcessorEnabled;
186 }
187
188 void Controller::SetAutoScrollEnabled( bool enable )
189 {
190   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 );
191
192   if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
193   {
194     if( enable )
195     {
196       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
197       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
198                                                                LAYOUT                    |
199                                                                ALIGN                     |
200                                                                UPDATE_LAYOUT_SIZE        |
201                                                                UPDATE_DIRECTION          |
202                                                                REORDER );
203
204     }
205     else
206     {
207       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
208       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
209                                                                LAYOUT                    |
210                                                                ALIGN                     |
211                                                                UPDATE_LAYOUT_SIZE        |
212                                                                REORDER );
213     }
214
215     mImpl->mIsAutoScrollEnabled = enable;
216     mImpl->RequestRelayout();
217   }
218   else
219   {
220     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
221     mImpl->mIsAutoScrollEnabled = false;
222   }
223 }
224
225 bool Controller::IsAutoScrollEnabled() const
226 {
227   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
228
229   return mImpl->mIsAutoScrollEnabled;
230 }
231
232 CharacterDirection Controller::GetAutoScrollDirection() const
233 {
234   return mImpl->mAutoScrollDirectionRTL;
235 }
236
237 float Controller::GetAutoScrollLineAlignment() const
238 {
239   float offset = 0.f;
240
241   if( mImpl->mModel->mVisualModel &&
242       ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
243   {
244     offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
245   }
246
247   return offset;
248 }
249
250 void Controller::SetHorizontalScrollEnabled( bool enable )
251 {
252   if( ( NULL != mImpl->mEventData ) &&
253       mImpl->mEventData->mDecorator )
254   {
255     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
256   }
257 }
258 bool Controller::IsHorizontalScrollEnabled() const
259 {
260   if( ( NULL != mImpl->mEventData ) &&
261       mImpl->mEventData->mDecorator )
262   {
263     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
264   }
265
266   return false;
267 }
268
269 void Controller::SetVerticalScrollEnabled( bool enable )
270 {
271   if( ( NULL != mImpl->mEventData ) &&
272       mImpl->mEventData->mDecorator )
273   {
274     if( mImpl->mEventData->mDecorator )
275     {
276       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
277     }
278   }
279 }
280
281 bool Controller::IsVerticalScrollEnabled() const
282 {
283   if( ( NULL != mImpl->mEventData ) &&
284       mImpl->mEventData->mDecorator )
285   {
286     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
287   }
288
289   return false;
290 }
291
292 void Controller::SetSmoothHandlePanEnabled( bool enable )
293 {
294   if( ( NULL != mImpl->mEventData ) &&
295       mImpl->mEventData->mDecorator )
296   {
297     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
298   }
299 }
300
301 bool Controller::IsSmoothHandlePanEnabled() const
302 {
303   if( ( NULL != mImpl->mEventData ) &&
304       mImpl->mEventData->mDecorator )
305   {
306     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
307   }
308
309   return false;
310 }
311
312 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
313 {
314   mImpl->mMaximumNumberOfCharacters = maxCharacters;
315 }
316
317 int Controller::GetMaximumNumberOfCharacters()
318 {
319   return mImpl->mMaximumNumberOfCharacters;
320 }
321
322 void Controller::SetEnableCursorBlink( bool enable )
323 {
324   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
325
326   if( NULL != mImpl->mEventData )
327   {
328     mImpl->mEventData->mCursorBlinkEnabled = enable;
329
330     if( !enable &&
331         mImpl->mEventData->mDecorator )
332     {
333       mImpl->mEventData->mDecorator->StopCursorBlink();
334     }
335   }
336 }
337
338 bool Controller::GetEnableCursorBlink() const
339 {
340   if( NULL != mImpl->mEventData )
341   {
342     return mImpl->mEventData->mCursorBlinkEnabled;
343   }
344
345   return false;
346 }
347
348 void Controller::SetMultiLineEnabled( bool enable )
349 {
350   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
351
352   if( layout != mImpl->mLayoutEngine.GetLayout() )
353   {
354     // Set the layout type.
355     mImpl->mLayoutEngine.SetLayout( layout );
356
357     // Set the flags to redo the layout operations
358     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
359                                                                           UPDATE_LAYOUT_SIZE |
360                                                                           ALIGN              |
361                                                                           REORDER );
362
363     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
364     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
365
366     mImpl->RequestRelayout();
367   }
368 }
369
370 bool Controller::IsMultiLineEnabled() const
371 {
372   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
373 }
374
375 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
376 {
377   if( alignment != mImpl->mModel->mHorizontalAlignment )
378   {
379     // Set the alignment.
380     mImpl->mModel->mHorizontalAlignment = alignment;
381
382     // Set the flag to redo the alignment operation.
383     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
384
385     mImpl->RequestRelayout();
386   }
387 }
388
389 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
390 {
391   return mImpl->mModel->mHorizontalAlignment;
392 }
393
394 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
395 {
396   if( alignment != mImpl->mModel->mVerticalAlignment )
397   {
398     // Set the alignment.
399     mImpl->mModel->mVerticalAlignment = alignment;
400
401     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
402
403     mImpl->RequestRelayout();
404   }
405 }
406
407 VerticalAlignment::Type Controller::GetVerticalAlignment() const
408 {
409   return mImpl->mModel->mVerticalAlignment;
410 }
411
412 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
413 {
414   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
415   {
416     // Set the text wrap mode.
417     mImpl->mModel->mLineWrapMode = lineWrapMode;
418
419
420     // Update Text layout for applying wrap mode
421     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
422                                                              ALIGN                     |
423                                                              LAYOUT                    |
424                                                              UPDATE_LAYOUT_SIZE        |
425                                                              REORDER                   );
426     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
427     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
428     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
429
430     // Request relayout
431     mImpl->RequestRelayout();
432   }
433 }
434
435 Text::LineWrap::Mode Controller::GetLineWrapMode() const
436 {
437   return mImpl->mModel->mLineWrapMode;
438 }
439
440 void Controller::SetTextElideEnabled( bool enabled )
441 {
442   mImpl->mModel->mElideEnabled = enabled;
443 }
444
445 bool Controller::IsTextElideEnabled() const
446 {
447   return mImpl->mModel->mElideEnabled;
448 }
449
450 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
451 {
452   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
453   mImpl->mEventData->mPlaceholderEllipsisFlag = true;
454
455   // Update placeholder if there is no text
456   if( mImpl->IsShowingPlaceholderText() ||
457       ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
458   {
459     ShowPlaceholderText();
460   }
461 }
462
463 bool Controller::IsPlaceholderTextElideEnabled() const
464 {
465   return mImpl->mEventData->mIsPlaceholderElideEnabled;
466 }
467
468 void Controller::SetSelectionEnabled( bool enabled )
469 {
470   mImpl->mEventData->mSelectionEnabled = enabled;
471 }
472
473 bool Controller::IsSelectionEnabled() const
474 {
475   return mImpl->mEventData->mSelectionEnabled;
476 }
477
478 void Controller::SetShiftSelectionEnabled( bool enabled )
479 {
480   mImpl->mEventData->mShiftSelectionFlag = enabled;
481 }
482
483 bool Controller::IsShiftSelectionEnabled() const
484 {
485   return mImpl->mEventData->mShiftSelectionFlag;
486 }
487
488 // public : Update
489
490 void Controller::SetText( const std::string& text )
491 {
492   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
493
494   // Reset keyboard as text changed
495   mImpl->ResetImfManager();
496
497   // Remove the previously set text and style.
498   ResetText();
499
500   // Remove the style.
501   ClearStyleData();
502
503   CharacterIndex lastCursorIndex = 0u;
504
505   if( NULL != mImpl->mEventData )
506   {
507     // If popup shown then hide it by switching to Editing state
508     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
509         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
510         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
511         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
512     {
513       mImpl->ChangeState( EventData::EDITING );
514     }
515   }
516
517   if( !text.empty() )
518   {
519     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
520
521     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
522                                          mImpl->mModel->mLogicalModel->mFontDescriptionRuns );
523
524     Length textSize = 0u;
525     const uint8_t* utf8 = NULL;
526     if( mImpl->mMarkupProcessorEnabled )
527     {
528       ProcessMarkupString( text, markupProcessData );
529       textSize = markupProcessData.markupProcessedText.size();
530
531       // This is a bit horrible but std::string returns a (signed) char*
532       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
533     }
534     else
535     {
536       textSize = text.size();
537
538       // This is a bit horrible but std::string returns a (signed) char*
539       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
540     }
541
542     //  Convert text into UTF-32
543     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
544     utf32Characters.Resize( textSize );
545
546     // Transform a text array encoded in utf8 into an array encoded in utf32.
547     // It returns the actual number of characters.
548     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
549     utf32Characters.Resize( characterCount );
550
551     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
552     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
553
554     // The characters to be added.
555     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
556
557     // To reset the cursor position
558     lastCursorIndex = characterCount;
559
560     // Update the rest of the model during size negotiation
561     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
562
563     // The natural size needs to be re-calculated.
564     mImpl->mRecalculateNaturalSize = true;
565
566     // Apply modifications to the model
567     mImpl->mOperationsPending = ALL_OPERATIONS;
568   }
569   else
570   {
571     ShowPlaceholderText();
572   }
573
574   // Resets the cursor position.
575   ResetCursorPosition( lastCursorIndex );
576
577   // Scrolls the text to make the cursor visible.
578   ResetScrollPosition();
579
580   mImpl->RequestRelayout();
581
582   if( NULL != mImpl->mEventData )
583   {
584     // Cancel previously queued events
585     mImpl->mEventData->mEventQueue.clear();
586   }
587
588   // Do this last since it provides callbacks into application code.
589   if( NULL != mImpl->mEditableControlInterface )
590   {
591     mImpl->mEditableControlInterface->TextChanged();
592   }
593 }
594
595 void Controller::GetText( std::string& text ) const
596 {
597   if( !mImpl->IsShowingPlaceholderText() )
598   {
599     // Retrieves the text string.
600     mImpl->GetText( 0u, text );
601   }
602   else
603   {
604     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
605   }
606 }
607
608 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
609 {
610   if( NULL != mImpl->mEventData )
611   {
612     if( PLACEHOLDER_TYPE_INACTIVE == type )
613     {
614       mImpl->mEventData->mPlaceholderTextInactive = text;
615     }
616     else
617     {
618       mImpl->mEventData->mPlaceholderTextActive = text;
619     }
620
621     // Update placeholder if there is no text
622     if( mImpl->IsShowingPlaceholderText() ||
623         ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
624     {
625       ShowPlaceholderText();
626     }
627   }
628 }
629
630 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
631 {
632   if( NULL != mImpl->mEventData )
633   {
634     if( PLACEHOLDER_TYPE_INACTIVE == type )
635     {
636       text = mImpl->mEventData->mPlaceholderTextInactive;
637     }
638     else
639     {
640       text = mImpl->mEventData->mPlaceholderTextActive;
641     }
642   }
643 }
644
645 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
646 {
647   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
648
649   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
650   {
651     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
652     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
653
654     ClearFontData();
655
656     mImpl->RequestRelayout();
657   }
658 }
659
660 // public : Default style & Input style
661
662 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
663 {
664   if( NULL == mImpl->mFontDefaults )
665   {
666     mImpl->mFontDefaults = new FontDefaults();
667   }
668
669   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
670   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
671   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
672
673   // Clear the font-specific data
674   ClearFontData();
675
676   mImpl->RequestRelayout();
677 }
678
679 const std::string& Controller::GetDefaultFontFamily() const
680 {
681   if( NULL != mImpl->mFontDefaults )
682   {
683     return mImpl->mFontDefaults->mFontDescription.family;
684   }
685
686   return EMPTY_STRING;
687 }
688
689 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
690 {
691   if( NULL != mImpl->mEventData )
692   {
693     if( NULL == mImpl->mEventData->mPlaceholderFont )
694     {
695       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
696     }
697
698     mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
699     DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
700     mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
701
702     mImpl->RequestRelayout();
703   }
704 }
705
706 const std::string& Controller::GetPlaceholderFontFamily() const
707 {
708   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
709   {
710     return mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
711   }
712
713   return EMPTY_STRING;
714 }
715
716 void Controller::SetDefaultFontWeight( FontWeight weight )
717 {
718   if( NULL == mImpl->mFontDefaults )
719   {
720     mImpl->mFontDefaults = new FontDefaults();
721   }
722
723   mImpl->mFontDefaults->mFontDescription.weight = weight;
724   mImpl->mFontDefaults->weightDefined = true;
725
726   // Clear the font-specific data
727   ClearFontData();
728
729   mImpl->RequestRelayout();
730 }
731
732 bool Controller::IsDefaultFontWeightDefined() const
733 {
734   if( NULL != mImpl->mFontDefaults )
735   {
736     return mImpl->mFontDefaults->weightDefined;
737   }
738
739   return false;
740 }
741
742 FontWeight Controller::GetDefaultFontWeight() const
743 {
744   if( NULL != mImpl->mFontDefaults )
745   {
746     return mImpl->mFontDefaults->mFontDescription.weight;
747   }
748
749   return TextAbstraction::FontWeight::NORMAL;
750 }
751
752 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
753 {
754   if( NULL != mImpl->mEventData )
755   {
756     if( NULL == mImpl->mEventData->mPlaceholderFont )
757     {
758       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
759     }
760
761     mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
762     mImpl->mEventData->mPlaceholderFont->weightDefined = true;
763
764     mImpl->RequestRelayout();
765   }
766 }
767
768 bool Controller::IsPlaceholderTextFontWeightDefined() const
769 {
770   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
771   {
772     return mImpl->mEventData->mPlaceholderFont->weightDefined;
773   }
774   return false;
775 }
776
777 FontWeight Controller::GetPlaceholderTextFontWeight() const
778 {
779   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
780   {
781     return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
782   }
783
784   return TextAbstraction::FontWeight::NORMAL;
785 }
786
787 void Controller::SetDefaultFontWidth( FontWidth width )
788 {
789   if( NULL == mImpl->mFontDefaults )
790   {
791     mImpl->mFontDefaults = new FontDefaults();
792   }
793
794   mImpl->mFontDefaults->mFontDescription.width = width;
795   mImpl->mFontDefaults->widthDefined = true;
796
797   // Clear the font-specific data
798   ClearFontData();
799
800   mImpl->RequestRelayout();
801 }
802
803 bool Controller::IsDefaultFontWidthDefined() const
804 {
805   if( NULL != mImpl->mFontDefaults )
806   {
807     return mImpl->mFontDefaults->widthDefined;
808   }
809
810   return false;
811 }
812
813 FontWidth Controller::GetDefaultFontWidth() const
814 {
815   if( NULL != mImpl->mFontDefaults )
816   {
817     return mImpl->mFontDefaults->mFontDescription.width;
818   }
819
820   return TextAbstraction::FontWidth::NORMAL;
821 }
822
823 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
824 {
825   if( NULL != mImpl->mEventData )
826   {
827     if( NULL == mImpl->mEventData->mPlaceholderFont )
828     {
829       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
830     }
831
832     mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
833     mImpl->mEventData->mPlaceholderFont->widthDefined = true;
834
835     mImpl->RequestRelayout();
836   }
837 }
838
839 bool Controller::IsPlaceholderTextFontWidthDefined() const
840 {
841   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
842   {
843     return mImpl->mEventData->mPlaceholderFont->widthDefined;
844   }
845   return false;
846 }
847
848 FontWidth Controller::GetPlaceholderTextFontWidth() const
849 {
850   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
851   {
852     return mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
853   }
854
855   return TextAbstraction::FontWidth::NORMAL;
856 }
857
858 void Controller::SetDefaultFontSlant( FontSlant slant )
859 {
860   if( NULL == mImpl->mFontDefaults )
861   {
862     mImpl->mFontDefaults = new FontDefaults();
863   }
864
865   mImpl->mFontDefaults->mFontDescription.slant = slant;
866   mImpl->mFontDefaults->slantDefined = true;
867
868   // Clear the font-specific data
869   ClearFontData();
870
871   mImpl->RequestRelayout();
872 }
873
874 bool Controller::IsDefaultFontSlantDefined() const
875 {
876   if( NULL != mImpl->mFontDefaults )
877   {
878     return mImpl->mFontDefaults->slantDefined;
879   }
880   return false;
881 }
882
883 FontSlant Controller::GetDefaultFontSlant() const
884 {
885   if( NULL != mImpl->mFontDefaults )
886   {
887     return mImpl->mFontDefaults->mFontDescription.slant;
888   }
889
890   return TextAbstraction::FontSlant::NORMAL;
891 }
892
893 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
894 {
895   if( NULL != mImpl->mEventData )
896   {
897     if( NULL == mImpl->mEventData->mPlaceholderFont )
898     {
899       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
900     }
901
902     mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
903     mImpl->mEventData->mPlaceholderFont->slantDefined = true;
904
905     mImpl->RequestRelayout();
906   }
907 }
908
909 bool Controller::IsPlaceholderTextFontSlantDefined() const
910 {
911   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
912   {
913     return mImpl->mEventData->mPlaceholderFont->slantDefined;
914   }
915   return false;
916 }
917
918 FontSlant Controller::GetPlaceholderTextFontSlant() const
919 {
920   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
921   {
922     return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
923   }
924
925   return TextAbstraction::FontSlant::NORMAL;
926 }
927
928 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
929 {
930   if( NULL == mImpl->mFontDefaults )
931   {
932     mImpl->mFontDefaults = new FontDefaults();
933   }
934
935   switch( type )
936   {
937     case POINT_SIZE:
938     {
939       mImpl->mFontDefaults->mDefaultPointSize = fontSize;
940       mImpl->mFontDefaults->sizeDefined = true;
941       break;
942     }
943     case PIXEL_SIZE:
944     {
945       // Point size = Pixel size * 72.f / DPI
946       unsigned int horizontalDpi = 0u;
947       unsigned int verticalDpi = 0u;
948       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
949       fontClient.GetDpi( horizontalDpi, verticalDpi );
950
951       mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
952       mImpl->mFontDefaults->sizeDefined = true;
953       break;
954     }
955   }
956
957   // Clear the font-specific data
958   ClearFontData();
959
960   mImpl->RequestRelayout();
961 }
962
963 float Controller::GetDefaultFontSize( FontSizeType type ) const
964 {
965   float value = 0.0f;
966   if( NULL != mImpl->mFontDefaults )
967   {
968     switch( type )
969     {
970       case POINT_SIZE:
971       {
972         value = mImpl->mFontDefaults->mDefaultPointSize;
973         break;
974       }
975       case PIXEL_SIZE:
976       {
977         // Pixel size = Point size * DPI / 72.f
978         unsigned int horizontalDpi = 0u;
979         unsigned int verticalDpi = 0u;
980         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
981         fontClient.GetDpi( horizontalDpi, verticalDpi );
982
983         value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
984         break;
985       }
986     }
987     return value;
988   }
989
990   return value;
991 }
992
993 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
994 {
995   if( NULL != mImpl->mEventData )
996   {
997     if( NULL == mImpl->mEventData->mPlaceholderFont )
998     {
999       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
1000     }
1001
1002     switch( type )
1003     {
1004       case POINT_SIZE:
1005       {
1006         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
1007         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
1008         mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
1009         break;
1010       }
1011       case PIXEL_SIZE:
1012       {
1013         // Point size = Pixel size * 72.f / DPI
1014         unsigned int horizontalDpi = 0u;
1015         unsigned int verticalDpi = 0u;
1016         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1017         fontClient.GetDpi( horizontalDpi, verticalDpi );
1018
1019         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
1020         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
1021         mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
1022         break;
1023       }
1024     }
1025
1026     mImpl->RequestRelayout();
1027   }
1028 }
1029
1030 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1031 {
1032   float value = 0.0f;
1033   if( NULL != mImpl->mEventData )
1034   {
1035     switch( type )
1036     {
1037       case POINT_SIZE:
1038       {
1039         if( NULL != mImpl->mEventData->mPlaceholderFont )
1040         {
1041           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
1042         }
1043         else
1044         {
1045           // If the placeholder text font size is not set, then return the default font size.
1046           value = GetDefaultFontSize( POINT_SIZE );
1047         }
1048         break;
1049       }
1050       case PIXEL_SIZE:
1051       {
1052         if( NULL != mImpl->mEventData->mPlaceholderFont )
1053         {
1054           // Pixel size = Point size * DPI / 72.f
1055           unsigned int horizontalDpi = 0u;
1056           unsigned int verticalDpi = 0u;
1057           TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1058           fontClient.GetDpi( horizontalDpi, verticalDpi );
1059
1060           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1061         }
1062         else
1063         {
1064           // If the placeholder text font size is not set, then return the default font size.
1065           value = GetDefaultFontSize( PIXEL_SIZE );
1066         }
1067         break;
1068       }
1069     }
1070     return value;
1071   }
1072
1073   return value;
1074 }
1075
1076 void Controller::SetDefaultColor( const Vector4& color )
1077 {
1078   mImpl->mTextColor = color;
1079
1080   if( !mImpl->IsShowingPlaceholderText() )
1081   {
1082     mImpl->mModel->mVisualModel->SetTextColor( color );
1083
1084     mImpl->RequestRelayout();
1085   }
1086 }
1087
1088 const Vector4& Controller::GetDefaultColor() const
1089 {
1090   return mImpl->mTextColor;
1091 }
1092
1093 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1094 {
1095   if( NULL != mImpl->mEventData )
1096   {
1097     mImpl->mEventData->mPlaceholderTextColor = textColor;
1098   }
1099
1100   if( mImpl->IsShowingPlaceholderText() )
1101   {
1102     mImpl->mModel->mVisualModel->SetTextColor( textColor );
1103     mImpl->RequestRelayout();
1104   }
1105 }
1106
1107 const Vector4& Controller::GetPlaceholderTextColor() const
1108 {
1109   if( NULL != mImpl->mEventData )
1110   {
1111     return mImpl->mEventData->mPlaceholderTextColor;
1112   }
1113
1114   return Color::BLACK;
1115 }
1116
1117 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1118 {
1119   mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1120
1121   mImpl->RequestRelayout();
1122 }
1123
1124 const Vector2& Controller::GetShadowOffset() const
1125 {
1126   return mImpl->mModel->mVisualModel->GetShadowOffset();
1127 }
1128
1129 void Controller::SetShadowColor( const Vector4& shadowColor )
1130 {
1131   mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1132
1133   mImpl->RequestRelayout();
1134 }
1135
1136 const Vector4& Controller::GetShadowColor() const
1137 {
1138   return mImpl->mModel->mVisualModel->GetShadowColor();
1139 }
1140
1141 void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
1142 {
1143   if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
1144   {
1145     mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
1146
1147     mImpl->RequestRelayout();
1148   }
1149 }
1150
1151 const float& Controller::GetShadowBlurRadius() const
1152 {
1153   return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1154 }
1155
1156 void Controller::SetUnderlineColor( const Vector4& color )
1157 {
1158   mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1159
1160   mImpl->RequestRelayout();
1161 }
1162
1163 const Vector4& Controller::GetUnderlineColor() const
1164 {
1165   return mImpl->mModel->mVisualModel->GetUnderlineColor();
1166 }
1167
1168 void Controller::SetUnderlineEnabled( bool enabled )
1169 {
1170   mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1171
1172   mImpl->RequestRelayout();
1173 }
1174
1175 bool Controller::IsUnderlineEnabled() const
1176 {
1177   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1178 }
1179
1180 void Controller::SetUnderlineHeight( float height )
1181 {
1182   mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1183
1184   mImpl->RequestRelayout();
1185 }
1186
1187 float Controller::GetUnderlineHeight() const
1188 {
1189   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1190 }
1191
1192 void Controller::SetOutlineColor( const Vector4& color )
1193 {
1194   mImpl->mModel->mVisualModel->SetOutlineColor( color );
1195
1196   mImpl->RequestRelayout();
1197 }
1198
1199 const Vector4& Controller::GetOutlineColor() const
1200 {
1201   return mImpl->mModel->mVisualModel->GetOutlineColor();
1202 }
1203
1204 void Controller::SetOutlineWidth( unsigned int width )
1205 {
1206   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1207
1208   mImpl->RequestRelayout();
1209 }
1210
1211 unsigned int Controller::GetOutlineWidth() const
1212 {
1213   return mImpl->mModel->mVisualModel->GetOutlineWidth();
1214 }
1215
1216 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1217 {
1218   if( NULL == mImpl->mEmbossDefaults )
1219   {
1220     mImpl->mEmbossDefaults = new EmbossDefaults();
1221   }
1222
1223   mImpl->mEmbossDefaults->properties = embossProperties;
1224 }
1225
1226 const std::string& Controller::GetDefaultEmbossProperties() const
1227 {
1228   if( NULL != mImpl->mEmbossDefaults )
1229   {
1230     return mImpl->mEmbossDefaults->properties;
1231   }
1232
1233   return EMPTY_STRING;
1234 }
1235
1236 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1237 {
1238   if( NULL == mImpl->mOutlineDefaults )
1239   {
1240     mImpl->mOutlineDefaults = new OutlineDefaults();
1241   }
1242
1243   mImpl->mOutlineDefaults->properties = outlineProperties;
1244 }
1245
1246 const std::string& Controller::GetDefaultOutlineProperties() const
1247 {
1248   if( NULL != mImpl->mOutlineDefaults )
1249   {
1250     return mImpl->mOutlineDefaults->properties;
1251   }
1252
1253   return EMPTY_STRING;
1254 }
1255
1256 void Controller::SetDefaultLineSpacing( float lineSpacing )
1257 {
1258   //TODO finish implementation
1259   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
1260 }
1261
1262 float Controller::GetDefaultLineSpacing() const
1263 {
1264   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1265 }
1266
1267 void Controller::SetInputColor( const Vector4& color )
1268 {
1269   if( NULL != mImpl->mEventData )
1270   {
1271     mImpl->mEventData->mInputStyle.textColor = color;
1272     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1273
1274     if( EventData::SELECTING == mImpl->mEventData->mState )
1275     {
1276       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1277
1278       // Get start and end position of selection
1279       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1280       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1281
1282       // Add the color run.
1283       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1284       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1285
1286       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1287       colorRun.color = color;
1288       colorRun.characterRun.characterIndex = startOfSelectedText;
1289       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1290
1291       // Request to relayout.
1292       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1293       mImpl->RequestRelayout();
1294
1295       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1296       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1297       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1298     }
1299   }
1300 }
1301
1302 const Vector4& Controller::GetInputColor() const
1303 {
1304   if( NULL != mImpl->mEventData )
1305   {
1306     return mImpl->mEventData->mInputStyle.textColor;
1307   }
1308
1309   // Return the default text's color if there is no EventData.
1310   return mImpl->mTextColor;
1311
1312 }
1313
1314 void Controller::SetInputFontFamily( const std::string& fontFamily )
1315 {
1316   if( NULL != mImpl->mEventData )
1317   {
1318     mImpl->mEventData->mInputStyle.familyName = fontFamily;
1319     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
1320
1321     if( EventData::SELECTING == mImpl->mEventData->mState )
1322     {
1323       CharacterIndex startOfSelectedText = 0u;
1324       Length lengthOfSelectedText = 0u;
1325       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1326                                                                             mImpl->mModel->mLogicalModel,
1327                                                                             startOfSelectedText,
1328                                                                             lengthOfSelectedText );
1329
1330       fontDescriptionRun.familyLength = fontFamily.size();
1331       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1332       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
1333       fontDescriptionRun.familyDefined = true;
1334
1335       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1336
1337       // Request to relayout.
1338       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1339                                                                VALIDATE_FONTS            |
1340                                                                SHAPE_TEXT                |
1341                                                                GET_GLYPH_METRICS         |
1342                                                                LAYOUT                    |
1343                                                                UPDATE_LAYOUT_SIZE        |
1344                                                                REORDER                   |
1345                                                                ALIGN );
1346       mImpl->mRecalculateNaturalSize = true;
1347       mImpl->RequestRelayout();
1348
1349       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1350       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1351       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1352
1353       // As the font changes, recalculate the handle positions is needed.
1354       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1355       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1356       mImpl->mEventData->mUpdateHighlightBox = true;
1357       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1358     }
1359   }
1360 }
1361
1362 const std::string& Controller::GetInputFontFamily() const
1363 {
1364   if( NULL != mImpl->mEventData )
1365   {
1366     return mImpl->mEventData->mInputStyle.familyName;
1367   }
1368
1369   // Return the default font's family if there is no EventData.
1370   return GetDefaultFontFamily();
1371 }
1372
1373 void Controller::SetInputFontWeight( FontWeight weight )
1374 {
1375   if( NULL != mImpl->mEventData )
1376   {
1377     mImpl->mEventData->mInputStyle.weight = weight;
1378     mImpl->mEventData->mInputStyle.isWeightDefined = true;
1379
1380     if( EventData::SELECTING == mImpl->mEventData->mState )
1381     {
1382       CharacterIndex startOfSelectedText = 0u;
1383       Length lengthOfSelectedText = 0u;
1384       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1385                                                                             mImpl->mModel->mLogicalModel,
1386                                                                             startOfSelectedText,
1387                                                                             lengthOfSelectedText );
1388
1389       fontDescriptionRun.weight = weight;
1390       fontDescriptionRun.weightDefined = true;
1391
1392       // Request to relayout.
1393       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1394                                                                VALIDATE_FONTS            |
1395                                                                SHAPE_TEXT                |
1396                                                                GET_GLYPH_METRICS         |
1397                                                                LAYOUT                    |
1398                                                                UPDATE_LAYOUT_SIZE        |
1399                                                                REORDER                   |
1400                                                                ALIGN );
1401       mImpl->mRecalculateNaturalSize = true;
1402       mImpl->RequestRelayout();
1403
1404       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1405       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1406       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1407
1408       // As the font might change, recalculate the handle positions is needed.
1409       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1410       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1411       mImpl->mEventData->mUpdateHighlightBox = true;
1412       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1413     }
1414   }
1415 }
1416
1417 bool Controller::IsInputFontWeightDefined() const
1418 {
1419   bool defined = false;
1420
1421   if( NULL != mImpl->mEventData )
1422   {
1423     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1424   }
1425
1426   return defined;
1427 }
1428
1429 FontWeight Controller::GetInputFontWeight() const
1430 {
1431   if( NULL != mImpl->mEventData )
1432   {
1433     return mImpl->mEventData->mInputStyle.weight;
1434   }
1435
1436   return GetDefaultFontWeight();
1437 }
1438
1439 void Controller::SetInputFontWidth( FontWidth width )
1440 {
1441   if( NULL != mImpl->mEventData )
1442   {
1443     mImpl->mEventData->mInputStyle.width = width;
1444     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1445
1446     if( EventData::SELECTING == mImpl->mEventData->mState )
1447     {
1448       CharacterIndex startOfSelectedText = 0u;
1449       Length lengthOfSelectedText = 0u;
1450       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1451                                                                             mImpl->mModel->mLogicalModel,
1452                                                                             startOfSelectedText,
1453                                                                             lengthOfSelectedText );
1454
1455       fontDescriptionRun.width = width;
1456       fontDescriptionRun.widthDefined = true;
1457
1458       // Request to relayout.
1459       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1460                                                                VALIDATE_FONTS            |
1461                                                                SHAPE_TEXT                |
1462                                                                GET_GLYPH_METRICS         |
1463                                                                LAYOUT                    |
1464                                                                UPDATE_LAYOUT_SIZE        |
1465                                                                REORDER                   |
1466                                                                ALIGN );
1467       mImpl->mRecalculateNaturalSize = true;
1468       mImpl->RequestRelayout();
1469
1470       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1471       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1472       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1473
1474       // As the font might change, recalculate the handle positions is needed.
1475       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1476       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1477       mImpl->mEventData->mUpdateHighlightBox = true;
1478       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1479     }
1480   }
1481 }
1482
1483 bool Controller::IsInputFontWidthDefined() const
1484 {
1485   bool defined = false;
1486
1487   if( NULL != mImpl->mEventData )
1488   {
1489     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1490   }
1491
1492   return defined;
1493 }
1494
1495 FontWidth Controller::GetInputFontWidth() const
1496 {
1497   if( NULL != mImpl->mEventData )
1498   {
1499     return mImpl->mEventData->mInputStyle.width;
1500   }
1501
1502   return GetDefaultFontWidth();
1503 }
1504
1505 void Controller::SetInputFontSlant( FontSlant slant )
1506 {
1507   if( NULL != mImpl->mEventData )
1508   {
1509     mImpl->mEventData->mInputStyle.slant = slant;
1510     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1511
1512     if( EventData::SELECTING == mImpl->mEventData->mState )
1513     {
1514       CharacterIndex startOfSelectedText = 0u;
1515       Length lengthOfSelectedText = 0u;
1516       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1517                                                                             mImpl->mModel->mLogicalModel,
1518                                                                             startOfSelectedText,
1519                                                                             lengthOfSelectedText );
1520
1521       fontDescriptionRun.slant = slant;
1522       fontDescriptionRun.slantDefined = true;
1523
1524       // Request to relayout.
1525       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1526                                                                VALIDATE_FONTS            |
1527                                                                SHAPE_TEXT                |
1528                                                                GET_GLYPH_METRICS         |
1529                                                                LAYOUT                    |
1530                                                                UPDATE_LAYOUT_SIZE        |
1531                                                                REORDER                   |
1532                                                                ALIGN );
1533       mImpl->mRecalculateNaturalSize = true;
1534       mImpl->RequestRelayout();
1535
1536       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1537       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1538       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1539
1540       // As the font might change, recalculate the handle positions is needed.
1541       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1542       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1543       mImpl->mEventData->mUpdateHighlightBox = true;
1544       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1545     }
1546   }
1547 }
1548
1549 bool Controller::IsInputFontSlantDefined() const
1550 {
1551   bool defined = false;
1552
1553   if( NULL != mImpl->mEventData )
1554   {
1555     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1556   }
1557
1558   return defined;
1559 }
1560
1561 FontSlant Controller::GetInputFontSlant() const
1562 {
1563   if( NULL != mImpl->mEventData )
1564   {
1565     return mImpl->mEventData->mInputStyle.slant;
1566   }
1567
1568   return GetDefaultFontSlant();
1569 }
1570
1571 void Controller::SetInputFontPointSize( float size )
1572 {
1573   if( NULL != mImpl->mEventData )
1574   {
1575     mImpl->mEventData->mInputStyle.size = size;
1576     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1577
1578     if( EventData::SELECTING == mImpl->mEventData->mState )
1579     {
1580       CharacterIndex startOfSelectedText = 0u;
1581       Length lengthOfSelectedText = 0u;
1582       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1583                                                                             mImpl->mModel->mLogicalModel,
1584                                                                             startOfSelectedText,
1585                                                                             lengthOfSelectedText );
1586
1587       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1588       fontDescriptionRun.sizeDefined = true;
1589
1590       // Request to relayout.
1591       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1592                                                                VALIDATE_FONTS            |
1593                                                                SHAPE_TEXT                |
1594                                                                GET_GLYPH_METRICS         |
1595                                                                LAYOUT                    |
1596                                                                UPDATE_LAYOUT_SIZE        |
1597                                                                REORDER                   |
1598                                                                ALIGN );
1599       mImpl->mRecalculateNaturalSize = true;
1600       mImpl->RequestRelayout();
1601
1602       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1603       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1604       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1605
1606       // As the font might change, recalculate the handle positions is needed.
1607       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1608       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1609       mImpl->mEventData->mUpdateHighlightBox = true;
1610       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1611     }
1612   }
1613 }
1614
1615 float Controller::GetInputFontPointSize() const
1616 {
1617   if( NULL != mImpl->mEventData )
1618   {
1619     return mImpl->mEventData->mInputStyle.size;
1620   }
1621
1622   // Return the default font's point size if there is no EventData.
1623   return GetDefaultFontSize( Text::Controller::POINT_SIZE );
1624 }
1625
1626 void Controller::SetInputLineSpacing( float lineSpacing )
1627 {
1628   if( NULL != mImpl->mEventData )
1629   {
1630     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1631     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1632   }
1633 }
1634
1635 float Controller::GetInputLineSpacing() const
1636 {
1637   if( NULL != mImpl->mEventData )
1638   {
1639     return mImpl->mEventData->mInputStyle.lineSpacing;
1640   }
1641
1642   return 0.f;
1643 }
1644
1645 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1646 {
1647   if( NULL != mImpl->mEventData )
1648   {
1649     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1650   }
1651 }
1652
1653 const std::string& Controller::GetInputShadowProperties() const
1654 {
1655   if( NULL != mImpl->mEventData )
1656   {
1657     return mImpl->mEventData->mInputStyle.shadowProperties;
1658   }
1659
1660   return EMPTY_STRING;
1661 }
1662
1663 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1664 {
1665   if( NULL != mImpl->mEventData )
1666   {
1667     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1668   }
1669 }
1670
1671 const std::string& Controller::GetInputUnderlineProperties() const
1672 {
1673   if( NULL != mImpl->mEventData )
1674   {
1675     return mImpl->mEventData->mInputStyle.underlineProperties;
1676   }
1677
1678   return EMPTY_STRING;
1679 }
1680
1681 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1682 {
1683   if( NULL != mImpl->mEventData )
1684   {
1685     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1686   }
1687 }
1688
1689 const std::string& Controller::GetInputEmbossProperties() const
1690 {
1691   if( NULL != mImpl->mEventData )
1692   {
1693     return mImpl->mEventData->mInputStyle.embossProperties;
1694   }
1695
1696   return GetDefaultEmbossProperties();
1697 }
1698
1699 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1700 {
1701   if( NULL != mImpl->mEventData )
1702   {
1703     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1704   }
1705 }
1706
1707 const std::string& Controller::GetInputOutlineProperties() const
1708 {
1709   if( NULL != mImpl->mEventData )
1710   {
1711     return mImpl->mEventData->mInputStyle.outlineProperties;
1712   }
1713
1714   return GetDefaultOutlineProperties();
1715 }
1716
1717 void Controller::SetInputModePassword( bool passwordInput )
1718 {
1719   if( NULL != mImpl->mEventData )
1720   {
1721     mImpl->mEventData->mPasswordInput = passwordInput;
1722   }
1723 }
1724
1725 bool Controller::IsInputModePassword()
1726 {
1727   if( NULL != mImpl->mEventData )
1728   {
1729     return mImpl->mEventData->mPasswordInput;
1730   }
1731   return false;
1732 }
1733
1734 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1735 {
1736   if( NULL != mImpl->mEventData )
1737   {
1738     mImpl->mEventData->mDoubleTapAction = action;
1739   }
1740 }
1741
1742 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1743 {
1744   NoTextTap::Action action = NoTextTap::NO_ACTION;
1745
1746   if( NULL != mImpl->mEventData )
1747   {
1748     action = mImpl->mEventData->mDoubleTapAction;
1749   }
1750
1751   return action;
1752 }
1753
1754 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1755 {
1756   if( NULL != mImpl->mEventData )
1757   {
1758     mImpl->mEventData->mLongPressAction = action;
1759   }
1760 }
1761
1762 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1763 {
1764   NoTextTap::Action action = NoTextTap::NO_ACTION;
1765
1766   if( NULL != mImpl->mEventData )
1767   {
1768     action = mImpl->mEventData->mLongPressAction;
1769   }
1770
1771   return action;
1772 }
1773
1774 bool Controller::IsUnderlineSetByString()
1775 {
1776   return mImpl->mUnderlineSetByString;
1777 }
1778
1779 void Controller::UnderlineSetByString( bool setByString )
1780 {
1781   mImpl->mUnderlineSetByString = setByString;
1782 }
1783
1784 bool Controller::IsShadowSetByString()
1785 {
1786   return mImpl->mShadowSetByString;
1787 }
1788
1789 void Controller::ShadowSetByString( bool setByString )
1790 {
1791   mImpl->mShadowSetByString = setByString;
1792 }
1793
1794 bool Controller::IsOutlineSetByString()
1795 {
1796   return mImpl->mOutlineSetByString;
1797 }
1798
1799 void Controller::OutlineSetByString( bool setByString )
1800 {
1801   mImpl->mOutlineSetByString = setByString;
1802 }
1803
1804 bool Controller::IsFontStyleSetByString()
1805 {
1806   return mImpl->mFontStyleSetByString;
1807 }
1808
1809 void Controller::FontStyleSetByString( bool setByString )
1810 {
1811   mImpl->mFontStyleSetByString = setByString;
1812 }
1813
1814 // public : Queries & retrieves.
1815
1816 Layout::Engine& Controller::GetLayoutEngine()
1817 {
1818   return mImpl->mLayoutEngine;
1819 }
1820
1821 View& Controller::GetView()
1822 {
1823   return mImpl->mView;
1824 }
1825
1826 Vector3 Controller::GetNaturalSize()
1827 {
1828   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1829   Vector3 naturalSize;
1830
1831   // Make sure the model is up-to-date before layouting
1832   ProcessModifyEvents();
1833
1834   if( mImpl->mRecalculateNaturalSize )
1835   {
1836     // Operations that can be done only once until the text changes.
1837     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1838                                                                            GET_SCRIPTS       |
1839                                                                            VALIDATE_FONTS    |
1840                                                                            GET_LINE_BREAKS   |
1841                                                                            GET_WORD_BREAKS   |
1842                                                                            BIDI_INFO         |
1843                                                                            SHAPE_TEXT        |
1844                                                                            GET_GLYPH_METRICS );
1845
1846     // Set the update info to relayout the whole text.
1847     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1848     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1849
1850     // Make sure the model is up-to-date before layouting
1851     mImpl->UpdateModel( onlyOnceOperations );
1852
1853     // Layout the text for the new width.
1854     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1855
1856     // Store the actual control's size to restore later.
1857     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1858
1859     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1860                 static_cast<OperationsMask>( onlyOnceOperations |
1861                                              LAYOUT | REORDER ),
1862                 naturalSize.GetVectorXY() );
1863
1864     // Do not do again the only once operations.
1865     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1866
1867     // Do the size related operations again.
1868     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1869                                                                         ALIGN  |
1870                                                                         REORDER );
1871     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1872
1873     // Stores the natural size to avoid recalculate it again
1874     // unless the text/style changes.
1875     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1876
1877     mImpl->mRecalculateNaturalSize = false;
1878
1879     // Clear the update info. This info will be set the next time the text is updated.
1880     mImpl->mTextUpdateInfo.Clear();
1881
1882     // Restore the actual control's size.
1883     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1884
1885     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1886   }
1887   else
1888   {
1889     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1890
1891     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1892   }
1893
1894   naturalSize.x = ConvertToEven( naturalSize.x );
1895   naturalSize.y = ConvertToEven( naturalSize.y );
1896
1897   return naturalSize;
1898 }
1899
1900 float Controller::GetHeightForWidth( float width )
1901 {
1902   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1903   // Make sure the model is up-to-date before layouting
1904   ProcessModifyEvents();
1905
1906   Size layoutSize;
1907   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1908                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1909                                                          mImpl->mTextUpdateInfo.mClearAll            )
1910   {
1911     // Operations that can be done only once until the text changes.
1912     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1913                                                                            GET_SCRIPTS       |
1914                                                                            VALIDATE_FONTS    |
1915                                                                            GET_LINE_BREAKS   |
1916                                                                            GET_WORD_BREAKS   |
1917                                                                            BIDI_INFO         |
1918                                                                            SHAPE_TEXT        |
1919                                                                            GET_GLYPH_METRICS );
1920
1921     // Set the update info to relayout the whole text.
1922     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1923     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1924
1925     // Make sure the model is up-to-date before layouting
1926     mImpl->UpdateModel( onlyOnceOperations );
1927
1928
1929     // Layout the text for the new width.
1930     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1931
1932     // Store the actual control's width.
1933     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1934
1935     DoRelayout( Size( width, MAX_FLOAT ),
1936                 static_cast<OperationsMask>( onlyOnceOperations |
1937                                              LAYOUT ),
1938                 layoutSize );
1939
1940     // Do not do again the only once operations.
1941     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1942
1943     // Do the size related operations again.
1944     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1945                                                                         ALIGN  |
1946                                                                         REORDER );
1947
1948     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1949
1950     // Clear the update info. This info will be set the next time the text is updated.
1951     mImpl->mTextUpdateInfo.Clear();
1952     mImpl->mTextUpdateInfo.mClearAll = true;
1953
1954     // Restore the actual control's width.
1955     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1956
1957     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1958   }
1959   else
1960   {
1961     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1962     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1963   }
1964
1965   return layoutSize.height;
1966 }
1967
1968 int Controller::GetLineCount( float width )
1969 {
1970   GetHeightForWidth( width );
1971   int numberofLines = mImpl->mModel->GetNumberOfLines();
1972   return numberofLines;
1973 }
1974
1975 const ModelInterface* const Controller::GetTextModel() const
1976 {
1977   return mImpl->mModel.Get();
1978 }
1979
1980 float Controller::GetScrollAmountByUserInput()
1981 {
1982   float scrollAmount = 0.0f;
1983
1984   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1985   {
1986     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1987     mImpl->mEventData->mCheckScrollAmount = false;
1988   }
1989   return scrollAmount;
1990 }
1991
1992 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1993 {
1994   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1995   bool isScrolled;
1996
1997   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1998   layoutHeight = layout.height;
1999   scrollPosition = mImpl->mModel->mScrollPosition.y;
2000   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
2001   return isScrolled;
2002 }
2003
2004 void Controller::SetHiddenInputOption(const Property::Map& options )
2005 {
2006   if( NULL == mImpl->mHiddenInput )
2007   {
2008     mImpl->mHiddenInput = new HiddenText( this );
2009   }
2010   mImpl->mHiddenInput->SetProperties(options);
2011 }
2012
2013 void Controller::GetHiddenInputOption(Property::Map& options )
2014 {
2015   if( NULL != mImpl->mHiddenInput )
2016   {
2017     mImpl->mHiddenInput->GetProperties(options);
2018   }
2019 }
2020
2021 void Controller::SetPlaceholderProperty( const Property::Map& map )
2022 {
2023   const Property::Map::SizeType count = map.Count();
2024
2025   for( Property::Map::SizeType position = 0; position < count; ++position )
2026   {
2027     KeyValuePair keyValue = map.GetKeyValue( position );
2028     Property::Key& key = keyValue.first;
2029     Property::Value& value = keyValue.second;
2030
2031     if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
2032     {
2033       std::string text = "";
2034       value.Get( text );
2035       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
2036     }
2037     else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
2038     {
2039       std::string text = "";
2040       value.Get( text );
2041       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
2042     }
2043     else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
2044     {
2045       Vector4 textColor;
2046       value.Get( textColor );
2047       if( GetPlaceholderTextColor() != textColor )
2048       {
2049         SetPlaceholderTextColor( textColor );
2050       }
2051     }
2052     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
2053     {
2054       std::string fontFamily = "";
2055       value.Get( fontFamily );
2056       SetPlaceholderFontFamily( fontFamily );
2057     }
2058     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
2059     {
2060       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2061     }
2062     else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
2063     {
2064       float pointSize;
2065       value.Get( pointSize );
2066       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2067       {
2068         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2069       }
2070     }
2071     else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
2072     {
2073       float pixelSize;
2074       value.Get( pixelSize );
2075       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2076       {
2077         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2078       }
2079     }
2080     else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
2081     {
2082       bool ellipsis;
2083       value.Get( ellipsis );
2084       SetPlaceholderTextElideEnabled( ellipsis );
2085     }
2086   }
2087 }
2088
2089 void Controller::GetPlaceholderProperty( Property::Map& map )
2090 {
2091   if( NULL != mImpl->mEventData )
2092   {
2093     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2094     {
2095       map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2096     }
2097     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2098     {
2099       map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2100     }
2101
2102     map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2103     map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
2104
2105     Property::Value fontStyleMapGet;
2106     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2107     map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
2108
2109     // Choose font size : POINT_SIZE or PIXEL_SIZE
2110     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2111     {
2112       map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2113     }
2114     else
2115     {
2116       map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2117     }
2118
2119     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2120     {
2121       map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2122     }
2123   }
2124 }
2125
2126 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
2127 {
2128   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
2129   {
2130     return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2131   }
2132
2133   const Character character = mImpl->mModel->mLogicalModel->mText[0];
2134   Script script = TextAbstraction::GetCharacterScript( character );
2135
2136   if( TextAbstraction::IsRightToLeftScript( script ) )
2137   {
2138     return Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT;
2139   }
2140
2141   return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2142 }
2143
2144 // public : Relayout.
2145
2146 Controller::UpdateTextType Controller::Relayout( const Size& size )
2147 {
2148   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2149
2150   UpdateTextType updateTextType = NONE_UPDATED;
2151
2152   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2153   {
2154     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2155     {
2156       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2157       updateTextType = MODEL_UPDATED;
2158     }
2159
2160     // Clear the update info. This info will be set the next time the text is updated.
2161     mImpl->mTextUpdateInfo.Clear();
2162
2163     // Not worth to relayout if width or height is equal to zero.
2164     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2165
2166     return updateTextType;
2167   }
2168
2169   // Whether a new size has been set.
2170   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2171
2172   if( newSize )
2173   {
2174     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2175
2176     if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
2177         ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
2178         ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
2179     {
2180       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
2181     }
2182
2183     // Layout operations that need to be done if the size changes.
2184     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2185                                                              LAYOUT                    |
2186                                                              ALIGN                     |
2187                                                              UPDATE_LAYOUT_SIZE        |
2188                                                              REORDER );
2189     // Set the update info to relayout the whole text.
2190     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2191     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2192
2193     // Store the size used to layout the text.
2194     mImpl->mModel->mVisualModel->mControlSize = size;
2195   }
2196
2197   // Whether there are modify events.
2198   if( 0u != mImpl->mModifyEvents.Count() )
2199   {
2200     // Style operations that need to be done if the text is modified.
2201     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2202                                                              COLOR );
2203   }
2204
2205   // Set the update info to elide the text.
2206   if( mImpl->mModel->mElideEnabled ||
2207       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2208   {
2209     // Update Text layout for applying elided
2210     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2211                                                              ALIGN                     |
2212                                                              LAYOUT                    |
2213                                                              UPDATE_LAYOUT_SIZE        |
2214                                                              REORDER );
2215     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2216     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2217   }
2218
2219   // Make sure the model is up-to-date before layouting.
2220   ProcessModifyEvents();
2221   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2222
2223   // Layout the text.
2224   Size layoutSize;
2225   updated = DoRelayout( size,
2226                         mImpl->mOperationsPending,
2227                         layoutSize ) || updated;
2228
2229   if( updated )
2230   {
2231     updateTextType = MODEL_UPDATED;
2232   }
2233
2234   // Do not re-do any operation until something changes.
2235   mImpl->mOperationsPending = NO_OPERATION;
2236   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2237
2238   // Whether the text control is editable
2239   const bool isEditable = NULL != mImpl->mEventData;
2240
2241   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2242   Vector2 offset;
2243   if( newSize && isEditable )
2244   {
2245     offset = mImpl->mModel->mScrollPosition;
2246   }
2247
2248   if( !isEditable || !IsMultiLineEnabled() )
2249   {
2250     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2251     CalculateVerticalOffset( size );
2252   }
2253
2254   if( isEditable )
2255   {
2256     if( newSize )
2257     {
2258       // If there is a new size, the scroll position needs to be clamped.
2259       mImpl->ClampHorizontalScroll( layoutSize );
2260
2261       // Update the decorator's positions is needed if there is a new size.
2262       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2263     }
2264
2265     // Move the cursor, grab handle etc.
2266     if( mImpl->ProcessInputEvents() )
2267     {
2268       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2269     }
2270   }
2271
2272   // Clear the update info. This info will be set the next time the text is updated.
2273   mImpl->mTextUpdateInfo.Clear();
2274   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2275
2276   return updateTextType;
2277 }
2278
2279 void Controller::RequestRelayout()
2280 {
2281   mImpl->RequestRelayout();
2282 }
2283
2284 // public : Input style change signals.
2285
2286 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2287 {
2288   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2289 }
2290
2291 void Controller::ProcessInputStyleChangedSignals()
2292 {
2293   if( NULL == mImpl->mEventData )
2294   {
2295     // Nothing to do.
2296     return;
2297   }
2298
2299   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2300          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2301        it != endIt;
2302        ++it )
2303   {
2304     const InputStyle::Mask mask = *it;
2305
2306     if( NULL != mImpl->mEditableControlInterface )
2307     {
2308       // Emit the input style changed signal.
2309       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2310     }
2311   }
2312
2313   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2314 }
2315
2316 // public : Text-input Event Queuing.
2317
2318 void Controller::KeyboardFocusGainEvent()
2319 {
2320   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2321
2322   if( NULL != mImpl->mEventData )
2323   {
2324     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2325         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2326     {
2327       mImpl->ChangeState( EventData::EDITING );
2328       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2329       mImpl->mEventData->mUpdateInputStyle = true;
2330     }
2331     mImpl->NotifyImfMultiLineStatus();
2332     if( mImpl->IsShowingPlaceholderText() )
2333     {
2334       // Show alternative placeholder-text when editing
2335       ShowPlaceholderText();
2336     }
2337
2338     mImpl->RequestRelayout();
2339   }
2340 }
2341
2342 void Controller::KeyboardFocusLostEvent()
2343 {
2344   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2345
2346   if( NULL != mImpl->mEventData )
2347   {
2348     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2349     {
2350       mImpl->ChangeState( EventData::INACTIVE );
2351
2352       if( !mImpl->IsShowingRealText() )
2353       {
2354         // Revert to regular placeholder-text when not editing
2355         ShowPlaceholderText();
2356       }
2357     }
2358   }
2359   mImpl->RequestRelayout();
2360 }
2361
2362 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2363 {
2364   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2365
2366   bool textChanged = false;
2367   bool relayoutNeeded = false;
2368
2369   if( ( NULL != mImpl->mEventData ) &&
2370       ( keyEvent.state == KeyEvent::Down ) )
2371   {
2372     int keyCode = keyEvent.keyCode;
2373     const std::string& keyString = keyEvent.keyPressed;
2374     const std::string keyName = keyEvent.keyPressedName;
2375
2376     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2377
2378     // Pre-process to separate modifying events from non-modifying input events.
2379     if( isNullKey )
2380     {
2381       // In some platforms arrive key events with no key code.
2382       // Do nothing.
2383       return false;
2384     }
2385     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2386     {
2387       // Do nothing
2388       return false;
2389     }
2390     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2391              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2392              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2393              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2394     {
2395       // If don't have any text, do nothing.
2396       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2397       {
2398         return false;
2399       }
2400
2401       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2402       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2403       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2404       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2405
2406       // Logic to determine whether this text control will lose focus or not.
2407       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) ||
2408           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) ||
2409           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2410           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2411           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2412           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2413       {
2414         // Release the active highlight.
2415         if( mImpl->mEventData->mState == EventData::SELECTING )
2416         {
2417           mImpl->ChangeState( EventData::EDITING );
2418
2419           // Update selection position.
2420           mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2421           mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2422           mImpl->mEventData->mUpdateCursorPosition = true;
2423           mImpl->RequestRelayout();
2424         }
2425         return false;
2426       }
2427
2428       mImpl->mEventData->mCheckScrollAmount = true;
2429       Event event( Event::CURSOR_KEY_EVENT );
2430       event.p1.mInt = keyCode;
2431       event.p2.mBool = keyEvent.IsShiftModifier();
2432       mImpl->mEventData->mEventQueue.push_back( event );
2433
2434       // Will request for relayout.
2435       relayoutNeeded = true;
2436     }
2437     else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode )
2438     {
2439       // Left or Right Control key event is received before Ctrl-C/V/X key event is received
2440       // If not handle it here, any selected text will be deleted
2441
2442       // Do nothing
2443       return false;
2444     }
2445     else if ( keyEvent.IsCtrlModifier() )
2446     {
2447       bool consumed = false;
2448       if (keyName == KEY_C_NAME)
2449       {
2450         // Ctrl-C to copy the selected text
2451         TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
2452         consumed = true;
2453       }
2454       else if (keyName == KEY_V_NAME)
2455       {
2456         // Ctrl-V to paste the copied text
2457         TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE );
2458         consumed = true;
2459       }
2460       else if (keyName == KEY_X_NAME)
2461       {
2462         // Ctrl-X to cut the selected text
2463         TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
2464         consumed = true;
2465       }
2466       return consumed;
2467     }
2468     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2469              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2470     {
2471       textChanged = DeleteEvent( keyCode );
2472
2473       // Will request for relayout.
2474       relayoutNeeded = true;
2475     }
2476     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2477              IsKey( keyEvent, Dali::DALI_KEY_MENU )  ||
2478              IsKey( keyEvent, static_cast<Dali::KEY>(Dali::DevelKey::DALI_KEY_SOURCE) ) ||
2479              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2480     {
2481       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2482       mImpl->ChangeState( EventData::INACTIVE );
2483
2484       // Will request for relayout.
2485       relayoutNeeded = true;
2486
2487       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2488     }
2489     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2490     {
2491       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2492       // and a character is typed after the type of a upper case latin character.
2493
2494       // Do nothing.
2495       return false;
2496     }
2497     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2498     {
2499       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2500       // Do nothing.
2501       return false;
2502     }
2503     else
2504     {
2505       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2506
2507       // IMF manager is no longer handling key-events
2508       mImpl->ClearPreEditFlag();
2509
2510       InsertText( keyString, COMMIT );
2511       textChanged = true;
2512
2513       // Will request for relayout.
2514       relayoutNeeded = true;
2515     }
2516
2517     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2518          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2519          ( !isNullKey ) &&
2520          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2521          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2522          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2523     {
2524       // Should not change the state if the key is the shift send by the imf manager.
2525       // Otherwise, when the state is SELECTING the text controller can't send the right
2526       // surrounding info to the imf.
2527       mImpl->ChangeState( EventData::EDITING );
2528
2529       // Will request for relayout.
2530       relayoutNeeded = true;
2531     }
2532
2533     if( relayoutNeeded )
2534     {
2535       mImpl->RequestRelayout();
2536     }
2537   }
2538
2539   if( textChanged &&
2540       ( NULL != mImpl->mEditableControlInterface ) )
2541   {
2542     // Do this last since it provides callbacks into application code
2543     mImpl->mEditableControlInterface->TextChanged();
2544   }
2545
2546   return true;
2547 }
2548
2549 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2550 {
2551   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2552
2553   if( NULL != mImpl->mEventData )
2554   {
2555     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2556     EventData::State state( mImpl->mEventData->mState );
2557     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2558
2559     if( mImpl->IsClipboardVisible() )
2560     {
2561       if( EventData::INACTIVE == state || EventData::EDITING == state)
2562       {
2563         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2564       }
2565       relayoutNeeded = true;
2566     }
2567     else if( 1u == tapCount )
2568     {
2569       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2570       {
2571         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2572       }
2573
2574       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2575       {
2576         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2577         relayoutNeeded = true;
2578       }
2579       else
2580       {
2581         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2582         {
2583           // Hide placeholder text
2584           ResetText();
2585         }
2586
2587         if( EventData::INACTIVE == state )
2588         {
2589           mImpl->ChangeState( EventData::EDITING );
2590         }
2591         else if( !mImpl->IsClipboardEmpty() )
2592         {
2593           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2594         }
2595         relayoutNeeded = true;
2596       }
2597     }
2598     else if( 2u == tapCount )
2599     {
2600       if( mImpl->mEventData->mSelectionEnabled &&
2601           mImpl->IsShowingRealText() )
2602       {
2603         relayoutNeeded = true;
2604         mImpl->mEventData->mIsLeftHandleSelected = true;
2605         mImpl->mEventData->mIsRightHandleSelected = true;
2606       }
2607     }
2608
2609     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2610     if( relayoutNeeded )
2611     {
2612       Event event( Event::TAP_EVENT );
2613       event.p1.mUint = tapCount;
2614       event.p2.mFloat = x;
2615       event.p3.mFloat = y;
2616       mImpl->mEventData->mEventQueue.push_back( event );
2617
2618       mImpl->RequestRelayout();
2619     }
2620   }
2621
2622   // Reset keyboard as tap event has occurred.
2623   mImpl->ResetImfManager();
2624 }
2625
2626 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2627 {
2628   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2629
2630   if( NULL != mImpl->mEventData )
2631   {
2632     Event event( Event::PAN_EVENT );
2633     event.p1.mInt = state;
2634     event.p2.mFloat = displacement.x;
2635     event.p3.mFloat = displacement.y;
2636     mImpl->mEventData->mEventQueue.push_back( event );
2637
2638     mImpl->RequestRelayout();
2639   }
2640 }
2641
2642 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2643 {
2644   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2645
2646   if( ( state == Gesture::Started ) &&
2647       ( NULL != mImpl->mEventData ) )
2648   {
2649     // The 1st long-press on inactive text-field is treated as tap
2650     if( EventData::INACTIVE == mImpl->mEventData->mState )
2651     {
2652       mImpl->ChangeState( EventData::EDITING );
2653
2654       Event event( Event::TAP_EVENT );
2655       event.p1.mUint = 1;
2656       event.p2.mFloat = x;
2657       event.p3.mFloat = y;
2658       mImpl->mEventData->mEventQueue.push_back( event );
2659
2660       mImpl->RequestRelayout();
2661     }
2662     else if( !mImpl->IsShowingRealText() )
2663     {
2664       Event event( Event::LONG_PRESS_EVENT );
2665       event.p1.mInt = state;
2666       event.p2.mFloat = x;
2667       event.p3.mFloat = y;
2668       mImpl->mEventData->mEventQueue.push_back( event );
2669       mImpl->RequestRelayout();
2670     }
2671     else if( !mImpl->IsClipboardVisible() )
2672     {
2673       // Reset the imf manager to commit the pre-edit before selecting the text.
2674       mImpl->ResetImfManager();
2675
2676       Event event( Event::LONG_PRESS_EVENT );
2677       event.p1.mInt = state;
2678       event.p2.mFloat = x;
2679       event.p3.mFloat = y;
2680       mImpl->mEventData->mEventQueue.push_back( event );
2681       mImpl->RequestRelayout();
2682
2683       mImpl->mEventData->mIsLeftHandleSelected = true;
2684       mImpl->mEventData->mIsRightHandleSelected = true;
2685     }
2686   }
2687 }
2688
2689 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2690 {
2691   // Whether the text needs to be relaid-out.
2692   bool requestRelayout = false;
2693
2694   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2695   bool retrieveText = false;
2696   bool retrieveCursor = false;
2697
2698   switch( imfEvent.eventName )
2699   {
2700     case ImfManager::COMMIT:
2701     {
2702       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2703       requestRelayout = true;
2704       retrieveCursor = true;
2705       break;
2706     }
2707     case ImfManager::PREEDIT:
2708     {
2709       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2710       requestRelayout = true;
2711       retrieveCursor = true;
2712       break;
2713     }
2714     case ImfManager::DELETESURROUNDING:
2715     {
2716       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2717                                            imfEvent.numberOfChars,
2718                                            DONT_UPDATE_INPUT_STYLE );
2719
2720       if( textDeleted )
2721       {
2722         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2723             !mImpl->IsPlaceholderAvailable() )
2724         {
2725           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2726         }
2727         else
2728         {
2729           ShowPlaceholderText();
2730         }
2731         mImpl->mEventData->mUpdateCursorPosition = true;
2732         mImpl->mEventData->mScrollAfterDelete = true;
2733
2734         requestRelayout = true;
2735       }
2736       break;
2737     }
2738     case ImfManager::GETSURROUNDING:
2739     {
2740       retrieveText = true;
2741       retrieveCursor = true;
2742       break;
2743     }
2744     case ImfManager::PRIVATECOMMAND:
2745     {
2746       // PRIVATECOMMAND event is just for getting the private command message
2747       retrieveText = true;
2748       retrieveCursor = true;
2749       break;
2750     }
2751     case ImfManager::VOID:
2752     {
2753       // do nothing
2754       break;
2755     }
2756   } // end switch
2757
2758   if( requestRelayout )
2759   {
2760     mImpl->mOperationsPending = ALL_OPERATIONS;
2761     mImpl->RequestRelayout();
2762   }
2763
2764   std::string text;
2765   CharacterIndex cursorPosition = 0u;
2766   Length numberOfWhiteSpaces = 0u;
2767
2768   if( retrieveCursor )
2769   {
2770     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2771
2772     cursorPosition = mImpl->GetLogicalCursorPosition();
2773
2774     if( cursorPosition < numberOfWhiteSpaces )
2775     {
2776       cursorPosition = 0u;
2777     }
2778     else
2779     {
2780       cursorPosition -= numberOfWhiteSpaces;
2781     }
2782   }
2783
2784   if( retrieveText )
2785   {
2786     if( !mImpl->IsShowingPlaceholderText() )
2787     {
2788       // Retrieves the normal text string.
2789       mImpl->GetText( numberOfWhiteSpaces, text );
2790     }
2791     else
2792     {
2793       // When the current text is Placeholder Text, the surrounding text should be empty string.
2794       // It means DALi should send empty string ("") to IME.
2795       text = "";
2796     }
2797   }
2798
2799   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2800
2801   if( requestRelayout &&
2802       ( NULL != mImpl->mEditableControlInterface ) )
2803   {
2804     // Do this last since it provides callbacks into application code
2805     mImpl->mEditableControlInterface->TextChanged();
2806   }
2807
2808   return callbackData;
2809 }
2810
2811 void Controller::PasteClipboardItemEvent()
2812 {
2813   // Retrieve the clipboard contents first
2814   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2815   std::string stringToPaste( notifier.GetContent() );
2816
2817   // Commit the current pre-edit text; the contents of the clipboard should be appended
2818   mImpl->ResetImfManager();
2819
2820   // Temporary disable hiding clipboard
2821   mImpl->SetClipboardHideEnable( false );
2822
2823   // Paste
2824   PasteText( stringToPaste );
2825
2826   mImpl->SetClipboardHideEnable( true );
2827 }
2828
2829 // protected : Inherit from Text::Decorator::ControllerInterface.
2830
2831 void Controller::GetTargetSize( Vector2& targetSize )
2832 {
2833   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2834 }
2835
2836 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2837 {
2838   if( NULL != mImpl->mEditableControlInterface )
2839   {
2840     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2841   }
2842 }
2843
2844 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2845 {
2846   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2847
2848   if( NULL != mImpl->mEventData )
2849   {
2850     switch( handleType )
2851     {
2852       case GRAB_HANDLE:
2853       {
2854         Event event( Event::GRAB_HANDLE_EVENT );
2855         event.p1.mUint  = state;
2856         event.p2.mFloat = x;
2857         event.p3.mFloat = y;
2858
2859         mImpl->mEventData->mEventQueue.push_back( event );
2860         break;
2861       }
2862       case LEFT_SELECTION_HANDLE:
2863       {
2864         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2865         event.p1.mUint  = state;
2866         event.p2.mFloat = x;
2867         event.p3.mFloat = y;
2868
2869         mImpl->mEventData->mEventQueue.push_back( event );
2870         break;
2871       }
2872       case RIGHT_SELECTION_HANDLE:
2873       {
2874         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2875         event.p1.mUint  = state;
2876         event.p2.mFloat = x;
2877         event.p3.mFloat = y;
2878
2879         mImpl->mEventData->mEventQueue.push_back( event );
2880         break;
2881       }
2882       case LEFT_SELECTION_HANDLE_MARKER:
2883       case RIGHT_SELECTION_HANDLE_MARKER:
2884       {
2885         // Markers do not move the handles.
2886         break;
2887       }
2888       case HANDLE_TYPE_COUNT:
2889       {
2890         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2891       }
2892     }
2893
2894     mImpl->RequestRelayout();
2895   }
2896 }
2897
2898 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2899
2900 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2901 {
2902   if( NULL == mImpl->mEventData )
2903   {
2904     return;
2905   }
2906
2907   switch( button )
2908   {
2909     case Toolkit::TextSelectionPopup::CUT:
2910     {
2911       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2912       mImpl->mOperationsPending = ALL_OPERATIONS;
2913
2914       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2915           !mImpl->IsPlaceholderAvailable() )
2916       {
2917         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2918       }
2919       else
2920       {
2921         ShowPlaceholderText();
2922       }
2923
2924       mImpl->mEventData->mUpdateCursorPosition = true;
2925       mImpl->mEventData->mScrollAfterDelete = true;
2926
2927       mImpl->RequestRelayout();
2928
2929       if( NULL != mImpl->mEditableControlInterface )
2930       {
2931         mImpl->mEditableControlInterface->TextChanged();
2932       }
2933       break;
2934     }
2935     case Toolkit::TextSelectionPopup::COPY:
2936     {
2937       mImpl->SendSelectionToClipboard( false ); // Text not modified
2938
2939       mImpl->mEventData->mUpdateCursorPosition = true;
2940
2941       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2942       break;
2943     }
2944     case Toolkit::TextSelectionPopup::PASTE:
2945     {
2946       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2947       break;
2948     }
2949     case Toolkit::TextSelectionPopup::SELECT:
2950     {
2951       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2952
2953       if( mImpl->mEventData->mSelectionEnabled )
2954       {
2955         // Creates a SELECT event.
2956         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2957       }
2958       break;
2959     }
2960     case Toolkit::TextSelectionPopup::SELECT_ALL:
2961     {
2962       // Creates a SELECT_ALL event
2963       SelectEvent( 0.f, 0.f, true );
2964       break;
2965     }
2966     case Toolkit::TextSelectionPopup::CLIPBOARD:
2967     {
2968       mImpl->ShowClipboard();
2969       break;
2970     }
2971     case Toolkit::TextSelectionPopup::NONE:
2972     {
2973       // Nothing to do.
2974       break;
2975     }
2976   }
2977 }
2978
2979 void Controller::DisplayTimeExpired()
2980 {
2981   mImpl->mEventData->mUpdateCursorPosition = true;
2982   // Apply modifications to the model
2983   mImpl->mOperationsPending = ALL_OPERATIONS;
2984
2985   mImpl->RequestRelayout();
2986 }
2987
2988 // private : Update.
2989
2990 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2991 {
2992   bool removedPrevious = false;
2993   bool removedSelected = false;
2994   bool maxLengthReached = false;
2995
2996   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2997
2998   if( NULL == mImpl->mEventData )
2999   {
3000     return;
3001   }
3002
3003   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
3004                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
3005                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3006
3007   // TODO: At the moment the underline runs are only for pre-edit.
3008   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
3009
3010   // Remove the previous IMF pre-edit.
3011   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
3012   {
3013     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
3014                                   mImpl->mEventData->mPreEditLength,
3015                                   DONT_UPDATE_INPUT_STYLE );
3016
3017     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
3018     mImpl->mEventData->mPreEditLength = 0u;
3019   }
3020   else
3021   {
3022     // Remove the previous Selection.
3023     removedSelected = RemoveSelectedText();
3024
3025   }
3026
3027   Vector<Character> utf32Characters;
3028   Length characterCount = 0u;
3029
3030   if( !text.empty() )
3031   {
3032     //  Convert text into UTF-32
3033     utf32Characters.Resize( text.size() );
3034
3035     // This is a bit horrible but std::string returns a (signed) char*
3036     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
3037
3038     // Transform a text array encoded in utf8 into an array encoded in utf32.
3039     // It returns the actual number of characters.
3040     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
3041     utf32Characters.Resize( characterCount );
3042
3043     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
3044     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
3045   }
3046
3047   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
3048   {
3049     // The placeholder text is no longer needed
3050     if( mImpl->IsShowingPlaceholderText() )
3051     {
3052       ResetText();
3053     }
3054
3055     mImpl->ChangeState( EventData::EDITING );
3056
3057     // Handle the IMF (predicitive text) state changes
3058     if( COMMIT == type )
3059     {
3060       // IMF manager is no longer handling key-events
3061       mImpl->ClearPreEditFlag();
3062     }
3063     else // PRE_EDIT
3064     {
3065       if( !mImpl->mEventData->mPreEditFlag )
3066       {
3067         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
3068
3069         // Record the start of the pre-edit text
3070         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
3071       }
3072
3073       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
3074       mImpl->mEventData->mPreEditFlag = true;
3075
3076       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3077     }
3078
3079     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
3080
3081     // Restrict new text to fit within Maximum characters setting.
3082     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
3083     maxLengthReached = ( characterCount > maxSizeOfNewText );
3084
3085     // The cursor position.
3086     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3087
3088     // Update the text's style.
3089
3090     // Updates the text style runs by adding characters.
3091     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3092
3093     // Get the character index from the cursor index.
3094     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3095
3096     // Retrieve the text's style for the given index.
3097     InputStyle style;
3098     mImpl->RetrieveDefaultInputStyle( style );
3099     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3100
3101     // Whether to add a new text color run.
3102     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
3103
3104     // Whether to add a new font run.
3105     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
3106     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3107     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3108     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3109     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3110
3111     // Add style runs.
3112     if( addColorRun )
3113     {
3114       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3115       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3116
3117       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3118       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3119       colorRun.characterRun.characterIndex = cursorIndex;
3120       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3121     }
3122
3123     if( addFontNameRun   ||
3124         addFontWeightRun ||
3125         addFontWidthRun  ||
3126         addFontSlantRun  ||
3127         addFontSizeRun )
3128     {
3129       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3130       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3131
3132       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3133
3134       if( addFontNameRun )
3135       {
3136         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3137         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3138         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3139         fontDescriptionRun.familyDefined = true;
3140
3141         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3142       }
3143
3144       if( addFontWeightRun )
3145       {
3146         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3147         fontDescriptionRun.weightDefined = true;
3148       }
3149
3150       if( addFontWidthRun )
3151       {
3152         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3153         fontDescriptionRun.widthDefined = true;
3154       }
3155
3156       if( addFontSlantRun )
3157       {
3158         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3159         fontDescriptionRun.slantDefined = true;
3160       }
3161
3162       if( addFontSizeRun )
3163       {
3164         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3165         fontDescriptionRun.sizeDefined = true;
3166       }
3167
3168       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3169       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3170     }
3171
3172     // Insert at current cursor position.
3173     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3174
3175     if( cursorIndex < numberOfCharactersInModel )
3176     {
3177       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3178     }
3179     else
3180     {
3181       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3182     }
3183
3184     // Mark the first paragraph to be updated.
3185     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3186     {
3187       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3188       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3189       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3190       mImpl->mTextUpdateInfo.mClearAll = true;
3191     }
3192     else
3193     {
3194       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3195       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3196     }
3197
3198     // Update the cursor index.
3199     cursorIndex += maxSizeOfNewText;
3200
3201     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 );
3202   }
3203
3204   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3205       mImpl->IsPlaceholderAvailable() )
3206   {
3207     // Show place-holder if empty after removing the pre-edit text
3208     ShowPlaceholderText();
3209     mImpl->mEventData->mUpdateCursorPosition = true;
3210     mImpl->ClearPreEditFlag();
3211   }
3212   else if( removedPrevious ||
3213            removedSelected ||
3214            ( 0 != utf32Characters.Count() ) )
3215   {
3216     // Queue an inserted event
3217     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3218
3219     mImpl->mEventData->mUpdateCursorPosition = true;
3220     if( removedSelected )
3221     {
3222       mImpl->mEventData->mScrollAfterDelete = true;
3223     }
3224     else
3225     {
3226       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3227     }
3228   }
3229
3230   if( maxLengthReached )
3231   {
3232     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3233
3234     mImpl->ResetImfManager();
3235
3236     if( NULL != mImpl->mEditableControlInterface )
3237     {
3238       // Do this last since it provides callbacks into application code
3239       mImpl->mEditableControlInterface->MaxLengthReached();
3240     }
3241   }
3242 }
3243
3244 void Controller::PasteText( const std::string& stringToPaste )
3245 {
3246   InsertText( stringToPaste, Text::Controller::COMMIT );
3247   mImpl->ChangeState( EventData::EDITING );
3248   mImpl->RequestRelayout();
3249
3250   if( NULL != mImpl->mEditableControlInterface )
3251   {
3252     // Do this last since it provides callbacks into application code
3253     mImpl->mEditableControlInterface->TextChanged();
3254   }
3255 }
3256
3257 bool Controller::RemoveText( int cursorOffset,
3258                              int numberOfCharacters,
3259                              UpdateInputStyleType type )
3260 {
3261   bool removed = false;
3262
3263   // When the users press "Delete All" button, the IME sends numberOfCharacters as '200000' value which means the max number of characters.
3264   const bool deleteAll = ( numberOfCharacters >= MAX_NUMBER_OF_CHARACTERS );
3265
3266   if( NULL == mImpl->mEventData )
3267   {
3268     return removed;
3269   }
3270
3271   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3272                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3273
3274   if( !mImpl->IsShowingPlaceholderText() )
3275   {
3276     // Delete at current cursor position
3277     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3278     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3279
3280     CharacterIndex cursorIndex = 0;
3281
3282     // Validate the cursor position & number of characters
3283     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3284     {
3285       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3286     }
3287
3288     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3289     {
3290       numberOfCharacters = currentText.Count() - cursorIndex;
3291     }
3292
3293     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.
3294         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) || deleteAll /*'Delete All' button clicked*/ )
3295     {
3296       // Mark the paragraphs to be updated.
3297       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3298       {
3299         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3300         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3301         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3302         mImpl->mTextUpdateInfo.mClearAll = true;
3303       }
3304       else
3305       {
3306         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3307         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3308       }
3309
3310       // Update the input style and remove the text's style before removing the text.
3311
3312       if( UPDATE_INPUT_STYLE == type )
3313       {
3314         // Keep a copy of the current input style.
3315         InputStyle currentInputStyle;
3316         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3317
3318         // Set first the default input style.
3319         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3320
3321         // Update the input style.
3322         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3323
3324         // Compare if the input style has changed.
3325         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3326
3327         if( hasInputStyleChanged )
3328         {
3329           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3330           // Queue the input style changed signal.
3331           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3332         }
3333       }
3334
3335       // Updates the text style runs by removing characters. Runs with no characters are removed.
3336       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3337
3338       // Remove the characters.
3339       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3340       Vector<Character>::Iterator last  = first + numberOfCharacters;
3341
3342       currentText.Erase( first, last );
3343
3344       // Cursor position retreat
3345       oldCursorIndex = cursorIndex;
3346
3347       mImpl->mEventData->mScrollAfterDelete = true;
3348
3349       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3350       removed = true;
3351     }
3352   }
3353
3354   return removed;
3355 }
3356
3357 bool Controller::RemoveSelectedText()
3358 {
3359   bool textRemoved( false );
3360
3361   if( EventData::SELECTING == mImpl->mEventData->mState )
3362   {
3363     std::string removedString;
3364     mImpl->RetrieveSelection( removedString, true );
3365
3366     if( !removedString.empty() )
3367     {
3368       textRemoved = true;
3369       mImpl->ChangeState( EventData::EDITING );
3370     }
3371   }
3372
3373   return textRemoved;
3374 }
3375
3376 // private : Relayout.
3377
3378 bool Controller::DoRelayout( const Size& size,
3379                              OperationsMask operationsRequired,
3380                              Size& layoutSize )
3381 {
3382   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3383   bool viewUpdated( false );
3384
3385   // Calculate the operations to be done.
3386   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3387
3388   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3389   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3390
3391   // Get the current layout size.
3392   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3393
3394   if( NO_OPERATION != ( LAYOUT & operations ) )
3395   {
3396     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3397
3398     // Some vectors with data needed to layout and reorder may be void
3399     // after the first time the text has been laid out.
3400     // Fill the vectors again.
3401
3402     // Calculate the number of glyphs to layout.
3403     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3404     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3405     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3406     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3407
3408     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3409     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3410     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3411     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3412
3413     if( 0u == totalNumberOfGlyphs )
3414     {
3415       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3416       {
3417         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3418       }
3419
3420       // Nothing else to do if there is no glyphs.
3421       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3422       return true;
3423     }
3424
3425     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3426     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3427     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3428     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3429     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3430     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3431     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3432     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
3433
3434     // Set the layout parameters.
3435     Layout::Parameters layoutParameters( size,
3436                                          textBuffer,
3437                                          lineBreakInfo.Begin(),
3438                                          wordBreakInfo.Begin(),
3439                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3440                                          glyphs.Begin(),
3441                                          glyphsToCharactersMap.Begin(),
3442                                          charactersPerGlyph.Begin(),
3443                                          charactersToGlyphBuffer,
3444                                          glyphsPerCharacterBuffer,
3445                                          totalNumberOfGlyphs,
3446                                          mImpl->mModel->mHorizontalAlignment,
3447                                          mImpl->mModel->mLineWrapMode,
3448                                          outlineWidth );
3449
3450     // Resize the vector of positions to have the same size than the vector of glyphs.
3451     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3452     glyphPositions.Resize( totalNumberOfGlyphs );
3453
3454     // Whether the last character is a new paragraph character.
3455     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3456     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3457
3458     // The initial glyph and the number of glyphs to layout.
3459     layoutParameters.startGlyphIndex = startGlyphIndex;
3460     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3461     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3462     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3463
3464     // Update the ellipsis
3465     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3466
3467     if( NULL != mImpl->mEventData )
3468     {
3469       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3470       {
3471         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3472       }
3473       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3474       {
3475         // Disable ellipsis when editing
3476         elideTextEnabled = false;
3477       }
3478
3479       // Reset the scroll position in inactive state
3480       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3481       {
3482         ResetScrollPosition();
3483       }
3484     }
3485
3486     // Update the visual model.
3487     Size newLayoutSize;
3488     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3489                                                    glyphPositions,
3490                                                    mImpl->mModel->mVisualModel->mLines,
3491                                                    newLayoutSize,
3492                                                    elideTextEnabled );
3493
3494     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3495
3496     if( viewUpdated )
3497     {
3498       layoutSize = newLayoutSize;
3499
3500       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3501       {
3502         mImpl->mAutoScrollDirectionRTL = false;
3503       }
3504
3505       // Reorder the lines
3506       if( NO_OPERATION != ( REORDER & operations ) )
3507       {
3508         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3509         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3510
3511         // Check first if there are paragraphs with bidirectional info.
3512         if( 0u != bidirectionalInfo.Count() )
3513         {
3514           // Get the lines
3515           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3516
3517           // Reorder the lines.
3518           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3519           ReorderLines( bidirectionalInfo,
3520                         startIndex,
3521                         requestedNumberOfCharacters,
3522                         mImpl->mModel->mVisualModel->mLines,
3523                         bidirectionalLineInfo );
3524
3525           // Set the bidirectional info per line into the layout parameters.
3526           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3527           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3528
3529           // Re-layout the text. Reorder those lines with right to left characters.
3530           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3531                                                          startIndex,
3532                                                          requestedNumberOfCharacters,
3533                                                          glyphPositions );
3534
3535           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3536           {
3537             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3538             if ( firstline )
3539             {
3540               mImpl->mAutoScrollDirectionRTL = firstline->direction;
3541             }
3542           }
3543         }
3544       } // REORDER
3545
3546       // Sets the layout size.
3547       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3548       {
3549         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3550       }
3551     } // view updated
3552   }
3553
3554   if( NO_OPERATION != ( ALIGN & operations ) )
3555   {
3556     // The laid-out lines.
3557     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3558
3559     // Need to align with the control's size as the text may contain lines
3560     // starting either with left to right text or right to left.
3561     mImpl->mLayoutEngine.Align( size,
3562                                 startIndex,
3563                                 requestedNumberOfCharacters,
3564                                 mImpl->mModel->mHorizontalAlignment,
3565                                 lines,
3566                                 mImpl->mModel->mAlignmentOffset );
3567
3568     viewUpdated = true;
3569   }
3570 #if defined(DEBUG_ENABLED)
3571   std::string currentText;
3572   GetText( currentText );
3573   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
3574 #endif
3575   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3576   return viewUpdated;
3577 }
3578
3579 void Controller::CalculateVerticalOffset( const Size& controlSize )
3580 {
3581   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3582
3583   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3584   {
3585     // Get the line height of the default font.
3586     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3587   }
3588
3589   switch( mImpl->mModel->mVerticalAlignment )
3590   {
3591     case VerticalAlignment::TOP:
3592     {
3593       mImpl->mModel->mScrollPosition.y = 0.f;
3594       break;
3595     }
3596     case VerticalAlignment::CENTER:
3597     {
3598       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3599       break;
3600     }
3601     case VerticalAlignment::BOTTOM:
3602     {
3603       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3604       break;
3605     }
3606   }
3607 }
3608
3609 // private : Events.
3610
3611 void Controller::ProcessModifyEvents()
3612 {
3613   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3614
3615   if( 0u == events.Count() )
3616   {
3617     // Nothing to do.
3618     return;
3619   }
3620
3621   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3622          endIt = events.End();
3623        it != endIt;
3624        ++it )
3625   {
3626     const ModifyEvent& event = *it;
3627
3628     if( ModifyEvent::TEXT_REPLACED == event.type )
3629     {
3630       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3631       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3632
3633       TextReplacedEvent();
3634     }
3635     else if( ModifyEvent::TEXT_INSERTED == event.type )
3636     {
3637       TextInsertedEvent();
3638     }
3639     else if( ModifyEvent::TEXT_DELETED == event.type )
3640     {
3641       // Placeholder-text cannot be deleted
3642       if( !mImpl->IsShowingPlaceholderText() )
3643       {
3644         TextDeletedEvent();
3645       }
3646     }
3647   }
3648
3649   if( NULL != mImpl->mEventData )
3650   {
3651     // When the text is being modified, delay cursor blinking
3652     mImpl->mEventData->mDecorator->DelayCursorBlink();
3653
3654     // Update selection position after modifying the text
3655     mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3656     mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3657   }
3658
3659   // Discard temporary text
3660   events.Clear();
3661 }
3662
3663 void Controller::TextReplacedEvent()
3664 {
3665   // The natural size needs to be re-calculated.
3666   mImpl->mRecalculateNaturalSize = true;
3667
3668   // Apply modifications to the model
3669   mImpl->mOperationsPending = ALL_OPERATIONS;
3670 }
3671
3672 void Controller::TextInsertedEvent()
3673 {
3674   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3675
3676   if( NULL == mImpl->mEventData )
3677   {
3678     return;
3679   }
3680
3681   mImpl->mEventData->mCheckScrollAmount = true;
3682
3683   // The natural size needs to be re-calculated.
3684   mImpl->mRecalculateNaturalSize = true;
3685
3686   // Apply modifications to the model; TODO - Optimize this
3687   mImpl->mOperationsPending = ALL_OPERATIONS;
3688 }
3689
3690 void Controller::TextDeletedEvent()
3691 {
3692   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3693
3694   if( NULL == mImpl->mEventData )
3695   {
3696     return;
3697   }
3698
3699   mImpl->mEventData->mCheckScrollAmount = true;
3700
3701   // The natural size needs to be re-calculated.
3702   mImpl->mRecalculateNaturalSize = true;
3703
3704   // Apply modifications to the model; TODO - Optimize this
3705   mImpl->mOperationsPending = ALL_OPERATIONS;
3706 }
3707
3708 void Controller::SelectEvent( float x, float y, bool selectAll )
3709 {
3710   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3711
3712   if( NULL != mImpl->mEventData )
3713   {
3714     if( selectAll )
3715     {
3716       Event event( Event::SELECT_ALL );
3717       mImpl->mEventData->mEventQueue.push_back( event );
3718     }
3719     else
3720     {
3721       Event event( Event::SELECT );
3722       event.p2.mFloat = x;
3723       event.p3.mFloat = y;
3724       mImpl->mEventData->mEventQueue.push_back( event );
3725     }
3726
3727     mImpl->mEventData->mCheckScrollAmount = true;
3728     mImpl->mEventData->mIsLeftHandleSelected = true;
3729     mImpl->mEventData->mIsRightHandleSelected = true;
3730     mImpl->RequestRelayout();
3731   }
3732 }
3733
3734 bool Controller::DeleteEvent( int keyCode )
3735 {
3736   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
3737
3738   bool removed = false;
3739
3740   if( NULL == mImpl->mEventData )
3741   {
3742     return removed;
3743   }
3744
3745   // IMF manager is no longer handling key-events
3746   mImpl->ClearPreEditFlag();
3747
3748   if( EventData::SELECTING == mImpl->mEventData->mState )
3749   {
3750     removed = RemoveSelectedText();
3751   }
3752   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
3753   {
3754     // Remove the character before the current cursor position
3755     removed = RemoveText( -1,
3756                           1,
3757                           UPDATE_INPUT_STYLE );
3758   }
3759   else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
3760   {
3761     // Remove the character after the current cursor position
3762     removed = RemoveText( 0,
3763                           1,
3764                           UPDATE_INPUT_STYLE );
3765   }
3766
3767   if( removed )
3768   {
3769     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3770         !mImpl->IsPlaceholderAvailable() )
3771     {
3772       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3773     }
3774     else
3775     {
3776       ShowPlaceholderText();
3777     }
3778     mImpl->mEventData->mUpdateCursorPosition = true;
3779     mImpl->mEventData->mScrollAfterDelete = true;
3780   }
3781
3782   return removed;
3783 }
3784
3785 // private : Helpers.
3786
3787 void Controller::ResetText()
3788 {
3789   // Reset buffers.
3790   mImpl->mModel->mLogicalModel->mText.Clear();
3791
3792   // We have cleared everything including the placeholder-text
3793   mImpl->PlaceholderCleared();
3794
3795   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3796   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3797   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3798
3799   // Clear any previous text.
3800   mImpl->mTextUpdateInfo.mClearAll = true;
3801
3802   // The natural size needs to be re-calculated.
3803   mImpl->mRecalculateNaturalSize = true;
3804
3805   // Apply modifications to the model
3806   mImpl->mOperationsPending = ALL_OPERATIONS;
3807 }
3808
3809 void Controller::ShowPlaceholderText()
3810 {
3811   if( mImpl->IsPlaceholderAvailable() )
3812   {
3813     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3814
3815     if( NULL == mImpl->mEventData )
3816     {
3817       return;
3818     }
3819
3820     mImpl->mEventData->mIsShowingPlaceholderText = true;
3821
3822     // Disable handles when showing place-holder text
3823     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3824     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3825     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3826
3827     const char* text( NULL );
3828     size_t size( 0 );
3829
3830     // TODO - Switch Placeholder text when changing state
3831     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3832         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3833     {
3834       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3835       size = mImpl->mEventData->mPlaceholderTextActive.size();
3836     }
3837     else
3838     {
3839       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3840       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3841     }
3842
3843     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3844     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3845
3846     // Reset model for showing placeholder.
3847     mImpl->mModel->mLogicalModel->mText.Clear();
3848     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3849
3850     // Convert text into UTF-32
3851     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3852     utf32Characters.Resize( size );
3853
3854     // This is a bit horrible but std::string returns a (signed) char*
3855     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3856
3857     // Transform a text array encoded in utf8 into an array encoded in utf32.
3858     // It returns the actual number of characters.
3859     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3860     utf32Characters.Resize( characterCount );
3861
3862     // The characters to be added.
3863     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3864
3865     // Reset the cursor position
3866     mImpl->mEventData->mPrimaryCursorPosition = 0;
3867
3868     // The natural size needs to be re-calculated.
3869     mImpl->mRecalculateNaturalSize = true;
3870
3871     // Apply modifications to the model
3872     mImpl->mOperationsPending = ALL_OPERATIONS;
3873
3874     // Update the rest of the model during size negotiation
3875     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3876   }
3877 }
3878
3879 void Controller::ClearFontData()
3880 {
3881   if( mImpl->mFontDefaults )
3882   {
3883     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3884   }
3885
3886   // Set flags to update the model.
3887   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3888   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3889   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3890
3891   mImpl->mTextUpdateInfo.mClearAll = true;
3892   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3893   mImpl->mRecalculateNaturalSize = true;
3894
3895   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3896                                                            VALIDATE_FONTS            |
3897                                                            SHAPE_TEXT                |
3898                                                            BIDI_INFO                 |
3899                                                            GET_GLYPH_METRICS         |
3900                                                            LAYOUT                    |
3901                                                            UPDATE_LAYOUT_SIZE        |
3902                                                            REORDER                   |
3903                                                            ALIGN );
3904 }
3905
3906 void Controller::ClearStyleData()
3907 {
3908   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3909   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3910 }
3911
3912 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3913 {
3914   // Reset the cursor position
3915   if( NULL != mImpl->mEventData )
3916   {
3917     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3918
3919     // Update the cursor if it's in editing mode.
3920     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3921     {
3922       mImpl->mEventData->mUpdateCursorPosition = true;
3923     }
3924   }
3925 }
3926
3927 void Controller::ResetScrollPosition()
3928 {
3929   if( NULL != mImpl->mEventData )
3930   {
3931     // Reset the scroll position.
3932     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3933     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3934   }
3935 }
3936
3937 void Controller::SetControlInterface( ControlInterface* controlInterface )
3938 {
3939   mImpl->mControlInterface = controlInterface;
3940 }
3941
3942 bool Controller::ShouldClearFocusOnEscape() const
3943 {
3944   return mImpl->mShouldClearFocusOnEscape;
3945 }
3946
3947 // private : Private contructors & copy operator.
3948
3949 Controller::Controller()
3950 : mImpl( NULL )
3951 {
3952   mImpl = new Controller::Impl( NULL, NULL );
3953 }
3954
3955 Controller::Controller( ControlInterface* controlInterface )
3956 {
3957   mImpl = new Controller::Impl( controlInterface, NULL );
3958 }
3959
3960 Controller::Controller( ControlInterface* controlInterface,
3961                         EditableControlInterface* editableControlInterface )
3962 {
3963   mImpl = new Controller::Impl( controlInterface,
3964                                 editableControlInterface );
3965 }
3966
3967 // The copy constructor and operator are left unimplemented.
3968
3969 // protected : Destructor.
3970
3971 Controller::~Controller()
3972 {
3973   delete mImpl;
3974 }
3975
3976 } // namespace Text
3977
3978 } // namespace Toolkit
3979
3980 } // namespace Dali