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