Merge "Enum properties added for the text effects style." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-effects-style.cpp
1 /*
2  * Copyright (c) 2019 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 // FILE HEADER
19 #include <dali-toolkit/internal/text/text-effects-style.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
23 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
24 #include <dali-toolkit/internal/text/property-string-parser.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Text
33 {
34
35 namespace
36 {
37 const std::string COLOR_KEY( "color" );
38 const std::string OFFSET_KEY( "offset" );
39 const std::string BLUR_RADIUS_KEY( "blurRadius" );
40 const std::string WIDTH_KEY( "width" );
41 const std::string HEIGHT_KEY( "height" );
42 const std::string ENABLE_KEY( "enable" );
43 const std::string TRUE_TOKEN( "true" );
44 const std::string FALSE_TOKEN( "false" );
45 }
46
47 bool ParseShadowProperties( const Property::Map& shadowPropertiesMap,
48                             bool& colorDefined,
49                             Vector4& color,
50                             bool& offsetDefined,
51                             Vector2& offset,
52                             bool& blurRadiusDefined,
53                             float& blurRadius )
54 {
55   const unsigned int numberOfItems = shadowPropertiesMap.Count();
56
57   // Parses and applies the style.
58   for( unsigned int index = 0u; index < numberOfItems; ++index )
59   {
60     const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue( index );
61
62     if( ( DevelText::Shadow::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
63     {
64       /// Color key.
65       colorDefined = true;
66
67       if( valueGet.second.GetType() == Dali::Property::STRING )
68       {
69         const std::string colorStr = valueGet.second.Get<std::string>();
70         Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
71       }
72       else
73       {
74         color = valueGet.second.Get<Vector4>();
75       }
76     }
77     else if( ( DevelText::Shadow::Property::OFFSET == valueGet.first.indexKey ) || ( OFFSET_KEY == valueGet.first.stringKey ) )
78     {
79       /// Offset key.
80       offsetDefined = true;
81
82       if( valueGet.second.GetType() == Dali::Property::STRING )
83       {
84         const std::string offsetStr = valueGet.second.Get<std::string>();
85         StringToVector2( offsetStr.c_str(), offsetStr.size(), offset );
86       }
87       else
88       {
89         offset = valueGet.second.Get<Vector2>();
90       }
91     }
92     else if( ( DevelText::Shadow::Property::BLUR_RADIUS == valueGet.first.indexKey ) || ( BLUR_RADIUS_KEY == valueGet.first.stringKey ) )
93     {
94       /// Blur radius key.
95       blurRadiusDefined = true;
96
97       if( valueGet.second.GetType() == Dali::Property::STRING )
98       {
99         const std::string blurRadiusStr = valueGet.second.Get<std::string>();
100         blurRadius = StringToFloat( blurRadiusStr.c_str() );
101       }
102       else
103       {
104         blurRadius = valueGet.second.Get<float>();
105       }
106     }
107   }
108
109   return 0u == numberOfItems;
110 }
111
112 bool ParseUnderlineProperties( const Property::Map& underlinePropertiesMap,
113                                bool& enabled,
114                                bool& colorDefined,
115                                Vector4& color,
116                                bool& heightDefined,
117                                float& height )
118 {
119   const unsigned int numberOfItems = underlinePropertiesMap.Count();
120
121   // Parses and applies the style.
122   for( unsigned int index = 0u; index < numberOfItems; ++index )
123   {
124     const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
125
126     if( ( DevelText::Underline::Property::ENABLE == valueGet.first.indexKey ) || ( ENABLE_KEY == valueGet.first.stringKey ) )
127     {
128       /// Enable key.
129       if( valueGet.second.GetType() == Dali::Property::STRING )
130       {
131         const std::string enableStr = valueGet.second.Get<std::string>();
132         enabled = Text::TokenComparison( TRUE_TOKEN, enableStr.c_str(), enableStr.size() );
133       }
134       else
135       {
136         enabled = valueGet.second.Get<bool>();
137       }
138     }
139     else if( ( DevelText::Underline::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
140     {
141       /// Color key.
142       colorDefined = true;
143
144       if( valueGet.second.GetType() == Dali::Property::STRING )
145       {
146         const std::string colorStr = valueGet.second.Get<std::string>();
147         Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
148       }
149       else
150       {
151         color = valueGet.second.Get<Vector4>();
152       }
153     }
154     else if( ( DevelText::Underline::Property::HEIGHT == valueGet.first.indexKey ) || ( HEIGHT_KEY == valueGet.first.stringKey ) )
155     {
156       /// Height key.
157       heightDefined = true;
158
159       if( valueGet.second.GetType() == Dali::Property::STRING )
160       {
161         const std::string heightStr = valueGet.second.Get<std::string>();
162         height = StringToFloat( heightStr.c_str() );
163       }
164       else
165       {
166         height = valueGet.second.Get<float>();
167       }
168     }
169   }
170
171   return 0u == numberOfItems;
172 }
173
174 bool ParseOutlineProperties( const Property::Map& underlinePropertiesMap,
175                                bool& colorDefined,
176                                Vector4& color,
177                                bool& widthDefined,
178                                unsigned int& width )
179 {
180   const unsigned int numberOfItems = underlinePropertiesMap.Count();
181
182   // Parses and applies the style.
183   for( unsigned int index = 0u; index < numberOfItems; ++index )
184   {
185     const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
186
187     if( ( DevelText::Outline::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
188     {
189       /// Color key.
190       colorDefined = true;
191       color = valueGet.second.Get<Vector4>();
192     }
193     else if( ( DevelText::Outline::Property::WIDTH == valueGet.first.indexKey ) || ( WIDTH_KEY == valueGet.first.stringKey ) )
194     {
195       /// Width key.
196       widthDefined = true;
197       width = static_cast<unsigned int>( valueGet.second.Get<float>() );
198     }
199   }
200
201   return 0u == numberOfItems;
202 }
203
204 bool ParseBackgroundProperties( const Property::Map& backgroundProperties,
205                                 bool& enabled,
206                                 bool& colorDefined,
207                                 Vector4& color )
208 {
209   const unsigned int numberOfItems = backgroundProperties.Count();
210
211   // Parses and applies the style.
212   for( unsigned int index = 0u; index < numberOfItems; ++index )
213   {
214     const KeyValuePair& valueGet = backgroundProperties.GetKeyValue( index );
215
216     if( ( DevelText::Background::Property::ENABLE == valueGet.first.indexKey ) || ( ENABLE_KEY == valueGet.first.stringKey ) )
217     {
218       /// Enable key.
219       enabled = valueGet.second.Get<bool>();
220     }
221     else if( ( DevelText::Background::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
222     {
223       /// Color key.
224       colorDefined = true;
225       color = valueGet.second.Get<Vector4>();
226     }
227   }
228
229   return 0u == numberOfItems;
230 }
231
232 bool SetUnderlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
233 {
234   bool update = false;
235
236   if( controller )
237   {
238     switch( type )
239     {
240       case EffectStyle::DEFAULT:
241       {
242         const Property::Map& propertiesMap = value.Get<Property::Map>();
243
244         bool enabled = false;
245         bool colorDefined = false;
246         Vector4 color;
247         bool heightDefined = false;
248         float height = 0.f;
249
250         bool empty = true;
251
252         if ( propertiesMap.Empty() )
253         {
254           // Map empty so check if a string provided
255           const std::string propertyString = value.Get<std::string>();
256
257           if ( !propertyString.empty() )
258           {
259             Property::Map parsedStringMap;
260             Text::ParsePropertyString( propertyString, parsedStringMap );
261
262             empty = ParseUnderlineProperties( parsedStringMap,
263                                               enabled,
264                                               colorDefined,
265                                               color,
266                                               heightDefined,
267                                               height );
268
269             controller->UnderlineSetByString( !empty );
270           }
271         }
272         else
273         {
274            empty = ParseUnderlineProperties( propertiesMap,
275                                              enabled,
276                                              colorDefined,
277                                              color,
278                                              heightDefined,
279                                              height );
280
281            controller->UnderlineSetByString( false );
282         }
283
284         if( !empty )
285         {
286           if( enabled != controller->IsUnderlineEnabled() )
287           {
288             controller->SetUnderlineEnabled( enabled );
289             update = true;
290           }
291
292           // Sets the default underline values.
293           if( colorDefined && ( controller->GetUnderlineColor() != color ) )
294           {
295             controller->SetUnderlineColor( color );
296             update = true;
297           }
298
299           if( heightDefined && ( fabsf( controller->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 ) )
300           {
301             controller->SetUnderlineHeight( height );
302             update = true;
303           }
304         }
305         else
306         {
307           // Disable underline.
308           if( controller->IsUnderlineEnabled() )
309           {
310             controller->SetUnderlineEnabled( false );
311             update = true;
312           }
313         }
314         break;
315       }
316       case EffectStyle::INPUT:
317       {
318         const std::string& underlineProperties = value.Get<std::string>();
319
320         controller->SetInputUnderlineProperties( underlineProperties );
321         break;
322       }
323     } // switch
324   } // if( controller )
325
326   return update;
327 }
328
329 void GetUnderlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
330 {
331   if( controller )
332   {
333     switch( type )
334     {
335       case EffectStyle::DEFAULT:
336       {
337         const bool enabled = controller->IsUnderlineEnabled();
338         const Vector4& color = controller->GetUnderlineColor();
339         const float height = controller->GetUnderlineHeight();
340
341         if ( controller->IsUnderlineSetByString() )
342         {
343           std::string underlineProperties = "{\"enable\":";
344           const std::string enabledStr = enabled ? "true" : "false";
345           underlineProperties += "\"" + enabledStr + "\",";
346
347           std::string colorStr;
348           Vector4ToColorString( color, colorStr );
349           underlineProperties += "\"color\":\"" + colorStr + "\",";
350
351           std::string heightStr;
352           FloatToString( height, heightStr );
353           underlineProperties += "\"height\":\"" + heightStr + "\"}";
354
355           value = underlineProperties;
356         }
357         else
358         {
359           Property::Map map;
360
361           const std::string enabledStr = enabled ? TRUE_TOKEN : FALSE_TOKEN;
362           map.Insert( ENABLE_KEY, enabledStr );
363
364           std::string colorStr;
365           Vector4ToColorString( color, colorStr );
366           map.Insert( COLOR_KEY, colorStr );
367
368           std::string heightStr;
369           FloatToString( height, heightStr );
370           map.Insert( HEIGHT_KEY, heightStr );
371
372           value = map;
373         }
374
375         break;
376       }
377       case EffectStyle::INPUT:
378       {
379         value = controller->GetInputUnderlineProperties();
380         break;
381       }
382     }
383   }
384 }
385
386 bool SetShadowProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
387 {
388   bool update = false;
389
390   if( controller )
391   {
392     switch( type )
393     {
394       case EffectStyle::DEFAULT:
395       {
396         const Property::Map& propertiesMap = value.Get<Property::Map>();
397
398         bool colorDefined = false;
399         Vector4 color;
400         bool offsetDefined = false;
401         Vector2 offset;
402         bool blurRadiusDefined = false;
403         float blurRadius;
404
405         bool empty = true;
406
407         if ( propertiesMap.Empty() )
408         {
409            // Map empty so check if a string provided
410            const std::string propertyString = value.Get<std::string>();
411
412            Property::Map parsedStringMap;
413            Text::ParsePropertyString( propertyString, parsedStringMap );
414
415            empty = ParseShadowProperties( parsedStringMap,
416                                           colorDefined,
417                                           color,
418                                           offsetDefined,
419                                           offset,
420                                           blurRadiusDefined,
421                                           blurRadius );
422
423            controller->ShadowSetByString( !empty );
424
425         }
426         else
427         {
428           empty = ParseShadowProperties( propertiesMap,
429                                          colorDefined,
430                                          color,
431                                          offsetDefined,
432                                          offset,
433                                          blurRadiusDefined,
434                                          blurRadius );
435
436           controller->ShadowSetByString( false );
437         }
438
439         if( !empty )
440         {
441           // Sets the default shadow values.
442           if( colorDefined && ( controller->GetShadowColor() != color ) )
443           {
444             controller->SetShadowColor( color );
445             update = true;
446           }
447
448           if( offsetDefined && ( controller->GetShadowOffset() != offset ) )
449           {
450             controller->SetShadowOffset( offset );
451             update = true;
452           }
453
454           if( blurRadiusDefined && ( controller->GetShadowBlurRadius() != blurRadius ) )
455           {
456             controller->SetShadowBlurRadius( blurRadius );
457             update = true;
458           }
459         }
460         else
461         {
462           // Disable shadow.
463           if( Vector2::ZERO != controller->GetShadowOffset() )
464           {
465             controller->SetShadowOffset( Vector2::ZERO );
466           }
467         }
468         break;
469       }
470       case EffectStyle::INPUT:
471       {
472         const std::string& shadowString = value.Get<std::string>();
473
474         controller->SetInputShadowProperties( shadowString );
475         break;
476       }
477     } // switch
478   } // if( controller )
479
480   return update;
481 }
482
483 void GetShadowProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
484 {
485   if( controller )
486   {
487     switch( type )
488     {
489       case EffectStyle::DEFAULT:
490       {
491         const Vector4& color = controller->GetShadowColor();
492         const Vector2& offset = controller->GetShadowOffset();
493         const float& blurRadius = controller->GetShadowBlurRadius();
494
495         if ( controller->IsShadowSetByString() )
496         {
497           std::string shadowProperties = "{";
498
499           std::string colorStr;
500           Vector4ToColorString( color, colorStr );
501           shadowProperties += "\"color\":\"" + colorStr + "\",";
502
503           std::string offsetStr;
504           Vector2ToString( offset, offsetStr );
505           shadowProperties += "\"offset\":\"" + offsetStr + "\",";
506
507           std::string blurRadiusStr;
508           FloatToString( blurRadius, blurRadiusStr );
509           shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
510
511           value = shadowProperties;
512         }
513         else
514         {
515           Property::Map map;
516
517           map.Insert( COLOR_KEY, color );
518           map.Insert( OFFSET_KEY, offset );
519           map.Insert( BLUR_RADIUS_KEY, blurRadius );
520
521           value = map;
522         }
523         break;
524       }
525       case EffectStyle::INPUT:
526       {
527         value = controller->GetInputShadowProperties();
528         break;
529       }
530     }
531   }
532 }
533
534 bool SetEmbossProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
535 {
536   bool update = false;
537
538   if( controller )
539   {
540     const std::string properties = value.Get< std::string >();
541
542     switch( type )
543     {
544       case EffectStyle::DEFAULT:
545       {
546         // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
547         controller->SetDefaultEmbossProperties( properties );
548         break;
549       }
550       case EffectStyle::INPUT:
551       {
552         // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
553         controller->SetInputEmbossProperties( properties );
554         break;
555       }
556     }
557   }
558
559   return update;
560 }
561
562 void GetEmbossProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
563 {
564   if( controller )
565   {
566     switch( type )
567     {
568       case EffectStyle::DEFAULT:
569       {
570         value = controller->GetDefaultEmbossProperties();
571         break;
572       }
573       case EffectStyle::INPUT:
574       {
575         value = controller->GetInputEmbossProperties();
576         break;
577       }
578     }
579   }
580 }
581
582 bool SetOutlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
583 {
584   bool update = false;
585
586   if( controller )
587   {
588     switch( type )
589     {
590       case EffectStyle::DEFAULT:
591       {
592         const Property::Map& propertiesMap = value.Get<Property::Map>();
593
594         bool colorDefined = false;
595         Vector4 color;
596         bool widthDefined = false;
597         unsigned int width = 0u;
598
599         bool empty = true;
600
601         if ( propertiesMap.Empty() )
602         {
603            // Map empty so check if a string provided
604            // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
605            const std::string propertyString = value.Get<std::string>();
606
607            // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
608            controller->SetDefaultOutlineProperties( propertyString );
609
610            controller->OutlineSetByString( true );
611         }
612         else
613         {
614            empty = ParseOutlineProperties( propertiesMap,
615                                            colorDefined,
616                                            color,
617                                            widthDefined,
618                                            width );
619
620            controller->OutlineSetByString( false );
621         }
622
623         if( !empty )
624         {
625           // Sets the default outline values.
626           if( colorDefined && ( controller->GetOutlineColor() != color ) )
627           {
628             controller->SetOutlineColor( color );
629             update = true;
630           }
631
632           if( widthDefined && ( controller->GetOutlineWidth() != width ) )
633           {
634             controller->SetOutlineWidth( width );
635             update = true;
636           }
637         }
638         else
639         {
640           // Disable outline
641           if( 0u != controller->GetOutlineWidth() )
642           {
643             controller->SetOutlineWidth( 0u );
644             update = true;
645           }
646         }
647         break;
648       }
649       case EffectStyle::INPUT:
650       {
651         const std::string& outlineProperties = value.Get<std::string>();
652
653         controller->SetInputOutlineProperties( outlineProperties );
654         break;
655       }
656     } // switch
657   } // if( controller )
658
659   return update;
660 }
661
662 void GetOutlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
663 {
664   if( controller )
665   {
666     switch( type )
667     {
668       case EffectStyle::DEFAULT:
669       {
670         if ( controller->IsOutlineSetByString() )
671         {
672           value = controller->GetDefaultOutlineProperties();
673           break;
674         }
675         else
676         {
677           const Vector4& color = controller->GetOutlineColor();
678           const unsigned int width = controller->GetOutlineWidth();
679
680           Property::Map map;
681           map.Insert( COLOR_KEY, color );
682           map.Insert( WIDTH_KEY, static_cast<int>( width ) );
683
684           value = map;
685
686           break;
687         }
688       }
689       case EffectStyle::INPUT:
690       {
691         value = controller->GetInputOutlineProperties();
692         break;
693       }
694     }
695   }
696 }
697
698 bool SetBackgroundProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
699 {
700   bool update = false;
701
702   if( controller )
703   {
704     switch( type )
705     {
706       case EffectStyle::DEFAULT:
707       {
708         const Property::Map& propertiesMap = value.Get<Property::Map>();
709
710         bool enabled = false;
711         bool colorDefined = false;
712         Vector4 color;
713
714         bool empty = true;
715
716         if ( !propertiesMap.Empty() )
717         {
718            empty = ParseBackgroundProperties( propertiesMap,
719                                               enabled,
720                                               colorDefined,
721                                               color );
722         }
723
724         if( !empty )
725         {
726           if( enabled != controller->IsBackgroundEnabled() )
727           {
728             controller->SetBackgroundEnabled( enabled );
729             update = true;
730           }
731
732           if( colorDefined && ( controller->GetBackgroundColor() != color ) )
733           {
734             controller->SetBackgroundColor( color );
735             update = true;
736           }
737         }
738         else
739         {
740           // Disable background.
741           if( controller->IsBackgroundEnabled() )
742           {
743             controller->SetBackgroundEnabled( false );
744             update = true;
745           }
746         }
747         break;
748       }
749       case EffectStyle::INPUT:
750       {
751         // Text background is not supported while inputting yet
752         break;
753       }
754     } // switch
755   } // if( controller )
756
757   return update;
758 }
759
760 void GetBackgroundProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
761 {
762   if( controller )
763   {
764     switch( type )
765     {
766       case EffectStyle::DEFAULT:
767       {
768         const bool enabled = controller->IsBackgroundEnabled();
769         const Vector4& color = controller->GetBackgroundColor();
770
771         Property::Map map;
772         map.Insert( ENABLE_KEY, enabled );
773         map.Insert( COLOR_KEY, color );
774
775         value = map;
776
777         break;
778
779       }
780       case EffectStyle::INPUT:
781       {
782         // Text background is not supported while inputting yet
783         break;
784       }
785     }
786   }
787 }
788
789
790 } // namespace Text
791
792 } // namespace Toolkit
793
794 } // namespace Dali