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