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