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