Merge changes I8783ad29,I2c860a84 into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2023 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/devel-api/object/handle-devel.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/internal/common/const-string.h>
28 #include <dali/internal/event/animation/constraint-impl.h>
29 #include <dali/internal/event/common/property-helper.h>
30 #include <dali/internal/event/common/property-notification-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/type-registry-impl.h>
33 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
34 #include <dali/internal/update/common/animatable-property.h>
35 #include <dali/internal/update/common/property-owner-messages.h>
36 #include <dali/internal/update/common/property-owner.h>
37 #include <dali/internal/update/common/uniform-map.h>
38
39 #include <dali/internal/update/common/animatable-property-messages.h>
40
41 using Dali::Internal::SceneGraph::AnimatableProperty;
42 using Dali::Internal::SceneGraph::PropertyBase;
43
44 namespace Dali
45 {
46 namespace Internal
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_view 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.GetStringView();
133     }
134   }
135
136   DALI_LOG_ERROR("Property index %d not found\n", index);
137   return {};
138 }
139
140 Property::Index Object::GetPropertyIndex(KeyRef key) const
141 {
142   Property::Index index = Property::INVALID_INDEX;
143
144   if(key.mType == Property::Key::STRING)
145   {
146     const TypeInfo* typeInfo(GetTypeInfo());
147     if(typeInfo)
148     {
149       index = typeInfo->GetPropertyIndex(key.mString);
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.mType == Property::Key::STRING && custom->name == key.mString) ||
162          (key.mType == Property::Key::INDEX && custom->key == key.mIndex))
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 = ConstString(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 void Object::SetProperties(const Property::Map& properties)
541 {
542   const auto count = properties.Count();
543   for(auto position = 0u; position < count; ++position)
544   {
545     // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
546     // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
547
548     const auto& key           = properties.GetKeyAt(position);
549     const auto  propertyIndex = (key.type == Property::Key::INDEX) ? key.indexKey : GetPropertyIndex(key);
550
551     if(propertyIndex != Property::INVALID_INDEX)
552     {
553       const auto& value = properties.GetValue(position);
554       SetProperty(propertyIndex, value);
555     }
556   }
557 }
558
559 void Object::GetProperties(Property::Map& properties)
560 {
561   properties.Clear();
562
563   Property::IndexContainer indexContainer;
564   GetPropertyIndices(indexContainer);
565
566   for(auto index : indexContainer)
567   {
568     properties[index] = GetProperty(index);
569   }
570 }
571
572 void Object::ReserveCustomProperties(int propertyCount)
573 {
574   mCustomProperties.Reserve(propertyCount);
575   const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
576   ReservePropertiesMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, propertyCount);
577 }
578
579 Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
580 {
581   return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE, true);
582 }
583
584 Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue, bool checkForUniqueName)
585 {
586   return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE, checkForUniqueName);
587 }
588
589 Property::Index Object::RegisterProperty(std::string_view     name,
590                                          Property::Value      propertyValue,
591                                          Property::AccessMode accessMode)
592 {
593   return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode, true);
594 }
595
596 Property::Index Object::RegisterProperty(std::string_view     name,
597                                          Property::Index      key,
598                                          Property::Value      propertyValue,
599                                          Property::AccessMode accessMode,
600                                          bool                 checkForUniqueName)
601 {
602   auto constString = ConstString(name);
603
604   // If property with the required key already exists, then just set it.
605   // Don't search names if checkForUniqueName is false.
606   Property::Index index = Property::INVALID_INDEX;
607   if(key != Property::INVALID_KEY) // Try integer key first if it's valid
608   {
609     index = GetPropertyIndex(key);
610   }
611   if(index == Property::INVALID_INDEX && checkForUniqueName) // try name search if requested
612   {
613     index = GetPropertyIndex(constString);
614   }
615
616   if(index != Property::INVALID_INDEX) // If there was a valid index found by either key, set it.
617   {
618     SetProperty(index, std::move(propertyValue));
619   }
620   else
621   {
622     // Otherwise register the property
623     if(Property::ANIMATABLE == accessMode)
624     {
625       index = RegisterSceneGraphProperty(
626         constString,
627         key,
628         PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
629         std::move(propertyValue));
630       AddUniformMapping(index, constString);
631     }
632     else
633     {
634       // Add entry to the property lookup
635       index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count());
636
637       CustomPropertyMetadata* customProperty =
638         new CustomPropertyMetadata(constString, std::move(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(customProperty->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, ConstString 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     SceneGraph::UniformPropertyMapping map(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, ConstString(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 Handle::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(ConstString name, Property::Index key, Property::Index index, 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, std::move(propertyValue), property));
1162   }
1163   else
1164   {
1165     mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, std::move(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   auto            propertyName = ConstString(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.IsEmpty())
1251         {
1252           if(customProperty->childPropertyIndex != Property::INVALID_INDEX)
1253           {
1254             // Resolve name for any child property with no name
1255             customProperty->name = ConstString(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(), *mUpdateObject, *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(), *mUpdateObject, *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(), *mUpdateObject, *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(), *mUpdateObject, *property, value.Get<float>());
1502       }
1503       else if(entry.componentIndex == 1)
1504       {
1505         SetYComponentMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1506       }
1507       else
1508       {
1509         BakeMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *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(), *mUpdateObject, *property, value.Get<float>());
1523       }
1524       else if(entry.componentIndex == 1)
1525       {
1526         SetYComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1527       }
1528       else if(entry.componentIndex == 2)
1529       {
1530         SetZComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1531       }
1532       else
1533       {
1534         BakeMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *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(), *mUpdateObject, *property, value.Get<float>());
1549       }
1550       else if(entry.componentIndex == 1)
1551       {
1552         SetYComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1553       }
1554       else if(entry.componentIndex == 2)
1555       {
1556         SetZComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1557       }
1558       else if(entry.componentIndex == 3)
1559       {
1560         SetWComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1561       }
1562       else
1563       {
1564         BakeMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *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(), *mUpdateObject, *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(), *mUpdateObject, *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(), *mUpdateObject, *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