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