Merge "(Builder) Added Quit Signal" into tizen
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / builder / builder-signals.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 <dali/integration-api/debug.h>
20 #include <boost/function.hpp>
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
26 namespace Dali
27 {
28 namespace Toolkit
29 {
30 namespace Internal
31 {
32 extern Animation CreateAnimation( const TreeNode& child );
33 extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
34 }
35 }
36 }
37
38 namespace
39 {
40 using namespace Dali;
41
42 //
43 // Signal Actions
44 //
45
46 // Action on child actor. The child is found by alias so can be 'previous' etc.
47 struct ChildActorAction
48 {
49   std::string actorName;
50   std::string actionName;
51   std::string childAlias;
52   std::vector<Property::Value> parameters;
53
54   void operator()(void)
55   {
56     Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
57
58     if(actor)
59     {
60       Actor child_actor = actor.FindChildByAlias(childAlias);
61
62       if(child_actor)
63       {
64         child_actor.DoAction(actionName, parameters);
65       }
66       else
67       {
68         DALI_SCRIPT_WARNING("Could not find child by alias '%s'\n", childAlias.c_str());
69       }
70     }
71   };
72 };
73
74 // Action to set a property
75 struct PropertySetAction
76 {
77   std::string actorName;
78   std::string propertyName;
79   Property::Value value;
80
81   void operator()(void)
82   {
83     Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
84
85     if(actor)
86     {
87       Property::Index idx = actor.GetPropertyIndex(propertyName);
88
89       if( idx != Property::INVALID_INDEX )
90       {
91         if( actor.GetPropertyType(idx) != value.GetType() )
92         {
93           DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
94         }
95         else
96         {
97           actor.SetProperty( idx, value );
98         }
99       }
100       else
101       {
102         DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
103       }
104     }
105   };
106 };
107
108 // Generic action on a handle (Animation & Actor)
109 struct GenericAction
110 {
111   std::string actorName;
112   std::string actionName;
113   std::vector<Property::Value> parameters;
114
115   void operator()(void)
116   {
117     Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
118     if(actor)
119     {
120       actor.DoAction(actionName, parameters);
121     }
122
123   };
124 };
125
126 // Delay an animation play; ie wait as its not on stage yet
127 struct DelayedAnimationPlay
128 {
129   Toolkit::JsonParser memento;
130
131   void operator()(void)
132   {
133     Animation anim = Toolkit::Internal::CreateAnimation(*memento.GetRoot());
134     if(anim)
135     {
136       anim.Play();
137     }
138   };
139 };
140
141 /*
142  * Gets Property::Value from child
143  */
144 Property::Value GetPropertyValue(const TreeNode &child)
145 {
146   size_t nChildren = child.Size();
147
148   Property::Value ret;
149
150   if(0 == nChildren)
151   {
152     // cast away unused return for static analyzers
153     static_cast<void>( Dali::Toolkit::Internal::SetPropertyFromNode( child, ret ) );
154   }
155   else if(1 == nChildren)
156   {
157     // {"property": {"quaternion":[1,2,3,4]} }
158     // {"property": {"angle":22, "axis": [1,2,3]} }
159
160     OptionalChild quaternion  = IsChild(&child, "quaternion");
161     OptionalChild axis        = IsChild(&child, "axis");
162     OptionalChild angle       = IsChild(&child, "angle");
163
164     if(quaternion)
165     {
166       ret = Property::Value(Quaternion(GetVector4(*quaternion)));
167     }
168     else if(axis && angle)
169     {
170       ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
171     }
172   }
173   else if(2 == nChildren)
174   {
175     // {"property": [1,2]}
176     ret = Property::Value(GetVector2(child));
177   }
178   else if(3 == nChildren)
179   {
180     // {"property": [1,2,3]}
181     ret = Property::Value(GetVector3(child));
182   }
183   else if(4 == nChildren)
184   {
185     // {"property": [1,2,3,4]}
186     ret = Property::Value(GetVector4(child));
187   }
188
189   return ret;
190 }
191
192
193 /*
194  * Gets Parmeter list from child
195  * params is be cleared before insertion
196  */
197 void GetParameters(const TreeNode &child, std::vector<Property::Value> &params)
198 {
199   if( OptionalChild c = IsChild(child, "parameters") )
200   {
201     const TreeNode& node = *c;
202
203     if(0 == node.Size())
204     {
205       GetPropertyValue(node);
206     }
207     else
208     {
209       params.clear();
210       params.reserve(node.Size());
211
212       for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
213       {
214         params.push_back( GetPropertyValue( (*iter).second ) );
215       }
216     }
217   }
218 }
219
220 void DoNothing(void) {};
221
222 /**
223  * Get an action as boost function callback
224  */
225 boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction)
226 {
227   OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
228   OptionalString actorName(IsString( IsChild(&child, "actor")) );
229   OptionalString propertyName(IsString( IsChild(&child, "property")) );
230   OptionalChild  valueChild( IsChild(&child, "value") );
231
232   OptionalString actionName = IsString( IsChild(&child, "action") );
233   DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
234
235   boost::function<void(void)> callback = DoNothing;
236
237   if(childActorName)
238   {
239     ChildActorAction action;
240     action.actorName       = *actorName;
241     action.childAlias      = *childActorName;
242     action.actionName      = *actionName;
243     GetParameters(child, action.parameters);
244     callback = action;
245   }
246   else if(actorName)
247   {
248     if(propertyName && valueChild && ("set" == *actionName) )
249     {
250       PropertySetAction action;
251       action.actorName       = *actorName;
252       action.propertyName    = *propertyName;
253       // actor may not exist yet so we can't check the property type
254       if( !Dali::Toolkit::Internal::SetPropertyFromNode( *valueChild, action.value ) )
255       {
256         DALI_SCRIPT_WARNING("Cannot set property for set property action\n");
257       }
258       callback = action;
259     }
260     else
261     {
262       GenericAction action;
263       action.actorName       = *actorName;
264       action.actionName      = *actionName;
265       GetParameters(child, action.parameters);
266       callback = action;
267     }
268   }
269   else if("quit" == *actionName)
270   {
271     callback = quitAction;
272   }
273   else if("play" == *actionName)
274   {
275     OptionalChild animations     = IsChild( root, "animations" );
276     OptionalString animationName = IsString( IsChild(child, "animation") );
277     if( animations && animationName )
278     {
279       if( OptionalChild animNode = IsChild(*animations, *animationName) )
280       {
281         DelayedAnimationPlay action;
282         action.memento = Toolkit::JsonParser::New(*animNode);
283         // @todo; put constants into the map
284         callback = action;
285       }
286       else
287       {
288         DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
289       }
290     }
291     else
292     {
293       DALI_SCRIPT_WARNING("Cannot find animations section\n");
294     }
295   }
296   else
297   {
298     // no named actor; presume self
299     GenericAction action;
300     action.actorName       = actor.GetName();
301     action.actionName      = *actionName;
302     GetParameters(child, action.parameters);
303     callback = action;
304   }
305
306   return callback;
307 }
308
309
310 /**
311  * Get a notification condition argument0 as 'arg0' 'value' or 'min'
312  */
313 float GetConditionArg0(const TreeNode &child)
314 {
315   OptionalFloat f = IsFloat( IsChild(child, "arg0") );
316   // allowing some human preferable alternatives
317   if(!f)
318   {
319     f = IsFloat( IsChild(child, "value") );
320   }
321   if(!f)
322   {
323     f = IsFloat( IsChild(child, "min") );
324   }
325   DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
326   if(f)
327   {
328     return *f;
329   }
330   else
331   {
332     return 0.f;
333   }
334 }
335
336 /**
337  * Get a notification condition argument1 as 'arg1' or 'max'
338  */
339 float GetConditionArg1(const TreeNode &child)
340 {
341   OptionalFloat f = IsFloat( IsChild(child, "arg1") );
342   // allowing some human preferable alternatives
343   if(!f)
344   {
345     f = IsFloat( IsChild(child, "max") );
346   }
347   DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
348   if(f)
349   {
350     return *f;
351   }
352   else
353   {
354     return 0.f;
355   }
356 }
357
358
359
360 }; // anon namespace
361
362 namespace Dali
363 {
364 namespace Toolkit
365 {
366 namespace Internal
367 {
368
369 Actor SetupSignalAction(const TreeNode &child, Actor actor);
370 Actor SetupPropertyNotification(const TreeNode &child, Actor actor);
371
372 /**
373  * Setup signals and actions on an actor
374  */
375 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction)
376 {
377   DALI_ASSERT_ALWAYS(actor);
378
379   if(OptionalChild signalsChild = IsChild(child, "signals"))
380   {
381     const TreeNode& signalsNode = *signalsChild;
382     const TreeConstIter endIter = signalsNode.CEnd();
383     for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
384     {
385       const TreeNode::KeyNodePair& key_child = *iter;
386
387       DALI_SCRIPT_INFO("  Creating Signal for: %s\n", actor.GetName().c_str());
388
389       OptionalString name( IsString( IsChild( key_child.second, "name")) );
390       DALI_ASSERT_ALWAYS(name && "Signal must have a name");
391
392       boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction);
393
394       actor.ConnectSignal(tracker, *name, callback);
395     }
396   }
397
398   return actor;
399 }
400
401 /**
402  * Setup Property notifications for an actor
403  */
404 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction)
405 {
406   DALI_ASSERT_ALWAYS(actor);
407
408   if(OptionalChild notificationsChild = IsChild(child,"notifications"))
409   {
410     const TreeNode& notificationsNode = *notificationsChild;
411     const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
412     for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
413     {
414       const TreeNode::KeyNodePair& key_child = *iter;
415
416       // Actor actions reference by pointer because of circular reference actor->signal
417       // So this callback should only go onto the actor maintained list.
418       boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction);
419
420       OptionalString prop(IsString( IsChild(key_child.second, "property")) );
421       DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
422
423       Property::Index prop_index = actor.GetPropertyIndex(*prop);
424       DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
425
426       OptionalString cond(IsString( IsChild(key_child.second, "condition")));
427       DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
428
429       if("False" == *cond)
430       {
431         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
432                                                                            LessThanCondition(1.f) );
433         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
434       }
435       else if("LessThan" == *cond)
436       {
437         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
438                                                                            LessThanCondition(GetConditionArg0(key_child.second)) );
439         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
440       }
441       else if("GreaterThan" == *cond)
442       {
443         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
444                                                                            GreaterThanCondition(GetConditionArg0(key_child.second)) );
445         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
446       }
447       else if("Inside" == *cond)
448       {
449         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
450                                                                            InsideCondition(GetConditionArg0(key_child.second),
451                                                                            GetConditionArg1(key_child.second)) );
452         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
453       }
454       else if("Outside" == *cond)
455       {
456         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
457                                                                            OutsideCondition(GetConditionArg0(key_child.second),
458                                                                            GetConditionArg1(key_child.second)) );
459         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
460       }
461       else
462       {
463         DALI_ASSERT_ALWAYS(!"Unknown condition");
464       }
465     }
466   } // if notifications
467
468   return actor;
469
470 } // AddPropertyNotification
471
472
473 } // namespace Internal
474 } // namespace Toolkit
475 } // namespace Dali