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