2 * Copyright (c) 2020 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/integration-api/debug.h>
26 #include <dali/devel-api/object/handle-devel.h>
27 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
28 #include <dali/internal/update/common/animatable-property.h>
29 #include <dali/internal/update/common/property-owner.h>
30 #include <dali/internal/update/common/property-owner-messages.h>
31 #include <dali/internal/update/common/uniform-map.h>
32 #include <dali/internal/event/animation/constraint-impl.h>
33 #include <dali/internal/event/common/property-helper.h>
34 #include <dali/internal/event/common/property-notification-impl.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/type-registry-impl.h>
37 #include <dali/internal/common/const-string.h>
39 using Dali::Internal::SceneGraph::AnimatableProperty;
40 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 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 );
136 DALI_LOG_ERROR( "Property index %d not found\n", index );
137 return std::string();
140 Property::Index Object::GetPropertyIndex( Property::Key key ) const
142 Property::Index index = Property::INVALID_INDEX;
144 if( key.type == Property::Key::STRING )
146 const TypeInfo* typeInfo( GetTypeInfo() );
149 index = typeInfo->GetPropertyIndex( key.stringKey );
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.type == Property::Key::STRING && custom->name == key.stringKey) ||
162 ( key.type == Property::Key::INDEX && custom->key == key.indexKey ) )
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 = 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 Property::Index Object::RegisterProperty(std::string name, Property::Value propertyValue)
542 return RegisterProperty(std::move(name), Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE);
545 Property::Index Object::RegisterProperty(std::string name, Property::Index key, Property::Value propertyValue)
547 return RegisterProperty(std::move(name), key, std::move(propertyValue), Property::ANIMATABLE);
550 void Object::SetProperties( const Property::Map& properties )
552 const auto count = properties.Count();
553 for( auto position = 0u; position < count; ++position )
555 // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
556 // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
558 const auto& key = properties.GetKeyAt( position );
559 const auto propertyIndex = ( key.type == Property::Key::INDEX ) ? key.indexKey : GetPropertyIndex( key );
561 if( propertyIndex != Property::INVALID_INDEX )
563 const auto& value = properties.GetValue( position );
564 SetProperty( propertyIndex, value );
569 void Object::GetProperties( Property::Map& properties )
573 Property::IndexContainer indexContainer;
574 GetPropertyIndices( indexContainer );
576 for( auto index : indexContainer )
578 properties[ index ] = GetProperty( index );
582 Property::Index Object::RegisterProperty(std::string name,
583 Property::Value propertyValue,
584 Property::AccessMode accessMode)
586 return RegisterProperty(std::move(name), Property::INVALID_KEY, std::move(propertyValue), accessMode);
589 Property::Index Object::RegisterProperty(std::string name,
591 Property::Value propertyValue,
592 Property::AccessMode accessMode)
594 // If property with the required key already exists, then just set it.
595 Property::Index index = Property::INVALID_INDEX;
596 if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
598 index = GetPropertyIndex( key );
600 if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
602 index = GetPropertyIndex( name );
605 if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
607 SetProperty(index, std::move(propertyValue));
611 // Otherwise register the property
612 if( Property::ANIMATABLE == accessMode )
614 index = RegisterSceneGraphProperty(
617 PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
618 std::move(propertyValue));
619 AddUniformMapping(index, std::move(name));
623 // Add entry to the property lookup
624 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
626 CustomPropertyMetadata* customProperty =
627 new CustomPropertyMetadata(std::move(name), std::move(propertyValue), accessMode);
629 // Resolve index for the child property
630 Object* parent = GetParentObject();
633 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
636 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
637 if( childPropertyIndex != Property::INVALID_INDEX )
639 customProperty->childPropertyIndex = childPropertyIndex;
640 index = childPropertyIndex;
645 mCustomProperties.PushBack( customProperty );
652 bool Object::DoesCustomPropertyExist( Property::Index index )
654 auto metadata = FindCustomProperty( index );
655 return metadata != nullptr;
658 Dali::PropertyNotification Object::AddPropertyNotification( Property::Index index,
659 int32_t componentIndex,
660 const Dali::PropertyCondition& condition)
662 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
664 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
666 DALI_ABORT( "Property notification added to event side only property." );
668 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
670 // check whether the animatable property is registered already, if not then register one.
671 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
672 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
674 else if ( mCustomProperties.Count() > 0 )
676 CustomPropertyMetadata* custom = FindCustomProperty( index );
677 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
678 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
682 Dali::Handle self(this);
683 Property target( self, index );
685 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
686 Dali::PropertyNotification propertyNotification(internal.Get());
688 if( !mPropertyNotifications )
690 mPropertyNotifications = new PropertyNotificationContainer;
692 mPropertyNotifications->push_back(propertyNotification);
694 return propertyNotification;
697 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
699 if( mPropertyNotifications )
701 auto iter = mPropertyNotifications->begin();
702 while(iter != mPropertyNotifications->end() )
704 if(*iter == propertyNotification)
706 mPropertyNotifications->erase(iter);
707 // As we can't ensure all references are removed, we can just disable
709 GetImplementation(propertyNotification).Disable();
717 void Object::RemovePropertyNotifications()
719 if( mPropertyNotifications )
721 auto iter = mPropertyNotifications->begin();
722 while(iter != mPropertyNotifications->end() )
724 // As we can't ensure all references are removed, we can just disable
726 GetImplementation(*iter).Disable();
730 mPropertyNotifications->clear();
734 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
736 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
738 OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
742 PropertyMetadata* propertyMetadata = nullptr;
743 if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
745 propertyMetadata = FindAnimatableProperty( index );
749 CustomPropertyMetadata* custom = FindCustomProperty( index );
750 if( custom && custom->IsAnimatable() )
752 propertyMetadata = custom;
756 if( propertyMetadata )
758 switch( animationType )
761 case Animation::BETWEEN:
763 // Update the cached property value
764 propertyMetadata->SetPropertyValue( value );
769 // Adjust the cached property value
770 propertyMetadata->AdjustPropertyValueBy( value );
778 void Object::AddUniformMapping(Property::Index propertyIndex, std::string uniformName) const
780 // Get the address of the property if it's a scene property
781 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
783 // Check instead for newly registered properties
784 if( propertyPtr == nullptr )
786 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
789 propertyPtr = animatable->GetSceneGraphProperty();
793 if( propertyPtr == nullptr )
795 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
798 propertyPtr = custom->GetSceneGraphProperty();
804 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
806 OwnerPointer<SceneGraph::UniformPropertyMapping> map =
807 new SceneGraph::UniformPropertyMapping(ConstString(uniformName), propertyPtr);
808 // Message takes ownership of Uniform map (and will delete it after copy)
809 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map );
813 void Object::RemoveUniformMapping( const std::string& uniformName ) const
815 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
816 RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
819 void Object::ApplyConstraint( ConstraintBase& constraint )
823 mConstraints = new ConstraintContainer;
825 mConstraints->push_back( Dali::Constraint( &constraint ) );
828 void Object::RemoveConstraint( ConstraintBase& constraint )
830 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
833 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
834 if( it != mConstraints->end() )
836 mConstraints->erase( it );
841 void Object::RemoveConstraints()
843 // guard against constraint sending messages during core destruction
844 if( mConstraints && Stage::IsInstalled() )
846 for ( auto&& item : *mConstraints )
848 GetImplementation( item ).RemoveInternal();
852 mConstraints = nullptr;
856 void Object::RemoveConstraints( uint32_t tag )
858 // guard against constraint sending messages during core destruction
859 if( mConstraints && Stage::IsInstalled() )
861 auto iter( mConstraints->begin() );
862 while(iter != mConstraints->end() )
864 ConstraintBase& constraint = GetImplementation( *iter );
865 if( constraint.GetTag() == tag )
867 GetImplementation( *iter ).RemoveInternal();
868 iter = mConstraints->erase( iter );
876 if ( mConstraints->empty() )
879 mConstraints = nullptr;
884 void Object::SetTypeInfo( const TypeInfo* typeInfo )
886 mTypeInfo = typeInfo;
889 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
893 auto sceneObject = SceneGraph::PropertyOwner::New();
894 OwnerPointer< SceneGraph::PropertyOwner > transferOwnership( sceneObject );
895 mUpdateObject = sceneObject;
896 AddObjectMessage( const_cast<EventThreadServices&>( GetEventThreadServices() ).GetUpdateManager(), transferOwnership );
898 DALI_ASSERT_DEBUG( mUpdateObject && "there must always be a scene object" );
899 return *mUpdateObject;
902 const PropertyBase* Object::GetSceneObjectAnimatableProperty( Property::Index index ) const
904 const SceneGraph::PropertyBase* property = nullptr;
905 if ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX )
907 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
908 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
910 property = animatable->GetSceneGraphProperty();
912 else if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && // Child properties are also stored as custom properties
913 ( index <= PROPERTY_CUSTOM_MAX_INDEX ) )
915 CustomPropertyMetadata* custom = FindCustomProperty( index );
916 DALI_ASSERT_ALWAYS( custom && "Property index is invalid" );
918 property = custom->GetSceneGraphProperty();
923 const PropertyInputImpl* Object::GetSceneObjectInputProperty( Property::Index index ) const
925 // reuse animatable version as they are inputs as well
926 return GetSceneObjectAnimatableProperty( index );
929 int32_t Object::GetPropertyComponentIndex( Property::Index index ) const
931 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
933 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
935 // check whether the animatable property is registered already, if not then register one.
936 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
937 if( animatableProperty )
939 componentIndex = animatableProperty->componentIndex;
942 if( Property::INVALID_COMPONENT_INDEX == componentIndex )
944 const TypeInfo* typeInfo( GetTypeInfo() );
947 componentIndex = typeInfo->GetComponentIndex(index);
951 return componentIndex;
954 Handle::PropertySetSignalType& Object::PropertySetSignal()
956 return mPropertySetSignal;
959 Object::Object( const SceneGraph::PropertyOwner* sceneObject )
960 : mEventThreadServices( EventThreadServices::Get() ),
961 mUpdateObject( sceneObject ),
962 mTypeInfo( nullptr ),
963 mConstraints( nullptr ),
964 mPropertyNotifications( nullptr )
970 // Notification for observers
971 for( auto&& item : mObservers )
973 item->ObjectDestroyed( *this );
976 delete mPropertyNotifications;
978 // Guard to allow handle destruction after Core has been destroyed
979 if( Stage::IsInstalled() )
981 if( nullptr != mUpdateObject )
983 RemoveObjectMessage( GetEventThreadServices().GetUpdateManager(), mUpdateObject );
988 void Object::OnSceneObjectAdd()
990 // Notification for observers
991 for( auto&& item : mObservers )
993 item->SceneObjectAdded(*this);
996 // enable property notifications in scene graph
997 EnablePropertyNotifications();
1000 void Object::OnSceneObjectRemove()
1002 // Notification for observers
1003 for( auto&& item : mObservers )
1005 item->SceneObjectRemoved(*this);
1008 // disable property notifications in scene graph
1009 DisablePropertyNotifications();
1012 const TypeInfo* Object::GetTypeInfo() const
1016 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1017 // especially as the type-info does not change during the life-time of an application
1019 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1020 if ( typeInfoHandle )
1022 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1029 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1031 CustomPropertyMetadata* property = nullptr;
1032 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1034 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1036 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1037 if( custom->childPropertyIndex == index )
1045 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1046 if( arrayIndex >= 0 )
1048 if( arrayIndex < static_cast<int32_t>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
1050 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1057 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1059 for( auto&& entry : mAnimatableProperties )
1061 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( entry );
1062 if( property->index == index )
1070 Property::Index Object::RegisterSceneGraphProperty( std::string name, Property::Index key, Property::Index index, Property::Value propertyValue ) const
1072 // Create a new property
1073 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1075 switch ( propertyValue.GetType() )
1077 case Property::BOOLEAN:
1079 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
1083 case Property::INTEGER:
1085 newProperty = new AnimatableProperty<int32_t>( propertyValue.Get<int32_t>() );
1089 case Property::FLOAT:
1091 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
1095 case Property::VECTOR2:
1097 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
1101 case Property::VECTOR3:
1103 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
1107 case Property::VECTOR4:
1109 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
1113 case Property::MATRIX:
1115 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
1119 case Property::MATRIX3:
1121 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
1125 case Property::ROTATION:
1127 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
1131 case Property::RECTANGLE:
1132 case Property::STRING:
1133 case Property::ARRAY:
1135 case Property::EXTENTS:
1136 case Property::NONE:
1138 DALI_ASSERT_ALWAYS( !"Property type is not animatable" );
1143 // get the scene property owner
1144 const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1145 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1146 const PropertyBase* property = newProperty.Get();
1147 if(index >= PROPERTY_CUSTOM_START_INDEX)
1149 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
1151 mCustomProperties.PushBack( new CustomPropertyMetadata( std::move(name), key, std::move(propertyValue), property ) );
1155 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, std::move(propertyValue), property ) );
1158 // queue a message to add the property
1159 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty ); // Message takes ownership
1164 void Object::RegisterAnimatableProperty( const TypeInfo& typeInfo,
1165 Property::Index index,
1166 const Property::Value* value ) const
1168 // If the property is not a component of a base property, register the whole property itself.
1169 const std::string& propertyName = typeInfo.GetPropertyName( index );
1170 Property::Value initialValue;
1173 initialValue = *value;
1177 initialValue = typeInfo.GetPropertyDefaultValue( index ); // recurses type hierarchy
1178 if( Property::NONE == initialValue.GetType() )
1180 initialValue = Property::Value( typeInfo.GetPropertyType( index ) ); // recurses type hierarchy
1183 RegisterSceneGraphProperty( propertyName, Property::INVALID_KEY, index, initialValue );
1184 AddUniformMapping( index, propertyName );
1187 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty( Property::Index index, const Property::Value* value ) const
1189 // property range already checked by calling methods
1190 // check whether the animatable property is registered already, if not then register one.
1191 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1192 if( !animatableProperty )
1194 const TypeInfo* typeInfo( GetTypeInfo() );
1197 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex( index );
1198 if( basePropertyIndex == Property::INVALID_INDEX )
1200 // If the property is not a component of a base property, register the whole property itself.
1201 RegisterAnimatableProperty( *typeInfo, index, value );
1205 // Since the property is a component of a base property, check whether the base property is registered.
1206 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1207 if( !animatableProperty )
1209 // If the base property is not registered yet, register the base property first.
1210 RegisterAnimatableProperty( *typeInfo, basePropertyIndex, value );
1211 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1214 // Create the metadata for the property component.
1215 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1218 // The metadata has just been added and therefore should be in the end of the vector.
1219 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1223 return animatableProperty;
1226 void Object::ResolveChildProperties()
1228 // Resolve index for the child property
1229 Object* parent = GetParentObject();
1232 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1233 if( parentTypeInfo )
1235 // Go through each custom property
1236 for( auto&& entry : mCustomProperties )
1238 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
1240 if( customProperty->name.empty() )
1242 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1244 // Resolve name for any child property with no name
1245 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1250 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1251 if( childPropertyIndex != Property::INVALID_INDEX )
1253 // Resolve index for any property with a name that matches the parent's child property name
1254 customProperty->childPropertyIndex = childPropertyIndex;
1262 void Object::SetDefaultProperty( Property::Index index, const Property::Value& property )
1267 Property::Value Object::GetDefaultProperty(Property::Index index) const
1269 return Property::Value();
1272 Property::Value Object::GetDefaultPropertyCurrentValue( Property::Index index ) const
1274 return GetDefaultProperty( index );
1277 void Object::EnablePropertyNotifications()
1279 if( mPropertyNotifications )
1281 for( auto&& element : *mPropertyNotifications )
1283 GetImplementation( element ).Enable();
1288 void Object::DisablePropertyNotifications()
1290 if( mPropertyNotifications )
1292 for( auto&& element : *mPropertyNotifications )
1294 GetImplementation( element ).Disable();
1299 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata& entry ) const
1301 Property::Value value;
1303 if( !entry.IsAnimatable() )
1305 value = entry.GetPropertyValue();
1309 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1311 switch ( entry.GetType() )
1313 case Property::BOOLEAN:
1315 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1316 DALI_ASSERT_DEBUG( property );
1318 value = (*property)[ bufferIndex ];
1322 case Property::INTEGER:
1324 const AnimatableProperty<int32_t>* property = static_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1325 DALI_ASSERT_DEBUG( property );
1327 value = (*property)[ bufferIndex ];
1331 case Property::FLOAT:
1333 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1334 DALI_ASSERT_DEBUG( property );
1336 value = (*property)[ bufferIndex ];
1340 case Property::VECTOR2:
1342 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1343 DALI_ASSERT_DEBUG( property );
1345 if(entry.componentIndex == 0)
1347 value = (*property)[ bufferIndex ].x;
1349 else if(entry.componentIndex == 1)
1351 value = (*property)[ bufferIndex ].y;
1355 value = (*property)[ bufferIndex ];
1360 case Property::VECTOR3:
1362 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1363 DALI_ASSERT_DEBUG( property );
1365 if(entry.componentIndex == 0)
1367 value = (*property)[ bufferIndex ].x;
1369 else if(entry.componentIndex == 1)
1371 value = (*property)[ bufferIndex ].y;
1373 else if(entry.componentIndex == 2)
1375 value = (*property)[ bufferIndex ].z;
1379 value = (*property)[ bufferIndex ];
1384 case Property::VECTOR4:
1386 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1387 DALI_ASSERT_DEBUG( property );
1389 if(entry.componentIndex == 0)
1391 value = (*property)[ bufferIndex ].x;
1393 else if(entry.componentIndex == 1)
1395 value = (*property)[ bufferIndex ].y;
1397 else if(entry.componentIndex == 2)
1399 value = (*property)[ bufferIndex ].z;
1401 else if(entry.componentIndex == 3)
1403 value = (*property)[ bufferIndex ].w;
1407 value = (*property)[ bufferIndex ];
1412 case Property::MATRIX:
1414 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1415 DALI_ASSERT_DEBUG( property );
1417 value = (*property)[ bufferIndex ];
1421 case Property::MATRIX3:
1423 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1424 DALI_ASSERT_DEBUG( property );
1426 value = (*property)[ bufferIndex ];
1430 case Property::ROTATION:
1432 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1433 DALI_ASSERT_DEBUG( property );
1435 value = (*property)[ bufferIndex ];
1441 // unreachable code due to higher level logic
1449 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1451 switch ( entry.GetType() )
1453 case Property::BOOLEAN:
1455 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1456 DALI_ASSERT_DEBUG( property );
1458 // property is being used in a separate thread; queue a message to set the property
1459 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1463 case Property::INTEGER:
1465 const AnimatableProperty<int32_t>* property = dynamic_cast< const AnimatableProperty<int32_t>* >( 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<int32_t>( GetEventThreadServices(), *property, value.Get<int32_t>() );
1473 case Property::FLOAT:
1475 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( 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<float>( GetEventThreadServices(), *property, value.Get<float>() );
1483 case Property::VECTOR2:
1485 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1486 DALI_ASSERT_DEBUG( property );
1488 // property is being used in a separate thread; queue a message to set the property
1489 if(entry.componentIndex == 0)
1491 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1493 else if(entry.componentIndex == 1)
1495 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1499 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1504 case Property::VECTOR3:
1506 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1507 DALI_ASSERT_DEBUG( property );
1509 // property is being used in a separate thread; queue a message to set the property
1510 if(entry.componentIndex == 0)
1512 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1514 else if(entry.componentIndex == 1)
1516 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1518 else if(entry.componentIndex == 2)
1520 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1524 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1530 case Property::VECTOR4:
1532 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1533 DALI_ASSERT_DEBUG( property );
1535 // property is being used in a separate thread; queue a message to set the property
1536 if(entry.componentIndex == 0)
1538 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1540 else if(entry.componentIndex == 1)
1542 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1544 else if(entry.componentIndex == 2)
1546 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1548 else if(entry.componentIndex == 3)
1550 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1554 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1559 case Property::ROTATION:
1561 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1562 DALI_ASSERT_DEBUG( property );
1564 // property is being used in a separate thread; queue a message to set the property
1565 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1569 case Property::MATRIX:
1571 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( 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<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1579 case Property::MATRIX3:
1581 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( 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<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1591 // non-animatable scene graph property, do nothing
1596 } // namespace Internal