2d07c1e1b701e53fb6ef4edcbbfae3da45df4614
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-field-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <string>
23 #include <iostream>
24 #include <cstring>
25 #include <dali/public-api/adaptor-framework/key.h>
26 #include <dali/public-api/common/stage.h>
27 #include <dali/public-api/images/resource-image.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/devel-api/object/type-registry-helper.h>
30 #include <dali/devel-api/scripting/scripting.h>
31 #include <dali/devel-api/adaptor-framework/virtual-keyboard.h>
32 #include <dali/integration-api/debug.h>
33
34 // INTERNAL INCLUDES
35 #include <dali-toolkit/public-api/text/rendering-backend.h>
36 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
37 #include <dali-toolkit/internal/text/rendering/text-backend.h>
38 #include <dali-toolkit/internal/styling/style-manager-impl.h>
39
40 using namespace Dali::Toolkit::Text;
41
42 namespace Dali
43 {
44
45 namespace Toolkit
46 {
47
48 namespace Internal
49 {
50
51 namespace // unnamed namespace
52 {
53
54 #if defined(DEBUG_ENABLED)
55   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
56 #endif
57
58   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
59
60 } // unnamed namespace
61
62 namespace
63 {
64
65 const Scripting::StringEnum< Toolkit::Text::LayoutEngine::HorizontalAlignment > HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
66 {
67   { "BEGIN",  Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_BEGIN  },
68   { "CENTER", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_CENTER },
69   { "END",    Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_END    },
70 };
71 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
72
73 const Scripting::StringEnum< Toolkit::Text::LayoutEngine::VerticalAlignment > VERTICAL_ALIGNMENT_STRING_TABLE[] =
74 {
75   { "TOP",    Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_TOP    },
76   { "CENTER", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_CENTER },
77   { "BOTTOM", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_BOTTOM },
78 };
79 const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( VERTICAL_ALIGNMENT_STRING_TABLE ) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
80
81 // Type registration
82 BaseHandle Create()
83 {
84   return Toolkit::TextField::New();
85 }
86
87 // Setup properties, signals and actions using the type-registry.
88 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextField, Toolkit::Control, Create );
89
90 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "rendering-backend",                    INTEGER,   RENDERING_BACKEND                    )
91 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "text",                                 STRING,    TEXT                                 )
92 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholder-text",                     STRING,    PLACEHOLDER_TEXT                     )
93 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholder-text-focused",             STRING,    PLACEHOLDER_TEXT_FOCUSED             )
94 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "font-family",                          STRING,    FONT_FAMILY                          )
95 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "font-style",                           STRING,    FONT_STYLE                           )
96 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "point-size",                           FLOAT,     POINT_SIZE                           )
97 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "max-length",                           INTEGER,   MAX_LENGTH                           )
98 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "exceed-policy",                        INTEGER,   EXCEED_POLICY                        )
99 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "horizontal-alignment",                 STRING,    HORIZONTAL_ALIGNMENT                 )
100 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "vertical-alignment",                   STRING,    VERTICAL_ALIGNMENT                   )
101 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "text-color",                           VECTOR4,   TEXT_COLOR                           )
102 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholder-text-color",               VECTOR4,   PLACEHOLDER_TEXT_COLOR               )
103 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadow-offset",                        VECTOR2,   SHADOW_OFFSET                        )
104 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadow-color",                         VECTOR4,   SHADOW_COLOR                         )
105 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "primary-cursor-color",                 VECTOR4,   PRIMARY_CURSOR_COLOR                 )
106 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "secondary-cursor-color",               VECTOR4,   SECONDARY_CURSOR_COLOR               )
107 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "enable-cursor-blink",                  BOOLEAN,   ENABLE_CURSOR_BLINK                  )
108 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "cursor-blink-interval",                FLOAT,     CURSOR_BLINK_INTERVAL                )
109 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "cursor-blink-duration",                FLOAT,     CURSOR_BLINK_DURATION                )
110 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "grab-handle-image",                    STRING,    GRAB_HANDLE_IMAGE                    )
111 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "grab-handle-pressed-image",            VECTOR4,   GRAB_HANDLE_PRESSED_IMAGE            )
112 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "scroll-threshold",                     FLOAT,     SCROLL_THRESHOLD                     )
113 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "scroll-speed",                         FLOAT,     SCROLL_SPEED                         )
114 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-handle-image-left",          STRING,    SELECTION_HANDLE_IMAGE_LEFT          )
115 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-handle-image-right",         STRING,    SELECTION_HANDLE_IMAGE_RIGHT         )
116 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-handle-pressed-image-left",  STRING,    SELECTION_HANDLE_PRESSED_IMAGE_LEFT  )
117 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-handle-pressed-image-right", STRING,    SELECTION_HANDLE_PRESSED_IMAGE_RIGHT )
118 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-highlight-color",            STRING,    SELECTION_HIGHLIGHT_COLOR            )
119 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "decoration-bounding-box",              RECTANGLE, DECORATION_BOUNDING_BOX              )
120 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "input-method-settings",                MAP,       INPUT_METHOD_SETTINGS                )
121
122 DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "max-length-reached", SIGNAL_MAX_LENGTH_REACHED )
123
124 DALI_TYPE_REGISTRATION_END()
125
126 } // namespace
127
128 Toolkit::TextField TextField::New()
129 {
130   // Create the implementation, temporarily owned by this handle on stack
131   IntrusivePtr< TextField > impl = new TextField();
132
133   // Pass ownership to CustomActor handle
134   Toolkit::TextField handle( *impl );
135
136   // Second-phase init of the implementation
137   // This can only be done after the CustomActor connection has been made...
138   impl->Initialize();
139
140   return handle;
141 }
142
143 void TextField::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
144 {
145   Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
146
147   if( textField )
148   {
149     TextField& impl( GetImpl( textField ) );
150
151     switch( index )
152     {
153       case Toolkit::TextField::Property::RENDERING_BACKEND:
154       {
155         int backend = value.Get< int >();
156         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend );
157
158         if( impl.mRenderingBackend != backend )
159         {
160           impl.mRenderingBackend = backend;
161           impl.mRenderer.Reset();
162         }
163         break;
164       }
165       case Toolkit::TextField::Property::TEXT:
166       {
167         if( impl.mController )
168         {
169           std::string text = value.Get< std::string >();
170           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p TEXT %s\n", impl.mController.Get(), text.c_str() );
171
172           impl.mController->SetText( text );
173         }
174         break;
175       }
176       case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
177       {
178         if( impl.mController )
179         {
180           std::string text = value.Get< std::string >();
181           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str() );
182
183           impl.mController->SetPlaceholderText( PLACEHOLDER_TYPE_INACTIVE, text );
184         }
185         break;
186       }
187       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
188       {
189         if( impl.mController )
190         {
191           std::string text = value.Get< std::string >();
192           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_FOCUSED %s\n", impl.mController.Get(), text.c_str() );
193
194           impl.mController->SetPlaceholderText( PLACEHOLDER_TYPE_ACTIVE, text );
195         }
196         break;
197       }
198       case Toolkit::TextField::Property::FONT_FAMILY:
199       {
200         if( impl.mController )
201         {
202           std::string fontFamily = value.Get< std::string >();
203           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() );
204
205           if( impl.mController->GetDefaultFontFamily() != fontFamily )
206           {
207             impl.mController->SetDefaultFontFamily( fontFamily );
208             impl.RequestTextRelayout();
209           }
210         }
211         break;
212       }
213       case Toolkit::TextField::Property::FONT_STYLE:
214       {
215         if( impl.mController )
216         {
217           std::string fontStyle = value.Get< std::string >();
218           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p FONT_STYLE %s\n", impl.mController.Get(), fontStyle.c_str() );
219
220           if( impl.mController->GetDefaultFontStyle() != fontStyle )
221           {
222             impl.mController->SetDefaultFontStyle( fontStyle );
223             impl.RequestTextRelayout();
224           }
225         }
226         break;
227       }
228       case Toolkit::TextField::Property::POINT_SIZE:
229       {
230         if( impl.mController )
231         {
232           float pointSize = value.Get< float >();
233           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p FONT_STYLE %f\n", impl.mController.Get(), pointSize );
234
235           if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) )
236           {
237             impl.mController->SetDefaultPointSize( pointSize );
238             impl.RequestTextRelayout();
239           }
240         }
241         break;
242       }
243       case Toolkit::TextField::Property::EXCEED_POLICY:
244       {
245         // TODO
246         break;
247       }
248       case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
249       {
250         if( impl.mController )
251         {
252           std::string alignStr = value.Get< std::string >();
253           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p HORIZONTAL_ALIGNMENT %f\n", impl.mController.Get(), alignStr.c_str() );
254
255           LayoutEngine& engine = impl.mController->GetLayoutEngine();
256           LayoutEngine::HorizontalAlignment alignment = Scripting::GetEnumeration< LayoutEngine::HorizontalAlignment >( alignStr.c_str(),
257                                                                                                                         HORIZONTAL_ALIGNMENT_STRING_TABLE,
258                                                                                                                         HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
259
260           if( engine.GetHorizontalAlignment() != alignment )
261           {
262             engine.SetHorizontalAlignment( alignment );
263             impl.RequestTextRelayout();
264           }
265         }
266         break;
267       }
268       case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
269       {
270         if( impl.mController )
271         {
272           std::string alignStr = value.Get< std::string >();
273           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p VERTICAL_ALIGNMENT %f\n", impl.mController.Get(), alignStr.c_str() );
274
275           LayoutEngine& engine = impl.mController->GetLayoutEngine();
276           LayoutEngine::VerticalAlignment alignment = Scripting::GetEnumeration< LayoutEngine::VerticalAlignment >( alignStr.c_str(),
277                                                                                                                     VERTICAL_ALIGNMENT_STRING_TABLE,
278                                                                                                                     VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
279
280           if( engine.GetVerticalAlignment() != alignment )
281           {
282             engine.SetVerticalAlignment( alignment );
283             impl.RequestTextRelayout();
284           }
285         }
286         break;
287       }
288       case Toolkit::TextField::Property::TEXT_COLOR:
289       {
290         if ( impl.mController )
291         {
292           Vector4 textColor = value.Get< Vector4 >();
293           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a );
294
295           if ( impl.mController->GetTextColor() != textColor )
296           {
297             impl.mController->SetTextColor( textColor );
298             impl.RequestTextRelayout();
299           }
300         }
301         break;
302       }
303       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
304       {
305         if ( impl.mController )
306         {
307           Vector4 textColor = value.Get< Vector4 >();
308           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a );
309
310           if ( impl.mController->GetPlaceholderTextColor() != textColor )
311           {
312             impl.mController->SetPlaceholderTextColor( textColor );
313             impl.RequestTextRelayout();
314           }
315         }
316         break;
317       }
318       case Toolkit::TextField::Property::SHADOW_OFFSET:
319       {
320         if( impl.mController )
321         {
322           Vector2 shadowOffset = value.Get< Vector2 >();
323           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SHADOW_OFFSET %f,%f\n", impl.mController.Get(), shadowOffset.x, shadowOffset.y );
324
325           if ( impl.mController->GetShadowOffset() != shadowOffset )
326           {
327             impl.mController->SetShadowOffset( shadowOffset );
328             impl.RequestTextRelayout();
329           }
330         }
331         break;
332       }
333       case Toolkit::TextField::Property::SHADOW_COLOR:
334       {
335         if( impl.mController )
336         {
337           Vector4 shadowColor = value.Get< Vector4 >();
338           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SHADOW_COLOR %f,%f,%f,%f\n", impl.mController.Get(), shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a );
339
340           if ( impl.mController->GetShadowColor() != shadowColor )
341           {
342             impl.mController->SetShadowColor( shadowColor );
343             impl.RequestTextRelayout();
344           }
345         }
346         break;
347       }
348       case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
349       {
350         if( impl.mDecorator )
351         {
352           Vector4 color = value.Get< Vector4 >();
353           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_COLOR %f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
354
355           impl.mDecorator->SetColor( PRIMARY_CURSOR, color );
356         }
357         break;
358       }
359       case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
360       {
361         if( impl.mDecorator )
362         {
363           Vector4 color = value.Get< Vector4 >();
364           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SECONDARY_CURSOR_COLOR %f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
365
366           impl.mDecorator->SetColor( SECONDARY_CURSOR, color );
367         }
368         break;
369       }
370       case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
371       {
372         if( impl.mController )
373         {
374           bool enable = value.Get< bool >();
375           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable );
376
377           impl.mController->SetEnableCursorBlink( enable );
378         }
379         break;
380       }
381       case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
382       {
383         if( impl.mDecorator )
384         {
385           float interval = value.Get< float >();
386           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval );
387
388           impl.mDecorator->SetCursorBlinkInterval( interval );
389         }
390         break;
391       }
392       case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
393       {
394         if( impl.mDecorator )
395         {
396           float duration = value.Get< float >();
397           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), duration );
398
399           impl.mDecorator->SetCursorBlinkDuration( duration );
400         }
401         break;
402       }
403       case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
404       {
405         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
406         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
407
408         if( impl.mDecorator )
409         {
410           impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, image );
411         }
412         break;
413       }
414       case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
415       {
416         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
417         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
418
419         if( impl.mDecorator )
420         {
421           impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED, image );
422         }
423         break;
424       }
425       case Toolkit::TextField::Property::SCROLL_THRESHOLD:
426       {
427         float threshold = value.Get< float >();
428         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold );
429
430         if( impl.mDecorator )
431         {
432           impl.mDecorator->SetScrollThreshold( threshold );
433         }
434         break;
435       }
436       case Toolkit::TextField::Property::SCROLL_SPEED:
437       {
438         float speed = value.Get< float >();
439         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SCROLL_SPEED %f\n", impl.mController.Get(), speed );
440
441         if( impl.mDecorator )
442         {
443           impl.mDecorator->SetScrollSpeed( speed );
444         }
445         break;
446       }
447       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
448       {
449         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
450         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_IMAGE_LEFT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
451
452         if( impl.mDecorator )
453         {
454           impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
455         }
456         break;
457       }
458       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
459       {
460         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
461         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_IMAGE_RIGHT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
462
463         if( impl.mDecorator )
464         {
465           impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
466         }
467         break;
468       }
469       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
470       {
471         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
472         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_PRESSED_IMAGE_LEFT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
473
474         if( impl.mDecorator )
475         {
476           impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
477         }
478         break;
479       }
480       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
481       {
482         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
483         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_PRESSED_IMAGE_RIGHT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
484
485         if( impl.mDecorator )
486         {
487           impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
488         }
489         break;
490       }
491       case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
492       {
493         Vector4 color = value.Get< Vector4 >();
494         DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SELECTION_HIGHLIGHT_COLOR %f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
495
496         if( impl.mDecorator )
497         {
498           impl.mDecorator->SetHighlightColor( color );
499         }
500         break;
501       }
502       case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
503       {
504         if( impl.mDecorator )
505         {
506           Rect<int> box = value.Get< Rect<int> >();
507           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height );
508
509           impl.mDecorator->SetBoundingBox( box );
510         }
511         break;
512       }
513       case Toolkit::TextField::Property::MAX_LENGTH:
514       {
515         if( impl.mController )
516         {
517           int max = value.Get< int >();
518           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p MAX_LENGTH %d\n", impl.mController.Get(), max );
519
520           impl.mController->SetMaximumNumberOfCharacters( max );
521         }
522         break;
523       }
524       case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
525       {
526         // Empty implementation for now.
527         Property::Map map = value.Get<Property::Map>();
528         VirtualKeyboard::ApplySettings( map );
529         break;
530       }
531     } // switch
532   } // textfield
533 }
534
535 Property::Value TextField::GetProperty( BaseObject* object, Property::Index index )
536 {
537   Property::Value value;
538
539   Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
540
541   if( textField )
542   {
543     TextField& impl( GetImpl( textField ) );
544
545     switch( index )
546     {
547       case Toolkit::TextField::Property::RENDERING_BACKEND:
548       {
549         value = impl.mRenderingBackend;
550         break;
551       }
552       case Toolkit::TextField::Property::TEXT:
553       {
554         if( impl.mController )
555         {
556           std::string text;
557           impl.mController->GetText( text );
558           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p returning text: %s\n", impl.mController.Get(), text.c_str() );
559           value = text;
560         }
561         break;
562       }
563       case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
564       {
565         if( impl.mController )
566         {
567           std::string text;
568           impl.mController->GetPlaceholderText( PLACEHOLDER_TYPE_INACTIVE, text );
569           value = text;
570         }
571         break;
572       }
573       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
574       {
575         if( impl.mController )
576         {
577           std::string text;
578           impl.mController->GetPlaceholderText( PLACEHOLDER_TYPE_ACTIVE, text );
579           value = text;
580         }
581         break;
582       }
583       case Toolkit::TextField::Property::EXCEED_POLICY:
584       {
585         value = impl.mExceedPolicy;
586         break;
587       }
588       case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
589       {
590         if( impl.mController )
591         {
592           value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetLayoutEngine().GetHorizontalAlignment(),
593                                                                                                                   HORIZONTAL_ALIGNMENT_STRING_TABLE,
594                                                                                                                   HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ) );
595         }
596         break;
597       }
598       case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
599       {
600         if( impl.mController )
601         {
602           value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetLayoutEngine().GetVerticalAlignment(),
603                                                                                                                   VERTICAL_ALIGNMENT_STRING_TABLE,
604                                                                                                                   VERTICAL_ALIGNMENT_STRING_TABLE_COUNT ) );
605         }
606         break;
607       }
608       case Toolkit::TextField::Property::TEXT_COLOR:
609       {
610         if ( impl.mController )
611         {
612           value = impl.mController->GetTextColor();
613         }
614         break;
615       }
616       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
617       {
618         if ( impl.mController )
619         {
620           value = impl.mController->GetPlaceholderTextColor();
621         }
622         break;
623       }
624       case Toolkit::TextField::Property::SHADOW_OFFSET:
625       {
626         if ( impl.mController )
627         {
628           value = impl.mController->GetShadowOffset();
629         }
630         break;
631       }
632       case Toolkit::TextField::Property::SHADOW_COLOR:
633       {
634         if ( impl.mController )
635         {
636           value = impl.mController->GetShadowColor();
637         }
638         break;
639       }
640       case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
641       {
642         if( impl.mDecorator )
643         {
644           value = impl.mDecorator->GetColor( PRIMARY_CURSOR );
645         }
646         break;
647       }
648       case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
649       {
650         if( impl.mDecorator )
651         {
652           value = impl.mDecorator->GetColor( SECONDARY_CURSOR );
653         }
654         break;
655       }
656       case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
657       {
658         value = impl.mController->GetEnableCursorBlink();
659         break;
660       }
661       case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
662       {
663         if( impl.mDecorator )
664         {
665           value = impl.mDecorator->GetCursorBlinkInterval();
666         }
667         break;
668       }
669       case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
670       {
671         if( impl.mDecorator )
672         {
673           value = impl.mDecorator->GetCursorBlinkDuration();
674         }
675         break;
676       }
677       case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
678       {
679         if( impl.mDecorator )
680         {
681           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED ) );
682           if( image )
683           {
684             value = image.GetUrl();
685           }
686         }
687         break;
688       }
689       case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
690       {
691         if( impl.mDecorator )
692         {
693           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED ) );
694           if( image )
695           {
696             value = image.GetUrl();
697           }
698         }
699         break;
700       }
701       case Toolkit::TextField::Property::SCROLL_THRESHOLD:
702       {
703         if( impl.mDecorator )
704         {
705           value = impl.mDecorator->GetScrollThreshold();
706         }
707         break;
708       }
709       case Toolkit::TextField::Property::SCROLL_SPEED:
710       {
711         if( impl.mDecorator )
712         {
713           value = impl.mDecorator->GetScrollSpeed();
714         }
715         break;
716       }
717       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
718       {
719         if( impl.mDecorator )
720         {
721           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) );
722           if( image )
723           {
724             value = image.GetUrl();
725           }
726         }
727         break;
728       }
729       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
730       {
731         if( impl.mDecorator )
732         {
733           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) );
734           if( image )
735           {
736             value = image.GetUrl();
737           }
738         }
739         break;
740       }
741       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
742       {
743         if( impl.mDecorator )
744         {
745           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ) );
746           if( image )
747           {
748             value = image.GetUrl();
749           }
750         }
751         break;
752       }
753       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
754       {
755         if( impl.mDecorator )
756         {
757           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ) );
758           if( image )
759           {
760             value = image.GetUrl();
761           }
762         }
763         break;
764       }
765       case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
766       {
767         if( impl.mDecorator )
768         {
769           value = impl.mDecorator->GetHighlightColor();
770         }
771         break;
772       }
773       case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
774       {
775         if( impl.mDecorator )
776         {
777           value = impl.mDecorator->GetBoundingBox();
778         }
779         break;
780       }
781       case Toolkit::TextField::Property::MAX_LENGTH:
782       {
783         if( impl.mController )
784         {
785           value = impl.mController->GetMaximumNumberOfCharacters();
786         }
787         break;
788       }
789       case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
790       {
791         break;
792       }
793     } //switch
794   }
795
796   return value;
797 }
798
799 bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
800 {
801   Dali::BaseHandle handle( object );
802
803   bool connected( true );
804   Toolkit::TextField field = Toolkit::TextField::DownCast( handle );
805
806   if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
807   {
808     field.MaxLengthReachedSignal().Connect( tracker, functor );
809   }
810   else
811   {
812     // signalName does not match any signal
813     connected = false;
814   }
815
816   return connected;
817 }
818
819 Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
820 {
821   return mMaxLengthReachedSignal;
822 }
823
824 void TextField::OnInitialize()
825 {
826   Actor self = Self();
827
828   mController = Text::Controller::New( *this );
829
830   mDecorator = Text::Decorator::New( *this, *mController );
831
832   mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
833
834   mController->EnableTextInput( mDecorator );
835
836   // Forward input events to controller
837   EnableGestureDetection(Gesture::Tap);
838   GetTapGestureDetector().SetMaximumTapsRequired( 2 );
839   EnableGestureDetection(Gesture::Pan);
840
841   self.TouchedSignal().Connect( this, &TextField::OnTouched );
842
843   // Set BoundingBox to stage size if not already set.
844   if ( mDecorator->GetBoundingBox().IsEmpty() )
845   {
846     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
847     mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
848   }
849
850   // Fill-parent area by default
851   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
852   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
853 }
854
855 void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
856 {
857   GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
858 }
859
860 Vector3 TextField::GetNaturalSize()
861 {
862   return mController->GetNaturalSize();
863 }
864
865 float TextField::GetHeightForWidth( float width )
866 {
867   return mController->GetHeightForWidth( width );
868 }
869
870 void TextField::OnRelayout( const Vector2& size, RelayoutContainer& container )
871 {
872   if( mController->Relayout( size ) ||
873       !mRenderer )
874   {
875     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnRelayout %p Displaying new contents\n", mController.Get() );
876
877     if( mDecorator )
878     {
879       mDecorator->Relayout( size );
880     }
881
882     if( !mRenderer )
883     {
884       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
885     }
886
887     RenderableActor renderableActor;
888     if( mRenderer )
889     {
890       renderableActor = mRenderer->Render( mController->GetView() );
891     }
892
893     EnableClipping( (Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy), size );
894
895     if( renderableActor != mRenderableActor )
896     {
897       UnparentAndReset( mRenderableActor );
898       mRenderableActor = renderableActor;
899     }
900
901     if( mRenderableActor )
902     {
903       const Vector2 offset = mController->GetScrollPosition() + mController->GetAlignmentOffset();
904
905       mRenderableActor.SetPosition( offset.x, offset.y );
906
907       // Make sure the actor is parented correctly with/without clipping
908       if( mClipper )
909       {
910         mClipper->GetRootActor().Add( mRenderableActor );
911       }
912       else
913       {
914         Self().Add( mRenderableActor );
915       }
916     }
917   }
918 }
919
920 void TextField::OnKeyInputFocusGained()
921 {
922   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyInputFocusGained %p\n", mController.Get() );
923
924   VirtualKeyboard::StatusChangedSignal().Connect( this, &TextField::KeyboardStatusChanged );
925
926   ImfManager imfManager = ImfManager::Get();
927
928   if ( imfManager )
929   {
930     imfManager.EventReceivedSignal().Connect( this, &TextField::OnImfEvent );
931
932     // Notify that the text editing start.
933     imfManager.Activate();
934
935     // When window gain lost focus, the imf manager is deactivated. Thus when window gain focus again, the imf manager must be activated.
936     imfManager.SetRestoreAfterFocusLost( true );
937   }
938
939   mController->KeyboardFocusGainEvent();
940
941   EmitKeyInputFocusSignal( true ); // Calls back into the Control hence done last.
942 }
943
944 void TextField::OnKeyInputFocusLost()
945 {
946   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField:OnKeyInputFocusLost %p\n", mController.Get() );
947
948   VirtualKeyboard::StatusChangedSignal().Disconnect( this, &TextField::KeyboardStatusChanged );
949
950   ImfManager imfManager = ImfManager::Get();
951   if ( imfManager )
952   {
953     // The text editing is finished. Therefore the imf manager don't have restore activation.
954     imfManager.SetRestoreAfterFocusLost( false );
955
956     // Notify that the text editing finish.
957     imfManager.Deactivate();
958
959     imfManager.EventReceivedSignal().Disconnect( this, &TextField::OnImfEvent );
960   }
961
962   mController->KeyboardFocusLostEvent();
963
964   EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last.
965 }
966
967 void TextField::OnTap( const TapGesture& gesture )
968 {
969   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get() );
970
971   // Show the keyboard if it was hidden.
972   if (!VirtualKeyboard::IsVisible())
973   {
974     VirtualKeyboard::Show();
975   }
976
977   // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
978   mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x, gesture.localPoint.y );
979
980   SetKeyInputFocus();
981 }
982
983 void TextField::OnPan( const PanGesture& gesture )
984 {
985   mController->PanEvent( gesture.state, gesture.displacement );
986 }
987
988 bool TextField::OnKeyEvent( const KeyEvent& event )
989 {
990   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyEvent %p keyCode %d\n", mController.Get(), event.keyCode );
991
992   if( Dali::DALI_KEY_ESCAPE == event.keyCode ||
993       "Return" == event.keyPressedName ) // Make a Dali key code for this
994   {
995     ClearKeyInputFocus();
996     return true;
997   }
998
999   return mController->KeyEvent( event );
1000 }
1001
1002 ImfManager::ImfCallbackData TextField::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
1003 {
1004   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName );
1005
1006   bool update( false );
1007
1008   std::string text;
1009   unsigned int cursorPosition( 0 );
1010
1011   switch ( imfEvent.eventName )
1012   {
1013     case ImfManager::COMMIT:
1014     {
1015       mController->InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
1016       break;
1017     }
1018     case ImfManager::PREEDIT:
1019     {
1020       mController->InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
1021       update = true;
1022       break;
1023     }
1024     case ImfManager::DELETESURROUNDING:
1025     {
1026       mController->RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
1027       break;
1028     }
1029     case ImfManager::GETSURROUNDING:
1030     {
1031       mController->GetText( text );
1032       cursorPosition = mController->GetLogicalCursorPosition();
1033
1034       imfManager.SetSurroundingText( text );
1035       imfManager.SetCursorPosition( cursorPosition );
1036       break;
1037     }
1038     case ImfManager::VOID:
1039     {
1040       // do nothing
1041       break;
1042     }
1043   } // end switch
1044
1045   if( ImfManager::GETSURROUNDING != imfEvent.eventName )
1046   {
1047     mController->GetText( text );
1048     cursorPosition = mController->GetLogicalCursorPosition();
1049   }
1050
1051   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
1052
1053   return callbackData;
1054 }
1055
1056 void TextField::RequestTextRelayout()
1057 {
1058   RelayoutRequest();
1059 }
1060
1061 void TextField::MaxLengthReached()
1062 {
1063   Dali::Toolkit::TextField handle( GetOwner() );
1064   mMaxLengthReachedSignal.Emit( handle );
1065 }
1066
1067 void TextField::EnableClipping( bool clipping, const Vector2& size )
1068 {
1069   if( clipping )
1070   {
1071     // Not worth to created clip actor if width or height is equal to zero.
1072     if( size.width > Math::MACHINE_EPSILON_1000 && size.height > Math::MACHINE_EPSILON_1000 )
1073     {
1074       if( !mClipper )
1075       {
1076         Actor self = Self();
1077
1078         mClipper = Clipper::New( size );
1079         self.Add( mClipper->GetRootActor() );
1080         self.Add( mClipper->GetImageActor() );
1081       }
1082       else if ( mClipper )
1083       {
1084         mClipper->Refresh( size );
1085       }
1086     }
1087   }
1088   else
1089   {
1090     // Note - this will automatically remove the root & image actors
1091     mClipper.Reset();
1092   }
1093 }
1094
1095 void TextField::KeyboardStatusChanged(bool keyboardShown)
1096 {
1097   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown );
1098
1099   // Just hide the grab handle when keyboard is hidden.
1100   if (!keyboardShown )
1101   {
1102     mController->KeyboardFocusLostEvent();
1103   }
1104 }
1105
1106 bool TextField::OnTouched( Actor actor, const TouchEvent& event )
1107 {
1108   return true;
1109 }
1110
1111 TextField::TextField()
1112 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
1113   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
1114   mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP )
1115 {
1116 }
1117
1118 TextField::~TextField()
1119 {
1120   mClipper.Reset();
1121 }
1122
1123 } // namespace Internal
1124
1125 } // namespace Toolkit
1126
1127 } // namespace Dali