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