Remove dali-any from Property::Value
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / builder-set-property.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 // EXTERNAL INCLUDES
19 #include <sstream>
20 #include <dali/public-api/object/property-array.h>
21 #include <dali/public-api/object/property-map.h>
22 #include <dali/devel-api/adaptor-framework/color-controller.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/builder/builder-impl.h>
26 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
27 #include <dali-toolkit/internal/builder/replacement.h>
28
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 namespace Internal
37 {
38
39 /*
40  * Set a property value from a tree node.
41  * This function guesses the type of the property from the format of the string in the node.
42  * This is not always possible and could be surprising.
43  * @param node  The node string to convert from
44  * @param value The property value to set
45  * @return true if the string could be converted.
46  */
47 bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
48
49 /*
50  * Set a property value from a tree node as SetPropertyFromNode() above
51  * @param node  The node string to convert from
52  * @param value The property value to set
53  * @param replacement The overriding replacement map (if any)
54  * @return true if the string could be converted.
55  */
56 bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
57                           const Replacement& replacement );
58
59 /*
60  * Set a property value as the given type from a tree node.
61  * @param node The node string to convert from
62  * @param type The property type to convert to.
63  * @param value The property value to set
64  * @return true if the string could be converted to the correct type.
65  */
66 bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value );
67
68 /*
69  * Set a property value as the given type from a tree node as SetPropertyFromNode() above
70  * @param node The node string to convert from
71  * @param type The property type to convert to.
72  * @param value The property value to set
73  * @param replacement The overriding replacement map (if any)
74  * @return true if the string could be converted to the correct type.
75  */
76 bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value,
77                           const Replacement& replacement );
78
79
80 namespace
81 {
82
83 /**
84  * Converts a HTML style 'color' hex string ("#FF0000" for bright red) to a Vector4.
85  * The Vector4 alpha component will be set to 1.0f
86  * @param hexString The HTML style hex string
87  * @return a Vector4 containing the new color value
88  */
89 Vector4 HexStringToVector4( const char* s )
90 {
91   unsigned int value(0u);
92   std::istringstream( s ) >> std::hex >> value;
93   return Vector4( ((value >> 16 ) & 0xff ) / 255.0f,
94                   ((value >> 8 ) & 0xff ) / 255.0f,
95                   (value & 0xff ) / 255.0f,
96                   1.0f );
97 }
98
99 } // anon namespace
100
101
102 /**
103  * A property value type can be forced when its unknown by a disambiguation convention in the json
104  * ie  "myarray": [1,2,3,4] ; would be a vector but
105  *     "myarray": {'type-cast':'array', 'value':[1,2,3,4]} would be an array
106  * @param child The node whos string to search for a disambiguated type
107  * @param value The value to set
108  * @param overrideMap The user overriding constant map
109  * @param defaultMap The default map.
110  * @return True if child contained a disambiguated string that could be converted.
111  */
112 bool Disambiguated(const TreeNode& child, // ConstantLut& constantLut,
113                    Dali::Property::Value& value,
114                    const Replacement& replacement )
115 {
116   OptionalString childType = IsString( IsChild(child, "type-cast") );
117   OptionalChild childValue = IsChild(child, "value");
118
119   if( childType && childValue && (2 == child.Size()) )
120   {
121     // this case allows disambiguation but normally the type is guessed
122     // 2 == child.count() is an extra check as the user could have a user dictionary/map with
123     // type-cast and value keys. If they do then a work around is to add a bogus key to not run this case.
124     if(*childType == "boolean")
125     {
126       return SetPropertyFromNode( *childValue, Dali::Property::BOOLEAN, value, replacement);
127     }
128     else if(*childType == "float")
129     {
130       return SetPropertyFromNode( *childValue, Dali::Property::FLOAT, value, replacement);
131     }
132     else if(*childType == "vector2")
133     {
134       return SetPropertyFromNode( *childValue, Dali::Property::VECTOR2, value, replacement);
135     }
136     else if(*childType == "vector3")
137     {
138       return SetPropertyFromNode( *childValue, Dali::Property::VECTOR3, value, replacement);
139     }
140     else if(*childType == "vector4")
141     {
142       return SetPropertyFromNode( *childValue, Dali::Property::VECTOR4, value, replacement);
143     }
144     else if(*childType == "rotation")
145     {
146       return SetPropertyFromNode( *childValue, Dali::Property::ROTATION, value, replacement);
147     }
148     else if(*childType == "rect")
149     {
150       return SetPropertyFromNode( *childValue, Dali::Property::RECTANGLE, value, replacement);
151     }
152     else if(*childType == "string")
153     {
154       return SetPropertyFromNode( *childValue, Dali::Property::STRING, value, replacement);
155     }
156     else if(*childType == "map")
157     {
158       return SetPropertyFromNode( *childValue, Dali::Property::MAP, value, replacement);
159     }
160     else if(*childType == "array")
161     {
162       return SetPropertyFromNode( *childValue, Dali::Property::ARRAY, value, replacement);
163     }
164   }
165
166   // else we failed to disambiguate
167   return false;
168 }
169
170
171 bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value)
172 {
173   Replacement noReplacement;
174   return SetPropertyFromNode( node, type, value, noReplacement );
175 }
176
177 bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value,
178                           const Replacement& replacer )
179 {
180   bool done = false;
181
182   switch(type)
183   {
184     case Property::BOOLEAN:
185     {
186       if( OptionalBoolean v = replacer.IsBoolean(node) )
187       {
188         value = *v;
189         done = true;
190       }
191       break;
192     }
193     case Property::FLOAT:
194     {
195       if( OptionalFloat v = replacer.IsFloat(node) )
196       {
197         value = *v;
198         done = true;
199       }
200       break;
201     }
202     case Property::INTEGER:
203     {
204       if( OptionalInteger v = replacer.IsInteger(node) )
205       {
206         value = *v;
207         done = true;
208       }
209       break;
210     }
211     case Property::UNSIGNED_INTEGER:
212     {
213       if( OptionalUnsignedInt v = replacer.IsUnsignedInteger( node) )
214       {
215         if( *v >= 0 ) // with a loss of resolution....
216         {
217           value = *v;
218           done = true;
219         }
220       }
221       break;
222     }
223     case Property::VECTOR2:
224     {
225       if( OptionalVector2 v = replacer.IsVector2(node) )
226       {
227         value = *v;
228         done = true;
229       }
230       break;
231     }
232     case Property::VECTOR3:
233     {
234       if( OptionalVector3 v = replacer.IsVector3(node) )
235       {
236         value = *v;
237         done = true;
238       }
239       break;
240     }
241     case Property::VECTOR4:
242     {
243       if( OptionalVector4 v = replacer.IsVector4(node) )
244       {
245         value = *v;
246         done = true;
247       }
248       else if( OptionalString s = replacer.IsString(node) )
249       {
250         if( (*s)[0] == '#' && 7 == (*s).size() )
251         {
252           value = HexStringToVector4( &(*s)[1] );
253           done = true;
254         }
255         else if( Dali::ColorController::Get() )
256         {
257           Vector4 color;
258           done = Dali::ColorController::Get().RetrieveColor( *s, color );
259           value = color;
260         }
261       }
262       else if( TreeNode::OBJECT == node.GetType() )
263       {
264         // check for "r", "g" and "b" child color component nodes
265         OptionalInteger r = replacer.IsInteger( IsChild(node, "r") );
266         OptionalInteger g = replacer.IsInteger( IsChild(node, "g") );
267         OptionalInteger b = replacer.IsInteger( IsChild(node, "b") );
268         if( r && g && b )
269         {
270           float red( (*r) * (1.0f/255.0f) );
271           float green( (*g) * (1.0f/255.0f) );
272           float blue( (*b) * (1.0f/255.0f) );
273           // check for optional "a" (alpha) node, default to fully opaque if it is not found.
274           float alpha( 1.0f );
275           OptionalInteger a = replacer.IsInteger( IsChild(node, "a") );
276           if( a )
277           {
278             alpha = (*a) * (1.0f/255.0f);
279           }
280           value = Vector4( red, green, blue, alpha );
281           done = true;
282         }
283       }
284       break;
285     }
286     case Property::MATRIX3:
287     {
288       if( OptionalMatrix3 v = replacer.IsMatrix3(node) )
289       {
290         value = *v;
291         done = true;
292       }
293       break;
294     }
295     case Property::MATRIX:
296     {
297       if( OptionalMatrix v = replacer.IsMatrix(node) )
298       {
299         value = *v;
300         done = true;
301       }
302       break;
303     }
304     case Property::RECTANGLE:
305     {
306       if( OptionalRect v = replacer.IsRect(node) )
307       {
308         value = *v;
309         done = true;
310       }
311       break;
312     }
313     case Property::ROTATION:
314     {
315       if(4 == node.Size())
316       {
317         if( OptionalVector4 ov = replacer.IsVector4(node) )
318         {
319           const Vector4& v = *ov;
320           // angle, axis as per spec
321           value = Quaternion(Radian(Degree(v[3])),
322                              Vector3(v[0],v[1],v[2]));
323           done = true;
324         }
325       }
326       else
327       {
328         // degrees Euler as per spec
329         if( OptionalVector3 v = replacer.IsVector3(node) )
330         {
331           value = Quaternion(Radian(Degree((*v).x)),
332                              Radian(Degree((*v).y)),
333                              Radian(Degree((*v).z)));
334           done = true;
335         }
336       }
337       break;
338     }
339     case Property::STRING:
340     {
341       if( OptionalString v = replacer.IsString(node) )
342       {
343         value = *v;
344         done = true;
345       }
346       break;
347     }
348     case Property::ARRAY:
349     {
350       if( replacer.IsArray( node, value ) )
351       {
352         done = true;
353       }
354       else if(node.Size())
355       {
356         value = Property::Value(Property::ARRAY);
357         Property::Array* array = value.GetArray();
358         unsigned int i = 0;
359         TreeNode::ConstIterator iter(node.CBegin());
360         for( ; i < node.Size(); ++i, ++iter)
361         {
362           Property::Value childValue;
363           if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
364           {
365             array->PushBack( childValue );
366           }
367         }
368
369         if( array->Count() == node.Size() )
370         {
371           done = true;
372         }
373         else
374         {
375           done = false;
376         }
377       }
378       break;
379     }
380     case Property::MAP:
381     {
382       if( replacer.IsMap( node, value ) )
383       {
384         done = true;
385       }
386       else if(node.Size())
387       {
388         value = Property::Value(Property::MAP);
389         Property::Map* map = value.GetMap();
390         unsigned int i = 0;
391         TreeNode::ConstIterator iter(node.CBegin());
392         for( ; i < node.Size(); ++i, ++iter)
393         {
394           Property::Value childValue;
395           if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
396           {
397             map->Insert( (*iter).first, childValue );
398           }
399         }
400
401         if( map->Count() == node.Size() )
402         {
403           done = true;
404         }
405         else
406         {
407           done = false;
408         }
409       }
410       break;
411     }
412     case Property::TYPE_COUNT:
413     case Property::NONE:
414     {
415       break;
416     }
417   } // switch type
418
419   return done;
420 }
421
422 bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
423
424 {
425   Replacement replacer;
426   return SetPropertyFromNode( node, value, replacer );
427 }
428
429 bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
430                           const Replacement& replacer )
431 {
432   bool done = false;
433
434   // some values are ambiguous as we have no Property::Type but can be disambiguated in the json
435
436   // Currently Rotations and Rectangle must always be disambiguated when a type isnt available
437   if( Disambiguated( node, value, replacer ) )
438   {
439     done = true;
440   }
441   else
442   {
443     if( node.Size() )
444     {
445       // our current heuristic for deciding an array is actually a vector and not say a map
446       // is to check if the values are all floats
447       bool allNumbers = true;
448       for(TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter)
449       {
450         OptionalFloat f = IsFloat((*iter).second);
451         if(!f)
452         {
453           allNumbers = false;
454           break;
455         }
456       }
457
458       if( allNumbers )
459       {
460         // prefer finding vectors over presuming composite Property::Array...
461         if( OptionalMatrix v = IsMatrix(node) )
462         {
463           value = *v;
464           done = true;
465         }
466         else if( OptionalMatrix3 v = IsMatrix3(node) )
467         {
468           value = *v;
469           done = true;
470         }
471         else if( OptionalVector4 v = IsVector4(node) )
472         {
473           value = *v;
474           done = true;
475         }
476         else if( OptionalVector3 v = IsVector3(node) )
477         {
478           value = *v;
479           done = true;
480         }
481         else if( OptionalVector2 v = IsVector2(node) )
482         {
483           value = *v;
484           done = true;
485         }
486         else if( 4 == node.Size() )
487         {
488           if( OptionalVector4 v = IsVector4(node) )
489           {
490             value = *v;
491             done = true;
492           }
493         }
494         else
495         {
496           value = Property::Value(Property::ARRAY);
497           Property::Array* array = value.GetArray();
498
499           for(TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter)
500           {
501             Property::Value childValue;
502             if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
503             {
504               array->PushBack( childValue );
505               done = true;
506             }
507           }
508         }
509       }
510
511       if(!done)
512       {
513         // presume an array or map
514         // container of size 1
515         TreeNode::ConstIterator iter = node.CBegin();
516
517         // its seems legal with current json parser for a map to have an empty key
518         // but here we take that to mean the structure is a list
519         if( ((*iter).first) == 0 )
520         {
521           value = Property::Value(Property::ARRAY);
522           Property::Array* array = value.GetArray();
523           for(unsigned int i = 0; i < node.Size(); ++i, ++iter)
524           {
525             Property::Value childValue;
526             if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
527             {
528               array->PushBack( childValue );
529               done = true;
530             }
531           }
532         }
533         else
534         {
535           value = Property::Value(Property::MAP);
536           Property::Map* map = value.GetMap();
537           for(unsigned int i = 0; i < node.Size(); ++i, ++iter)
538           {
539             Property::Value childValue;
540             if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
541             {
542               map->Insert( (*iter).first, childValue );
543               done = true;
544             }
545           }
546         }
547       } // if!done
548     } // if node.size()
549     else // if( 0 == node.size() )
550     {
551       // no children so either one of bool, float, integer, string
552       OptionalBoolean aBool    = replacer.IsBoolean(node);
553       OptionalInteger anInt    = replacer.IsInteger(node);
554       OptionalFloat   aFloat   = replacer.IsFloat(node);
555       OptionalString  aString  = replacer.IsString(node);
556
557       if(aBool)
558       {
559         // a bool is also an int but here we presume int
560         if(anInt)
561         {
562           value = *anInt;
563           done = true;
564         }
565         else
566         {
567           value = *aBool;
568           done = true;
569         }
570       }
571       else
572       {
573         // Note: These are both floats and strings
574         // {"value":"123"}
575         // {"value":123}
576         // This means we can't have a string with purely numeric content without disambiguation.
577         if(aFloat)
578         {
579           value = *aFloat;
580           done = true;
581         }
582         else if(anInt)
583         {
584           value = *anInt;
585           done = true;
586         }
587         else
588         {
589           // string always succeeds with the current json parser so its last
590           value = *aString;
591           done = true;
592         }
593
594       } // if aBool
595
596     } // if( node.size() )
597
598   } // if Disambiguated()
599
600   return done;
601 } // bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
602
603
604 } // namespace Internal
605
606 } // namespace Toolkit
607
608 } // namespace Dali