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