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