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