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