7d3c7a515c2c82726fe527d7617e6dc617bde854
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / active-constraint-impl.h
1 #ifndef __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
2 #define __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
3
4 //
5 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
6 //
7 // Licensed under the Flora License, Version 1.0 (the License);
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //     http://floralicense.org/license/
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an AS IS BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19
20 // EXTERNAL INCLUDES
21 #include <set>
22 #include <boost/function.hpp>
23
24 // INTERNAL INCLUDES
25 #include <dali/internal/common/event-to-update.h>
26 #include <dali/internal/common/message.h>
27 #include <dali/internal/event/common/proxy-object.h>
28 #include <dali/internal/event/common/thread-local-storage.h>
29 #include <dali/internal/event/common/stage-impl.h>
30 #include <dali/internal/event/animation/active-constraint-base.h>
31 #include <dali/internal/event/animation/constraint-source-impl.h>
32 #include <dali/internal/event/animation/property-constraint-ptr.h>
33 #include <dali/internal/update/common/animatable-property.h>
34 #include <dali/internal/update/common/property-owner.h>
35 #include <dali/internal/update/common/property-owner-messages.h>
36 #include <dali/internal/update/animation/scene-graph-constraint.h>
37 #include <dali/internal/update/animation/property-accessor.h>
38 #include <dali/internal/update/animation/property-component-accessor.h>
39
40 namespace Dali
41 {
42
43 namespace Internal
44 {
45
46 typedef std::set<ProxyObject*>          ProxyObjectContainer;
47 typedef ProxyObjectContainer::iterator  ProxyObjectIter;
48
49 /**
50  * Connects a constraint which takes another property as an input.
51  */
52 template < typename PropertyType >
53 class ActiveConstraint : public ActiveConstraintBase, public ProxyObject::Observer
54 {
55 public:
56
57   typedef SceneGraph::Constraint< PropertyType, PropertyAccessor<PropertyType> > SceneGraphConstraint;
58   typedef const SceneGraph::AnimatableProperty<PropertyType>* ScenePropertyPtr;
59   typedef typename PropertyConstraintPtr<PropertyType>::Type ConstraintFunctionPtr;
60   typedef boost::function< PropertyType (const PropertyType&, const PropertyType&, float) > InterpolatorFunction;
61
62   /**
63    * Construct a new active-constraint.
64    * @param[in] targetIndex The index of the property to constrain.
65    * @param[in] sources The sources of the input properties passed to func.
66    * @param[in] func The constraint function.
67    * @param[in] interpolator The interpolator function.
68    * @return A newly allocated active-constraint.
69    */
70   static ActiveConstraintBase* New( Property::Index targetIndex,
71                                     SourceContainer& sources,
72                                     ConstraintFunctionPtr func,
73                                     InterpolatorFunction interpolator )
74   {
75     ThreadLocalStorage& tls = ThreadLocalStorage::Get();
76
77     return new ActiveConstraint< PropertyType >( tls.GetEventToUpdate(), targetIndex, sources, sources.size(), func, interpolator );
78   }
79
80   /**
81    * Virtual destructor.
82    */
83   virtual ~ActiveConstraint()
84   {
85     StopObservation();
86
87     // This is not responsible for removing constraints.
88   }
89
90   /**
91    * @copydoc ActiveConstraintBase::Clone()
92    */
93   virtual ActiveConstraintBase* Clone()
94   {
95     ActiveConstraintBase* clone( NULL );
96
97     ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
98
99     clone = new ActiveConstraint< PropertyType >( mEventToUpdate,
100                                                   mTargetIndex,
101                                                   mSources,
102                                                   mSourceCount,
103                                                   funcPtr,
104                                                   mInterpolatorFunction );
105
106     clone->SetRemoveTime(mRemoveTime);
107     clone->SetAlphaFunction(mAlphaFunction);
108     clone->SetRemoveAction(mRemoveAction);
109     clone->SetTag( mTag );
110
111     return clone;
112   }
113
114   /**
115    * @copydoc ActiveConstraintBase::OnFirstApply()
116    */
117   virtual void OnFirstApply( ProxyObject& parent )
118   {
119     DALI_ASSERT_ALWAYS( NULL == mTargetProxy && "Parent of ActiveConstraint already set" );
120
121     // No need to do anything, if the source objects are gone
122     if( mSources.size() == mSourceCount )
123     {
124       mTargetProxy = &parent;
125
126       ObserveProxy( parent );
127
128       ConnectConstraint();
129     }
130   }
131
132   /**
133    * @copydoc ActiveConstraintBase::OnBeginRemove()
134    */
135   virtual void OnBeginRemove()
136   {
137     // Stop observing the remaining proxies
138     StopObservation();
139
140     // Discard all proxy pointers
141     mSources.clear();
142   }
143
144   /**
145    * @copydoc ProxyObject::Observer::SceneObjectAdded()
146    */
147   virtual void SceneObjectAdded( ProxyObject& proxy )
148   {
149     // Should not be getting callbacks when mSources has been cleared
150     DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
151
152     if ( mTargetProxy )
153     {
154       ConnectConstraint();
155     }
156   }
157
158   /**
159    * @copydoc ProxyObject::Observer::SceneObjectRemoved()
160    */
161   virtual void SceneObjectRemoved( ProxyObject& proxy )
162   {
163     // Notify base class that the scene-graph constraint is being removed
164     OnSceneObjectRemove();
165
166     if ( mSceneGraphConstraint )
167     {
168       // Preserve the previous weight
169       mOffstageWeight = mSceneGraphConstraint->GetWeight( mEventToUpdate.GetEventBufferIndex() );
170
171       // This is not responsible for removing constraints.
172       mSceneGraphConstraint = NULL;
173     }
174   }
175
176   /**
177    * @copydoc ProxyObject::Observer::ProxyDestroyed()
178    */
179   virtual void ProxyDestroyed( ProxyObject& proxy )
180   {
181     // Remove proxy pointer from observation set
182     ProxyObjectIter iter = mObservedProxies.find( &proxy );
183     DALI_ASSERT_DEBUG( mObservedProxies.end() != iter );
184     mObservedProxies.erase( iter );
185
186     // Stop observing the remaining proxies
187     StopObservation();
188
189     // Discard all proxy pointers
190     mTargetProxy = NULL;
191     mSources.clear();
192   }
193
194 private:
195
196   /**
197    * Private constructor; see also ActiveConstraint::New().
198    */
199   ActiveConstraint( EventToUpdate& eventToUpdate,
200                     Property::Index targetIndex,
201                     SourceContainer& sources,
202                     unsigned int sourceCount,
203                     ConstraintFunctionPtr& func,
204                     InterpolatorFunction& interpolator )
205   : ActiveConstraintBase( eventToUpdate, targetIndex ),
206     mTargetIndex( targetIndex ),
207     mSources( sources ),
208     mSourceCount( sourceCount ),
209     mUserFunction( func ),
210     mInterpolatorFunction( interpolator )
211   {
212     // Skip init when any of the proxy objects have been destroyed
213     if ( mSources.size() != mSourceCount )
214     {
215       // Discard all proxy pointers
216       mTargetProxy = NULL;
217       mSources.clear();
218     }
219
220     // Observe the objects providing properties
221     for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
222     {
223       if ( OBJECT_PROPERTY == iter->sourceType )
224       {
225         DALI_ASSERT_ALWAYS( NULL != iter->object && "ActiveConstraint source object not found" );
226
227         ObserveProxy( *(iter->object) );
228       }
229     }
230   }
231
232   // Undefined
233   ActiveConstraint( const ActiveConstraint& );
234
235   // Undefined
236   ActiveConstraint& operator=( const ActiveConstraint& rhs );
237
238   /**
239    * Helper to observe a proxy, if not already observing it
240    */
241   void ObserveProxy( ProxyObject& proxy )
242   {
243     if ( mObservedProxies.end() == mObservedProxies.find(&proxy) )
244     {
245       proxy.AddObserver( *this );
246       mObservedProxies.insert( &proxy );
247     }
248   }
249
250   /**
251    * Helper to stop observing proxies
252    */
253   void StopObservation()
254   {
255     for( ProxyObjectIter iter = mObservedProxies.begin(); mObservedProxies.end() != iter; ++iter )
256     {
257       (*iter)->RemoveObserver( *this );
258     }
259
260     mObservedProxies.clear();
261   }
262
263   /**
264    * Create and connect a constraint for a scene-object.
265    */
266   void ConnectConstraint()
267   {
268     // Should not come here any proxies have been destroyed
269     DALI_ASSERT_DEBUG( NULL != mTargetProxy );
270     DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
271
272     // Guard against double connections
273     DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
274
275     // Short-circuit until the target scene-object exists
276     SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetProxy->GetSceneObject() );
277     if ( NULL == targetObject )
278     {
279       return;
280     }
281
282     // Build a set of property-owners, providing the scene-graph properties
283     SceneGraph::PropertyOwnerSet propertyOwners;
284     propertyOwners.insert( targetObject );
285
286     // Build the constraint function; this requires a scene-graph property from each source
287     ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
288
289     if ( func )
290     {
291       // Create the SceneGraphConstraint, and connect to the scene-graph
292
293       const SceneGraph::PropertyBase* targetProperty = mTargetProxy->GetSceneObjectAnimatableProperty( mTargetIndex );
294
295       // The targetProperty should exist, when targetObject exists
296       DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
297
298       // Connect the constraint
299       SceneGraph::ConstraintBase* sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
300                                                                                      propertyOwners,
301                                                                                      func,
302                                                                                      mInterpolatorFunction );
303       DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
304       sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
305       sceneGraphConstraint->SetRemoveAction( mRemoveAction );
306
307       // object is being used in a separate thread; queue a message to apply the constraint
308       ApplyConstraintMessage( Stage::GetCurrent()->GetUpdateInterface(), *targetObject, *sceneGraphConstraint );
309
310       // Keep a raw-pointer to the scene-graph constraint
311       mSceneGraphConstraint = sceneGraphConstraint;
312
313       // Notify ProxyObject base-class that the scene-graph constraint has been added
314       OnSceneObjectAdd();
315     }
316   }
317
318   /**
319    * Helper for ConnectConstraint. Creates a connected constraint-function.
320    * Also populates the property-owner set, for each input connected to the constraint-function.
321    * @param[out] propertyOwners The set of property-owners providing the scene-graph properties.
322    * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
323    */
324   PropertyConstraintBase<PropertyType>* ConnectConstraintFunction( SceneGraph::PropertyOwnerSet& propertyOwners )
325   {
326     PropertyConstraintBase<PropertyType>* func = mUserFunction->Clone();
327     bool usingComponentFunc( false );
328
329     for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
330     {
331       Source& source = *iter;
332
333       PropertyInputImpl* inputProperty( NULL );
334       int componentIndex( Property::INVALID_COMPONENT_INDEX );
335
336       if ( OBJECT_PROPERTY == source.sourceType )
337       {
338         DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
339
340         SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
341
342         // The property owner will not exist, if the target proxy-object is off-stage
343         if( NULL != owner )
344         {
345           propertyOwners.insert( owner );
346           inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
347           componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
348
349           // The scene-object property should exist, when the property owner exists
350           DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
351         }
352       }
353       else if ( LOCAL_PROPERTY == source.sourceType )
354       {
355         DALI_ASSERT_ALWAYS( mTargetProxy->IsPropertyAConstraintInput( source.propertyIndex ) );
356
357         inputProperty = const_cast< PropertyInputImpl* >( mTargetProxy->GetSceneObjectInputProperty( source.propertyIndex ) );
358         componentIndex = mTargetProxy->GetPropertyComponentIndex( source.propertyIndex );
359
360         // The target scene-object should provide this property
361         DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
362       }
363       else
364       {
365         DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
366
367         ProxyObject* proxyParent = dynamic_cast< Actor& >( *mTargetProxy ).GetParent();
368
369         // This will not exist, if the target proxy-object is off-stage
370         if ( NULL != proxyParent )
371         {
372           DALI_ASSERT_ALWAYS( proxyParent->IsPropertyAConstraintInput( source.propertyIndex ) );
373
374           SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( proxyParent->GetSceneObject() );
375
376           // The property owner will not exist, if the parent proxy-object is off-stage
377           if ( NULL != owner )
378           {
379             propertyOwners.insert( owner );
380             inputProperty = const_cast< PropertyInputImpl* >( proxyParent->GetSceneObjectInputProperty( source.propertyIndex ) );
381             componentIndex = proxyParent->GetPropertyComponentIndex( source.propertyIndex );
382
383             // The scene-object property should exist, when the property owner exists
384             DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
385           }
386         }
387       }
388
389       if ( NULL == inputProperty )
390       {
391         delete func;
392         func = NULL;
393
394         // Exit if a scene-graph object is not available from one of the sources
395         break;
396       }
397       else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
398       {
399         // Special case where component indices are required
400         if ( !usingComponentFunc )
401         {
402           PropertyConstraintBase<PropertyType>* componentFunc = func->CloneComponentFunc();
403           usingComponentFunc = true;
404
405           // Switch to function supporting component indices
406           delete func;
407           func = componentFunc;
408         }
409       }
410
411       func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
412     }
413
414     return func;
415   }
416
417 protected:
418
419   Property::Index mTargetIndex;
420
421   SourceContainer mSources;
422   unsigned int mSourceCount;
423
424   ProxyObjectContainer mObservedProxies; // We don't observe the same object twice
425
426   ConstraintFunctionPtr mUserFunction;
427   InterpolatorFunction mInterpolatorFunction;
428 };
429
430 /**
431  * Variant which allows float components to be animated individually.
432  */
433 template <>
434 class ActiveConstraint<float> : public ActiveConstraintBase, public ProxyObject::Observer
435 {
436 public:
437
438   typedef typename PropertyConstraintPtr<float>::Type ConstraintFunctionPtr;
439   typedef boost::function< float (const float&, const float&, float) > InterpolatorFunction;
440
441   /**
442    * Construct a new active-constraint.
443    * @param[in] targetIndex The index of the property to constrain.
444    * @param[in] sources The sources of the input properties passed to func.
445    * @param[in] func The constraint function.
446    * @param[in] interpolator The interpolator function.
447    * @return A newly allocated active-constraint.
448    */
449   static ActiveConstraintBase* New( Property::Index targetIndex,
450                                     SourceContainer& sources,
451                                     ConstraintFunctionPtr func,
452                                     InterpolatorFunction interpolator )
453   {
454     ThreadLocalStorage& tls = ThreadLocalStorage::Get();
455
456     return new ActiveConstraint< float >( tls.GetEventToUpdate(), targetIndex, sources, sources.size(), func, interpolator );
457   }
458
459   /**
460    * Virtual destructor.
461    */
462   virtual ~ActiveConstraint()
463   {
464     StopObservation();
465
466     // This is not responsible for removing constraints.
467   }
468
469   /**
470    * @copydoc ActiveConstraintBase::Clone()
471    */
472   virtual ActiveConstraintBase* Clone()
473   {
474     ActiveConstraintBase* clone( NULL );
475
476     ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
477
478     clone = new ActiveConstraint< float >( mEventToUpdate,
479                                            mTargetIndex,
480                                            mSources,
481                                            mSourceCount,
482                                            funcPtr,
483                                            mInterpolatorFunction );
484
485     clone->SetRemoveTime(mRemoveTime);
486     clone->SetAlphaFunction(mAlphaFunction);
487     clone->SetRemoveAction(mRemoveAction);
488     clone->SetTag( mTag );
489
490     return clone;
491   }
492
493   /**
494    * @copydoc ActiveConstraintBase::OnFirstApply()
495    */
496   virtual void OnFirstApply( ProxyObject& parent )
497   {
498     DALI_ASSERT_ALWAYS( NULL == mTargetProxy && "Parent of ActiveConstraint already set" );
499
500     // No need to do anything, if the source objects are gone
501     if( mSources.size() == mSourceCount )
502     {
503       mTargetProxy = &parent;
504
505       ObserveProxy( parent );
506
507       ConnectConstraint();
508     }
509   }
510
511   /**
512    * @copydoc ActiveConstraintBase::OnBeginRemove()
513    */
514   virtual void OnBeginRemove()
515   {
516     // Stop observing the remaining proxies
517     StopObservation();
518
519     // Discard all proxy pointers
520     mSources.clear();
521   }
522
523   /**
524    * @copydoc ProxyObject::Observer::SceneObjectAdded()
525    */
526   virtual void SceneObjectAdded( ProxyObject& proxy )
527   {
528     // Should not be getting callbacks when mSources has been cleared
529     DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
530
531     if ( mTargetProxy )
532     {
533       ConnectConstraint();
534     }
535   }
536
537   /**
538    * @copydoc ProxyObject::Observer::SceneObjectRemoved()
539    */
540   virtual void SceneObjectRemoved( ProxyObject& proxy )
541   {
542     // Notify base class that the scene-graph constraint is being removed
543     OnSceneObjectRemove();
544
545     if ( mSceneGraphConstraint )
546     {
547       // Preserve the previous weight
548       mOffstageWeight = mSceneGraphConstraint->GetWeight( mEventToUpdate.GetEventBufferIndex() );
549
550       // This is not responsible for removing constraints.
551       mSceneGraphConstraint = NULL;
552     }
553   }
554
555   /**
556    * @copydoc ProxyObject::Observer::ProxyDestroyed()
557    */
558   virtual void ProxyDestroyed( ProxyObject& proxy )
559   {
560     // Remove proxy pointer from observation set
561     ProxyObjectIter iter = mObservedProxies.find( &proxy );
562     DALI_ASSERT_DEBUG( mObservedProxies.end() != iter );
563     mObservedProxies.erase( iter );
564
565     // Stop observing the remaining proxies
566     StopObservation();
567
568     // Discard all proxy pointers
569     mTargetProxy = NULL;
570     mSources.clear();
571   }
572
573 private:
574
575   /**
576    * Private constructor; see also ActiveConstraint::New().
577    */
578   ActiveConstraint( EventToUpdate& eventToUpdate,
579                     Property::Index targetIndex,
580                     SourceContainer& sources,
581                     unsigned int sourceCount,
582                     ConstraintFunctionPtr& func,
583                     InterpolatorFunction& interpolator )
584   : ActiveConstraintBase( eventToUpdate, targetIndex ),
585     mTargetIndex( targetIndex ),
586     mSources( sources ),
587     mSourceCount( sourceCount ),
588     mUserFunction( func ),
589     mInterpolatorFunction( interpolator )
590   {
591     // Skip init when any of the proxy objects have been destroyed
592     if ( mSources.size() != mSourceCount )
593     {
594       // Discard all proxy pointers
595       mTargetProxy = NULL;
596       mSources.clear();
597     }
598
599     // Observe the objects providing properties
600     for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
601     {
602       if ( OBJECT_PROPERTY == iter->sourceType )
603       {
604         DALI_ASSERT_ALWAYS( NULL != iter->object && "ActiveConstraint source object not found" );
605
606         ObserveProxy( *(iter->object) );
607       }
608     }
609   }
610
611   // Undefined
612   ActiveConstraint( const ActiveConstraint& );
613
614   // Undefined
615   ActiveConstraint& operator=( const ActiveConstraint& rhs );
616
617   /**
618    * Helper to observe a proxy, if not already observing it
619    */
620   void ObserveProxy( ProxyObject& proxy )
621   {
622     if ( mObservedProxies.end() == mObservedProxies.find(&proxy) )
623     {
624       proxy.AddObserver( *this );
625       mObservedProxies.insert( &proxy );
626     }
627   }
628
629   /**
630    * Helper to stop observing proxies
631    */
632   void StopObservation()
633   {
634     for( ProxyObjectIter iter = mObservedProxies.begin(); mObservedProxies.end() != iter; ++iter )
635     {
636       (*iter)->RemoveObserver( *this );
637     }
638
639     mObservedProxies.clear();
640   }
641
642   /**
643    * Create and connect a constraint for a scene-object.
644    */
645   void ConnectConstraint()
646   {
647     // Should not come here any proxies have been destroyed
648     DALI_ASSERT_DEBUG( NULL != mTargetProxy );
649     DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
650
651     // Guard against double connections
652     DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
653
654     // Short-circuit until the target scene-object exists
655     SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetProxy->GetSceneObject() );
656     if ( NULL == targetObject )
657     {
658       return;
659     }
660
661     // Build a set of property-owners, providing the scene-graph properties
662     SceneGraph::PropertyOwnerSet propertyOwners;
663     propertyOwners.insert( targetObject );
664
665     // Build the constraint function; this requires a scene-graph property from each source
666     ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
667
668     if ( func )
669     {
670       // Create the SceneGraphConstraint, and connect to the scene-graph
671
672       const SceneGraph::PropertyBase* targetProperty = mTargetProxy->GetSceneObjectAnimatableProperty( mTargetIndex );
673
674       // The targetProperty should exist, when targetObject exists
675       DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
676
677       const int componentIndex = mTargetProxy->GetPropertyComponentIndex( mTargetIndex );
678
679       SceneGraph::ConstraintBase* sceneGraphConstraint( NULL );
680
681       if ( Property::INVALID_COMPONENT_INDEX == componentIndex )
682       {
683         // Not a Vector3 or Vector4 component, expecting float type
684         DALI_ASSERT_DEBUG( PropertyTypes::Get< float >() == targetProperty->GetType() );
685
686         typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
687
688         sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
689                                                            propertyOwners,
690                                                            func,
691                                                            mInterpolatorFunction );
692       }
693       else
694       {
695         // Expecting Vector3 or Vector4 type
696
697         if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
698         {
699           // Constrain float component of Vector3 property
700
701           if ( 0 == componentIndex )
702           {
703             typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> > SceneGraphConstraint;
704             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
705           }
706           else if ( 1 == componentIndex )
707           {
708             typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> > SceneGraphConstraint;
709             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
710           }
711           else if ( 2 == componentIndex )
712           {
713             typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
714             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
715           }
716         }
717         else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
718         {
719           // Constrain float component of Vector4 property
720
721           if ( 0 == componentIndex )
722           {
723             typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> > SceneGraphConstraint;
724             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
725           }
726           else if ( 1 == componentIndex )
727           {
728             typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> > SceneGraphConstraint;
729             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
730           }
731           else if ( 2 == componentIndex )
732           {
733             typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> > SceneGraphConstraint;
734             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
735           }
736           else if ( 3 == componentIndex )
737           {
738             typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
739             sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction );
740           }
741         }
742       }
743
744       DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
745       sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
746       sceneGraphConstraint->SetRemoveAction( mRemoveAction );
747
748         // object is being used in a separate thread; queue a message to apply the constraint
749       ApplyConstraintMessage( Stage::GetCurrent()->GetUpdateInterface(), *targetObject, *sceneGraphConstraint );
750
751       // Keep a raw-pointer to the scene-graph constraint
752       mSceneGraphConstraint = sceneGraphConstraint;
753
754       // Notify ProxyObject base-class that the scene-graph constraint has been added
755       OnSceneObjectAdd();
756     }
757   }
758
759   /**
760    * Helper for ConnectConstraint. Creates a connected constraint-function.
761    * Also populates the property-owner set, for each input connected to the constraint-function.
762    * @param[out] propertyOwners The set of property-owners providing the scene-graph properties.
763    * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
764    */
765   PropertyConstraintBase<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerSet& propertyOwners )
766   {
767     PropertyConstraintBase<float>* func = mUserFunction->Clone();
768     bool usingComponentFunc( false );
769
770     for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
771     {
772       Source& source = *iter;
773
774       PropertyInputImpl* inputProperty( NULL );
775       int componentIndex( Property::INVALID_COMPONENT_INDEX );
776
777       if ( OBJECT_PROPERTY == source.sourceType )
778       {
779         DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
780
781         SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
782
783         // The property owner will not exist, if the target proxy-object is off-stage
784         if( NULL != owner )
785         {
786           propertyOwners.insert( owner );
787           inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
788           componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
789
790           // The scene-object property should exist, when the property owner exists
791           DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
792         }
793       }
794       else if ( LOCAL_PROPERTY == source.sourceType )
795       {
796         DALI_ASSERT_ALWAYS( mTargetProxy->IsPropertyAConstraintInput( source.propertyIndex ) );
797
798         inputProperty = const_cast< PropertyInputImpl* >( mTargetProxy->GetSceneObjectInputProperty( source.propertyIndex ) );
799         componentIndex = mTargetProxy->GetPropertyComponentIndex( source.propertyIndex );
800
801         // The target scene-object should provide this property
802         DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
803       }
804       else
805       {
806         DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
807
808         ProxyObject* proxyParent = dynamic_cast< Actor& >( *mTargetProxy ).GetParent();
809
810         // This will not exist, if the target proxy-object is off-stage
811         if ( NULL != proxyParent )
812         {
813           DALI_ASSERT_ALWAYS( proxyParent->IsPropertyAConstraintInput( source.propertyIndex ) );
814
815           SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( proxyParent->GetSceneObject() );
816
817           // The property owner will not exist, if the parent proxy-object is off-stage
818           if ( NULL != owner )
819           {
820             propertyOwners.insert( owner );
821             inputProperty = const_cast< PropertyInputImpl* >( proxyParent->GetSceneObjectInputProperty( source.propertyIndex ) );
822             componentIndex = proxyParent->GetPropertyComponentIndex( source.propertyIndex );
823
824             // The scene-object property should exist, when the property owner exists
825             DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
826           }
827         }
828       }
829
830       if ( NULL == inputProperty )
831       {
832         delete func;
833         func = NULL;
834
835         // Exit if a scene-graph object is not available from one of the sources
836         break;
837       }
838       else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
839       {
840         // Special case where component indices are required
841         if ( !usingComponentFunc )
842         {
843           PropertyConstraintBase<float>* componentFunc = func->CloneComponentFunc();
844           usingComponentFunc = true;
845
846           // Switch to function supporting component indices
847           delete func;
848           func = componentFunc;
849         }
850       }
851
852       func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
853     }
854
855     return func;
856   }
857
858 protected:
859
860   Property::Index mTargetIndex;
861
862   SourceContainer mSources;
863   unsigned int mSourceCount;
864
865   ProxyObjectContainer mObservedProxies; // We don't observe the same object twice
866
867   ConstraintFunctionPtr mUserFunction;
868   InterpolatorFunction mInterpolatorFunction;
869 };
870
871 } // namespace Internal
872
873 } // namespace Dali
874
875 #endif // __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__