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