Merge "Added integer keys for custom properties." into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/common/object-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
27 #include <dali/internal/update/common/animatable-property.h>
28 #include <dali/internal/update/common/property-owner-messages.h>
29 #include <dali/internal/update/common/uniform-map.h>
30 #include <dali/internal/event/animation/constraint-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/property-notification-impl.h>
33 #include <dali/internal/event/common/type-registry-impl.h>
34
35 using Dali::Internal::SceneGraph::AnimatableProperty;
36 using Dali::Internal::SceneGraph::PropertyBase;
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace // unnamed namespace
45 {
46 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES;  // Object provides this capability
47 typedef Dali::Vector<Object::Observer*>::Iterator ObserverIter;
48 typedef Dali::Vector<Object::Observer*>::ConstIterator ConstObserverIter;
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
52 #endif
53
54
55 } // unnamed namespace
56
57 Object::Object()
58 : mEventThreadServices( *Stage::GetCurrent() ),
59   mTypeInfo( NULL ),
60   mConstraints( NULL ),
61   mPropertyNotifications( NULL )
62 {
63 }
64
65 void Object::AddObserver(Observer& observer)
66 {
67   // make sure an observer doesn't observe the same object twice
68   // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
69   DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70
71   mObservers.PushBack( &observer );
72 }
73
74 void Object::RemoveObserver(Observer& observer)
75 {
76   // Find the observer...
77   const ConstObserverIter endIter =  mObservers.End();
78   for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
79   {
80     if( (*iter) == &observer)
81     {
82       mObservers.Erase( iter );
83       break;
84     }
85   }
86   DALI_ASSERT_DEBUG(endIter != mObservers.End());
87 }
88
89 void Object::OnSceneObjectAdd()
90 {
91   // Notification for observers
92   for( ConstObserverIter iter = mObservers.Begin(),  endIter =  mObservers.End(); iter != endIter; ++iter)
93   {
94     (*iter)->SceneObjectAdded(*this);
95   }
96
97   // enable property notifications in scene graph
98   EnablePropertyNotifications();
99 }
100
101 void Object::OnSceneObjectRemove()
102 {
103   // Notification for observers
104   for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
105   {
106     (*iter)->SceneObjectRemoved(*this);
107   }
108
109   // disable property notifications in scene graph
110   DisablePropertyNotifications();
111 }
112
113 int Object::GetPropertyComponentIndex( Property::Index index ) const
114 {
115   int componentIndex = Property::INVALID_COMPONENT_INDEX;
116
117   const TypeInfo* typeInfo( GetTypeInfo() );
118   if ( typeInfo )
119   {
120     componentIndex = typeInfo->GetComponentIndex(index);
121   }
122
123   // For animatable property, check whether it is registered already and register it if not yet.
124   if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) && ( NULL == RegisterAnimatableProperty(index) ) )
125   {
126     componentIndex = Property::INVALID_COMPONENT_INDEX;
127   }
128
129   return componentIndex;
130 }
131
132 bool Object::Supports( Capability capability ) const
133 {
134   return (capability & SUPPORTED_CAPABILITIES);
135 }
136
137 unsigned int Object::GetPropertyCount() const
138 {
139   unsigned int count = GetDefaultPropertyCount();
140
141   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
142
143   const TypeInfo* typeInfo( GetTypeInfo() );
144   if ( typeInfo )
145   {
146     unsigned int manual( typeInfo->GetPropertyCount() );
147     count += manual;
148
149     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties:  %d\n", manual );
150   }
151
152   unsigned int custom( mCustomProperties.Count() );
153   count += custom;
154   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties:  %d\n", custom );
155
156   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties:   %d\n", count );
157
158   return count;
159 }
160
161 std::string Object::GetPropertyName( Property::Index index ) const
162 {
163   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
164
165   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
166   {
167     std::string string;
168
169     const char * propertyName = GetDefaultPropertyName( index );
170     if( propertyName )
171     {
172       string = propertyName;
173     }
174     return string;
175   }
176
177   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
178     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
179   {
180     const TypeInfo* typeInfo( GetTypeInfo() );
181     if ( typeInfo )
182     {
183       return typeInfo->GetPropertyName( index );
184     }
185     else
186     {
187       DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
188     }
189   }
190
191   CustomPropertyMetadata* custom = FindCustomProperty( index );
192   if( custom )
193   {
194     return custom->name;
195   }
196   return "";
197 }
198
199 Property::Index Object::GetPropertyIndex(const std::string& name) const
200 {
201   Property::Index index = GetDefaultPropertyIndex( name );
202
203   if(index == Property::INVALID_INDEX)
204   {
205     const TypeInfo* typeInfo( GetTypeInfo() );
206     if ( typeInfo )
207     {
208       index = typeInfo->GetPropertyIndex( name );
209       if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
210       {
211         // check whether the animatable property is registered already, if not then register one.
212         if ( NULL == RegisterAnimatableProperty(index) )
213         {
214           index = Property::INVALID_INDEX;
215         }
216       }
217     }
218   }
219
220   if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
221   {
222     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
223     const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
224     for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
225     {
226       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
227       if ( custom->name == name )
228       {
229         if ( custom->childPropertyIndex != Property::INVALID_INDEX )
230         {
231           // If it is a child property, return the child property index
232           index = custom->childPropertyIndex;
233         }
234         else
235         {
236           index = count;
237         }
238         break;
239       }
240     }
241   }
242
243   return index;
244 }
245
246 Property::Index Object::GetPropertyIndex( Property::Index key ) const
247 {
248   Property::Index index = Property::INVALID_INDEX;
249
250   if( mCustomProperties.Count() > 0 )
251   {
252     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
253     const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
254     for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
255     {
256       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
257       if( custom->key == key )
258       {
259         if( custom->childPropertyIndex != Property::INVALID_INDEX )
260         {
261           // If it is a child property, return the child property index
262           index = custom->childPropertyIndex;
263         }
264         else
265         {
266           index = count;
267         }
268         break;
269       }
270     }
271   }
272
273   return index;
274 }
275
276 bool Object::IsPropertyWritable( Property::Index index ) const
277 {
278   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
279
280   bool writable = false;
281
282   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
283   {
284     writable = IsDefaultPropertyWritable( index );
285   }
286   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
287   {
288     const TypeInfo* typeInfo( GetTypeInfo() );
289     if ( typeInfo )
290     {
291       writable = typeInfo->IsPropertyWritable( index );
292     }
293     else
294     {
295       DALI_ASSERT_ALWAYS( ! "Invalid property index" );
296     }
297   }
298   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
299   {
300     // Type Registry scene-graph properties are writable.
301     writable = true;
302   }
303   else
304   {
305     CustomPropertyMetadata* custom = FindCustomProperty( index );
306     if( custom )
307     {
308       writable = custom->IsWritable();
309     }
310   }
311
312   return writable;
313 }
314
315 bool Object::IsPropertyAnimatable( Property::Index index ) const
316 {
317   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
318
319   bool animatable = false;
320
321   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
322   {
323     animatable = IsDefaultPropertyAnimatable( index );
324   }
325   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
326   {
327     // Type Registry event-thread only properties are not animatable.
328     animatable = false;
329   }
330   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
331   {
332     // Type Registry scene-graph properties are animatable.
333     animatable = true;
334   }
335   else
336   {
337     CustomPropertyMetadata* custom = FindCustomProperty( index );
338     if( custom )
339     {
340       animatable = custom->IsAnimatable();
341     }
342   }
343
344   return animatable;
345 }
346
347 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
348 {
349   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
350
351   bool isConstraintInput = false;
352
353   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
354   {
355     isConstraintInput = IsDefaultPropertyAConstraintInput( index );
356   }
357   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
358   {
359     // Type Registry event-thread only properties cannot be used as an input to a constraint.
360     isConstraintInput = false;
361   }
362   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
363   {
364     // scene graph properties can be used as input to a constraint.
365     isConstraintInput = true;
366   }
367   else
368   {
369     CustomPropertyMetadata* custom = FindCustomProperty( index );
370     if( custom )
371     {
372       // ... custom properties can be used as input to a constraint.
373       isConstraintInput = true;
374     }
375   }
376
377   return isConstraintInput;
378 }
379
380 Property::Type Object::GetPropertyType( Property::Index index ) const
381 {
382   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
383
384   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
385   {
386     return GetDefaultPropertyType( index );
387   }
388
389   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
390     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
391   {
392     const TypeInfo* typeInfo( GetTypeInfo() );
393     if ( typeInfo )
394     {
395       return typeInfo->GetPropertyType( index );
396     }
397     else
398     {
399       DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
400     }
401   }
402
403   CustomPropertyMetadata* custom = FindCustomProperty( index );
404   if( custom )
405   {
406     return custom->GetType();
407   }
408
409   return Property::NONE;
410 }
411
412 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
413 {
414   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
415
416   bool propertySet( true );
417
418   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
419   {
420     SetDefaultProperty( index, propertyValue );
421   }
422   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
423   {
424     const TypeInfo* typeInfo( GetTypeInfo() );
425     if ( typeInfo )
426     {
427       typeInfo->SetProperty( this, index, propertyValue );
428     }
429     else
430     {
431       DALI_LOG_ERROR("Cannot find property index\n");
432       propertySet = false;
433     }
434   }
435   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
436   {
437     // check whether the animatable property is registered already, if not then register one.
438     AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
439     if(!animatableProperty)
440     {
441       DALI_LOG_ERROR("Cannot find property index\n");
442       propertySet = false;
443     }
444     else
445     {
446       // set the scene graph property value
447       SetSceneGraphProperty( index, *animatableProperty, propertyValue );
448     }
449   }
450   else
451   {
452     CustomPropertyMetadata* custom = FindCustomProperty( index );
453
454     if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
455     {
456       if( !custom )
457       {
458         // If the child property is not registered yet, register it.
459         custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
460         mCustomProperties.PushBack( custom );
461       }
462
463       custom->childPropertyIndex = index;
464
465       // Resolve name for the child property
466       Object* parent = GetParentObject();
467       if( parent )
468       {
469         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
470         if( parentTypeInfo )
471         {
472           custom->name = parentTypeInfo->GetChildPropertyName( index );
473         }
474       }
475     }
476
477     if( custom )
478     {
479       if( custom->IsAnimatable() )
480       {
481         // set the scene graph property value
482         SetSceneGraphProperty( index, *custom, propertyValue );
483       }
484       else if( custom->IsWritable() )
485       {
486         custom->value = propertyValue;
487       }
488       else
489       {
490         // trying to set value on read only property is no-op
491         propertySet = false;
492       }
493     }
494     else
495     {
496       DALI_LOG_ERROR("Invalid property index\n");
497       propertySet = false;
498     }
499   }
500
501   // Let derived classes know that a property has been set
502   // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
503   if ( propertySet )
504   {
505     OnPropertySet(index, propertyValue);
506   }
507 }
508
509 Property::Value Object::GetProperty(Property::Index index) const
510 {
511   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
512
513   Property::Value value;
514
515   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
516   {
517     value = GetDefaultProperty( index );
518   }
519   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
520   {
521     const TypeInfo* typeInfo( GetTypeInfo() );
522     if ( typeInfo )
523     {
524       value = typeInfo->GetProperty( this, index );
525     }
526     else
527     {
528       DALI_LOG_ERROR("Cannot find property index\n");
529     }
530   }
531   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
532   {
533     // check whether the animatable property is registered already, if not then register one.
534     AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
535     if(!animatableProperty)
536     {
537       DALI_LOG_ERROR("Cannot find property index\n");
538     }
539     else
540     {
541       // get the animatable property value
542       value = GetPropertyValue( animatableProperty );
543     }
544   }
545   else if(mCustomProperties.Count() > 0)
546   {
547     CustomPropertyMetadata* custom = FindCustomProperty( index );
548     if(custom)
549     {
550       // get the custom property value
551       value = GetPropertyValue( custom );
552     }
553     else
554     {
555       DALI_LOG_ERROR("Invalid property index\n");
556     }
557   } // if custom
558
559   return value;
560 }
561
562 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
563 {
564   indices.Clear();
565
566   // Default Properties
567   GetDefaultPropertyIndices( indices );
568
569   // Manual Properties
570   const TypeInfo* typeInfo( GetTypeInfo() );
571   if ( typeInfo )
572   {
573     typeInfo->GetPropertyIndices( indices );
574   }
575
576   // Custom Properties
577   if ( mCustomProperties.Count() > 0 )
578   {
579     indices.Reserve( indices.Size() + mCustomProperties.Count() );
580
581     PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
582     const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
583     int i=0;
584     for ( ; iter != endIter; ++iter, ++i )
585     {
586       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
587       if ( custom->childPropertyIndex != Property::INVALID_INDEX )
588       {
589         // If it is a child property, add the child property index
590         indices.PushBack( custom->childPropertyIndex );
591       }
592       else
593       {
594         indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
595       }
596     }
597   }
598 }
599
600 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue) const
601 {
602   // Create a new property
603   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
604
605   switch ( propertyValue.GetType() )
606   {
607     case Property::BOOLEAN:
608     {
609       newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
610       break;
611     }
612
613     case Property::INTEGER:
614     {
615       newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
616       break;
617     }
618
619     case Property::FLOAT:
620     {
621       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
622       break;
623     }
624
625     case Property::VECTOR2:
626     {
627       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
628       break;
629     }
630
631     case Property::VECTOR3:
632     {
633       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
634       break;
635     }
636
637     case Property::VECTOR4:
638     {
639       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
640       break;
641     }
642
643     case Property::MATRIX:
644     {
645       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
646       break;
647     }
648
649     case Property::MATRIX3:
650     {
651       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
652       break;
653     }
654
655     case Property::ROTATION:
656     {
657       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
658       break;
659     }
660
661     case Property::RECTANGLE:
662     case Property::STRING:
663     case Property::ARRAY:
664     case Property::MAP:
665     case Property::NONE:
666     {
667       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
668       break;
669     }
670   }
671
672   // get the scene property owner from derived class
673   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
674   // we can only pass properties to scene graph side if there is a scene object
675   if( scenePropertyOwner )
676   {
677     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
678     const PropertyBase* property = newProperty.Get();
679     if(index >= PROPERTY_CUSTOM_START_INDEX)
680     {
681       DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
682
683       mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue.GetType(), property ) );
684     }
685     else
686     {
687       mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, Property::INVALID_COMPONENT_INDEX, propertyValue.GetType(), property ) ); // base property
688     }
689
690     // queue a message to add the property
691     InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
692
693     // notify the derived class (optional) method in case it needs to do some more work on the new property
694     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
695     NotifyScenePropertyInstalled( *property, name, index );
696
697     return index;
698   }
699   else
700   {
701     // property was orphaned and killed so return invalid index
702     return Property::INVALID_INDEX;
703   }
704 }
705
706 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
707 {
708   return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
709 }
710
711 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
712 {
713   return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
714 }
715
716 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
717 {
718   return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
719 }
720
721 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
722 {
723   // If property with the required key already exists, then just set it.
724   Property::Index index = Property::INVALID_INDEX;
725   if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
726   {
727     index = GetPropertyIndex( key );
728   }
729   if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
730   {
731     index = GetPropertyIndex( name );
732   }
733
734   if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
735   {
736     SetProperty( index, propertyValue );
737   }
738   else
739   {
740     // Otherwise register the property
741
742     if( Property::ANIMATABLE == accessMode )
743     {
744       index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue );
745       AddUniformMapping( index, name );
746     }
747     else
748     {
749       // Add entry to the property lookup
750       index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
751
752       CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
753
754       // Resolve index for the child property
755       Object* parent = GetParentObject();
756       if( parent )
757       {
758         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
759         if( parentTypeInfo )
760         {
761           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
762           if( childPropertyIndex != Property::INVALID_INDEX )
763           {
764             customProperty->childPropertyIndex = childPropertyIndex;
765             index = childPropertyIndex;
766           }
767         }
768       }
769
770       mCustomProperties.PushBack( customProperty );
771     }
772   }
773
774   return index;
775 }
776
777 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
778                                                                 int componentIndex,
779                                                                 const Dali::PropertyCondition& condition)
780 {
781   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
782   {
783     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
784     {
785       DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
786     }
787     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
788     {
789       // check whether the animatable property is registered already, if not then register one.
790       AnimatablePropertyMetadata* animatable = RegisterAnimatableProperty( index );
791       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
792     }
793     else if ( mCustomProperties.Count() > 0 )
794     {
795       CustomPropertyMetadata* custom = FindCustomProperty( index );
796       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
797       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
798     }
799   }
800
801   Dali::Handle self(this);
802   Property target( self, index );
803
804   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
805   Dali::PropertyNotification propertyNotification(internal.Get());
806
807   if( !mPropertyNotifications )
808   {
809     mPropertyNotifications = new PropertyNotificationContainer;
810   }
811   mPropertyNotifications->push_back(propertyNotification);
812
813   return propertyNotification;
814 }
815
816 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
817 {
818   if( mPropertyNotifications )
819   {
820     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
821     while(iter != mPropertyNotifications->end() )
822     {
823       if(*iter == propertyNotification)
824       {
825         mPropertyNotifications->erase(iter);
826         // As we can't ensure all references are removed, we can just disable
827         // the notification.
828         GetImplementation(propertyNotification).Disable();
829         return;
830       }
831       ++iter;
832     }
833   }
834 }
835
836 void Object::RemovePropertyNotifications()
837 {
838   if( mPropertyNotifications )
839   {
840     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
841     while(iter != mPropertyNotifications->end() )
842     {
843       // As we can't ensure all references are removed, we can just disable
844       // the notification.
845       GetImplementation(*iter).Disable();
846       ++iter;
847     }
848
849     mPropertyNotifications->clear();
850   }
851 }
852
853 void Object::EnablePropertyNotifications()
854 {
855   if( mPropertyNotifications )
856   {
857     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
858     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
859
860     for( ; iter != endIter; ++iter )
861     {
862       GetImplementation(*iter).Enable();
863     }
864   }
865 }
866
867 void Object::DisablePropertyNotifications()
868 {
869   if( mPropertyNotifications )
870   {
871     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
872     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
873
874     for( ; iter != endIter; ++iter )
875     {
876       GetImplementation(*iter).Disable();
877     }
878   }
879 }
880
881 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
882 {
883   // Get the address of the property if it's a scene property
884   const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
885
886   // Check instead for newly registered properties
887   if( propertyPtr == NULL )
888   {
889     PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
890     if( animatable != NULL )
891     {
892       propertyPtr = animatable->GetSceneGraphProperty();
893     }
894   }
895
896   if( propertyPtr == NULL )
897   {
898     PropertyMetadata* custom = FindCustomProperty( propertyIndex );
899     if( custom != NULL )
900     {
901       propertyPtr = custom->GetSceneGraphProperty();
902     }
903   }
904
905   if( propertyPtr != NULL )
906   {
907     const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
908
909     if( sceneObject != NULL )
910     {
911       SceneGraph::UniformPropertyMapping* map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
912       // Message takes ownership of Uniform map (and will delete it after copy)
913       AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map);
914     }
915     else
916     {
917       DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
918     }
919   }
920 }
921
922 void Object::RemoveUniformMapping( const std::string& uniformName )
923 {
924   const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
925   RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
926 }
927
928 Property::Value Object::GetPropertyValue( const PropertyMetadata* entry ) const
929 {
930   Property::Value value;
931
932   DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
933
934   if( !entry->IsAnimatable() )
935   {
936     value = entry->value;
937   }
938   else
939   {
940     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
941
942     switch ( entry->GetType() )
943     {
944       case Property::BOOLEAN:
945       {
946         const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
947         DALI_ASSERT_DEBUG( NULL != property );
948
949         value = (*property)[ bufferIndex ];
950         break;
951       }
952
953       case Property::INTEGER:
954       {
955         const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
956         DALI_ASSERT_DEBUG( NULL != property );
957
958         value = (*property)[ bufferIndex ];
959         break;
960       }
961
962       case Property::FLOAT:
963       {
964         const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
965         DALI_ASSERT_DEBUG( NULL != property );
966
967         value = (*property)[ bufferIndex ];
968         break;
969       }
970
971       case Property::VECTOR2:
972       {
973         const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
974         DALI_ASSERT_DEBUG( NULL != property );
975
976         if(entry->componentIndex == 0)
977         {
978           value = (*property)[ bufferIndex ].x;
979         }
980         else if(entry->componentIndex == 1)
981         {
982           value = (*property)[ bufferIndex ].y;
983         }
984         else
985         {
986           value = (*property)[ bufferIndex ];
987         }
988         break;
989       }
990
991       case Property::VECTOR3:
992       {
993         const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
994         DALI_ASSERT_DEBUG( NULL != property );
995
996         if(entry->componentIndex == 0)
997         {
998           value = (*property)[ bufferIndex ].x;
999         }
1000         else if(entry->componentIndex == 1)
1001         {
1002           value = (*property)[ bufferIndex ].y;
1003         }
1004         else if(entry->componentIndex == 2)
1005         {
1006           value = (*property)[ bufferIndex ].z;
1007         }
1008         else
1009         {
1010           value = (*property)[ bufferIndex ];
1011         }
1012         break;
1013       }
1014
1015       case Property::VECTOR4:
1016       {
1017         const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
1018         DALI_ASSERT_DEBUG( NULL != property );
1019
1020         if(entry->componentIndex == 0)
1021         {
1022           value = (*property)[ bufferIndex ].x;
1023         }
1024         else if(entry->componentIndex == 1)
1025         {
1026           value = (*property)[ bufferIndex ].y;
1027         }
1028         else if(entry->componentIndex == 2)
1029         {
1030           value = (*property)[ bufferIndex ].z;
1031         }
1032         else if(entry->componentIndex == 3)
1033         {
1034           value = (*property)[ bufferIndex ].w;
1035         }
1036         else
1037         {
1038           value = (*property)[ bufferIndex ];
1039         }
1040         break;
1041       }
1042
1043       case Property::MATRIX:
1044       {
1045         const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
1046         DALI_ASSERT_DEBUG( NULL != property );
1047
1048         value = (*property)[ bufferIndex ];
1049         break;
1050       }
1051
1052       case Property::MATRIX3:
1053       {
1054         const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
1055         DALI_ASSERT_DEBUG( NULL != property );
1056
1057         value = (*property)[ bufferIndex ];
1058         break;
1059       }
1060
1061       case Property::ROTATION:
1062       {
1063         const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
1064         DALI_ASSERT_DEBUG( NULL != property );
1065
1066         value = (*property)[ bufferIndex ];
1067         break;
1068       }
1069
1070       default:
1071       {
1072         DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
1073         break;
1074       }
1075     } // switch(type)
1076   } // if animatable
1077
1078   return value;
1079 }
1080
1081 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1082 {
1083   switch ( entry.GetType() )
1084   {
1085     case Property::BOOLEAN:
1086     {
1087       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1088       DALI_ASSERT_DEBUG( NULL != property );
1089
1090       // property is being used in a separate thread; queue a message to set the property
1091       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1092       break;
1093     }
1094
1095     case Property::INTEGER:
1096     {
1097       const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1098       DALI_ASSERT_DEBUG( NULL != property );
1099
1100       // property is being used in a separate thread; queue a message to set the property
1101       BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
1102       break;
1103     }
1104
1105     case Property::FLOAT:
1106     {
1107       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1108       DALI_ASSERT_DEBUG( NULL != property );
1109
1110       // property is being used in a separate thread; queue a message to set the property
1111       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1112       break;
1113     }
1114
1115     case Property::VECTOR2:
1116     {
1117       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1118       DALI_ASSERT_DEBUG( NULL != property );
1119
1120       // property is being used in a separate thread; queue a message to set the property
1121       if(entry.componentIndex == 0)
1122       {
1123         SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1124       }
1125       else if(entry.componentIndex == 1)
1126       {
1127         SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1128       }
1129       else
1130       {
1131         BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1132       }
1133       break;
1134     }
1135
1136     case Property::VECTOR3:
1137     {
1138       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1139       DALI_ASSERT_DEBUG( NULL != property );
1140
1141       // property is being used in a separate thread; queue a message to set the property
1142       if(entry.componentIndex == 0)
1143       {
1144         SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1145       }
1146       else if(entry.componentIndex == 1)
1147       {
1148         SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1149       }
1150       else if(entry.componentIndex == 2)
1151       {
1152         SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1153       }
1154       else
1155       {
1156         BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1157       }
1158
1159       break;
1160     }
1161
1162     case Property::VECTOR4:
1163     {
1164       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1165       DALI_ASSERT_DEBUG( NULL != property );
1166
1167       // property is being used in a separate thread; queue a message to set the property
1168       if(entry.componentIndex == 0)
1169       {
1170         SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1171       }
1172       else if(entry.componentIndex == 1)
1173       {
1174         SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1175       }
1176       else if(entry.componentIndex == 2)
1177       {
1178         SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1179       }
1180       else if(entry.componentIndex == 3)
1181       {
1182         SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1183       }
1184       else
1185       {
1186         BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1187       }
1188       break;
1189     }
1190
1191     case Property::ROTATION:
1192     {
1193       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1194       DALI_ASSERT_DEBUG( NULL != property );
1195
1196       // property is being used in a separate thread; queue a message to set the property
1197       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1198       break;
1199     }
1200
1201     case Property::MATRIX:
1202     {
1203       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1204       DALI_ASSERT_DEBUG( NULL != property );
1205
1206       // property is being used in a separate thread; queue a message to set the property
1207       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1208       break;
1209     }
1210
1211     case Property::MATRIX3:
1212     {
1213       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1214       DALI_ASSERT_DEBUG( NULL != property );
1215
1216       // property is being used in a separate thread; queue a message to set the property
1217       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1218       break;
1219     }
1220
1221     default:
1222     {
1223       // non-animatable scene graph property, do nothing
1224     }
1225   }
1226 }
1227
1228 const TypeInfo* Object::GetTypeInfo() const
1229 {
1230   if ( !mTypeInfo )
1231   {
1232     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1233     // especially as the type-info does not change during the life-time of an application
1234
1235     Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1236     if ( typeInfoHandle )
1237     {
1238       mTypeInfo = &GetImplementation( typeInfoHandle );
1239     }
1240   }
1241
1242   return mTypeInfo;
1243 }
1244
1245 void Object::ApplyConstraint( ConstraintBase& constraint )
1246 {
1247   if( !mConstraints )
1248   {
1249     mConstraints = new ConstraintContainer;
1250   }
1251   mConstraints->push_back( Dali::Constraint( &constraint ) );
1252 }
1253
1254 void Object::RemoveConstraint( ConstraintBase& constraint )
1255 {
1256   // NULL if the Constraint sources are destroyed before Constraint::Apply()
1257   if( mConstraints )
1258   {
1259     ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1260     if( it != mConstraints->end() )
1261     {
1262       mConstraints->erase( it );
1263     }
1264   }
1265 }
1266
1267 void Object::RemoveConstraints()
1268 {
1269   // guard against constraint sending messages during core destruction
1270   if( mConstraints && Stage::IsInstalled() )
1271   {
1272     // If we have nothing in the scene-graph, just clear constraint containers
1273     const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1274     if ( NULL != propertyOwner )
1275     {
1276       const ConstraintConstIter endIter = mConstraints->end();
1277       for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1278       {
1279         GetImplementation( *iter ).RemoveInternal();
1280       }
1281     }
1282
1283     delete mConstraints;
1284     mConstraints = NULL;
1285   }
1286 }
1287
1288 void Object::RemoveConstraints( unsigned int tag )
1289 {
1290   // guard against constraint sending messages during core destruction
1291   if( mConstraints && Stage::IsInstalled() )
1292   {
1293     ConstraintIter iter( mConstraints->begin() );
1294     while(iter != mConstraints->end() )
1295     {
1296       ConstraintBase& constraint = GetImplementation( *iter );
1297       if( constraint.GetTag() == tag )
1298       {
1299         GetImplementation( *iter ).RemoveInternal();
1300         iter = mConstraints->erase( iter );
1301       }
1302       else
1303       {
1304         ++iter;
1305       }
1306     }
1307
1308     if ( mConstraints->empty() )
1309     {
1310       delete mConstraints;
1311       mConstraints = NULL;
1312     }
1313   }
1314 }
1315
1316 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1317 {
1318   mTypeInfo = typeInfo;
1319 }
1320
1321 Object::~Object()
1322 {
1323   // Notification for observers
1324   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
1325   {
1326     (*iter)->ObjectDestroyed(*this);
1327   }
1328
1329   delete mConstraints;
1330   delete mPropertyNotifications;
1331 }
1332
1333 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1334 {
1335   CustomPropertyMetadata* property( NULL );
1336   if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1337   {
1338     for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1339     {
1340       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1341       if( custom->childPropertyIndex == index )
1342       {
1343         property = custom;
1344       }
1345     }
1346   }
1347   else
1348   {
1349     int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1350     if( arrayIndex >= 0 )
1351     {
1352       if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1353       {
1354         property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1355       }
1356     }
1357   }
1358   return property;
1359 }
1360
1361 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1362 {
1363   for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1364   {
1365     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1366     if( property->index == index )
1367     {
1368       return property;
1369     }
1370   }
1371   return NULL;
1372 }
1373
1374 AnimatablePropertyMetadata* Object::RegisterAnimatableProperty(Property::Index index) const
1375 {
1376   DALI_ASSERT_ALWAYS( (( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ))
1377                       && "Property index is out of bounds" );
1378
1379   // check whether the animatable property is registered already, if not then register one.
1380   AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1381   if( !animatableProperty )
1382   {
1383     const TypeInfo* typeInfo( GetTypeInfo() );
1384     if( typeInfo )
1385     {
1386       Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1387       if( basePropertyIndex == Property::INVALID_INDEX )
1388       {
1389         // If the property is not a component of a base property, register the whole property itself.
1390         const  std::string& propertyName = typeInfo->GetPropertyName(index);
1391         RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, typeInfo->GetPropertyDefaultValue(index));
1392         AddUniformMapping( index, propertyName );
1393       }
1394       else
1395       {
1396         // Since the property is a component of a base property, check whether the base property is registered.
1397         animatableProperty = FindAnimatableProperty( basePropertyIndex );
1398         if( !animatableProperty )
1399         {
1400           // If the base property is not registered yet, register the base property first.
1401           const  std::string& basePropertyName = typeInfo->GetPropertyName(basePropertyIndex);
1402
1403           if( Property::INVALID_INDEX != RegisterSceneGraphProperty( basePropertyName, Property::INVALID_KEY, basePropertyIndex, Property::Value(typeInfo->GetPropertyType( basePropertyIndex ) ) ) )
1404           {
1405             animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1406             AddUniformMapping( basePropertyIndex, basePropertyName );
1407           }
1408         }
1409
1410         if(animatableProperty)
1411         {
1412           // Create the metadata for the property component.
1413           mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->GetType(), animatableProperty->GetSceneGraphProperty() ) );
1414         }
1415       }
1416
1417       // The metadata has just been added and therefore should be in the end of the vector.
1418       animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1419     }
1420   }
1421
1422   return animatableProperty;
1423 }
1424
1425 void Object::ResolveChildProperties()
1426 {
1427   // Resolve index for the child property
1428   Object* parent = GetParentObject();
1429   if( parent )
1430   {
1431     const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1432     if( parentTypeInfo )
1433     {
1434       // Go through each custom property
1435       for ( int arrayIndex = 0; arrayIndex < (int)mCustomProperties.Count(); arrayIndex++ )
1436       {
1437         CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1438
1439         if( customProperty->name == "" )
1440         {
1441           if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1442           {
1443             // Resolve name for any child property with no name
1444             customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1445           }
1446         }
1447         else
1448         {
1449           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1450           if( childPropertyIndex != Property::INVALID_INDEX )
1451           {
1452             // Resolve index for any property with a name that matches the parent's child property name
1453             customProperty->childPropertyIndex = childPropertyIndex;
1454           }
1455         }
1456       }
1457     }
1458   }
1459 }
1460
1461 } // namespace Internal
1462
1463 } // namespace Dali