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