DALi Version 2.2.14
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2022 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 void Object::SetProperties(const Property::Map& properties)
539 {
540   const auto count = properties.Count();
541   for(auto position = 0u; position < count; ++position)
542   {
543     // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
544     // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
545
546     const auto& key           = properties.GetKeyAt(position);
547     const auto  propertyIndex = (key.type == Property::Key::INDEX) ? key.indexKey : GetPropertyIndex(key);
548
549     if(propertyIndex != Property::INVALID_INDEX)
550     {
551       const auto& value = properties.GetValue(position);
552       SetProperty(propertyIndex, value);
553     }
554   }
555 }
556
557 void Object::GetProperties(Property::Map& properties)
558 {
559   properties.Clear();
560
561   Property::IndexContainer indexContainer;
562   GetPropertyIndices(indexContainer);
563
564   for(auto index : indexContainer)
565   {
566     properties[index] = GetProperty(index);
567   }
568 }
569
570 void Object::ReserveCustomProperties(int propertyCount)
571 {
572   mCustomProperties.Reserve(propertyCount);
573   const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
574   ReservePropertiesMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, propertyCount);
575 }
576
577 Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
578 {
579   return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE, true);
580 }
581
582 Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue, bool checkForUniqueName)
583 {
584   return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE, checkForUniqueName);
585 }
586
587 Property::Index Object::RegisterProperty(std::string_view     name,
588                                          Property::Value      propertyValue,
589                                          Property::AccessMode accessMode)
590 {
591   return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode, true);
592 }
593
594 Property::Index Object::RegisterProperty(std::string_view     name,
595                                          Property::Index      key,
596                                          Property::Value      propertyValue,
597                                          Property::AccessMode accessMode,
598                                          bool                 checkForUniqueName)
599 {
600   auto constString = ConstString(name);
601
602   // If property with the required key already exists, then just set it.
603   // Don't search names if checkForUniqueName is false.
604   Property::Index index = Property::INVALID_INDEX;
605   if(key != Property::INVALID_KEY) // Try integer key first if it's valid
606   {
607     index = GetPropertyIndex(key);
608   }
609   if(index == Property::INVALID_INDEX && checkForUniqueName) // try name search if requested
610   {
611     index = GetPropertyIndex(constString);
612   }
613
614   if(index != Property::INVALID_INDEX) // If there was a valid index found by either key, set it.
615   {
616     SetProperty(index, std::move(propertyValue));
617   }
618   else
619   {
620     // Otherwise register the property
621     if(Property::ANIMATABLE == accessMode)
622     {
623       index = RegisterSceneGraphProperty(
624         constString,
625         key,
626         PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
627         std::move(propertyValue));
628       AddUniformMapping(index, constString);
629     }
630     else
631     {
632       // Add entry to the property lookup
633       index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count());
634
635       CustomPropertyMetadata* customProperty =
636         new CustomPropertyMetadata(constString, std::move(propertyValue), accessMode);
637
638       // Resolve index for the child property
639       Object* parent = GetParentObject();
640       if(parent)
641       {
642         const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
643         if(parentTypeInfo)
644         {
645           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
646           if(childPropertyIndex != Property::INVALID_INDEX)
647           {
648             customProperty->childPropertyIndex = childPropertyIndex;
649             index                              = childPropertyIndex;
650           }
651         }
652       }
653
654       mCustomProperties.PushBack(customProperty);
655     }
656   }
657
658   return index;
659 }
660
661 bool Object::DoesCustomPropertyExist(Property::Index index)
662 {
663   auto metadata = FindCustomProperty(index);
664   return metadata != nullptr;
665 }
666
667 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index                index,
668                                                            int32_t                        componentIndex,
669                                                            const Dali::PropertyCondition& condition)
670 {
671   if(index >= DEFAULT_PROPERTY_MAX_COUNT)
672   {
673     if(index <= PROPERTY_REGISTRATION_MAX_INDEX)
674     {
675       DALI_ABORT("Property notification added to event side only property.");
676     }
677     else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
678     {
679       // check whether the animatable property is registered already, if not then register one.
680       AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
681       DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
682     }
683     else if(mCustomProperties.Count() > 0)
684     {
685       CustomPropertyMetadata* custom = FindCustomProperty(index);
686       DALI_ASSERT_ALWAYS(custom && "Invalid property index");
687       DALI_ASSERT_ALWAYS(custom->IsAnimatable() && "Property notification added to event side only property.");
688     }
689   }
690
691   Dali::Handle self(this);
692   Property     target(self, index);
693
694   PropertyNotificationPtr    internal = PropertyNotification::New(target, componentIndex, condition);
695   Dali::PropertyNotification propertyNotification(internal.Get());
696
697   if(!mPropertyNotifications)
698   {
699     mPropertyNotifications = new PropertyNotificationContainer;
700   }
701   mPropertyNotifications->push_back(propertyNotification);
702
703   return propertyNotification;
704 }
705
706 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
707 {
708   if(mPropertyNotifications)
709   {
710     auto iter = mPropertyNotifications->begin();
711     while(iter != mPropertyNotifications->end())
712     {
713       if(*iter == propertyNotification)
714       {
715         mPropertyNotifications->erase(iter);
716         // As we can't ensure all references are removed, we can just disable
717         // the notification.
718         GetImplementation(propertyNotification).Disable();
719         return;
720       }
721       ++iter;
722     }
723   }
724 }
725
726 void Object::RemovePropertyNotifications()
727 {
728   if(mPropertyNotifications)
729   {
730     auto iter = mPropertyNotifications->begin();
731     while(iter != mPropertyNotifications->end())
732     {
733       // As we can't ensure all references are removed, we can just disable
734       // the notification.
735       GetImplementation(*iter).Disable();
736       ++iter;
737     }
738
739     mPropertyNotifications->clear();
740   }
741 }
742
743 void Object::NotifyPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
744 {
745   if(index < DEFAULT_PROPERTY_MAX_COUNT)
746   {
747     OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
748   }
749   else
750   {
751     PropertyMetadata* propertyMetadata = nullptr;
752     if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
753     {
754       propertyMetadata = FindAnimatableProperty(index);
755     }
756     else
757     {
758       CustomPropertyMetadata* custom = FindCustomProperty(index);
759       if(custom && custom->IsAnimatable())
760       {
761         propertyMetadata = custom;
762       }
763     }
764
765     if(propertyMetadata)
766     {
767       switch(animationType)
768       {
769         case Animation::TO:
770         case Animation::BETWEEN:
771         {
772           // Update the cached property value
773           propertyMetadata->SetPropertyValue(value);
774           break;
775         }
776         case Animation::BY:
777         {
778           // Adjust the cached property value
779           propertyMetadata->AdjustPropertyValueBy(value);
780           break;
781         }
782       }
783     }
784   }
785 }
786
787 void Object::AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const
788 {
789   // Get the address of the property if it's a scene property
790   const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty(propertyIndex);
791
792   // Check instead for newly registered properties
793   if(propertyPtr == nullptr)
794   {
795     PropertyMetadata* animatable = FindAnimatableProperty(propertyIndex);
796     if(animatable)
797     {
798       propertyPtr = animatable->GetSceneGraphProperty();
799     }
800   }
801
802   if(propertyPtr == nullptr)
803   {
804     PropertyMetadata* custom = FindCustomProperty(propertyIndex);
805     if(custom)
806     {
807       propertyPtr = custom->GetSceneGraphProperty();
808     }
809   }
810
811   if(propertyPtr)
812   {
813     const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
814
815     SceneGraph::UniformPropertyMapping map(uniformName, propertyPtr);
816     // Message takes ownership of Uniform map (and will delete it after copy)
817     AddUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map);
818   }
819 }
820
821 void Object::RemoveUniformMapping(const std::string& uniformName) const
822 {
823   const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
824   RemoveUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
825 }
826
827 void Object::ApplyConstraint(ConstraintBase& constraint)
828 {
829   if(!mConstraints)
830   {
831     mConstraints = new ConstraintContainer;
832   }
833   mConstraints->push_back(Dali::Constraint(&constraint));
834 }
835
836 void Object::RemoveConstraint(ConstraintBase& constraint)
837 {
838   // nullptr if the Constraint sources are destroyed before Constraint::Apply()
839   if(mConstraints)
840   {
841     ConstraintIter it(std::find(mConstraints->begin(), mConstraints->end(), Dali::Constraint(&constraint)));
842     if(it != mConstraints->end())
843     {
844       mConstraints->erase(it);
845     }
846   }
847 }
848
849 void Object::RemoveConstraints()
850 {
851   // guard against constraint sending messages during core destruction
852   if(mConstraints && Stage::IsInstalled())
853   {
854     for(auto&& item : *mConstraints)
855     {
856       GetImplementation(item).RemoveInternal();
857     }
858
859     delete mConstraints;
860     mConstraints = nullptr;
861   }
862 }
863
864 void Object::RemoveConstraints(uint32_t tag)
865 {
866   // guard against constraint sending messages during core destruction
867   if(mConstraints && Stage::IsInstalled())
868   {
869     auto iter(mConstraints->begin());
870     while(iter != mConstraints->end())
871     {
872       ConstraintBase& constraint = GetImplementation(*iter);
873       if(constraint.GetTag() == tag)
874       {
875         GetImplementation(*iter).RemoveInternal();
876         iter = mConstraints->erase(iter);
877       }
878       else
879       {
880         ++iter;
881       }
882     }
883
884     if(mConstraints->empty())
885     {
886       delete mConstraints;
887       mConstraints = nullptr;
888     }
889   }
890 }
891
892 void Object::SetTypeInfo(const TypeInfo* typeInfo)
893 {
894   mTypeInfo = typeInfo;
895 }
896
897 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
898 {
899   if(!mUpdateObject)
900   {
901     auto                                    sceneObject = SceneGraph::PropertyOwner::New();
902     OwnerPointer<SceneGraph::PropertyOwner> transferOwnership(sceneObject);
903     mUpdateObject = sceneObject;
904     AddObjectMessage(const_cast<EventThreadServices&>(GetEventThreadServices()).GetUpdateManager(), transferOwnership);
905   }
906   DALI_ASSERT_DEBUG(mUpdateObject && "there must always be a scene object");
907   return *mUpdateObject;
908 }
909
910 const PropertyBase* Object::GetSceneObjectAnimatableProperty(Property::Index index) const
911 {
912   const SceneGraph::PropertyBase* property = nullptr;
913   if(index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX)
914   {
915     AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
916     DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
917
918     property = animatable->GetSceneGraphProperty();
919   }
920   else if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && // Child properties are also stored as custom properties
921           (index <= PROPERTY_CUSTOM_MAX_INDEX))
922   {
923     CustomPropertyMetadata* custom = FindCustomProperty(index);
924     DALI_ASSERT_ALWAYS(custom && "Property index is invalid");
925
926     property = custom->GetSceneGraphProperty();
927   }
928   return property;
929 }
930
931 const PropertyInputImpl* Object::GetSceneObjectInputProperty(Property::Index index) const
932 {
933   // reuse animatable version as they are inputs as well
934   return GetSceneObjectAnimatableProperty(index);
935 }
936
937 int32_t Object::GetPropertyComponentIndex(Property::Index index) const
938 {
939   int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
940
941   if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
942   {
943     // check whether the animatable property is registered already, if not then register one.
944     AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
945     if(animatableProperty)
946     {
947       componentIndex = animatableProperty->componentIndex;
948     }
949   }
950   if(Property::INVALID_COMPONENT_INDEX == componentIndex)
951   {
952     const TypeInfo* typeInfo(GetTypeInfo());
953     if(typeInfo)
954     {
955       componentIndex = typeInfo->GetComponentIndex(index);
956     }
957   }
958
959   return componentIndex;
960 }
961
962 Handle::PropertySetSignalType& Object::PropertySetSignal()
963 {
964   return mPropertySetSignal;
965 }
966
967 Object::Object(const SceneGraph::PropertyOwner* sceneObject)
968 : mEventThreadServices(EventThreadServices::Get()),
969   mUpdateObject(sceneObject),
970   mTypeInfo(nullptr),
971   mConstraints(nullptr),
972   mPropertyNotifications(nullptr)
973 {
974 }
975
976 Object::~Object()
977 {
978   // Notification for observers
979   for(auto&& item : mObservers)
980   {
981     item->ObjectDestroyed(*this);
982   }
983   delete mConstraints;
984   delete mPropertyNotifications;
985
986   // Guard to allow handle destruction after Core has been destroyed
987   if(Stage::IsInstalled())
988   {
989     if(nullptr != mUpdateObject)
990     {
991       RemoveObjectMessage(GetEventThreadServices().GetUpdateManager(), mUpdateObject);
992     }
993   }
994 }
995
996 void Object::OnSceneObjectAdd()
997 {
998   // Notification for observers
999   for(auto&& item : mObservers)
1000   {
1001     item->SceneObjectAdded(*this);
1002   }
1003
1004   // enable property notifications in scene graph
1005   EnablePropertyNotifications();
1006 }
1007
1008 void Object::OnSceneObjectRemove()
1009 {
1010   // Notification for observers
1011   for(auto&& item : mObservers)
1012   {
1013     item->SceneObjectRemoved(*this);
1014   }
1015
1016   // disable property notifications in scene graph
1017   DisablePropertyNotifications();
1018 }
1019
1020 const TypeInfo* Object::GetTypeInfo() const
1021 {
1022   if(!mTypeInfo)
1023   {
1024     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1025     // especially as the type-info does not change during the life-time of an application
1026
1027     TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo(this);
1028     if(typeInfoHandle)
1029     {
1030       mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1031     }
1032   }
1033
1034   return mTypeInfo;
1035 }
1036
1037 CustomPropertyMetadata* Object::FindCustomProperty(Property::Index index) const
1038 {
1039   CustomPropertyMetadata* property = nullptr;
1040   if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
1041   {
1042     for(std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++)
1043     {
1044       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1045       if(custom->childPropertyIndex == index)
1046       {
1047         property = custom;
1048       }
1049     }
1050   }
1051   else
1052   {
1053     int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1054     if(arrayIndex >= 0)
1055     {
1056       if(arrayIndex < static_cast<int32_t>(mCustomProperties.Count())) // we can only access the first 2 billion custom properties
1057       {
1058         property = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1059       }
1060     }
1061   }
1062   return property;
1063 }
1064
1065 AnimatablePropertyMetadata* Object::FindAnimatableProperty(Property::Index index) const
1066 {
1067   for(auto&& entry : mAnimatableProperties)
1068   {
1069     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>(entry);
1070     if(property->index == index)
1071     {
1072       return property;
1073     }
1074   }
1075   return nullptr;
1076 }
1077
1078 Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
1079 {
1080   // Create a new property
1081   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1082
1083   switch(propertyValue.GetType())
1084   {
1085     case Property::BOOLEAN:
1086     {
1087       newProperty = new AnimatableProperty<bool>(propertyValue.Get<bool>());
1088       break;
1089     }
1090
1091     case Property::INTEGER:
1092     {
1093       newProperty = new AnimatableProperty<int32_t>(propertyValue.Get<int32_t>());
1094       break;
1095     }
1096
1097     case Property::FLOAT:
1098     {
1099       newProperty = new AnimatableProperty<float>(propertyValue.Get<float>());
1100       break;
1101     }
1102
1103     case Property::VECTOR2:
1104     {
1105       newProperty = new AnimatableProperty<Vector2>(propertyValue.Get<Vector2>());
1106       break;
1107     }
1108
1109     case Property::VECTOR3:
1110     {
1111       newProperty = new AnimatableProperty<Vector3>(propertyValue.Get<Vector3>());
1112       break;
1113     }
1114
1115     case Property::VECTOR4:
1116     {
1117       newProperty = new AnimatableProperty<Vector4>(propertyValue.Get<Vector4>());
1118       break;
1119     }
1120
1121     case Property::MATRIX:
1122     {
1123       newProperty = new AnimatableProperty<Matrix>(propertyValue.Get<Matrix>());
1124       break;
1125     }
1126
1127     case Property::MATRIX3:
1128     {
1129       newProperty = new AnimatableProperty<Matrix3>(propertyValue.Get<Matrix3>());
1130       break;
1131     }
1132
1133     case Property::ROTATION:
1134     {
1135       newProperty = new AnimatableProperty<Quaternion>(propertyValue.Get<Quaternion>());
1136       break;
1137     }
1138
1139     case Property::RECTANGLE:
1140     case Property::STRING:
1141     case Property::ARRAY:
1142     case Property::MAP:
1143     case Property::EXTENTS:
1144     case Property::NONE:
1145     {
1146       DALI_ASSERT_ALWAYS(!"Property type is not animatable");
1147       break;
1148     }
1149   }
1150
1151   // get the scene property owner
1152   const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1153   // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1154   const PropertyBase* property = newProperty.Get();
1155   if(index >= PROPERTY_CUSTOM_START_INDEX)
1156   {
1157     DALI_ASSERT_ALWAYS(index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered");
1158
1159     mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
1160   }
1161   else
1162   {
1163     mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, std::move(propertyValue), property));
1164   }
1165
1166   // queue a message to add the property
1167   InstallCustomPropertyMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty); // Message takes ownership
1168
1169   return index;
1170 }
1171
1172 void Object::RegisterAnimatableProperty(const TypeInfo&        typeInfo,
1173                                         Property::Index        index,
1174                                         const Property::Value* value) const
1175 {
1176   // If the property is not a component of a base property, register the whole property itself.
1177   auto            propertyName = ConstString(typeInfo.GetPropertyName(index));
1178   Property::Value initialValue;
1179   if(value)
1180   {
1181     initialValue = *value;
1182   }
1183   else
1184   {
1185     initialValue = typeInfo.GetPropertyDefaultValue(index); // recurses type hierarchy
1186     if(Property::NONE == initialValue.GetType())
1187     {
1188       initialValue = Property::Value(typeInfo.GetPropertyType(index)); // recurses type hierarchy
1189     }
1190   }
1191   RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, initialValue);
1192   AddUniformMapping(index, propertyName);
1193 }
1194
1195 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty(Property::Index index, const Property::Value* value) const
1196 {
1197   // property range already checked by calling methods
1198   // check whether the animatable property is registered already, if not then register one.
1199   AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty(index);
1200   if(!animatableProperty)
1201   {
1202     const TypeInfo* typeInfo(GetTypeInfo());
1203     if(typeInfo)
1204     {
1205       Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1206       if(basePropertyIndex == Property::INVALID_INDEX)
1207       {
1208         // If the property is not a component of a base property, register the whole property itself.
1209         RegisterAnimatableProperty(*typeInfo, index, value);
1210       }
1211       else
1212       {
1213         // Since the property is a component of a base property, check whether the base property is registered.
1214         animatableProperty = FindAnimatableProperty(basePropertyIndex);
1215         if(!animatableProperty)
1216         {
1217           // If the base property is not registered yet, register the base property first.
1218           RegisterAnimatableProperty(*typeInfo, basePropertyIndex, value);
1219           animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1220         }
1221
1222         // Create the metadata for the property component.
1223         mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty()));
1224       }
1225
1226       // The metadata has just been added and therefore should be in the end of the vector.
1227       animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1228     }
1229   }
1230
1231   return animatableProperty;
1232 }
1233
1234 void Object::ResolveChildProperties()
1235 {
1236   // Resolve index for the child property
1237   Object* parent = GetParentObject();
1238   if(parent)
1239   {
1240     const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
1241     if(parentTypeInfo)
1242     {
1243       // Go through each custom property
1244       for(auto&& entry : mCustomProperties)
1245       {
1246         CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>(entry);
1247
1248         if(customProperty->name.IsEmpty())
1249         {
1250           if(customProperty->childPropertyIndex != Property::INVALID_INDEX)
1251           {
1252             // Resolve name for any child property with no name
1253             customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
1254           }
1255         }
1256         else
1257         {
1258           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
1259           if(childPropertyIndex != Property::INVALID_INDEX)
1260           {
1261             // Resolve index for any property with a name that matches the parent's child property name
1262             customProperty->childPropertyIndex = childPropertyIndex;
1263           }
1264         }
1265       }
1266     }
1267   }
1268 }
1269
1270 void Object::SetDefaultProperty(Property::Index index, const Property::Value& property)
1271 {
1272   // do nothing
1273 }
1274
1275 Property::Value Object::GetDefaultProperty(Property::Index index) const
1276 {
1277   return Property::Value();
1278 }
1279
1280 Property::Value Object::GetDefaultPropertyCurrentValue(Property::Index index) const
1281 {
1282   return GetDefaultProperty(index);
1283 }
1284
1285 void Object::EnablePropertyNotifications()
1286 {
1287   if(mPropertyNotifications)
1288   {
1289     for(auto&& element : *mPropertyNotifications)
1290     {
1291       GetImplementation(element).Enable();
1292     }
1293   }
1294 }
1295
1296 void Object::DisablePropertyNotifications()
1297 {
1298   if(mPropertyNotifications)
1299   {
1300     for(auto&& element : *mPropertyNotifications)
1301     {
1302       GetImplementation(element).Disable();
1303     }
1304   }
1305 }
1306
1307 Property::Value Object::GetCurrentPropertyValue(const PropertyMetadata& entry) const
1308 {
1309   Property::Value value;
1310
1311   if(!entry.IsAnimatable())
1312   {
1313     value = entry.GetPropertyValue();
1314   }
1315   else
1316   {
1317     BufferIndex bufferIndex(GetEventThreadServices().GetEventBufferIndex());
1318
1319     switch(entry.GetType())
1320     {
1321       case Property::BOOLEAN:
1322       {
1323         const AnimatableProperty<bool>* property = static_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1324         DALI_ASSERT_DEBUG(property);
1325
1326         value = (*property)[bufferIndex];
1327         break;
1328       }
1329
1330       case Property::INTEGER:
1331       {
1332         const AnimatableProperty<int32_t>* property = static_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1333         DALI_ASSERT_DEBUG(property);
1334
1335         value = (*property)[bufferIndex];
1336         break;
1337       }
1338
1339       case Property::FLOAT:
1340       {
1341         const AnimatableProperty<float>* property = static_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1342         DALI_ASSERT_DEBUG(property);
1343
1344         value = (*property)[bufferIndex];
1345         break;
1346       }
1347
1348       case Property::VECTOR2:
1349       {
1350         const AnimatableProperty<Vector2>* property = static_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1351         DALI_ASSERT_DEBUG(property);
1352
1353         if(entry.componentIndex == 0)
1354         {
1355           value = (*property)[bufferIndex].x;
1356         }
1357         else if(entry.componentIndex == 1)
1358         {
1359           value = (*property)[bufferIndex].y;
1360         }
1361         else
1362         {
1363           value = (*property)[bufferIndex];
1364         }
1365         break;
1366       }
1367
1368       case Property::VECTOR3:
1369       {
1370         const AnimatableProperty<Vector3>* property = static_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1371         DALI_ASSERT_DEBUG(property);
1372
1373         if(entry.componentIndex == 0)
1374         {
1375           value = (*property)[bufferIndex].x;
1376         }
1377         else if(entry.componentIndex == 1)
1378         {
1379           value = (*property)[bufferIndex].y;
1380         }
1381         else if(entry.componentIndex == 2)
1382         {
1383           value = (*property)[bufferIndex].z;
1384         }
1385         else
1386         {
1387           value = (*property)[bufferIndex];
1388         }
1389         break;
1390       }
1391
1392       case Property::VECTOR4:
1393       {
1394         const AnimatableProperty<Vector4>* property = static_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1395         DALI_ASSERT_DEBUG(property);
1396
1397         if(entry.componentIndex == 0)
1398         {
1399           value = (*property)[bufferIndex].x;
1400         }
1401         else if(entry.componentIndex == 1)
1402         {
1403           value = (*property)[bufferIndex].y;
1404         }
1405         else if(entry.componentIndex == 2)
1406         {
1407           value = (*property)[bufferIndex].z;
1408         }
1409         else if(entry.componentIndex == 3)
1410         {
1411           value = (*property)[bufferIndex].w;
1412         }
1413         else
1414         {
1415           value = (*property)[bufferIndex];
1416         }
1417         break;
1418       }
1419
1420       case Property::MATRIX:
1421       {
1422         const AnimatableProperty<Matrix>* property = static_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1423         DALI_ASSERT_DEBUG(property);
1424
1425         value = (*property)[bufferIndex];
1426         break;
1427       }
1428
1429       case Property::MATRIX3:
1430       {
1431         const AnimatableProperty<Matrix3>* property = static_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1432         DALI_ASSERT_DEBUG(property);
1433
1434         value = (*property)[bufferIndex];
1435         break;
1436       }
1437
1438       case Property::ROTATION:
1439       {
1440         const AnimatableProperty<Quaternion>* property = static_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1441         DALI_ASSERT_DEBUG(property);
1442
1443         value = (*property)[bufferIndex];
1444         break;
1445       }
1446
1447       default:
1448       {
1449         // unreachable code due to higher level logic
1450       }
1451     } // switch(type)
1452   }   // if animatable
1453
1454   return value;
1455 }
1456
1457 void Object::SetSceneGraphProperty(Property::Index index, const PropertyMetadata& entry, const Property::Value& value)
1458 {
1459   switch(entry.GetType())
1460   {
1461     case Property::BOOLEAN:
1462     {
1463       const AnimatableProperty<bool>* property = dynamic_cast<const AnimatableProperty<bool>*>(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<bool>(GetEventThreadServices(), *property, value.Get<bool>());
1468       break;
1469     }
1470
1471     case Property::INTEGER:
1472     {
1473       const AnimatableProperty<int32_t>* property = dynamic_cast<const AnimatableProperty<int32_t>*>(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<int32_t>(GetEventThreadServices(), *property, value.Get<int32_t>());
1478       break;
1479     }
1480
1481     case Property::FLOAT:
1482     {
1483       const AnimatableProperty<float>* property = dynamic_cast<const AnimatableProperty<float>*>(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       BakeMessage<float>(GetEventThreadServices(), *property, value.Get<float>());
1488       break;
1489     }
1490
1491     case Property::VECTOR2:
1492     {
1493       const AnimatableProperty<Vector2>* property = dynamic_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1494       DALI_ASSERT_DEBUG(property);
1495
1496       // property is being used in a separate thread; queue a message to set the property
1497       if(entry.componentIndex == 0)
1498       {
1499         SetXComponentMessage<Vector2>(GetEventThreadServices(), *property, value.Get<float>());
1500       }
1501       else if(entry.componentIndex == 1)
1502       {
1503         SetYComponentMessage<Vector2>(GetEventThreadServices(), *property, value.Get<float>());
1504       }
1505       else
1506       {
1507         BakeMessage<Vector2>(GetEventThreadServices(), *property, value.Get<Vector2>());
1508       }
1509       break;
1510     }
1511
1512     case Property::VECTOR3:
1513     {
1514       const AnimatableProperty<Vector3>* property = dynamic_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1515       DALI_ASSERT_DEBUG(property);
1516
1517       // property is being used in a separate thread; queue a message to set the property
1518       if(entry.componentIndex == 0)
1519       {
1520         SetXComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1521       }
1522       else if(entry.componentIndex == 1)
1523       {
1524         SetYComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1525       }
1526       else if(entry.componentIndex == 2)
1527       {
1528         SetZComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1529       }
1530       else
1531       {
1532         BakeMessage<Vector3>(GetEventThreadServices(), *property, value.Get<Vector3>());
1533       }
1534
1535       break;
1536     }
1537
1538     case Property::VECTOR4:
1539     {
1540       const AnimatableProperty<Vector4>* property = dynamic_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1541       DALI_ASSERT_DEBUG(property);
1542
1543       // property is being used in a separate thread; queue a message to set the property
1544       if(entry.componentIndex == 0)
1545       {
1546         SetXComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1547       }
1548       else if(entry.componentIndex == 1)
1549       {
1550         SetYComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1551       }
1552       else if(entry.componentIndex == 2)
1553       {
1554         SetZComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1555       }
1556       else if(entry.componentIndex == 3)
1557       {
1558         SetWComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1559       }
1560       else
1561       {
1562         BakeMessage<Vector4>(GetEventThreadServices(), *property, value.Get<Vector4>());
1563       }
1564       break;
1565     }
1566
1567     case Property::ROTATION:
1568     {
1569       const AnimatableProperty<Quaternion>* property = dynamic_cast<const AnimatableProperty<Quaternion>*>(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<Quaternion>(GetEventThreadServices(), *property, value.Get<Quaternion>());
1574       break;
1575     }
1576
1577     case Property::MATRIX:
1578     {
1579       const AnimatableProperty<Matrix>* property = dynamic_cast<const AnimatableProperty<Matrix>*>(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<Matrix>(GetEventThreadServices(), *property, value.Get<Matrix>());
1584       break;
1585     }
1586
1587     case Property::MATRIX3:
1588     {
1589       const AnimatableProperty<Matrix3>* property = dynamic_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1590       DALI_ASSERT_DEBUG(property);
1591
1592       // property is being used in a separate thread; queue a message to set the property
1593       BakeMessage<Matrix3>(GetEventThreadServices(), *property, value.Get<Matrix3>());
1594       break;
1595     }
1596
1597     default:
1598     {
1599       // non-animatable scene graph property, do nothing
1600     }
1601   }
1602 }
1603
1604 } // namespace Internal
1605
1606 } // namespace Dali