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