2 * Copyright (c) 2023 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 } // unnamed namespace
60 IntrusivePtr<Object> Object::New()
62 return new Object(nullptr); // no scene object by default
65 void Object::AddObserver(Observer& observer)
67 // make sure an observer doesn't observe the same object twice
68 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
69 DALI_ASSERT_DEBUG(mObservers.End() == std::find(mObservers.Begin(), mObservers.End(), &observer));
71 mObservers.PushBack(&observer);
74 void Object::RemoveObserver(Observer& observer)
76 // Find the observer...
77 const auto endIter = mObservers.End();
78 for(auto iter = mObservers.Begin(); iter != endIter; ++iter)
80 if((*iter) == &observer)
82 mObservers.Erase(iter);
86 DALI_ASSERT_DEBUG(endIter != mObservers.End());
89 bool Object::Supports(Capability capability) const
91 return (capability & SUPPORTED_CAPABILITIES);
94 uint32_t Object::GetPropertyCount() const
97 const TypeInfo* typeInfo(GetTypeInfo());
100 count = typeInfo->GetPropertyCount();
102 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count);
105 uint32_t custom = static_cast<uint32_t>(mCustomProperties.Count());
107 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom);
109 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Total Properties: %d\n", count);
114 std::string_view Object::GetPropertyName(Property::Index index) const
116 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index out of bounds");
118 // is this a per class or per instance property
119 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
121 const TypeInfo* typeInfo(GetTypeInfo());
124 return typeInfo->GetPropertyName(index);
127 else // child property or custom property
129 CustomPropertyMetadata* custom = FindCustomProperty(index);
132 return custom->name.GetStringView();
136 DALI_LOG_ERROR("Property index %d not found\n", index);
140 Property::Index Object::GetPropertyIndex(KeyRef key) const
142 Property::Index index = Property::INVALID_INDEX;
144 if(key.mType == Property::Key::STRING)
146 const TypeInfo* typeInfo(GetTypeInfo());
149 index = typeInfo->GetPropertyIndex(key.mString);
153 if((index == Property::INVALID_INDEX) && (mCustomProperties.Count() > 0))
155 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
156 const auto end = mCustomProperties.End();
157 for(auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count)
159 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
161 if((key.mType == Property::Key::STRING && custom->name == key.mString) ||
162 (key.mType == Property::Key::INDEX && custom->key == key.mIndex))
164 if(custom->childPropertyIndex != Property::INVALID_INDEX)
166 // If it is a child property, return the child property index
167 index = custom->childPropertyIndex;
181 bool Object::IsPropertyWritable(Property::Index index) const
183 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
185 bool writable = false;
187 // is this a per class or per instance property
188 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
190 const TypeInfo* typeInfo(GetTypeInfo());
193 writable = typeInfo->IsPropertyWritable(index);
198 CustomPropertyMetadata* custom = FindCustomProperty(index);
201 writable = custom->IsWritable();
208 bool Object::IsPropertyAnimatable(Property::Index index) const
210 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
212 bool animatable = false;
214 // is this a per class or per instance property
215 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
217 const TypeInfo* typeInfo(GetTypeInfo());
220 animatable = typeInfo->IsPropertyAnimatable(index);
225 CustomPropertyMetadata* custom = FindCustomProperty(index);
228 animatable = custom->IsAnimatable();
235 bool Object::IsPropertyAConstraintInput(Property::Index index) const
237 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
239 bool isConstraintInput = false;
241 // is this a per class or per instance property
242 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
244 const TypeInfo* typeInfo(GetTypeInfo());
247 isConstraintInput = typeInfo->IsPropertyAConstraintInput(index);
252 CustomPropertyMetadata* custom = FindCustomProperty(index);
255 // ... custom properties can be used as input to a constraint.
256 isConstraintInput = true;
260 return isConstraintInput;
263 Property::Type Object::GetPropertyType(Property::Index index) const
265 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
267 // is this a per class or per instance property
268 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
270 const TypeInfo* typeInfo(GetTypeInfo());
273 return typeInfo->GetPropertyType(index);
277 CustomPropertyMetadata* custom = FindCustomProperty(index);
280 return custom->GetType();
283 return Property::NONE;
286 void Object::SetProperty(Property::Index index, Property::Value propertyValue)
288 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
290 bool propertySet(true);
292 if(index < DEFAULT_PROPERTY_MAX_COUNT)
294 SetDefaultProperty(index, propertyValue);
296 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
298 const TypeInfo* typeInfo(GetTypeInfo());
301 typeInfo->SetProperty(this, index, propertyValue);
305 // cannot register this property as there is no setter for it.
306 // event side properties must have a setter for now so need to be registered
307 DALI_LOG_ERROR("Property index %d not found\n", index);
311 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
313 // check whether the animatable property is registered already, if not then register one.
314 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, &propertyValue);
315 if(!animatableProperty)
317 DALI_LOG_ERROR("Property index %d not found\n", index);
322 // update the cached property value
323 animatableProperty->SetPropertyValue(propertyValue);
325 // set the scene graph property value
326 SetSceneGraphProperty(index, *animatableProperty, propertyValue);
331 CustomPropertyMetadata* custom = FindCustomProperty(index);
333 if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
337 // If the child property is not registered yet, register it.
338 custom = new CustomPropertyMetadata({}, propertyValue, Property::READ_WRITE);
339 mCustomProperties.PushBack(custom);
342 custom->childPropertyIndex = index;
344 // Resolve name for the child property
345 Object* parent = GetParentObject();
348 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
351 custom->name = ConstString(parentTypeInfo->GetChildPropertyName(index));
358 if(custom->IsAnimatable())
360 // update the cached property value
361 custom->SetPropertyValue(propertyValue);
363 // set the scene graph property value
364 SetSceneGraphProperty(index, *custom, propertyValue);
366 else if(custom->IsWritable())
368 // update the cached property value
369 custom->SetPropertyValue(propertyValue);
373 // trying to set value on read only property is no-op
379 DALI_LOG_ERROR("Property index %d not found\n", index);
384 // Let derived classes know that a property has been set
385 // 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
388 OnPropertySet(index, propertyValue);
389 if(!mPropertySetSignal.Empty())
391 Dali::Handle handle(this);
392 mPropertySetSignal.Emit(handle, index, propertyValue);
397 Property::Value Object::GetProperty(Property::Index index) const
399 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
401 Property::Value value;
403 if(index < DEFAULT_PROPERTY_MAX_COUNT)
405 value = GetDefaultProperty(index);
407 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
409 const TypeInfo* typeInfo(GetTypeInfo());
412 value = typeInfo->GetProperty(this, index);
416 DALI_LOG_ERROR("Property index %d not found\n", index);
419 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
421 // check whether the animatable property is registered already, if not then register one.
422 // this is needed because property value may have been set as full property and get as a property component
423 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
424 if(animatableProperty)
426 // get the cached animatable property value
427 value = animatableProperty->GetPropertyValue();
431 DALI_LOG_ERROR("Property index %d not found\n", index);
434 else if(mCustomProperties.Count() > 0)
436 CustomPropertyMetadata* custom = FindCustomProperty(index);
439 // get the cached custom property value
440 value = custom->GetPropertyValue();
444 DALI_LOG_ERROR("Property index %d not found\n", index);
451 Property::Value Object::GetCurrentProperty(Property::Index index) const
453 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
455 Property::Value value;
457 if(index < DEFAULT_PROPERTY_MAX_COUNT)
459 value = GetDefaultPropertyCurrentValue(index);
461 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
463 const TypeInfo* typeInfo(GetTypeInfo());
466 value = typeInfo->GetProperty(this, index);
470 DALI_LOG_ERROR("Property index %d not found\n", index);
473 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
475 // check whether the animatable property is registered already, if not then register one.
476 // this is needed because property value may have been set as full property and get as a property component
477 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
478 if(animatableProperty)
480 // get the animatable property value
481 value = GetCurrentPropertyValue(*animatableProperty);
485 DALI_LOG_ERROR("Property index %d not found\n", index);
488 else if(mCustomProperties.Count() > 0)
490 CustomPropertyMetadata* custom = FindCustomProperty(index);
493 // get the custom property value
494 value = GetCurrentPropertyValue(*custom);
498 DALI_LOG_ERROR("Property index %d not found\n", index);
505 void Object::GetPropertyIndices(Property::IndexContainer& indices) const
510 const TypeInfo* typeInfo(GetTypeInfo());
513 typeInfo->GetPropertyIndices(indices);
517 if(mCustomProperties.Count() > 0)
519 indices.Reserve(indices.Size() + mCustomProperties.Count());
521 auto iter = mCustomProperties.Begin();
522 const auto endIter = mCustomProperties.End();
524 for(; iter != endIter; ++iter, ++i)
526 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
527 if(custom->childPropertyIndex != Property::INVALID_INDEX)
529 // If it is a child property, add the child property index
530 indices.PushBack(custom->childPropertyIndex);
534 indices.PushBack(PROPERTY_CUSTOM_START_INDEX + i);
540 void Object::SetProperties(const Property::Map& properties)
542 const auto count = properties.Count();
543 for(auto position = 0u; position < count; ++position)
545 // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
546 // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
548 const auto& key = properties.GetKeyAt(position);
549 const auto propertyIndex = (key.type == Property::Key::INDEX) ? key.indexKey : GetPropertyIndex(key);
551 if(propertyIndex != Property::INVALID_INDEX)
553 const auto& value = properties.GetValue(position);
554 SetProperty(propertyIndex, value);
559 void Object::GetProperties(Property::Map& properties)
563 Property::IndexContainer indexContainer;
564 GetPropertyIndices(indexContainer);
566 for(auto index : indexContainer)
568 properties[index] = GetProperty(index);
572 void Object::ReserveCustomProperties(int propertyCount)
574 mCustomProperties.Reserve(propertyCount);
575 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
576 ReservePropertiesMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, propertyCount);
579 Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
581 return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE, true);
584 Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue, bool checkForUniqueName)
586 return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE, checkForUniqueName);
589 Property::Index Object::RegisterProperty(std::string_view name,
590 Property::Value propertyValue,
591 Property::AccessMode accessMode)
593 return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode, true);
596 Property::Index Object::RegisterProperty(std::string_view name,
598 Property::Value propertyValue,
599 Property::AccessMode accessMode,
600 bool checkForUniqueName)
602 auto constString = ConstString(name);
604 // If property with the required key already exists, then just set it.
605 // Don't search names if checkForUniqueName is false.
606 Property::Index index = Property::INVALID_INDEX;
607 if(key != Property::INVALID_KEY) // Try integer key first if it's valid
609 index = GetPropertyIndex(key);
611 if(index == Property::INVALID_INDEX && checkForUniqueName) // try name search if requested
613 index = GetPropertyIndex(constString);
616 if(index != Property::INVALID_INDEX) // If there was a valid index found by either key, set it.
618 SetProperty(index, std::move(propertyValue));
622 // Otherwise register the property
623 if(Property::ANIMATABLE == accessMode)
625 index = RegisterSceneGraphProperty(
628 PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
629 std::move(propertyValue));
630 AddUniformMapping(index, constString);
634 // Add entry to the property lookup
635 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count());
637 CustomPropertyMetadata* customProperty =
638 new CustomPropertyMetadata(constString, std::move(propertyValue), accessMode);
640 // Resolve index for the child property
641 Object* parent = GetParentObject();
644 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
647 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
648 if(childPropertyIndex != Property::INVALID_INDEX)
650 customProperty->childPropertyIndex = childPropertyIndex;
651 index = childPropertyIndex;
656 mCustomProperties.PushBack(customProperty);
663 bool Object::DoesCustomPropertyExist(Property::Index index)
665 auto metadata = FindCustomProperty(index);
666 return metadata != nullptr;
669 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
670 int32_t componentIndex,
671 const Dali::PropertyCondition& condition)
673 if(index >= DEFAULT_PROPERTY_MAX_COUNT)
675 if(index <= PROPERTY_REGISTRATION_MAX_INDEX)
677 DALI_ABORT("Property notification added to event side only property.");
679 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
681 // check whether the animatable property is registered already, if not then register one.
682 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
683 DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
685 else if(mCustomProperties.Count() > 0)
687 CustomPropertyMetadata* custom = FindCustomProperty(index);
688 DALI_ASSERT_ALWAYS(custom && "Invalid property index");
689 DALI_ASSERT_ALWAYS(custom->IsAnimatable() && "Property notification added to event side only property.");
693 Dali::Handle self(this);
694 Property target(self, index);
696 PropertyNotificationPtr internal = PropertyNotification::New(target, componentIndex, condition);
697 Dali::PropertyNotification propertyNotification(internal.Get());
699 if(!mPropertyNotifications)
701 mPropertyNotifications = new PropertyNotificationContainer;
703 mPropertyNotifications->push_back(propertyNotification);
705 return propertyNotification;
708 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
710 if(mPropertyNotifications)
712 auto iter = mPropertyNotifications->begin();
713 while(iter != mPropertyNotifications->end())
715 if(*iter == propertyNotification)
717 mPropertyNotifications->erase(iter);
718 // As we can't ensure all references are removed, we can just disable
720 GetImplementation(propertyNotification).Disable();
728 void Object::RemovePropertyNotifications()
730 if(mPropertyNotifications)
732 auto iter = mPropertyNotifications->begin();
733 while(iter != mPropertyNotifications->end())
735 // As we can't ensure all references are removed, we can just disable
737 GetImplementation(*iter).Disable();
741 mPropertyNotifications->clear();
745 void Object::NotifyPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
747 if(index < DEFAULT_PROPERTY_MAX_COUNT)
749 OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
753 PropertyMetadata* propertyMetadata = nullptr;
754 if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
756 propertyMetadata = FindAnimatableProperty(index);
760 CustomPropertyMetadata* custom = FindCustomProperty(index);
761 if(custom && custom->IsAnimatable())
763 propertyMetadata = custom;
769 switch(animationType)
772 case Animation::BETWEEN:
774 // Update the cached property value
775 propertyMetadata->SetPropertyValue(value);
780 // Adjust the cached property value
781 propertyMetadata->AdjustPropertyValueBy(value);
789 void Object::AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const
791 // Get the address of the property if it's a scene property
792 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty(propertyIndex);
794 // Check instead for newly registered properties
795 if(propertyPtr == nullptr)
797 PropertyMetadata* animatable = FindAnimatableProperty(propertyIndex);
800 propertyPtr = animatable->GetSceneGraphProperty();
804 if(propertyPtr == nullptr)
806 PropertyMetadata* custom = FindCustomProperty(propertyIndex);
809 propertyPtr = custom->GetSceneGraphProperty();
815 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
817 SceneGraph::UniformPropertyMapping map(uniformName, propertyPtr);
818 // Message takes ownership of Uniform map (and will delete it after copy)
819 AddUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map);
823 void Object::RemoveUniformMapping(const std::string& uniformName) const
825 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
826 RemoveUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
829 void Object::ApplyConstraint(ConstraintBase& constraint)
833 mConstraints = new ConstraintContainer;
835 mConstraints->push_back(Dali::Constraint(&constraint));
838 void Object::RemoveConstraint(ConstraintBase& constraint)
840 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
843 ConstraintIter it(std::find(mConstraints->begin(), mConstraints->end(), Dali::Constraint(&constraint)));
844 if(it != mConstraints->end())
846 mConstraints->erase(it);
851 void Object::RemoveConstraints()
853 // guard against constraint sending messages during core destruction
854 if(mConstraints && Stage::IsInstalled())
856 for(auto&& item : *mConstraints)
858 GetImplementation(item).RemoveInternal();
862 mConstraints = nullptr;
866 void Object::RemoveConstraints(uint32_t tag)
868 // guard against constraint sending messages during core destruction
869 if(mConstraints && Stage::IsInstalled())
871 auto iter(mConstraints->begin());
872 while(iter != mConstraints->end())
874 ConstraintBase& constraint = GetImplementation(*iter);
875 if(constraint.GetTag() == tag)
877 GetImplementation(*iter).RemoveInternal();
878 iter = mConstraints->erase(iter);
886 if(mConstraints->empty())
889 mConstraints = nullptr;
894 void Object::SetTypeInfo(const TypeInfo* typeInfo)
896 mTypeInfo = typeInfo;
899 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
903 auto sceneObject = SceneGraph::PropertyOwner::New();
904 OwnerPointer<SceneGraph::PropertyOwner> transferOwnership(sceneObject);
905 mUpdateObject = sceneObject;
906 AddObjectMessage(const_cast<EventThreadServices&>(GetEventThreadServices()).GetUpdateManager(), transferOwnership);
908 DALI_ASSERT_DEBUG(mUpdateObject && "there must always be a scene object");
909 return *mUpdateObject;
912 const PropertyBase* Object::GetSceneObjectAnimatableProperty(Property::Index index) const
914 const SceneGraph::PropertyBase* property = nullptr;
915 if(index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX)
917 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
918 DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
920 property = animatable->GetSceneGraphProperty();
922 else if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && // Child properties are also stored as custom properties
923 (index <= PROPERTY_CUSTOM_MAX_INDEX))
925 CustomPropertyMetadata* custom = FindCustomProperty(index);
926 DALI_ASSERT_ALWAYS(custom && "Property index is invalid");
928 property = custom->GetSceneGraphProperty();
933 const PropertyInputImpl* Object::GetSceneObjectInputProperty(Property::Index index) const
935 // reuse animatable version as they are inputs as well
936 return GetSceneObjectAnimatableProperty(index);
939 int32_t Object::GetPropertyComponentIndex(Property::Index index) const
941 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
943 if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
945 // check whether the animatable property is registered already, if not then register one.
946 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
947 if(animatableProperty)
949 componentIndex = animatableProperty->componentIndex;
952 if(Property::INVALID_COMPONENT_INDEX == componentIndex)
954 const TypeInfo* typeInfo(GetTypeInfo());
957 componentIndex = typeInfo->GetComponentIndex(index);
961 return componentIndex;
964 Handle::PropertySetSignalType& Object::PropertySetSignal()
966 return mPropertySetSignal;
969 Object::Object(const SceneGraph::PropertyOwner* sceneObject)
970 : mEventThreadServices(EventThreadServices::Get()),
971 mUpdateObject(sceneObject),
973 mConstraints(nullptr),
974 mPropertyNotifications(nullptr)
980 // Notification for observers
981 for(auto&& item : mObservers)
983 item->ObjectDestroyed(*this);
986 delete mPropertyNotifications;
988 // Guard to allow handle destruction after Core has been destroyed
989 if(Stage::IsInstalled())
991 if(nullptr != mUpdateObject)
993 RemoveObjectMessage(GetEventThreadServices().GetUpdateManager(), mUpdateObject);
998 void Object::OnSceneObjectAdd()
1000 // Notification for observers
1001 for(auto&& item : mObservers)
1003 item->SceneObjectAdded(*this);
1006 // enable property notifications in scene graph
1007 EnablePropertyNotifications();
1010 void Object::OnSceneObjectRemove()
1012 // Notification for observers
1013 for(auto&& item : mObservers)
1015 item->SceneObjectRemoved(*this);
1018 // disable property notifications in scene graph
1019 DisablePropertyNotifications();
1022 const TypeInfo* Object::GetTypeInfo() const
1026 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1027 // especially as the type-info does not change during the life-time of an application
1029 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo(this);
1032 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1039 CustomPropertyMetadata* Object::FindCustomProperty(Property::Index index) const
1041 CustomPropertyMetadata* property = nullptr;
1042 if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
1044 for(std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++)
1046 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1047 if(custom->childPropertyIndex == index)
1055 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1058 if(arrayIndex < static_cast<int32_t>(mCustomProperties.Count())) // we can only access the first 2 billion custom properties
1060 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1067 AnimatablePropertyMetadata* Object::FindAnimatableProperty(Property::Index index) const
1069 for(auto&& entry : mAnimatableProperties)
1071 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>(entry);
1072 if(property->index == index)
1080 Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
1082 // Create a new property
1083 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1085 switch(propertyValue.GetType())
1087 case Property::BOOLEAN:
1089 newProperty = new AnimatableProperty<bool>(propertyValue.Get<bool>());
1093 case Property::INTEGER:
1095 newProperty = new AnimatableProperty<int32_t>(propertyValue.Get<int32_t>());
1099 case Property::FLOAT:
1101 newProperty = new AnimatableProperty<float>(propertyValue.Get<float>());
1105 case Property::VECTOR2:
1107 newProperty = new AnimatableProperty<Vector2>(propertyValue.Get<Vector2>());
1111 case Property::VECTOR3:
1113 newProperty = new AnimatableProperty<Vector3>(propertyValue.Get<Vector3>());
1117 case Property::VECTOR4:
1119 newProperty = new AnimatableProperty<Vector4>(propertyValue.Get<Vector4>());
1123 case Property::MATRIX:
1125 newProperty = new AnimatableProperty<Matrix>(propertyValue.Get<Matrix>());
1129 case Property::MATRIX3:
1131 newProperty = new AnimatableProperty<Matrix3>(propertyValue.Get<Matrix3>());
1135 case Property::ROTATION:
1137 newProperty = new AnimatableProperty<Quaternion>(propertyValue.Get<Quaternion>());
1141 case Property::RECTANGLE:
1142 case Property::STRING:
1143 case Property::ARRAY:
1145 case Property::EXTENTS:
1146 case Property::NONE:
1148 DALI_ASSERT_ALWAYS(!"Property type is not animatable");
1153 // get the scene property owner
1154 const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1155 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1156 const PropertyBase* property = newProperty.Get();
1157 if(index >= PROPERTY_CUSTOM_START_INDEX)
1159 DALI_ASSERT_ALWAYS(index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered");
1161 mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
1165 mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, std::move(propertyValue), property));
1168 // queue a message to add the property
1169 InstallCustomPropertyMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty); // Message takes ownership
1174 void Object::RegisterAnimatableProperty(const TypeInfo& typeInfo,
1175 Property::Index index,
1176 const Property::Value* value) const
1178 // If the property is not a component of a base property, register the whole property itself.
1179 auto propertyName = ConstString(typeInfo.GetPropertyName(index));
1180 Property::Value initialValue;
1183 initialValue = *value;
1187 initialValue = typeInfo.GetPropertyDefaultValue(index); // recurses type hierarchy
1188 if(Property::NONE == initialValue.GetType())
1190 initialValue = Property::Value(typeInfo.GetPropertyType(index)); // recurses type hierarchy
1193 RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, initialValue);
1194 AddUniformMapping(index, propertyName);
1197 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty(Property::Index index, const Property::Value* value) const
1199 // property range already checked by calling methods
1200 // check whether the animatable property is registered already, if not then register one.
1201 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty(index);
1202 if(!animatableProperty)
1204 const TypeInfo* typeInfo(GetTypeInfo());
1207 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1208 if(basePropertyIndex == Property::INVALID_INDEX)
1210 // If the property is not a component of a base property, register the whole property itself.
1211 RegisterAnimatableProperty(*typeInfo, index, value);
1215 // Since the property is a component of a base property, check whether the base property is registered.
1216 animatableProperty = FindAnimatableProperty(basePropertyIndex);
1217 if(!animatableProperty)
1219 // If the base property is not registered yet, register the base property first.
1220 RegisterAnimatableProperty(*typeInfo, basePropertyIndex, value);
1221 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1224 // Create the metadata for the property component.
1225 mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty()));
1228 // The metadata has just been added and therefore should be in the end of the vector.
1229 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1233 return animatableProperty;
1236 void Object::ResolveChildProperties()
1238 // Resolve index for the child property
1239 Object* parent = GetParentObject();
1242 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
1245 // Go through each custom property
1246 for(auto&& entry : mCustomProperties)
1248 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>(entry);
1250 if(customProperty->name.IsEmpty())
1252 if(customProperty->childPropertyIndex != Property::INVALID_INDEX)
1254 // Resolve name for any child property with no name
1255 customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
1260 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
1261 if(childPropertyIndex != Property::INVALID_INDEX)
1263 // Resolve index for any property with a name that matches the parent's child property name
1264 customProperty->childPropertyIndex = childPropertyIndex;
1272 void Object::SetDefaultProperty(Property::Index index, const Property::Value& property)
1277 Property::Value Object::GetDefaultProperty(Property::Index index) const
1279 return Property::Value();
1282 Property::Value Object::GetDefaultPropertyCurrentValue(Property::Index index) const
1284 return GetDefaultProperty(index);
1287 void Object::EnablePropertyNotifications()
1289 if(mPropertyNotifications)
1291 for(auto&& element : *mPropertyNotifications)
1293 GetImplementation(element).Enable();
1298 void Object::DisablePropertyNotifications()
1300 if(mPropertyNotifications)
1302 for(auto&& element : *mPropertyNotifications)
1304 GetImplementation(element).Disable();
1309 Property::Value Object::GetCurrentPropertyValue(const PropertyMetadata& entry) const
1311 Property::Value value;
1313 if(!entry.IsAnimatable())
1315 value = entry.GetPropertyValue();
1319 BufferIndex bufferIndex(GetEventThreadServices().GetEventBufferIndex());
1321 switch(entry.GetType())
1323 case Property::BOOLEAN:
1325 const AnimatableProperty<bool>* property = static_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1326 DALI_ASSERT_DEBUG(property);
1328 value = (*property)[bufferIndex];
1332 case Property::INTEGER:
1334 const AnimatableProperty<int32_t>* property = static_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1335 DALI_ASSERT_DEBUG(property);
1337 value = (*property)[bufferIndex];
1341 case Property::FLOAT:
1343 const AnimatableProperty<float>* property = static_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1344 DALI_ASSERT_DEBUG(property);
1346 value = (*property)[bufferIndex];
1350 case Property::VECTOR2:
1352 const AnimatableProperty<Vector2>* property = static_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1353 DALI_ASSERT_DEBUG(property);
1355 if(entry.componentIndex == 0)
1357 value = (*property)[bufferIndex].x;
1359 else if(entry.componentIndex == 1)
1361 value = (*property)[bufferIndex].y;
1365 value = (*property)[bufferIndex];
1370 case Property::VECTOR3:
1372 const AnimatableProperty<Vector3>* property = static_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1373 DALI_ASSERT_DEBUG(property);
1375 if(entry.componentIndex == 0)
1377 value = (*property)[bufferIndex].x;
1379 else if(entry.componentIndex == 1)
1381 value = (*property)[bufferIndex].y;
1383 else if(entry.componentIndex == 2)
1385 value = (*property)[bufferIndex].z;
1389 value = (*property)[bufferIndex];
1394 case Property::VECTOR4:
1396 const AnimatableProperty<Vector4>* property = static_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1397 DALI_ASSERT_DEBUG(property);
1399 if(entry.componentIndex == 0)
1401 value = (*property)[bufferIndex].x;
1403 else if(entry.componentIndex == 1)
1405 value = (*property)[bufferIndex].y;
1407 else if(entry.componentIndex == 2)
1409 value = (*property)[bufferIndex].z;
1411 else if(entry.componentIndex == 3)
1413 value = (*property)[bufferIndex].w;
1417 value = (*property)[bufferIndex];
1422 case Property::MATRIX:
1424 const AnimatableProperty<Matrix>* property = static_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1425 DALI_ASSERT_DEBUG(property);
1427 value = (*property)[bufferIndex];
1431 case Property::MATRIX3:
1433 const AnimatableProperty<Matrix3>* property = static_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1434 DALI_ASSERT_DEBUG(property);
1436 value = (*property)[bufferIndex];
1440 case Property::ROTATION:
1442 const AnimatableProperty<Quaternion>* property = static_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1443 DALI_ASSERT_DEBUG(property);
1445 value = (*property)[bufferIndex];
1451 // unreachable code due to higher level logic
1459 void Object::SetSceneGraphProperty(Property::Index index, const PropertyMetadata& entry, const Property::Value& value)
1461 switch(entry.GetType())
1463 case Property::BOOLEAN:
1465 const AnimatableProperty<bool>* property = dynamic_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1466 DALI_ASSERT_DEBUG(property);
1468 // property is being used in a separate thread; queue a message to set the property
1469 BakeMessage<bool>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<bool>());
1473 case Property::INTEGER:
1475 const AnimatableProperty<int32_t>* property = dynamic_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1476 DALI_ASSERT_DEBUG(property);
1478 // property is being used in a separate thread; queue a message to set the property
1479 BakeMessage<int32_t>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<int32_t>());
1483 case Property::FLOAT:
1485 const AnimatableProperty<float>* property = dynamic_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1486 DALI_ASSERT_DEBUG(property);
1488 // property is being used in a separate thread; queue a message to set the property
1489 BakeMessage<float>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1493 case Property::VECTOR2:
1495 const AnimatableProperty<Vector2>* property = dynamic_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1496 DALI_ASSERT_DEBUG(property);
1498 // property is being used in a separate thread; queue a message to set the property
1499 if(entry.componentIndex == 0)
1501 SetXComponentMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1503 else if(entry.componentIndex == 1)
1505 SetYComponentMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1509 BakeMessage<Vector2>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Vector2>());
1514 case Property::VECTOR3:
1516 const AnimatableProperty<Vector3>* property = dynamic_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1517 DALI_ASSERT_DEBUG(property);
1519 // property is being used in a separate thread; queue a message to set the property
1520 if(entry.componentIndex == 0)
1522 SetXComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1524 else if(entry.componentIndex == 1)
1526 SetYComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1528 else if(entry.componentIndex == 2)
1530 SetZComponentMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1534 BakeMessage<Vector3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Vector3>());
1540 case Property::VECTOR4:
1542 const AnimatableProperty<Vector4>* property = dynamic_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1543 DALI_ASSERT_DEBUG(property);
1545 // property is being used in a separate thread; queue a message to set the property
1546 if(entry.componentIndex == 0)
1548 SetXComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1550 else if(entry.componentIndex == 1)
1552 SetYComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1554 else if(entry.componentIndex == 2)
1556 SetZComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1558 else if(entry.componentIndex == 3)
1560 SetWComponentMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<float>());
1564 BakeMessage<Vector4>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Vector4>());
1569 case Property::ROTATION:
1571 const AnimatableProperty<Quaternion>* property = dynamic_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1572 DALI_ASSERT_DEBUG(property);
1574 // property is being used in a separate thread; queue a message to set the property
1575 BakeMessage<Quaternion>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Quaternion>());
1579 case Property::MATRIX:
1581 const AnimatableProperty<Matrix>* property = dynamic_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1582 DALI_ASSERT_DEBUG(property);
1584 // property is being used in a separate thread; queue a message to set the property
1585 BakeMessage<Matrix>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Matrix>());
1589 case Property::MATRIX3:
1591 const AnimatableProperty<Matrix3>* property = dynamic_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1592 DALI_ASSERT_DEBUG(property);
1594 // property is being used in a separate thread; queue a message to set the property
1595 BakeMessage<Matrix3>(GetEventThreadServices(), *mUpdateObject, *property, value.Get<Matrix3>());
1601 // non-animatable scene graph property, do nothing
1606 } // namespace Internal