2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/common/object-impl.h>
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>
39 #include <dali/internal/update/common/animatable-property-messages.h>
41 using Dali::Internal::SceneGraph::AnimatableProperty;
42 using Dali::Internal::SceneGraph::PropertyBase;
48 namespace // unnamed namespace
50 const int32_t SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT");
56 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
58 /// Helper to notify observers
59 using ObserverNotifyMethod = void (Object::Observer::*)(Object&);
61 void NotifyObservers(Object& object, Object::ObserverContainer& observers, ObserverNotifyMethod memberFunction)
63 // Guard Add/Remove observer during observer notifying.
64 object.mObserverNotifying = true;
66 // Copy observers to prevent changes to vector affecting loop iterator.
67 Object::ObserverContainer copiedObservers;
68 for(auto&& item : observers)
70 copiedObservers.PushBack(item);
73 object.mObserverRemoved = false;
75 // Notification for observers
76 for(auto&& item : copiedObservers)
78 if(!object.mObserverRemoved)
80 (item->*memberFunction)(object);
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())
89 (item->*memberFunction)(object);
94 object.mObserverNotifying = false;
97 } // unnamed namespace
99 IntrusivePtr<Object> Object::New()
101 return new Object(nullptr); // no scene object by default
104 void Object::AddObserver(Observer& observer)
106 DALI_ASSERT_ALWAYS(!mObserverNotifying && "Cannot add observer while notifying Object::Observers");
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));
112 mObservers.PushBack(&observer);
115 void Object::RemoveObserver(Observer& observer)
117 // Note : We allow to remove observer during notifying.
118 // TODO : Could we assert during notifying in future?
120 // Find the observer...
121 const auto iter = mObservers.Find(&observer);
122 if(iter != mObservers.End())
124 mObserverRemoved = true;
125 mObservers.Erase(iter);
129 bool Object::Supports(Capability capability) const
131 return (capability & SUPPORTED_CAPABILITIES);
134 uint32_t Object::GetPropertyCount() const
137 const TypeInfo* typeInfo(GetTypeInfo());
140 count = typeInfo->GetPropertyCount();
142 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count);
145 uint32_t custom = static_cast<uint32_t>(mCustomProperties.Count());
147 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom);
149 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Total Properties: %d\n", count);
154 std::string_view Object::GetPropertyName(Property::Index index) const
156 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index out of bounds");
158 // is this a per class or per instance property
159 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
161 const TypeInfo* typeInfo(GetTypeInfo());
164 return typeInfo->GetPropertyName(index);
167 else // child property or custom property
169 CustomPropertyMetadata* custom = FindCustomProperty(index);
172 return custom->name.GetStringView();
176 DALI_LOG_ERROR("Property index %d not found\n", index);
180 Property::Index Object::GetPropertyIndex(KeyRef key) const
182 Property::Index index = Property::INVALID_INDEX;
184 if(key.mType == Property::Key::STRING)
186 const TypeInfo* typeInfo(GetTypeInfo());
189 index = typeInfo->GetPropertyIndex(key.mString);
193 if((index == Property::INVALID_INDEX) && (mCustomProperties.Count() > 0))
195 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
196 const auto end = mCustomProperties.End();
197 for(auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count)
199 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
201 if((key.mType == Property::Key::STRING && custom->name == key.mString) ||
202 (key.mType == Property::Key::INDEX && custom->key == key.mIndex))
204 if(custom->childPropertyIndex != Property::INVALID_INDEX)
206 // If it is a child property, return the child property index
207 index = custom->childPropertyIndex;
221 bool Object::IsPropertyWritable(Property::Index index) const
223 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
225 bool writable = false;
227 // is this a per class or per instance property
228 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
230 const TypeInfo* typeInfo(GetTypeInfo());
233 writable = typeInfo->IsPropertyWritable(index);
238 CustomPropertyMetadata* custom = FindCustomProperty(index);
241 writable = custom->IsWritable();
248 bool Object::IsPropertyAnimatable(Property::Index index) const
250 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
252 bool animatable = false;
254 // is this a per class or per instance property
255 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
257 const TypeInfo* typeInfo(GetTypeInfo());
260 animatable = typeInfo->IsPropertyAnimatable(index);
265 CustomPropertyMetadata* custom = FindCustomProperty(index);
268 animatable = custom->IsAnimatable();
275 bool Object::IsPropertyAConstraintInput(Property::Index index) const
277 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
279 bool isConstraintInput = false;
281 // is this a per class or per instance property
282 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
284 const TypeInfo* typeInfo(GetTypeInfo());
287 isConstraintInput = typeInfo->IsPropertyAConstraintInput(index);
292 CustomPropertyMetadata* custom = FindCustomProperty(index);
295 // ... custom properties can be used as input to a constraint.
296 isConstraintInput = true;
300 return isConstraintInput;
303 Property::Type Object::GetPropertyType(Property::Index index) const
305 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
307 // is this a per class or per instance property
308 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
310 const TypeInfo* typeInfo(GetTypeInfo());
313 return typeInfo->GetPropertyType(index);
317 CustomPropertyMetadata* custom = FindCustomProperty(index);
320 return custom->GetType();
323 return Property::NONE;
326 void Object::SetProperty(Property::Index index, Property::Value propertyValue)
328 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
329 Dali::Handle handle(this);
331 bool propertySet(true);
333 if(index < DEFAULT_PROPERTY_MAX_COUNT)
335 SetDefaultProperty(index, propertyValue);
337 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
339 const TypeInfo* typeInfo(GetTypeInfo());
342 typeInfo->SetProperty(this, index, propertyValue);
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);
352 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
354 // check whether the animatable property is registered already, if not then register one.
355 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, &propertyValue);
356 if(!animatableProperty)
358 DALI_LOG_ERROR("Property index %d not found\n", index);
363 // update the cached property value
364 animatableProperty->SetPropertyValue(propertyValue);
366 // set the scene graph property value
367 SetSceneGraphProperty(index, *animatableProperty, propertyValue);
372 CustomPropertyMetadata* custom = FindCustomProperty(index);
374 if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
378 // If the child property is not registered yet, register it.
379 custom = new CustomPropertyMetadata({}, propertyValue, Property::READ_WRITE);
380 mCustomProperties.PushBack(custom);
383 custom->childPropertyIndex = index;
385 // Resolve name for the child property
386 Object* parent = GetParentObject();
389 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
392 custom->name = ConstString(parentTypeInfo->GetChildPropertyName(index));
399 if(custom->IsAnimatable())
401 // update the cached property value
402 custom->SetPropertyValue(propertyValue);
404 // set the scene graph property value
405 SetSceneGraphProperty(index, *custom, propertyValue);
407 else if(custom->IsWritable())
409 // update the cached property value
410 custom->SetPropertyValue(propertyValue);
414 // trying to set value on read only property is no-op
420 DALI_LOG_ERROR("Property index %d not found\n", index);
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
429 OnPropertySet(index, propertyValue);
430 if(!mPropertySetSignal.Empty())
432 mPropertySetSignal.Emit(handle, index, propertyValue);
437 Property::Value Object::GetProperty(Property::Index index) const
439 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
441 Property::Value value;
443 if(index < DEFAULT_PROPERTY_MAX_COUNT)
445 value = GetDefaultProperty(index);
447 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
449 const TypeInfo* typeInfo(GetTypeInfo());
452 value = typeInfo->GetProperty(this, index);
456 DALI_LOG_ERROR("Property index %d not found\n", index);
459 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
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)
466 // get the cached animatable property value
467 value = animatableProperty->GetPropertyValue();
471 DALI_LOG_ERROR("Property index %d not found\n", index);
474 else if(mCustomProperties.Count() > 0)
476 CustomPropertyMetadata* custom = FindCustomProperty(index);
479 // get the cached custom property value
480 value = custom->GetPropertyValue();
484 DALI_LOG_ERROR("Property index %d not found\n", index);
491 Property::Value Object::GetCurrentProperty(Property::Index index) const
493 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
495 Property::Value value;
497 if(index < DEFAULT_PROPERTY_MAX_COUNT)
499 value = GetDefaultPropertyCurrentValue(index);
501 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
503 const TypeInfo* typeInfo(GetTypeInfo());
506 value = typeInfo->GetProperty(this, index);
510 DALI_LOG_ERROR("Property index %d not found\n", index);
513 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
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)
520 // get the animatable property value
521 value = GetCurrentPropertyValue(*animatableProperty);
525 DALI_LOG_ERROR("Property index %d not found\n", index);
528 else if(mCustomProperties.Count() > 0)
530 CustomPropertyMetadata* custom = FindCustomProperty(index);
533 // get the custom property value
534 value = GetCurrentPropertyValue(*custom);
538 DALI_LOG_ERROR("Property index %d not found\n", index);
545 void Object::GetPropertyIndices(Property::IndexContainer& indices) const
550 const TypeInfo* typeInfo(GetTypeInfo());
553 typeInfo->GetPropertyIndices(indices);
557 if(mCustomProperties.Count() > 0)
559 indices.Reserve(indices.Size() + mCustomProperties.Count());
561 auto iter = mCustomProperties.Begin();
562 const auto endIter = mCustomProperties.End();
564 for(; iter != endIter; ++iter, ++i)
566 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
567 if(custom->childPropertyIndex != Property::INVALID_INDEX)
569 // If it is a child property, add the child property index
570 indices.PushBack(custom->childPropertyIndex);
574 indices.PushBack(PROPERTY_CUSTOM_START_INDEX + i);
580 void Object::SetProperties(const Property::Map& properties)
582 const auto count = properties.Count();
583 for(auto position = 0u; position < count; ++position)
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.
588 const auto& key = properties.GetKeyAt(position);
589 const auto propertyIndex = (key.type == Property::Key::INDEX) ? key.indexKey : GetPropertyIndex(key);
591 if(propertyIndex != Property::INVALID_INDEX)
593 const auto& value = properties.GetValue(position);
594 SetProperty(propertyIndex, value);
599 void Object::GetProperties(Property::Map& properties)
603 Property::IndexContainer indexContainer;
604 GetPropertyIndices(indexContainer);
606 for(auto index : indexContainer)
608 properties[index] = GetProperty(index);
612 void Object::ReserveCustomProperties(int propertyCount)
614 mCustomProperties.Reserve(propertyCount);
615 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
616 ReservePropertiesMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, propertyCount);
619 Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
621 return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE, true);
624 Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue, bool checkForUniqueName)
626 return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE, checkForUniqueName);
629 Property::Index Object::RegisterProperty(std::string_view name,
630 Property::Value propertyValue,
631 Property::AccessMode accessMode)
633 return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode, true);
636 Property::Index Object::RegisterProperty(std::string_view name,
638 Property::Value propertyValue,
639 Property::AccessMode accessMode,
640 bool checkForUniqueName)
642 auto constString = ConstString(name);
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
649 index = GetPropertyIndex(key);
651 if(index == Property::INVALID_INDEX && checkForUniqueName) // try name search if requested
653 index = GetPropertyIndex(constString);
656 if(index != Property::INVALID_INDEX) // If there was a valid index found by either key, set it.
658 SetProperty(index, std::move(propertyValue));
662 // Otherwise register the property
663 if(Property::ANIMATABLE == accessMode)
665 index = RegisterSceneGraphProperty(
668 PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
669 std::move(propertyValue));
670 AddUniformMapping(index, constString);
674 // Add entry to the property lookup
675 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count());
677 CustomPropertyMetadata* customProperty =
678 new CustomPropertyMetadata(constString, std::move(propertyValue), accessMode);
680 // Resolve index for the child property
681 Object* parent = GetParentObject();
684 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
687 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
688 if(childPropertyIndex != Property::INVALID_INDEX)
690 customProperty->childPropertyIndex = childPropertyIndex;
691 index = childPropertyIndex;
696 mCustomProperties.PushBack(customProperty);
703 bool Object::DoesCustomPropertyExist(Property::Index index)
705 auto metadata = FindCustomProperty(index);
706 return metadata != nullptr;
709 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
710 int32_t componentIndex,
711 const Dali::PropertyCondition& condition)
713 if(index >= DEFAULT_PROPERTY_MAX_COUNT)
715 if(index <= PROPERTY_REGISTRATION_MAX_INDEX)
717 DALI_ABORT("Property notification added to event side only property.");
719 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
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");
725 else if(mCustomProperties.Count() > 0)
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.");
733 Dali::Handle self(this);
734 Property target(self, index);
736 PropertyNotificationPtr internal = PropertyNotification::New(target, componentIndex, condition);
737 Dali::PropertyNotification propertyNotification(internal.Get());
739 if(!mPropertyNotifications)
741 mPropertyNotifications = new PropertyNotificationContainer;
743 mPropertyNotifications->push_back(propertyNotification);
745 return propertyNotification;
748 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
750 if(mPropertyNotifications)
752 auto iter = mPropertyNotifications->begin();
753 while(iter != mPropertyNotifications->end())
755 if(*iter == propertyNotification)
757 mPropertyNotifications->erase(iter);
758 // As we can't ensure all references are removed, we can just disable
760 GetImplementation(propertyNotification).Disable();
768 void Object::RemovePropertyNotifications()
770 if(mPropertyNotifications)
772 auto iter = mPropertyNotifications->begin();
773 while(iter != mPropertyNotifications->end())
775 // As we can't ensure all references are removed, we can just disable
777 GetImplementation(*iter).Disable();
781 mPropertyNotifications->clear();
785 void Object::NotifyPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
787 if(index < DEFAULT_PROPERTY_MAX_COUNT)
789 OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
793 PropertyMetadata* propertyMetadata = nullptr;
794 if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
796 propertyMetadata = FindAnimatableProperty(index);
800 CustomPropertyMetadata* custom = FindCustomProperty(index);
801 if(custom && custom->IsAnimatable())
803 propertyMetadata = custom;
809 switch(animationType)
812 case Animation::BETWEEN:
814 // Update the cached property value
815 propertyMetadata->SetPropertyValue(value);
820 // Adjust the cached property value
821 propertyMetadata->AdjustPropertyValueBy(value);
829 void Object::AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const
831 // Get the address of the property if it's a scene property
832 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty(propertyIndex);
834 // Check instead for newly registered properties
835 if(propertyPtr == nullptr)
837 PropertyMetadata* animatable = FindAnimatableProperty(propertyIndex);
840 propertyPtr = animatable->GetSceneGraphProperty();
844 if(propertyPtr == nullptr)
846 PropertyMetadata* custom = FindCustomProperty(propertyIndex);
849 propertyPtr = custom->GetSceneGraphProperty();
855 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
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);
863 void Object::RemoveUniformMapping(const std::string& uniformName) const
865 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
866 RemoveUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
869 void Object::ApplyConstraint(ConstraintBase& constraint)
873 mConstraints = new ConstraintContainer;
875 mConstraints->push_back(Dali::Constraint(&constraint));
878 void Object::RemoveConstraint(ConstraintBase& constraint)
880 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
883 ConstraintIter it(std::find(mConstraints->begin(), mConstraints->end(), Dali::Constraint(&constraint)));
884 if(it != mConstraints->end())
886 mConstraints->erase(it);
891 void Object::RemoveConstraints()
893 // guard against constraint sending messages during core destruction
894 if(mConstraints && Stage::IsInstalled())
896 for(auto&& item : *mConstraints)
898 GetImplementation(item).RemoveInternal();
902 mConstraints = nullptr;
906 void Object::RemoveConstraints(uint32_t tag)
908 // guard against constraint sending messages during core destruction
909 if(mConstraints && Stage::IsInstalled())
911 auto iter(mConstraints->begin());
912 while(iter != mConstraints->end())
914 ConstraintBase& constraint = GetImplementation(*iter);
915 if(constraint.GetTag() == tag)
917 GetImplementation(*iter).RemoveInternal();
918 iter = mConstraints->erase(iter);
926 if(mConstraints->empty())
929 mConstraints = nullptr;
934 void Object::SetTypeInfo(const TypeInfo* typeInfo)
936 mTypeInfo = typeInfo;
939 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
943 auto sceneObject = SceneGraph::PropertyOwner::New();
944 OwnerPointer<SceneGraph::PropertyOwner> transferOwnership(sceneObject);
945 mUpdateObject = sceneObject;
946 AddObjectMessage(const_cast<EventThreadServices&>(GetEventThreadServices()).GetUpdateManager(), transferOwnership);
948 DALI_ASSERT_DEBUG(mUpdateObject && "there must always be a scene object");
949 return *mUpdateObject;
952 const PropertyBase* Object::GetSceneObjectAnimatableProperty(Property::Index index) const
954 const SceneGraph::PropertyBase* property = nullptr;
955 if(index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX)
957 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
958 DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
960 property = animatable->GetSceneGraphProperty();
962 else if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && // Child properties are also stored as custom properties
963 (index <= PROPERTY_CUSTOM_MAX_INDEX))
965 CustomPropertyMetadata* custom = FindCustomProperty(index);
966 DALI_ASSERT_ALWAYS(custom && "Property index is invalid");
968 property = custom->GetSceneGraphProperty();
973 const PropertyInputImpl* Object::GetSceneObjectInputProperty(Property::Index index) const
975 // reuse animatable version as they are inputs as well
976 return GetSceneObjectAnimatableProperty(index);
979 int32_t Object::GetPropertyComponentIndex(Property::Index index) const
981 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
983 if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
985 // check whether the animatable property is registered already, if not then register one.
986 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
987 if(animatableProperty)
989 componentIndex = animatableProperty->componentIndex;
992 if(Property::INVALID_COMPONENT_INDEX == componentIndex)
994 const TypeInfo* typeInfo(GetTypeInfo());
997 componentIndex = typeInfo->GetComponentIndex(index);
1001 return componentIndex;
1004 Handle::PropertySetSignalType& Object::PropertySetSignal()
1006 return mPropertySetSignal;
1009 Object::Object(const SceneGraph::PropertyOwner* sceneObject)
1010 : mEventThreadServices(EventThreadServices::Get()),
1011 mUpdateObject(sceneObject),
1013 mConstraints(nullptr),
1014 mPropertyNotifications(nullptr),
1015 mObserverNotifying(false),
1016 mObserverRemoved(false)
1022 NotifyObservers(*this, mObservers, &Object::Observer::ObjectDestroyed);
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;
1028 // Remove all observers
1029 mObserverRemoved = true;
1032 // Disable property notifications in scene graph
1033 DisablePropertyNotifications();
1035 delete mConstraints;
1036 delete mPropertyNotifications;
1038 // Guard to allow handle destruction after Core has been destroyed
1039 if(Stage::IsInstalled())
1041 if(nullptr != mUpdateObject)
1043 RemoveObjectMessage(GetEventThreadServices().GetUpdateManager(), mUpdateObject);
1048 void Object::OnSceneObjectAdd()
1050 DALI_ASSERT_ALWAYS(!mObserverNotifying && "Should not be call OnSceneObjectAdd while notifying observers");
1052 NotifyObservers(*this, mObservers, &Object::Observer::SceneObjectAdded);
1054 // enable property notifications in scene graph
1055 EnablePropertyNotifications();
1058 void Object::OnSceneObjectRemove()
1060 DALI_ASSERT_ALWAYS(!mObserverNotifying && "Should not be call OnSceneObjectRemove while notifying observers");
1062 NotifyObservers(*this, mObservers, &Object::Observer::SceneObjectRemoved);
1064 // disable property notifications in scene graph
1065 DisablePropertyNotifications();
1068 const TypeInfo* Object::GetTypeInfo() const
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
1075 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo(this);
1078 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1085 CustomPropertyMetadata* Object::FindCustomProperty(Property::Index index) const
1087 CustomPropertyMetadata* property = nullptr;
1088 if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
1090 for(std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++)
1092 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1093 if(custom->childPropertyIndex == index)
1101 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1104 if(arrayIndex < static_cast<int32_t>(mCustomProperties.Count())) // we can only access the first 2 billion custom properties
1106 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1113 AnimatablePropertyMetadata* Object::FindAnimatableProperty(Property::Index index) const
1115 for(auto&& entry : mAnimatableProperties)
1117 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>(entry);
1118 if(property->index == index)
1126 Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
1128 // Create a new property
1129 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1131 switch(propertyValue.GetType())
1133 case Property::BOOLEAN:
1135 newProperty = new AnimatableProperty<bool>(propertyValue.Get<bool>());
1139 case Property::INTEGER:
1141 newProperty = new AnimatableProperty<int32_t>(propertyValue.Get<int32_t>());
1145 case Property::FLOAT:
1147 newProperty = new AnimatableProperty<float>(propertyValue.Get<float>());
1151 case Property::VECTOR2:
1153 newProperty = new AnimatableProperty<Vector2>(propertyValue.Get<Vector2>());
1157 case Property::VECTOR3:
1159 newProperty = new AnimatableProperty<Vector3>(propertyValue.Get<Vector3>());
1163 case Property::VECTOR4:
1165 newProperty = new AnimatableProperty<Vector4>(propertyValue.Get<Vector4>());
1169 case Property::MATRIX:
1171 newProperty = new AnimatableProperty<Matrix>(propertyValue.Get<Matrix>());
1175 case Property::MATRIX3:
1177 newProperty = new AnimatableProperty<Matrix3>(propertyValue.Get<Matrix3>());
1181 case Property::ROTATION:
1183 newProperty = new AnimatableProperty<Quaternion>(propertyValue.Get<Quaternion>());
1187 case Property::RECTANGLE:
1188 case Property::STRING:
1189 case Property::ARRAY:
1191 case Property::EXTENTS:
1192 case Property::NONE:
1194 DALI_ASSERT_ALWAYS(!"Property type is not animatable");
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)
1205 DALI_ASSERT_ALWAYS(index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered");
1207 mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
1211 mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, std::move(propertyValue), property));
1214 // queue a message to add the property
1215 InstallCustomPropertyMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty); // Message takes ownership
1220 void Object::RegisterAnimatableProperty(const TypeInfo& typeInfo,
1221 Property::Index index,
1222 const Property::Value* value) const
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;
1229 initialValue = *value;
1233 initialValue = typeInfo.GetPropertyDefaultValue(index); // recurses type hierarchy
1234 if(Property::NONE == initialValue.GetType())
1236 initialValue = Property::Value(typeInfo.GetPropertyType(index)); // recurses type hierarchy
1239 RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, initialValue);
1240 AddUniformMapping(index, propertyName);
1243 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty(Property::Index index, const Property::Value* value) const
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)
1250 const TypeInfo* typeInfo(GetTypeInfo());
1253 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1254 if(basePropertyIndex == Property::INVALID_INDEX)
1256 // If the property is not a component of a base property, register the whole property itself.
1257 RegisterAnimatableProperty(*typeInfo, index, value);
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)
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!");
1269 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1272 // Create the metadata for the property component.
1273 mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty()));
1275 DALI_ASSERT_ALWAYS(mAnimatableProperties.Size() > 0u && "Something wrong when we register new animatable property!");
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]);
1282 return animatableProperty;
1285 void Object::ResolveChildProperties()
1287 // Resolve index for the child property
1288 Object* parent = GetParentObject();
1291 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
1294 // Go through each custom property
1295 for(auto&& entry : mCustomProperties)
1297 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>(entry);
1299 if(customProperty->name.IsEmpty())
1301 if(customProperty->childPropertyIndex != Property::INVALID_INDEX)
1303 // Resolve name for any child property with no name
1304 customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
1309 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
1310 if(childPropertyIndex != Property::INVALID_INDEX)
1312 // Resolve index for any property with a name that matches the parent's child property name
1313 customProperty->childPropertyIndex = childPropertyIndex;
1321 void Object::SetDefaultProperty(Property::Index index, const Property::Value& property)
1326 Property::Value Object::GetDefaultProperty(Property::Index index) const
1328 return Property::Value();
1331 Property::Value Object::GetDefaultPropertyCurrentValue(Property::Index index) const
1333 return GetDefaultProperty(index);
1336 void Object::EnablePropertyNotifications()
1338 if(mPropertyNotifications)
1340 for(auto&& element : *mPropertyNotifications)
1342 GetImplementation(element).Enable();
1347 void Object::DisablePropertyNotifications()
1349 if(mPropertyNotifications)
1351 for(auto&& element : *mPropertyNotifications)
1353 GetImplementation(element).Disable();
1358 Property::Value Object::GetCurrentPropertyValue(const PropertyMetadata& entry) const
1360 Property::Value value;
1362 if(!entry.IsAnimatable())
1364 value = entry.GetPropertyValue();
1368 BufferIndex bufferIndex(GetEventThreadServices().GetEventBufferIndex());
1370 switch(entry.GetType())
1372 case Property::BOOLEAN:
1374 const AnimatableProperty<bool>* property = static_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1375 DALI_ASSERT_DEBUG(property);
1377 value = (*property)[bufferIndex];
1381 case Property::INTEGER:
1383 const AnimatableProperty<int32_t>* property = static_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1384 DALI_ASSERT_DEBUG(property);
1386 value = (*property)[bufferIndex];
1390 case Property::FLOAT:
1392 const AnimatableProperty<float>* property = static_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1393 DALI_ASSERT_DEBUG(property);
1395 value = (*property)[bufferIndex];
1399 case Property::VECTOR2:
1401 const AnimatableProperty<Vector2>* property = static_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1402 DALI_ASSERT_DEBUG(property);
1404 if(entry.componentIndex == 0)
1406 value = (*property)[bufferIndex].x;
1408 else if(entry.componentIndex == 1)
1410 value = (*property)[bufferIndex].y;
1414 value = (*property)[bufferIndex];
1419 case Property::VECTOR3:
1421 const AnimatableProperty<Vector3>* property = static_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1422 DALI_ASSERT_DEBUG(property);
1424 if(entry.componentIndex == 0)
1426 value = (*property)[bufferIndex].x;
1428 else if(entry.componentIndex == 1)
1430 value = (*property)[bufferIndex].y;
1432 else if(entry.componentIndex == 2)
1434 value = (*property)[bufferIndex].z;
1438 value = (*property)[bufferIndex];
1443 case Property::VECTOR4:
1445 const AnimatableProperty<Vector4>* property = static_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1446 DALI_ASSERT_DEBUG(property);
1448 if(entry.componentIndex == 0)
1450 value = (*property)[bufferIndex].x;
1452 else if(entry.componentIndex == 1)
1454 value = (*property)[bufferIndex].y;
1456 else if(entry.componentIndex == 2)
1458 value = (*property)[bufferIndex].z;
1460 else if(entry.componentIndex == 3)
1462 value = (*property)[bufferIndex].w;
1466 value = (*property)[bufferIndex];
1471 case Property::MATRIX:
1473 const AnimatableProperty<Matrix>* property = static_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1474 DALI_ASSERT_DEBUG(property);
1476 value = (*property)[bufferIndex];
1480 case Property::MATRIX3:
1482 const AnimatableProperty<Matrix3>* property = static_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1483 DALI_ASSERT_DEBUG(property);
1485 value = (*property)[bufferIndex];
1489 case Property::ROTATION:
1491 const AnimatableProperty<Quaternion>* property = static_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1492 DALI_ASSERT_DEBUG(property);
1494 value = (*property)[bufferIndex];
1500 // unreachable code due to higher level logic
1508 void Object::SetSceneGraphProperty(Property::Index index, const PropertyMetadata& entry, const Property::Value& value)
1510 switch(entry.GetType())
1512 case Property::BOOLEAN:
1514 const AnimatableProperty<bool>* property = dynamic_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1515 DALI_ASSERT_DEBUG(property);
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>());
1522 case Property::INTEGER:
1524 const AnimatableProperty<int32_t>* property = dynamic_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1525 DALI_ASSERT_DEBUG(property);
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>());
1532 case Property::FLOAT:
1534 const AnimatableProperty<float>* property = dynamic_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1535 DALI_ASSERT_DEBUG(property);
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>());
1542 case Property::VECTOR2:
1544 const AnimatableProperty<Vector2>* property = dynamic_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1545 DALI_ASSERT_DEBUG(property);
1547 // property is being used in a separate thread; queue a message to set the property
1548 if(entry.componentIndex == 0)
1550 SetXComponentMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1552 else if(entry.componentIndex == 1)
1554 SetYComponentMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1558 BakeMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Vector2>());
1563 case Property::VECTOR3:
1565 const AnimatableProperty<Vector3>* property = dynamic_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1566 DALI_ASSERT_DEBUG(property);
1568 // property is being used in a separate thread; queue a message to set the property
1569 if(entry.componentIndex == 0)
1571 SetXComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1573 else if(entry.componentIndex == 1)
1575 SetYComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1577 else if(entry.componentIndex == 2)
1579 SetZComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1583 BakeMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Vector3>());
1589 case Property::VECTOR4:
1591 const AnimatableProperty<Vector4>* property = dynamic_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1592 DALI_ASSERT_DEBUG(property);
1594 // property is being used in a separate thread; queue a message to set the property
1595 if(entry.componentIndex == 0)
1597 SetXComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1599 else if(entry.componentIndex == 1)
1601 SetYComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1603 else if(entry.componentIndex == 2)
1605 SetZComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1607 else if(entry.componentIndex == 3)
1609 SetWComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1613 BakeMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Vector4>());
1618 case Property::ROTATION:
1620 const AnimatableProperty<Quaternion>* property = dynamic_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1621 DALI_ASSERT_DEBUG(property);
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>());
1628 case Property::MATRIX:
1630 const AnimatableProperty<Matrix>* property = dynamic_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1631 DALI_ASSERT_DEBUG(property);
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>());
1638 case Property::MATRIX3:
1640 const AnimatableProperty<Matrix3>* property = dynamic_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1641 DALI_ASSERT_DEBUG(property);
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>());
1650 // non-animatable scene graph property, do nothing
1655 } // namespace Internal