153b34ce3db70006893b1fcecd3a8856e84eb996
[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           DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str() );
151           impl.mController->SetDefaultFontFamily( fontFamily );
152         }
153         break;
154       }
155       case Toolkit::TextLabel::Property::FONT_STYLE:
156       {
157         SetFontStyleProperty( impl.mController, value );
158         break;
159       }
160       case Toolkit::TextLabel::Property::POINT_SIZE:
161       {
162         if( impl.mController )
163         {
164           const float pointSize = value.Get< float >();
165
166           if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) )
167           {
168             impl.mController->SetDefaultPointSize( pointSize );
169           }
170         }
171         break;
172       }
173       case Toolkit::TextLabel::Property::MULTI_LINE:
174       {
175         if( impl.mController )
176         {
177           impl.mController->SetMultiLineEnabled( value.Get< bool >() );
178         }
179         break;
180       }
181       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
182       {
183         if( impl.mController )
184         {
185           LayoutEngine::HorizontalAlignment alignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN );
186           if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::HorizontalAlignment >( value.Get< std::string >().c_str(),
187                                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE,
188                                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
189                                                                                              alignment ) )
190           {
191             impl.mController->SetHorizontalAlignment( alignment );
192           }
193         }
194         break;
195       }
196       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
197       {
198         if( impl.mController )
199         {
200           LayoutEngine::VerticalAlignment alignment( LayoutEngine::VERTICAL_ALIGN_BOTTOM );
201           if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::VerticalAlignment >( value.Get< std::string >().c_str(),
202                                                                                            VERTICAL_ALIGNMENT_STRING_TABLE,
203                                                                                            VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
204                                                                                            alignment ) )
205           {
206             impl.mController->SetVerticalAlignment( alignment );
207           }
208         }
209         break;
210       }
211
212       case Toolkit::TextLabel::Property::TEXT_COLOR:
213       {
214         if( impl.mController )
215         {
216           const Vector4 textColor = value.Get< Vector4 >();
217           if( impl.mController->GetTextColor() != textColor )
218           {
219             impl.mController->SetTextColor( textColor );
220             impl.mRenderer.Reset();
221           }
222         }
223         break;
224       }
225
226       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
227       {
228         if( impl.mController )
229         {
230           const Vector2 shadowOffset = value.Get< Vector2 >();
231           if ( impl.mController->GetShadowOffset() != shadowOffset )
232           {
233             impl.mController->SetShadowOffset( shadowOffset );
234             impl.mRenderer.Reset();
235           }
236         }
237         break;
238       }
239       case Toolkit::TextLabel::Property::SHADOW_COLOR:
240       {
241         if( impl.mController )
242         {
243           const Vector4 shadowColor = value.Get< Vector4 >();
244           if ( impl.mController->GetShadowColor() != shadowColor )
245           {
246             impl.mController->SetShadowColor( shadowColor );
247             impl.mRenderer.Reset();
248           }
249         }
250         break;
251       }
252       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
253       {
254         if( impl.mController )
255         {
256           const Vector4 color = value.Get< Vector4 >();
257           if ( impl.mController->GetUnderlineColor() != color )
258           {
259             impl.mController->SetUnderlineColor( color );
260             impl.mRenderer.Reset();
261           }
262         }
263         break;
264       }
265       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
266       {
267         if( impl.mController )
268         {
269           const bool enabled = value.Get< bool >();
270           if ( impl.mController->IsUnderlineEnabled() != enabled )
271           {
272             impl.mController->SetUnderlineEnabled( enabled );
273             impl.mRenderer.Reset();
274           }
275         }
276         break;
277       }
278
279       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
280       {
281         if( impl.mController )
282         {
283           float height = value.Get< float >();
284           if ( impl.mController->GetUnderlineHeight() != height )
285           {
286             impl.mController->SetUnderlineHeight( height );
287             impl.mRenderer.Reset();
288           }
289         }
290         break;
291       }
292     }
293   }
294 }
295
296 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
297 {
298   Property::Value value;
299
300   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
301
302   if( label )
303   {
304     TextLabel& impl( GetImpl( label ) );
305     switch( index )
306     {
307       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
308       {
309         value = impl.mRenderingBackend;
310         break;
311       }
312       case Toolkit::TextLabel::Property::TEXT:
313       {
314         if( impl.mController )
315         {
316           std::string text;
317           impl.mController->GetText( text );
318           value = text;
319         }
320         break;
321       }
322       case Toolkit::TextLabel::Property::FONT_FAMILY:
323       {
324         if( impl.mController )
325         {
326           value = impl.mController->GetDefaultFontFamily();
327         }
328         break;
329       }
330       case Toolkit::TextLabel::Property::FONT_STYLE:
331       {
332         GetFontStyleProperty( impl.mController, value );
333         break;
334       }
335       case Toolkit::TextLabel::Property::POINT_SIZE:
336       {
337         if( impl.mController )
338         {
339           value = impl.mController->GetDefaultPointSize();
340         }
341         break;
342       }
343       case Toolkit::TextLabel::Property::MULTI_LINE:
344       {
345         if( impl.mController )
346         {
347           value = impl.mController->IsMultiLineEnabled();
348         }
349         break;
350       }
351       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
352       {
353         if( impl.mController )
354         {
355           const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(),
356                                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE,
357                                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
358           if( name )
359           {
360             value = std::string( name );
361           }
362         }
363         break;
364       }
365       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
366       {
367         if( impl.mController )
368         {
369           const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
370                                                                                                               VERTICAL_ALIGNMENT_STRING_TABLE,
371                                                                                                               VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
372           if( name )
373           {
374             value = std::string( name );
375           }
376         }
377         break;
378       }
379       case Toolkit::TextLabel::Property::TEXT_COLOR:
380       {
381         if ( impl.mController )
382         {
383           value = impl.mController->GetTextColor();
384         }
385         break;
386       }
387       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
388       {
389         if ( impl.mController )
390         {
391           value = impl.mController->GetShadowOffset();
392         }
393         break;
394       }
395       case Toolkit::TextLabel::Property::SHADOW_COLOR:
396       {
397         if ( impl.mController )
398         {
399           value = impl.mController->GetShadowColor();
400         }
401         break;
402       }
403       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
404       {
405         if ( impl.mController )
406         {
407           value = impl.mController->GetUnderlineColor();
408         }
409         break;
410       }
411       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
412       {
413         if ( impl.mController )
414         {
415           value = impl.mController->IsUnderlineEnabled();
416         }
417         break;
418       }
419       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
420       {
421         if ( impl.mController )
422         {
423           value = impl.mController->GetUnderlineHeight();
424         }
425         break;
426       }
427     }
428   }
429
430   return value;
431 }
432
433 void TextLabel::OnInitialize()
434 {
435   Actor self = Self();
436
437   mController = Text::Controller::New( *this );
438
439   // Use height-for-width negotiation by default
440   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
441   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
442
443   // Enable the text ellipsis.
444   LayoutEngine& engine = mController->GetLayoutEngine();
445   engine.SetTextEllipsisEnabled( true );
446   self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect );
447 }
448
449 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
450 {
451
452   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
453
454   switch ( change )
455   {
456     case StyleChange::DEFAULT_FONT_CHANGE:
457     {
458       // Property system did not set the font so should update it.
459       std::string newFont = styleManager.GetDefaultFontFamily();
460       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str() );
461       mController->UpdateAfterFontChange( newFont );
462       break;
463     }
464
465     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
466     {
467       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() );
468
469       if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f
470       {
471         // Property system did not set the PointSize so should update it.
472         // todo instruct text-controller to update model
473       }
474       break;
475     }
476     case StyleChange::THEME_CHANGE:
477     {
478       GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
479       break;
480     }
481   }
482 }
483
484 Vector3 TextLabel::GetNaturalSize()
485 {
486   return mController->GetNaturalSize();
487 }
488
489 float TextLabel::GetHeightForWidth( float width )
490 {
491   return mController->GetHeightForWidth( width );
492 }
493
494 void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
495 {
496   if( mController->Relayout( size ) ||
497       !mRenderer )
498   {
499     if( !mRenderer )
500     {
501       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
502     }
503     RenderText();
504   }
505 }
506
507 void TextLabel::RequestTextRelayout()
508 {
509   RelayoutRequest();
510 }
511
512 void TextLabel::RenderText()
513 {
514   Actor self = Self();
515   Actor renderableActor;
516   if( mRenderer )
517   {
518     renderableActor = mRenderer->Render( mController->GetView(), self.GetHierarchyDepth() );
519   }
520
521   if( renderableActor != mRenderableActor )
522   {
523     UnparentAndReset( mRenderableActor );
524
525     if( renderableActor )
526     {
527       const Vector2& alignmentOffset = mController->GetAlignmentOffset();
528       renderableActor.SetPosition( alignmentOffset.x, alignmentOffset.y );
529
530       self.Add( renderableActor );
531     }
532     mRenderableActor = renderableActor;
533   }
534 }
535
536 void TextLabel::OnStageConnect( Dali::Actor actor )
537 {
538   if ( mHasBeenStaged )
539   {
540     RenderText();
541   }
542   else
543   {
544     mHasBeenStaged = true;
545   }
546 }
547
548 void TextLabel::AddDecoration( Actor& actor, bool needsClipping )
549 {
550   // TextLabel does not show decorations
551 }
552
553 void TextLabel::OnStageConnection( int depth )
554 {
555   // Call the Control::OnStageConnection() to set the depth of the background.
556   Control::OnStageConnection( depth );
557
558   // The depth of the text renderer is set in the RenderText() called from OnRelayout().
559 }
560
561 void TextLabel::TextChanged()
562 {
563   // TextLabel does not provide a signal for this
564 }
565
566 void TextLabel::MaxLengthReached()
567 {
568   // Pure Virtual from TextController Interface, only needed when inputting text
569 }
570
571 TextLabel::TextLabel()
572 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
573   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
574   mHasBeenStaged( false )
575 {
576 }
577
578 TextLabel::~TextLabel()
579 {
580 }
581
582 } // namespace Internal
583
584 } // namespace Toolkit
585
586 } // namespace Dali