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