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