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