Fixes for the text controller.
[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           impl.RequestTextRelayout();
163         }
164         break;
165       }
166       case Toolkit::TextField::Property::TEXT:
167       {
168         if( impl.mController )
169         {
170           const std::string text = value.Get< std::string >();
171           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p TEXT %s\n", impl.mController.Get(), text.c_str() );
172
173           impl.mController->SetText( text );
174         }
175         break;
176       }
177       case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
178       {
179         if( impl.mController )
180         {
181           const std::string text = value.Get< std::string >();
182           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str() );
183
184           impl.mController->SetPlaceholderText( PLACEHOLDER_TYPE_INACTIVE, text );
185         }
186         break;
187       }
188       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
189       {
190         if( impl.mController )
191         {
192           const std::string text = value.Get< std::string >();
193           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_FOCUSED %s\n", impl.mController.Get(), text.c_str() );
194
195           impl.mController->SetPlaceholderText( PLACEHOLDER_TYPE_ACTIVE, text );
196         }
197         break;
198       }
199       case Toolkit::TextField::Property::FONT_FAMILY:
200       {
201         if( impl.mController )
202         {
203           const std::string fontFamily = value.Get< std::string >();
204           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() );
205
206           if( impl.mController->GetDefaultFontFamily() != fontFamily )
207           {
208             impl.mController->SetDefaultFontFamily( fontFamily );
209           }
210         }
211         break;
212       }
213       case Toolkit::TextField::Property::FONT_STYLE:
214       {
215         if( impl.mController )
216         {
217           const 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           }
224         }
225         break;
226       }
227       case Toolkit::TextField::Property::POINT_SIZE:
228       {
229         if( impl.mController )
230         {
231           const float pointSize = value.Get< float >();
232           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p FONT_STYLE %f\n", impl.mController.Get(), pointSize );
233
234           if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) )
235           {
236             impl.mController->SetDefaultPointSize( pointSize );
237           }
238         }
239         break;
240       }
241       case Toolkit::TextField::Property::EXCEED_POLICY:
242       {
243         // TODO
244         break;
245       }
246       case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
247       {
248         if( impl.mController )
249         {
250           const std::string alignStr = value.Get< std::string >();
251           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p HORIZONTAL_ALIGNMENT %f\n", impl.mController.Get(), alignStr.c_str() );
252
253           const LayoutEngine::HorizontalAlignment alignment = Scripting::GetEnumeration< LayoutEngine::HorizontalAlignment >( alignStr.c_str(),
254                                                                                                                         HORIZONTAL_ALIGNMENT_STRING_TABLE,
255                                                                                                                         HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
256
257           impl.mController->SetHorizontalAlignment( alignment );
258         }
259         break;
260       }
261       case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
262       {
263         if( impl.mController )
264         {
265           const std::string alignStr = value.Get< std::string >();
266           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p VERTICAL_ALIGNMENT %f\n", impl.mController.Get(), alignStr.c_str() );
267
268           LayoutEngine::VerticalAlignment alignment = Scripting::GetEnumeration< LayoutEngine::VerticalAlignment >( alignStr.c_str(),
269                                                                                                                     VERTICAL_ALIGNMENT_STRING_TABLE,
270                                                                                                                     VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
271
272           impl.mController->SetVerticalAlignment( alignment );
273         }
274         break;
275       }
276       case Toolkit::TextField::Property::TEXT_COLOR:
277       {
278         if( impl.mController )
279         {
280           const Vector4 textColor = value.Get< Vector4 >();
281           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 );
282
283           if( impl.mController->GetTextColor() != textColor )
284           {
285             impl.mController->SetTextColor( textColor );
286             impl.mRenderer.Reset();
287           }
288         }
289         break;
290       }
291       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
292       {
293         if( impl.mController )
294         {
295           const Vector4 textColor = value.Get< Vector4 >();
296           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 );
297
298           if( impl.mController->GetPlaceholderTextColor() != textColor )
299           {
300             impl.mController->SetPlaceholderTextColor( textColor );
301             impl.mRenderer.Reset();
302           }
303         }
304         break;
305       }
306       case Toolkit::TextField::Property::SHADOW_OFFSET:
307       {
308         if( impl.mController )
309         {
310           const Vector2 shadowOffset = value.Get< Vector2 >();
311           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SHADOW_OFFSET %f,%f\n", impl.mController.Get(), shadowOffset.x, shadowOffset.y );
312
313           if ( impl.mController->GetShadowOffset() != shadowOffset )
314           {
315             impl.mController->SetShadowOffset( shadowOffset );
316             impl.mRenderer.Reset();
317           }
318         }
319         break;
320       }
321       case Toolkit::TextField::Property::SHADOW_COLOR:
322       {
323         if( impl.mController )
324         {
325           const Vector4 shadowColor = value.Get< Vector4 >();
326           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 );
327
328           if ( impl.mController->GetShadowColor() != shadowColor )
329           {
330             impl.mController->SetShadowColor( shadowColor );
331             impl.mRenderer.Reset();
332           }
333         }
334         break;
335       }
336       case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
337       {
338         if( impl.mDecorator )
339         {
340           const Vector4 color = value.Get< Vector4 >();
341           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 );
342
343           impl.mDecorator->SetColor( PRIMARY_CURSOR, color );
344           impl.RequestTextRelayout();
345         }
346         break;
347       }
348       case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
349       {
350         if( impl.mDecorator )
351         {
352           const Vector4 color = value.Get< Vector4 >();
353           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 );
354
355           impl.mDecorator->SetColor( SECONDARY_CURSOR, color );
356           impl.RequestTextRelayout();
357         }
358         break;
359       }
360       case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
361       {
362         if( impl.mController )
363         {
364           const bool enable = value.Get< bool >();
365           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable );
366
367           impl.mController->SetEnableCursorBlink( enable );
368           impl.RequestTextRelayout();
369         }
370         break;
371       }
372       case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
373       {
374         if( impl.mDecorator )
375         {
376           const float interval = value.Get< float >();
377           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval );
378
379           impl.mDecorator->SetCursorBlinkInterval( interval );
380         }
381         break;
382       }
383       case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
384       {
385         if( impl.mDecorator )
386         {
387           const float duration = value.Get< float >();
388           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), duration );
389
390           impl.mDecorator->SetCursorBlinkDuration( duration );
391         }
392         break;
393       }
394       case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
395       {
396         const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
397         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
398
399         if( impl.mDecorator )
400         {
401           impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, image );
402           impl.RequestTextRelayout();
403         }
404         break;
405       }
406       case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
407       {
408         const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
409         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
410
411         if( impl.mDecorator )
412         {
413           impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED, image );
414           impl.RequestTextRelayout();
415         }
416         break;
417       }
418       case Toolkit::TextField::Property::SCROLL_THRESHOLD:
419       {
420         const float threshold = value.Get< float >();
421         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold );
422
423         if( impl.mDecorator )
424         {
425           impl.mDecorator->SetScrollThreshold( threshold );
426         }
427         break;
428       }
429       case Toolkit::TextField::Property::SCROLL_SPEED:
430       {
431         const float speed = value.Get< float >();
432         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SCROLL_SPEED %f\n", impl.mController.Get(), speed );
433
434         if( impl.mDecorator )
435         {
436           impl.mDecorator->SetScrollSpeed( speed );
437         }
438         break;
439       }
440       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
441       {
442         const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
443         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_IMAGE_LEFT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
444
445         if( impl.mDecorator )
446         {
447           impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
448           impl.RequestTextRelayout();
449         }
450         break;
451       }
452       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
453       {
454         const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
455         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_IMAGE_RIGHT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
456
457         if( impl.mDecorator )
458         {
459           impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
460           impl.RequestTextRelayout();
461         }
462         break;
463       }
464       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
465       {
466         const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
467         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_PRESSED_IMAGE_LEFT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
468
469         if( impl.mDecorator )
470         {
471           impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
472           impl.RequestTextRelayout();
473         }
474         break;
475       }
476       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
477       {
478         const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
479         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SELECTION_HANDLE_PRESSED_IMAGE_RIGHT %f\n", impl.mController.Get(), image.GetUrl().c_str() );
480
481         if( impl.mDecorator )
482         {
483           impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
484           impl.RequestTextRelayout();
485         }
486         break;
487       }
488       case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
489       {
490         const Vector4 color = value.Get< Vector4 >();
491         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 );
492
493         if( impl.mDecorator )
494         {
495           impl.mDecorator->SetHighlightColor( color );
496           impl.RequestTextRelayout();
497         }
498         break;
499       }
500       case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
501       {
502         if( impl.mDecorator )
503         {
504           const Rect<int> box = value.Get< Rect<int> >();
505           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 );
506
507           impl.mDecorator->SetBoundingBox( box );
508           impl.RequestTextRelayout();
509         }
510         break;
511       }
512       case Toolkit::TextField::Property::MAX_LENGTH:
513       {
514         if( impl.mController )
515         {
516           const int max = value.Get< int >();
517           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p MAX_LENGTH %d\n", impl.mController.Get(), max );
518
519           impl.mController->SetMaximumNumberOfCharacters( max );
520         }
521         break;
522       }
523       case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
524       {
525         const Property::Map map = value.Get<Property::Map>();
526         VirtualKeyboard::ApplySettings( map );
527         break;
528       }
529     } // switch
530   } // textfield
531 }
532
533 Property::Value TextField::GetProperty( BaseObject* object, Property::Index index )
534 {
535   Property::Value value;
536
537   Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
538
539   if( textField )
540   {
541     TextField& impl( GetImpl( textField ) );
542
543     switch( index )
544     {
545       case Toolkit::TextField::Property::RENDERING_BACKEND:
546       {
547         value = impl.mRenderingBackend;
548         break;
549       }
550       case Toolkit::TextField::Property::TEXT:
551       {
552         if( impl.mController )
553         {
554           std::string text;
555           impl.mController->GetText( text );
556           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p returning text: %s\n", impl.mController.Get(), text.c_str() );
557           value = text;
558         }
559         break;
560       }
561       case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
562       {
563         if( impl.mController )
564         {
565           std::string text;
566           impl.mController->GetPlaceholderText( PLACEHOLDER_TYPE_INACTIVE, text );
567           value = text;
568         }
569         break;
570       }
571       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
572       {
573         if( impl.mController )
574         {
575           std::string text;
576           impl.mController->GetPlaceholderText( PLACEHOLDER_TYPE_ACTIVE, text );
577           value = text;
578         }
579         break;
580       }
581       case Toolkit::TextField::Property::FONT_FAMILY:
582       {
583         if( impl.mController )
584         {
585           value = impl.mController->GetDefaultFontFamily();
586         }
587         break;
588       }
589       case Toolkit::TextField::Property::FONT_STYLE:
590       {
591         if( impl.mController )
592         {
593           value = impl.mController->GetDefaultFontStyle();
594         }
595         break;
596       }
597       case Toolkit::TextField::Property::POINT_SIZE:
598       {
599         if( impl.mController )
600         {
601           value = impl.mController->GetDefaultPointSize();
602         }
603         break;
604       }
605       case Toolkit::TextField::Property::EXCEED_POLICY:
606       {
607         value = impl.mExceedPolicy;
608         break;
609       }
610       case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
611       {
612         if( impl.mController )
613         {
614           value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetLayoutEngine().GetHorizontalAlignment(),
615                                                                                                                   HORIZONTAL_ALIGNMENT_STRING_TABLE,
616                                                                                                                   HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ) );
617         }
618         break;
619       }
620       case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
621       {
622         if( impl.mController )
623         {
624           value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetLayoutEngine().GetVerticalAlignment(),
625                                                                                                                   VERTICAL_ALIGNMENT_STRING_TABLE,
626                                                                                                                   VERTICAL_ALIGNMENT_STRING_TABLE_COUNT ) );
627         }
628         break;
629       }
630       case Toolkit::TextField::Property::TEXT_COLOR:
631       {
632         if ( impl.mController )
633         {
634           value = impl.mController->GetTextColor();
635         }
636         break;
637       }
638       case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
639       {
640         if ( impl.mController )
641         {
642           value = impl.mController->GetPlaceholderTextColor();
643         }
644         break;
645       }
646       case Toolkit::TextField::Property::SHADOW_OFFSET:
647       {
648         if ( impl.mController )
649         {
650           value = impl.mController->GetShadowOffset();
651         }
652         break;
653       }
654       case Toolkit::TextField::Property::SHADOW_COLOR:
655       {
656         if ( impl.mController )
657         {
658           value = impl.mController->GetShadowColor();
659         }
660         break;
661       }
662       case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
663       {
664         if( impl.mDecorator )
665         {
666           value = impl.mDecorator->GetColor( PRIMARY_CURSOR );
667         }
668         break;
669       }
670       case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
671       {
672         if( impl.mDecorator )
673         {
674           value = impl.mDecorator->GetColor( SECONDARY_CURSOR );
675         }
676         break;
677       }
678       case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
679       {
680         value = impl.mController->GetEnableCursorBlink();
681         break;
682       }
683       case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
684       {
685         if( impl.mDecorator )
686         {
687           value = impl.mDecorator->GetCursorBlinkInterval();
688         }
689         break;
690       }
691       case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
692       {
693         if( impl.mDecorator )
694         {
695           value = impl.mDecorator->GetCursorBlinkDuration();
696         }
697         break;
698       }
699       case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
700       {
701         if( impl.mDecorator )
702         {
703           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED ) );
704           if( image )
705           {
706             value = image.GetUrl();
707           }
708         }
709         break;
710       }
711       case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
712       {
713         if( impl.mDecorator )
714         {
715           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED ) );
716           if( image )
717           {
718             value = image.GetUrl();
719           }
720         }
721         break;
722       }
723       case Toolkit::TextField::Property::SCROLL_THRESHOLD:
724       {
725         if( impl.mDecorator )
726         {
727           value = impl.mDecorator->GetScrollThreshold();
728         }
729         break;
730       }
731       case Toolkit::TextField::Property::SCROLL_SPEED:
732       {
733         if( impl.mDecorator )
734         {
735           value = impl.mDecorator->GetScrollSpeed();
736         }
737         break;
738       }
739       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
740       {
741         if( impl.mDecorator )
742         {
743           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) );
744           if( image )
745           {
746             value = image.GetUrl();
747           }
748         }
749         break;
750       }
751       case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
752       {
753         if( impl.mDecorator )
754         {
755           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) );
756           if( image )
757           {
758             value = image.GetUrl();
759           }
760         }
761         break;
762       }
763       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
764       {
765         if( impl.mDecorator )
766         {
767           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ) );
768           if( image )
769           {
770             value = image.GetUrl();
771           }
772         }
773         break;
774       }
775       case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
776       {
777         if( impl.mDecorator )
778         {
779           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ) );
780           if( image )
781           {
782             value = image.GetUrl();
783           }
784         }
785         break;
786       }
787       case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
788       {
789         if( impl.mDecorator )
790         {
791           value = impl.mDecorator->GetHighlightColor();
792         }
793         break;
794       }
795       case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
796       {
797         if( impl.mDecorator )
798         {
799           value = impl.mDecorator->GetBoundingBox();
800         }
801         break;
802       }
803       case Toolkit::TextField::Property::MAX_LENGTH:
804       {
805         if( impl.mController )
806         {
807           value = impl.mController->GetMaximumNumberOfCharacters();
808         }
809         break;
810       }
811       case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
812       {
813         break;
814       }
815     } //switch
816   }
817
818   return value;
819 }
820
821 bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
822 {
823   Dali::BaseHandle handle( object );
824
825   bool connected( true );
826   Toolkit::TextField field = Toolkit::TextField::DownCast( handle );
827
828   if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
829   {
830     field.MaxLengthReachedSignal().Connect( tracker, functor );
831   }
832   else
833   {
834     // signalName does not match any signal
835     connected = false;
836   }
837
838   return connected;
839 }
840
841 Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
842 {
843   return mMaxLengthReachedSignal;
844 }
845
846 void TextField::OnInitialize()
847 {
848   Actor self = Self();
849
850   mController = Text::Controller::New( *this );
851
852   mDecorator = Text::Decorator::New( *this, *mController );
853
854   mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
855
856   mController->EnableTextInput( mDecorator );
857
858   // Forward input events to controller
859   EnableGestureDetection(Gesture::Tap);
860   GetTapGestureDetector().SetMaximumTapsRequired( 2 );
861   EnableGestureDetection(Gesture::Pan);
862
863   self.TouchedSignal().Connect( this, &TextField::OnTouched );
864
865   // Set BoundingBox to stage size if not already set.
866   if ( mDecorator->GetBoundingBox().IsEmpty() )
867   {
868     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
869     mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
870   }
871
872   // Fill-parent area by default
873   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
874   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
875 }
876
877 void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
878 {
879   GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
880 }
881
882 Vector3 TextField::GetNaturalSize()
883 {
884   return mController->GetNaturalSize();
885 }
886
887 float TextField::GetHeightForWidth( float width )
888 {
889   return mController->GetHeightForWidth( width );
890 }
891
892 void TextField::OnRelayout( const Vector2& size, RelayoutContainer& container )
893 {
894   if( mController->Relayout( size ) ||
895       !mRenderer )
896   {
897     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnRelayout %p Displaying new contents\n", mController.Get() );
898
899     if( mDecorator )
900     {
901       mDecorator->Relayout( size );
902     }
903
904     if( !mRenderer )
905     {
906       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
907     }
908
909     RenderableActor renderableActor;
910     if( mRenderer )
911     {
912       renderableActor = mRenderer->Render( mController->GetView() );
913     }
914
915     EnableClipping( (Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy), size );
916
917     if( renderableActor != mRenderableActor )
918     {
919       UnparentAndReset( mRenderableActor );
920       mRenderableActor = renderableActor;
921     }
922
923     if( mRenderableActor )
924     {
925       const Vector2 offset = mController->GetScrollPosition() + mController->GetAlignmentOffset();
926
927       mRenderableActor.SetPosition( offset.x, offset.y );
928
929       // Make sure the actor is parented correctly with/without clipping
930       if( mClipper )
931       {
932         mClipper->GetRootActor().Add( mRenderableActor );
933       }
934       else
935       {
936         Self().Add( mRenderableActor );
937       }
938     }
939   }
940 }
941
942 void TextField::OnKeyInputFocusGained()
943 {
944   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyInputFocusGained %p\n", mController.Get() );
945
946   VirtualKeyboard::StatusChangedSignal().Connect( this, &TextField::KeyboardStatusChanged );
947
948   ImfManager imfManager = ImfManager::Get();
949
950   if ( imfManager )
951   {
952     imfManager.EventReceivedSignal().Connect( this, &TextField::OnImfEvent );
953
954     // Notify that the text editing start.
955     imfManager.Activate();
956
957     // When window gain lost focus, the imf manager is deactivated. Thus when window gain focus again, the imf manager must be activated.
958     imfManager.SetRestoreAfterFocusLost( true );
959   }
960
961   mController->KeyboardFocusGainEvent();
962
963   EmitKeyInputFocusSignal( true ); // Calls back into the Control hence done last.
964 }
965
966 void TextField::OnKeyInputFocusLost()
967 {
968   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField:OnKeyInputFocusLost %p\n", mController.Get() );
969
970   VirtualKeyboard::StatusChangedSignal().Disconnect( this, &TextField::KeyboardStatusChanged );
971
972   ImfManager imfManager = ImfManager::Get();
973   if ( imfManager )
974   {
975     // The text editing is finished. Therefore the imf manager don't have restore activation.
976     imfManager.SetRestoreAfterFocusLost( false );
977
978     // Notify that the text editing finish.
979     imfManager.Deactivate();
980
981     imfManager.EventReceivedSignal().Disconnect( this, &TextField::OnImfEvent );
982   }
983
984   mController->KeyboardFocusLostEvent();
985
986   EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last.
987 }
988
989 void TextField::OnTap( const TapGesture& gesture )
990 {
991   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get() );
992
993   // Show the keyboard if it was hidden.
994   if (!VirtualKeyboard::IsVisible())
995   {
996     VirtualKeyboard::Show();
997   }
998
999   // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
1000   mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x, gesture.localPoint.y );
1001
1002   SetKeyInputFocus();
1003 }
1004
1005 void TextField::OnPan( const PanGesture& gesture )
1006 {
1007   mController->PanEvent( gesture.state, gesture.displacement );
1008 }
1009
1010 bool TextField::OnKeyEvent( const KeyEvent& event )
1011 {
1012   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyEvent %p keyCode %d\n", mController.Get(), event.keyCode );
1013
1014   if( Dali::DALI_KEY_ESCAPE == event.keyCode ||
1015       "Return" == event.keyPressedName ) // Make a Dali key code for this
1016   {
1017     ClearKeyInputFocus();
1018     return true;
1019   }
1020
1021   return mController->KeyEvent( event );
1022 }
1023
1024 ImfManager::ImfCallbackData TextField::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
1025 {
1026   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName );
1027   return mController->OnImfEvent( imfManager, imfEvent );
1028 }
1029
1030 void TextField::RequestTextRelayout()
1031 {
1032   RelayoutRequest();
1033 }
1034
1035 void TextField::MaxLengthReached()
1036 {
1037   Dali::Toolkit::TextField handle( GetOwner() );
1038   mMaxLengthReachedSignal.Emit( handle );
1039 }
1040
1041 void TextField::EnableClipping( bool clipping, const Vector2& size )
1042 {
1043   if( clipping )
1044   {
1045     // Not worth to created clip actor if width or height is equal to zero.
1046     if( size.width > Math::MACHINE_EPSILON_1000 && size.height > Math::MACHINE_EPSILON_1000 )
1047     {
1048       if( !mClipper )
1049       {
1050         Actor self = Self();
1051
1052         mClipper = Clipper::New( size );
1053         self.Add( mClipper->GetRootActor() );
1054         self.Add( mClipper->GetImageActor() );
1055       }
1056       else if ( mClipper )
1057       {
1058         mClipper->Refresh( size );
1059       }
1060     }
1061   }
1062   else
1063   {
1064     // Note - this will automatically remove the root & image actors
1065     mClipper.Reset();
1066   }
1067 }
1068
1069 void TextField::KeyboardStatusChanged(bool keyboardShown)
1070 {
1071   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown );
1072
1073   // Just hide the grab handle when keyboard is hidden.
1074   if (!keyboardShown )
1075   {
1076     mController->KeyboardFocusLostEvent();
1077   }
1078 }
1079
1080 bool TextField::OnTouched( Actor actor, const TouchEvent& event )
1081 {
1082   return true;
1083 }
1084
1085 TextField::TextField()
1086 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
1087   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
1088   mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP )
1089 {
1090 }
1091
1092 TextField::~TextField()
1093 {
1094   mClipper.Reset();
1095 }
1096
1097 } // namespace Internal
1098
1099 } // namespace Toolkit
1100
1101 } // namespace Dali