Add a callback to get textfitted font size.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2021 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 <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
23 #include <dali/devel-api/adaptor-framework/window-devel.h>
24 #include <dali/integration-api/debug.h>
25 #include <memory.h>
26 #include <cmath>
27 #include <limits>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
31 #include <dali-toolkit/internal/text/text-controller-event-handler.h>
32 #include <dali-toolkit/internal/text/text-controller-impl.h>
33 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
34 #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
35 #include <dali-toolkit/internal/text/text-controller-relayouter.h>
36 #include <dali-toolkit/internal/text/text-controller-text-updater.h>
37 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
38
39 namespace
40 {
41 #if defined(DEBUG_ENABLED)
42 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
43 #endif
44
45 constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
46
47 const std::string EMPTY_STRING("");
48
49 template<typename Type>
50 void EnsureCreated(Type*& object)
51 {
52   if(!object)
53   {
54     object = new Type();
55   }
56 }
57
58 template<typename Type>
59 void EnsureCreated(std::unique_ptr<Type>& object)
60 {
61   if(!object)
62   {
63     object = std::unique_ptr<Type>(new Type());
64   }
65 }
66
67 template<typename Type, typename Arg1>
68 void EnsureCreated(Type*& object, Arg1 arg1)
69 {
70   if(!object)
71   {
72     object = new Type(arg1);
73   }
74 }
75
76 template<typename Type, typename Arg1, typename Arg2>
77 void EnsureCreated(Type*& object, Arg1 arg1, Arg2 arg2)
78 {
79   if(!object)
80   {
81     object = new Type(arg1, arg2);
82   }
83 }
84
85 float GetDpi()
86 {
87   unsigned int                      horizontalDpi = 0u;
88   unsigned int                      verticalDpi   = 0u;
89   Dali::TextAbstraction::FontClient fontClient    = Dali::TextAbstraction::FontClient::Get();
90   fontClient.GetDpi(horizontalDpi, verticalDpi);
91   return static_cast<float>(horizontalDpi);
92 }
93
94 float ConvertPixelToPoint(float pixel)
95 {
96   return pixel * 72.0f / GetDpi();
97 }
98
99 float ConvertPointToPixel(float point)
100 {
101   // Pixel size = Point size * DPI / 72.f
102   return point * GetDpi() / 72.0f;
103 }
104
105 void UpdateCursorPosition(Dali::Toolkit::Text::EventData* eventData)
106 {
107   if(eventData && Dali::Toolkit::Text::EventData::IsEditingState(eventData->mState))
108   {
109     // Update the cursor position if it's in editing mode
110     eventData->mDecoratorUpdated     = true;
111     eventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
112   }
113 }
114
115 } // namespace
116
117 namespace Dali::Toolkit::Text
118 {
119
120 void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
121 {
122   if(!decorator)
123   {
124     delete mImpl->mEventData;
125     mImpl->mEventData = NULL;
126
127     // Nothing else to do.
128     return;
129   }
130
131   EnsureCreated(mImpl->mEventData, decorator, inputMethodContext);
132 }
133
134 void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
135 {
136   // Metrics for bitmap & vector based glyphs are different
137   mImpl->mMetrics->SetGlyphType(glyphType);
138
139   // Clear the font-specific data
140   ClearFontData();
141
142   mImpl->RequestRelayout();
143 }
144
145 void Controller::SetMarkupProcessorEnabled(bool enable)
146 {
147   if(enable != mImpl->mMarkupProcessorEnabled)
148   {
149     //If Text was already set, call the SetText again for enabling or disabling markup
150     mImpl->mMarkupProcessorEnabled = enable;
151     std::string text;
152     GetText(text);
153     SetText(text);
154   }
155
156   mImpl->mModel->mVisualModel->SetMarkupProcessorEnabled(enable);
157 }
158
159 bool Controller::IsMarkupProcessorEnabled() const
160 {
161   return mImpl->mMarkupProcessorEnabled;
162 }
163
164 bool Controller::HasAnchors() const
165 {
166   return (mImpl->mMarkupProcessorEnabled && mImpl->mModel->mLogicalModel->mAnchors.Count() && mImpl->IsShowingRealText());
167 }
168
169 void Controller::SetAutoScrollEnabled(bool enable)
170 {
171   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable) ? "true" : "false", (mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) ? "true" : "false", this);
172
173   if(mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
174   {
175     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
176                                                             LAYOUT |
177                                                             ALIGN |
178                                                             UPDATE_LAYOUT_SIZE |
179                                                             REORDER);
180
181     if(enable)
182     {
183       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
184       mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | UPDATE_DIRECTION);
185     }
186     else
187     {
188       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
189     }
190
191     mImpl->mIsAutoScrollEnabled = enable;
192     mImpl->RequestRelayout();
193   }
194   else
195   {
196     DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
197     mImpl->mIsAutoScrollEnabled = false;
198   }
199 }
200
201 bool Controller::IsAutoScrollEnabled() const
202 {
203   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
204
205   return mImpl->mIsAutoScrollEnabled;
206 }
207
208 CharacterDirection Controller::GetAutoScrollDirection() const
209 {
210   return mImpl->mIsTextDirectionRTL;
211 }
212
213 float Controller::GetAutoScrollLineAlignment() const
214 {
215   float offset = 0.f;
216   if(mImpl->mModel->mVisualModel && (0u != mImpl->mModel->mVisualModel->mLines.Count()))
217   {
218     offset = (*mImpl->mModel->mVisualModel->mLines.Begin()).alignmentOffset;
219   }
220   return offset;
221 }
222
223 void Controller::SetHorizontalScrollEnabled(bool enable)
224 {
225   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
226   {
227     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled(enable);
228   }
229 }
230
231 bool Controller::IsHorizontalScrollEnabled() const
232 {
233   return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
234 }
235
236 void Controller::SetVerticalScrollEnabled(bool enable)
237 {
238   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
239   {
240     mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
241   }
242 }
243
244 bool Controller::IsVerticalScrollEnabled() const
245 {
246   return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
247 }
248
249 void Controller::SetSmoothHandlePanEnabled(bool enable)
250 {
251   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
252   {
253     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled(enable);
254   }
255 }
256
257 bool Controller::IsSmoothHandlePanEnabled() const
258 {
259   return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
260 }
261
262 void Controller::SetMaximumNumberOfCharacters(Length maxCharacters)
263 {
264   mImpl->mMaximumNumberOfCharacters = maxCharacters;
265 }
266
267 int Controller::GetMaximumNumberOfCharacters()
268 {
269   return mImpl->mMaximumNumberOfCharacters;
270 }
271
272 void Controller::SetEnableCursorBlink(bool enable)
273 {
274   DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "TextInput disabled");
275
276   if(mImpl->mEventData)
277   {
278     mImpl->mEventData->mCursorBlinkEnabled = enable;
279
280     if(!enable && mImpl->mEventData->mDecorator)
281     {
282       mImpl->mEventData->mDecorator->StopCursorBlink();
283     }
284   }
285 }
286
287 bool Controller::GetEnableCursorBlink() const
288 {
289   return mImpl->mEventData && mImpl->mEventData->mCursorBlinkEnabled;
290 }
291
292 void Controller::SetMultiLineEnabled(bool enable)
293 {
294   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
295
296   if(layout != mImpl->mLayoutEngine.GetLayout())
297   {
298     // Set the layout type.
299     mImpl->mLayoutEngine.SetLayout(layout);
300
301     // Set the flags to redo the layout operations
302     const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
303                                                                         UPDATE_LAYOUT_SIZE |
304                                                                         ALIGN |
305                                                                         REORDER);
306
307     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
308     mImpl->mOperationsPending                  = static_cast<OperationsMask>(mImpl->mOperationsPending | layoutOperations);
309
310     // Need to recalculate natural size
311     mImpl->mRecalculateNaturalSize = true;
312
313     mImpl->RequestRelayout();
314   }
315 }
316
317 bool Controller::IsMultiLineEnabled() const
318 {
319   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
320 }
321
322 void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
323 {
324   if(alignment != mImpl->mModel->mHorizontalAlignment)
325   {
326     // Set the alignment.
327     mImpl->mModel->mHorizontalAlignment = alignment;
328
329     // Set the flag to redo the alignment operation.
330     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
331
332     if(mImpl->mEventData)
333     {
334       mImpl->mEventData->mUpdateAlignment = true;
335
336       // Update the cursor if it's in editing mode
337       if(EventData::IsEditingState(mImpl->mEventData->mState))
338       {
339         mImpl->ChangeState(EventData::EDITING);
340         mImpl->mEventData->mUpdateCursorPosition = true;
341       }
342     }
343
344     mImpl->RequestRelayout();
345   }
346 }
347
348 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
349 {
350   return mImpl->mModel->mHorizontalAlignment;
351 }
352
353 void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
354 {
355   if(alignment != mImpl->mModel->mVerticalAlignment)
356   {
357     // Set the alignment.
358     mImpl->mModel->mVerticalAlignment = alignment;
359     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
360     mImpl->RequestRelayout();
361   }
362 }
363
364 VerticalAlignment::Type Controller::GetVerticalAlignment() const
365 {
366   return mImpl->mModel->mVerticalAlignment;
367 }
368
369 bool Controller::IsIgnoreSpacesAfterText() const
370 {
371   return mImpl->mModel->mIgnoreSpacesAfterText;
372 }
373
374 void Controller::SetIgnoreSpacesAfterText(bool ignore)
375 {
376   mImpl->mModel->mIgnoreSpacesAfterText = ignore;
377 }
378
379 void Controller::ChangedLayoutDirection()
380 {
381   mImpl->mIsLayoutDirectionChanged = true;
382 }
383
384 void Controller::SetMatchLayoutDirection(DevelText::MatchLayoutDirection type)
385 {
386   mImpl->mModel->mMatchLayoutDirection = type;
387 }
388
389 DevelText::MatchLayoutDirection Controller::GetMatchLayoutDirection() const
390 {
391   return mImpl->mModel->mMatchLayoutDirection;
392 }
393
394 void Controller::SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection)
395 {
396   mImpl->mLayoutDirection = layoutDirection;
397 }
398
399 Dali::LayoutDirection::Type Controller::GetLayoutDirection(Dali::Actor& actor) const
400 {
401   if(mImpl->mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
402      (mImpl->mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mImpl->mIsLayoutDirectionChanged))
403   {
404     return static_cast<Dali::LayoutDirection::Type>(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
405   }
406   else
407   {
408     return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
409   }
410 }
411
412 bool Controller::IsShowingRealText() const
413 {
414   return mImpl->IsShowingRealText();
415 }
416
417 void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
418 {
419   if(lineWrapMode != mImpl->mModel->mLineWrapMode)
420   {
421     // Update Text layout for applying wrap mode
422     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
423                                                             ALIGN |
424                                                             LAYOUT |
425                                                             UPDATE_LAYOUT_SIZE |
426                                                             REORDER);
427
428     if((mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
429        (mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
430     {
431       mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | GET_LINE_BREAKS);
432     }
433
434     // Set the text wrap mode.
435     mImpl->mModel->mLineWrapMode = lineWrapMode;
436
437     mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
438     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
439     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
440
441     // Request relayout
442     mImpl->RequestRelayout();
443   }
444 }
445
446 Text::LineWrap::Mode Controller::GetLineWrapMode() const
447 {
448   return mImpl->mModel->mLineWrapMode;
449 }
450
451 void Controller::SetTextElideEnabled(bool enabled)
452 {
453   mImpl->mModel->mElideEnabled = enabled;
454   mImpl->mModel->mVisualModel->SetTextElideEnabled(enabled);
455 }
456
457 bool Controller::IsTextElideEnabled() const
458 {
459   return mImpl->mModel->mElideEnabled;
460 }
461
462 void Controller::SetTextFitEnabled(bool enabled)
463 {
464   mImpl->mTextFitEnabled = enabled;
465 }
466
467 bool Controller::IsTextFitEnabled() const
468 {
469   return mImpl->mTextFitEnabled;
470 }
471
472 void Controller::SetTextFitChanged(bool changed)
473 {
474   mImpl->mTextFitChanged = changed;
475 }
476
477 bool Controller::IsTextFitChanged() const
478 {
479   return mImpl->mTextFitChanged;
480 }
481
482 void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
483 {
484   mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize);
485 }
486
487 float Controller::GetTextFitMinSize() const
488 {
489   return mImpl->mTextFitMinSize;
490 }
491
492 void Controller::SetTextFitMaxSize(float maxSize, FontSizeType type)
493 {
494   mImpl->mTextFitMaxSize = (type == POINT_SIZE) ? maxSize : ConvertPixelToPoint(maxSize);
495 }
496
497 float Controller::GetTextFitMaxSize() const
498 {
499   return mImpl->mTextFitMaxSize;
500 }
501
502 void Controller::SetTextFitStepSize(float step, FontSizeType type)
503 {
504   mImpl->mTextFitStepSize = (type == POINT_SIZE) ? step : ConvertPixelToPoint(step);
505 }
506
507 float Controller::GetTextFitStepSize() const
508 {
509   return mImpl->mTextFitStepSize;
510 }
511
512 void Controller::SetTextFitContentSize(Vector2 size)
513 {
514   mImpl->mTextFitContentSize = size;
515 }
516
517 Vector2 Controller::GetTextFitContentSize() const
518 {
519   return mImpl->mTextFitContentSize;
520 }
521
522 float Controller::GetTextFitPointSize() const
523 {
524   return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFitPointSize : 0.0f;
525 }
526
527 void Controller::SetPlaceholderTextElideEnabled(bool enabled)
528 {
529   PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
530 }
531
532 bool Controller::IsPlaceholderTextElideEnabled() const
533 {
534   return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
535 }
536
537 void Controller::SetSelectionEnabled(bool enabled)
538 {
539   mImpl->mEventData->mSelectionEnabled = enabled;
540 }
541
542 bool Controller::IsSelectionEnabled() const
543 {
544   return mImpl->mEventData->mSelectionEnabled;
545 }
546
547 void Controller::SetShiftSelectionEnabled(bool enabled)
548 {
549   mImpl->mEventData->mShiftSelectionFlag = enabled;
550 }
551
552 bool Controller::IsShiftSelectionEnabled() const
553 {
554   return mImpl->mEventData->mShiftSelectionFlag;
555 }
556
557 void Controller::SetGrabHandleEnabled(bool enabled)
558 {
559   mImpl->mEventData->mGrabHandleEnabled = enabled;
560 }
561
562 bool Controller::IsGrabHandleEnabled() const
563 {
564   return mImpl->mEventData->mGrabHandleEnabled;
565 }
566
567 void Controller::SetGrabHandlePopupEnabled(bool enabled)
568 {
569   mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
570 }
571
572 bool Controller::IsGrabHandlePopupEnabled() const
573 {
574   return mImpl->mEventData->mGrabHandlePopupEnabled;
575 }
576
577 void Controller::SetText(const std::string& text)
578 {
579   TextUpdater::SetText(*this, text);
580 }
581
582 void Controller::GetText(std::string& text) const
583 {
584   if(!mImpl->IsShowingPlaceholderText())
585   {
586     // Retrieves the text string.
587     mImpl->GetText(0u, text);
588   }
589   else
590   {
591     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this);
592   }
593 }
594
595 void Controller::SetPlaceholderText(PlaceholderType type, const std::string& text)
596 {
597   PlaceholderHandler::SetPlaceholderText(*this, type, text);
598 }
599
600 void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) const
601 {
602   PlaceholderHandler::GetPlaceholderText(*this, type, text);
603 }
604
605 void Controller::UpdateAfterFontChange(const std::string& newDefaultFont)
606 {
607   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
608
609   if(!mImpl->mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
610   {
611     DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
612     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
613
614     ClearFontData();
615
616     mImpl->RequestRelayout();
617   }
618 }
619
620 void Controller::RetrieveSelection(std::string& selectedText) const
621 {
622   mImpl->RetrieveSelection(selectedText, false);
623 }
624
625 void Controller::SetSelection(int start, int end)
626 {
627   mImpl->SetSelection(start, end);
628 }
629
630 std::pair<int, int> Controller::GetSelectionIndexes() const
631 {
632   return mImpl->GetSelectionIndexes();
633 }
634
635 void Controller::CopyStringToClipboard(const std::string& source)
636 {
637   mImpl->CopyStringToClipboard(source);
638 }
639
640 void Controller::SendSelectionToClipboard(bool deleteAfterSending)
641 {
642   mImpl->SendSelectionToClipboard(deleteAfterSending);
643 }
644
645 void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
646 {
647   EnsureCreated(mImpl->mFontDefaults);
648
649   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
650   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
651   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
652
653   // Update the cursor position if it's in editing mode
654   UpdateCursorPosition(mImpl->mEventData);
655
656   // Clear the font-specific data
657   ClearFontData();
658
659   mImpl->RequestRelayout();
660 }
661
662 const std::string& Controller::GetDefaultFontFamily() const
663 {
664   return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.family : EMPTY_STRING;
665 }
666
667 void Controller::SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily)
668 {
669   PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
670 }
671
672 const std::string& Controller::GetPlaceholderFontFamily() const
673 {
674   return PlaceholderHandler::GetPlaceholderFontFamily(*this);
675 }
676
677 void Controller::SetDefaultFontWeight(FontWeight weight)
678 {
679   EnsureCreated(mImpl->mFontDefaults);
680
681   mImpl->mFontDefaults->mFontDescription.weight = weight;
682   mImpl->mFontDefaults->weightDefined           = true;
683
684   // Update the cursor position if it's in editing mode
685   UpdateCursorPosition(mImpl->mEventData);
686
687   // Clear the font-specific data
688   ClearFontData();
689
690   mImpl->RequestRelayout();
691 }
692
693 bool Controller::IsDefaultFontWeightDefined() const
694 {
695   return mImpl->mFontDefaults && mImpl->mFontDefaults->weightDefined;
696 }
697
698 FontWeight Controller::GetDefaultFontWeight() const
699 {
700   return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.weight : TextAbstraction::FontWeight::NORMAL;
701 }
702
703 void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
704 {
705   PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
706 }
707
708 bool Controller::IsPlaceholderTextFontWeightDefined() const
709 {
710   return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);
711 }
712
713 FontWeight Controller::GetPlaceholderTextFontWeight() const
714 {
715   return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
716 }
717
718 void Controller::SetDefaultFontWidth(FontWidth width)
719 {
720   EnsureCreated(mImpl->mFontDefaults);
721
722   mImpl->mFontDefaults->mFontDescription.width = width;
723   mImpl->mFontDefaults->widthDefined           = true;
724
725   // Update the cursor position if it's in editing mode
726   UpdateCursorPosition(mImpl->mEventData);
727
728   // Clear the font-specific data
729   ClearFontData();
730
731   mImpl->RequestRelayout();
732 }
733
734 bool Controller::IsDefaultFontWidthDefined() const
735 {
736   return mImpl->mFontDefaults && mImpl->mFontDefaults->widthDefined;
737 }
738
739 FontWidth Controller::GetDefaultFontWidth() const
740 {
741   return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.width : TextAbstraction::FontWidth::NORMAL;
742 }
743
744 void Controller::SetPlaceholderTextFontWidth(FontWidth width)
745 {
746   PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
747 }
748
749 bool Controller::IsPlaceholderTextFontWidthDefined() const
750 {
751   return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
752 }
753
754 FontWidth Controller::GetPlaceholderTextFontWidth() const
755 {
756   return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
757 }
758
759 void Controller::SetDefaultFontSlant(FontSlant slant)
760 {
761   EnsureCreated(mImpl->mFontDefaults);
762
763   mImpl->mFontDefaults->mFontDescription.slant = slant;
764   mImpl->mFontDefaults->slantDefined           = true;
765
766   // Update the cursor position if it's in editing mode
767   UpdateCursorPosition(mImpl->mEventData);
768
769   // Clear the font-specific data
770   ClearFontData();
771
772   mImpl->RequestRelayout();
773 }
774
775 bool Controller::IsDefaultFontSlantDefined() const
776 {
777   return mImpl->mFontDefaults && mImpl->mFontDefaults->slantDefined;
778 }
779
780 FontSlant Controller::GetDefaultFontSlant() const
781 {
782   return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.slant : TextAbstraction::FontSlant::NORMAL;
783 }
784
785 void Controller::SetPlaceholderTextFontSlant(FontSlant slant)
786 {
787   PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
788 }
789
790 bool Controller::IsPlaceholderTextFontSlantDefined() const
791 {
792   return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
793 }
794
795 FontSlant Controller::GetPlaceholderTextFontSlant() const
796 {
797   return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
798 }
799
800 void Controller::SetFontSizeScale(float scale)
801 {
802   mImpl->mFontSizeScale = scale;
803
804   // Update the cursor position if it's in editing mode
805   UpdateCursorPosition(mImpl->mEventData);
806
807   // Clear the font-specific data
808   ClearFontData();
809
810   mImpl->RequestRelayout();
811 }
812
813 float Controller::GetFontSizeScale() const
814 {
815   return mImpl->mFontDefaults ? mImpl->mFontSizeScale : 1.0f;
816 }
817
818 void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
819 {
820   EnsureCreated(mImpl->mFontDefaults);
821
822   mImpl->mFontDefaults->mDefaultPointSize = (type == POINT_SIZE) ? fontSize : ConvertPixelToPoint(fontSize);
823   mImpl->mFontDefaults->sizeDefined       = true;
824
825   // Update the cursor position if it's in editing mode
826   UpdateCursorPosition(mImpl->mEventData);
827
828   // Clear the font-specific data
829   ClearFontData();
830
831   mImpl->RequestRelayout();
832 }
833
834 float Controller::GetDefaultFontSize(FontSizeType type) const
835 {
836   if(mImpl->mFontDefaults)
837   {
838     return (type == POINT_SIZE) ? mImpl->mFontDefaults->mDefaultPointSize : ConvertPointToPixel(mImpl->mFontDefaults->mDefaultPointSize);
839   }
840   return 0.0f;
841 }
842
843 void Controller::SetPlaceholderTextFontSize(float fontSize, FontSizeType type)
844 {
845   PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
846 }
847
848 float Controller::GetPlaceholderTextFontSize(FontSizeType type) const
849 {
850   return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
851 }
852
853 void Controller::SetDefaultColor(const Vector4& color)
854 {
855   mImpl->mTextColor = color;
856
857   if(!mImpl->IsShowingPlaceholderText())
858   {
859     mImpl->mModel->mVisualModel->SetTextColor(color);
860     mImpl->mModel->mLogicalModel->mColorRuns.Clear();
861     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
862     mImpl->RequestRelayout();
863   }
864 }
865
866 const Vector4& Controller::GetDefaultColor() const
867 {
868   return mImpl->mTextColor;
869 }
870
871 void Controller::SetPlaceholderTextColor(const Vector4& textColor)
872 {
873   PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
874 }
875
876 const Vector4& Controller::GetPlaceholderTextColor() const
877 {
878   return PlaceholderHandler::GetPlaceholderTextColor(*this);
879 }
880
881 void Controller::SetShadowOffset(const Vector2& shadowOffset)
882 {
883   mImpl->mModel->mVisualModel->SetShadowOffset(shadowOffset);
884   mImpl->RequestRelayout();
885 }
886
887 const Vector2& Controller::GetShadowOffset() const
888 {
889   return mImpl->mModel->mVisualModel->GetShadowOffset();
890 }
891
892 void Controller::SetShadowColor(const Vector4& shadowColor)
893 {
894   mImpl->mModel->mVisualModel->SetShadowColor(shadowColor);
895   mImpl->RequestRelayout();
896 }
897
898 const Vector4& Controller::GetShadowColor() const
899 {
900   return mImpl->mModel->mVisualModel->GetShadowColor();
901 }
902
903 void Controller::SetShadowBlurRadius(const float& shadowBlurRadius)
904 {
905   if(fabsf(GetShadowBlurRadius() - shadowBlurRadius) > Math::MACHINE_EPSILON_1)
906   {
907     mImpl->mModel->mVisualModel->SetShadowBlurRadius(shadowBlurRadius);
908     mImpl->RequestRelayout();
909   }
910 }
911
912 const float& Controller::GetShadowBlurRadius() const
913 {
914   return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
915 }
916
917 void Controller::SetUnderlineColor(const Vector4& color)
918 {
919   mImpl->mModel->mVisualModel->SetUnderlineColor(color);
920   mImpl->RequestRelayout();
921 }
922
923 const Vector4& Controller::GetUnderlineColor() const
924 {
925   return mImpl->mModel->mVisualModel->GetUnderlineColor();
926 }
927
928 void Controller::SetUnderlineEnabled(bool enabled)
929 {
930   mImpl->mModel->mVisualModel->SetUnderlineEnabled(enabled);
931   mImpl->RequestRelayout();
932 }
933
934 bool Controller::IsUnderlineEnabled() const
935 {
936   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
937 }
938
939 void Controller::SetUnderlineHeight(float height)
940 {
941   mImpl->mModel->mVisualModel->SetUnderlineHeight(height);
942   mImpl->RequestRelayout();
943 }
944
945 float Controller::GetUnderlineHeight() const
946 {
947   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
948 }
949
950 void Controller::SetOutlineColor(const Vector4& color)
951 {
952   mImpl->mModel->mVisualModel->SetOutlineColor(color);
953   mImpl->RequestRelayout();
954 }
955
956 const Vector4& Controller::GetOutlineColor() const
957 {
958   return mImpl->mModel->mVisualModel->GetOutlineColor();
959 }
960
961 void Controller::SetOutlineWidth(uint16_t width)
962 {
963   mImpl->mModel->mVisualModel->SetOutlineWidth(width);
964   mImpl->RequestRelayout();
965 }
966
967 uint16_t Controller::GetOutlineWidth() const
968 {
969   return mImpl->mModel->mVisualModel->GetOutlineWidth();
970 }
971
972 void Controller::SetBackgroundColor(const Vector4& color)
973 {
974   mImpl->mModel->mVisualModel->SetBackgroundColor(color);
975   mImpl->RequestRelayout();
976 }
977
978 const Vector4& Controller::GetBackgroundColor() const
979 {
980   return mImpl->mModel->mVisualModel->GetBackgroundColor();
981 }
982
983 void Controller::SetBackgroundEnabled(bool enabled)
984 {
985   mImpl->mModel->mVisualModel->SetBackgroundEnabled(enabled);
986   mImpl->RequestRelayout();
987 }
988
989 bool Controller::IsBackgroundEnabled() const
990 {
991   return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
992 }
993
994 void Controller::SetDefaultEmbossProperties(const std::string& embossProperties)
995 {
996   EnsureCreated(mImpl->mEmbossDefaults);
997   mImpl->mEmbossDefaults->properties = embossProperties;
998 }
999
1000 const std::string& Controller::GetDefaultEmbossProperties() const
1001 {
1002   return mImpl->mEmbossDefaults ? mImpl->mEmbossDefaults->properties : EMPTY_STRING;
1003 }
1004
1005 void Controller::SetDefaultOutlineProperties(const std::string& outlineProperties)
1006 {
1007   EnsureCreated(mImpl->mOutlineDefaults);
1008   mImpl->mOutlineDefaults->properties = outlineProperties;
1009 }
1010
1011 const std::string& Controller::GetDefaultOutlineProperties() const
1012 {
1013   return mImpl->mOutlineDefaults ? mImpl->mOutlineDefaults->properties : EMPTY_STRING;
1014 }
1015
1016 void Controller::RelayoutForNewLineSize()
1017 {
1018   // relayout all characters
1019   mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
1020   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1021   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
1022   mImpl->mOperationsPending                          = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
1023
1024   //remove selection
1025   if(mImpl->mEventData && mImpl->mEventData->mState == EventData::SELECTING)
1026   {
1027     mImpl->ChangeState(EventData::EDITING);
1028   }
1029
1030   mImpl->RequestRelayout();
1031 }
1032
1033 bool Controller::SetDefaultLineSpacing(float lineSpacing)
1034 {
1035   if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
1036   {
1037     mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
1038     mImpl->mRecalculateNaturalSize = true;
1039
1040     RelayoutForNewLineSize();
1041     return true;
1042   }
1043   return false;
1044 }
1045
1046 float Controller::GetDefaultLineSpacing() const
1047 {
1048   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1049 }
1050
1051 bool Controller::SetDefaultLineSize(float lineSize)
1052 {
1053   if(std::fabs(lineSize - mImpl->mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
1054   {
1055     mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
1056     mImpl->mRecalculateNaturalSize = true;
1057
1058     RelayoutForNewLineSize();
1059     return true;
1060   }
1061   return false;
1062 }
1063
1064 float Controller::GetDefaultLineSize() const
1065 {
1066   return mImpl->mLayoutEngine.GetDefaultLineSize();
1067 }
1068
1069 void Controller::SetInputColor(const Vector4& color)
1070 {
1071   if(mImpl->mEventData)
1072   {
1073     mImpl->mEventData->mInputStyle.textColor      = color;
1074     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1075
1076     if(EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState)
1077     {
1078       if(EventData::SELECTING == mImpl->mEventData->mState)
1079       {
1080         const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1081
1082         // Get start and end position of selection
1083         const CharacterIndex startOfSelectedText  = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1084         const Length         lengthOfSelectedText = (handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
1085
1086         // Add the color run.
1087         const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1088         mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
1089
1090         ColorRun& colorRun                       = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
1091         colorRun.color                           = color;
1092         colorRun.characterRun.characterIndex     = startOfSelectedText;
1093         colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1094
1095         mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
1096         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1097         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
1098       }
1099       else
1100       {
1101         mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
1102         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1103         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
1104       }
1105
1106       // Request to relayout.
1107       mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1108       mImpl->RequestRelayout();
1109     }
1110   }
1111 }
1112
1113 const Vector4& Controller::GetInputColor() const
1114 {
1115   // Return event text input color if we have it, otherwise just return the default text's color
1116   return mImpl->mEventData ? mImpl->mEventData->mInputStyle.textColor : mImpl->mTextColor;
1117 }
1118
1119 void Controller::SetInputFontFamily(const std::string& fontFamily)
1120 {
1121   InputFontHandler::SetInputFontFamily(*this, fontFamily);
1122 }
1123
1124 const std::string& Controller::GetInputFontFamily() const
1125 {
1126   return InputFontHandler::GetInputFontFamily(*this);
1127 }
1128
1129 void Controller::SetInputFontWeight(FontWeight weight)
1130 {
1131   InputFontHandler::SetInputFontWeight(*this, weight);
1132 }
1133
1134 bool Controller::IsInputFontWeightDefined() const
1135 {
1136   return InputFontHandler::IsInputFontWeightDefined(*this);
1137 }
1138
1139 FontWeight Controller::GetInputFontWeight() const
1140 {
1141   return InputFontHandler::GetInputFontWeight(*this);
1142 }
1143
1144 void Controller::SetInputFontWidth(FontWidth width)
1145 {
1146   InputFontHandler::SetInputFontWidth(*this, width);
1147 }
1148
1149 bool Controller::IsInputFontWidthDefined() const
1150 {
1151   return InputFontHandler::IsInputFontWidthDefined(*this);
1152 }
1153
1154 FontWidth Controller::GetInputFontWidth() const
1155 {
1156   return InputFontHandler::GetInputFontWidth(*this);
1157 }
1158
1159 void Controller::SetInputFontSlant(FontSlant slant)
1160 {
1161   InputFontHandler::SetInputFontSlant(*this, slant);
1162 }
1163
1164 bool Controller::IsInputFontSlantDefined() const
1165 {
1166   return InputFontHandler::IsInputFontSlantDefined(*this);
1167 }
1168
1169 FontSlant Controller::GetInputFontSlant() const
1170 {
1171   return InputFontHandler::GetInputFontSlant(*this);
1172 }
1173
1174 void Controller::SetInputFontPointSize(float size)
1175 {
1176   InputFontHandler::SetInputFontPointSize(*this, size);
1177 }
1178
1179 float Controller::GetInputFontPointSize() const
1180 {
1181   return InputFontHandler::GetInputFontPointSize(*this);
1182 }
1183
1184 void Controller::SetInputLineSpacing(float lineSpacing)
1185 {
1186   if(mImpl->mEventData)
1187   {
1188     mImpl->mEventData->mInputStyle.lineSpacing          = lineSpacing;
1189     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1190   }
1191 }
1192
1193 float Controller::GetInputLineSpacing() const
1194 {
1195   return mImpl->mEventData ? mImpl->mEventData->mInputStyle.lineSpacing : 0.0f;
1196 }
1197
1198 void Controller::SetInputShadowProperties(const std::string& shadowProperties)
1199 {
1200   if(mImpl->mEventData)
1201   {
1202     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1203   }
1204 }
1205
1206 const std::string& Controller::GetInputShadowProperties() const
1207 {
1208   return mImpl->mEventData ? mImpl->mEventData->mInputStyle.shadowProperties : EMPTY_STRING;
1209 }
1210
1211 void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
1212 {
1213   if(mImpl->mEventData)
1214   {
1215     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1216   }
1217 }
1218
1219 const std::string& Controller::GetInputUnderlineProperties() const
1220 {
1221   return mImpl->mEventData ? mImpl->mEventData->mInputStyle.underlineProperties : EMPTY_STRING;
1222 }
1223
1224 void Controller::SetInputEmbossProperties(const std::string& embossProperties)
1225 {
1226   if(mImpl->mEventData)
1227   {
1228     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1229   }
1230 }
1231
1232 const std::string& Controller::GetInputEmbossProperties() const
1233 {
1234   return mImpl->mEventData ? mImpl->mEventData->mInputStyle.embossProperties : GetDefaultEmbossProperties();
1235 }
1236
1237 void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
1238 {
1239   if(mImpl->mEventData)
1240   {
1241     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1242   }
1243 }
1244
1245 const std::string& Controller::GetInputOutlineProperties() const
1246 {
1247   return mImpl->mEventData ? mImpl->mEventData->mInputStyle.outlineProperties : GetDefaultOutlineProperties();
1248 }
1249
1250 void Controller::SetInputModePassword(bool passwordInput)
1251 {
1252   if(mImpl->mEventData)
1253   {
1254     mImpl->mEventData->mPasswordInput = passwordInput;
1255   }
1256 }
1257
1258 bool Controller::IsInputModePassword()
1259 {
1260   return mImpl->mEventData && mImpl->mEventData->mPasswordInput;
1261 }
1262
1263 void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
1264 {
1265   if(mImpl->mEventData)
1266   {
1267     mImpl->mEventData->mDoubleTapAction = action;
1268   }
1269 }
1270
1271 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1272 {
1273   return mImpl->mEventData ? mImpl->mEventData->mDoubleTapAction : NoTextTap::NO_ACTION;
1274 }
1275
1276 void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
1277 {
1278   if(mImpl->mEventData)
1279   {
1280     mImpl->mEventData->mLongPressAction = action;
1281   }
1282 }
1283
1284 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1285 {
1286   return mImpl->mEventData ? mImpl->mEventData->mLongPressAction : NoTextTap::NO_ACTION;
1287 }
1288
1289 bool Controller::IsUnderlineSetByString()
1290 {
1291   return mImpl->mUnderlineSetByString;
1292 }
1293
1294 void Controller::UnderlineSetByString(bool setByString)
1295 {
1296   mImpl->mUnderlineSetByString = setByString;
1297 }
1298
1299 bool Controller::IsShadowSetByString()
1300 {
1301   return mImpl->mShadowSetByString;
1302 }
1303
1304 void Controller::ShadowSetByString(bool setByString)
1305 {
1306   mImpl->mShadowSetByString = setByString;
1307 }
1308
1309 bool Controller::IsOutlineSetByString()
1310 {
1311   return mImpl->mOutlineSetByString;
1312 }
1313
1314 void Controller::OutlineSetByString(bool setByString)
1315 {
1316   mImpl->mOutlineSetByString = setByString;
1317 }
1318
1319 bool Controller::IsFontStyleSetByString()
1320 {
1321   return mImpl->mFontStyleSetByString;
1322 }
1323
1324 void Controller::FontStyleSetByString(bool setByString)
1325 {
1326   mImpl->mFontStyleSetByString = setByString;
1327 }
1328
1329 Layout::Engine& Controller::GetLayoutEngine()
1330 {
1331   return mImpl->mLayoutEngine;
1332 }
1333
1334 View& Controller::GetView()
1335 {
1336   return mImpl->mView;
1337 }
1338
1339 Vector3 Controller::GetNaturalSize()
1340 {
1341   return Relayouter::GetNaturalSize(*this);
1342 }
1343
1344 bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
1345 {
1346   return Relayouter::CheckForTextFit(*this, pointSize, layoutSize);
1347 }
1348
1349 void Controller::FitPointSizeforLayout(Size layoutSize)
1350 {
1351   Relayouter::FitPointSizeforLayout(*this, layoutSize);
1352 }
1353
1354 float Controller::GetHeightForWidth(float width)
1355 {
1356   return Relayouter::GetHeightForWidth(*this, width);
1357 }
1358
1359 int Controller::GetLineCount(float width)
1360 {
1361   GetHeightForWidth(width);
1362   return mImpl->mModel->GetNumberOfLines();
1363 }
1364
1365 const ModelInterface* const Controller::GetTextModel() const
1366 {
1367   return mImpl->mModel.Get();
1368 }
1369
1370 float Controller::GetScrollAmountByUserInput()
1371 {
1372   float scrollAmount = 0.0f;
1373
1374   if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1375   {
1376     scrollAmount                          = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
1377     mImpl->mEventData->mCheckScrollAmount = false;
1378   }
1379   return scrollAmount;
1380 }
1381
1382 bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
1383 {
1384   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1385   bool           isScrolled;
1386
1387   controlHeight  = mImpl->mModel->mVisualModel->mControlSize.height;
1388   layoutHeight   = layout.height;
1389   scrollPosition = mImpl->mModel->mScrollPosition.y;
1390   isScrolled     = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
1391   return isScrolled;
1392 }
1393
1394 void Controller::SetHiddenInputOption(const Property::Map& options)
1395 {
1396   EnsureCreated<HiddenText, Controller*>(mImpl->mHiddenInput, this);
1397   mImpl->mHiddenInput->SetProperties(options);
1398 }
1399
1400 void Controller::GetHiddenInputOption(Property::Map& options)
1401 {
1402   if(mImpl->mHiddenInput)
1403   {
1404     mImpl->mHiddenInput->GetProperties(options);
1405   }
1406 }
1407
1408 void Controller::SetInputFilterOption(const Property::Map& options)
1409 {
1410   EnsureCreated(mImpl->mInputFilter);
1411   mImpl->mInputFilter->SetProperties(options);
1412 }
1413
1414 void Controller::GetInputFilterOption(Property::Map& options)
1415 {
1416   if(mImpl->mInputFilter)
1417   {
1418     mImpl->mInputFilter->GetProperties(options);
1419   }
1420 }
1421
1422 void Controller::SetPlaceholderProperty(const Property::Map& map)
1423 {
1424   PlaceholderHandler::SetPlaceholderProperty(*this, map);
1425 }
1426
1427 void Controller::GetPlaceholderProperty(Property::Map& map)
1428 {
1429   PlaceholderHandler::GetPlaceholderProperty(*this, map);
1430 }
1431
1432 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1433 {
1434   // Make sure the model is up-to-date before layouting
1435   ProcessModifyEvents();
1436
1437   if(mImpl->mUpdateTextDirection)
1438   {
1439     // Operations that can be done only once until the text changes.
1440     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1441                                                                           GET_SCRIPTS |
1442                                                                           VALIDATE_FONTS |
1443                                                                           GET_LINE_BREAKS |
1444                                                                           BIDI_INFO |
1445                                                                           SHAPE_TEXT |
1446                                                                           GET_GLYPH_METRICS);
1447
1448     // Set the update info to relayout the whole text.
1449     mImpl->mTextUpdateInfo.mParagraphCharacterIndex     = 0u;
1450     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1451
1452     // Make sure the model is up-to-date before layouting
1453     mImpl->UpdateModel(onlyOnceOperations);
1454
1455     Vector3 naturalSize;
1456     DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1457                static_cast<OperationsMask>(onlyOnceOperations |
1458                                            LAYOUT | REORDER | UPDATE_DIRECTION),
1459                naturalSize.GetVectorXY());
1460
1461     // Do not do again the only once operations.
1462     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1463
1464     // Clear the update info. This info will be set the next time the text is updated.
1465     mImpl->mTextUpdateInfo.Clear();
1466
1467     // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1468     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1469
1470     mImpl->mUpdateTextDirection = false;
1471   }
1472
1473   return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1474 }
1475
1476 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1477 {
1478   return mImpl->mModel->GetVerticalLineAlignment();
1479 }
1480
1481 void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
1482 {
1483   mImpl->mModel->mVerticalLineAlignment = alignment;
1484 }
1485
1486 Toolkit::DevelText::EllipsisPosition::Type Controller::GetEllipsisPosition() const
1487 {
1488   return mImpl->mModel->GetEllipsisPosition();
1489 }
1490
1491 void Controller::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
1492 {
1493   mImpl->mModel->mEllipsisPosition = ellipsisPosition;
1494   mImpl->mModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
1495 }
1496
1497 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
1498 {
1499   return Relayouter::Relayout(*this, size, layoutDirection);
1500 }
1501
1502 void Controller::RequestRelayout()
1503 {
1504   mImpl->RequestRelayout();
1505 }
1506
1507 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
1508 {
1509   return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
1510 }
1511
1512 void Controller::ProcessInputStyleChangedSignals()
1513 {
1514   if(mImpl->mEventData)
1515   {
1516     if(mImpl->mEditableControlInterface)
1517     {
1518       // Emit the input style changed signal for each mask
1519       std::for_each(mImpl->mEventData->mInputStyleChangedQueue.begin(),
1520                     mImpl->mEventData->mInputStyleChangedQueue.end(),
1521                     [&](const auto mask) { mImpl->mEditableControlInterface->InputStyleChanged(mask); } );
1522     }
1523
1524     mImpl->mEventData->mInputStyleChangedQueue.Clear();
1525   }
1526 }
1527
1528 void Controller::KeyboardFocusGainEvent()
1529 {
1530   EventHandler::KeyboardFocusGainEvent(*this);
1531 }
1532
1533 void Controller::KeyboardFocusLostEvent()
1534 {
1535   EventHandler::KeyboardFocusLostEvent(*this);
1536 }
1537
1538 bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
1539 {
1540   return EventHandler::KeyEvent(*this, keyEvent);
1541 }
1542
1543 void Controller::AnchorEvent(float x, float y)
1544 {
1545   EventHandler::AnchorEvent(*this, x, y);
1546 }
1547
1548 void Controller::TapEvent(unsigned int tapCount, float x, float y)
1549 {
1550   EventHandler::TapEvent(*this, tapCount, x, y);
1551 }
1552
1553 void Controller::PanEvent(GestureState state, const Vector2& displacement)
1554 {
1555   EventHandler::PanEvent(*this, state, displacement);
1556 }
1557
1558 void Controller::LongPressEvent(GestureState state, float x, float y)
1559 {
1560   EventHandler::LongPressEvent(*this, state, x, y);
1561 }
1562
1563 void Controller::SelectEvent(float x, float y, SelectionType selectType)
1564 {
1565   EventHandler::SelectEvent(*this, x, y, selectType);
1566 }
1567
1568 void Controller::SelectEvent(const uint32_t start, const uint32_t end, SelectionType selectType)
1569 {
1570   EventHandler::SelectEvent(*this, start, end, selectType);
1571 }
1572
1573 void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
1574 {
1575   if(mImpl->mEventData)
1576   {
1577     mImpl->mEventData->mCheckScrollAmount     = true;
1578     mImpl->mEventData->mIsLeftHandleSelected  = true;
1579     mImpl->mEventData->mIsRightHandleSelected = true;
1580     mImpl->SetTextSelectionRange(start, end);
1581     mImpl->RequestRelayout();
1582     KeyboardFocusGainEvent();
1583   }
1584 }
1585
1586 Uint32Pair Controller::GetTextSelectionRange() const
1587 {
1588   return mImpl->GetTextSelectionRange();
1589 }
1590
1591 CharacterIndex Controller::GetPrimaryCursorPosition() const
1592 {
1593   return mImpl->GetPrimaryCursorPosition();
1594 }
1595
1596 bool Controller::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
1597 {
1598   if(mImpl->mEventData)
1599   {
1600     mImpl->mEventData->mCheckScrollAmount     = true;
1601     mImpl->mEventData->mIsLeftHandleSelected  = true;
1602     mImpl->mEventData->mIsRightHandleSelected = true;
1603     mImpl->mEventData->mCheckScrollAmount     = true;
1604     if(mImpl->SetPrimaryCursorPosition(index, focused) && focused)
1605     {
1606       KeyboardFocusGainEvent();
1607       return true;
1608     }
1609   }
1610   return false;
1611 }
1612
1613 void Controller::SelectWholeText()
1614 {
1615   SelectEvent(0.f, 0.f, SelectionType::ALL);
1616 }
1617
1618 void Controller::SelectNone()
1619 {
1620   SelectEvent(0.f, 0.f, SelectionType::NONE);
1621 }
1622
1623 void Controller::SelectText(const uint32_t start, const uint32_t end)
1624 {
1625   SelectEvent(start, end, SelectionType::RANGE);
1626 }
1627
1628 string Controller::GetSelectedText() const
1629 {
1630   string text;
1631   if(EventData::SELECTING == mImpl->mEventData->mState)
1632   {
1633     mImpl->RetrieveSelection(text, false);
1634   }
1635   return text;
1636 }
1637
1638 string Controller::CopyText()
1639 {
1640   string text;
1641   mImpl->RetrieveSelection(text, false);
1642   mImpl->SendSelectionToClipboard(false); // Text not modified
1643
1644   mImpl->mEventData->mUpdateCursorPosition = true;
1645
1646   mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
1647
1648   return text;
1649 }
1650
1651 string Controller::CutText()
1652 {
1653   string text;
1654   mImpl->RetrieveSelection(text, false);
1655
1656   if(!IsEditable())
1657   {
1658     return EMPTY_STRING;
1659   }
1660
1661   mImpl->SendSelectionToClipboard(true); // Synchronous call to modify text
1662   mImpl->mOperationsPending = ALL_OPERATIONS;
1663
1664   if((0u != mImpl->mModel->mLogicalModel->mText.Count()) ||
1665      !mImpl->IsPlaceholderAvailable())
1666   {
1667     mImpl->QueueModifyEvent(ModifyEvent::TEXT_DELETED);
1668   }
1669   else
1670   {
1671     ShowPlaceholderText();
1672   }
1673
1674   mImpl->mEventData->mUpdateCursorPosition = true;
1675   mImpl->mEventData->mScrollAfterDelete    = true;
1676
1677   mImpl->RequestRelayout();
1678
1679   if(nullptr != mImpl->mEditableControlInterface)
1680   {
1681     mImpl->mEditableControlInterface->TextChanged(true);
1682   }
1683   return text;
1684 }
1685
1686 void Controller::PasteText()
1687 {
1688   mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
1689 }
1690
1691 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
1692 {
1693   return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
1694 }
1695
1696 void Controller::PasteClipboardItemEvent()
1697 {
1698   EventHandler::PasteClipboardItemEvent(*this);
1699 }
1700
1701 void Controller::GetTargetSize(Vector2& targetSize)
1702 {
1703   targetSize = mImpl->mModel->mVisualModel->mControlSize;
1704 }
1705
1706 void Controller::AddDecoration(Actor& actor, bool needsClipping)
1707 {
1708   if(mImpl->mEditableControlInterface)
1709   {
1710     mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
1711   }
1712 }
1713
1714 bool Controller::IsEditable() const
1715 {
1716   return mImpl->IsEditable();
1717 }
1718
1719 void Controller::SetEditable(bool editable)
1720 {
1721   mImpl->SetEditable(editable);
1722   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
1723   {
1724     mImpl->mEventData->mDecorator->SetEditable(editable);
1725   }
1726 }
1727
1728 void Controller::ScrollBy(Vector2 scroll)
1729 {
1730   if(mImpl->mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
1731   {
1732     const Vector2& layoutSize    = mImpl->mModel->mVisualModel->GetLayoutSize();
1733     const Vector2  currentScroll = mImpl->mModel->mScrollPosition;
1734
1735     scroll.x = -scroll.x;
1736     scroll.y = -scroll.y;
1737
1738     if(fabs(scroll.x) > Math::MACHINE_EPSILON_0)
1739     {
1740       mImpl->mModel->mScrollPosition.x += scroll.x;
1741       mImpl->ClampHorizontalScroll(layoutSize);
1742     }
1743
1744     if(fabs(scroll.y) > Math::MACHINE_EPSILON_0)
1745     {
1746       mImpl->mModel->mScrollPosition.y += scroll.y;
1747       mImpl->ClampVerticalScroll(layoutSize);
1748     }
1749
1750     if(mImpl->mModel->mScrollPosition != currentScroll)
1751     {
1752       mImpl->mEventData->mDecorator->UpdatePositions(mImpl->mModel->mScrollPosition - currentScroll);
1753       mImpl->RequestRelayout();
1754     }
1755   }
1756 }
1757
1758 float Controller::GetHorizontalScrollPosition()
1759 {
1760   // Scroll values are negative internally so we convert them to positive numbers
1761   return mImpl->mEventData ? -mImpl->mModel->mScrollPosition.x : 0.0f;
1762 }
1763
1764 float Controller::GetVerticalScrollPosition()
1765 {
1766   // Scroll values are negative internally so we convert them to positive numbers
1767   return mImpl->mEventData ? -mImpl->mModel->mScrollPosition.y : 0.0f;
1768 }
1769
1770 void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
1771 {
1772   EventHandler::DecorationEvent(*this, handleType, state, x, y);
1773 }
1774
1775 void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
1776 {
1777   EventHandler::TextPopupButtonTouched(*this, button);
1778 }
1779
1780 void Controller::DisplayTimeExpired()
1781 {
1782   mImpl->mEventData->mUpdateCursorPosition = true;
1783   // Apply modifications to the model
1784   mImpl->mOperationsPending = ALL_OPERATIONS;
1785
1786   mImpl->RequestRelayout();
1787 }
1788
1789 void Controller::InsertText(const std::string& text, Controller::InsertType type)
1790 {
1791   TextUpdater::InsertText(*this, text, type);
1792 }
1793
1794 void Controller::PasteText(const std::string& stringToPaste)
1795 {
1796   TextUpdater::PasteText(*this, stringToPaste);
1797 }
1798
1799 bool Controller::RemoveText(int cursorOffset, int numberOfCharacters, UpdateInputStyleType type)
1800 {
1801   return TextUpdater::RemoveText(*this, cursorOffset, numberOfCharacters, type);
1802 }
1803
1804 bool Controller::RemoveSelectedText()
1805 {
1806   return TextUpdater::RemoveSelectedText(*this);
1807 }
1808
1809 void Controller::InsertTextAnchor(int numberOfCharacters, CharacterIndex previousCursorIndex)
1810 {
1811   TextUpdater::InsertTextAnchor(*this, numberOfCharacters, previousCursorIndex);
1812 }
1813
1814 void Controller::RemoveTextAnchor(int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex)
1815 {
1816   TextUpdater::RemoveTextAnchor(*this, cursorOffset, numberOfCharacters, previousCursorIndex);
1817 }
1818
1819 bool Controller::DoRelayout(const Size& size, OperationsMask operationsRequired, Size& layoutSize)
1820 {
1821   return Relayouter::DoRelayout(*this, size, operationsRequired, layoutSize);
1822 }
1823
1824 void Controller::CalculateVerticalOffset(const Size& controlSize)
1825 {
1826   Relayouter::CalculateVerticalOffset(*this, controlSize);
1827 }
1828
1829 void Controller::ProcessModifyEvents()
1830 {
1831   EventHandler::ProcessModifyEvents(*this);
1832 }
1833
1834 void Controller::TextReplacedEvent()
1835 {
1836   EventHandler::TextReplacedEvent(*this);
1837 }
1838
1839 void Controller::TextInsertedEvent()
1840 {
1841   EventHandler::TextInsertedEvent(*this);
1842 }
1843
1844 void Controller::TextDeletedEvent()
1845 {
1846   EventHandler::TextDeletedEvent(*this);
1847 }
1848
1849 bool Controller::DeleteEvent(int keyCode)
1850 {
1851   return EventHandler::DeleteEvent(*this, keyCode);
1852 }
1853
1854 // private : Helpers.
1855
1856 void Controller::ResetText()
1857 {
1858   TextUpdater::ResetText(*this);
1859 }
1860
1861 void Controller::ShowPlaceholderText()
1862 {
1863   PlaceholderHandler::ShowPlaceholderText(*this);
1864 }
1865
1866 void Controller::ClearFontData()
1867 {
1868   if(mImpl->mFontDefaults)
1869   {
1870     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1871   }
1872
1873   // Set flags to update the model.
1874   mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
1875   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1876   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
1877
1878   mImpl->mTextUpdateInfo.mClearAll           = true;
1879   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1880   mImpl->mRecalculateNaturalSize             = true;
1881
1882   mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1883                                                           VALIDATE_FONTS |
1884                                                           SHAPE_TEXT |
1885                                                           BIDI_INFO |
1886                                                           GET_GLYPH_METRICS |
1887                                                           LAYOUT |
1888                                                           UPDATE_LAYOUT_SIZE |
1889                                                           REORDER |
1890                                                           ALIGN);
1891 }
1892
1893 void Controller::ClearStyleData()
1894 {
1895   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
1896   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
1897 }
1898
1899 void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
1900 {
1901   // Reset the cursor position
1902   if(NULL != mImpl->mEventData)
1903   {
1904     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
1905
1906     // Update the cursor if it's in editing mode.
1907     if(EventData::IsEditingState(mImpl->mEventData->mState))
1908     {
1909       mImpl->mEventData->mUpdateCursorPosition = true;
1910     }
1911   }
1912 }
1913
1914 CharacterIndex Controller::GetCursorPosition()
1915 {
1916   if(!mImpl->mEventData)
1917     return 0;
1918
1919   return mImpl->mEventData->mPrimaryCursorPosition;
1920 }
1921
1922 void Controller::ResetScrollPosition()
1923 {
1924   if(mImpl->mEventData)
1925   {
1926     // Reset the scroll position.
1927     mImpl->mModel->mScrollPosition                = Vector2::ZERO;
1928     mImpl->mEventData->mScrollAfterUpdatePosition = true;
1929   }
1930 }
1931
1932 void Controller::SetControlInterface(ControlInterface* controlInterface)
1933 {
1934   mImpl->mControlInterface = controlInterface;
1935 }
1936
1937 void Controller::SetAnchorControlInterface(AnchorControlInterface* anchorControlInterface)
1938 {
1939   mImpl->mAnchorControlInterface = anchorControlInterface;
1940 }
1941
1942 bool Controller::ShouldClearFocusOnEscape() const
1943 {
1944   return mImpl->mShouldClearFocusOnEscape;
1945 }
1946
1947 Actor Controller::CreateBackgroundActor()
1948 {
1949   return mImpl->CreateBackgroundActor();
1950 }
1951
1952 Controller::Controller(ControlInterface*           controlInterface,
1953                        EditableControlInterface*   editableControlInterface,
1954                        SelectableControlInterface* selectableControlInterface,
1955                        AnchorControlInterface*     anchorControlInterface)
1956 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface, anchorControlInterface))
1957 {
1958 }
1959
1960 Controller::~Controller()
1961 {
1962   delete mImpl;
1963 }
1964
1965 } // namespace Dali::Toolkit::Text