0cbb799e0ff49f06bfbe1819b61d5a67b3fbac75
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-label-impl.cpp
1 /*
2  * Copyright (c) 2017 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-helper.h>
23 #include <dali/devel-api/object/property-helper-devel.h>
24 #include <dali/devel-api/adaptor-framework/image-loading.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/public-api/text/text-enumerations.h>
30 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
31 #include <dali-toolkit/internal/text/property-string-parser.h>
32 #include <dali-toolkit/internal/text/rendering/text-backend.h>
33 #include <dali-toolkit/internal/text/text-effects-style.h>
34 #include <dali-toolkit/internal/text/text-font-style.h>
35 #include <dali-toolkit/internal/text/text-view.h>
36 #include <dali-toolkit/internal/text/text-definitions.h>
37 #include <dali-toolkit/internal/styling/style-manager-impl.h>
38
39 #include <dali-toolkit/public-api/align-enumerations.h>
40 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
41 #include <dali-toolkit/devel-api/controls/control-devel.h>
42 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
43 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
44 #include <dali-toolkit/public-api/visuals/visual-properties.h>
45 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
46
47 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
48
49 using namespace Dali::Toolkit::Text;
50
51 namespace Dali
52 {
53
54 namespace Toolkit
55 {
56
57 namespace Internal
58 {
59
60 namespace
61 {
62   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
63 }
64
65 namespace
66 {
67
68 #if defined ( DEBUG_ENABLED )
69   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
70 #endif
71
72 const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
73 {
74   { "IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE },
75   { "FINISH_LOOP",  Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP  },
76 };
77 const unsigned int AUTO_SCROLL_STOP_MODE_TABLE_COUNT = sizeof( AUTO_SCROLL_STOP_MODE_TABLE ) / sizeof( AUTO_SCROLL_STOP_MODE_TABLE[0] );
78
79 // Type registration
80 BaseHandle Create()
81 {
82   return Toolkit::TextLabel::New();
83 }
84
85 // Setup properties, signals and actions using the type-registry.
86 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create );
87
88 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "renderingBackend",          INTEGER, RENDERING_BACKEND          )
89 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "text",                      STRING,  TEXT                       )
90 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "fontFamily",                STRING,  FONT_FAMILY                )
91 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "fontStyle",                 MAP,     FONT_STYLE                 )
92 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "pointSize",                 FLOAT,   POINT_SIZE                 )
93 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "multiLine",                 BOOLEAN, MULTI_LINE                 )
94 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "horizontalAlignment",       STRING,  HORIZONTAL_ALIGNMENT       )
95 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "verticalAlignment",         STRING,  VERTICAL_ALIGNMENT         )
96 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "unusedPropertyTextColor",   VECTOR4, UNUSED_PROPERTY_TEXT_COLOR )
97 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "shadowOffset",              VECTOR2, SHADOW_OFFSET              )
98 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "shadowColor",               VECTOR4, SHADOW_COLOR               )
99 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "underlineEnabled",          BOOLEAN, UNDERLINE_ENABLED          )
100 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "underlineColor",            VECTOR4, UNDERLINE_COLOR            )
101 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "underlineHeight",           FLOAT,   UNDERLINE_HEIGHT           )
102 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "enableMarkup",              BOOLEAN, ENABLE_MARKUP              )
103 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "enableAutoScroll",          BOOLEAN, ENABLE_AUTO_SCROLL         )
104 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollSpeed",           INTEGER, AUTO_SCROLL_SPEED          )
105 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollLoopCount",       INTEGER, AUTO_SCROLL_LOOP_COUNT     )
106 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollGap",             FLOAT,   AUTO_SCROLL_GAP            )
107 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "lineSpacing",               FLOAT,   LINE_SPACING               )
108 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "underline",                 MAP,     UNDERLINE                  )
109 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "shadow",                    MAP,     SHADOW                     )
110 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "emboss",                    MAP,     EMBOSS                     )
111 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "outline",                   MAP,     OUTLINE                    )
112 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "pixelSize",                 FLOAT,   PIXEL_SIZE                 )
113 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "ellipsis",                  BOOLEAN, ELLIPSIS                   )
114 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollLoopDelay",       FLOAT,   AUTO_SCROLL_LOOP_DELAY     )
115 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollStopMode",        STRING,  AUTO_SCROLL_STOP_MODE      )
116 DALI_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "lineCount",                 INTEGER, LINE_COUNT                 )
117 DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "lineWrapMode",              INTEGER, LINE_WRAP_MODE             )
118 DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "textDirection",       INTEGER, TEXT_DIRECTION             )
119 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "verticalLineAlignment",         INTEGER, VERTICAL_LINE_ALIGNMENT    )
120 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColor",      Color::BLACK,     TEXT_COLOR     )
121 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR, 0  )
122 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1  )
123 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorBlue",  TEXT_COLOR_BLUE,  TEXT_COLOR, 2  )
124 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR, 3  )
125 DALI_TYPE_REGISTRATION_END()
126
127 } // namespace
128
129 Toolkit::TextLabel TextLabel::New()
130 {
131   // Create the implementation, temporarily owned by this handle on stack
132   IntrusivePtr< TextLabel > impl = new TextLabel();
133
134   // Pass ownership to CustomActor handle
135   Toolkit::TextLabel handle( *impl );
136
137   // Second-phase init of the implementation
138   // This can only be done after the CustomActor connection has been made...
139   impl->Initialize();
140
141   return handle;
142 }
143
144 void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
145 {
146   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
147
148   if( label )
149   {
150     TextLabel& impl( GetImpl( label ) );
151     switch( index )
152     {
153       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
154       {
155         DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
156
157         int backend = value.Get< int >();
158
159 #ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
160         if( Text::RENDERING_VECTOR_BASED == backend )
161         {
162           backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
163         }
164 #endif
165         if( impl.mRenderingBackend != backend )
166         {
167           impl.mRenderingBackend = backend;
168           impl.mTextUpdateNeeded = true;
169
170           if( impl.mController )
171           {
172             // When using the vector-based rendering, the size of the GLyphs are different
173             TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
174             impl.mController->SetGlyphType( glyphType );
175           }
176         }
177         break;
178       }
179       case Toolkit::TextLabel::Property::TEXT:
180       {
181         if( impl.mController )
182         {
183           impl.mController->SetText( value.Get< std::string >() );
184         }
185         break;
186       }
187       case Toolkit::TextLabel::Property::FONT_FAMILY:
188       {
189         if( impl.mController )
190         {
191           const std::string& fontFamily = value.Get< std::string >();
192
193           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str() );
194           impl.mController->SetDefaultFontFamily( fontFamily );
195         }
196         break;
197       }
198       case Toolkit::TextLabel::Property::FONT_STYLE:
199       {
200         SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
201         break;
202       }
203       case Toolkit::TextLabel::Property::POINT_SIZE:
204       {
205         if( impl.mController )
206         {
207           const float pointSize = value.Get< float >();
208
209           if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
210           {
211             impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
212           }
213         }
214         break;
215       }
216       case Toolkit::TextLabel::Property::MULTI_LINE:
217       {
218         if( impl.mController )
219         {
220           impl.mController->SetMultiLineEnabled( value.Get< bool >() );
221         }
222         break;
223       }
224       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
225       {
226         if( impl.mController )
227         {
228           Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
229           if( Text::GetHorizontalAlignmentEnumeration( value, alignment ) )
230           {
231             impl.mController->SetHorizontalAlignment( alignment );
232           }
233         }
234         break;
235       }
236       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
237       {
238         if( impl.mController )
239         {
240           Toolkit::Text::VerticalAlignment::Type alignment( static_cast< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
241           if( Text::GetVerticalAlignmentEnumeration( value, alignment ) )
242           {
243             impl.mController->SetVerticalAlignment( alignment );
244           }
245         }
246         break;
247       }
248
249       case Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR:
250       {
251         label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, value );
252         impl.mTextUpdateNeeded = true;
253         break;
254       }
255
256       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
257       {
258         if( impl.mController )
259         {
260           const Vector2& shadowOffset = value.Get< Vector2 >();
261           if ( impl.mController->GetShadowOffset() != shadowOffset )
262           {
263             impl.mController->SetShadowOffset( shadowOffset );
264             impl.mTextUpdateNeeded = true;
265           }
266         }
267         break;
268       }
269       case Toolkit::TextLabel::Property::SHADOW_COLOR:
270       {
271         if( impl.mController )
272         {
273           const Vector4& shadowColor = value.Get< Vector4 >();
274           if ( impl.mController->GetShadowColor() != shadowColor )
275           {
276             impl.mController->SetShadowColor( shadowColor );
277             impl.mTextUpdateNeeded = true;
278           }
279         }
280         break;
281       }
282       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
283       {
284         if( impl.mController )
285         {
286           const Vector4& color = value.Get< Vector4 >();
287           if ( impl.mController->GetUnderlineColor() != color )
288           {
289             impl.mController->SetUnderlineColor( color );
290             impl.mTextUpdateNeeded = true;
291           }
292         }
293         break;
294       }
295       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
296       {
297         if( impl.mController )
298         {
299           const bool enabled = value.Get< bool >();
300           if ( impl.mController->IsUnderlineEnabled() != enabled )
301           {
302             impl.mController->SetUnderlineEnabled( enabled );
303             impl.mTextUpdateNeeded = true;
304           }
305         }
306         break;
307       }
308
309       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
310       {
311         if( impl.mController )
312         {
313           float height = value.Get< float >();
314           if( fabsf( impl.mController->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 )
315           {
316             impl.mController->SetUnderlineHeight( height );
317             impl.mTextUpdateNeeded = true;
318           }
319         }
320         break;
321       }
322       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
323       {
324         if( impl.mController )
325         {
326           const bool enableMarkup = value.Get<bool>();
327           impl.mController->SetMarkupProcessorEnabled( enableMarkup );
328         }
329         break;
330       }
331       case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
332       {
333         if( impl.mController )
334         {
335           const bool enableAutoScroll = value.Get<bool>();
336           // If request to auto scroll is the same as current state then do nothing.
337           if ( enableAutoScroll != impl.mController->IsAutoScrollEnabled() )
338           {
339              // If request is disable (false) and auto scrolling is enabled then need to stop it
340              if ( enableAutoScroll == false )
341              {
342                if( impl.mTextScroller )
343                {
344                  impl.mTextScroller->StopScrolling();
345                }
346              }
347              // If request is enable (true) then start autoscroll as not already running
348              else
349              {
350                impl.mController->SetTextElideEnabled( false );
351                impl.mController->SetAutoScrollEnabled( enableAutoScroll );
352              }
353           }
354         }
355         break;
356       }
357       case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
358       {
359         if( !impl.mTextScroller )
360         {
361           impl.mTextScroller = Text::TextScroller::New( impl );
362         }
363         Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = impl.mTextScroller->GetStopMode();
364         if( Scripting::GetEnumerationProperty< Toolkit::TextLabel::AutoScrollStopMode::Type >( value,
365                                                                                                     AUTO_SCROLL_STOP_MODE_TABLE,
366                                                                                                     AUTO_SCROLL_STOP_MODE_TABLE_COUNT,
367                                                                                                     stopMode ) )
368         {
369             impl.mTextScroller->SetStopMode( stopMode );
370         }
371         break;
372       }
373       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
374       {
375         if( !impl.mTextScroller )
376         {
377           impl.mTextScroller = Text::TextScroller::New( impl );
378         }
379         impl.mTextScroller->SetSpeed( value.Get<int>() );
380         break;
381       }
382       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
383       {
384         if( !impl.mTextScroller )
385         {
386           impl.mTextScroller = Text::TextScroller::New( impl );
387         }
388         impl.mTextScroller->SetLoopCount( value.Get<int>() );
389         break;
390       }
391       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
392       {
393          if( !impl.mTextScroller )
394         {
395           impl.mTextScroller = Text::TextScroller::New( impl );
396         }
397         impl.mTextScroller->SetLoopDelay( value.Get<float>() );
398         break;
399       }
400       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
401       {
402         if( !impl.mTextScroller )
403         {
404           impl.mTextScroller = Text::TextScroller::New( impl );
405         }
406         impl.mTextScroller->SetGap( value.Get<float>() );
407         break;
408       }
409       case Toolkit::TextLabel::Property::LINE_SPACING:
410       {
411         if( impl.mController )
412         {
413           const float lineSpacing = value.Get<float>();
414
415           // Don't trigger anything if the line spacing didn't change
416           if( impl.mController->SetDefaultLineSpacing( lineSpacing ) )
417           {
418             impl.mTextUpdateNeeded = true;
419           }
420         }
421         break;
422       }
423       case Toolkit::TextLabel::Property::UNDERLINE:
424       {
425         const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
426         if( update )
427         {
428           impl.mTextUpdateNeeded = true;
429         }
430         break;
431       }
432       case Toolkit::TextLabel::Property::SHADOW:
433       {
434         const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
435         if( update )
436         {
437           impl.mTextUpdateNeeded = true;
438         }
439         break;
440       }
441       case Toolkit::TextLabel::Property::EMBOSS:
442       {
443         const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
444         if( update )
445         {
446           impl.mTextUpdateNeeded = true;
447         }
448         break;
449       }
450       case Toolkit::TextLabel::Property::OUTLINE:
451       {
452         const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
453         if( update )
454         {
455           impl.mTextUpdateNeeded = true;
456         }
457         break;
458       }
459       case Toolkit::TextLabel::Property::PIXEL_SIZE:
460       {
461         if( impl.mController )
462         {
463           const float pixelSize = value.Get< float >();
464           DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize );
465
466           if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
467           {
468             impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
469           }
470         }
471         break;
472       }
473       case Toolkit::TextLabel::Property::ELLIPSIS:
474       {
475         if( impl.mController )
476         {
477           const bool ellipsis = value.Get<bool>();
478           DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis );
479
480           impl.mController->SetTextElideEnabled( ellipsis );
481         }
482         break;
483       }
484       case Toolkit::TextLabel::Property::LINE_WRAP_MODE:
485       {
486         if( impl.mController )
487         {
488           Text::LineWrap::Mode lineWrapMode( static_cast< Text::LineWrap::Mode >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
489           if( GetLineWrapModeEnumeration( value, lineWrapMode ) )
490           {
491             DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode );
492             impl.mController->SetLineWrapMode( lineWrapMode );
493           }
494         }
495         break;
496       }
497       case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT:
498       {
499         if( impl.mController && impl.mController->GetTextModel() )
500         {
501           DevelText::VerticalLineAlignment::Type alignment = static_cast<DevelText::VerticalLineAlignment::Type>( value.Get<int>() );
502
503           impl.mController->SetVerticalLineAlignment( alignment );
504
505           // Property doesn't affect the layout, only Visual must be updated
506           TextVisual::EnableRendererUpdate( impl.mVisual );
507
508           // No need to trigger full re-layout. Instead call UpdateRenderer() directly
509           TextVisual::UpdateRenderer( impl.mVisual );
510         }
511         break;
512       }
513     }
514
515     // Request relayout when text update is needed. It's necessary to call it
516     // as changing the property not via UI interaction brings no effect if only
517     // the mTextUpdateNeeded is changed.
518     if( impl.mTextUpdateNeeded )
519     {
520       // need to request relayout as size of text may have changed
521       impl.RequestTextRelayout();
522     }
523   }
524
525
526
527
528 }
529
530 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
531 {
532   Property::Value value;
533
534   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
535
536   if( label )
537   {
538     TextLabel& impl( GetImpl( label ) );
539     switch( index )
540     {
541       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
542       {
543         DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
544
545         value = impl.mRenderingBackend;
546         break;
547       }
548       case Toolkit::TextLabel::Property::TEXT:
549       {
550         if( impl.mController )
551         {
552           std::string text;
553           impl.mController->GetText( text );
554           value = text;
555         }
556         break;
557       }
558       case Toolkit::TextLabel::Property::FONT_FAMILY:
559       {
560         if( impl.mController )
561         {
562           value = impl.mController->GetDefaultFontFamily();
563         }
564         break;
565       }
566       case Toolkit::TextLabel::Property::FONT_STYLE:
567       {
568         GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
569         break;
570       }
571       case Toolkit::TextLabel::Property::POINT_SIZE:
572       {
573         if( impl.mController )
574         {
575           value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE );
576         }
577         break;
578       }
579       case Toolkit::TextLabel::Property::MULTI_LINE:
580       {
581         if( impl.mController )
582         {
583           value = impl.mController->IsMultiLineEnabled();
584         }
585         break;
586       }
587       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
588       {
589         if( impl.mController )
590         {
591           const char* name = Text::GetHorizontalAlignmentString( impl.mController->GetHorizontalAlignment() );
592
593            if ( name )
594            {
595              value = std::string( name );
596            }
597         }
598         break;
599       }
600       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
601       {
602         if( impl.mController )
603         {
604           const char* name = Text::GetVerticalAlignmentString( impl.mController->GetVerticalAlignment() );
605           if( name )
606           {
607             value = std::string( name );
608           }
609         }
610         break;
611       }
612       case Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR:
613       {
614         value = label.GetProperty( Toolkit::TextLabel::Property::TEXT_COLOR );
615         break;
616       }
617       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
618       {
619         if ( impl.mController )
620         {
621           value = impl.mController->GetShadowOffset();
622         }
623         break;
624       }
625       case Toolkit::TextLabel::Property::SHADOW_COLOR:
626       {
627         if ( impl.mController )
628         {
629           value = impl.mController->GetShadowColor();
630         }
631         break;
632       }
633       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
634       {
635         if ( impl.mController )
636         {
637           value = impl.mController->GetUnderlineColor();
638         }
639         break;
640       }
641       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
642       {
643         if ( impl.mController )
644         {
645           value = impl.mController->IsUnderlineEnabled();
646         }
647         break;
648       }
649       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
650       {
651         if ( impl.mController )
652         {
653           value = impl.mController->GetUnderlineHeight();
654         }
655         break;
656       }
657       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
658       {
659         if( impl.mController )
660         {
661           value = impl.mController->IsMarkupProcessorEnabled();
662         }
663         break;
664       }
665       case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
666       {
667         if( impl.mController )
668         {
669           value = impl.mController->IsAutoScrollEnabled();
670         }
671         break;
672       }
673       case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
674       {
675         if( impl.mTextScroller )
676         {
677           const char* mode = Scripting::GetEnumerationName< Toolkit::TextLabel::AutoScrollStopMode::Type >( impl.mTextScroller->GetStopMode(),
678                                                                                                                  AUTO_SCROLL_STOP_MODE_TABLE,
679                                                                                                                  AUTO_SCROLL_STOP_MODE_TABLE_COUNT );
680           if( mode )
681           {
682             value = std::string( mode );
683           }
684         }
685         break;
686       }
687       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
688       {
689         TextLabel& impl( GetImpl( label ) );
690         if ( impl.mTextScroller )
691         {
692           value = impl.mTextScroller->GetSpeed();
693         }
694         break;
695       }
696       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
697       {
698         if( impl.mController )
699         {
700           TextLabel& impl( GetImpl( label ) );
701           if ( impl.mTextScroller )
702           {
703             value = impl.mTextScroller->GetLoopCount();
704           }
705         }
706         break;
707       }
708       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
709       {
710         if( impl.mController )
711         {
712           TextLabel& impl( GetImpl( label ) );
713           if ( impl.mTextScroller )
714           {
715             value = impl.mTextScroller->GetLoopDelay();
716           }
717         }
718         break;
719       }
720       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
721       {
722         TextLabel& impl( GetImpl( label ) );
723         if ( impl.mTextScroller )
724         {
725           value = impl.mTextScroller->GetGap();
726         }
727         break;
728       }
729       case Toolkit::TextLabel::Property::LINE_SPACING:
730       {
731         if( impl.mController )
732         {
733           value = impl.mController->GetDefaultLineSpacing();
734         }
735         break;
736       }
737       case Toolkit::TextLabel::Property::UNDERLINE:
738       {
739         GetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
740         break;
741       }
742       case Toolkit::TextLabel::Property::SHADOW:
743       {
744         GetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
745         break;
746       }
747       case Toolkit::TextLabel::Property::EMBOSS:
748       {
749         GetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
750         break;
751       }
752       case Toolkit::TextLabel::Property::OUTLINE:
753       {
754         GetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
755         break;
756       }
757       case Toolkit::TextLabel::Property::PIXEL_SIZE:
758       {
759         if( impl.mController )
760         {
761           value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE );
762         }
763         break;
764       }
765       case Toolkit::TextLabel::Property::ELLIPSIS:
766       {
767         if( impl.mController )
768         {
769           value = impl.mController->IsTextElideEnabled();
770         }
771         break;
772       }
773       case Toolkit::TextLabel::Property::LINE_WRAP_MODE:
774       {
775         if( impl.mController )
776         {
777           value = impl.mController->GetLineWrapMode();
778         }
779         break;
780       }
781       case Toolkit::TextLabel::Property::LINE_COUNT:
782       {
783         if( impl.mController )
784         {
785           float width = label.GetProperty( Actor::Property::SIZE_WIDTH ).Get<float>();
786           value = impl.mController->GetLineCount( width );
787         }
788         break;
789       }
790       case Toolkit::DevelTextLabel::Property::TEXT_DIRECTION:
791       {
792         if( impl.mController )
793         {
794           value = impl.mController->GetTextDirection();
795         }
796         break;
797       }
798       case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT:
799       {
800         if( impl.mController )
801         {
802           value = impl.mController->GetVerticalLineAlignment();
803         }
804         break;
805       }
806     }
807   }
808
809   return value;
810 }
811
812 void TextLabel::OnInitialize()
813 {
814   Actor self = Self();
815
816   Property::Map propertyMap;
817   propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
818
819   mVisual =  Toolkit::VisualFactory::Get().CreateVisual( propertyMap );
820   DevelControl::RegisterVisual( *this, Toolkit::TextLabel::Property::TEXT, mVisual  );
821
822   TextVisual::SetAnimatableTextColorProperty( mVisual, Toolkit::TextLabel::Property::TEXT_COLOR );
823
824   mController = TextVisual::GetController(mVisual);
825   if( mController )
826   {
827     mController->SetControlInterface(this);
828   }
829
830   // Use height-for-width negotiation by default
831   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
832   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
833
834   // Enable the text ellipsis.
835   mController->SetTextElideEnabled( true );   // If false then text larger than control will overflow
836
837   Layout::Engine& engine = mController->GetLayoutEngine();
838   engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
839 }
840
841 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
842 {
843   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
844
845   switch ( change )
846   {
847     case StyleChange::DEFAULT_FONT_CHANGE:
848     {
849       // Property system did not set the font so should update it.
850       const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
851       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str() );
852       mController->UpdateAfterFontChange( newFont );
853       RelayoutRequest();
854       break;
855     }
856     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
857     {
858       GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
859       RelayoutRequest();
860       break;
861     }
862     case StyleChange::THEME_CHANGE:
863     {
864       // Nothing to do, let control base class handle this
865       break;
866     }
867   }
868
869   // Up call to Control
870   Control::OnStyleChange( styleManager, change );
871 }
872
873 Vector3 TextLabel::GetNaturalSize()
874 {
875   Extents padding;
876   padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
877
878   Vector3 naturalSize = mController->GetNaturalSize();
879   naturalSize.width += ( padding.start + padding.end );
880   naturalSize.height += ( padding.top + padding.bottom );
881
882   return naturalSize;
883 }
884
885 float TextLabel::GetHeightForWidth( float width )
886 {
887   Extents padding;
888   padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
889
890   return mController->GetHeightForWidth( width ) + padding.top + padding.bottom;
891 }
892
893 void TextLabel::OnPropertySet( Property::Index index, Property::Value propertyValue )
894 {
895   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnPropertySet index[%d]\n", index );
896
897   switch ( index )
898   {
899     case Toolkit::TextLabel::Property::TEXT_COLOR:
900     {
901       const Vector4& textColor = propertyValue.Get< Vector4 >();
902       if( mController->GetDefaultColor() != textColor )
903       {
904          mController->SetDefaultColor( textColor );
905          mTextUpdateNeeded = true;
906       }
907       break;
908     }
909     default:
910     {
911       Control::OnPropertySet( index, propertyValue ); // up call to control for non-handled properties
912       break;
913     }
914   }
915 }
916
917 void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
918 {
919   DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout\n" );
920
921   Extents padding;
922   padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
923
924   Vector2 contentSize( size.x - ( padding.start + padding.end ), size.y - ( padding.top + padding.bottom ) );
925
926   const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize );
927
928   if( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
929      || mTextUpdateNeeded )
930   {
931     DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout IsAutoScrollEnabled[%s] [%p]\n", ( mController->IsAutoScrollEnabled())?"true":"false", this );
932
933     // Update the visual
934     TextVisual::EnableRendererUpdate( mVisual );
935
936     // Support Right-To-Left of padding
937     Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
938     if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
939     {
940       std::swap( padding.start, padding.end );
941     }
942
943     Property::Map visualTransform;
944     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, contentSize )
945                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
946                    .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( padding.start, padding.top ) )
947                    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
948                    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
949                    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
950     mVisual.SetTransformAndSize( visualTransform, size );
951
952     if ( mController->IsAutoScrollEnabled() )
953     {
954       SetUpAutoScrolling();
955     }
956
957     mTextUpdateNeeded = false;
958   }
959 }
960
961 void TextLabel::RequestTextRelayout()
962 {
963   RelayoutRequest();
964 }
965
966 void TextLabel::SetUpAutoScrolling()
967 {
968   const Size& controlSize = mController->GetView().GetControlSize();
969   const Size textNaturalSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only.
970   const Text::CharacterDirection direction = mController->GetAutoScrollDirection();
971
972   DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling textNaturalSize[%f,%f] controlSize[%f,%f]\n",
973                  textNaturalSize.x,textNaturalSize.y , controlSize.x,controlSize.y );
974
975   if ( !mTextScroller )
976   {
977     DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling Creating default TextScoller\n" );
978
979     // If speed, loopCount or gap not set via property system then will need to create a TextScroller with defaults
980     mTextScroller = Text::TextScroller::New( *this );
981   }
982
983   // Calculate the actual gap before scrolling wraps.
984   int textPadding = std::max( controlSize.x - textNaturalSize.x, 0.0f );
985   float wrapGap = std::max( mTextScroller->GetGap(), textPadding );
986   Vector2 textureSize = textNaturalSize + Vector2(wrapGap, 0.0f); // Add the gap as a part of the texture
987
988   // Create a texture of the text for scrolling
989   Size verifiedSize = textureSize;
990   const int maxTextureSize = Dali::GetMaxTextureSize();
991
992   //if the texture size width exceed maxTextureSize, modify the visual model size and enabled the ellipsis
993   if( verifiedSize.width > maxTextureSize )
994   {
995     verifiedSize.width = maxTextureSize;
996     if( textNaturalSize.width > maxTextureSize )
997     {
998       mController->SetTextElideEnabled( true );
999     }
1000     GetHeightForWidth( maxTextureSize );
1001     wrapGap = std::max( maxTextureSize - textNaturalSize.width, 0.0f );
1002   }
1003
1004   Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
1005
1006   PixelData data = typesetter->Render( verifiedSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
1007   Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
1008                                   data.GetPixelFormat(),
1009                                   data.GetWidth(),
1010                                   data.GetHeight() );
1011   texture.Upload( data );
1012
1013   TextureSet textureSet = TextureSet::New();
1014   textureSet.SetTexture( 0u, texture );
1015
1016   // Filter mode needs to be set to linear to produce better quality while scaling.
1017   Sampler sampler = Sampler::New();
1018   sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
1019   sampler.SetWrapMode( Dali::WrapMode::DEFAULT, Dali::WrapMode::REPEAT, Dali::WrapMode::DEFAULT ); // Wrap the texture in the x direction
1020   textureSet.SetSampler( 0u, sampler );
1021
1022   // Set parameters for scrolling
1023   Renderer renderer = static_cast<Internal::Visual::Base&>( GetImplementation( mVisual ) ).GetRenderer();
1024   mTextScroller->SetParameters( Self(), renderer, textureSet, controlSize, verifiedSize, wrapGap, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment(), mController->IsTextElideEnabled() );
1025 }
1026
1027 void TextLabel::ScrollingFinished()
1028 {
1029   // Pure Virtual from TextScroller Interface
1030   DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n");
1031   mController->SetAutoScrollEnabled( false );
1032   mController->SetTextElideEnabled( true );
1033   RequestTextRelayout();
1034 }
1035
1036 TextLabel::TextLabel()
1037 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
1038   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
1039   mTextUpdateNeeded( false )
1040 {
1041 }
1042
1043 TextLabel::~TextLabel()
1044 {
1045 }
1046
1047 } // namespace Internal
1048
1049 } // namespace Toolkit
1050
1051 } // namespace Dali