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