0094c9ba5fb9d06d2d4e9dcc23fcecd46137cb95
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-label-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/object/type-registry-helper.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/text/rendering-backend.h>
27 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
28 #include <dali-toolkit/internal/controls/text-controls/text-font-style.h>
29 #include <dali-toolkit/internal/text/rendering/text-backend.h>
30 #include <dali-toolkit/internal/text/text-view.h>
31 #include <dali-toolkit/internal/styling/style-manager-impl.h>
32
33 using Dali::Toolkit::Text::LayoutEngine;
34 using Dali::Toolkit::Text::Backend;
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace
46 {
47   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
48 }
49
50 namespace
51 {
52
53 #if defined(DEBUG_ENABLED)
54   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
55 #endif
56
57 const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
58 {
59   { "BEGIN",  Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_BEGIN  },
60   { "CENTER", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_CENTER },
61   { "END",    Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_END    },
62 };
63 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
64
65 const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
66 {
67   { "TOP",    Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_TOP    },
68   { "CENTER", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_CENTER },
69   { "BOTTOM", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_BOTTOM },
70 };
71 const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( VERTICAL_ALIGNMENT_STRING_TABLE ) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
72
73 // Type registration
74 BaseHandle Create()
75 {
76   return Toolkit::TextLabel::New();
77 }
78
79 // Setup properties, signals and actions using the type-registry.
80 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create );
81
82 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "renderingBackend",     INTEGER, RENDERING_BACKEND    )
83 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "text",                 STRING,  TEXT                 )
84 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontFamily",           STRING,  FONT_FAMILY          )
85 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontStyle",            STRING,  FONT_STYLE           )
86 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "pointSize",            FLOAT,   POINT_SIZE           )
87 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "multiLine",            BOOLEAN, MULTI_LINE           )
88 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "horizontalAlignment",  STRING,  HORIZONTAL_ALIGNMENT )
89 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "verticalAlignment",    STRING,  VERTICAL_ALIGNMENT   )
90 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textColor",            VECTOR4, TEXT_COLOR           )
91 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadowOffset",         VECTOR2, SHADOW_OFFSET        )
92 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadowColor",          VECTOR4, SHADOW_COLOR         )
93 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineEnabled",     BOOLEAN, UNDERLINE_ENABLED    )
94 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineColor",       VECTOR4, UNDERLINE_COLOR      )
95 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineHeight",      FLOAT,   UNDERLINE_HEIGHT     )
96 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "enableMarkup",         BOOLEAN, ENABLE_MARKUP        )
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           DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str() );
153           impl.mController->SetDefaultFontFamily( fontFamily );
154         }
155         break;
156       }
157       case Toolkit::TextLabel::Property::FONT_STYLE:
158       {
159         SetFontStyleProperty( impl.mController, value );
160         break;
161       }
162       case Toolkit::TextLabel::Property::POINT_SIZE:
163       {
164         if( impl.mController )
165         {
166           const float pointSize = value.Get< float >();
167
168           if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) )
169           {
170             impl.mController->SetDefaultPointSize( pointSize );
171           }
172         }
173         break;
174       }
175       case Toolkit::TextLabel::Property::MULTI_LINE:
176       {
177         if( impl.mController )
178         {
179           impl.mController->SetMultiLineEnabled( value.Get< bool >() );
180         }
181         break;
182       }
183       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
184       {
185         if( impl.mController )
186         {
187           LayoutEngine::HorizontalAlignment alignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN );
188           if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::HorizontalAlignment >( value.Get< std::string >().c_str(),
189                                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE,
190                                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
191                                                                                              alignment ) )
192           {
193             impl.mController->SetHorizontalAlignment( alignment );
194           }
195         }
196         break;
197       }
198       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
199       {
200         if( impl.mController )
201         {
202           LayoutEngine::VerticalAlignment alignment( LayoutEngine::VERTICAL_ALIGN_BOTTOM );
203           if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::VerticalAlignment >( value.Get< std::string >().c_str(),
204                                                                                            VERTICAL_ALIGNMENT_STRING_TABLE,
205                                                                                            VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
206                                                                                            alignment ) )
207           {
208             impl.mController->SetVerticalAlignment( alignment );
209           }
210         }
211         break;
212       }
213
214       case Toolkit::TextLabel::Property::TEXT_COLOR:
215       {
216         if( impl.mController )
217         {
218           const Vector4 textColor = value.Get< Vector4 >();
219           if( impl.mController->GetTextColor() != textColor )
220           {
221             impl.mController->SetTextColor( textColor );
222             impl.mRenderer.Reset();
223           }
224         }
225         break;
226       }
227
228       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
229       {
230         if( impl.mController )
231         {
232           const Vector2 shadowOffset = value.Get< Vector2 >();
233           if ( impl.mController->GetShadowOffset() != shadowOffset )
234           {
235             impl.mController->SetShadowOffset( shadowOffset );
236             impl.mRenderer.Reset();
237           }
238         }
239         break;
240       }
241       case Toolkit::TextLabel::Property::SHADOW_COLOR:
242       {
243         if( impl.mController )
244         {
245           const Vector4 shadowColor = value.Get< Vector4 >();
246           if ( impl.mController->GetShadowColor() != shadowColor )
247           {
248             impl.mController->SetShadowColor( shadowColor );
249             impl.mRenderer.Reset();
250           }
251         }
252         break;
253       }
254       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
255       {
256         if( impl.mController )
257         {
258           const Vector4 color = value.Get< Vector4 >();
259           if ( impl.mController->GetUnderlineColor() != color )
260           {
261             impl.mController->SetUnderlineColor( color );
262             impl.mRenderer.Reset();
263           }
264         }
265         break;
266       }
267       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
268       {
269         if( impl.mController )
270         {
271           const bool enabled = value.Get< bool >();
272           if ( impl.mController->IsUnderlineEnabled() != enabled )
273           {
274             impl.mController->SetUnderlineEnabled( enabled );
275             impl.mRenderer.Reset();
276           }
277         }
278         break;
279       }
280
281       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
282       {
283         if( impl.mController )
284         {
285           float height = value.Get< float >();
286           if( fabsf( impl.mController->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 )
287           {
288             impl.mController->SetUnderlineHeight( height );
289             impl.mRenderer.Reset();
290           }
291         }
292         break;
293       }
294       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
295       {
296         if( impl.mController )
297         {
298           const bool enableMarkup = value.Get<bool>();
299           impl.mController->SetMarkupProcessorEnabled( enableMarkup );
300         }
301         break;
302       }
303     }
304   }
305 }
306
307 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
308 {
309   Property::Value value;
310
311   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
312
313   if( label )
314   {
315     TextLabel& impl( GetImpl( label ) );
316     switch( index )
317     {
318       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
319       {
320         value = impl.mRenderingBackend;
321         break;
322       }
323       case Toolkit::TextLabel::Property::TEXT:
324       {
325         if( impl.mController )
326         {
327           std::string text;
328           impl.mController->GetText( text );
329           value = text;
330         }
331         break;
332       }
333       case Toolkit::TextLabel::Property::FONT_FAMILY:
334       {
335         if( impl.mController )
336         {
337           value = impl.mController->GetDefaultFontFamily();
338         }
339         break;
340       }
341       case Toolkit::TextLabel::Property::FONT_STYLE:
342       {
343         GetFontStyleProperty( impl.mController, value );
344         break;
345       }
346       case Toolkit::TextLabel::Property::POINT_SIZE:
347       {
348         if( impl.mController )
349         {
350           value = impl.mController->GetDefaultPointSize();
351         }
352         break;
353       }
354       case Toolkit::TextLabel::Property::MULTI_LINE:
355       {
356         if( impl.mController )
357         {
358           value = impl.mController->IsMultiLineEnabled();
359         }
360         break;
361       }
362       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
363       {
364         if( impl.mController )
365         {
366           const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(),
367                                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE,
368                                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
369           if( name )
370           {
371             value = std::string( name );
372           }
373         }
374         break;
375       }
376       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
377       {
378         if( impl.mController )
379         {
380           const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
381                                                                                                               VERTICAL_ALIGNMENT_STRING_TABLE,
382                                                                                                               VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
383           if( name )
384           {
385             value = std::string( name );
386           }
387         }
388         break;
389       }
390       case Toolkit::TextLabel::Property::TEXT_COLOR:
391       {
392         if ( impl.mController )
393         {
394           value = impl.mController->GetTextColor();
395         }
396         break;
397       }
398       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
399       {
400         if ( impl.mController )
401         {
402           value = impl.mController->GetShadowOffset();
403         }
404         break;
405       }
406       case Toolkit::TextLabel::Property::SHADOW_COLOR:
407       {
408         if ( impl.mController )
409         {
410           value = impl.mController->GetShadowColor();
411         }
412         break;
413       }
414       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
415       {
416         if ( impl.mController )
417         {
418           value = impl.mController->GetUnderlineColor();
419         }
420         break;
421       }
422       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
423       {
424         if ( impl.mController )
425         {
426           value = impl.mController->IsUnderlineEnabled();
427         }
428         break;
429       }
430       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
431       {
432         if ( impl.mController )
433         {
434           value = impl.mController->GetUnderlineHeight();
435         }
436         break;
437       }
438       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
439       {
440         if( impl.mController )
441         {
442           value = impl.mController->IsMarkupProcessorEnabled();
443         }
444         break;
445       }
446     }
447   }
448
449   return value;
450 }
451
452 void TextLabel::OnInitialize()
453 {
454   Actor self = Self();
455
456   mController = Text::Controller::New( *this );
457
458   // Use height-for-width negotiation by default
459   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
460   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
461
462   // Enable the text ellipsis.
463   LayoutEngine& engine = mController->GetLayoutEngine();
464
465   engine.SetTextEllipsisEnabled( true );
466   engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
467
468   self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect );
469 }
470
471 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
472 {
473
474   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
475
476   switch ( change )
477   {
478     case StyleChange::DEFAULT_FONT_CHANGE:
479     {
480       // Property system did not set the font so should update it.
481       std::string newFont = styleManager.GetDefaultFontFamily();
482       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str() );
483       mController->UpdateAfterFontChange( newFont );
484       break;
485     }
486
487     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
488     {
489       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() );
490
491       if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f
492       {
493         // Property system did not set the PointSize so should update it.
494         // todo instruct text-controller to update model
495       }
496       break;
497     }
498     case StyleChange::THEME_CHANGE:
499     {
500       GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
501       break;
502     }
503   }
504 }
505
506 Vector3 TextLabel::GetNaturalSize()
507 {
508   return mController->GetNaturalSize();
509 }
510
511 float TextLabel::GetHeightForWidth( float width )
512 {
513   return mController->GetHeightForWidth( width );
514 }
515
516 void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
517 {
518   if( mController->Relayout( size ) ||
519       !mRenderer )
520   {
521     if( !mRenderer )
522     {
523       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
524     }
525     RenderText();
526   }
527 }
528
529 void TextLabel::RequestTextRelayout()
530 {
531   RelayoutRequest();
532 }
533
534 void TextLabel::RenderText()
535 {
536   Actor self = Self();
537   Actor renderableActor;
538   if( mRenderer )
539   {
540     renderableActor = mRenderer->Render( mController->GetView(), DepthIndex::TEXT );
541   }
542
543   if( renderableActor != mRenderableActor )
544   {
545     UnparentAndReset( mRenderableActor );
546
547     if( renderableActor )
548     {
549       const Vector2& alignmentOffset = mController->GetAlignmentOffset();
550       renderableActor.SetPosition( alignmentOffset.x, alignmentOffset.y );
551
552       self.Add( renderableActor );
553     }
554     mRenderableActor = renderableActor;
555   }
556 }
557
558 void TextLabel::OnStageConnect( Dali::Actor actor )
559 {
560   if ( mHasBeenStaged )
561   {
562     RenderText();
563   }
564   else
565   {
566     mHasBeenStaged = true;
567   }
568 }
569
570 void TextLabel::AddDecoration( Actor& actor, bool needsClipping )
571 {
572   // TextLabel does not show decorations
573 }
574
575 void TextLabel::OnStageConnection( int depth )
576 {
577   // Call the Control::OnStageConnection() to set the depth of the background.
578   Control::OnStageConnection( depth );
579
580   // The depth of the text renderer is set in the RenderText() called from OnRelayout().
581 }
582
583 void TextLabel::TextChanged()
584 {
585   // TextLabel does not provide a signal for this
586 }
587
588 void TextLabel::MaxLengthReached()
589 {
590   // Pure Virtual from TextController Interface, only needed when inputting text
591 }
592
593 TextLabel::TextLabel()
594 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
595   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
596   mHasBeenStaged( false )
597 {
598 }
599
600 TextLabel::~TextLabel()
601 {
602 }
603
604 } // namespace Internal
605
606 } // namespace Toolkit
607
608 } // namespace Dali