Extending Style - Adding Strikethrough
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-editor-impl.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/controls/text-controls/text-editor-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/devel-api/object/property-helper-devel.h>
25 #include <dali/integration-api/adaptor-framework/adaptor.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/public-api/actors/layer.h>
28 #include <dali/public-api/adaptor-framework/key.h>
29 #include <dali/public-api/common/dali-common.h>
30 #include <dali/public-api/object/type-registry-helper.h>
31 #include <cstring>
32 #include <limits>
33
34 // INTERNAL INCLUDES
35 #include <dali-toolkit/devel-api/controls/control-devel.h>
36 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
37 #include <dali-toolkit/devel-api/text/rendering-backend.h>
38 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
39 #include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
40 #include <dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h>
41 #include <dali-toolkit/internal/styling/style-manager-impl.h>
42 #include <dali-toolkit/internal/text/rendering/text-backend.h>
43 #include <dali-toolkit/internal/text/text-effects-style.h>
44 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
45 #include <dali-toolkit/internal/text/text-font-style.h>
46 #include <dali-toolkit/internal/text/text-view.h>
47 #include <dali-toolkit/public-api/text/text-enumerations.h>
48 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
49 #include <dali-toolkit/public-api/visuals/visual-properties.h>
50
51 using namespace Dali::Toolkit::Text;
52
53 #if defined(DEBUG_ENABLED)
54 Debug::Filter* gTextEditorLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
55 #endif
56
57 namespace Dali
58 {
59 namespace Toolkit
60 {
61 namespace Internal
62 {
63 namespace // unnamed namespace
64 {
65 const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT_RENDERING_BACKEND;
66 const float        DEFAULT_SCROLL_SPEED      = 1200.f; ///< The default scroll speed for the text editor in pixels/second.
67 } // unnamed namespace
68
69 namespace
70 {
71 const char* const SCROLL_BAR_POSITION("sourcePosition");
72 const char* const SCROLL_BAR_POSITION_MIN("sourcePositionMin");
73 const char* const SCROLL_BAR_POSITION_MAX("sourcePositionMax");
74 const char* const SCROLL_BAR_CONTENT_SIZE("sourceContentSize");
75
76 // Type registration
77 BaseHandle Create()
78 {
79   return Toolkit::TextEditor::New();
80 }
81
82 // clang-format off
83 // Setup properties, signals and actions using the type-registry.
84 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextEditor, Toolkit::Control, Create);
85
86 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "text",                                 STRING,    TEXT                                )
87 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "textColor",                            VECTOR4,   TEXT_COLOR                          )
88 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "fontFamily",                           STRING,    FONT_FAMILY                         )
89 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "fontStyle",                            MAP,       FONT_STYLE                          )
90 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "pointSize",                            FLOAT,     POINT_SIZE                          )
91 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "horizontalAlignment",                  STRING,    HORIZONTAL_ALIGNMENT                )
92 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "scrollThreshold",                      FLOAT,     SCROLL_THRESHOLD                    )
93 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "scrollSpeed",                          FLOAT,     SCROLL_SPEED                        )
94 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "primaryCursorColor",                   VECTOR4,   PRIMARY_CURSOR_COLOR                )
95 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "secondaryCursorColor",                 VECTOR4,   SECONDARY_CURSOR_COLOR              )
96 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "enableCursorBlink",                    BOOLEAN,   ENABLE_CURSOR_BLINK                 )
97 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "cursorBlinkInterval",                  FLOAT,     CURSOR_BLINK_INTERVAL               )
98 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "cursorBlinkDuration",                  FLOAT,     CURSOR_BLINK_DURATION               )
99 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "cursorWidth",                          INTEGER,   CURSOR_WIDTH                        )
100 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "grabHandleImage",                      STRING,    GRAB_HANDLE_IMAGE                   )
101 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "grabHandlePressedImage",               STRING,    GRAB_HANDLE_PRESSED_IMAGE           )
102 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHandleImageLeft",             MAP,       SELECTION_HANDLE_IMAGE_LEFT         )
103 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHandleImageRight",            MAP,       SELECTION_HANDLE_IMAGE_RIGHT        )
104 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHandlePressedImageLeft",      MAP,       SELECTION_HANDLE_PRESSED_IMAGE_LEFT )
105 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHandlePressedImageRight",     MAP,       SELECTION_HANDLE_PRESSED_IMAGE_RIGHT)
106 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHandleMarkerImageLeft",       MAP,       SELECTION_HANDLE_MARKER_IMAGE_LEFT  )
107 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHandleMarkerImageRight",      MAP,       SELECTION_HANDLE_MARKER_IMAGE_RIGHT )
108 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "selectionHighlightColor",              VECTOR4,   SELECTION_HIGHLIGHT_COLOR           )
109 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "decorationBoundingBox",                RECTANGLE, DECORATION_BOUNDING_BOX             )
110 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "enableMarkup",                         BOOLEAN,   ENABLE_MARKUP                       )
111 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputColor",                           VECTOR4,   INPUT_COLOR                         )
112 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputFontFamily",                      STRING,    INPUT_FONT_FAMILY                   )
113 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputFontStyle",                       MAP,       INPUT_FONT_STYLE                    )
114 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputPointSize",                       FLOAT,     INPUT_POINT_SIZE                    )
115 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "lineSpacing",                          FLOAT,     LINE_SPACING                        )
116 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputLineSpacing",                     FLOAT,     INPUT_LINE_SPACING                  )
117 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "underline",                            MAP,       UNDERLINE                           )
118 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputUnderline",                       MAP,       INPUT_UNDERLINE                     )
119 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "shadow",                               MAP,       SHADOW                              )
120 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputShadow",                          MAP,       INPUT_SHADOW                        )
121 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "emboss",                               MAP,       EMBOSS                              )
122 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputEmboss",                          MAP,       INPUT_EMBOSS                        )
123 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "outline",                              MAP,       OUTLINE                             )
124 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "inputOutline",                         MAP,       INPUT_OUTLINE                       )
125 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "smoothScroll",                         BOOLEAN,   SMOOTH_SCROLL                       )
126 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "smoothScrollDuration",                 FLOAT,     SMOOTH_SCROLL_DURATION              )
127 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "enableScrollBar",                      BOOLEAN,   ENABLE_SCROLL_BAR                   )
128 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "scrollBarShowDuration",                FLOAT,     SCROLL_BAR_SHOW_DURATION            )
129 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "scrollBarFadeDuration",                FLOAT,     SCROLL_BAR_FADE_DURATION            )
130 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "pixelSize",                            FLOAT,     PIXEL_SIZE                          )
131 DALI_PROPERTY_REGISTRATION_READ_ONLY(Toolkit,       TextEditor, "lineCount",                            INTEGER,   LINE_COUNT                          )
132 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "enableSelection",                      BOOLEAN,   ENABLE_SELECTION                    )
133 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "placeholder",                          MAP,       PLACEHOLDER                         )
134 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextEditor, "lineWrapMode",                         INTEGER,   LINE_WRAP_MODE                      )
135 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "placeholderText",                      STRING,    PLACEHOLDER_TEXT                    )
136 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "placeholderTextColor",                 VECTOR4,   PLACEHOLDER_TEXT_COLOR              )
137 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "enableShiftSelection",                 BOOLEAN,   ENABLE_SHIFT_SELECTION              )
138 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "enableGrabHandle",                     BOOLEAN,   ENABLE_GRAB_HANDLE                  )
139 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "matchSystemLanguageDirection",         BOOLEAN,   MATCH_SYSTEM_LANGUAGE_DIRECTION     )
140 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "renderingBackend",                     INTEGER,   RENDERING_BACKEND                   )
141 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "maxLength",                            INTEGER,   MAX_LENGTH                          )
142 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "selectedTextStart",                    INTEGER,   SELECTED_TEXT_START                 )
143 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "selectedTextEnd",                      INTEGER,   SELECTED_TEXT_END                   )
144 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "horizontalScrollPosition",             FLOAT,     HORIZONTAL_SCROLL_POSITION          )
145 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "verticalScrollPosition",               INTEGER,   VERTICAL_SCROLL_POSITION            )
146 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "enableEditing",                        BOOLEAN,   ENABLE_EDITING                      )
147 DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY(Toolkit, TextEditor, "selectedText",                         STRING,    SELECTED_TEXT                       )
148 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "fontSizeScale",                        FLOAT,     FONT_SIZE_SCALE                     )
149 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "primaryCursorPosition",                INTEGER,   PRIMARY_CURSOR_POSITION             )
150 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "grabHandleColor",                      VECTOR4,   GRAB_HANDLE_COLOR                   )
151 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "enableGrabHandlePopup",                BOOLEAN,   ENABLE_GRAB_HANDLE_POPUP            )
152 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputMethodSettings",                  MAP,       INPUT_METHOD_SETTINGS               )
153 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputFilter",                          MAP,       INPUT_FILTER                        )
154 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "ellipsis",                             BOOLEAN,   ELLIPSIS                            )
155 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "ellipsisPosition",                     INTEGER,   ELLIPSIS_POSITION                   )
156 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "minLineSize",                          FLOAT,     MIN_LINE_SIZE                       )
157 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "strikethrough",                        MAP,       STRIKETHROUGH                       )
158 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputStrikethrough",                   MAP,       INPUT_STRIKETHROUGH                 )
159
160 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged",           SIGNAL_TEXT_CHANGED           )
161 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged",     SIGNAL_INPUT_STYLE_CHANGED    )
162 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "maxLengthReached",      SIGNAL_MAX_LENGTH_REACHED     )
163 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "anchorClicked",         SIGNAL_ANCHOR_CLICKED         )
164 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputFiltered",         SIGNAL_INPUT_FILTERED         )
165 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "cursorPositionChanged", SIGNAL_CURSOR_POSITION_CHANGED)
166 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "selectionChanged",      SIGNAL_SELECTION_CHANGED      )
167 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "selectionCleared",      SIGNAL_SELECTION_CLEARED      )
168
169 DALI_TYPE_REGISTRATION_END()
170 // clang-format on
171
172 Toolkit::TextEditor::InputStyle::Mask ConvertInputStyle(Text::InputStyle::Mask inputStyleMask)
173 {
174   Toolkit::TextEditor::InputStyle::Mask editorInputStyleMask = Toolkit::TextEditor::InputStyle::NONE;
175
176   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_COLOR))
177   {
178     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::COLOR);
179   }
180   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_FAMILY))
181   {
182     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_FAMILY);
183   }
184   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_POINT_SIZE))
185   {
186     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::POINT_SIZE);
187   }
188   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WEIGHT))
189   {
190     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
191   }
192   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WIDTH))
193   {
194     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
195   }
196   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_SLANT))
197   {
198     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
199   }
200   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_LINE_SPACING))
201   {
202     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::LINE_SPACING);
203   }
204   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_UNDERLINE))
205   {
206     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::UNDERLINE);
207   }
208   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_SHADOW))
209   {
210     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::SHADOW);
211   }
212   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_EMBOSS))
213   {
214     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::EMBOSS);
215   }
216   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_OUTLINE))
217   {
218     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::OUTLINE);
219   }
220   if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_STRIKETHROUGH))
221   {
222     editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::STRIKETHROUGH);
223   }
224
225   return editorInputStyleMask;
226 }
227
228 } // namespace
229
230 Toolkit::TextEditor TextEditor::New()
231 {
232   // Create the implementation, temporarily owned by this handle on stack
233   IntrusivePtr<TextEditor> impl = new TextEditor();
234
235   // Pass ownership to CustomActor handle
236   Toolkit::TextEditor handle(*impl);
237
238   // Second-phase init of the implementation
239   // This can only be done after the CustomActor connection has been made...
240   impl->Initialize();
241
242   return handle;
243 }
244
245 void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
246 {
247   Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast(Dali::BaseHandle(object));
248
249   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor SetProperty\n");
250
251   if(textEditor)
252   {
253     PropertyHandler::SetProperty(textEditor, index, value);
254   }
255 }
256
257 Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index index)
258 {
259   Property::Value value;
260
261   Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast(Dali::BaseHandle(object));
262
263   if(textEditor)
264   {
265     value = PropertyHandler::GetProperty(textEditor, index);
266   }
267   return value;
268 }
269
270 void TextEditor::SelectWholeText()
271 {
272   if(mController && mController->IsShowingRealText())
273   {
274     mController->SelectWholeText();
275     SetKeyInputFocus();
276   }
277 }
278
279 void TextEditor::SelectNone()
280 {
281   if(mController && mController->IsShowingRealText())
282   {
283     mController->SelectNone();
284   }
285 }
286
287 void TextEditor::SelectText(const uint32_t start, const uint32_t end)
288 {
289   if(mController && mController->IsShowingRealText())
290   {
291     mController->SelectText(start, end);
292     SetKeyInputFocus();
293   }
294 }
295
296 string TextEditor::CopyText()
297 {
298   string copiedText = "";
299   if(mController && mController->IsShowingRealText())
300   {
301     copiedText = mController->CopyText();
302   }
303   return copiedText;
304 }
305
306 string TextEditor::CutText()
307 {
308   string cutText = "";
309   if(mController && mController->IsShowingRealText())
310   {
311     cutText = mController->CutText();
312   }
313   return cutText;
314 }
315
316 void TextEditor::PasteText()
317 {
318   if(mController)
319   {
320     SetKeyInputFocus(); //Giving focus to the editor that was passed to the PasteText in case the passed editor (current editor) doesn't have focus.
321     mController->PasteText();
322   }
323 }
324
325 void TextEditor::ScrollBy(Vector2 scroll)
326 {
327   if(mController && mController->IsShowingRealText())
328   {
329     mController->ScrollBy(scroll);
330   }
331 }
332
333 float TextEditor::GetHorizontalScrollPosition()
334 {
335   if(mController && mController->IsShowingRealText())
336   {
337     return mController->GetHorizontalScrollPosition();
338   }
339   return 0;
340 }
341
342 float TextEditor::GetVerticalScrollPosition()
343 {
344   if(mController && mController->IsShowingRealText())
345   {
346     return mController->GetVerticalScrollPosition();
347   }
348   return 0;
349 }
350
351 Vector<Vector2> TextEditor::GetTextSize(const uint32_t startIndex, const uint32_t endIndex) const
352 {
353   return mController->GetTextSize(startIndex, endIndex);
354 }
355
356 Vector<Vector2> TextEditor::GetTextPosition(const uint32_t startIndex, const uint32_t endIndex) const
357 {
358   return mController->GetTextPosition(startIndex, endIndex);
359 }
360
361 string TextEditor::GetSelectedText() const
362 {
363   string selectedText = "";
364   if(mController && mController->IsShowingRealText())
365   {
366     selectedText = mController->GetSelectedText();
367   }
368   return selectedText;
369 }
370
371 InputMethodContext TextEditor::GetInputMethodContext()
372 {
373   return mInputMethodContext;
374 }
375
376 DevelTextEditor::MaxLengthReachedSignalType& TextEditor::MaxLengthReachedSignal()
377 {
378   return mMaxLengthReachedSignal;
379 }
380
381 DevelTextEditor::AnchorClickedSignalType& TextEditor::AnchorClickedSignal()
382 {
383   return mAnchorClickedSignal;
384 }
385
386 DevelTextEditor::CursorPositionChangedSignalType& TextEditor::CursorPositionChangedSignal()
387 {
388   return mCursorPositionChangedSignal;
389 }
390
391 DevelTextEditor::InputFilteredSignalType& TextEditor::InputFilteredSignal()
392 {
393   return mInputFilteredSignal;
394 }
395
396 DevelTextEditor::SelectionChangedSignalType& TextEditor::SelectionChangedSignal()
397 {
398   return mSelectionChangedSignal;
399 }
400
401 DevelTextEditor::SelectionClearedSignalType& TextEditor::SelectionClearedSignal()
402 {
403   return mSelectionClearedSignal;
404 }
405
406 Text::ControllerPtr TextEditor::GetTextController()
407 {
408   return mController;
409 }
410
411 bool TextEditor::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
412 {
413   Dali::BaseHandle handle(object);
414
415   bool                connected(true);
416   Toolkit::TextEditor editor = Toolkit::TextEditor::DownCast(handle);
417
418   if(0 == strcmp(signalName.c_str(), SIGNAL_TEXT_CHANGED))
419   {
420     editor.TextChangedSignal().Connect(tracker, functor);
421   }
422   else if(0 == strcmp(signalName.c_str(), SIGNAL_INPUT_STYLE_CHANGED))
423   {
424     editor.InputStyleChangedSignal().Connect(tracker, functor);
425   }
426   else if(0 == strcmp(signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED))
427   {
428     if(editor)
429     {
430       Internal::TextEditor& editorImpl(GetImpl(editor));
431       editorImpl.MaxLengthReachedSignal().Connect(tracker, functor);
432     }
433   }
434   else if(0 == strcmp(signalName.c_str(), SIGNAL_ANCHOR_CLICKED))
435   {
436     if(editor)
437     {
438       Internal::TextEditor& editorImpl(GetImpl(editor));
439       editorImpl.AnchorClickedSignal().Connect(tracker, functor);
440     }
441   }
442   else if(0 == strcmp(signalName.c_str(), SIGNAL_CURSOR_POSITION_CHANGED))
443   {
444     if(editor)
445     {
446       Internal::TextEditor& editorImpl(GetImpl(editor));
447       editorImpl.CursorPositionChangedSignal().Connect(tracker, functor);
448     }
449   }
450   else if(0 == strcmp(signalName.c_str(), SIGNAL_INPUT_FILTERED))
451   {
452     if(editor)
453     {
454       Internal::TextEditor& editorImpl(GetImpl(editor));
455       editorImpl.InputFilteredSignal().Connect(tracker, functor);
456     }
457   }
458   else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_CHANGED))
459   {
460     if(editor)
461     {
462       Internal::TextEditor& editorImpl(GetImpl(editor));
463       editorImpl.SelectionChangedSignal().Connect(tracker, functor);
464     }
465   }
466   else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_CLEARED))
467   {
468     if(editor)
469     {
470       Internal::TextEditor& editorImpl(GetImpl(editor));
471       editorImpl.SelectionClearedSignal().Connect(tracker, functor);
472     }
473   }
474   else
475   {
476     // signalName does not match any signal
477     connected = false;
478   }
479
480   return connected;
481 }
482
483 Toolkit::TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal()
484 {
485   return mTextChangedSignal;
486 }
487
488 Toolkit::TextEditor::InputStyleChangedSignalType& TextEditor::InputStyleChangedSignal()
489 {
490   return mInputStyleChangedSignal;
491 }
492
493 Toolkit::TextEditor::ScrollStateChangedSignalType& TextEditor::ScrollStateChangedSignal()
494 {
495   return mScrollStateChangedSignal;
496 }
497
498 void TextEditor::OnAccessibilityStatusChanged()
499 {
500   CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
501 }
502
503 void TextEditor::OnInitialize()
504 {
505   Actor self = Self();
506
507   mController = Text::Controller::New(this, this, this, this);
508
509   mDecorator = Text::Decorator::New(*mController,
510                                     *mController);
511
512   mInputMethodContext = InputMethodContext::New(self);
513
514   mController->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
515
516   // Enables the text input.
517   mController->EnableTextInput(mDecorator, mInputMethodContext);
518
519   // Enables the vertical scrolling after the text input has been enabled.
520   mController->SetVerticalScrollEnabled(true);
521
522   // Disables the horizontal scrolling.
523   mController->SetHorizontalScrollEnabled(false);
524
525   // Sets the maximum number of characters.
526   mController->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
527
528   // Enable the smooth handle panning.
529   mController->SetSmoothHandlePanEnabled(true);
530
531   mController->SetNoTextDoubleTapAction(Controller::NoTextTap::HIGHLIGHT);
532   mController->SetNoTextLongPressAction(Controller::NoTextTap::HIGHLIGHT);
533
534   // Sets layoutDirection value
535   Dali::Stage                 stage           = Dali::Stage::GetCurrent();
536   Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(stage.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
537   mController->SetLayoutDirection(layoutDirection);
538
539   self.LayoutDirectionChangedSignal().Connect(this, &TextEditor::OnLayoutDirectionChanged);
540
541   // Forward input events to controller
542   EnableGestureDetection(static_cast<GestureType::Value>(GestureType::TAP | GestureType::PAN | GestureType::LONG_PRESS));
543   GetTapGestureDetector().SetMaximumTapsRequired(2);
544   GetTapGestureDetector().ReceiveAllTapEvents(true);
545
546   self.TouchedSignal().Connect(this, &TextEditor::OnTouched);
547
548   // Set BoundingBox to stage size if not already set.
549   Rect<int> boundingBox;
550   mDecorator->GetBoundingBox(boundingBox);
551
552   if(boundingBox.IsEmpty())
553   {
554     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
555     mDecorator->SetBoundingBox(Rect<int>(0.0f, 0.0f, stageSize.width, stageSize.height));
556   }
557
558   // Whether to flip the selection handles as soon as they cross.
559   mDecorator->FlipSelectionHandlesOnCrossEnabled(true);
560
561   // Set the default scroll speed.
562   mDecorator->SetScrollSpeed(DEFAULT_SCROLL_SPEED);
563
564   // Fill-parent area by default
565   self.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
566   self.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT);
567   self.OnSceneSignal().Connect(this, &TextEditor::OnSceneConnect);
568
569   //Enable highightability
570   self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
571
572   DevelControl::SetInputMethodContext(*this, mInputMethodContext);
573
574   // Creates an extra control to be used as stencil buffer.
575   mStencil = Control::New();
576   mStencil.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
577   mStencil.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
578
579   // Creates a background visual. Even if the color is transparent it updates the stencil.
580   mStencil.SetProperty(Toolkit::Control::Property::BACKGROUND,
581                        Property::Map().Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR).Add(ColorVisual::Property::MIX_COLOR, Color::TRANSPARENT));
582
583   // Enable the clipping property.
584   mStencil.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
585   mStencil.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
586
587   self.Add(mStencil);
588
589   DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
590     return std::unique_ptr<Dali::Accessibility::Accessible>(
591       new AccessibleImpl(actor, Dali::Accessibility::Role::ENTRY));
592   });
593
594   Accessibility::Bridge::EnabledSignal().Connect(this, &TextEditor::OnAccessibilityStatusChanged);
595   Accessibility::Bridge::DisabledSignal().Connect(this, &TextEditor::OnAccessibilityStatusChanged);
596 }
597
598 void TextEditor::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
599 {
600   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnStyleChange\n");
601
602   switch(change)
603   {
604     case StyleChange::DEFAULT_FONT_CHANGE:
605     {
606       DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnStyleChange DEFAULT_FONT_CHANGE\n");
607       const std::string& newFont = GetImpl(styleManager).GetDefaultFontFamily();
608       // Property system did not set the font so should update it.
609       mController->UpdateAfterFontChange(newFont);
610       RelayoutRequest();
611       break;
612     }
613
614     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
615     {
616       GetImpl(styleManager).ApplyThemeStyle(Toolkit::Control(GetOwner()));
617       RelayoutRequest();
618       break;
619     }
620     case StyleChange::THEME_CHANGE:
621     {
622       // Nothing to do, let control base class handle this
623       break;
624     }
625   }
626
627   // Up call to Control
628   Control::OnStyleChange(styleManager, change);
629 }
630
631 Vector3 TextEditor::GetNaturalSize()
632 {
633   Extents padding;
634   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
635
636   Vector3 naturalSize = mController->GetNaturalSize();
637   naturalSize.width += (padding.start + padding.end);
638   naturalSize.height += (padding.top + padding.bottom);
639
640   return naturalSize;
641 }
642
643 float TextEditor::GetHeightForWidth(float width)
644 {
645   Extents padding;
646   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
647   return mController->GetHeightForWidth(width) + padding.top + padding.bottom;
648 }
649
650 void TextEditor::ResizeActor(Actor& actor, const Vector2& size)
651 {
652   if(actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
653   {
654     actor.SetProperty(Actor::Property::SIZE, size);
655   }
656 }
657
658 void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
659 {
660   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor OnRelayout\n");
661
662   Actor self = Self();
663
664   Extents padding;
665   padding = self.GetProperty<Extents>(Toolkit::Control::Property::PADDING);
666
667   Vector2 contentSize(size.x - (padding.start + padding.end), size.y - (padding.top + padding.bottom));
668
669   // Support Right-To-Left of padding
670   Dali::LayoutDirection::Type layoutDirection = mController->GetLayoutDirection(self);
671
672   if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
673   {
674     std::swap(padding.start, padding.end);
675   }
676
677   if(mStencil)
678   {
679     mStencil.SetProperty(Actor::Property::POSITION, Vector2(padding.start, padding.top));
680     ResizeActor(mStencil, contentSize);
681   }
682   if(mActiveLayer)
683   {
684     mActiveLayer.SetProperty(Actor::Property::POSITION, Vector2(padding.start, padding.top));
685     ResizeActor(mActiveLayer, contentSize);
686   }
687
688   // If there is text changed, callback is called.
689   if(mTextChanged)
690   {
691     EmitTextChangedSignal();
692   }
693
694   const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
695
696   if((Text::Controller::NONE_UPDATED != updateTextType) ||
697      !mRenderer)
698   {
699     DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnRelayout %p Displaying new contents\n", mController.Get());
700
701     if(mDecorator &&
702        (Text::Controller::NONE_UPDATED != (Text::Controller::DECORATOR_UPDATED & updateTextType)))
703     {
704       mDecorator->Relayout(contentSize);
705     }
706
707     if(!mRenderer)
708     {
709       mRenderer = Backend::Get().NewRenderer(mRenderingBackend);
710     }
711
712     RenderText(updateTextType);
713   }
714
715   if(mCursorPositionChanged)
716   {
717     EmitCursorPositionChangedSignal();
718   }
719
720   if(mSelectionChanged)
721   {
722     EmitSelectionChangedSignal();
723   }
724
725   if(mSelectionCleared)
726   {
727     EmitSelectionClearedSignal();
728   }
729
730   // The text-editor emits signals when the input style changes. These changes of style are
731   // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
732   // can't be emitted during the size negotiation as the callbacks may update the UI.
733   // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation.
734   if(!mController->IsInputStyleChangedSignalsQueueEmpty())
735   {
736     if(Adaptor::IsAvailable())
737     {
738       Adaptor& adaptor = Adaptor::Get();
739
740       if(NULL == mIdleCallback)
741       {
742         // @note: The callback manager takes the ownership of the callback object.
743         mIdleCallback = MakeCallback(this, &TextEditor::OnIdleSignal);
744         adaptor.AddIdle(mIdleCallback, false);
745       }
746     }
747   }
748 }
749
750 void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
751 {
752   CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
753   if(mRenderableActor)
754   {
755     ApplyScrollPosition();
756   }
757   UpdateScrollBar();
758 }
759
760 void TextEditor::OnKeyInputFocusGained()
761 {
762   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnKeyInputFocusGained %p\n", mController.Get());
763   if(mInputMethodContext && IsEditable())
764   {
765     // All input panel properties, such as layout, return key type, and input hint, should be set before input panel activates (or shows).
766     mInputMethodContext.ApplyOptions(mInputMethodOptions);
767     mInputMethodContext.NotifyTextInputMultiLine(true);
768
769     mInputMethodContext.StatusChangedSignal().Connect(this, &TextEditor::KeyboardStatusChanged);
770
771     mInputMethodContext.EventReceivedSignal().Connect(this, &TextEditor::OnInputMethodContextEvent);
772
773     // Notify that the text editing start.
774     mInputMethodContext.Activate();
775
776     // When window gain lost focus, the InputMethodContext is deactivated. Thus when window gain focus again, the InputMethodContext must be activated.
777     mInputMethodContext.SetRestoreAfterFocusLost(true);
778   }
779   ClipboardEventNotifier notifier(ClipboardEventNotifier::Get());
780
781   if(notifier)
782   {
783     notifier.ContentSelectedSignal().Connect(this, &TextEditor::OnClipboardTextSelected);
784   }
785
786   mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
787
788   EmitKeyInputFocusSignal(true); // Calls back into the Control hence done last.
789 }
790
791 void TextEditor::OnKeyInputFocusLost()
792 {
793   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor:OnKeyInputFocusLost %p\n", mController.Get());
794   if(mInputMethodContext)
795   {
796     mInputMethodContext.StatusChangedSignal().Disconnect(this, &TextEditor::KeyboardStatusChanged);
797
798     // The text editing is finished. Therefore the InputMethodContext don't have restore activation.
799     mInputMethodContext.SetRestoreAfterFocusLost(false);
800
801     // Notify that the text editing finish.
802     mInputMethodContext.Deactivate();
803
804     mInputMethodContext.EventReceivedSignal().Disconnect(this, &TextEditor::OnInputMethodContextEvent);
805   }
806   ClipboardEventNotifier notifier(ClipboardEventNotifier::Get());
807
808   if(notifier)
809   {
810     notifier.ContentSelectedSignal().Disconnect(this, &TextEditor::OnClipboardTextSelected);
811   }
812
813   mController->KeyboardFocusLostEvent();
814
815   EmitKeyInputFocusSignal(false); // Calls back into the Control hence done last.
816 }
817
818 bool TextEditor::OnAccessibilityActivated()
819 {
820   SetKeyInputFocus();
821   return true;
822 }
823
824 void TextEditor::OnTap(const TapGesture& gesture)
825 {
826   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get());
827   if(mInputMethodContext && IsEditable())
828   {
829     mInputMethodContext.Activate();
830   }
831   // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
832   Extents padding;
833   padding                   = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
834   const Vector2& localPoint = gesture.GetLocalPoint();
835   mController->TapEvent(gesture.GetNumberOfTaps(), localPoint.x - padding.start, localPoint.y - padding.top);
836   mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
837
838   SetKeyInputFocus();
839 }
840
841 void TextEditor::OnPan(const PanGesture& gesture)
842 {
843   mController->PanEvent(gesture.GetState(), gesture.GetDisplacement());
844 }
845
846 void TextEditor::OnLongPress(const LongPressGesture& gesture)
847 {
848   if(mInputMethodContext && IsEditable())
849   {
850     mInputMethodContext.Activate();
851   }
852   Extents padding;
853   padding                   = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
854   const Vector2& localPoint = gesture.GetLocalPoint();
855   mController->LongPressEvent(gesture.GetState(), localPoint.x - padding.start, localPoint.y - padding.top);
856
857   SetKeyInputFocus();
858 }
859
860 bool TextEditor::OnKeyEvent(const KeyEvent& event)
861 {
862   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnKeyEvent %p keyCode %d\n", mController.Get(), event.GetKeyCode());
863
864   if(Dali::DALI_KEY_ESCAPE == event.GetKeyCode() && mController->ShouldClearFocusOnEscape())
865   {
866     // Make sure ClearKeyInputFocus when only key is up
867     if(event.GetState() == KeyEvent::UP)
868     {
869       ClearKeyInputFocus();
870     }
871
872     return true;
873   }
874
875   return mController->KeyEvent(event);
876 }
877
878 void TextEditor::RequestTextRelayout()
879 {
880   RelayoutRequest();
881 }
882
883 void TextEditor::TextInserted(unsigned int position, unsigned int length, const std::string& content)
884 {
885   if(Accessibility::IsUp())
886   {
887     Control::Impl::GetAccessibilityObject(Self())->EmitTextInserted(position, length, content);
888   }
889 }
890
891 void TextEditor::TextDeleted(unsigned int position, unsigned int length, const std::string& content)
892 {
893   if(Accessibility::IsUp())
894   {
895     Control::Impl::GetAccessibilityObject(Self())->EmitTextDeleted(position, length, content);
896   }
897 }
898
899 void TextEditor::CursorPositionChanged(unsigned int oldPosition, unsigned int newPosition)
900 {
901   if(Accessibility::IsUp())
902   {
903     Control::Impl::GetAccessibilityObject(Self())->EmitTextCursorMoved(newPosition);
904   }
905
906   if((oldPosition != newPosition) && !mCursorPositionChanged)
907   {
908     mCursorPositionChanged = true;
909     mOldPosition           = oldPosition;
910   }
911 }
912
913 void TextEditor::TextChanged(bool immediate)
914 {
915   if(immediate) // Emits TextChangedSignal immediately
916   {
917     EmitTextChangedSignal();
918   }
919   else
920   {
921     mTextChanged = true;
922   }
923 }
924
925 void TextEditor::EmitTextChangedSignal()
926 {
927   Dali::Toolkit::TextEditor handle(GetOwner());
928   mTextChangedSignal.Emit(handle);
929   mTextChanged = false;
930 }
931
932 void TextEditor::MaxLengthReached()
933 {
934   Dali::Toolkit::TextEditor handle(GetOwner());
935   mMaxLengthReachedSignal.Emit(handle);
936 }
937
938 void TextEditor::InputStyleChanged(Text::InputStyle::Mask inputStyleMask)
939 {
940   Dali::Toolkit::TextEditor handle(GetOwner());
941   mInputStyleChangedSignal.Emit(handle, ConvertInputStyle(inputStyleMask));
942 }
943
944 void TextEditor::AnchorClicked(const std::string& href)
945 {
946   Dali::Toolkit::TextEditor handle(GetOwner());
947   mAnchorClickedSignal.Emit(handle, href.c_str(), href.length());
948 }
949
950 void TextEditor::EmitCursorPositionChangedSignal()
951 {
952   Dali::Toolkit::TextEditor handle(GetOwner());
953   mCursorPositionChanged = false;
954   mCursorPositionChangedSignal.Emit(handle, mOldPosition);
955 }
956
957 void TextEditor::InputFiltered(Toolkit::InputFilter::Property::Type type)
958 {
959   Dali::Toolkit::TextEditor handle(GetOwner());
960   mInputFilteredSignal.Emit(handle, type);
961 }
962
963 void TextEditor::EmitSelectionChangedSignal()
964 {
965   Dali::Toolkit::TextEditor handle(GetOwner());
966   mSelectionChangedSignal.Emit(handle, mOldSelectionStart, mOldSelectionEnd);
967   mSelectionChanged = false;
968 }
969
970 void TextEditor::EmitSelectionClearedSignal()
971 {
972   Dali::Toolkit::TextEditor handle(GetOwner());
973   mSelectionClearedSignal.Emit(handle);
974   mSelectionCleared = false;
975 }
976
977 void TextEditor::SelectionChanged(uint32_t oldStart, uint32_t oldEnd, uint32_t newStart, uint32_t newEnd)
978 {
979   if(((oldStart != newStart) || (oldEnd != newEnd)) && !mSelectionChanged)
980   {
981     if(newStart == newEnd)
982     {
983       mSelectionCleared = true;
984     }
985
986     mSelectionChanged  = true;
987     mOldSelectionStart = oldStart;
988     mOldSelectionEnd   = oldEnd;
989
990     if(mOldSelectionStart > mOldSelectionEnd)
991     {
992       //swap
993       uint32_t temp      = mOldSelectionStart;
994       mOldSelectionStart = mOldSelectionEnd;
995       mOldSelectionEnd   = temp;
996     }
997   }
998 }
999
1000 void TextEditor::AddDecoration(Actor& actor, bool needsClipping)
1001 {
1002   if(actor)
1003   {
1004     if(needsClipping)
1005     {
1006       mClippingDecorationActors.push_back(actor);
1007     }
1008     else
1009     {
1010       actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
1011       actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
1012       Self().Add(actor);
1013       mActiveLayer = actor;
1014     }
1015   }
1016 }
1017
1018 void TextEditor::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
1019 {
1020   if(mController && mController->IsShowingRealText())
1021   {
1022     mController->SetTextSelectionRange(start, end);
1023     SetKeyInputFocus();
1024   }
1025 }
1026
1027 Uint32Pair TextEditor::GetTextSelectionRange() const
1028 {
1029   Uint32Pair range(0, 0);
1030   if(mController && mController->IsShowingRealText())
1031   {
1032     range = mController->GetTextSelectionRange();
1033   }
1034   return range;
1035 }
1036
1037 void TextEditor::GetControlBackgroundColor(Vector4& color) const
1038 {
1039   Property::Value propValue = Self().GetProperty(Toolkit::Control::Property::BACKGROUND);
1040   Property::Map*  resultMap = propValue.GetMap();
1041
1042   Property::Value* colorValue = nullptr;
1043   if(resultMap && (colorValue = resultMap->Find(ColorVisual::Property::MIX_COLOR)))
1044   {
1045     colorValue->Get(color);
1046   }
1047 }
1048
1049 void TextEditor::UpdateScrollBar()
1050 {
1051   using namespace Dali;
1052
1053   float scrollPosition;
1054   float controlSize;
1055   float layoutSize;
1056   bool  latestScrolled;
1057
1058   if(!mScrollBarEnabled)
1059   {
1060     return;
1061   }
1062   latestScrolled = mController->GetTextScrollInfo(scrollPosition, controlSize, layoutSize);
1063   if(!latestScrolled || controlSize > layoutSize)
1064   {
1065     return;
1066   }
1067
1068   CustomActor self = Self();
1069   if(!mScrollBar)
1070   {
1071     mScrollBar = Toolkit::ScrollBar::New(Toolkit::ScrollBar::VERTICAL);
1072     mScrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::VARIABLE);
1073     mScrollBar.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_RIGHT);
1074     mScrollBar.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT);
1075     mScrollBar.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT);
1076     mScrollBar.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH);
1077
1078     // Register the scroll position property
1079     Property::Index propertyScrollPosition = self.RegisterProperty(SCROLL_BAR_POSITION, scrollPosition);
1080     // Register the minimum scroll position property
1081     Property::Index propertyMinScrollPosition = self.RegisterProperty(SCROLL_BAR_POSITION_MIN, 0.0f);
1082     // Register the maximum scroll position property
1083     Property::Index propertyMaxScrollPosition = self.RegisterProperty(SCROLL_BAR_POSITION_MAX, (layoutSize - controlSize));
1084     // Register the scroll content size property
1085     Property::Index propertyScrollContentSize = self.RegisterProperty(SCROLL_BAR_CONTENT_SIZE, layoutSize);
1086
1087     mScrollBar.SetScrollPropertySource(self, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
1088
1089     // Set style name of ScrollBar for styling
1090     mScrollBar.SetStyleName("TextEditorScrollBar");
1091     Toolkit::Control scrollIndicator = Toolkit::Control::DownCast(mScrollBar.GetScrollIndicator());
1092     if(scrollIndicator)
1093     {
1094       // Set style name of ScrollBarIndicator for styling
1095       scrollIndicator.SetStyleName("TextEditorScrollBarIndicator");
1096     }
1097
1098     self.Add(mScrollBar);
1099   }
1100   else
1101   {
1102     Property::Index propertyScrollPosition    = self.GetPropertyIndex(SCROLL_BAR_POSITION);
1103     Property::Index propertyMaxScrollPosition = self.GetPropertyIndex(SCROLL_BAR_POSITION_MAX);
1104     Property::Index propertyScrollContentSize = self.GetPropertyIndex(SCROLL_BAR_CONTENT_SIZE);
1105
1106     self.SetProperty(propertyScrollPosition, scrollPosition);
1107     self.SetProperty(propertyMaxScrollPosition, (layoutSize - controlSize));
1108     self.SetProperty(propertyScrollContentSize, layoutSize);
1109   }
1110
1111   // If scrolling is not started, start scrolling and emit ScrollStateChangedSignal
1112   if(!mScrollStarted)
1113   {
1114     mScrollStarted = true;
1115     Dali::Toolkit::TextEditor handle(GetOwner());
1116     mScrollStateChangedSignal.Emit(handle, Toolkit::TextEditor::Scroll::STARTED);
1117   }
1118
1119   Actor indicator = mScrollBar.GetScrollIndicator();
1120   if(mAnimation)
1121   {
1122     mAnimation.Stop(); // Cancel any animation
1123   }
1124   else
1125   {
1126     mAnimation = Animation::New(mAnimationPeriod.durationSeconds);
1127   }
1128   indicator.SetProperty(Actor::Property::OPACITY, 1.0f);
1129   mAnimation.AnimateTo(Property(indicator, Actor::Property::COLOR_ALPHA), 0.0f, AlphaFunction::EASE_IN, mAnimationPeriod);
1130   mAnimation.Play();
1131   mAnimation.FinishedSignal().Connect(this, &TextEditor::OnScrollIndicatorAnimationFinished);
1132 }
1133
1134 void TextEditor::OnScrollIndicatorAnimationFinished(Animation& animation)
1135 {
1136   // If animation is successfully ended, then emit ScrollStateChangedSignal
1137   if(animation.GetCurrentProgress() == 0.0f)
1138   {
1139     mScrollStarted = false;
1140     Dali::Toolkit::TextEditor handle(GetOwner());
1141     mScrollStateChangedSignal.Emit(handle, Toolkit::TextEditor::Scroll::FINISHED);
1142   }
1143 }
1144
1145 void TextEditor::OnSceneConnect(Dali::Actor actor)
1146 {
1147   if(mHasBeenStaged)
1148   {
1149     RenderText(static_cast<Text::Controller::UpdateTextType>(Text::Controller::MODEL_UPDATED | Text::Controller::DECORATOR_UPDATED));
1150   }
1151   else
1152   {
1153     mHasBeenStaged = true;
1154   }
1155 }
1156
1157 InputMethodContext::CallbackData TextEditor::OnInputMethodContextEvent(Dali::InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
1158 {
1159   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName);
1160   return mController->OnInputMethodContextEvent(inputMethodContext, inputMethodContextEvent);
1161 }
1162
1163 void TextEditor::GetHandleImagePropertyValue(Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType)
1164 {
1165   if(mDecorator)
1166   {
1167     Property::Map map;
1168     map[TextEditor::PropertyHandler::IMAGE_MAP_FILENAME_STRING] = mDecorator->GetHandleImage(handleType, handleImageType);
1169
1170     value = map;
1171   }
1172 }
1173
1174 void TextEditor::OnClipboardTextSelected(ClipboardEventNotifier& clipboard)
1175 {
1176   mController->PasteClipboardItemEvent();
1177 }
1178
1179 void TextEditor::KeyboardStatusChanged(bool keyboardShown)
1180 {
1181   DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown);
1182
1183   // Just hide the grab handle when keyboard is hidden.
1184   if(!keyboardShown)
1185   {
1186     mController->KeyboardFocusLostEvent();
1187   }
1188   else
1189   {
1190     mController->KeyboardFocusGainEvent(); // Initially called by OnKeyInputFocusGained
1191   }
1192 }
1193
1194 void TextEditor::OnSceneConnection(int depth)
1195 {
1196   // Sets the depth to the visuals inside the text's decorator.
1197   mDecorator->SetTextDepth(depth);
1198
1199   // The depth of the text renderer is set in the RenderText() called from OnRelayout().
1200
1201   // Call the Control::OnSceneConnection() to set the depth of the background.
1202   Control::OnSceneConnection(depth);
1203 }
1204
1205 bool TextEditor::OnTouched(Actor actor, const TouchEvent& touch)
1206 {
1207   return false;
1208 }
1209
1210 void TextEditor::OnIdleSignal()
1211 {
1212   // Emits the change of input style signals.
1213   mController->ProcessInputStyleChangedSignals();
1214
1215   // Set the pointer to null as the callback manager deletes the callback after execute it.
1216   mIdleCallback = NULL;
1217 }
1218
1219 void TextEditor::ApplyScrollPosition()
1220 {
1221   const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
1222   float          scrollAmount = 0.0f;
1223
1224   if(mScrollAnimationEnabled)
1225   {
1226     scrollAmount = mController->GetScrollAmountByUserInput();
1227   }
1228   if(mTextVerticalScroller)
1229   {
1230     mTextVerticalScroller->CheckStartAnimation(mRenderableActor, scrollOffset.x + mAlignmentOffset, scrollOffset.y - scrollAmount, scrollAmount);
1231   }
1232   else if(Equals(scrollAmount, 0.0f, Math::MACHINE_EPSILON_1))
1233   {
1234     mRenderableActor.SetProperty(Actor::Property::POSITION, Vector2(scrollOffset.x + mAlignmentOffset, scrollOffset.y - scrollAmount));
1235   }
1236   else
1237   {
1238     mTextVerticalScroller = Text::TextVerticalScroller::New();
1239     if(!Equals(mScrollAnimationDuration, 0.0f, Math::MACHINE_EPSILON_1))
1240     {
1241       mTextVerticalScroller->SetDuration(mScrollAnimationDuration);
1242     }
1243     mTextVerticalScroller->CheckStartAnimation(mRenderableActor, scrollOffset.x + mAlignmentOffset, scrollOffset.y - scrollAmount, scrollAmount);
1244   }
1245 }
1246
1247 bool TextEditor::IsEditable() const
1248 {
1249   return mController->IsEditable();
1250 }
1251
1252 void TextEditor::SetEditable(bool editable)
1253 {
1254   mController->SetEditable(editable);
1255   if(mInputMethodContext && !editable)
1256   {
1257     mInputMethodContext.Deactivate();
1258   }
1259 }
1260
1261 void TextEditor::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type)
1262 {
1263   mController->ChangedLayoutDirection();
1264 }
1265
1266 TextEditor::TextEditor()
1267 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
1268   mAnimationPeriod(0.0f, 0.0f),
1269   mIdleCallback(NULL),
1270   mAlignmentOffset(0.f),
1271   mScrollAnimationDuration(0.f),
1272   mLineSpacing(0.f),
1273   mRenderingBackend(DEFAULT_RENDERING_BACKEND),
1274   mHasBeenStaged(false),
1275   mScrollAnimationEnabled(false),
1276   mScrollBarEnabled(false),
1277   mScrollStarted(false),
1278   mTextChanged(false),
1279   mCursorPositionChanged(false),
1280   mSelectionChanged(false),
1281   mSelectionCleared(false),
1282   mOldPosition(0u),
1283   mOldSelectionStart(0u),
1284   mOldSelectionEnd(0u)
1285 {
1286 }
1287
1288 TextEditor::~TextEditor()
1289 {
1290   UnparentAndReset(mStencil);
1291
1292   if((NULL != mIdleCallback) && Adaptor::IsAvailable())
1293   {
1294     // Removes the callback from the callback manager in case the text-editor is destroyed before the callback is executed.
1295     Adaptor::Get().RemoveIdle(mIdleCallback);
1296   }
1297 }
1298
1299 std::string TextEditor::AccessibleImpl::GetName()
1300 {
1301   auto self = Toolkit::TextEditor::DownCast(Self());
1302   return self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1303 }
1304
1305 std::string TextEditor::AccessibleImpl::GetText(size_t startOffset, size_t endOffset)
1306 {
1307   if(endOffset <= startOffset)
1308   {
1309     return {};
1310   }
1311
1312   auto self = Toolkit::TextEditor::DownCast(Self());
1313   auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1314
1315   if(startOffset > text.size() || endOffset > text.size())
1316   {
1317     return {};
1318   }
1319
1320   return text.substr(startOffset, endOffset - startOffset);
1321 }
1322
1323 size_t TextEditor::AccessibleImpl::GetCharacterCount()
1324 {
1325   auto self = Toolkit::TextEditor::DownCast(Self());
1326   auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1327
1328   return text.size();
1329 }
1330
1331 size_t TextEditor::AccessibleImpl::GetCursorOffset()
1332 {
1333   auto slf = Toolkit::TextEditor::DownCast(Self());
1334   return Dali::Toolkit::GetImpl(slf).GetTextController()->GetCursorPosition();
1335 }
1336
1337 bool TextEditor::AccessibleImpl::SetCursorOffset(size_t offset)
1338 {
1339   auto slf = Toolkit::TextEditor::DownCast(Self());
1340   auto txt = slf.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1341   if(offset > txt.size())
1342   {
1343     return false;
1344   }
1345
1346   auto& slfImpl = Dali::Toolkit::GetImpl(slf);
1347   slfImpl.GetTextController()->ResetCursorPosition(offset);
1348   slfImpl.RequestTextRelayout();
1349
1350   return true;
1351 }
1352
1353 Dali::Accessibility::Range TextEditor::AccessibleImpl::GetTextAtOffset(size_t offset, Dali::Accessibility::TextBoundary boundary)
1354 {
1355   auto self     = Toolkit::TextEditor::DownCast(Self());
1356   auto text     = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1357   auto textSize = text.size();
1358
1359   auto range = Dali::Accessibility::Range{};
1360
1361   switch(boundary)
1362   {
1363     case Dali::Accessibility::TextBoundary::CHARACTER:
1364     {
1365       if(offset < textSize)
1366       {
1367         range.content     = text[offset];
1368         range.startOffset = offset;
1369         range.endOffset   = offset + 1;
1370       }
1371       break;
1372     }
1373     case Dali::Accessibility::TextBoundary::WORD:
1374     case Dali::Accessibility::TextBoundary::LINE:
1375     {
1376       auto textString = text.c_str();
1377       auto breaks     = std::vector<char>(textSize, 0);
1378
1379       if(boundary == Dali::Accessibility::TextBoundary::WORD)
1380       {
1381         Accessibility::Accessible::FindWordSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
1382       }
1383       else
1384       {
1385         Accessibility::Accessible::FindLineSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
1386       }
1387
1388       auto index   = 0u;
1389       auto counter = 0u;
1390       while(index < textSize && counter <= offset)
1391       {
1392         auto start = index;
1393         if(breaks[index])
1394         {
1395           while(breaks[index])
1396           {
1397             index++;
1398           }
1399           counter++;
1400         }
1401         else
1402         {
1403           if(boundary == Dali::Accessibility::TextBoundary::WORD)
1404           {
1405             index++;
1406           }
1407           if(boundary == Dali::Accessibility::TextBoundary::LINE)
1408           {
1409             counter++;
1410           }
1411         }
1412
1413         if((counter > 0) && ((counter - 1) == offset))
1414         {
1415           range.content     = text.substr(start, index - start + 1);
1416           range.startOffset = start;
1417           range.endOffset   = index + 1;
1418         }
1419
1420         if(boundary == Dali::Accessibility::TextBoundary::LINE)
1421         {
1422           index++;
1423         }
1424       }
1425       break;
1426     }
1427     case Dali::Accessibility::TextBoundary::SENTENCE:
1428     {
1429       /* not supported by default */
1430       break;
1431     }
1432     case Dali::Accessibility::TextBoundary::PARAGRAPH:
1433     {
1434       /* Paragraph is not supported by libunibreak library */
1435       break;
1436     }
1437     default:
1438       break;
1439   }
1440
1441   return range;
1442 }
1443
1444 Dali::Accessibility::Range TextEditor::AccessibleImpl::GetRangeOfSelection(size_t selectionIndex)
1445 {
1446   // Since DALi supports only one selection indexes higher than 0 are ignored
1447   if(selectionIndex > 0)
1448   {
1449     return {};
1450   }
1451
1452   auto        self       = Toolkit::TextEditor::DownCast(Self());
1453   auto        controller = Dali::Toolkit::GetImpl(self).GetTextController();
1454   std::string value{};
1455   controller->RetrieveSelection(value);
1456   auto indices = controller->GetSelectionIndexes();
1457
1458   return {static_cast<size_t>(indices.first), static_cast<size_t>(indices.second), value};
1459 }
1460
1461 bool TextEditor::AccessibleImpl::RemoveSelection(size_t selectionIndex)
1462 {
1463   // Since DALi supports only one selection indexes higher than 0 are ignored
1464   if(selectionIndex > 0)
1465   {
1466     return false;
1467   }
1468
1469   auto self = Toolkit::TextEditor::DownCast(Self());
1470   Dali::Toolkit::GetImpl(self).GetTextController()->SetSelection(0, 0);
1471   return true;
1472 }
1473
1474 bool TextEditor::AccessibleImpl::SetRangeOfSelection(size_t selectionIndex, size_t startOffset, size_t endOffset)
1475 {
1476   // Since DALi supports only one selection indexes higher than 0 are ignored
1477   if(selectionIndex > 0)
1478   {
1479     return false;
1480   }
1481
1482   auto self = Toolkit::TextEditor::DownCast(Self());
1483   Dali::Toolkit::GetImpl(self).GetTextController()->SetSelection(startOffset, endOffset);
1484   return true;
1485 }
1486
1487 bool TextEditor::AccessibleImpl::CopyText(size_t startPosition, size_t endPosition)
1488 {
1489   if(endPosition <= startPosition)
1490   {
1491     return false;
1492   }
1493
1494   auto self = Toolkit::TextEditor::DownCast(Self());
1495   auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1496   Dali::Toolkit::GetImpl(self).GetTextController()->CopyStringToClipboard(text.substr(startPosition, endPosition - startPosition));
1497
1498   return true;
1499 }
1500
1501 bool TextEditor::AccessibleImpl::CutText(size_t startPosition, size_t endPosition)
1502 {
1503   if(endPosition <= startPosition)
1504   {
1505     return false;
1506   }
1507
1508   auto self = Toolkit::TextEditor::DownCast(Self());
1509   auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1510   Dali::Toolkit::GetImpl(self).GetTextController()->CopyStringToClipboard(text.substr(startPosition, endPosition - startPosition));
1511
1512   self.SetProperty(Toolkit::TextEditor::Property::TEXT, text.substr(0, startPosition) + text.substr(endPosition));
1513
1514   return true;
1515 }
1516
1517 bool TextEditor::AccessibleImpl::DeleteText(size_t startPosition, size_t endPosition)
1518 {
1519   if(endPosition <= startPosition)
1520   {
1521     return false;
1522   }
1523
1524   auto self = Toolkit::TextEditor::DownCast(Self());
1525   auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1526
1527   self.SetProperty(Toolkit::TextEditor::Property::TEXT, text.substr(0, startPosition) + text.substr(endPosition));
1528
1529   return true;
1530 }
1531
1532 Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates()
1533 {
1534   using namespace Dali::Accessibility;
1535
1536   auto states              = DevelControl::AccessibleImpl::CalculateStates();
1537   states[State::EDITABLE]  = true;
1538   states[State::FOCUSABLE] = true;
1539
1540   Toolkit::Control focusControl = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
1541   if(mSelf == focusControl)
1542   {
1543     states[State::FOCUSED] = true;
1544   }
1545
1546   return states;
1547 }
1548
1549 bool TextEditor::AccessibleImpl::InsertText(size_t startPosition, std::string text)
1550 {
1551   auto self         = Toolkit::TextEditor::DownCast(Self());
1552   auto insertedText = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
1553
1554   insertedText.insert(startPosition, text);
1555
1556   self.SetProperty(Toolkit::TextEditor::Property::TEXT, std::move(insertedText));
1557
1558   return true;
1559 }
1560
1561 bool TextEditor::AccessibleImpl::SetTextContents(std::string newContents)
1562 {
1563   auto self = Toolkit::TextEditor::DownCast(Self());
1564   self.SetProperty(Toolkit::TextEditor::Property::TEXT, std::move(newContents));
1565   return true;
1566 }
1567
1568 int32_t TextEditor::AccessibleImpl::GetLinkCount() const
1569 {
1570   auto self = Toolkit::TextEditor::DownCast(Self());
1571   return Dali::Toolkit::GetImpl(self).mAnchorActors.size();
1572 }
1573
1574 Accessibility::Hyperlink* TextEditor::AccessibleImpl::GetLink(int32_t linkIndex) const
1575 {
1576   if(linkIndex < 0 || linkIndex >= GetLinkCount())
1577   {
1578     return nullptr;
1579   }
1580   auto self        = Toolkit::TextEditor::DownCast(Self());
1581   auto anchorActor = Dali::Toolkit::GetImpl(self).mAnchorActors[linkIndex];
1582   return dynamic_cast<Accessibility::Hyperlink*>(Dali::Accessibility::Accessible::Get(anchorActor));
1583 }
1584
1585 int32_t TextEditor::AccessibleImpl::GetLinkIndex(int32_t characterOffset) const
1586 {
1587   auto self       = Toolkit::TextEditor::DownCast(Self());
1588   auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
1589   return controller->GetAnchorIndex(static_cast<size_t>(characterOffset));
1590 }
1591
1592 } // namespace Internal
1593
1594 } // namespace Toolkit
1595
1596 } // namespace Dali