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