2 * Copyright (c) 2022 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 using Dali::Internal::SceneGraph::AnimatableProperty;
40 using Dali::Internal::SceneGraph::PropertyBase;
46 namespace // unnamed namespace
48 const int32_t SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT");
54 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
56 } // unnamed namespace
58 IntrusivePtr<Object> Object::New()
60 return new Object(nullptr); // no scene object by default
63 void Object::AddObserver(Observer& observer)
65 // make sure an observer doesn't observe the same object twice
66 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
67 DALI_ASSERT_DEBUG(mObservers.End() == std::find(mObservers.Begin(), mObservers.End(), &observer));
69 mObservers.PushBack(&observer);
72 void Object::RemoveObserver(Observer& observer)
74 // Find the observer...
75 const auto endIter = mObservers.End();
76 for(auto iter = mObservers.Begin(); iter != endIter; ++iter)
78 if((*iter) == &observer)
80 mObservers.Erase(iter);
84 DALI_ASSERT_DEBUG(endIter != mObservers.End());
87 bool Object::Supports(Capability capability) const
89 return (capability & SUPPORTED_CAPABILITIES);
92 uint32_t Object::GetPropertyCount() const
95 const TypeInfo* typeInfo(GetTypeInfo());
98 count = typeInfo->GetPropertyCount();
100 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count);
103 uint32_t custom = static_cast<uint32_t>(mCustomProperties.Count());
105 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom);
107 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Total Properties: %d\n", count);
112 std::string_view Object::GetPropertyName(Property::Index index) const
114 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index out of bounds");
116 // is this a per class or per instance property
117 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
119 const TypeInfo* typeInfo(GetTypeInfo());
122 return typeInfo->GetPropertyName(index);
125 else // child property or custom property
127 CustomPropertyMetadata* custom = FindCustomProperty(index);
130 return custom->name.GetStringView();
134 DALI_LOG_ERROR("Property index %d not found\n", index);
138 Property::Index Object::GetPropertyIndex(KeyRef key) const
140 Property::Index index = Property::INVALID_INDEX;
142 if(key.mType == Property::Key::STRING)
144 const TypeInfo* typeInfo(GetTypeInfo());
147 index = typeInfo->GetPropertyIndex(key.mString);
151 if((index == Property::INVALID_INDEX) && (mCustomProperties.Count() > 0))
153 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
154 const auto end = mCustomProperties.End();
155 for(auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count)
157 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
159 if((key.mType == Property::Key::STRING && custom->name == key.mString) ||
160 (key.mType == Property::Key::INDEX && custom->key == key.mIndex))
162 if(custom->childPropertyIndex != Property::INVALID_INDEX)
164 // If it is a child property, return the child property index
165 index = custom->childPropertyIndex;
179 bool Object::IsPropertyWritable(Property::Index index) const
181 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
183 bool writable = false;
185 // is this a per class or per instance property
186 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
188 const TypeInfo* typeInfo(GetTypeInfo());
191 writable = typeInfo->IsPropertyWritable(index);
196 CustomPropertyMetadata* custom = FindCustomProperty(index);
199 writable = custom->IsWritable();
206 bool Object::IsPropertyAnimatable(Property::Index index) const
208 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
210 bool animatable = false;
212 // is this a per class or per instance property
213 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
215 const TypeInfo* typeInfo(GetTypeInfo());
218 animatable = typeInfo->IsPropertyAnimatable(index);
223 CustomPropertyMetadata* custom = FindCustomProperty(index);
226 animatable = custom->IsAnimatable();
233 bool Object::IsPropertyAConstraintInput(Property::Index index) const
235 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
237 bool isConstraintInput = false;
239 // is this a per class or per instance property
240 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
242 const TypeInfo* typeInfo(GetTypeInfo());
245 isConstraintInput = typeInfo->IsPropertyAConstraintInput(index);
250 CustomPropertyMetadata* custom = FindCustomProperty(index);
253 // ... custom properties can be used as input to a constraint.
254 isConstraintInput = true;
258 return isConstraintInput;
261 Property::Type Object::GetPropertyType(Property::Index index) const
263 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
265 // is this a per class or per instance property
266 if(index < MAX_PER_CLASS_PROPERTY_INDEX)
268 const TypeInfo* typeInfo(GetTypeInfo());
271 return typeInfo->GetPropertyType(index);
275 CustomPropertyMetadata* custom = FindCustomProperty(index);
278 return custom->GetType();
281 return Property::NONE;
284 void Object::SetProperty(Property::Index index, Property::Value propertyValue)
286 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
288 bool propertySet(true);
290 if(index < DEFAULT_PROPERTY_MAX_COUNT)
292 SetDefaultProperty(index, propertyValue);
294 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
296 const TypeInfo* typeInfo(GetTypeInfo());
299 typeInfo->SetProperty(this, index, propertyValue);
303 // cannot register this property as there is no setter for it.
304 // event side properties must have a setter for now so need to be registered
305 DALI_LOG_ERROR("Property index %d not found\n", index);
309 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
311 // check whether the animatable property is registered already, if not then register one.
312 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, &propertyValue);
313 if(!animatableProperty)
315 DALI_LOG_ERROR("Property index %d not found\n", index);
320 // update the cached property value
321 animatableProperty->SetPropertyValue(propertyValue);
323 // set the scene graph property value
324 SetSceneGraphProperty(index, *animatableProperty, propertyValue);
329 CustomPropertyMetadata* custom = FindCustomProperty(index);
331 if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
335 // If the child property is not registered yet, register it.
336 custom = new CustomPropertyMetadata({}, propertyValue, Property::READ_WRITE);
337 mCustomProperties.PushBack(custom);
340 custom->childPropertyIndex = index;
342 // Resolve name for the child property
343 Object* parent = GetParentObject();
346 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
349 custom->name = ConstString(parentTypeInfo->GetChildPropertyName(index));
356 if(custom->IsAnimatable())
358 // update the cached property value
359 custom->SetPropertyValue(propertyValue);
361 // set the scene graph property value
362 SetSceneGraphProperty(index, *custom, propertyValue);
364 else if(custom->IsWritable())
366 // update the cached property value
367 custom->SetPropertyValue(propertyValue);
371 // trying to set value on read only property is no-op
377 DALI_LOG_ERROR("Property index %d not found\n", index);
382 // Let derived classes know that a property has been set
383 // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
386 OnPropertySet(index, propertyValue);
387 if(!mPropertySetSignal.Empty())
389 Dali::Handle handle(this);
390 mPropertySetSignal.Emit(handle, index, propertyValue);
395 Property::Value Object::GetProperty(Property::Index index) const
397 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
399 Property::Value value;
401 if(index < DEFAULT_PROPERTY_MAX_COUNT)
403 value = GetDefaultProperty(index);
405 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
407 const TypeInfo* typeInfo(GetTypeInfo());
410 value = typeInfo->GetProperty(this, index);
414 DALI_LOG_ERROR("Property index %d not found\n", index);
417 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
419 // check whether the animatable property is registered already, if not then register one.
420 // this is needed because property value may have been set as full property and get as a property component
421 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
422 if(animatableProperty)
424 // get the cached animatable property value
425 value = animatableProperty->GetPropertyValue();
429 DALI_LOG_ERROR("Property index %d not found\n", index);
432 else if(mCustomProperties.Count() > 0)
434 CustomPropertyMetadata* custom = FindCustomProperty(index);
437 // get the cached custom property value
438 value = custom->GetPropertyValue();
442 DALI_LOG_ERROR("Property index %d not found\n", index);
449 Property::Value Object::GetCurrentProperty(Property::Index index) const
451 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
453 Property::Value value;
455 if(index < DEFAULT_PROPERTY_MAX_COUNT)
457 value = GetDefaultPropertyCurrentValue(index);
459 else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
461 const TypeInfo* typeInfo(GetTypeInfo());
464 value = typeInfo->GetProperty(this, index);
468 DALI_LOG_ERROR("Property index %d not found\n", index);
471 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
473 // check whether the animatable property is registered already, if not then register one.
474 // this is needed because property value may have been set as full property and get as a property component
475 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
476 if(animatableProperty)
478 // get the animatable property value
479 value = GetCurrentPropertyValue(*animatableProperty);
483 DALI_LOG_ERROR("Property index %d not found\n", index);
486 else if(mCustomProperties.Count() > 0)
488 CustomPropertyMetadata* custom = FindCustomProperty(index);
491 // get the custom property value
492 value = GetCurrentPropertyValue(*custom);
496 DALI_LOG_ERROR("Property index %d not found\n", index);
503 void Object::GetPropertyIndices(Property::IndexContainer& indices) const
508 const TypeInfo* typeInfo(GetTypeInfo());
511 typeInfo->GetPropertyIndices(indices);
515 if(mCustomProperties.Count() > 0)
517 indices.Reserve(indices.Size() + mCustomProperties.Count());
519 auto iter = mCustomProperties.Begin();
520 const auto endIter = mCustomProperties.End();
522 for(; iter != endIter; ++iter, ++i)
524 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
525 if(custom->childPropertyIndex != Property::INVALID_INDEX)
527 // If it is a child property, add the child property index
528 indices.PushBack(custom->childPropertyIndex);
532 indices.PushBack(PROPERTY_CUSTOM_START_INDEX + i);
538 void Object::SetProperties(const Property::Map& properties)
540 const auto count = properties.Count();
541 for(auto position = 0u; position < count; ++position)
543 // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
544 // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
546 const auto& key = properties.GetKeyAt(position);
547 const auto propertyIndex = (key.type == Property::Key::INDEX) ? key.indexKey : GetPropertyIndex(key);
549 if(propertyIndex != Property::INVALID_INDEX)
551 const auto& value = properties.GetValue(position);
552 SetProperty(propertyIndex, value);
557 void Object::GetProperties(Property::Map& properties)
561 Property::IndexContainer indexContainer;
562 GetPropertyIndices(indexContainer);
564 for(auto index : indexContainer)
566 properties[index] = GetProperty(index);
570 void Object::ReserveCustomProperties(int propertyCount)
572 mCustomProperties.Reserve(propertyCount);
573 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
574 ReservePropertiesMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, propertyCount);
577 Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
579 return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE, true);
582 Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue, bool checkForUniqueName)
584 return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE, checkForUniqueName);
587 Property::Index Object::RegisterProperty(std::string_view name,
588 Property::Value propertyValue,
589 Property::AccessMode accessMode)
591 return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode, true);
594 Property::Index Object::RegisterProperty(std::string_view name,
596 Property::Value propertyValue,
597 Property::AccessMode accessMode,
598 bool checkForUniqueName)
600 auto constString = ConstString(name);
602 // If property with the required key already exists, then just set it.
603 // Don't search names if checkForUniqueName is false.
604 Property::Index index = Property::INVALID_INDEX;
605 if(key != Property::INVALID_KEY) // Try integer key first if it's valid
607 index = GetPropertyIndex(key);
609 if(index == Property::INVALID_INDEX && checkForUniqueName) // try name search if requested
611 index = GetPropertyIndex(constString);
614 if(index != Property::INVALID_INDEX) // If there was a valid index found by either key, set it.
616 SetProperty(index, std::move(propertyValue));
620 // Otherwise register the property
621 if(Property::ANIMATABLE == accessMode)
623 index = RegisterSceneGraphProperty(
626 PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
627 std::move(propertyValue));
628 AddUniformMapping(index, constString);
632 // Add entry to the property lookup
633 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count());
635 CustomPropertyMetadata* customProperty =
636 new CustomPropertyMetadata(constString, std::move(propertyValue), accessMode);
638 // Resolve index for the child property
639 Object* parent = GetParentObject();
642 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
645 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
646 if(childPropertyIndex != Property::INVALID_INDEX)
648 customProperty->childPropertyIndex = childPropertyIndex;
649 index = childPropertyIndex;
654 mCustomProperties.PushBack(customProperty);
661 bool Object::DoesCustomPropertyExist(Property::Index index)
663 auto metadata = FindCustomProperty(index);
664 return metadata != nullptr;
667 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
668 int32_t componentIndex,
669 const Dali::PropertyCondition& condition)
671 if(index >= DEFAULT_PROPERTY_MAX_COUNT)
673 if(index <= PROPERTY_REGISTRATION_MAX_INDEX)
675 DALI_ABORT("Property notification added to event side only property.");
677 else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
679 // check whether the animatable property is registered already, if not then register one.
680 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
681 DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
683 else if(mCustomProperties.Count() > 0)
685 CustomPropertyMetadata* custom = FindCustomProperty(index);
686 DALI_ASSERT_ALWAYS(custom && "Invalid property index");
687 DALI_ASSERT_ALWAYS(custom->IsAnimatable() && "Property notification added to event side only property.");
691 Dali::Handle self(this);
692 Property target(self, index);
694 PropertyNotificationPtr internal = PropertyNotification::New(target, componentIndex, condition);
695 Dali::PropertyNotification propertyNotification(internal.Get());
697 if(!mPropertyNotifications)
699 mPropertyNotifications = new PropertyNotificationContainer;
701 mPropertyNotifications->push_back(propertyNotification);
703 return propertyNotification;
706 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
708 if(mPropertyNotifications)
710 auto iter = mPropertyNotifications->begin();
711 while(iter != mPropertyNotifications->end())
713 if(*iter == propertyNotification)
715 mPropertyNotifications->erase(iter);
716 // As we can't ensure all references are removed, we can just disable
718 GetImplementation(propertyNotification).Disable();
726 void Object::RemovePropertyNotifications()
728 if(mPropertyNotifications)
730 auto iter = mPropertyNotifications->begin();
731 while(iter != mPropertyNotifications->end())
733 // As we can't ensure all references are removed, we can just disable
735 GetImplementation(*iter).Disable();
739 mPropertyNotifications->clear();
743 void Object::NotifyPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
745 if(index < DEFAULT_PROPERTY_MAX_COUNT)
747 OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
751 PropertyMetadata* propertyMetadata = nullptr;
752 if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
754 propertyMetadata = FindAnimatableProperty(index);
758 CustomPropertyMetadata* custom = FindCustomProperty(index);
759 if(custom && custom->IsAnimatable())
761 propertyMetadata = custom;
767 switch(animationType)
770 case Animation::BETWEEN:
772 // Update the cached property value
773 propertyMetadata->SetPropertyValue(value);
778 // Adjust the cached property value
779 propertyMetadata->AdjustPropertyValueBy(value);
787 void Object::AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const
789 // Get the address of the property if it's a scene property
790 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty(propertyIndex);
792 // Check instead for newly registered properties
793 if(propertyPtr == nullptr)
795 PropertyMetadata* animatable = FindAnimatableProperty(propertyIndex);
798 propertyPtr = animatable->GetSceneGraphProperty();
802 if(propertyPtr == nullptr)
804 PropertyMetadata* custom = FindCustomProperty(propertyIndex);
807 propertyPtr = custom->GetSceneGraphProperty();
813 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
815 SceneGraph::UniformPropertyMapping map(uniformName, propertyPtr);
816 // Message takes ownership of Uniform map (and will delete it after copy)
817 AddUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map);
821 void Object::RemoveUniformMapping(const std::string& uniformName) const
823 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
824 RemoveUniformMapMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
827 void Object::ApplyConstraint(ConstraintBase& constraint)
831 mConstraints = new ConstraintContainer;
833 mConstraints->push_back(Dali::Constraint(&constraint));
836 void Object::RemoveConstraint(ConstraintBase& constraint)
838 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
841 ConstraintIter it(std::find(mConstraints->begin(), mConstraints->end(), Dali::Constraint(&constraint)));
842 if(it != mConstraints->end())
844 mConstraints->erase(it);
849 void Object::RemoveConstraints()
851 // guard against constraint sending messages during core destruction
852 if(mConstraints && Stage::IsInstalled())
854 for(auto&& item : *mConstraints)
856 GetImplementation(item).RemoveInternal();
860 mConstraints = nullptr;
864 void Object::RemoveConstraints(uint32_t tag)
866 // guard against constraint sending messages during core destruction
867 if(mConstraints && Stage::IsInstalled())
869 auto iter(mConstraints->begin());
870 while(iter != mConstraints->end())
872 ConstraintBase& constraint = GetImplementation(*iter);
873 if(constraint.GetTag() == tag)
875 GetImplementation(*iter).RemoveInternal();
876 iter = mConstraints->erase(iter);
884 if(mConstraints->empty())
887 mConstraints = nullptr;
892 void Object::SetTypeInfo(const TypeInfo* typeInfo)
894 mTypeInfo = typeInfo;
897 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
901 auto sceneObject = SceneGraph::PropertyOwner::New();
902 OwnerPointer<SceneGraph::PropertyOwner> transferOwnership(sceneObject);
903 mUpdateObject = sceneObject;
904 AddObjectMessage(const_cast<EventThreadServices&>(GetEventThreadServices()).GetUpdateManager(), transferOwnership);
906 DALI_ASSERT_DEBUG(mUpdateObject && "there must always be a scene object");
907 return *mUpdateObject;
910 const PropertyBase* Object::GetSceneObjectAnimatableProperty(Property::Index index) const
912 const SceneGraph::PropertyBase* property = nullptr;
913 if(index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX)
915 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty(index, nullptr);
916 DALI_ASSERT_ALWAYS(animatable && "Property index is invalid");
918 property = animatable->GetSceneGraphProperty();
920 else if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && // Child properties are also stored as custom properties
921 (index <= PROPERTY_CUSTOM_MAX_INDEX))
923 CustomPropertyMetadata* custom = FindCustomProperty(index);
924 DALI_ASSERT_ALWAYS(custom && "Property index is invalid");
926 property = custom->GetSceneGraphProperty();
931 const PropertyInputImpl* Object::GetSceneObjectInputProperty(Property::Index index) const
933 // reuse animatable version as they are inputs as well
934 return GetSceneObjectAnimatableProperty(index);
937 int32_t Object::GetPropertyComponentIndex(Property::Index index) const
939 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
941 if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
943 // check whether the animatable property is registered already, if not then register one.
944 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty(index, nullptr);
945 if(animatableProperty)
947 componentIndex = animatableProperty->componentIndex;
950 if(Property::INVALID_COMPONENT_INDEX == componentIndex)
952 const TypeInfo* typeInfo(GetTypeInfo());
955 componentIndex = typeInfo->GetComponentIndex(index);
959 return componentIndex;
962 Handle::PropertySetSignalType& Object::PropertySetSignal()
964 return mPropertySetSignal;
967 Object::Object(const SceneGraph::PropertyOwner* sceneObject)
968 : mEventThreadServices(EventThreadServices::Get()),
969 mUpdateObject(sceneObject),
971 mConstraints(nullptr),
972 mPropertyNotifications(nullptr)
978 // Notification for observers
979 for(auto&& item : mObservers)
981 item->ObjectDestroyed(*this);
984 delete mPropertyNotifications;
986 // Guard to allow handle destruction after Core has been destroyed
987 if(Stage::IsInstalled())
989 if(nullptr != mUpdateObject)
991 RemoveObjectMessage(GetEventThreadServices().GetUpdateManager(), mUpdateObject);
996 void Object::OnSceneObjectAdd()
998 // Notification for observers
999 for(auto&& item : mObservers)
1001 item->SceneObjectAdded(*this);
1004 // enable property notifications in scene graph
1005 EnablePropertyNotifications();
1008 void Object::OnSceneObjectRemove()
1010 // Notification for observers
1011 for(auto&& item : mObservers)
1013 item->SceneObjectRemoved(*this);
1016 // disable property notifications in scene graph
1017 DisablePropertyNotifications();
1020 const TypeInfo* Object::GetTypeInfo() const
1024 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1025 // especially as the type-info does not change during the life-time of an application
1027 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo(this);
1030 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1037 CustomPropertyMetadata* Object::FindCustomProperty(Property::Index index) const
1039 CustomPropertyMetadata* property = nullptr;
1040 if((index >= CHILD_PROPERTY_REGISTRATION_START_INDEX) && (index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX))
1042 for(std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++)
1044 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1045 if(custom->childPropertyIndex == index)
1053 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1056 if(arrayIndex < static_cast<int32_t>(mCustomProperties.Count())) // we can only access the first 2 billion custom properties
1058 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[arrayIndex]);
1065 AnimatablePropertyMetadata* Object::FindAnimatableProperty(Property::Index index) const
1067 for(auto&& entry : mAnimatableProperties)
1069 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>(entry);
1070 if(property->index == index)
1078 Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
1080 // Create a new property
1081 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1083 switch(propertyValue.GetType())
1085 case Property::BOOLEAN:
1087 newProperty = new AnimatableProperty<bool>(propertyValue.Get<bool>());
1091 case Property::INTEGER:
1093 newProperty = new AnimatableProperty<int32_t>(propertyValue.Get<int32_t>());
1097 case Property::FLOAT:
1099 newProperty = new AnimatableProperty<float>(propertyValue.Get<float>());
1103 case Property::VECTOR2:
1105 newProperty = new AnimatableProperty<Vector2>(propertyValue.Get<Vector2>());
1109 case Property::VECTOR3:
1111 newProperty = new AnimatableProperty<Vector3>(propertyValue.Get<Vector3>());
1115 case Property::VECTOR4:
1117 newProperty = new AnimatableProperty<Vector4>(propertyValue.Get<Vector4>());
1121 case Property::MATRIX:
1123 newProperty = new AnimatableProperty<Matrix>(propertyValue.Get<Matrix>());
1127 case Property::MATRIX3:
1129 newProperty = new AnimatableProperty<Matrix3>(propertyValue.Get<Matrix3>());
1133 case Property::ROTATION:
1135 newProperty = new AnimatableProperty<Quaternion>(propertyValue.Get<Quaternion>());
1139 case Property::RECTANGLE:
1140 case Property::STRING:
1141 case Property::ARRAY:
1143 case Property::EXTENTS:
1144 case Property::NONE:
1146 DALI_ASSERT_ALWAYS(!"Property type is not animatable");
1151 // get the scene property owner
1152 const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1153 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1154 const PropertyBase* property = newProperty.Get();
1155 if(index >= PROPERTY_CUSTOM_START_INDEX)
1157 DALI_ASSERT_ALWAYS(index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered");
1159 mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
1163 mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, std::move(propertyValue), property));
1166 // queue a message to add the property
1167 InstallCustomPropertyMessage(const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty); // Message takes ownership
1172 void Object::RegisterAnimatableProperty(const TypeInfo& typeInfo,
1173 Property::Index index,
1174 const Property::Value* value) const
1176 // If the property is not a component of a base property, register the whole property itself.
1177 auto propertyName = ConstString(typeInfo.GetPropertyName(index));
1178 Property::Value initialValue;
1181 initialValue = *value;
1185 initialValue = typeInfo.GetPropertyDefaultValue(index); // recurses type hierarchy
1186 if(Property::NONE == initialValue.GetType())
1188 initialValue = Property::Value(typeInfo.GetPropertyType(index)); // recurses type hierarchy
1191 RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, initialValue);
1192 AddUniformMapping(index, propertyName);
1195 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty(Property::Index index, const Property::Value* value) const
1197 // property range already checked by calling methods
1198 // check whether the animatable property is registered already, if not then register one.
1199 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty(index);
1200 if(!animatableProperty)
1202 const TypeInfo* typeInfo(GetTypeInfo());
1205 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1206 if(basePropertyIndex == Property::INVALID_INDEX)
1208 // If the property is not a component of a base property, register the whole property itself.
1209 RegisterAnimatableProperty(*typeInfo, index, value);
1213 // Since the property is a component of a base property, check whether the base property is registered.
1214 animatableProperty = FindAnimatableProperty(basePropertyIndex);
1215 if(!animatableProperty)
1217 // If the base property is not registered yet, register the base property first.
1218 RegisterAnimatableProperty(*typeInfo, basePropertyIndex, value);
1219 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1222 // Create the metadata for the property component.
1223 mAnimatableProperties.PushBack(new AnimatablePropertyMetadata(index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty()));
1226 // The metadata has just been added and therefore should be in the end of the vector.
1227 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size() - 1]);
1231 return animatableProperty;
1234 void Object::ResolveChildProperties()
1236 // Resolve index for the child property
1237 Object* parent = GetParentObject();
1240 const TypeInfo* parentTypeInfo(parent->GetTypeInfo());
1243 // Go through each custom property
1244 for(auto&& entry : mCustomProperties)
1246 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>(entry);
1248 if(customProperty->name.IsEmpty())
1250 if(customProperty->childPropertyIndex != Property::INVALID_INDEX)
1252 // Resolve name for any child property with no name
1253 customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
1258 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
1259 if(childPropertyIndex != Property::INVALID_INDEX)
1261 // Resolve index for any property with a name that matches the parent's child property name
1262 customProperty->childPropertyIndex = childPropertyIndex;
1270 void Object::SetDefaultProperty(Property::Index index, const Property::Value& property)
1275 Property::Value Object::GetDefaultProperty(Property::Index index) const
1277 return Property::Value();
1280 Property::Value Object::GetDefaultPropertyCurrentValue(Property::Index index) const
1282 return GetDefaultProperty(index);
1285 void Object::EnablePropertyNotifications()
1287 if(mPropertyNotifications)
1289 for(auto&& element : *mPropertyNotifications)
1291 GetImplementation(element).Enable();
1296 void Object::DisablePropertyNotifications()
1298 if(mPropertyNotifications)
1300 for(auto&& element : *mPropertyNotifications)
1302 GetImplementation(element).Disable();
1307 Property::Value Object::GetCurrentPropertyValue(const PropertyMetadata& entry) const
1309 Property::Value value;
1311 if(!entry.IsAnimatable())
1313 value = entry.GetPropertyValue();
1317 BufferIndex bufferIndex(GetEventThreadServices().GetEventBufferIndex());
1319 switch(entry.GetType())
1321 case Property::BOOLEAN:
1323 const AnimatableProperty<bool>* property = static_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1324 DALI_ASSERT_DEBUG(property);
1326 value = (*property)[bufferIndex];
1330 case Property::INTEGER:
1332 const AnimatableProperty<int32_t>* property = static_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1333 DALI_ASSERT_DEBUG(property);
1335 value = (*property)[bufferIndex];
1339 case Property::FLOAT:
1341 const AnimatableProperty<float>* property = static_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1342 DALI_ASSERT_DEBUG(property);
1344 value = (*property)[bufferIndex];
1348 case Property::VECTOR2:
1350 const AnimatableProperty<Vector2>* property = static_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1351 DALI_ASSERT_DEBUG(property);
1353 if(entry.componentIndex == 0)
1355 value = (*property)[bufferIndex].x;
1357 else if(entry.componentIndex == 1)
1359 value = (*property)[bufferIndex].y;
1363 value = (*property)[bufferIndex];
1368 case Property::VECTOR3:
1370 const AnimatableProperty<Vector3>* property = static_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1371 DALI_ASSERT_DEBUG(property);
1373 if(entry.componentIndex == 0)
1375 value = (*property)[bufferIndex].x;
1377 else if(entry.componentIndex == 1)
1379 value = (*property)[bufferIndex].y;
1381 else if(entry.componentIndex == 2)
1383 value = (*property)[bufferIndex].z;
1387 value = (*property)[bufferIndex];
1392 case Property::VECTOR4:
1394 const AnimatableProperty<Vector4>* property = static_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1395 DALI_ASSERT_DEBUG(property);
1397 if(entry.componentIndex == 0)
1399 value = (*property)[bufferIndex].x;
1401 else if(entry.componentIndex == 1)
1403 value = (*property)[bufferIndex].y;
1405 else if(entry.componentIndex == 2)
1407 value = (*property)[bufferIndex].z;
1409 else if(entry.componentIndex == 3)
1411 value = (*property)[bufferIndex].w;
1415 value = (*property)[bufferIndex];
1420 case Property::MATRIX:
1422 const AnimatableProperty<Matrix>* property = static_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1423 DALI_ASSERT_DEBUG(property);
1425 value = (*property)[bufferIndex];
1429 case Property::MATRIX3:
1431 const AnimatableProperty<Matrix3>* property = static_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1432 DALI_ASSERT_DEBUG(property);
1434 value = (*property)[bufferIndex];
1438 case Property::ROTATION:
1440 const AnimatableProperty<Quaternion>* property = static_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1441 DALI_ASSERT_DEBUG(property);
1443 value = (*property)[bufferIndex];
1449 // unreachable code due to higher level logic
1457 void Object::SetSceneGraphProperty(Property::Index index, const PropertyMetadata& entry, const Property::Value& value)
1459 switch(entry.GetType())
1461 case Property::BOOLEAN:
1463 const AnimatableProperty<bool>* property = dynamic_cast<const AnimatableProperty<bool>*>(entry.GetSceneGraphProperty());
1464 DALI_ASSERT_DEBUG(property);
1466 // property is being used in a separate thread; queue a message to set the property
1467 BakeMessage<bool>(GetEventThreadServices(), *property, value.Get<bool>());
1471 case Property::INTEGER:
1473 const AnimatableProperty<int32_t>* property = dynamic_cast<const AnimatableProperty<int32_t>*>(entry.GetSceneGraphProperty());
1474 DALI_ASSERT_DEBUG(property);
1476 // property is being used in a separate thread; queue a message to set the property
1477 BakeMessage<int32_t>(GetEventThreadServices(), *property, value.Get<int32_t>());
1481 case Property::FLOAT:
1483 const AnimatableProperty<float>* property = dynamic_cast<const AnimatableProperty<float>*>(entry.GetSceneGraphProperty());
1484 DALI_ASSERT_DEBUG(property);
1486 // property is being used in a separate thread; queue a message to set the property
1487 BakeMessage<float>(GetEventThreadServices(), *property, value.Get<float>());
1491 case Property::VECTOR2:
1493 const AnimatableProperty<Vector2>* property = dynamic_cast<const AnimatableProperty<Vector2>*>(entry.GetSceneGraphProperty());
1494 DALI_ASSERT_DEBUG(property);
1496 // property is being used in a separate thread; queue a message to set the property
1497 if(entry.componentIndex == 0)
1499 SetXComponentMessage<Vector2>(GetEventThreadServices(), *property, value.Get<float>());
1501 else if(entry.componentIndex == 1)
1503 SetYComponentMessage<Vector2>(GetEventThreadServices(), *property, value.Get<float>());
1507 BakeMessage<Vector2>(GetEventThreadServices(), *property, value.Get<Vector2>());
1512 case Property::VECTOR3:
1514 const AnimatableProperty<Vector3>* property = dynamic_cast<const AnimatableProperty<Vector3>*>(entry.GetSceneGraphProperty());
1515 DALI_ASSERT_DEBUG(property);
1517 // property is being used in a separate thread; queue a message to set the property
1518 if(entry.componentIndex == 0)
1520 SetXComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1522 else if(entry.componentIndex == 1)
1524 SetYComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1526 else if(entry.componentIndex == 2)
1528 SetZComponentMessage<Vector3>(GetEventThreadServices(), *property, value.Get<float>());
1532 BakeMessage<Vector3>(GetEventThreadServices(), *property, value.Get<Vector3>());
1538 case Property::VECTOR4:
1540 const AnimatableProperty<Vector4>* property = dynamic_cast<const AnimatableProperty<Vector4>*>(entry.GetSceneGraphProperty());
1541 DALI_ASSERT_DEBUG(property);
1543 // property is being used in a separate thread; queue a message to set the property
1544 if(entry.componentIndex == 0)
1546 SetXComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1548 else if(entry.componentIndex == 1)
1550 SetYComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1552 else if(entry.componentIndex == 2)
1554 SetZComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1556 else if(entry.componentIndex == 3)
1558 SetWComponentMessage<Vector4>(GetEventThreadServices(), *property, value.Get<float>());
1562 BakeMessage<Vector4>(GetEventThreadServices(), *property, value.Get<Vector4>());
1567 case Property::ROTATION:
1569 const AnimatableProperty<Quaternion>* property = dynamic_cast<const AnimatableProperty<Quaternion>*>(entry.GetSceneGraphProperty());
1570 DALI_ASSERT_DEBUG(property);
1572 // property is being used in a separate thread; queue a message to set the property
1573 BakeMessage<Quaternion>(GetEventThreadServices(), *property, value.Get<Quaternion>());
1577 case Property::MATRIX:
1579 const AnimatableProperty<Matrix>* property = dynamic_cast<const AnimatableProperty<Matrix>*>(entry.GetSceneGraphProperty());
1580 DALI_ASSERT_DEBUG(property);
1582 // property is being used in a separate thread; queue a message to set the property
1583 BakeMessage<Matrix>(GetEventThreadServices(), *property, value.Get<Matrix>());
1587 case Property::MATRIX3:
1589 const AnimatableProperty<Matrix3>* property = dynamic_cast<const AnimatableProperty<Matrix3>*>(entry.GetSceneGraphProperty());
1590 DALI_ASSERT_DEBUG(property);
1592 // property is being used in a separate thread; queue a message to set the property
1593 BakeMessage<Matrix3>(GetEventThreadServices(), *property, value.Get<Matrix3>());
1599 // non-animatable scene graph property, do nothing
1604 } // namespace Internal