8175be4dd8fa0d0d0cbcff93299da1c20bc0320f
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2015 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
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/internal/text/bidirectional-support.h>
30 #include <dali-toolkit/internal/text/character-set-conversion.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/markup-processor.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
40 #endif
41
42 const float MAX_FLOAT = std::numeric_limits<float>::max();
43
44 const std::string EMPTY_STRING("");
45
46 float ConvertToEven( float value )
47 {
48   int intValue(static_cast<int>( value ));
49   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
50 }
51
52 } // namespace
53
54 namespace Dali
55 {
56
57 namespace Toolkit
58 {
59
60 namespace Text
61 {
62
63 /**
64  * @brief Adds a new font description run for the selected text.
65  *
66  * The new font parameters are added after the call to this method.
67  *
68  * @param[in] eventData The event data pointer.
69  * @param[in] logicalModel The logical model where to add the new font description run.
70  * @param[out] startOfSelectedText Index to the first selected character.
71  * @param[out] lengthOfSelectedText Number of selected characters.
72  */
73 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
74                                                  LogicalModelPtr logicalModel,
75                                                  CharacterIndex& startOfSelectedText,
76                                                  Length& lengthOfSelectedText )
77 {
78   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
79
80   // Get start and end position of selection
81   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
82   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
83
84   // Add the font run.
85   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
86   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
87
88   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
89
90   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
91   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
92
93   // Recalculate the selection highlight as the metrics may have changed.
94   eventData->mUpdateLeftSelectionPosition = true;
95   eventData->mUpdateRightSelectionPosition = true;
96
97   return fontDescriptionRun;
98 }
99
100 ControllerPtr Controller::New( ControlInterface& controlInterface )
101 {
102   return ControllerPtr( new Controller( controlInterface ) );
103 }
104
105 void Controller::EnableTextInput( DecoratorPtr decorator )
106 {
107   if( NULL == mImpl->mEventData )
108   {
109     mImpl->mEventData = new EventData( decorator );
110   }
111 }
112
113 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
114 {
115   // Metrics for bitmap & vector based glyphs are different
116   mImpl->mMetrics->SetGlyphType( glyphType );
117
118   // Clear the font-specific data
119   ClearFontData();
120
121   mImpl->RequestRelayout();
122 }
123
124 void Controller::SetMarkupProcessorEnabled( bool enable )
125 {
126   mImpl->mMarkupProcessorEnabled = enable;
127 }
128
129 bool Controller::IsMarkupProcessorEnabled() const
130 {
131   return mImpl->mMarkupProcessorEnabled;
132 }
133
134 void Controller::SetAutoScrollEnabled( bool enable )
135 {
136   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX)?"true":"false", this );
137
138   if ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX )
139   {
140     if ( enable )
141     {
142       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
143       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
144                                                                LAYOUT                    |
145                                                                ALIGN                     |
146                                                                UPDATE_ACTUAL_SIZE        |
147                                                                UPDATE_DIRECTION          |
148                                                                REORDER );
149
150     }
151     else
152     {
153       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
154       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
155                                                                LAYOUT                    |
156                                                                ALIGN                     |
157                                                                UPDATE_ACTUAL_SIZE        |
158                                                                REORDER );
159     }
160
161     mImpl->mAutoScrollEnabled = enable;
162     mImpl->RequestRelayout();
163   }
164   else
165   {
166     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored" );
167     mImpl->mAutoScrollEnabled = false;
168   }
169 }
170
171 bool Controller::IsAutoScrollEnabled() const
172 {
173   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", (mImpl->mAutoScrollEnabled)?"true":"false" );
174
175   return mImpl->mAutoScrollEnabled;
176 }
177
178 CharacterDirection Controller::GetAutoScrollDirection() const
179 {
180   return mImpl->mAutoScrollDirectionRTL;
181 }
182
183 float Controller::GetAutoScrollLineAlignment() const
184 {
185   float offset = 0.f;
186
187   if( mImpl->mVisualModel &&
188       ( 0u != mImpl->mVisualModel->mLines.Count() ) )
189   {
190     offset = ( *mImpl->mVisualModel->mLines.Begin() ).alignmentOffset;
191   }
192
193   return offset;
194 }
195
196 void Controller::SetText( const std::string& text )
197 {
198   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
199
200   // Reset keyboard as text changed
201   mImpl->ResetImfManager();
202
203   // Remove the previously set text and style.
204   ResetText();
205
206   // Remove the style.
207   ClearStyleData();
208
209   CharacterIndex lastCursorIndex = 0u;
210
211   if( NULL != mImpl->mEventData )
212   {
213     // If popup shown then hide it by switching to Editing state
214     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
215         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
216         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
217         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
218     {
219       mImpl->ChangeState( EventData::EDITING );
220     }
221   }
222
223   if( !text.empty() )
224   {
225     mImpl->mVisualModel->SetTextColor( mImpl->mTextColor );
226
227     MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns,
228                                          mImpl->mLogicalModel->mFontDescriptionRuns );
229
230     Length textSize = 0u;
231     const uint8_t* utf8 = NULL;
232     if( mImpl->mMarkupProcessorEnabled )
233     {
234       ProcessMarkupString( text, markupProcessData );
235       textSize = markupProcessData.markupProcessedText.size();
236
237       // This is a bit horrible but std::string returns a (signed) char*
238       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
239     }
240     else
241     {
242       textSize = text.size();
243
244       // This is a bit horrible but std::string returns a (signed) char*
245       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
246     }
247
248     //  Convert text into UTF-32
249     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
250     utf32Characters.Resize( textSize );
251
252     // Transform a text array encoded in utf8 into an array encoded in utf32.
253     // It returns the actual number of characters.
254     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
255     utf32Characters.Resize( characterCount );
256
257     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
258     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mLogicalModel->mText.Count() );
259
260     // The characters to be added.
261     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
262
263     // To reset the cursor position
264     lastCursorIndex = characterCount;
265
266     // Update the rest of the model during size negotiation
267     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
268
269     // The natural size needs to be re-calculated.
270     mImpl->mRecalculateNaturalSize = true;
271
272     // Apply modifications to the model
273     mImpl->mOperationsPending = ALL_OPERATIONS;
274   }
275   else
276   {
277     ShowPlaceholderText();
278   }
279
280   // Resets the cursor position.
281   ResetCursorPosition( lastCursorIndex );
282
283   // Scrolls the text to make the cursor visible.
284   ResetScrollPosition();
285
286   mImpl->RequestRelayout();
287
288   if( NULL != mImpl->mEventData )
289   {
290     // Cancel previously queued events
291     mImpl->mEventData->mEventQueue.clear();
292   }
293
294   // Do this last since it provides callbacks into application code
295   mImpl->mControlInterface.TextChanged();
296 }
297
298 void Controller::GetText( std::string& text ) const
299 {
300   if( !mImpl->IsShowingPlaceholderText() )
301   {
302     // Retrieves the text string.
303     mImpl->GetText( 0u, text );
304   }
305   else
306   {
307     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
308   }
309 }
310
311 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
312 {
313   if( NULL != mImpl->mEventData )
314   {
315     if( PLACEHOLDER_TYPE_INACTIVE == type )
316     {
317       mImpl->mEventData->mPlaceholderTextInactive = text;
318     }
319     else
320     {
321       mImpl->mEventData->mPlaceholderTextActive = text;
322     }
323
324     // Update placeholder if there is no text
325     if( mImpl->IsShowingPlaceholderText() ||
326         ( 0u == mImpl->mLogicalModel->mText.Count() ) )
327     {
328       ShowPlaceholderText();
329     }
330   }
331 }
332
333 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
334 {
335   if( NULL != mImpl->mEventData )
336   {
337     if( PLACEHOLDER_TYPE_INACTIVE == type )
338     {
339       text = mImpl->mEventData->mPlaceholderTextInactive;
340     }
341     else
342     {
343       text = mImpl->mEventData->mPlaceholderTextActive;
344     }
345   }
346 }
347
348 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
349 {
350   mImpl->mMaximumNumberOfCharacters = maxCharacters;
351 }
352
353 int Controller::GetMaximumNumberOfCharacters()
354 {
355   return mImpl->mMaximumNumberOfCharacters;
356 }
357
358 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
359 {
360   if( NULL == mImpl->mFontDefaults )
361   {
362     mImpl->mFontDefaults = new FontDefaults();
363   }
364
365   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
366   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
367   mImpl->mFontDefaults->familyDefined = true;
368
369   // Clear the font-specific data
370   ClearFontData();
371
372   mImpl->RequestRelayout();
373 }
374
375 const std::string& Controller::GetDefaultFontFamily() const
376 {
377   if( NULL != mImpl->mFontDefaults )
378   {
379     return mImpl->mFontDefaults->mFontDescription.family;
380   }
381
382   return EMPTY_STRING;
383 }
384
385 void Controller::SetDefaultFontStyle( const std::string& style )
386 {
387   if( NULL == mImpl->mFontDefaults )
388   {
389     mImpl->mFontDefaults = new FontDefaults();
390   }
391
392   mImpl->mFontDefaults->mFontStyle = style;
393 }
394
395 const std::string& Controller::GetDefaultFontStyle() const
396 {
397   if( NULL != mImpl->mFontDefaults )
398   {
399     return mImpl->mFontDefaults->mFontStyle;
400   }
401
402   return EMPTY_STRING;
403 }
404
405 void Controller::SetDefaultFontWeight( FontWeight weight )
406 {
407   if( NULL == mImpl->mFontDefaults )
408   {
409     mImpl->mFontDefaults = new FontDefaults();
410   }
411
412   mImpl->mFontDefaults->mFontDescription.weight = weight;
413   mImpl->mFontDefaults->weightDefined = true;
414
415   // Clear the font-specific data
416   ClearFontData();
417
418   mImpl->RequestRelayout();
419 }
420
421 FontWeight Controller::GetDefaultFontWeight() const
422 {
423   if( NULL != mImpl->mFontDefaults )
424   {
425     return mImpl->mFontDefaults->mFontDescription.weight;
426   }
427
428   return TextAbstraction::FontWeight::NORMAL;
429 }
430
431 void Controller::SetDefaultFontWidth( FontWidth width )
432 {
433   if( NULL == mImpl->mFontDefaults )
434   {
435     mImpl->mFontDefaults = new FontDefaults();
436   }
437
438   mImpl->mFontDefaults->mFontDescription.width = width;
439   mImpl->mFontDefaults->widthDefined = true;
440
441   // Clear the font-specific data
442   ClearFontData();
443
444   mImpl->RequestRelayout();
445 }
446
447 FontWidth Controller::GetDefaultFontWidth() const
448 {
449   if( NULL != mImpl->mFontDefaults )
450   {
451     return mImpl->mFontDefaults->mFontDescription.width;
452   }
453
454   return TextAbstraction::FontWidth::NORMAL;
455 }
456
457 void Controller::SetDefaultFontSlant( FontSlant slant )
458 {
459   if( NULL == mImpl->mFontDefaults )
460   {
461     mImpl->mFontDefaults = new FontDefaults();
462   }
463
464   mImpl->mFontDefaults->mFontDescription.slant = slant;
465   mImpl->mFontDefaults->slantDefined = true;
466
467   // Clear the font-specific data
468   ClearFontData();
469
470   mImpl->RequestRelayout();
471 }
472
473 FontSlant Controller::GetDefaultFontSlant() const
474 {
475   if( NULL != mImpl->mFontDefaults )
476   {
477     return mImpl->mFontDefaults->mFontDescription.slant;
478   }
479
480   return TextAbstraction::FontSlant::NORMAL;
481 }
482
483 void Controller::SetDefaultPointSize( float pointSize )
484 {
485   if( NULL == mImpl->mFontDefaults )
486   {
487     mImpl->mFontDefaults = new FontDefaults();
488   }
489
490   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
491   mImpl->mFontDefaults->sizeDefined = true;
492
493   // Clear the font-specific data
494   ClearFontData();
495
496   mImpl->RequestRelayout();
497 }
498
499 float Controller::GetDefaultPointSize() const
500 {
501   if( NULL != mImpl->mFontDefaults )
502   {
503     return mImpl->mFontDefaults->mDefaultPointSize;
504   }
505
506   return 0.0f;
507 }
508
509 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
510 {
511   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange");
512
513   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
514   {
515     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
516     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
517
518     ClearFontData();
519
520     mImpl->RequestRelayout();
521   }
522 }
523
524 void Controller::SetTextColor( const Vector4& textColor )
525 {
526   mImpl->mTextColor = textColor;
527
528   if( !mImpl->IsShowingPlaceholderText() )
529   {
530     mImpl->mVisualModel->SetTextColor( textColor );
531
532     mImpl->RequestRelayout();
533   }
534 }
535
536 const Vector4& Controller::GetTextColor() const
537 {
538   return mImpl->mTextColor;
539 }
540
541 bool Controller::RemoveText( int cursorOffset,
542                              int numberOfCharacters,
543                              UpdateInputStyleType type )
544 {
545   bool removed = false;
546
547   if( NULL == mImpl->mEventData )
548   {
549     return removed;
550   }
551
552   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
553                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
554
555   if( !mImpl->IsShowingPlaceholderText() )
556   {
557     // Delete at current cursor position
558     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
559     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
560
561     CharacterIndex cursorIndex = oldCursorIndex;
562
563     // Validate the cursor position & number of characters
564     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
565     {
566       cursorIndex = oldCursorIndex + cursorOffset;
567     }
568
569     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
570     {
571       numberOfCharacters = currentText.Count() - cursorIndex;
572     }
573
574     if( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
575     {
576       // Mark the paragraphs to be updated.
577       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
578       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
579
580       // Update the input style and remove the text's style before removing the text.
581
582       if( UPDATE_INPUT_STYLE == type )
583       {
584         // Set first the default input style.
585         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
586
587         // Update the input style.
588         mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
589       }
590
591       // Updates the text style runs by removing characters. Runs with no characters are removed.
592       mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
593
594       // Remove the characters.
595       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
596       Vector<Character>::Iterator last  = first + numberOfCharacters;
597
598       currentText.Erase( first, last );
599
600       // Cursor position retreat
601       oldCursorIndex = cursorIndex;
602
603       mImpl->mEventData->mScrollAfterDelete = true;
604
605       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
606       removed = true;
607     }
608   }
609
610   return removed;
611 }
612
613 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
614 {
615   if( NULL != mImpl->mEventData )
616   {
617     mImpl->mEventData->mPlaceholderTextColor = textColor;
618   }
619
620   if( mImpl->IsShowingPlaceholderText() )
621   {
622     mImpl->mVisualModel->SetTextColor( textColor );
623     mImpl->RequestRelayout();
624   }
625 }
626
627 const Vector4& Controller::GetPlaceholderTextColor() const
628 {
629   if( NULL != mImpl->mEventData )
630   {
631     return mImpl->mEventData->mPlaceholderTextColor;
632   }
633
634   return Color::BLACK;
635 }
636
637 void Controller::SetShadowOffset( const Vector2& shadowOffset )
638 {
639   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
640
641   mImpl->RequestRelayout();
642 }
643
644 const Vector2& Controller::GetShadowOffset() const
645 {
646   return mImpl->mVisualModel->GetShadowOffset();
647 }
648
649 void Controller::SetShadowColor( const Vector4& shadowColor )
650 {
651   mImpl->mVisualModel->SetShadowColor( shadowColor );
652
653   mImpl->RequestRelayout();
654 }
655
656 const Vector4& Controller::GetShadowColor() const
657 {
658   return mImpl->mVisualModel->GetShadowColor();
659 }
660
661 void Controller::SetDefaultShadowProperties( const std::string& shadowProperties )
662 {
663   if( NULL == mImpl->mShadowDefaults )
664   {
665     mImpl->mShadowDefaults = new ShadowDefaults();
666   }
667
668   mImpl->mShadowDefaults->properties = shadowProperties;
669 }
670
671 const std::string& Controller::GetDefaultShadowProperties() const
672 {
673   if( NULL != mImpl->mShadowDefaults )
674   {
675     return mImpl->mShadowDefaults->properties;
676   }
677
678   return EMPTY_STRING;
679 }
680
681 void Controller::SetUnderlineColor( const Vector4& color )
682 {
683   mImpl->mVisualModel->SetUnderlineColor( color );
684
685   mImpl->RequestRelayout();
686 }
687
688 const Vector4& Controller::GetUnderlineColor() const
689 {
690   return mImpl->mVisualModel->GetUnderlineColor();
691 }
692
693 void Controller::SetUnderlineEnabled( bool enabled )
694 {
695   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
696
697   mImpl->RequestRelayout();
698 }
699
700 bool Controller::IsUnderlineEnabled() const
701 {
702   return mImpl->mVisualModel->IsUnderlineEnabled();
703 }
704
705 void Controller::SetUnderlineHeight( float height )
706 {
707   mImpl->mVisualModel->SetUnderlineHeight( height );
708
709   mImpl->RequestRelayout();
710 }
711
712 float Controller::GetUnderlineHeight() const
713 {
714   return mImpl->mVisualModel->GetUnderlineHeight();
715 }
716
717 void Controller::SetDefaultUnderlineProperties( const std::string& underlineProperties )
718 {
719   if( NULL == mImpl->mUnderlineDefaults )
720   {
721     mImpl->mUnderlineDefaults = new UnderlineDefaults();
722   }
723
724   mImpl->mUnderlineDefaults->properties = underlineProperties;
725 }
726
727 const std::string& Controller::GetDefaultUnderlineProperties() const
728 {
729   if( NULL != mImpl->mUnderlineDefaults )
730   {
731     return mImpl->mUnderlineDefaults->properties;
732   }
733
734   return EMPTY_STRING;
735 }
736
737 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
738 {
739   if( NULL == mImpl->mEmbossDefaults )
740   {
741     mImpl->mEmbossDefaults = new EmbossDefaults();
742   }
743
744   mImpl->mEmbossDefaults->properties = embossProperties;
745 }
746
747 const std::string& Controller::GetDefaultEmbossProperties() const
748 {
749   if( NULL != mImpl->mEmbossDefaults )
750   {
751     return mImpl->mEmbossDefaults->properties;
752   }
753
754   return EMPTY_STRING;
755 }
756
757 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
758 {
759   if( NULL == mImpl->mOutlineDefaults )
760   {
761     mImpl->mOutlineDefaults = new OutlineDefaults();
762   }
763
764   mImpl->mOutlineDefaults->properties = outlineProperties;
765 }
766
767 const std::string& Controller::GetDefaultOutlineProperties() const
768 {
769   if( NULL != mImpl->mOutlineDefaults )
770   {
771     return mImpl->mOutlineDefaults->properties;
772   }
773
774   return EMPTY_STRING;
775 }
776
777 void Controller::SetDefaultLineSpacing( float lineSpacing )
778 {
779   //TODO finish implementation
780   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
781 }
782
783 float Controller::GetDefaultLineSpacing() const
784 {
785   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
786 }
787
788 void Controller::SetInputColor( const Vector4& color )
789 {
790   if( NULL != mImpl->mEventData )
791   {
792     mImpl->mEventData->mInputStyle.textColor = color;
793     mImpl->mEventData->mInputStyle.isDefaultColor = false;
794
795     if( EventData::SELECTING == mImpl->mEventData->mState )
796     {
797       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
798
799       // Get start and end position of selection
800       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
801       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
802
803       // Add the color run.
804       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
805       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
806
807       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
808       colorRun.color = color;
809       colorRun.characterRun.characterIndex = startOfSelectedText;
810       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
811
812       // Request to relayout.
813       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
814       mImpl->RequestRelayout();
815
816       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
817       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
818       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
819     }
820   }
821 }
822
823 const Vector4& Controller::GetInputColor() const
824 {
825   if( NULL != mImpl->mEventData )
826   {
827     return mImpl->mEventData->mInputStyle.textColor;
828   }
829
830   // Return the default text's color if there is no EventData.
831   return mImpl->mTextColor;
832
833 }
834
835 void Controller::SetInputFontFamily( const std::string& fontFamily )
836 {
837   if( NULL != mImpl->mEventData )
838   {
839     mImpl->mEventData->mInputStyle.familyName = fontFamily;
840     mImpl->mEventData->mInputStyle.familyDefined = true;
841
842     if( EventData::SELECTING == mImpl->mEventData->mState )
843     {
844       CharacterIndex startOfSelectedText = 0u;
845       Length lengthOfSelectedText = 0u;
846       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
847                                                                             mImpl->mLogicalModel,
848                                                                             startOfSelectedText,
849                                                                             lengthOfSelectedText );
850
851       fontDescriptionRun.familyLength = fontFamily.size();
852       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
853       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
854       fontDescriptionRun.familyDefined = true;
855
856       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
857
858       // Request to relayout.
859       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
860                                                                VALIDATE_FONTS            |
861                                                                SHAPE_TEXT                |
862                                                                GET_GLYPH_METRICS         |
863                                                                LAYOUT                    |
864                                                                UPDATE_ACTUAL_SIZE        |
865                                                                REORDER                   |
866                                                                ALIGN );
867       mImpl->mRecalculateNaturalSize = true;
868       mImpl->RequestRelayout();
869
870       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
871       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
872       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
873
874       // As the font changes, recalculate the handle positions is needed.
875       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
876       mImpl->mEventData->mUpdateRightSelectionPosition = true;
877       mImpl->mEventData->mScrollAfterUpdatePosition = true;
878     }
879   }
880 }
881
882 const std::string& Controller::GetInputFontFamily() const
883 {
884   if( NULL != mImpl->mEventData )
885   {
886     return mImpl->mEventData->mInputStyle.familyName;
887   }
888
889   // Return the default font's family if there is no EventData.
890   return GetDefaultFontFamily();
891 }
892
893 void Controller::SetInputFontStyle( const std::string& fontStyle )
894 {
895   if( NULL != mImpl->mEventData )
896   {
897     mImpl->mEventData->mInputStyle.fontStyle = fontStyle;
898   }
899 }
900
901 const std::string& Controller::GetInputFontStyle() const
902 {
903   if( NULL != mImpl->mEventData )
904   {
905     return mImpl->mEventData->mInputStyle.fontStyle;
906   }
907
908   // Return the default font's style if there is no EventData.
909   return GetDefaultFontStyle();
910 }
911
912 void Controller::SetInputFontWeight( FontWeight weight )
913 {
914   if( NULL != mImpl->mEventData )
915   {
916     mImpl->mEventData->mInputStyle.weight = weight;
917     mImpl->mEventData->mInputStyle.weightDefined = true;
918
919     if( EventData::SELECTING == mImpl->mEventData->mState )
920     {
921       CharacterIndex startOfSelectedText = 0u;
922       Length lengthOfSelectedText = 0u;
923       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
924                                                                             mImpl->mLogicalModel,
925                                                                             startOfSelectedText,
926                                                                             lengthOfSelectedText );
927
928       fontDescriptionRun.weight = weight;
929       fontDescriptionRun.weightDefined = true;
930
931       // Request to relayout.
932       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
933                                                                VALIDATE_FONTS            |
934                                                                SHAPE_TEXT                |
935                                                                GET_GLYPH_METRICS         |
936                                                                LAYOUT                    |
937                                                                UPDATE_ACTUAL_SIZE        |
938                                                                REORDER                   |
939                                                                ALIGN );
940       mImpl->mRecalculateNaturalSize = true;
941       mImpl->RequestRelayout();
942
943       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
944       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
945       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
946
947       // As the font might change, recalculate the handle positions is needed.
948       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
949       mImpl->mEventData->mUpdateRightSelectionPosition = true;
950       mImpl->mEventData->mScrollAfterUpdatePosition = true;
951     }
952   }
953 }
954
955 FontWeight Controller::GetInputFontWeight() const
956 {
957   if( NULL != mImpl->mEventData )
958   {
959     return mImpl->mEventData->mInputStyle.weight;
960   }
961
962   return GetDefaultFontWeight();
963 }
964
965 void Controller::SetInputFontWidth( FontWidth width )
966 {
967   if( NULL != mImpl->mEventData )
968   {
969     mImpl->mEventData->mInputStyle.width = width;
970     mImpl->mEventData->mInputStyle.widthDefined = true;
971
972     if( EventData::SELECTING == mImpl->mEventData->mState )
973     {
974       CharacterIndex startOfSelectedText = 0u;
975       Length lengthOfSelectedText = 0u;
976       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
977                                                                             mImpl->mLogicalModel,
978                                                                             startOfSelectedText,
979                                                                             lengthOfSelectedText );
980
981       fontDescriptionRun.width = width;
982       fontDescriptionRun.widthDefined = true;
983
984       // Request to relayout.
985       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
986                                                                VALIDATE_FONTS            |
987                                                                SHAPE_TEXT                |
988                                                                GET_GLYPH_METRICS         |
989                                                                LAYOUT                    |
990                                                                UPDATE_ACTUAL_SIZE        |
991                                                                REORDER                   |
992                                                                ALIGN );
993       mImpl->mRecalculateNaturalSize = true;
994       mImpl->RequestRelayout();
995
996       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
997       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
998       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
999
1000       // As the font might change, recalculate the handle positions is needed.
1001       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1002       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1003       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1004     }
1005   }
1006 }
1007
1008 FontWidth Controller::GetInputFontWidth() const
1009 {
1010   if( NULL != mImpl->mEventData )
1011   {
1012     return mImpl->mEventData->mInputStyle.width;
1013   }
1014
1015   return GetDefaultFontWidth();
1016 }
1017
1018 void Controller::SetInputFontSlant( FontSlant slant )
1019 {
1020   if( NULL != mImpl->mEventData )
1021   {
1022     mImpl->mEventData->mInputStyle.slant = slant;
1023     mImpl->mEventData->mInputStyle.slantDefined = true;
1024
1025     if( EventData::SELECTING == mImpl->mEventData->mState )
1026     {
1027       CharacterIndex startOfSelectedText = 0u;
1028       Length lengthOfSelectedText = 0u;
1029       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1030                                                                             mImpl->mLogicalModel,
1031                                                                             startOfSelectedText,
1032                                                                             lengthOfSelectedText );
1033
1034       fontDescriptionRun.slant = slant;
1035       fontDescriptionRun.slantDefined = true;
1036
1037       // Request to relayout.
1038       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1039                                                                VALIDATE_FONTS            |
1040                                                                SHAPE_TEXT                |
1041                                                                GET_GLYPH_METRICS         |
1042                                                                LAYOUT                    |
1043                                                                UPDATE_ACTUAL_SIZE        |
1044                                                                REORDER                   |
1045                                                                ALIGN );
1046       mImpl->mRecalculateNaturalSize = true;
1047       mImpl->RequestRelayout();
1048
1049       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1050       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1051       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1052
1053       // As the font might change, recalculate the handle positions is needed.
1054       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1055       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1056       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1057     }
1058   }
1059 }
1060
1061 FontSlant Controller::GetInputFontSlant() const
1062 {
1063   if( NULL != mImpl->mEventData )
1064   {
1065     return mImpl->mEventData->mInputStyle.slant;
1066   }
1067
1068   return GetDefaultFontSlant();
1069 }
1070
1071 void Controller::SetInputFontPointSize( float size )
1072 {
1073   if( NULL != mImpl->mEventData )
1074   {
1075     mImpl->mEventData->mInputStyle.size = size;
1076
1077     if( EventData::SELECTING == mImpl->mEventData->mState )
1078     {
1079       CharacterIndex startOfSelectedText = 0u;
1080       Length lengthOfSelectedText = 0u;
1081       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1082                                                                             mImpl->mLogicalModel,
1083                                                                             startOfSelectedText,
1084                                                                             lengthOfSelectedText );
1085
1086       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1087       fontDescriptionRun.sizeDefined = true;
1088
1089       // Request to relayout.
1090       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1091                                                                VALIDATE_FONTS            |
1092                                                                SHAPE_TEXT                |
1093                                                                GET_GLYPH_METRICS         |
1094                                                                LAYOUT                    |
1095                                                                UPDATE_ACTUAL_SIZE        |
1096                                                                REORDER                   |
1097                                                                ALIGN );
1098       mImpl->mRecalculateNaturalSize = true;
1099       mImpl->RequestRelayout();
1100
1101       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1102       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1103       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1104
1105       // As the font might change, recalculate the handle positions is needed.
1106       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1107       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1108       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1109     }
1110   }
1111 }
1112
1113 float Controller::GetInputFontPointSize() const
1114 {
1115   if( NULL != mImpl->mEventData )
1116   {
1117     return mImpl->mEventData->mInputStyle.size;
1118   }
1119
1120   // Return the default font's point size if there is no EventData.
1121   return GetDefaultPointSize();
1122 }
1123
1124 void Controller::SetInputLineSpacing( float lineSpacing )
1125 {
1126   if( NULL != mImpl->mEventData )
1127   {
1128     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1129   }
1130 }
1131
1132 float Controller::GetInputLineSpacing() const
1133 {
1134   if( NULL != mImpl->mEventData )
1135   {
1136     return mImpl->mEventData->mInputStyle.lineSpacing;
1137   }
1138
1139   return 0.f;
1140 }
1141
1142 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1143 {
1144   if( NULL != mImpl->mEventData )
1145   {
1146     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1147   }
1148 }
1149
1150 const std::string& Controller::GetInputShadowProperties() const
1151 {
1152   if( NULL != mImpl->mEventData )
1153   {
1154     return mImpl->mEventData->mInputStyle.shadowProperties;
1155   }
1156
1157   return GetDefaultShadowProperties();
1158 }
1159
1160 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1161 {
1162   if( NULL != mImpl->mEventData )
1163   {
1164     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1165   }
1166 }
1167
1168 const std::string& Controller::GetInputUnderlineProperties() const
1169 {
1170   if( NULL != mImpl->mEventData )
1171   {
1172     return mImpl->mEventData->mInputStyle.underlineProperties;
1173   }
1174
1175   return GetDefaultUnderlineProperties();
1176 }
1177
1178 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1179 {
1180   if( NULL != mImpl->mEventData )
1181   {
1182     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1183   }
1184 }
1185
1186 const std::string& Controller::GetInputEmbossProperties() const
1187 {
1188   if( NULL != mImpl->mEventData )
1189   {
1190     return mImpl->mEventData->mInputStyle.embossProperties;
1191   }
1192
1193   return GetDefaultEmbossProperties();
1194 }
1195
1196 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1197 {
1198   if( NULL != mImpl->mEventData )
1199   {
1200     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1201   }
1202 }
1203
1204 const std::string& Controller::GetInputOutlineProperties() const
1205 {
1206   if( NULL != mImpl->mEventData )
1207   {
1208     return mImpl->mEventData->mInputStyle.outlineProperties;
1209   }
1210
1211   return GetDefaultOutlineProperties();
1212 }
1213
1214 void Controller::SetEnableCursorBlink( bool enable )
1215 {
1216   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
1217
1218   if( NULL != mImpl->mEventData )
1219   {
1220     mImpl->mEventData->mCursorBlinkEnabled = enable;
1221
1222     if( !enable &&
1223         mImpl->mEventData->mDecorator )
1224     {
1225       mImpl->mEventData->mDecorator->StopCursorBlink();
1226     }
1227   }
1228 }
1229
1230 bool Controller::GetEnableCursorBlink() const
1231 {
1232   if( NULL != mImpl->mEventData )
1233   {
1234     return mImpl->mEventData->mCursorBlinkEnabled;
1235   }
1236
1237   return false;
1238 }
1239
1240 const Vector2& Controller::GetScrollPosition() const
1241 {
1242   return mImpl->mScrollPosition;
1243 }
1244
1245 Vector3 Controller::GetNaturalSize()
1246 {
1247   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1248   Vector3 naturalSize;
1249
1250   // Make sure the model is up-to-date before layouting
1251   ProcessModifyEvents();
1252
1253   if( mImpl->mRecalculateNaturalSize )
1254   {
1255     // Operations that can be done only once until the text changes.
1256     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1257                                                                            GET_SCRIPTS       |
1258                                                                            VALIDATE_FONTS    |
1259                                                                            GET_LINE_BREAKS   |
1260                                                                            GET_WORD_BREAKS   |
1261                                                                            BIDI_INFO         |
1262                                                                            SHAPE_TEXT        |
1263                                                                            GET_GLYPH_METRICS );
1264     // Make sure the model is up-to-date before layouting
1265     mImpl->UpdateModel( onlyOnceOperations );
1266
1267     // Layout the text for the new width.
1268     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1269
1270     // Set the update info to relayout the whole text.
1271     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1272     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1273
1274     // Store the actual control's size to restore later.
1275     const Size actualControlSize = mImpl->mVisualModel->mControlSize;
1276
1277     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1278                 static_cast<OperationsMask>( onlyOnceOperations |
1279                                              LAYOUT ),
1280                 naturalSize.GetVectorXY() );
1281
1282     // Do not do again the only once operations.
1283     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1284
1285     // Do the size related operations again.
1286     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1287                                                                         ALIGN  |
1288                                                                         REORDER );
1289     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1290
1291     // Stores the natural size to avoid recalculate it again
1292     // unless the text/style changes.
1293     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1294
1295     mImpl->mRecalculateNaturalSize = false;
1296
1297     // Clear the update info. This info will be set the next time the text is updated.
1298     mImpl->mTextUpdateInfo.Clear();
1299
1300     // Restore the actual control's size.
1301     mImpl->mVisualModel->mControlSize = actualControlSize;
1302
1303     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1304   }
1305   else
1306   {
1307     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1308
1309     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1310   }
1311
1312   naturalSize.x = ConvertToEven( naturalSize.x );
1313   naturalSize.y = ConvertToEven( naturalSize.y );
1314
1315   return naturalSize;
1316 }
1317
1318 float Controller::GetHeightForWidth( float width )
1319 {
1320   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1321   // Make sure the model is up-to-date before layouting
1322   ProcessModifyEvents();
1323
1324   Size layoutSize;
1325   if( fabsf( width - mImpl->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 )
1326   {
1327     // Operations that can be done only once until the text changes.
1328     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1329                                                                            GET_SCRIPTS       |
1330                                                                            VALIDATE_FONTS    |
1331                                                                            GET_LINE_BREAKS   |
1332                                                                            GET_WORD_BREAKS   |
1333                                                                            BIDI_INFO         |
1334                                                                            SHAPE_TEXT        |
1335                                                                            GET_GLYPH_METRICS );
1336     // Make sure the model is up-to-date before layouting
1337     mImpl->UpdateModel( onlyOnceOperations );
1338
1339
1340     // Layout the text for the new width.
1341     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1342
1343     // Set the update info to relayout the whole text.
1344     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1345     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1346
1347     // Store the actual control's width.
1348     const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
1349
1350     DoRelayout( Size( width, MAX_FLOAT ),
1351                 static_cast<OperationsMask>( onlyOnceOperations |
1352                                              LAYOUT ),
1353                 layoutSize );
1354
1355     // Do not do again the only once operations.
1356     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1357
1358     // Do the size related operations again.
1359     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1360                                                                         ALIGN  |
1361                                                                         REORDER );
1362
1363     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1364
1365     // Clear the update info. This info will be set the next time the text is updated.
1366     mImpl->mTextUpdateInfo.Clear();
1367
1368     // Restore the actual control's width.
1369     mImpl->mVisualModel->mControlSize.width = actualControlWidth;
1370
1371     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1372   }
1373   else
1374   {
1375     layoutSize = mImpl->mVisualModel->GetLayoutSize();
1376     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1377   }
1378
1379   return layoutSize.height;
1380 }
1381
1382 bool Controller::Relayout( const Size& size )
1383 {
1384   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, (mImpl->mAutoScrollEnabled)?"true":"false"  );
1385
1386   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1387   {
1388     bool glyphsRemoved( false );
1389     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
1390     {
1391       mImpl->mVisualModel->mGlyphPositions.Clear();
1392       glyphsRemoved = true;
1393     }
1394
1395     // Clear the update info. This info will be set the next time the text is updated.
1396     mImpl->mTextUpdateInfo.Clear();
1397
1398     // Not worth to relayout if width or height is equal to zero.
1399     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
1400
1401     return glyphsRemoved;
1402   }
1403
1404   // Whether a new size has been set.
1405   const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
1406
1407   if( newSize )
1408   {
1409     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
1410
1411     // Layout operations that need to be done if the size changes.
1412     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1413                                                              LAYOUT                    |
1414                                                              ALIGN                     |
1415                                                              UPDATE_ACTUAL_SIZE        |
1416                                                              REORDER );
1417     // Set the update info to relayout the whole text.
1418     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1419     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1420   }
1421
1422   // Whether there are modify events.
1423   if( 0u != mImpl->mModifyEvents.Count() )
1424   {
1425     // Style operations that need to be done if the text is modified.
1426     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1427                                                              COLOR );
1428   }
1429
1430   // Make sure the model is up-to-date before layouting.
1431   ProcessModifyEvents();
1432   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
1433
1434   // Layout the text.
1435   Size layoutSize;
1436   updated = DoRelayout( size,
1437                         mImpl->mOperationsPending,
1438                         layoutSize ) || updated;
1439
1440   // Do not re-do any operation until something changes.
1441   mImpl->mOperationsPending = NO_OPERATION;
1442
1443   // Whether the text control is editable
1444   const bool isEditable = NULL != mImpl->mEventData;
1445
1446   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
1447   Vector2 offset;
1448   if( newSize && isEditable )
1449   {
1450     offset = mImpl->mScrollPosition;
1451   }
1452
1453   if( !isEditable || !IsMultiLineEnabled() )
1454   {
1455     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
1456     CalculateVerticalOffset( size );
1457   }
1458
1459   if( isEditable )
1460   {
1461     if( newSize )
1462     {
1463       // If there is a new size, the scroll position needs to be clamped.
1464       mImpl->ClampHorizontalScroll( layoutSize );
1465
1466       // Update the decorator's positions is needed if there is a new size.
1467       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mScrollPosition - offset );
1468     }
1469
1470     // Move the cursor, grab handle etc.
1471     updated = mImpl->ProcessInputEvents() || updated;
1472   }
1473
1474   // Clear the update info. This info will be set the next time the text is updated.
1475   mImpl->mTextUpdateInfo.Clear();
1476   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
1477
1478   return updated;
1479 }
1480
1481 void Controller::ProcessModifyEvents()
1482 {
1483   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
1484
1485   if( 0u == events.Count() )
1486   {
1487     // Nothing to do.
1488     return;
1489   }
1490
1491   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
1492          endIt = events.End();
1493        it != endIt;
1494        ++it )
1495   {
1496     const ModifyEvent& event = *it;
1497
1498     if( ModifyEvent::TEXT_REPLACED == event.type )
1499     {
1500       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
1501       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
1502
1503       TextReplacedEvent();
1504     }
1505     else if( ModifyEvent::TEXT_INSERTED == event.type )
1506     {
1507       TextInsertedEvent();
1508     }
1509     else if( ModifyEvent::TEXT_DELETED == event.type )
1510     {
1511       // Placeholder-text cannot be deleted
1512       if( !mImpl->IsShowingPlaceholderText() )
1513       {
1514         TextDeletedEvent();
1515       }
1516     }
1517   }
1518
1519   if( NULL != mImpl->mEventData )
1520   {
1521     // When the text is being modified, delay cursor blinking
1522     mImpl->mEventData->mDecorator->DelayCursorBlink();
1523   }
1524
1525   // Discard temporary text
1526   events.Clear();
1527 }
1528
1529 void Controller::ResetText()
1530 {
1531   // Reset buffers.
1532   mImpl->mLogicalModel->mText.Clear();
1533
1534   // We have cleared everything including the placeholder-text
1535   mImpl->PlaceholderCleared();
1536
1537   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1538   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1539   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
1540
1541   // Clear any previous text.
1542   mImpl->mTextUpdateInfo.mClearAll = true;
1543
1544   // The natural size needs to be re-calculated.
1545   mImpl->mRecalculateNaturalSize = true;
1546
1547   // Apply modifications to the model
1548   mImpl->mOperationsPending = ALL_OPERATIONS;
1549 }
1550
1551 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
1552 {
1553   // Reset the cursor position
1554   if( NULL != mImpl->mEventData )
1555   {
1556     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
1557
1558     // Update the cursor if it's in editing mode.
1559     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
1560     {
1561       mImpl->mEventData->mUpdateCursorPosition = true;
1562     }
1563   }
1564 }
1565
1566 void Controller::ResetScrollPosition()
1567 {
1568   if( NULL != mImpl->mEventData )
1569   {
1570     // Reset the scroll position.
1571     mImpl->mScrollPosition = Vector2::ZERO;
1572     mImpl->mEventData->mScrollAfterUpdatePosition = true;
1573   }
1574 }
1575
1576 void Controller::TextReplacedEvent()
1577 {
1578   // The natural size needs to be re-calculated.
1579   mImpl->mRecalculateNaturalSize = true;
1580
1581   // Apply modifications to the model
1582   mImpl->mOperationsPending = ALL_OPERATIONS;
1583 }
1584
1585 void Controller::TextInsertedEvent()
1586 {
1587   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
1588
1589   if( NULL == mImpl->mEventData )
1590   {
1591     return;
1592   }
1593
1594   // The natural size needs to be re-calculated.
1595   mImpl->mRecalculateNaturalSize = true;
1596
1597   // Apply modifications to the model; TODO - Optimize this
1598   mImpl->mOperationsPending = ALL_OPERATIONS;
1599 }
1600
1601 void Controller::TextDeletedEvent()
1602 {
1603   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
1604
1605   if( NULL == mImpl->mEventData )
1606   {
1607     return;
1608   }
1609
1610   // The natural size needs to be re-calculated.
1611   mImpl->mRecalculateNaturalSize = true;
1612
1613   // Apply modifications to the model; TODO - Optimize this
1614   mImpl->mOperationsPending = ALL_OPERATIONS;
1615 }
1616
1617 bool Controller::DoRelayout( const Size& size,
1618                              OperationsMask operationsRequired,
1619                              Size& layoutSize )
1620 {
1621   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
1622   bool viewUpdated( false );
1623
1624   // Calculate the operations to be done.
1625   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1626
1627   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
1628   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
1629
1630   if( NO_OPERATION != ( LAYOUT & operations ) )
1631   {
1632     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
1633
1634     // Some vectors with data needed to layout and reorder may be void
1635     // after the first time the text has been laid out.
1636     // Fill the vectors again.
1637
1638     // Calculate the number of glyphs to layout.
1639     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mVisualModel->mCharactersToGlyph;
1640     const Vector<Length>& glyphsPerCharacter = mImpl->mVisualModel->mGlyphsPerCharacter;
1641     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
1642     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
1643
1644     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
1645     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
1646     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
1647     const Length totalNumberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
1648
1649     if( 0u == totalNumberOfGlyphs )
1650     {
1651       if( NO_OPERATION != ( UPDATE_ACTUAL_SIZE & operations ) )
1652       {
1653         mImpl->mVisualModel->SetLayoutSize( Size::ZERO );
1654       }
1655
1656       // Nothing else to do if there is no glyphs.
1657       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
1658       return true;
1659     }
1660
1661     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1662     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1663     const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
1664     const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1665     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1666     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1667     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
1668
1669     // Set the layout parameters.
1670     LayoutParameters layoutParameters( size,
1671                                        textBuffer,
1672                                        lineBreakInfo.Begin(),
1673                                        wordBreakInfo.Begin(),
1674                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
1675                                        glyphs.Begin(),
1676                                        glyphsToCharactersMap.Begin(),
1677                                        charactersPerGlyph.Begin(),
1678                                        charactersToGlyphBuffer,
1679                                        glyphsPerCharacterBuffer,
1680                                        totalNumberOfGlyphs );
1681
1682     // Resize the vector of positions to have the same size than the vector of glyphs.
1683     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1684     glyphPositions.Resize( totalNumberOfGlyphs );
1685
1686     // Whether the last character is a new paragraph character.
1687     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
1688     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
1689
1690     // The initial glyph and the number of glyphs to layout.
1691     layoutParameters.startGlyphIndex = startGlyphIndex;
1692     layoutParameters.numberOfGlyphs = numberOfGlyphs;
1693     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
1694     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
1695
1696     // Update the visual model.
1697     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1698                                                    glyphPositions,
1699                                                    mImpl->mVisualModel->mLines,
1700                                                    layoutSize );
1701
1702
1703     if( viewUpdated )
1704     {
1705       if ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
1706       {
1707         mImpl->mAutoScrollDirectionRTL = false;
1708       }
1709
1710       // Reorder the lines
1711       if( NO_OPERATION != ( REORDER & operations ) )
1712       {
1713         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1714         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
1715
1716         // Check first if there are paragraphs with bidirectional info.
1717         if( 0u != bidirectionalInfo.Count() )
1718         {
1719           // Get the lines
1720           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
1721
1722           // Reorder the lines.
1723           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1724           ReorderLines( bidirectionalInfo,
1725                         startIndex,
1726                         requestedNumberOfCharacters,
1727                         mImpl->mVisualModel->mLines,
1728                         bidirectionalLineInfo );
1729
1730           // Set the bidirectional info per line into the layout parameters.
1731           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
1732           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
1733
1734           // Re-layout the text. Reorder those lines with right to left characters.
1735           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1736                                                          startIndex,
1737                                                          requestedNumberOfCharacters,
1738                                                          glyphPositions );
1739
1740           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
1741           {
1742             const LineRun* const firstline = mImpl->mVisualModel->mLines.Begin();
1743             if ( firstline )
1744             {
1745               mImpl->mAutoScrollDirectionRTL = firstline->direction;
1746             }
1747           }
1748         }
1749       } // REORDER
1750
1751       // Sets the actual size.
1752       if( NO_OPERATION != ( UPDATE_ACTUAL_SIZE & operations ) )
1753       {
1754         mImpl->mVisualModel->SetLayoutSize( layoutSize );
1755       }
1756     } // view updated
1757
1758     // Store the size used to layout the text.
1759     mImpl->mVisualModel->mControlSize = size;
1760   }
1761   else
1762   {
1763     layoutSize = mImpl->mVisualModel->GetLayoutSize();
1764   }
1765
1766   if( NO_OPERATION != ( ALIGN & operations ) )
1767   {
1768     // The laid-out lines.
1769     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1770
1771     mImpl->mLayoutEngine.Align( size,
1772                                 startIndex,
1773                                 requestedNumberOfCharacters,
1774                                 lines );
1775
1776     viewUpdated = true;
1777   }
1778 #if defined(DEBUG_ENABLED)
1779   std::string currentText;
1780   GetText( currentText );
1781   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
1782 #endif
1783   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
1784   return viewUpdated;
1785 }
1786
1787 void Controller::SetMultiLineEnabled( bool enable )
1788 {
1789   const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
1790
1791   if( layout != mImpl->mLayoutEngine.GetLayout() )
1792   {
1793     // Set the layout type.
1794     mImpl->mLayoutEngine.SetLayout( layout );
1795
1796     // Set the flags to redo the layout operations
1797     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
1798                                                                           UPDATE_ACTUAL_SIZE |
1799                                                                           ALIGN              |
1800                                                                           REORDER );
1801
1802     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
1803
1804     mImpl->RequestRelayout();
1805   }
1806 }
1807
1808 bool Controller::IsMultiLineEnabled() const
1809 {
1810   return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
1811 }
1812
1813 void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
1814 {
1815   if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
1816   {
1817     // Set the alignment.
1818     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
1819
1820     // Set the flag to redo the alignment operation.
1821     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1822
1823     mImpl->RequestRelayout();
1824   }
1825 }
1826
1827 LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
1828 {
1829   return mImpl->mLayoutEngine.GetHorizontalAlignment();
1830 }
1831
1832 void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
1833 {
1834   if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
1835   {
1836     // Set the alignment.
1837     mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
1838
1839     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1840
1841     mImpl->RequestRelayout();
1842   }
1843 }
1844
1845 LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
1846 {
1847   return mImpl->mLayoutEngine.GetVerticalAlignment();
1848 }
1849
1850 void Controller::CalculateVerticalOffset( const Size& controlSize )
1851 {
1852   Size layoutSize = mImpl->mVisualModel->GetLayoutSize();
1853
1854   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
1855   {
1856     // Get the line height of the default font.
1857     layoutSize.height = mImpl->GetDefaultFontLineHeight();
1858   }
1859
1860   switch( mImpl->mLayoutEngine.GetVerticalAlignment() )
1861   {
1862     case LayoutEngine::VERTICAL_ALIGN_TOP:
1863     {
1864       mImpl->mScrollPosition.y = 0.f;
1865       break;
1866     }
1867     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1868     {
1869       mImpl->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
1870       break;
1871     }
1872     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1873     {
1874       mImpl->mScrollPosition.y = controlSize.height - layoutSize.height;
1875       break;
1876     }
1877   }
1878 }
1879
1880 LayoutEngine& Controller::GetLayoutEngine()
1881 {
1882   return mImpl->mLayoutEngine;
1883 }
1884
1885 View& Controller::GetView()
1886 {
1887   return mImpl->mView;
1888 }
1889
1890 void Controller::KeyboardFocusGainEvent()
1891 {
1892   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1893
1894   if( NULL != mImpl->mEventData )
1895   {
1896     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1897         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1898     {
1899       mImpl->ChangeState( EventData::EDITING );
1900       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1901     }
1902
1903     if( mImpl->IsShowingPlaceholderText() )
1904     {
1905       // Show alternative placeholder-text when editing
1906       ShowPlaceholderText();
1907     }
1908
1909     mImpl->RequestRelayout();
1910   }
1911 }
1912
1913 void Controller::KeyboardFocusLostEvent()
1914 {
1915   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1916
1917   if( NULL != mImpl->mEventData )
1918   {
1919     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
1920     {
1921       mImpl->ChangeState( EventData::INACTIVE );
1922
1923       if( !mImpl->IsShowingRealText() )
1924       {
1925         // Revert to regular placeholder-text when not editing
1926         ShowPlaceholderText();
1927       }
1928     }
1929   }
1930   mImpl->RequestRelayout();
1931 }
1932
1933 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1934 {
1935   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1936
1937   bool textChanged( false );
1938
1939   if( ( NULL != mImpl->mEventData ) &&
1940       ( keyEvent.state == KeyEvent::Down ) )
1941   {
1942     int keyCode = keyEvent.keyCode;
1943     const std::string& keyString = keyEvent.keyPressed;
1944
1945     // Pre-process to separate modifying events from non-modifying input events.
1946     if( Dali::DALI_KEY_ESCAPE == keyCode )
1947     {
1948       // Escape key is a special case which causes focus loss
1949       KeyboardFocusLostEvent();
1950     }
1951     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
1952              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
1953              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
1954              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
1955     {
1956       Event event( Event::CURSOR_KEY_EVENT );
1957       event.p1.mInt = keyCode;
1958       mImpl->mEventData->mEventQueue.push_back( event );
1959     }
1960     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1961     {
1962       textChanged = BackspaceKeyEvent();
1963     }
1964     else if( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
1965     {
1966       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
1967       // Avoids calling the InsertText() method which can delete selected text
1968     }
1969     else if( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1970              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1971     {
1972       mImpl->ChangeState( EventData::INACTIVE );
1973       // Menu/Home key behaviour does not allow edit mode to resume like Power key
1974       // Avoids calling the InsertText() method which can delete selected text
1975     }
1976     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1977     {
1978       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1979       // and a character is typed after the type of a upper case latin character.
1980
1981       // Do nothing.
1982     }
1983     else
1984     {
1985       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1986
1987       // IMF manager is no longer handling key-events
1988       mImpl->ClearPreEditFlag();
1989
1990       InsertText( keyString, COMMIT );
1991       textChanged = true;
1992     }
1993
1994     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1995          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
1996          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) )
1997     {
1998       // Should not change the state if the key is the shift send by the imf manager.
1999       // Otherwise, when the state is SELECTING the text controller can't send the right
2000       // surrounding info to the imf.
2001       mImpl->ChangeState( EventData::EDITING );
2002     }
2003
2004     mImpl->RequestRelayout();
2005   }
2006
2007   if( textChanged )
2008   {
2009     // Do this last since it provides callbacks into application code
2010     mImpl->mControlInterface.TextChanged();
2011   }
2012
2013   return true;
2014 }
2015
2016 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2017 {
2018   bool removedPrevious( false );
2019   bool maxLengthReached( false );
2020
2021   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2022
2023   if( NULL == mImpl->mEventData )
2024   {
2025     return;
2026   }
2027
2028   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2029                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2030                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2031
2032   // TODO: At the moment the underline runs are only for pre-edit.
2033   mImpl->mVisualModel->mUnderlineRuns.Clear();
2034
2035   // Keep the current number of characters.
2036   const Length currentNumberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
2037
2038   // Remove the previous IMF pre-edit.
2039   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2040   {
2041     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2042                                   mImpl->mEventData->mPreEditLength,
2043                                   DONT_UPDATE_INPUT_STYLE );
2044
2045     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2046     mImpl->mEventData->mPreEditLength = 0u;
2047   }
2048   else
2049   {
2050     // Remove the previous Selection.
2051     removedPrevious = RemoveSelectedText();
2052   }
2053
2054   Vector<Character> utf32Characters;
2055   Length characterCount = 0u;
2056
2057   if( !text.empty() )
2058   {
2059     //  Convert text into UTF-32
2060     utf32Characters.Resize( text.size() );
2061
2062     // This is a bit horrible but std::string returns a (signed) char*
2063     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2064
2065     // Transform a text array encoded in utf8 into an array encoded in utf32.
2066     // It returns the actual number of characters.
2067     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2068     utf32Characters.Resize( characterCount );
2069
2070     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2071     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2072   }
2073
2074   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2075   {
2076     // The placeholder text is no longer needed
2077     if( mImpl->IsShowingPlaceholderText() )
2078     {
2079       ResetText();
2080     }
2081
2082     mImpl->ChangeState( EventData::EDITING );
2083
2084     // Handle the IMF (predicitive text) state changes
2085     if( COMMIT == type )
2086     {
2087       // IMF manager is no longer handling key-events
2088       mImpl->ClearPreEditFlag();
2089     }
2090     else // PRE_EDIT
2091     {
2092       if( !mImpl->mEventData->mPreEditFlag )
2093       {
2094         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
2095
2096         // Record the start of the pre-edit text
2097         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2098       }
2099
2100       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2101       mImpl->mEventData->mPreEditFlag = true;
2102
2103       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2104     }
2105
2106     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
2107
2108     // Restrict new text to fit within Maximum characters setting.
2109     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2110     maxLengthReached = ( characterCount > maxSizeOfNewText );
2111
2112     // The cursor position.
2113     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2114
2115     // Update the text's style.
2116
2117     // Updates the text style runs by adding characters.
2118     mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2119
2120     // Get the character index from the cursor index.
2121     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2122
2123     // Retrieve the text's style for the given index.
2124     InputStyle style;
2125     mImpl->RetrieveDefaultInputStyle( style );
2126     mImpl->mLogicalModel->RetrieveStyle( styleIndex, style );
2127
2128     // Whether to add a new text color run.
2129     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2130
2131     // Whether to add a new font run.
2132     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2133     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
2134     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
2135     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
2136     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
2137
2138     // Add style runs.
2139     if( addColorRun )
2140     {
2141       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
2142       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2143
2144       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2145       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2146       colorRun.characterRun.characterIndex = cursorIndex;
2147       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2148     }
2149
2150     if( addFontNameRun   ||
2151         addFontWeightRun ||
2152         addFontWidthRun  ||
2153         addFontSlantRun  ||
2154         addFontSizeRun )
2155     {
2156       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mFontDescriptionRuns.Count();
2157       mImpl->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2158
2159       FontDescriptionRun& fontDescriptionRun = *( mImpl->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
2160
2161       if( addFontNameRun )
2162       {
2163         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2164         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2165         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
2166         fontDescriptionRun.familyDefined = true;
2167
2168         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2169       }
2170
2171       if( addFontWeightRun )
2172       {
2173         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2174         fontDescriptionRun.weightDefined = true;
2175       }
2176
2177       if( addFontWidthRun )
2178       {
2179         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2180         fontDescriptionRun.widthDefined = true;
2181       }
2182
2183       if( addFontSlantRun )
2184       {
2185         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2186         fontDescriptionRun.slantDefined = true;
2187       }
2188
2189       if( addFontSizeRun )
2190       {
2191         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
2192         fontDescriptionRun.sizeDefined = true;
2193       }
2194
2195       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2196       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2197     }
2198
2199     // Insert at current cursor position.
2200     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
2201
2202     if( cursorIndex < numberOfCharactersInModel )
2203     {
2204       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2205     }
2206     else
2207     {
2208       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2209     }
2210
2211     // Mark the first paragraph to be updated.
2212     mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2213     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2214
2215     // Update the cursor index.
2216     cursorIndex += maxSizeOfNewText;
2217
2218     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
2219   }
2220
2221   const Length numberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
2222
2223   if( ( 0u == mImpl->mLogicalModel->mText.Count() ) &&
2224       mImpl->IsPlaceholderAvailable() )
2225   {
2226     // Show place-holder if empty after removing the pre-edit text
2227     ShowPlaceholderText();
2228     mImpl->mEventData->mUpdateCursorPosition = true;
2229     mImpl->ClearPreEditFlag();
2230   }
2231   else if( removedPrevious ||
2232            ( 0 != utf32Characters.Count() ) )
2233   {
2234     // Queue an inserted event
2235     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2236
2237     mImpl->mEventData->mUpdateCursorPosition = true;
2238     if( numberOfCharacters < currentNumberOfCharacters )
2239     {
2240       mImpl->mEventData->mScrollAfterDelete = true;
2241     }
2242     else
2243     {
2244       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2245     }
2246   }
2247
2248   if( maxLengthReached )
2249   {
2250     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
2251
2252     mImpl->ResetImfManager();
2253
2254     // Do this last since it provides callbacks into application code
2255     mImpl->mControlInterface.MaxLengthReached();
2256   }
2257 }
2258
2259 bool Controller::RemoveSelectedText()
2260 {
2261   bool textRemoved( false );
2262
2263   if( EventData::SELECTING == mImpl->mEventData->mState )
2264   {
2265     std::string removedString;
2266     mImpl->RetrieveSelection( removedString, true );
2267
2268     if( !removedString.empty() )
2269     {
2270       textRemoved = true;
2271       mImpl->ChangeState( EventData::EDITING );
2272     }
2273   }
2274
2275   return textRemoved;
2276 }
2277
2278 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2279 {
2280   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2281
2282   if( NULL != mImpl->mEventData )
2283   {
2284     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2285
2286     if( 1u == tapCount )
2287     {
2288       // This is to avoid unnecessary relayouts when tapping an empty text-field
2289       bool relayoutNeeded( false );
2290
2291       if( ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
2292           ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
2293       {
2294         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2295       }
2296
2297       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != mImpl->mEventData->mState ) )
2298       {
2299         // Already in an active state so show a popup
2300         if( !mImpl->IsClipboardEmpty() )
2301         {
2302           // Shows Paste popup but could show full popup with Selection options. ( EDITING_WITH_POPUP )
2303           mImpl->ChangeState( EventData::EDITING_WITH_PASTE_POPUP );
2304         }
2305         else
2306         {
2307           mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2308         }
2309         relayoutNeeded = true;
2310       }
2311       else
2312       {
2313         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2314         {
2315           // Hide placeholder text
2316           ResetText();
2317         }
2318
2319         if( EventData::INACTIVE == mImpl->mEventData->mState )
2320         {
2321           mImpl->ChangeState( EventData::EDITING );
2322         }
2323         else if( !mImpl->IsClipboardEmpty() )
2324         {
2325           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2326         }
2327         relayoutNeeded = true;
2328       }
2329
2330       // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2331       if( relayoutNeeded )
2332       {
2333         Event event( Event::TAP_EVENT );
2334         event.p1.mUint = tapCount;
2335         event.p2.mFloat = x;
2336         event.p3.mFloat = y;
2337         mImpl->mEventData->mEventQueue.push_back( event );
2338
2339         mImpl->RequestRelayout();
2340       }
2341     }
2342     else if( 2u == tapCount )
2343     {
2344       if( mImpl->mEventData->mSelectionEnabled &&
2345           mImpl->IsShowingRealText() )
2346       {
2347         SelectEvent( x, y, false );
2348       }
2349     }
2350   }
2351
2352   // Reset keyboard as tap event has occurred.
2353   mImpl->ResetImfManager();
2354 }
2355
2356 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2357         // Show cursor and grabhandle on first tap, this matches the behaviour of tapping when already editing
2358 {
2359   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2360
2361   if( NULL != mImpl->mEventData )
2362   {
2363     Event event( Event::PAN_EVENT );
2364     event.p1.mInt = state;
2365     event.p2.mFloat = displacement.x;
2366     event.p3.mFloat = displacement.y;
2367     mImpl->mEventData->mEventQueue.push_back( event );
2368
2369     mImpl->RequestRelayout();
2370   }
2371 }
2372
2373 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2374 {
2375   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2376
2377   if( ( state == Gesture::Started ) &&
2378       ( NULL != mImpl->mEventData ) )
2379   {
2380     if( !mImpl->IsShowingRealText() )
2381     {
2382       Event event( Event::LONG_PRESS_EVENT );
2383       event.p1.mInt = state;
2384       mImpl->mEventData->mEventQueue.push_back( event );
2385       mImpl->RequestRelayout();
2386     }
2387     else
2388     {
2389       // The 1st long-press on inactive text-field is treated as tap
2390       if( EventData::INACTIVE == mImpl->mEventData->mState )
2391       {
2392         mImpl->ChangeState( EventData::EDITING );
2393
2394         Event event( Event::TAP_EVENT );
2395         event.p1.mUint = 1;
2396         event.p2.mFloat = x;
2397         event.p3.mFloat = y;
2398         mImpl->mEventData->mEventQueue.push_back( event );
2399
2400         mImpl->RequestRelayout();
2401       }
2402       else
2403       {
2404         // Reset the imf manger to commit the pre-edit before selecting the text.
2405         mImpl->ResetImfManager();
2406
2407         SelectEvent( x, y, false );
2408       }
2409     }
2410   }
2411 }
2412
2413 void Controller::SelectEvent( float x, float y, bool selectAll )
2414 {
2415   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
2416
2417   if( NULL != mImpl->mEventData )
2418   {
2419     mImpl->ChangeState( EventData::SELECTING );
2420
2421     if( selectAll )
2422     {
2423       Event event( Event::SELECT_ALL );
2424       mImpl->mEventData->mEventQueue.push_back( event );
2425     }
2426     else
2427     {
2428       Event event( Event::SELECT );
2429       event.p2.mFloat = x;
2430       event.p3.mFloat = y;
2431       mImpl->mEventData->mEventQueue.push_back( event );
2432     }
2433
2434     mImpl->RequestRelayout();
2435   }
2436 }
2437
2438 void Controller::GetTargetSize( Vector2& targetSize )
2439 {
2440   targetSize = mImpl->mVisualModel->mControlSize;
2441 }
2442
2443 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2444 {
2445   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
2446 }
2447
2448 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2449 {
2450   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2451
2452   if( NULL != mImpl->mEventData )
2453   {
2454     switch( handleType )
2455     {
2456       case GRAB_HANDLE:
2457       {
2458         Event event( Event::GRAB_HANDLE_EVENT );
2459         event.p1.mUint  = state;
2460         event.p2.mFloat = x;
2461         event.p3.mFloat = y;
2462
2463         mImpl->mEventData->mEventQueue.push_back( event );
2464         break;
2465       }
2466       case LEFT_SELECTION_HANDLE:
2467       {
2468         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2469         event.p1.mUint  = state;
2470         event.p2.mFloat = x;
2471         event.p3.mFloat = y;
2472
2473         mImpl->mEventData->mEventQueue.push_back( event );
2474         break;
2475       }
2476       case RIGHT_SELECTION_HANDLE:
2477       {
2478         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2479         event.p1.mUint  = state;
2480         event.p2.mFloat = x;
2481         event.p3.mFloat = y;
2482
2483         mImpl->mEventData->mEventQueue.push_back( event );
2484         break;
2485       }
2486       case LEFT_SELECTION_HANDLE_MARKER:
2487       case RIGHT_SELECTION_HANDLE_MARKER:
2488       {
2489         // Markers do not move the handles.
2490         break;
2491       }
2492       case HANDLE_TYPE_COUNT:
2493       {
2494         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2495       }
2496     }
2497
2498     mImpl->RequestRelayout();
2499   }
2500 }
2501
2502 void Controller::PasteText( const std::string& stringToPaste )
2503 {
2504   InsertText( stringToPaste, Text::Controller::COMMIT );
2505   mImpl->ChangeState( EventData::EDITING );
2506   mImpl->RequestRelayout();
2507
2508   // Do this last since it provides callbacks into application code
2509   mImpl->mControlInterface.TextChanged();
2510 }
2511
2512 void Controller::PasteClipboardItemEvent()
2513 {
2514   // Retrieve the clipboard contents first
2515   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2516   std::string stringToPaste( notifier.GetContent() );
2517
2518   // Commit the current pre-edit text; the contents of the clipboard should be appended
2519   mImpl->ResetImfManager();
2520
2521   // Temporary disable hiding clipboard
2522   mImpl->SetClipboardHideEnable( false );
2523
2524   // Paste
2525   PasteText( stringToPaste );
2526
2527   mImpl->SetClipboardHideEnable( true );
2528 }
2529
2530 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2531 {
2532   if( NULL == mImpl->mEventData )
2533   {
2534     return;
2535   }
2536
2537   switch( button )
2538   {
2539     case Toolkit::TextSelectionPopup::CUT:
2540     {
2541       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2542       mImpl->mOperationsPending = ALL_OPERATIONS;
2543
2544       if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2545           !mImpl->IsPlaceholderAvailable() )
2546       {
2547         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2548       }
2549       else
2550       {
2551         ShowPlaceholderText();
2552       }
2553
2554       mImpl->mEventData->mUpdateCursorPosition = true;
2555       mImpl->mEventData->mScrollAfterDelete = true;
2556
2557       mImpl->RequestRelayout();
2558       mImpl->mControlInterface.TextChanged();
2559       break;
2560     }
2561     case Toolkit::TextSelectionPopup::COPY:
2562     {
2563       mImpl->SendSelectionToClipboard( false ); // Text not modified
2564       mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
2565       break;
2566     }
2567     case Toolkit::TextSelectionPopup::PASTE:
2568     {
2569       std::string stringToPaste("");
2570       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
2571       PasteText( stringToPaste );
2572       break;
2573     }
2574     case Toolkit::TextSelectionPopup::SELECT:
2575     {
2576       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2577
2578       if( mImpl->mEventData->mSelectionEnabled )
2579       {
2580         // Creates a SELECT event.
2581         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2582       }
2583       break;
2584     }
2585     case Toolkit::TextSelectionPopup::SELECT_ALL:
2586     {
2587       // Creates a SELECT_ALL event
2588       SelectEvent( 0.f, 0.f, true );
2589       break;
2590     }
2591     case Toolkit::TextSelectionPopup::CLIPBOARD:
2592     {
2593       mImpl->ShowClipboard();
2594       break;
2595     }
2596     case Toolkit::TextSelectionPopup::NONE:
2597     {
2598       // Nothing to do.
2599       break;
2600     }
2601   }
2602 }
2603
2604 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2605 {
2606   // Whether the text needs to be relaid-out.
2607   bool requestRelayout = false;
2608
2609   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2610   bool retrieveText = false;
2611   bool retrieveCursor = false;
2612
2613   switch( imfEvent.eventName )
2614   {
2615     case ImfManager::COMMIT:
2616     {
2617       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2618       requestRelayout = true;
2619       retrieveCursor = true;
2620       break;
2621     }
2622     case ImfManager::PREEDIT:
2623     {
2624       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2625       requestRelayout = true;
2626       retrieveCursor = true;
2627       break;
2628     }
2629     case ImfManager::DELETESURROUNDING:
2630     {
2631       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2632                                            imfEvent.numberOfChars,
2633                                            DONT_UPDATE_INPUT_STYLE );
2634
2635       if( textDeleted )
2636       {
2637         if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2638             !mImpl->IsPlaceholderAvailable() )
2639         {
2640           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2641         }
2642         else
2643         {
2644           ShowPlaceholderText();
2645         }
2646         mImpl->mEventData->mUpdateCursorPosition = true;
2647         mImpl->mEventData->mScrollAfterDelete = true;
2648
2649         requestRelayout = true;
2650         retrieveCursor = true;
2651       }
2652       break;
2653     }
2654     case ImfManager::GETSURROUNDING:
2655     {
2656       retrieveText = true;
2657       retrieveCursor = true;
2658       break;
2659     }
2660     case ImfManager::VOID:
2661     {
2662       // do nothing
2663       break;
2664     }
2665   } // end switch
2666
2667   if( requestRelayout )
2668   {
2669     mImpl->mOperationsPending = ALL_OPERATIONS;
2670     mImpl->RequestRelayout();
2671
2672     // Do this last since it provides callbacks into application code
2673     mImpl->mControlInterface.TextChanged();
2674   }
2675
2676   std::string text;
2677   CharacterIndex cursorPosition = 0u;
2678   Length numberOfWhiteSpaces = 0u;
2679
2680   if( retrieveCursor )
2681   {
2682     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2683
2684     cursorPosition = mImpl->GetLogicalCursorPosition();
2685
2686     if( cursorPosition < numberOfWhiteSpaces )
2687     {
2688       cursorPosition = 0u;
2689     }
2690     else
2691     {
2692       cursorPosition -= numberOfWhiteSpaces;
2693     }
2694   }
2695
2696   if( retrieveText )
2697   {
2698     mImpl->GetText( numberOfWhiteSpaces, text );
2699   }
2700
2701   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2702
2703   return callbackData;
2704 }
2705
2706 Controller::~Controller()
2707 {
2708   delete mImpl;
2709 }
2710
2711 bool Controller::BackspaceKeyEvent()
2712 {
2713   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
2714
2715   bool removed = false;
2716
2717   if( NULL == mImpl->mEventData )
2718   {
2719     return removed;
2720   }
2721
2722   // IMF manager is no longer handling key-events
2723   mImpl->ClearPreEditFlag();
2724
2725   if( EventData::SELECTING == mImpl->mEventData->mState )
2726   {
2727     removed = RemoveSelectedText();
2728   }
2729   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
2730   {
2731     // Remove the character before the current cursor position
2732     removed = RemoveText( -1,
2733                           1,
2734                           UPDATE_INPUT_STYLE );
2735   }
2736
2737   if( removed )
2738   {
2739     if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2740         !mImpl->IsPlaceholderAvailable() )
2741     {
2742       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2743     }
2744     else
2745     {
2746       ShowPlaceholderText();
2747     }
2748     mImpl->mEventData->mUpdateCursorPosition = true;
2749     mImpl->mEventData->mScrollAfterDelete = true;
2750   }
2751
2752   return removed;
2753 }
2754
2755 void Controller::ShowPlaceholderText()
2756 {
2757   if( mImpl->IsPlaceholderAvailable() )
2758   {
2759     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
2760
2761     if( NULL == mImpl->mEventData )
2762     {
2763       return;
2764     }
2765
2766     mImpl->mEventData->mIsShowingPlaceholderText = true;
2767
2768     // Disable handles when showing place-holder text
2769     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2770     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2771     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2772
2773     const char* text( NULL );
2774     size_t size( 0 );
2775
2776     // TODO - Switch placeholder text styles when changing state
2777     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
2778         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
2779     {
2780       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2781       size = mImpl->mEventData->mPlaceholderTextActive.size();
2782     }
2783     else
2784     {
2785       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2786       size = mImpl->mEventData->mPlaceholderTextInactive.size();
2787     }
2788
2789     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2790     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2791
2792     // Reset model for showing placeholder.
2793     mImpl->mLogicalModel->mText.Clear();
2794     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
2795
2796     // Convert text into UTF-32
2797     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
2798     utf32Characters.Resize( size );
2799
2800     // This is a bit horrible but std::string returns a (signed) char*
2801     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
2802
2803     // Transform a text array encoded in utf8 into an array encoded in utf32.
2804     // It returns the actual number of characters.
2805     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
2806     utf32Characters.Resize( characterCount );
2807
2808     // The characters to be added.
2809     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
2810
2811     // Reset the cursor position
2812     mImpl->mEventData->mPrimaryCursorPosition = 0;
2813
2814     // The natural size needs to be re-calculated.
2815     mImpl->mRecalculateNaturalSize = true;
2816
2817     // Apply modifications to the model
2818     mImpl->mOperationsPending = ALL_OPERATIONS;
2819
2820     // Update the rest of the model during size negotiation
2821     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
2822   }
2823 }
2824
2825 void Controller::ClearFontData()
2826 {
2827   if( mImpl->mFontDefaults )
2828   {
2829     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2830   }
2831
2832   // Set flags to update the model.
2833   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2834   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2835   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
2836
2837   mImpl->mTextUpdateInfo.mClearAll = true;
2838   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2839   mImpl->mRecalculateNaturalSize = true;
2840
2841   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2842                                                            VALIDATE_FONTS            |
2843                                                            SHAPE_TEXT                |
2844                                                            GET_GLYPH_METRICS         |
2845                                                            LAYOUT                    |
2846                                                            UPDATE_ACTUAL_SIZE        |
2847                                                            REORDER                   |
2848                                                            ALIGN );
2849 }
2850
2851 void Controller::ClearStyleData()
2852 {
2853   mImpl->mLogicalModel->mColorRuns.Clear();
2854   mImpl->mLogicalModel->ClearFontDescriptionRuns();
2855 }
2856
2857 Controller::Controller( ControlInterface& controlInterface )
2858 : mImpl( NULL )
2859 {
2860   mImpl = new Controller::Impl( controlInterface );
2861 }
2862
2863 } // namespace Text
2864
2865 } // namespace Toolkit
2866
2867 } // namespace Dali