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