Framework for Font styles
[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 <dali/public-api/adaptor-framework/key.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/images/resource-image.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/integration-api/debug.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/text/rendering-backend.h>
32 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
33 #include <dali-toolkit/internal/text/rendering/text-backend.h>
34 #include <dali-toolkit/internal/styling/style-manager-impl.h>
35
36 using namespace Dali::Toolkit::Text;
37
38 namespace Dali
39 {
40
41 namespace Toolkit
42 {
43
44 namespace Internal
45 {
46
47 namespace
48 {
49   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
50 }
51
52 namespace
53 {
54
55 // Type registration
56 BaseHandle Create()
57 {
58   return Toolkit::TextField::New();
59 }
60
61 // Setup properties, signals and actions using the type-registry.
62 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextField, Toolkit::Control, Create );
63
64 DALI_PROPERTY_REGISTRATION( TextField, "rendering-backend",       INTEGER,   RENDERING_BACKEND       )
65 DALI_PROPERTY_REGISTRATION( TextField, "placeholder-text",        STRING,    PLACEHOLDER_TEXT        )
66 DALI_PROPERTY_REGISTRATION( TextField, "text",                    STRING,    TEXT                    )
67 DALI_PROPERTY_REGISTRATION( TextField, "font-family",             STRING,    FONT_FAMILY             )
68 DALI_PROPERTY_REGISTRATION( TextField, "font-style",              STRING,    FONT_STYLE              )
69 DALI_PROPERTY_REGISTRATION( TextField, "point-size",              FLOAT,     POINT_SIZE              )
70 DALI_PROPERTY_REGISTRATION( TextField, "exceed-policy",           INTEGER,   EXCEED_POLICY           )
71 DALI_PROPERTY_REGISTRATION( TextField, "cursor-image",            STRING,    CURSOR_IMAGE            )
72 DALI_PROPERTY_REGISTRATION( TextField, "primary-cursor-color",    VECTOR4,   PRIMARY_CURSOR_COLOR    )
73 DALI_PROPERTY_REGISTRATION( TextField, "secondary-cursor-color",  VECTOR4,   SECONDARY_CURSOR_COLOR  )
74 DALI_PROPERTY_REGISTRATION( TextField, "enable-cursor-blink",     BOOLEAN,   ENABLE_CURSOR_BLINK     )
75 DALI_PROPERTY_REGISTRATION( TextField, "cursor-blink-interval",   FLOAT,     CURSOR_BLINK_INTERVAL   )
76 DALI_PROPERTY_REGISTRATION( TextField, "cursor-blink-duration",   FLOAT,     CURSOR_BLINK_DURATION   )
77 DALI_PROPERTY_REGISTRATION( TextField, "grab-handle-image",       STRING,    GRAB_HANDLE_IMAGE       )
78 DALI_PROPERTY_REGISTRATION( TextField, "decoration bounding-box", RECTANGLE, DECORATION_BOUNDING_BOX )
79
80 DALI_TYPE_REGISTRATION_END()
81
82 } // namespace
83
84 Toolkit::TextField TextField::New()
85 {
86   // Create the implementation, temporarily owned by this handle on stack
87   IntrusivePtr< TextField > impl = new TextField();
88
89   // Pass ownership to CustomActor handle
90   Toolkit::TextField handle( *impl );
91
92   // Second-phase init of the implementation
93   // This can only be done after the CustomActor connection has been made...
94   impl->Initialize();
95
96   return handle;
97 }
98
99 void TextField::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
100 {
101   Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
102
103   if( textField )
104   {
105     TextField& impl( GetImpl( textField ) );
106
107     switch( index )
108     {
109       case Toolkit::TextField::Property::RENDERING_BACKEND:
110       {
111         int backend = value.Get< int >();
112
113         if( impl.mRenderingBackend != backend )
114         {
115           impl.mRenderingBackend = backend;
116           impl.mRenderer.Reset();
117         }
118         break;
119       }
120       case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
121       {
122         if( impl.mController )
123         {
124           //impl.mController->SetPlaceholderText( value.Get< std::string >() ); TODO
125         }
126         break;
127       }
128       case Toolkit::TextField::Property::TEXT:
129       {
130         if( impl.mController )
131         {
132           impl.mController->SetText( value.Get< std::string >() );
133         }
134         break;
135       }
136       case Toolkit::TextField::Property::FONT_FAMILY:
137       {
138         if( impl.mController )
139         {
140           std::string fontFamily = value.Get< std::string >();
141
142           if( impl.mController->GetDefaultFontFamily() != fontFamily )
143           {
144             impl.mController->SetDefaultFontFamily( fontFamily );
145             impl.RequestTextRelayout();
146           }
147         }
148         break;
149       }
150       case Toolkit::TextField::Property::FONT_STYLE:
151       {
152         if( impl.mController )
153         {
154           std::string fontStyle = value.Get< std::string >();
155
156           if( impl.mController->GetDefaultFontStyle() != fontStyle )
157           {
158             impl.mController->SetDefaultFontStyle( fontStyle );
159             impl.RequestTextRelayout();
160           }
161         }
162         break;
163       }
164       case Toolkit::TextField::Property::POINT_SIZE:
165       {
166         if( impl.mController )
167         {
168           float pointSize = value.Get< float >();
169
170           if( impl.mController->GetDefaultPointSize() != pointSize /*TODO - epsilon*/ )
171           {
172             impl.mController->SetDefaultPointSize( pointSize );
173             impl.RequestTextRelayout();
174           }
175         }
176         break;
177       }
178       case Toolkit::TextField::Property::EXCEED_POLICY:
179       {
180         impl.mExceedPolicy = value.Get< int >();
181         break;
182       }
183       case Toolkit::TextField::Property::CURSOR_IMAGE:
184       {
185         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
186
187         if( impl.mDecorator )
188         {
189           impl.mDecorator->SetCursorImage( image );
190         }
191         break;
192       }
193       case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
194       {
195         if( impl.mDecorator )
196         {
197           impl.mDecorator->SetColor( PRIMARY_CURSOR, value.Get< Vector4 >() );
198         }
199         break;
200       }
201       case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
202       {
203         if( impl.mDecorator )
204         {
205           impl.mDecorator->SetColor( SECONDARY_CURSOR, value.Get< Vector4 >() );
206         }
207         break;
208       }
209       case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
210       {
211         if( impl.mController )
212         {
213           //impl.mController->SetEnableCursorBlink( value.Get< bool >() ); TODO
214         }
215         break;
216       }
217       case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
218       {
219         if( impl.mDecorator )
220         {
221           impl.mDecorator->SetCursorBlinkInterval( value.Get< float >() );
222         }
223         break;
224       }
225       case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
226       {
227         if( impl.mDecorator )
228         {
229           impl.mDecorator->SetCursorBlinkDuration( value.Get< float >() );
230         }
231         break;
232       }
233       case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
234       {
235         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
236
237         if( impl.mDecorator )
238         {
239           impl.mDecorator->SetGrabHandleImage( image );
240         }
241         break;
242       }
243       case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
244       {
245         if( impl.mDecorator )
246         {
247           impl.mDecorator->SetBoundingBox( value.Get< Rect<int> >() );
248         }
249         break;
250       }
251     }
252   }
253 }
254
255 Property::Value TextField::GetProperty( BaseObject* object, Property::Index index )
256 {
257   Property::Value value;
258
259   Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
260
261   if( textField )
262   {
263     TextField& impl( GetImpl( textField ) );
264
265     switch( index )
266     {
267       case Toolkit::TextField::Property::RENDERING_BACKEND:
268       {
269         value = impl.mRenderingBackend;
270         break;
271       }
272       case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
273       {
274         if( impl.mController )
275         {
276           std::string text;
277           impl.mController->GetPlaceholderText( text );
278           value = text;
279         }
280         break;
281       }
282       case Toolkit::TextField::Property::TEXT:
283       {
284         if( impl.mController )
285         {
286           std::string text;
287           impl.mController->GetText( text );
288           value = text;
289         }
290         break;
291       }
292       case Toolkit::TextField::Property::EXCEED_POLICY:
293       {
294         value = impl.mExceedPolicy;
295         break;
296       }
297       case Toolkit::TextField::Property::CURSOR_IMAGE:
298       {
299         if( impl.mDecorator )
300         {
301           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetCursorImage() );
302           if( image )
303           {
304             value = image.GetUrl();
305           }
306         }
307         break;
308       }
309       case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
310       {
311         if( impl.mDecorator )
312         {
313           value = impl.mDecorator->GetColor( PRIMARY_CURSOR );
314         }
315         break;
316       }
317       case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
318       {
319         if( impl.mDecorator )
320         {
321           value = impl.mDecorator->GetColor( SECONDARY_CURSOR );
322         }
323         break;
324       }
325       case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
326       {
327         //value = impl.mController->GetEnableCursorBlink(); TODO
328         break;
329       }
330       case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
331       {
332         if( impl.mDecorator )
333         {
334           value = impl.mDecorator->GetCursorBlinkInterval();
335         }
336         break;
337       }
338       case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
339       {
340         if( impl.mDecorator )
341         {
342           value = impl.mDecorator->GetCursorBlinkDuration();
343         }
344         break;
345       }
346       case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
347       {
348         if( impl.mDecorator )
349         {
350           ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetCursorImage() );
351           if( image )
352           {
353             value = image.GetUrl();
354           }
355         }
356         break;
357       }
358       case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
359       {
360         if( impl.mDecorator )
361         {
362           value = impl.mDecorator->GetBoundingBox();
363         }
364         break;
365       }
366     }
367   }
368
369   return value;
370 }
371
372 void TextField::OnInitialize()
373 {
374   mController = Text::Controller::New( *this );
375
376   mDecorator = Text::Decorator::New( *this, *mController );
377
378   mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
379
380   mController->EnableTextInput( mDecorator );
381
382   // Forward input events to controller
383   EnableGestureDetection(Gesture::Tap);
384   GetTapGestureDetector().SetMaximumTapsRequired( 2 );
385
386   // Set BoundingBox to stage size if not already set.
387   if ( mDecorator->GetBoundingBox().IsEmpty() )
388   {
389     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
390     mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
391   }
392 }
393
394 void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange change )
395 {
396   GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
397 }
398
399 Vector3 TextField::GetNaturalSize()
400 {
401   return mController->GetNaturalSize();
402 }
403
404 float TextField::GetHeightForWidth( float width )
405 {
406   return mController->GetHeightForWidth( width );
407 }
408
409 void TextField::OnRelayout( const Vector2& size, ActorSizeContainer& container )
410 {
411   if( mController->Relayout( size ) ||
412       !mRenderer )
413   {
414     if( mDecorator )
415     {
416       mDecorator->Relayout( size );
417     }
418
419     if( !mRenderer )
420     {
421       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
422     }
423
424     RenderableActor renderableActor;
425     if( mRenderer )
426     {
427       renderableActor = mRenderer->Render( mController->GetView() );
428     }
429
430     EnableClipping( (Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy), size );
431
432     if( renderableActor != mRenderableActor )
433     {
434       UnparentAndReset( mRenderableActor );
435       mRenderableActor = renderableActor;
436     }
437
438     if( mRenderableActor )
439     {
440       // Make sure the actor is parented correctly with/without clipping
441       if( mClipper )
442       {
443         mClipper->GetRootActor().Add( mRenderableActor );
444       }
445       else
446       {
447         Self().Add( mRenderableActor );
448       }
449     }
450   }
451 }
452
453 void TextField::OnTap( const TapGesture& gesture )
454 {
455   SetKeyInputFocus();
456
457   mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x, gesture.localPoint.y );
458 }
459
460 bool TextField::OnKeyEvent( const KeyEvent& event )
461 {
462   if( Dali::DALI_KEY_ESCAPE == event.keyCode )
463   {
464     ClearKeyInputFocus();
465   }
466
467   return mController->KeyEvent( event );
468 }
469
470 void TextField::RequestTextRelayout()
471 {
472   RelayoutRequest();
473 }
474
475 void TextField::EnableClipping( bool clipping, const Vector2& size )
476 {
477   if( clipping )
478   {
479     // Not worth to created clip actor if width or height is equal to zero.
480     if( size.width > Math::MACHINE_EPSILON_1000 && size.height > Math::MACHINE_EPSILON_1000 )
481     {
482       if( !mClipper )
483       {
484         Actor self = Self();
485
486         mClipper = Clipper::New( size );
487         self.Add( mClipper->GetRootActor() );
488         self.Add( mClipper->GetImageActor() );
489       }
490       else if ( mClipper )
491       {
492         mClipper->Refresh( size );
493       }
494     }
495   }
496   else
497   {
498     // Note - this will automatically remove the root & image actors
499     mClipper.Reset();
500   }
501 }
502
503 TextField::TextField()
504 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
505   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
506   mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP )
507 {
508 }
509
510 TextField::~TextField()
511 {
512   mClipper.Reset();
513 }
514
515 } // namespace Internal
516
517 } // namespace Toolkit
518
519 } // namespace Dali