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