Merge "Added GetReadPosition to AccessibilityManager API" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-label-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-label-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/devel-api/object/type-registry-helper.h>
24 #include <dali/devel-api/scripting/scripting.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/public-api/text/rendering-backend.h>
29 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
30 #include <dali-toolkit/internal/text/rendering/text-backend.h>
31 #include <dali-toolkit/internal/styling/style-manager-impl.h>
32
33 using Dali::Toolkit::Text::LayoutEngine;
34 using Dali::Toolkit::Text::Backend;
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace
46 {
47   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
48 }
49
50 namespace
51 {
52
53 const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
54 {
55   { "BEGIN",  Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_BEGIN  },
56   { "CENTER", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_CENTER },
57   { "END",    Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_END    },
58 };
59 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
60
61 const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
62 {
63   { "TOP",    Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_TOP    },
64   { "CENTER", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_CENTER },
65   { "BOTTOM", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_BOTTOM },
66 };
67 const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( VERTICAL_ALIGNMENT_STRING_TABLE ) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
68
69 // Type registration
70 BaseHandle Create()
71 {
72   return Toolkit::TextLabel::New();
73 }
74
75 // Setup properties, signals and actions using the type-registry.
76 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create );
77
78 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "rendering-backend",    INTEGER, RENDERING_BACKEND    )
79 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "text",                 STRING,  TEXT                 )
80 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "font-family",          STRING,  FONT_FAMILY          )
81 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "font-style",           STRING,  FONT_STYLE           )
82 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "point-size",           FLOAT,   POINT_SIZE           )
83 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "multi-line",           BOOLEAN, MULTI_LINE           )
84 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "horizontal-alignment", STRING,  HORIZONTAL_ALIGNMENT )
85 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "vertical-alignment",   STRING,  VERTICAL_ALIGNMENT   )
86 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "text-color",           VECTOR4, TEXT_COLOR           )
87 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadow-offset",        VECTOR2, SHADOW_OFFSET        )
88 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadow-color",         VECTOR4, SHADOW_COLOR         )
89 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underline-enabled",    BOOLEAN, UNDERLINE_ENABLED    )
90 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underline-color",      VECTOR4, UNDERLINE_COLOR      )
91 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underline-height",     FLOAT,   UNDERLINE_HEIGHT     )
92
93 DALI_TYPE_REGISTRATION_END()
94
95 } // namespace
96
97 Toolkit::TextLabel TextLabel::New()
98 {
99   // Create the implementation, temporarily owned by this handle on stack
100   IntrusivePtr< TextLabel > impl = new TextLabel();
101
102   // Pass ownership to CustomActor handle
103   Toolkit::TextLabel handle( *impl );
104
105   // Second-phase init of the implementation
106   // This can only be done after the CustomActor connection has been made...
107   impl->Initialize();
108
109   return handle;
110 }
111
112 void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
113 {
114   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
115
116   if( label )
117   {
118     TextLabel& impl( GetImpl( label ) );
119     switch( index )
120     {
121       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
122       {
123         const int backend = value.Get< int >();
124
125         if( impl.mRenderingBackend != backend )
126         {
127           impl.mRenderingBackend = backend;
128           impl.mRenderer.Reset();
129           impl.RequestTextRelayout();
130         }
131         break;
132       }
133       case Toolkit::TextLabel::Property::TEXT:
134       {
135         if( impl.mController )
136         {
137           impl.mController->SetText( value.Get< std::string >() );
138         }
139         break;
140       }
141       case Toolkit::TextLabel::Property::FONT_FAMILY:
142       {
143         if( impl.mController )
144         {
145           const std::string fontFamily = value.Get< std::string >();
146
147           if( impl.mController->GetDefaultFontFamily() != fontFamily )
148           {
149             impl.mController->SetDefaultFontFamily( fontFamily );
150           }
151         }
152         break;
153       }
154       case Toolkit::TextLabel::Property::FONT_STYLE:
155       {
156         if( impl.mController )
157         {
158           const std::string fontStyle = value.Get< std::string >();
159
160           if( impl.mController->GetDefaultFontStyle() != fontStyle )
161           {
162             impl.mController->SetDefaultFontStyle( fontStyle );
163           }
164         }
165         break;
166       }
167       case Toolkit::TextLabel::Property::POINT_SIZE:
168       {
169         if( impl.mController )
170         {
171           const float pointSize = value.Get< float >();
172
173           if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) )
174           {
175             impl.mController->SetDefaultPointSize( pointSize );
176           }
177         }
178         break;
179       }
180       case Toolkit::TextLabel::Property::MULTI_LINE:
181       {
182         if( impl.mController )
183         {
184           impl.mController->SetMultiLineEnabled( value.Get< bool >() );
185         }
186         break;
187       }
188       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
189       {
190         if( impl.mController )
191         {
192           LayoutEngine::HorizontalAlignment alignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN );
193           if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::HorizontalAlignment >( value.Get< std::string >().c_str(),
194                                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE,
195                                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
196                                                                                              alignment ) )
197           {
198             impl.mController->SetHorizontalAlignment( alignment );
199           }
200         }
201         break;
202       }
203       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
204       {
205         if( impl.mController )
206         {
207           LayoutEngine::VerticalAlignment alignment( LayoutEngine::VERTICAL_ALIGN_BOTTOM );
208           if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::VerticalAlignment >( value.Get< std::string >().c_str(),
209                                                                                            VERTICAL_ALIGNMENT_STRING_TABLE,
210                                                                                            VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
211                                                                                            alignment ) )
212           {
213             impl.mController->SetVerticalAlignment( alignment );
214           }
215         }
216         break;
217       }
218
219       case Toolkit::TextLabel::Property::TEXT_COLOR:
220       {
221         if( impl.mController )
222         {
223           const Vector4 textColor = value.Get< Vector4 >();
224           if( impl.mController->GetTextColor() != textColor )
225           {
226             impl.mController->SetTextColor( textColor );
227             impl.mRenderer.Reset();
228           }
229         }
230         break;
231       }
232
233       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
234       {
235         if( impl.mController )
236         {
237           const Vector2 shadowOffset = value.Get< Vector2 >();
238           if ( impl.mController->GetShadowOffset() != shadowOffset )
239           {
240             impl.mController->SetShadowOffset( shadowOffset );
241             impl.mRenderer.Reset();
242           }
243         }
244         break;
245       }
246       case Toolkit::TextLabel::Property::SHADOW_COLOR:
247       {
248         if( impl.mController )
249         {
250           const Vector4 shadowColor = value.Get< Vector4 >();
251           if ( impl.mController->GetShadowColor() != shadowColor )
252           {
253             impl.mController->SetShadowColor( shadowColor );
254             impl.mRenderer.Reset();
255           }
256         }
257         break;
258       }
259       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
260       {
261         if( impl.mController )
262         {
263           const Vector4 color = value.Get< Vector4 >();
264           if ( impl.mController->GetUnderlineColor() != color )
265           {
266             impl.mController->SetUnderlineColor( color );
267             impl.mRenderer.Reset();
268           }
269         }
270         break;
271       }
272       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
273       {
274         if( impl.mController )
275         {
276           const bool enabled = value.Get< bool >();
277           if ( impl.mController->IsUnderlineEnabled() != enabled )
278           {
279             impl.mController->SetUnderlineEnabled( enabled );
280             impl.mRenderer.Reset();
281           }
282         }
283         break;
284       }
285
286       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
287       {
288         if( impl.mController )
289         {
290           float height = value.Get< float >();
291           if ( impl.mController->GetUnderlineHeight() != height )
292           {
293             impl.mController->SetUnderlineHeight( height );
294             impl.mRenderer.Reset();
295           }
296         }
297         break;
298       }
299     }
300   }
301 }
302
303 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
304 {
305   Property::Value value;
306
307   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
308
309   if( label )
310   {
311     TextLabel& impl( GetImpl( label ) );
312     switch( index )
313     {
314       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
315       {
316         value = impl.mRenderingBackend;
317         break;
318       }
319       case Toolkit::TextLabel::Property::TEXT:
320       {
321         if( impl.mController )
322         {
323           std::string text;
324           impl.mController->GetText( text );
325           value = text;
326         }
327         break;
328       }
329       case Toolkit::TextLabel::Property::FONT_FAMILY:
330       {
331         if( impl.mController )
332         {
333           value = impl.mController->GetDefaultFontFamily();
334         }
335         break;
336       }
337       case Toolkit::TextLabel::Property::FONT_STYLE:
338       {
339         if( impl.mController )
340         {
341           value = impl.mController->GetDefaultFontStyle();
342         }
343         break;
344       }
345       case Toolkit::TextLabel::Property::POINT_SIZE:
346       {
347         if( impl.mController )
348         {
349           value = impl.mController->GetDefaultPointSize();
350         }
351         break;
352       }
353       case Toolkit::TextLabel::Property::MULTI_LINE:
354       {
355         if( impl.mController )
356         {
357           value = impl.mController->IsMultiLineEnabled();
358         }
359         break;
360       }
361       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
362       {
363         if( impl.mController )
364         {
365           const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(),
366                                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE,
367                                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
368           if( name )
369           {
370             value = std::string( name );
371           }
372         }
373         break;
374       }
375       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
376       {
377         if( impl.mController )
378         {
379           const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
380                                                                                                               VERTICAL_ALIGNMENT_STRING_TABLE,
381                                                                                                               VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
382           if( name )
383           {
384             value = std::string( name );
385           }
386         }
387         break;
388       }
389       case Toolkit::TextLabel::Property::TEXT_COLOR:
390       {
391         if ( impl.mController )
392         {
393           value = impl.mController->GetTextColor();
394         }
395         break;
396       }
397       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
398       {
399         if ( impl.mController )
400         {
401           value = impl.mController->GetShadowOffset();
402         }
403         break;
404       }
405       case Toolkit::TextLabel::Property::SHADOW_COLOR:
406       {
407         if ( impl.mController )
408         {
409           value = impl.mController->GetShadowColor();
410         }
411         break;
412       }
413       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
414       {
415         if ( impl.mController )
416         {
417           value = impl.mController->GetUnderlineColor();
418         }
419         break;
420       }
421       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
422       {
423         if ( impl.mController )
424         {
425           value = impl.mController->IsUnderlineEnabled();
426         }
427         break;
428       }
429       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
430       {
431         if ( impl.mController )
432         {
433           value = impl.mController->GetUnderlineHeight();
434         }
435         break;
436       }
437     }
438   }
439
440   return value;
441 }
442
443 void TextLabel::OnInitialize()
444 {
445   Actor self = Self();
446
447   mController = Text::Controller::New( *this );
448
449   // Use height-for-width negotiation by default
450   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
451   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
452
453   // Enable the text ellipsis.
454   LayoutEngine& engine = mController->GetLayoutEngine();
455   engine.SetTextEllipsisEnabled( true );
456   self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect );
457 }
458
459 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
460 {
461   GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
462 }
463
464 Vector3 TextLabel::GetNaturalSize()
465 {
466   return mController->GetNaturalSize();
467 }
468
469 float TextLabel::GetHeightForWidth( float width )
470 {
471   return mController->GetHeightForWidth( width );
472 }
473
474 void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
475 {
476   if( mController->Relayout( size ) ||
477       !mRenderer )
478   {
479     if( !mRenderer )
480     {
481       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
482     }
483     RenderText();
484   }
485 }
486
487 void TextLabel::RequestTextRelayout()
488 {
489   RelayoutRequest();
490 }
491
492 void TextLabel::RenderText()
493 {
494   Actor renderableActor;
495   if( mRenderer )
496   {
497     renderableActor = mRenderer->Render( mController->GetView(), mDepth );
498   }
499
500   if( renderableActor != mRenderableActor )
501   {
502     UnparentAndReset( mRenderableActor );
503
504     if( renderableActor )
505     {
506       const Vector2& alignmentOffset = mController->GetAlignmentOffset();
507       renderableActor.SetPosition( alignmentOffset.x, alignmentOffset.y );
508
509       Self().Add( renderableActor );
510     }
511     mRenderableActor = renderableActor;
512   }
513 }
514
515 void TextLabel::OnStageConnect( Dali::Actor actor )
516 {
517   if ( mHasBeenStaged )
518   {
519     RenderText();
520   }
521   else
522   {
523     mHasBeenStaged = true;
524   }
525 }
526
527 void TextLabel::AddDecoration( Actor& actor, bool needsClipping )
528 {
529   // TextLabel does not show decorations
530 }
531
532 void TextLabel::OnStageConnection( int depth )
533 {
534   mDepth = depth;
535 }
536
537 void TextLabel::TextChanged()
538 {
539   // TextLabel does not provide a signal for this
540 }
541
542 void TextLabel::MaxLengthReached()
543 {
544   // Pure Virtual from TextController Interface, only needed when inputting text
545 }
546
547 TextLabel::TextLabel()
548 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
549   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
550   mDepth( 0 ),
551   mHasBeenStaged( false )
552 {
553 }
554
555 TextLabel::~TextLabel()
556 {
557 }
558
559 } // namespace Internal
560
561 } // namespace Toolkit
562
563 } // namespace Dali