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