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