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