[dali_1.0.29] Merge branch 'tizen'
[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 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, Dali::Toolkit::Internal::Builder* const builder  );
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   PropertyValueContainer 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   PropertyValueContainer 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   OptionalChild                                         animNode;
130   Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
131
132   void operator()(void)
133   {
134     Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
135     if(anim)
136     {
137       anim.Play();
138     }
139   };
140 };
141
142 /*
143  * Gets Property::Value from child
144  */
145 Property::Value GetPropertyValue(const TreeNode &child)
146 {
147   size_t nChildren = child.Size();
148
149   Property::Value ret;
150
151   if(0 == nChildren)
152   {
153     // cast away unused return for static analyzers
154     static_cast<void>( Dali::Toolkit::Internal::SetPropertyFromNode( child, ret ) );
155   }
156   else if(1 == nChildren)
157   {
158     // {"property": {"quaternion":[1,2,3,4]} }
159     // {"property": {"angle":22, "axis": [1,2,3]} }
160
161     OptionalChild quaternion  = IsChild(&child, "quaternion");
162     OptionalChild axis        = IsChild(&child, "axis");
163     OptionalChild angle       = IsChild(&child, "angle");
164
165     if(quaternion)
166     {
167       ret = Property::Value(Quaternion(GetVector4(*quaternion)));
168     }
169     else if(axis && angle)
170     {
171       ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
172     }
173   }
174   else if(2 == nChildren)
175   {
176     // {"property": [1,2]}
177     ret = Property::Value(GetVector2(child));
178   }
179   else if(3 == nChildren)
180   {
181     // {"property": [1,2,3]}
182     ret = Property::Value(GetVector3(child));
183   }
184   else if(4 == nChildren)
185   {
186     // {"property": [1,2,3,4]}
187     ret = Property::Value(GetVector4(child));
188   }
189
190   return ret;
191 }
192
193
194 /*
195  * Gets Parmeter list from child
196  * params is be cleared before insertion
197  */
198 void GetParameters(const TreeNode& child, PropertyValueContainer& params)
199 {
200   if( OptionalChild c = IsChild(child, "parameters") )
201   {
202     const TreeNode& node = *c;
203
204     if(0 == node.Size())
205     {
206       GetPropertyValue(node);
207     }
208     else
209     {
210       params.clear();
211       params.reserve(node.Size());
212
213       for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
214       {
215         params.push_back( GetPropertyValue( (*iter).second ) );
216       }
217     }
218   }
219 }
220
221 void DoNothing(void) {};
222
223 /**
224  * Get an action as boost function callback
225  */
226 boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder)
227 {
228   OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
229   OptionalString actorName(IsString( IsChild(&child, "actor")) );
230   OptionalString propertyName(IsString( IsChild(&child, "property")) );
231   OptionalChild  valueChild( IsChild(&child, "value") );
232
233   OptionalString actionName = IsString( IsChild(&child, "action") );
234   DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
235
236   boost::function<void(void)> callback = DoNothing;
237
238   if(childActorName)
239   {
240     ChildActorAction action;
241     action.actorName       = *actorName;
242     action.childAlias      = *childActorName;
243     action.actionName      = *actionName;
244     GetParameters(child, action.parameters);
245     callback = action;
246   }
247   else if(actorName)
248   {
249     if(propertyName && valueChild && ("set" == *actionName) )
250     {
251       PropertySetAction action;
252       action.actorName       = *actorName;
253       action.propertyName    = *propertyName;
254       // actor may not exist yet so we can't check the property type
255       if( !Dali::Toolkit::Internal::SetPropertyFromNode( *valueChild, action.value ) )
256       {
257         DALI_SCRIPT_WARNING("Cannot set property for set property action\n");
258       }
259       callback = action;
260     }
261     else
262     {
263       GenericAction action;
264       action.actorName       = *actorName;
265       action.actionName      = *actionName;
266       GetParameters(child, action.parameters);
267       callback = action;
268     }
269   }
270   else if("quit" == *actionName)
271   {
272     callback = quitAction;
273   }
274   else if("play" == *actionName)
275   {
276     OptionalChild animations     = IsChild( root, "animations" );
277     OptionalString animationName = IsString( IsChild(child, "animation") );
278     if( animations && animationName )
279     {
280       if( OptionalChild animNode = IsChild(*animations, *animationName) )
281       {
282         DelayedAnimationPlay action;
283         action.animNode = animNode;
284         action.builder = builder;
285         // @todo; put constants into the map
286         callback = action;
287       }
288       else
289       {
290         DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
291       }
292     }
293     else
294     {
295       DALI_SCRIPT_WARNING("Cannot find animations section\n");
296     }
297   }
298   else
299   {
300     // no named actor; presume self
301     GenericAction action;
302     action.actorName       = actor.GetName();
303     action.actionName      = *actionName;
304     GetParameters(child, action.parameters);
305     callback = action;
306   }
307
308   return callback;
309 }
310
311
312 /**
313  * Get a notification condition argument0 as 'arg0' 'value' or 'min'
314  */
315 float GetConditionArg0(const TreeNode &child)
316 {
317   OptionalFloat f = IsFloat( IsChild(child, "arg0") );
318   // allowing some human preferable alternatives
319   if(!f)
320   {
321     f = IsFloat( IsChild(child, "value") );
322   }
323   if(!f)
324   {
325     f = IsFloat( IsChild(child, "min") );
326   }
327
328   DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
329
330   return *f;
331 }
332
333 /**
334  * Get a notification condition argument1 as 'arg1' or 'max'
335  */
336 float GetConditionArg1(const TreeNode &child)
337 {
338   OptionalFloat f = IsFloat( IsChild(child, "arg1") );
339   // allowing some human preferable alternatives
340   if(!f)
341   {
342     f = IsFloat( IsChild(child, "max") );
343   }
344
345   DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
346
347   return *f;
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, Dali::Toolkit::Internal::Builder* const builder );
362 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
363
364 /**
365  * Setup signals and actions on an actor
366  */
367 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
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, quitAction, builder );
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, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
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, quitAction, builder );
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