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