419d1c472e34f1e805e5bb69e3856062b7c5ba25
[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/public-api/object/type-registry-helper.h>
24 #include <dali/public-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< Toolkit::Text::LayoutEngine::HorizontalAlignment > 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< Toolkit::Text::LayoutEngine::VerticalAlignment > 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( TextLabel, "rendering-backend",    INTEGER, RENDERING_BACKEND    )
79 DALI_PROPERTY_REGISTRATION( TextLabel, "text",                 STRING,  TEXT                 )
80 DALI_PROPERTY_REGISTRATION( TextLabel, "font-family",          STRING,  FONT_FAMILY          )
81 DALI_PROPERTY_REGISTRATION( TextLabel, "font-style",           STRING,  FONT_STYLE           )
82 DALI_PROPERTY_REGISTRATION( TextLabel, "point-size",           FLOAT,   POINT_SIZE           )
83 DALI_PROPERTY_REGISTRATION( TextLabel, "multi-line",           BOOLEAN, MULTI_LINE           )
84 DALI_PROPERTY_REGISTRATION( TextLabel, "horizontal-alignment", STRING,  HORIZONTAL_ALIGNMENT )
85 DALI_PROPERTY_REGISTRATION( TextLabel, "vertical-alignment",   STRING,  VERTICAL_ALIGNMENT   )
86 DALI_PROPERTY_REGISTRATION( TextLabel, "text-color",           VECTOR4, TEXT_COLOR           )
87 DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-offset",        VECTOR2, SHADOW_OFFSET        )
88 DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-color",         VECTOR4, SHADOW_COLOR         )
89 DALI_PROPERTY_REGISTRATION( TextLabel, "underline-enabled",    BOOLEAN, UNDERLINE_ENABLED    )
90 DALI_PROPERTY_REGISTRATION( TextLabel, "underline-color",      VECTOR4, UNDERLINE_COLOR      )
91 DALI_PROPERTY_REGISTRATION( TextLabel, "underline-height",     FLOAT,   UNDERLINE_HEIGHT       )
92 DALI_TYPE_REGISTRATION_END()
93
94 } // namespace
95
96 Toolkit::TextLabel TextLabel::New()
97 {
98   // Create the implementation, temporarily owned by this handle on stack
99   IntrusivePtr< TextLabel > impl = new TextLabel();
100
101   // Pass ownership to CustomActor handle
102   Toolkit::TextLabel handle( *impl );
103
104   // Second-phase init of the implementation
105   // This can only be done after the CustomActor connection has been made...
106   impl->Initialize();
107
108   return handle;
109 }
110
111 void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
112 {
113   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
114
115   if( label )
116   {
117     TextLabel& impl( GetImpl( label ) );
118     switch( index )
119     {
120       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
121       {
122         int backend = value.Get< int >();
123
124         if( impl.mRenderingBackend != backend )
125         {
126           impl.mRenderingBackend = backend;
127           impl.mRenderer.Reset();
128           impl.RequestTextRelayout();
129         }
130         break;
131       }
132       case Toolkit::TextLabel::Property::TEXT:
133       {
134         if( impl.mController )
135         {
136           impl.mController->SetText( value.Get< std::string >() );
137           impl.RequestTextRelayout();
138         }
139         break;
140       }
141       case Toolkit::TextLabel::Property::FONT_FAMILY:
142       {
143         if( impl.mController )
144         {
145           std::string fontFamily = value.Get< std::string >();
146
147           if( impl.mController->GetDefaultFontFamily() != fontFamily )
148           {
149             impl.mController->SetDefaultFontFamily( fontFamily );
150             impl.RequestTextRelayout();
151           }
152         }
153         break;
154       }
155       case Toolkit::TextLabel::Property::FONT_STYLE:
156       {
157         if( impl.mController )
158         {
159           std::string fontStyle = value.Get< std::string >();
160
161           if( impl.mController->GetDefaultFontStyle() != fontStyle )
162           {
163             impl.mController->SetDefaultFontStyle( fontStyle );
164             impl.RequestTextRelayout();
165           }
166         }
167         break;
168       }
169       case Toolkit::TextLabel::Property::POINT_SIZE:
170       {
171         if( impl.mController )
172         {
173           float pointSize = value.Get< float >();
174
175           if( fabsf(impl.mController->GetDefaultPointSize() - pointSize) > Math::MACHINE_EPSILON_1 )
176           {
177             impl.mController->SetDefaultPointSize( pointSize );
178             impl.RequestTextRelayout();
179           }
180         }
181         break;
182       }
183       case Toolkit::TextLabel::Property::MULTI_LINE:
184       {
185         if( impl.mController )
186         {
187           LayoutEngine& engine = impl.mController->GetLayoutEngine();
188           LayoutEngine::Layout layout = value.Get< bool >() ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
189
190           if( engine.GetLayout() != layout )
191           {
192             engine.SetLayout( layout );
193             impl.RequestTextRelayout();
194           }
195         }
196         break;
197       }
198       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
199       {
200         LayoutEngine& engine = impl.mController->GetLayoutEngine();
201         const LayoutEngine::HorizontalAlignment alignment = Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::HorizontalAlignment >( value.Get< std::string >().c_str(),
202                                                                                                                                            HORIZONTAL_ALIGNMENT_STRING_TABLE,
203                                                                                                                                            HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
204
205         if( engine.GetHorizontalAlignment() != alignment )
206         {
207           engine.SetHorizontalAlignment( alignment );
208           impl.RequestTextRelayout();
209         }
210         break;
211       }
212       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
213       {
214         LayoutEngine& engine = impl.mController->GetLayoutEngine();
215         const LayoutEngine::VerticalAlignment alignment = Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::VerticalAlignment >( value.Get< std::string >().c_str(),
216                                                                                                                                        VERTICAL_ALIGNMENT_STRING_TABLE,
217                                                                                                                                        VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
218
219         if( engine.GetVerticalAlignment() != alignment )
220         {
221           engine.SetVerticalAlignment( alignment );
222           impl.RequestTextRelayout();
223         }
224         break;
225       }
226
227       case Toolkit::TextLabel::Property::TEXT_COLOR:
228       {
229         if ( impl.mController )
230         {
231           Vector4 textColor = value.Get< Vector4 >();
232           if ( impl.mController->GetTextColor() != textColor )
233           {
234             impl.mController->SetTextColor( textColor );
235             impl.RequestTextRelayout();
236           }
237         }
238         break;
239       }
240
241       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
242       {
243         if( impl.mController )
244         {
245           Vector2 shadowOffset = value.Get< Vector2 >();
246           if ( impl.mController->GetShadowOffset() != shadowOffset )
247           {
248             impl.mController->SetShadowOffset( shadowOffset );
249             impl.RequestTextRelayout();
250           }
251         }
252         break;
253       }
254       case Toolkit::TextLabel::Property::SHADOW_COLOR:
255       {
256         if( impl.mController )
257         {
258           Vector4 shadowColor = value.Get< Vector4 >();
259           if ( impl.mController->GetShadowColor() != shadowColor )
260           {
261             impl.mController->SetShadowColor( shadowColor );
262             impl.RequestTextRelayout();
263           }
264         }
265         break;
266       }
267       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
268       {
269         if( impl.mController )
270         {
271           Vector4 color = value.Get< Vector4 >();
272           if ( impl.mController->GetUnderlineColor() != color )
273           {
274             impl.mController->SetUnderlineColor( color );
275             impl.RequestTextRelayout();
276           }
277         }
278         break;
279       }
280       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
281       {
282         if( impl.mController )
283         {
284           bool enabled = value.Get< bool >();
285           if ( impl.mController->IsUnderlineEnabled() != enabled )
286           {
287             impl.mController->SetUnderlineEnabled( enabled );
288             impl.RequestTextRelayout();
289           }
290         }
291         break;
292       }
293
294       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
295       {
296         if( impl.mController )
297         {
298           float height = value.Get< float >();
299           if ( impl.mController->GetUnderlineHeight() != height )
300           {
301             impl.mController->SetUnderlineHeight( height );
302             impl.RequestTextRelayout();
303           }
304         }
305         break;
306       }
307     }
308   }
309 }
310
311 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
312 {
313   Property::Value value;
314
315   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
316
317   if( label )
318   {
319     TextLabel& impl( GetImpl( label ) );
320     switch( index )
321     {
322       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
323       {
324         value = impl.mRenderingBackend;
325         break;
326       }
327       case Toolkit::TextLabel::Property::TEXT:
328       {
329         if( impl.mController )
330         {
331           std::string text;
332           impl.mController->GetText( text );
333           value = text;
334         }
335         break;
336       }
337       case Toolkit::TextLabel::Property::MULTI_LINE:
338       {
339         if( impl.mController )
340         {
341           value = static_cast<bool>( LayoutEngine::MULTI_LINE_BOX == impl.mController->GetLayoutEngine().GetLayout() );
342         }
343         break;
344       }
345       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
346       {
347         if( impl.mController )
348         {
349           value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetLayoutEngine().GetHorizontalAlignment(),
350                                                                                                                   HORIZONTAL_ALIGNMENT_STRING_TABLE,
351                                                                                                                   HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ) );
352         }
353         break;
354       }
355       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
356       {
357         if( impl.mController )
358         {
359           value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetLayoutEngine().GetVerticalAlignment(),
360                                                                                                                 VERTICAL_ALIGNMENT_STRING_TABLE,
361                                                                                                                 VERTICAL_ALIGNMENT_STRING_TABLE_COUNT ) );
362         }
363         break;
364       }
365       case Toolkit::TextLabel::Property::TEXT_COLOR:
366       {
367         if ( impl.mController )
368         {
369           value = impl.mController->GetTextColor();
370         }
371         break;
372       }
373       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
374       {
375         if ( impl.mController )
376         {
377           value = impl.mController->GetShadowOffset();
378         }
379         break;
380       }
381       case Toolkit::TextLabel::Property::SHADOW_COLOR:
382       {
383         if ( impl.mController )
384         {
385           value = impl.mController->GetShadowColor();
386         }
387         break;
388       }
389       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
390       {
391         if ( impl.mController )
392         {
393           value = impl.mController->GetUnderlineColor();
394         }
395         break;
396       }
397       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
398       {
399         if ( impl.mController )
400         {
401           value = impl.mController->IsUnderlineEnabled();
402         }
403         break;
404       }
405       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
406       {
407         if ( impl.mController )
408         {
409           value = impl.mController->GetUnderlineHeight();
410         }
411         break;
412       }
413     }
414   }
415
416   return value;
417 }
418
419 void TextLabel::OnInitialize()
420 {
421   Actor self = Self();
422
423   mController = Text::Controller::New( *this );
424
425   // Use height-for-width negotiation by default
426   self.SetResizePolicy( FILL_TO_PARENT, WIDTH );
427   self.SetResizePolicy( DIMENSION_DEPENDENCY, HEIGHT );
428 }
429
430 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange change )
431 {
432   GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
433 }
434
435 Vector3 TextLabel::GetNaturalSize()
436 {
437   return mController->GetNaturalSize();
438 }
439
440 float TextLabel::GetHeightForWidth( float width )
441 {
442   return mController->GetHeightForWidth( width );
443 }
444
445 void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
446 {
447   if( mController->Relayout( size ) ||
448       !mRenderer )
449   {
450     if( !mRenderer )
451     {
452       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
453     }
454
455     RenderableActor renderableActor;
456     if( mRenderer )
457     {
458       renderableActor = mRenderer->Render( mController->GetView() );
459     }
460
461     if( renderableActor != mRenderableActor )
462     {
463       UnparentAndReset( mRenderableActor );
464
465       if( renderableActor )
466       {
467         const Vector2& alignmentOffset = mController->GetAlignmentOffset();
468         renderableActor.SetPosition( alignmentOffset.x, alignmentOffset.y );
469
470         Self().Add( renderableActor );
471       }
472
473       mRenderableActor = renderableActor;
474     }
475   }
476 }
477
478 void TextLabel::RequestTextRelayout()
479 {
480   RelayoutRequest();
481 }
482
483 TextLabel::TextLabel()
484 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
485   mRenderingBackend( DEFAULT_RENDERING_BACKEND )
486 {
487 }
488
489 TextLabel::~TextLabel()
490 {
491 }
492
493 } // namespace Internal
494
495 } // namespace Toolkit
496
497 } // namespace Dali