Merge "TextField to consume TouchEvents" into 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 <boost/function.hpp>
20 #include <dali/public-api/actors/layer.h>
21 #include <dali/public-api/common/vector-wrapper.h>
22 #include <dali/public-api/object/type-info.h>
23 #include <dali/public-api/object/property-notification.h>
24 #include <dali/integration-api/debug.h>
25 #include <limits>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/builder/builder-impl.h>
29 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
30
31 namespace Dali
32 {
33 namespace Toolkit
34 {
35 namespace Internal
36 {
37 extern Animation CreateAnimation( const TreeNode& child, Dali::Toolkit::Internal::Builder* const builder  );
38 extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
39 }
40 }
41 }
42
43 namespace
44 {
45 using namespace Dali;
46
47 //
48 // Signal Actions
49 //
50
51 // Action on child actor. The child is found by name
52 struct ChildActorAction
53 {
54   std::string actorName;
55   std::string actionName;
56   std::string childName;
57   PropertyValueContainer parameters;
58
59   void operator()(void)
60   {
61     Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
62
63     if(actor)
64     {
65       Actor child_actor = actor.FindChildByName(childName);
66
67       if(child_actor)
68       {
69         child_actor.DoAction(actionName, parameters);
70       }
71       else
72       {
73         DALI_SCRIPT_WARNING("Could not find child by name '%s'\n", childName.c_str());
74       }
75     }
76   };
77 };
78
79 // Action to set a property
80 struct PropertySetAction
81 {
82   std::string actorName;
83   std::string propertyName;
84   Property::Value value;
85
86   void operator()(void)
87   {
88     Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
89
90     if(actor)
91     {
92       Property::Index idx = actor.GetPropertyIndex(propertyName);
93
94       if( idx != Property::INVALID_INDEX )
95       {
96         if( actor.GetPropertyType(idx) != value.GetType() )
97         {
98           DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
99         }
100         else
101         {
102           actor.SetProperty( idx, value );
103         }
104       }
105       else
106       {
107         DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
108       }
109     }
110   };
111 };
112
113 // Generic action on a handle (Animation & Actor)
114 struct GenericAction
115 {
116   std::string actorName;
117   std::string actionName;
118   PropertyValueContainer parameters;
119
120   void operator()(void)
121   {
122     Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
123     if(actor)
124     {
125       actor.DoAction(actionName, parameters);
126     }
127
128   };
129 };
130
131 // Delay an animation play; ie wait as its not on stage yet
132 struct DelayedAnimationPlay
133 {
134   OptionalChild                                         animNode;
135   Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
136
137   void operator()(void)
138   {
139     Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
140     if(anim)
141     {
142       anim.Play();
143     }
144   };
145 };
146
147 // Delay a pathConstrainer apply
148 struct DelayedConstrainerApply
149 {
150   std::string     constrainerName;
151
152   std::vector<std::string> targetActorNames;
153   std::vector<std::string> sourceActorNames;
154   std::vector<std::string> targetPropertyNames;
155   std::vector<std::string> sourcePropertyNames;
156   std::vector<Vector2>  ranges;
157   std::vector<Vector2>  wrapRanges;
158
159   Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
160
161   /*
162    * Helper function to get the parameters to apply each constraint
163    * @param[in] i i-essim element
164    * @param[out] tagetActor Target actor for the constraint
165    * @param[out] tagetPropertyIndex Target property index for the constraint
166    * @param[out] sourceActor Source actor for the constraint
167    * @param[out] sourcePropertyIndex Source property index for the constraint
168    */
169   bool GetApplyParameters( size_t i,
170                            Actor& targetActor, Property::Index& targetPropertyIndex,
171                            Actor& sourceActor, Property::Index& sourcePropertyIndex)
172   {
173
174     targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
175     targetPropertyIndex = Property::INVALID_INDEX;
176     if(targetActor)
177     {
178       targetPropertyIndex = targetActor.GetPropertyIndex(targetPropertyNames[i]);
179       if( targetPropertyIndex ==  Property::INVALID_INDEX )
180       {
181         DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", targetPropertyNames[i].c_str(), targetActorNames[i].c_str() );
182         return false;
183       }
184     }
185     else
186     {
187       DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
188       return false;
189     }
190
191
192     sourceActor = Stage::GetCurrent().GetRootLayer().FindChildByName(sourceActorNames[i]);
193     sourcePropertyIndex = Property::INVALID_INDEX;
194     if(sourceActor)
195     {
196       sourcePropertyIndex = sourceActor.GetPropertyIndex(sourcePropertyNames[i]);
197       if( sourcePropertyIndex ==  Property::INVALID_INDEX )
198       {
199         DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", sourcePropertyNames[i].c_str(), sourceActorNames[i].c_str() );
200         return false;
201       }
202     }
203     else
204     {
205       DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
206       return false;
207     }
208     return true;
209   }
210
211   void operator()(void)
212   {
213     Actor sourceActor, targetActor;
214     Property::Index targetPropertyIndex(Property::INVALID_INDEX);
215     Property::Index sourcePropertyIndex(Property::INVALID_INDEX);
216     size_t actorCount( targetActorNames.size() );
217     if( builder.Get()->IsPathConstrainer( constrainerName ))
218     {
219       PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
220       if( constrainer )
221       {
222         for(size_t i(0); i<actorCount; ++i )
223         {
224
225           if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
226           {
227             constrainer.Apply( Property(targetActor,targetPropertyIndex),
228                                Property(sourceActor,sourcePropertyIndex),
229                                ranges[i],
230                                wrapRanges[i]);
231           }
232         }
233       }
234       else
235       {
236         DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
237       }
238     }
239     else if( builder.Get()->IsLinearConstrainer( constrainerName ) )
240     {
241       Dali::LinearConstrainer constrainer( builder.Get()->GetLinearConstrainer(constrainerName));
242       if( constrainer )
243       {
244         for(size_t i(0); i<actorCount; ++i )
245         {
246
247           if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
248           {
249             constrainer.Apply( Property(targetActor,targetPropertyIndex),
250                                Property(sourceActor,sourcePropertyIndex),
251                                ranges[i],
252                                wrapRanges[i]);
253           }
254         }
255       }
256       else
257       {
258         DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
259       }
260     }
261     else
262     {
263       DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
264     }
265   }
266 };
267
268 // Delay a pathConstrainer remove
269 struct DelayedConstrainerRemove
270 {
271   std::string     constrainerName;
272   std::vector<std::string> targetActorNames;
273   Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
274
275   void operator()(void)
276   {
277     size_t actorCount( targetActorNames.size() );
278     if( builder.Get()->IsPathConstrainer( constrainerName ))
279     {
280       PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
281       if( constrainer )
282       {
283         for(size_t i(0); i<actorCount; ++i )
284         {
285           Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
286           if(targetActor)
287           {
288             constrainer.Remove( targetActor );
289           }
290         }
291       }
292       else
293       {
294         DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
295       }
296     }
297     else if(builder.Get()->IsLinearConstrainer( constrainerName ))
298     {
299       LinearConstrainer constrainer = builder.Get()->GetLinearConstrainer(constrainerName);
300       if( constrainer )
301       {
302         for(size_t i(0); i<actorCount; ++i )
303         {
304           Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
305           if(targetActor)
306           {
307             constrainer.Remove( targetActor );
308           }
309         }
310       }
311       else
312       {
313         DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
314       }
315     }
316     else
317     {
318       DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
319     }
320   }
321 };
322
323 /*
324  * Gets Property::Value from child
325  */
326 Property::Value GetPropertyValue(const TreeNode &child)
327 {
328   size_t nChildren = child.Size();
329
330   Property::Value ret;
331
332   if(0 == nChildren)
333   {
334     // cast away unused return for static analyzers
335     static_cast<void>( Dali::Toolkit::Internal::SetPropertyFromNode( child, ret ) );
336   }
337   else if(1 == nChildren)
338   {
339     // {"property": {"quaternion":[1,2,3,4]} }
340     // {"property": {"angle":22, "axis": [1,2,3]} }
341
342     OptionalChild quaternion  = IsChild(&child, "quaternion");
343     OptionalChild axis        = IsChild(&child, "axis");
344     OptionalChild angle       = IsChild(&child, "angle");
345
346     if(quaternion)
347     {
348       ret = Property::Value(Quaternion(GetVector4(*quaternion)));
349     }
350     else if(axis && angle)
351     {
352       ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
353     }
354   }
355   else if(2 == nChildren)
356   {
357     // {"property": [1,2]}
358     ret = Property::Value(GetVector2(child));
359   }
360   else if(3 == nChildren)
361   {
362     // {"property": [1,2,3]}
363     ret = Property::Value(GetVector3(child));
364   }
365   else if(4 == nChildren)
366   {
367     // {"property": [1,2,3,4]}
368     ret = Property::Value(GetVector4(child));
369   }
370
371   return ret;
372 }
373
374
375 /*
376  * Gets Parmeter list from child
377  * params is be cleared before insertion
378  */
379 void GetParameters(const TreeNode& child, PropertyValueContainer& params)
380 {
381   if( OptionalChild c = IsChild(child, "parameters") )
382   {
383     const TreeNode& node = *c;
384
385     if(0 == node.Size())
386     {
387       GetPropertyValue(node);
388     }
389     else
390     {
391       params.clear();
392       params.reserve(node.Size());
393
394       for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
395       {
396         params.push_back( GetPropertyValue( (*iter).second ) );
397       }
398     }
399   }
400 }
401
402 void DoNothing(void) {};
403
404 /**
405  * Get an action as boost function callback
406  */
407 boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder)
408 {
409   OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
410   OptionalString actorName(IsString( IsChild(&child, "actor")) );
411   OptionalString propertyName(IsString( IsChild(&child, "property")) );
412   OptionalChild  valueChild( IsChild(&child, "value") );
413
414   OptionalString actionName = IsString( IsChild(&child, "action") );
415   DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
416
417   boost::function<void(void)> callback = DoNothing;
418
419   if(childActorName)
420   {
421     ChildActorAction action;
422     action.actorName       = *actorName;
423     action.childName       = *childActorName;
424     action.actionName      = *actionName;
425     GetParameters(child, action.parameters);
426     callback = action;
427   }
428   else if(actorName)
429   {
430     if(propertyName && valueChild && ("set" == *actionName) )
431     {
432       PropertySetAction action;
433       action.actorName       = *actorName;
434       action.propertyName    = *propertyName;
435       // actor may not exist yet so we can't check the property type
436       if( !Dali::Toolkit::Internal::SetPropertyFromNode( *valueChild, action.value ) )
437       {
438         DALI_SCRIPT_WARNING("Cannot set property for set property action\n");
439       }
440       callback = action;
441     }
442     else
443     {
444       GenericAction action;
445       action.actorName       = *actorName;
446       action.actionName      = *actionName;
447       GetParameters(child, action.parameters);
448       callback = action;
449     }
450   }
451   else if("quit" == *actionName)
452   {
453     callback = quitAction;
454   }
455   else if("play" == *actionName)
456   {
457     OptionalChild animations     = IsChild( root, "animations" );
458     OptionalString animationName = IsString( IsChild(child, "animation") );
459     if( animations && animationName )
460     {
461       if( OptionalChild animNode = IsChild(*animations, *animationName) )
462       {
463         DelayedAnimationPlay action;
464         action.animNode = animNode;
465         action.builder = builder;
466         // @todo; put constants into the map
467         callback = action;
468       }
469       else
470       {
471         DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
472       }
473     }
474     else
475     {
476       DALI_SCRIPT_WARNING("Cannot find animations section\n");
477     }
478   }
479   else if("applyConstraint" == *actionName )
480   {
481     OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
482     if( !constrainerName )
483     {
484       DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
485     }
486     else
487     {
488       DelayedConstrainerApply action;
489       action.constrainerName = *constrainerName;
490       action.builder = builder;
491       OptionalChild propertiesNode = IsChild(child, "properties");
492       if(propertiesNode)
493       {
494         const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
495         for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
496         {
497           const TreeNode::KeyNodePair& pKeyChild = *iter;
498           OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
499           if(!sourceActorName)
500           {
501             DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
502             continue;
503           }
504           OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
505           if(!sourcePropertyName)
506           {
507             DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
508             continue;
509           }
510
511           OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
512           if(!targetActorName)
513           {
514             DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
515             continue;
516           }
517
518           OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
519           if(!targetPropertyName)
520           {
521             DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
522             continue;
523           }
524
525           OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
526           if(!range)
527           {
528             DALI_SCRIPT_WARNING("Constrainer range not specified\n");
529             continue;
530           }
531
532           Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
533           OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
534           if(wrapRange)
535           {
536             wrap = *wrapRange;
537           }
538
539           action.sourceActorNames.push_back(*sourceActorName);
540           action.sourcePropertyNames.push_back(*sourcePropertyName);
541           action.targetActorNames.push_back(*targetActorName);
542           action.targetPropertyNames.push_back(*targetPropertyName);
543           action.ranges.push_back(*range);
544           action.wrapRanges.push_back(wrap);
545         }
546
547         callback = action;
548       }
549     }
550
551
552   }
553   else if("removeConstraints" == *actionName )
554   {
555     OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
556     if( !constrainerName )
557     {
558       DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
559     }
560     else
561     {
562
563       DelayedConstrainerRemove action;
564       action.constrainerName = *constrainerName;
565       action.builder = builder;
566       OptionalChild propertiesNode = IsChild(child, "properties");
567       if(propertiesNode)
568       {
569         const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
570         for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
571         {
572           const TreeNode::KeyNodePair& pKeyChild = *iter;
573           OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
574           if(targetActorName)
575           {
576             action.targetActorNames.push_back(*targetActorName);
577           }
578           else
579           {
580             DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
581             continue;
582           }
583         }
584       }
585       callback = action;
586     }
587   }
588   else
589   {
590     // no named actor; presume self
591     GenericAction action;
592     action.actorName       = actor.GetName();
593     action.actionName      = *actionName;
594     GetParameters(child, action.parameters);
595     callback = action;
596   }
597
598   return callback;
599 }
600
601
602 /**
603  * Get a notification condition argument0 as 'arg0' 'value' or 'min'
604  */
605 float GetConditionArg0(const TreeNode &child)
606 {
607   OptionalFloat f = IsFloat( IsChild(child, "arg0") );
608   // allowing some human preferable alternatives
609   if(!f)
610   {
611     f = IsFloat( IsChild(child, "value") );
612   }
613   if(!f)
614   {
615     f = IsFloat( IsChild(child, "min") );
616   }
617
618   DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
619
620   return *f;
621 }
622
623 /**
624  * Get a notification condition argument1 as 'arg1' or 'max'
625  */
626 float GetConditionArg1(const TreeNode &child)
627 {
628   OptionalFloat f = IsFloat( IsChild(child, "arg1") );
629   // allowing some human preferable alternatives
630   if(!f)
631   {
632     f = IsFloat( IsChild(child, "max") );
633   }
634
635   DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
636
637   return *f;
638 }
639
640
641
642 }; // anon namespace
643
644 namespace Dali
645 {
646 namespace Toolkit
647 {
648 namespace Internal
649 {
650
651 Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
652 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
653
654 /**
655  * Setup signals and actions on an actor
656  */
657 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
658 {
659   DALI_ASSERT_ALWAYS(actor);
660
661   if(OptionalChild signalsChild = IsChild(child, "signals"))
662   {
663     const TreeNode& signalsNode = *signalsChild;
664     const TreeConstIter endIter = signalsNode.CEnd();
665     for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
666     {
667       const TreeNode::KeyNodePair& key_child = *iter;
668
669       DALI_SCRIPT_INFO("  Creating Signal for: %s\n", actor.GetName().c_str());
670
671       OptionalString name( IsString( IsChild( key_child.second, "name")) );
672       DALI_ASSERT_ALWAYS(name && "Signal must have a name");
673
674       boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
675
676       actor.ConnectSignal(tracker, *name, callback);
677     }
678   }
679
680   return actor;
681 }
682
683 /**
684  * Setup Property notifications for an actor
685  */
686 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
687 {
688   DALI_ASSERT_ALWAYS(actor);
689
690   if(OptionalChild notificationsChild = IsChild(child,"notifications"))
691   {
692     const TreeNode& notificationsNode = *notificationsChild;
693     const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
694     for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
695     {
696       const TreeNode::KeyNodePair& key_child = *iter;
697
698       // Actor actions reference by pointer because of circular reference actor->signal
699       // So this callback should only go onto the actor maintained list.
700       boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
701
702       OptionalString prop(IsString( IsChild(key_child.second, "property")) );
703       DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
704
705       Property::Index prop_index = actor.GetPropertyIndex(*prop);
706       DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
707
708       OptionalString cond(IsString( IsChild(key_child.second, "condition")));
709       DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
710
711       if("False" == *cond)
712       {
713         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
714                                                                            LessThanCondition(1.f) );
715         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
716       }
717       else if("LessThan" == *cond)
718       {
719         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
720                                                                            LessThanCondition(GetConditionArg0(key_child.second)) );
721         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
722       }
723       else if("GreaterThan" == *cond)
724       {
725         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
726                                                                            GreaterThanCondition(GetConditionArg0(key_child.second)) );
727         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
728       }
729       else if("Inside" == *cond)
730       {
731         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
732                                                                            InsideCondition(GetConditionArg0(key_child.second),
733                                                                            GetConditionArg1(key_child.second)) );
734         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
735       }
736       else if("Outside" == *cond)
737       {
738         PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
739                                                                            OutsideCondition(GetConditionArg0(key_child.second),
740                                                                            GetConditionArg1(key_child.second)) );
741         notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
742       }
743       else
744       {
745         DALI_ASSERT_ALWAYS(!"Unknown condition");
746       }
747     }
748   } // if notifications
749
750   return actor;
751
752 } // AddPropertyNotification
753
754
755 } // namespace Internal
756 } // namespace Toolkit
757 } // namespace Dali