10982d31018408d07c338497393fc6ab0455e8a4
[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   delete mConstraints;
974   delete mPropertyNotifications;
975
976   // Guard to allow handle destruction after Core has been destroyed
977   if(Stage::IsInstalled())
978   {
979     if(nullptr != mUpdateObject)
980     {
981       RemoveObjectMessage(GetEventThreadServices().GetUpdateManager(), mUpdateObject);
982     }
983   }
984 }
985
986 void Object::OnSceneObjectAdd()
987 {
988   // Notification for observers
989   for(auto&& item : mObservers)
990   {
991     item->SceneObjectAdded(*this);
992   }
993
994   // enable property notifications in scene graph
995   EnablePropertyNotifications();
996 }
997
998 void Object::OnSceneObjectRemove()
999 {
1000   // Notification for observers
1001   for(auto&& item : mObservers)
1002   {
1003     item->SceneObjectRemoved(*this);
1004   }
1005
1006   // disable property notifications in scene graph
1007   DisablePropertyNotifications();
1008 }
1009
1010 const TypeInfo* Object::GetTypeInfo() const
1011 {
1012   if(!mTypeInfo)
1013   {
1014     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1015     // especially as the type-info does not change during the life-time of an application
1016
1017     TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo(this);
1018     if(typeInfoHandle)
1019     {
1020       mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1021     }
1022   }
1023
1024   return mTypeInfo;
1025 }
1026
1027 CustomPropertyMetadata* Object::FindCustomProperty(Property::Index index) const
1028 {
1029   CustomPropertyMetadata* property = nullptr;
1030   if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
1031   {
1032     for(std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++)
1033     {
1034       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1035       if(custom->childPropertyIndex == index)
1036       {
1037         property = custom;
1038       }
1039     }
1040   }
1041   else
1042   {
1043     int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1044     if(arrayIndex >= 0)
1045     {
1046       if(arrayIndex < static_cast<int32_t>(mCustomProperties.Count())) // we can only access the first 2 billion custom properties
1047       {
1048         property = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1049       }
1050     }
1051   }
1052   return property;
1053 }
1054
1055 AnimatablePropertyMetadata* Object::FindAnimatableProperty(Property::Index index) const
1056 {
1057   for(auto&& entry : mAnimatableProperties)
1058   {
1059     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>(entry);
1060     if(property->index == index)
1061     {
1062       return property;
1063     }
1064   }
1065   return nullptr;
1066 }
1067
1068 Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
1069 {
1070   // Create a new property
1071   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1072
1073   switch(propertyValue.GetType())
1074   {
1075     case Property::BOOLEAN:
1076     {
1077       newProperty = new AnimatableProperty<bool>(propertyValue.Get<bool>());
1078       break;
1079     }
1080
1081     case Property::INTEGER:
1082     {
1083       newProperty = new AnimatableProperty<int32_t>(propertyValue.Get<int32_t>());
1084       break;
1085     }
1086
1087     case Property::FLOAT:
1088     {
1089       newProperty = new AnimatableProperty<float>(propertyValue.Get<float>());
1090       break;
1091     }
1092
1093     case Property::VECTOR2:
1094     {
1095       newProperty = new AnimatableProperty<Vector2>(propertyValue.Get<Vector2>());
1096       break;
1097     }
1098
1099     case Property::VECTOR3:
1100     {
1101       newProperty = new AnimatableProperty<Vector3>(propertyValue.Get<Vector3>());
1102       break;
1103     }
1104
1105     case Property::VECTOR4:
1106     {
1107       newProperty = new AnimatableProperty<Vector4>(propertyValue.Get<Vector4>());
1108       break;
1109     }
1110
1111     case Property::MATRIX:
1112     {
1113       newProperty = new AnimatableProperty<Matrix>(propertyValue.Get<Matrix>());
1114       break;
1115     }
1116
1117     case Property::MATRIX3:
1118     {
1119       newProperty = new AnimatableProperty<Matrix3>(propertyValue.Get<Matrix3>());
1120       break;
1121     }
1122
1123     case Property::ROTATION:
1124     {
1125       newProperty = new AnimatableProperty<Quaternion>(propertyValue.Get<Quaternion>());
1126       break;
1127     }
1128
1129     case Property::RECTANGLE:
1130     case Property::STRING:
1131     case Property::ARRAY:
1132     case Property::MAP:
1133     case Property::EXTENTS:
1134     case Property::NONE:
1135     {
1136       DALI_ASSERT_ALWAYS(!"Property type is not animatable");
1137       break;
1138     }
1139   }
1140
1141   // get the scene property owner
1142   const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1143   // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1144   const PropertyBase* property = newProperty.Get();
1145   if(index >= PROPERTY_CUSTOM_START_INDEX)
1146   {
1147     DALI_ASSERT_ALWAYS(index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered");
1148
1149     mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
1150   }
1151   else
1152   {
1153     mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, std::move(propertyValue), property));
1154   }
1155
1156   // queue a message to add the property
1157   InstallCustomPropertyMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty); // Message takes ownership
1158
1159   return index;
1160 }
1161
1162 void Object::RegisterAnimatableProperty(const TypeInfo&        typeInfo,
1163                                         Property::Index        index,
1164                                         const Property::Value* value) const
1165 {
1166   // If the property is not a component of a base property, register the whole property itself.
1167   auto            propertyName = ConstString(typeInfo.GetPropertyName(index));
1168   Property::Value initialValue;
1169   if(value)
1170   {
1171     initialValue = *value;
1172   }
1173   else
1174   {
1175     initialValue = typeInfo.GetPropertyDefaultValue(index); // recurses type hierarchy
1176     if(Property::NONE == initialValue.GetType())
1177     {
1178       initialValue = Property::Value(typeInfo.GetPropertyType(index)); // recurses type hierarchy
1179     }
1180   }
1181   RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, initialValue);
1182   AddUniformMapping(index, propertyName);
1183 }
1184
1185 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty(Property::Index index, const Property::Value* value) const
1186 {
1187   // property range already checked by calling methods
1188   // check whether the animatable property is registered already, if not then register one.
1189   AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty(index);
1190   if(!animatableProperty)
1191   {
1192     const TypeInfo* typeInfo(GetTypeInfo());
1193     if(typeInfo)
1194     {
1195       Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1196       if(basePropertyIndex == Property::INVALID_INDEX)
1197       {
1198         // If the property is not a component of a base property, register the whole property itself.
1199         RegisterAnimatableProperty(*typeInfo, index, value);
1200       }
1201       else
1202       {
1203         // Since the property is a component of a base property, check whether the base property is registered.
1204         animatableProperty = FindAnimatableProperty(basePropertyIndex);
1205         if(!animatableProperty)
1206         {
1207           // If the base property is not registered yet, register the base property first.
1208           RegisterAnimatableProperty(*typeInfo, basePropertyIndex, value);
1209           animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1210         }
1211
1212         // Create the metadata for the property component.
1213         mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty()));
1214       }
1215
1216       // The metadata has just been added and therefore should be in the end of the vector.
1217       animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1218     }
1219   }
1220
1221   return animatableProperty;
1222 }
1223
1224 void Object::ResolveChildProperties()
1225 {
1226   // Resolve index for the child property
1227   Object* parent = GetParentObject();
1228   if(parent)
1229   {
1230     const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
1231     if(parentTypeInfo)
1232     {
1233       // Go through each custom property
1234       for(auto&& entry : mCustomProperties)
1235       {
1236         CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>(entry);
1237
1238         if(customProperty->name.IsEmpty())
1239         {
1240           if(customProperty->childPropertyIndex != Property::INVALID_INDEX)
1241           {
1242             // Resolve name for any child property with no name
1243             customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
1244           }
1245         }
1246         else
1247         {
1248           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
1249           if(childPropertyIndex != Property::INVALID_INDEX)
1250           {
1251             // Resolve index for any property with a name that matches the parent's child property name
1252             customProperty->childPropertyIndex = childPropertyIndex;
1253           }
1254         }
1255       }
1256     }
1257   }
1258 }
1259
1260 void Object::SetDefaultProperty(Property::Index index, const Property::Value& property)
1261 {
1262   // do nothing
1263 }
1264
1265 Property::Value Object::GetDefaultProperty(Property::Index index) const
1266 {
1267   return Property::Value();
1268 }
1269
1270 Property::Value Object::GetDefaultPropertyCurrentValue(Property::Index index) const
1271 {
1272   return GetDefaultProperty(index);
1273 }
1274
1275 void Object::EnablePropertyNotifications()
1276 {
1277   if(mPropertyNotifications)
1278   {
1279     for(auto&& element : *mPropertyNotifications)
1280     {
1281       GetImplementation(element).Enable();
1282     }
1283   }
1284 }
1285
1286 void Object::DisablePropertyNotifications()
1287 {
1288   if(mPropertyNotifications)
1289   {
1290     for(auto&& element : *mPropertyNotifications)
1291     {
1292       GetImplementation(element).Disable();
1293     }
1294   }
1295 }
1296
1297 Property::Value Object::GetCurrentPropertyValue(const PropertyMetadata& entry) const
1298 {
1299   Property::Value value;
1300
1301   if(!entry.IsAnimatable())
1302   {
1303     value = entry.GetPropertyValue();
1304   }
1305   else
1306   {
1307     BufferIndex bufferIndex(GetEventThreadServices().GetEventBufferIndex());
1308
1309     switch(entry.GetType())
1310     {
1311       case Property::BOOLEAN:
1312       {
1313         const AnimatableProperty<bool>* property = static_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1314         DALI_ASSERT_DEBUG(property);
1315
1316         value = (*property)[bufferIndex];
1317         break;
1318       }
1319
1320       case Property::INTEGER:
1321       {
1322         const AnimatableProperty<int32_t>* property = static_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1323         DALI_ASSERT_DEBUG(property);
1324
1325         value = (*property)[bufferIndex];
1326         break;
1327       }
1328
1329       case Property::FLOAT:
1330       {
1331         const AnimatableProperty<float>* property = static_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1332         DALI_ASSERT_DEBUG(property);
1333
1334         value = (*property)[bufferIndex];
1335         break;
1336       }
1337
1338       case Property::VECTOR2:
1339       {
1340         const AnimatableProperty<Vector2>* property = static_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1341         DALI_ASSERT_DEBUG(property);
1342
1343         if(entry.componentIndex == 0)
1344         {
1345           value = (*property)[bufferIndex].x;
1346         }
1347         else if(entry.componentIndex == 1)
1348         {
1349           value = (*property)[bufferIndex].y;
1350         }
1351         else
1352         {
1353           value = (*property)[bufferIndex];
1354         }
1355         break;
1356       }
1357
1358       case Property::VECTOR3:
1359       {
1360         const AnimatableProperty<Vector3>* property = static_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1361         DALI_ASSERT_DEBUG(property);
1362
1363         if(entry.componentIndex == 0)
1364         {
1365           value = (*property)[bufferIndex].x;
1366         }
1367         else if(entry.componentIndex == 1)
1368         {
1369           value = (*property)[bufferIndex].y;
1370         }
1371         else if(entry.componentIndex == 2)
1372         {
1373           value = (*property)[bufferIndex].z;
1374         }
1375         else
1376         {
1377           value = (*property)[bufferIndex];
1378         }
1379         break;
1380       }
1381
1382       case Property::VECTOR4:
1383       {
1384         const AnimatableProperty<Vector4>* property = static_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1385         DALI_ASSERT_DEBUG(property);
1386
1387         if(entry.componentIndex == 0)
1388         {
1389           value = (*property)[bufferIndex].x;
1390         }
1391         else if(entry.componentIndex == 1)
1392         {
1393           value = (*property)[bufferIndex].y;
1394         }
1395         else if(entry.componentIndex == 2)
1396         {
1397           value = (*property)[bufferIndex].z;
1398         }
1399         else if(entry.componentIndex == 3)
1400         {
1401           value = (*property)[bufferIndex].w;
1402         }
1403         else
1404         {
1405           value = (*property)[bufferIndex];
1406         }
1407         break;
1408       }
1409
1410       case Property::MATRIX:
1411       {
1412         const AnimatableProperty<Matrix>* property = static_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1413         DALI_ASSERT_DEBUG(property);
1414
1415         value = (*property)[bufferIndex];
1416         break;
1417       }
1418
1419       case Property::MATRIX3:
1420       {
1421         const AnimatableProperty<Matrix3>* property = static_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1422         DALI_ASSERT_DEBUG(property);
1423
1424         value = (*property)[bufferIndex];
1425         break;
1426       }
1427
1428       case Property::ROTATION:
1429       {
1430         const AnimatableProperty<Quaternion>* property = static_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1431         DALI_ASSERT_DEBUG(property);
1432
1433         value = (*property)[bufferIndex];
1434         break;
1435       }
1436
1437       default:
1438       {
1439         // unreachable code due to higher level logic
1440       }
1441     } // switch(type)
1442   }   // if animatable
1443
1444   return value;
1445 }
1446
1447 void Object::SetSceneGraphProperty(Property::Index index, const PropertyMetadata& entry, const Property::Value& value)
1448 {
1449   switch(entry.GetType())
1450   {
1451     case Property::BOOLEAN:
1452     {
1453       const AnimatableProperty<bool>* property = dynamic_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1454       DALI_ASSERT_DEBUG(property);
1455
1456       // property is being used in a separate thread; queue a message to set the property
1457       BakeMessage<bool>(GetEventThreadServices(), *property, value.Get<bool>());
1458       break;
1459     }
1460
1461     case Property::INTEGER:
1462     {
1463       const AnimatableProperty<int32_t>* property = dynamic_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1464       DALI_ASSERT_DEBUG(property);
1465
1466       // property is being used in a separate thread; queue a message to set the property
1467       BakeMessage<int32_t>(GetEventThreadServices(), *property, value.Get<int32_t>());
1468       break;
1469     }
1470
1471     case Property::FLOAT:
1472     {
1473       const AnimatableProperty<float>* property = dynamic_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1474       DALI_ASSERT_DEBUG(property);
1475
1476       // property is being used in a separate thread; queue a message to set the property
1477       BakeMessage<float>(GetEventThreadServices(), *property, value.Get<float>());
1478       break;
1479     }
1480
1481     case Property::VECTOR2:
1482     {
1483       const AnimatableProperty<Vector2>* property = dynamic_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1484       DALI_ASSERT_DEBUG(property);
1485
1486       // property is being used in a separate thread; queue a message to set the property
1487       if(entry.componentIndex == 0)
1488       {
1489         SetXComponentMessage<Vector2>(GetEventThreadServices(), *property, value.Get<float>());
1490       }
1491       else if(entry.componentIndex == 1)
1492       {
1493         SetYComponentMessage<Vector2>(GetEventThreadServices(), *property, value.Get<float>());
1494       }
1495       else
1496       {
1497         BakeMessage<Vector2>(GetEventThreadServices(), *property, value.Get<Vector2>());
1498       }
1499       break;
1500     }
1501
1502     case Property::VECTOR3:
1503     {
1504       const AnimatableProperty<Vector3>* property = dynamic_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1505       DALI_ASSERT_DEBUG(property);
1506
1507       // property is being used in a separate thread; queue a message to set the property
1508       if(entry.componentIndex == 0)
1509       {
1510         SetXComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1511       }
1512       else if(entry.componentIndex == 1)
1513       {
1514         SetYComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1515       }
1516       else if(entry.componentIndex == 2)
1517       {
1518         SetZComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1519       }
1520       else
1521       {
1522         BakeMessage<Vector3>(GetEventThreadServices(), *property, value.Get<Vector3>());
1523       }
1524
1525       break;
1526     }
1527
1528     case Property::VECTOR4:
1529     {
1530       const AnimatableProperty<Vector4>* property = dynamic_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1531       DALI_ASSERT_DEBUG(property);
1532
1533       // property is being used in a separate thread; queue a message to set the property
1534       if(entry.componentIndex == 0)
1535       {
1536         SetXComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1537       }
1538       else if(entry.componentIndex == 1)
1539       {
1540         SetYComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1541       }
1542       else if(entry.componentIndex == 2)
1543       {
1544         SetZComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1545       }
1546       else if(entry.componentIndex == 3)
1547       {
1548         SetWComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1549       }
1550       else
1551       {
1552         BakeMessage<Vector4>(GetEventThreadServices(), *property, value.Get<Vector4>());
1553       }
1554       break;
1555     }
1556
1557     case Property::ROTATION:
1558     {
1559       const AnimatableProperty<Quaternion>* property = dynamic_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1560       DALI_ASSERT_DEBUG(property);
1561
1562       // property is being used in a separate thread; queue a message to set the property
1563       BakeMessage<Quaternion>(GetEventThreadServices(), *property, value.Get<Quaternion>());
1564       break;
1565     }
1566
1567     case Property::MATRIX:
1568     {
1569       const AnimatableProperty<Matrix>* property = dynamic_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1570       DALI_ASSERT_DEBUG(property);
1571
1572       // property is being used in a separate thread; queue a message to set the property
1573       BakeMessage<Matrix>(GetEventThreadServices(), *property, value.Get<Matrix>());
1574       break;
1575     }
1576
1577     case Property::MATRIX3:
1578     {
1579       const AnimatableProperty<Matrix3>* property = dynamic_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1580       DALI_ASSERT_DEBUG(property);
1581
1582       // property is being used in a separate thread; queue a message to set the property
1583       BakeMessage<Matrix3>(GetEventThreadServices(), *property, value.Get<Matrix3>());
1584       break;
1585     }
1586
1587     default:
1588     {
1589       // non-animatable scene graph property, do nothing
1590     }
1591   }
1592 }
1593
1594 } // namespace Internal
1595
1596 } // namespace Dali