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