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>
38 using Dali::Internal::SceneGraph::AnimatableProperty;
39 using Dali::Internal::SceneGraph::PropertyBase;
47 namespace // unnamed namespace
49 const int32_t SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
55 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
57 } // unnamed namespace
59 IntrusivePtr<Object> Object::New()
61 return new Object( nullptr ); // no scene object by default
64 void Object::AddObserver(Observer& observer)
66 // make sure an observer doesn't observe the same object twice
67 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
68 DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70 mObservers.PushBack( &observer );
73 void Object::RemoveObserver(Observer& observer)
75 // Find the observer...
76 const auto endIter = mObservers.End();
77 for( auto iter = mObservers.Begin(); iter != endIter; ++iter)
79 if( (*iter) == &observer)
81 mObservers.Erase( iter );
85 DALI_ASSERT_DEBUG(endIter != mObservers.End());
88 bool Object::Supports( Capability capability ) const
90 return (capability & SUPPORTED_CAPABILITIES);
93 uint32_t Object::GetPropertyCount() const
96 const TypeInfo* typeInfo( GetTypeInfo() );
99 count = typeInfo->GetPropertyCount();
101 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count );
104 uint32_t custom = static_cast<uint32_t>( mCustomProperties.Count() );
106 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
108 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
113 std::string Object::GetPropertyName( Property::Index index ) const
115 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
117 // is this a per class or per instance property
118 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
120 const TypeInfo* typeInfo( GetTypeInfo() );
123 return typeInfo->GetPropertyName( index );
126 else // child property or custom property
128 CustomPropertyMetadata* custom = FindCustomProperty( index );
135 DALI_LOG_ERROR( "Property index %d not found\n", index );
136 return std::string();
139 Property::Index Object::GetPropertyIndex( Property::Key key ) const
141 Property::Index index = Property::INVALID_INDEX;
143 if( key.type == Property::Key::STRING )
145 const TypeInfo* typeInfo( GetTypeInfo() );
148 index = typeInfo->GetPropertyIndex( key.stringKey );
152 if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
154 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
155 const auto end = mCustomProperties.End();
156 for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
158 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
160 if( ( key.type == Property::Key::STRING && custom->name == key.stringKey) ||
161 ( key.type == Property::Key::INDEX && custom->key == key.indexKey ) )
163 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
165 // If it is a child property, return the child property index
166 index = custom->childPropertyIndex;
180 bool Object::IsPropertyWritable( Property::Index index ) const
182 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
184 bool writable = false;
186 // is this a per class or per instance property
187 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
189 const TypeInfo* typeInfo( GetTypeInfo() );
192 writable = typeInfo->IsPropertyWritable( index );
197 CustomPropertyMetadata* custom = FindCustomProperty( index );
200 writable = custom->IsWritable();
207 bool Object::IsPropertyAnimatable( Property::Index index ) const
209 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
211 bool animatable = false;
213 // is this a per class or per instance property
214 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
216 const TypeInfo* typeInfo( GetTypeInfo() );
219 animatable = typeInfo->IsPropertyAnimatable( index );
224 CustomPropertyMetadata* custom = FindCustomProperty( index );
227 animatable = custom->IsAnimatable();
234 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
236 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
238 bool isConstraintInput = false;
240 // is this a per class or per instance property
241 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
243 const TypeInfo* typeInfo( GetTypeInfo() );
246 isConstraintInput = typeInfo->IsPropertyAConstraintInput( index );
251 CustomPropertyMetadata* custom = FindCustomProperty( index );
254 // ... custom properties can be used as input to a constraint.
255 isConstraintInput = true;
259 return isConstraintInput;
262 Property::Type Object::GetPropertyType( Property::Index index ) const
264 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
266 // is this a per class or per instance property
267 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
269 const TypeInfo* typeInfo( GetTypeInfo() );
272 return typeInfo->GetPropertyType( index );
276 CustomPropertyMetadata* custom = FindCustomProperty( index );
279 return custom->GetType();
282 return Property::NONE;
285 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
287 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
289 bool propertySet( true );
291 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
293 SetDefaultProperty( index, propertyValue );
295 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
297 const TypeInfo* typeInfo( GetTypeInfo() );
300 typeInfo->SetProperty( this, index, propertyValue );
304 // cannot register this property as there is no setter for it.
305 // event side properties must have a setter for now so need to be registered
306 DALI_LOG_ERROR( "Property index %d not found\n", index );
310 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
312 // check whether the animatable property is registered already, if not then register one.
313 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, &propertyValue );
314 if( !animatableProperty )
316 DALI_LOG_ERROR( "Property index %d not found\n", index );
321 // update the cached property value
322 animatableProperty->SetPropertyValue( propertyValue );
324 // set the scene graph property value
325 SetSceneGraphProperty( index, *animatableProperty, propertyValue );
330 CustomPropertyMetadata* custom = FindCustomProperty( index );
332 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
336 // If the child property is not registered yet, register it.
337 custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
338 mCustomProperties.PushBack( custom );
341 custom->childPropertyIndex = index;
343 // Resolve name for the child property
344 Object* parent = GetParentObject();
347 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
350 custom->name = parentTypeInfo->GetChildPropertyName( index );
357 if( custom->IsAnimatable() )
359 // update the cached property value
360 custom->SetPropertyValue( propertyValue );
362 // set the scene graph property value
363 SetSceneGraphProperty( index, *custom, propertyValue );
365 else if( custom->IsWritable() )
367 // update the cached property value
368 custom->SetPropertyValue( propertyValue );
372 // trying to set value on read only property is no-op
378 DALI_LOG_ERROR( "Property index %d not found\n", index );
383 // Let derived classes know that a property has been set
384 // 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
387 OnPropertySet( index, propertyValue );
388 Dali::Handle handle( this );
389 mPropertySetSignal.Emit( handle, index, propertyValue );
393 Property::Value Object::GetProperty( Property::Index index ) const
395 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
397 Property::Value value;
399 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
401 value = GetDefaultProperty( index );
403 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
405 const TypeInfo* typeInfo( GetTypeInfo() );
408 value = typeInfo->GetProperty( this, index );
412 DALI_LOG_ERROR( "Property index %d not found\n", index );
415 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
417 // check whether the animatable property is registered already, if not then register one.
418 // this is needed because property value may have been set as full property and get as a property component
419 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
420 if( animatableProperty )
422 // get the cached animatable property value
423 value = animatableProperty->GetPropertyValue();
427 DALI_LOG_ERROR( "Property index %d not found\n", index );
430 else if(mCustomProperties.Count() > 0)
432 CustomPropertyMetadata* custom = FindCustomProperty( index );
435 // get the cached custom property value
436 value = custom->GetPropertyValue();
440 DALI_LOG_ERROR( "Property index %d not found\n", index );
447 Property::Value Object::GetCurrentProperty( Property::Index index ) const
449 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
451 Property::Value value;
453 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
455 value = GetDefaultPropertyCurrentValue( index );
457 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
459 const TypeInfo* typeInfo( GetTypeInfo() );
462 value = typeInfo->GetProperty( this, index );
466 DALI_LOG_ERROR( "Property index %d not found\n", index );
469 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
471 // check whether the animatable property is registered already, if not then register one.
472 // this is needed because property value may have been set as full property and get as a property component
473 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
474 if( animatableProperty )
476 // get the animatable property value
477 value = GetCurrentPropertyValue( *animatableProperty );
481 DALI_LOG_ERROR( "Property index %d not found\n", index );
484 else if(mCustomProperties.Count() > 0)
486 CustomPropertyMetadata* custom = FindCustomProperty( index );
489 // get the custom property value
490 value = GetCurrentPropertyValue( *custom );
494 DALI_LOG_ERROR( "Property index %d not found\n", index );
501 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
506 const TypeInfo* typeInfo( GetTypeInfo() );
509 typeInfo->GetPropertyIndices( indices );
513 if ( mCustomProperties.Count() > 0 )
515 indices.Reserve( indices.Size() + mCustomProperties.Count() );
517 auto iter = mCustomProperties.Begin();
518 const auto endIter = mCustomProperties.End();
520 for ( ; iter != endIter; ++iter, ++i )
522 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
523 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
525 // If it is a child property, add the child property index
526 indices.PushBack( custom->childPropertyIndex );
530 indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
536 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
538 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
541 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
543 return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
546 void Object::SetProperties( const Property::Map& properties )
548 const auto count = properties.Count();
549 for( auto position = 0u; position < count; ++position )
551 // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
552 // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
554 const auto& key = properties.GetKeyAt( position );
555 const auto propertyIndex = ( key.type == Property::Key::INDEX ) ? key.indexKey : GetPropertyIndex( key );
557 if( propertyIndex != Property::INVALID_INDEX )
559 const auto& value = properties.GetValue( position );
560 SetProperty( propertyIndex, value );
565 void Object::GetProperties( Property::Map& properties )
569 Property::IndexContainer indexContainer;
570 GetPropertyIndices( indexContainer );
572 for( auto index : indexContainer )
574 properties[ index ] = GetProperty( index );
578 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
580 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
583 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
585 // If property with the required key already exists, then just set it.
586 Property::Index index = Property::INVALID_INDEX;
587 if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
589 index = GetPropertyIndex( key );
591 if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
593 index = GetPropertyIndex( name );
596 if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
598 SetProperty( index, propertyValue );
602 // Otherwise register the property
603 if( Property::ANIMATABLE == accessMode )
605 index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() ), propertyValue );
606 AddUniformMapping( index, name );
610 // Add entry to the property lookup
611 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
613 CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
615 // Resolve index for the child property
616 Object* parent = GetParentObject();
619 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
622 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
623 if( childPropertyIndex != Property::INVALID_INDEX )
625 customProperty->childPropertyIndex = childPropertyIndex;
626 index = childPropertyIndex;
631 mCustomProperties.PushBack( customProperty );
638 bool Object::DoesCustomPropertyExist( Property::Index index )
640 auto metadata = FindCustomProperty( index );
641 return metadata != nullptr;
644 Dali::PropertyNotification Object::AddPropertyNotification( Property::Index index,
645 int32_t componentIndex,
646 const Dali::PropertyCondition& condition)
648 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
650 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
652 DALI_ABORT( "Property notification added to event side only property." );
654 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
656 // check whether the animatable property is registered already, if not then register one.
657 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
658 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
660 else if ( mCustomProperties.Count() > 0 )
662 CustomPropertyMetadata* custom = FindCustomProperty( index );
663 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
664 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
668 Dali::Handle self(this);
669 Property target( self, index );
671 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
672 Dali::PropertyNotification propertyNotification(internal.Get());
674 if( !mPropertyNotifications )
676 mPropertyNotifications = new PropertyNotificationContainer;
678 mPropertyNotifications->push_back(propertyNotification);
680 return propertyNotification;
683 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
685 if( mPropertyNotifications )
687 auto iter = mPropertyNotifications->begin();
688 while(iter != mPropertyNotifications->end() )
690 if(*iter == propertyNotification)
692 mPropertyNotifications->erase(iter);
693 // As we can't ensure all references are removed, we can just disable
695 GetImplementation(propertyNotification).Disable();
703 void Object::RemovePropertyNotifications()
705 if( mPropertyNotifications )
707 auto iter = mPropertyNotifications->begin();
708 while(iter != mPropertyNotifications->end() )
710 // As we can't ensure all references are removed, we can just disable
712 GetImplementation(*iter).Disable();
716 mPropertyNotifications->clear();
720 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
722 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
724 OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
728 PropertyMetadata* propertyMetadata = nullptr;
729 if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
731 propertyMetadata = FindAnimatableProperty( index );
735 CustomPropertyMetadata* custom = FindCustomProperty( index );
736 if( custom && custom->IsAnimatable() )
738 propertyMetadata = custom;
742 if( propertyMetadata )
744 switch( animationType )
747 case Animation::BETWEEN:
749 // Update the cached property value
750 propertyMetadata->SetPropertyValue( value );
755 // Adjust the cached property value
756 propertyMetadata->AdjustPropertyValueBy( value );
764 void Object::AddUniformMapping(Property::Index propertyIndex, std::string uniformName) const
766 // Get the address of the property if it's a scene property
767 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
769 // Check instead for newly registered properties
770 if( propertyPtr == nullptr )
772 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
775 propertyPtr = animatable->GetSceneGraphProperty();
779 if( propertyPtr == nullptr )
781 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
784 propertyPtr = custom->GetSceneGraphProperty();
790 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
792 OwnerPointer<SceneGraph::UniformPropertyMapping> map =
793 new SceneGraph::UniformPropertyMapping(std::move(uniformName), propertyPtr);
794 // Message takes ownership of Uniform map (and will delete it after copy)
795 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map );
799 void Object::RemoveUniformMapping( const std::string& uniformName ) const
801 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
802 RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, uniformName);
805 void Object::ApplyConstraint( ConstraintBase& constraint )
809 mConstraints = new ConstraintContainer;
811 mConstraints->push_back( Dali::Constraint( &constraint ) );
814 void Object::RemoveConstraint( ConstraintBase& constraint )
816 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
819 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
820 if( it != mConstraints->end() )
822 mConstraints->erase( it );
827 void Object::RemoveConstraints()
829 // guard against constraint sending messages during core destruction
830 if( mConstraints && Stage::IsInstalled() )
832 for ( auto&& item : *mConstraints )
834 GetImplementation( item ).RemoveInternal();
838 mConstraints = nullptr;
842 void Object::RemoveConstraints( uint32_t tag )
844 // guard against constraint sending messages during core destruction
845 if( mConstraints && Stage::IsInstalled() )
847 auto iter( mConstraints->begin() );
848 while(iter != mConstraints->end() )
850 ConstraintBase& constraint = GetImplementation( *iter );
851 if( constraint.GetTag() == tag )
853 GetImplementation( *iter ).RemoveInternal();
854 iter = mConstraints->erase( iter );
862 if ( mConstraints->empty() )
865 mConstraints = nullptr;
870 void Object::SetTypeInfo( const TypeInfo* typeInfo )
872 mTypeInfo = typeInfo;
875 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
879 auto sceneObject = SceneGraph::PropertyOwner::New();
880 OwnerPointer< SceneGraph::PropertyOwner > transferOwnership( sceneObject );
881 mUpdateObject = sceneObject;
882 AddObjectMessage( const_cast<EventThreadServices&>( GetEventThreadServices() ).GetUpdateManager(), transferOwnership );
884 DALI_ASSERT_DEBUG( mUpdateObject && "there must always be a scene object" );
885 return *mUpdateObject;
888 const PropertyBase* Object::GetSceneObjectAnimatableProperty( Property::Index index ) const
890 const SceneGraph::PropertyBase* property = nullptr;
891 if ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX )
893 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
894 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
896 property = animatable->GetSceneGraphProperty();
898 else if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && // Child properties are also stored as custom properties
899 ( index <= PROPERTY_CUSTOM_MAX_INDEX ) )
901 CustomPropertyMetadata* custom = FindCustomProperty( index );
902 DALI_ASSERT_ALWAYS( custom && "Property index is invalid" );
904 property = custom->GetSceneGraphProperty();
909 const PropertyInputImpl* Object::GetSceneObjectInputProperty( Property::Index index ) const
911 // reuse animatable version as they are inputs as well
912 return GetSceneObjectAnimatableProperty( index );
915 int32_t Object::GetPropertyComponentIndex( Property::Index index ) const
917 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
919 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
921 // check whether the animatable property is registered already, if not then register one.
922 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
923 if( animatableProperty )
925 componentIndex = animatableProperty->componentIndex;
928 if( Property::INVALID_COMPONENT_INDEX == componentIndex )
930 const TypeInfo* typeInfo( GetTypeInfo() );
933 componentIndex = typeInfo->GetComponentIndex(index);
937 return componentIndex;
940 Handle::PropertySetSignalType& Object::PropertySetSignal()
942 return mPropertySetSignal;
945 Object::Object( const SceneGraph::PropertyOwner* sceneObject )
946 : mEventThreadServices( EventThreadServices::Get() ),
947 mUpdateObject( sceneObject ),
948 mTypeInfo( nullptr ),
949 mConstraints( nullptr ),
950 mPropertyNotifications( nullptr )
956 // Notification for observers
957 for( auto&& item : mObservers )
959 item->ObjectDestroyed( *this );
962 delete mPropertyNotifications;
964 // Guard to allow handle destruction after Core has been destroyed
965 if( Stage::IsInstalled() )
967 if( nullptr != mUpdateObject )
969 RemoveObjectMessage( GetEventThreadServices().GetUpdateManager(), mUpdateObject );
974 void Object::OnSceneObjectAdd()
976 // Notification for observers
977 for( auto&& item : mObservers )
979 item->SceneObjectAdded(*this);
982 // enable property notifications in scene graph
983 EnablePropertyNotifications();
986 void Object::OnSceneObjectRemove()
988 // Notification for observers
989 for( auto&& item : mObservers )
991 item->SceneObjectRemoved(*this);
994 // disable property notifications in scene graph
995 DisablePropertyNotifications();
998 const TypeInfo* Object::GetTypeInfo() const
1002 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1003 // especially as the type-info does not change during the life-time of an application
1005 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1006 if ( typeInfoHandle )
1008 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1015 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1017 CustomPropertyMetadata* property = nullptr;
1018 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1020 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1022 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1023 if( custom->childPropertyIndex == index )
1031 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1032 if( arrayIndex >= 0 )
1034 if( arrayIndex < static_cast<int32_t>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
1036 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1043 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1045 for( auto&& entry : mAnimatableProperties )
1047 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( entry );
1048 if( property->index == index )
1056 Property::Index Object::RegisterSceneGraphProperty( const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue ) const
1058 // Create a new property
1059 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1061 switch ( propertyValue.GetType() )
1063 case Property::BOOLEAN:
1065 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
1069 case Property::INTEGER:
1071 newProperty = new AnimatableProperty<int32_t>( propertyValue.Get<int32_t>() );
1075 case Property::FLOAT:
1077 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
1081 case Property::VECTOR2:
1083 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
1087 case Property::VECTOR3:
1089 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
1093 case Property::VECTOR4:
1095 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
1099 case Property::MATRIX:
1101 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
1105 case Property::MATRIX3:
1107 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
1111 case Property::ROTATION:
1113 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
1117 case Property::RECTANGLE:
1118 case Property::STRING:
1119 case Property::ARRAY:
1121 case Property::EXTENTS:
1122 case Property::NONE:
1124 DALI_ASSERT_ALWAYS( !"Property type is not animatable" );
1129 // get the scene property owner
1130 const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1131 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1132 const PropertyBase* property = newProperty.Get();
1133 if(index >= PROPERTY_CUSTOM_START_INDEX)
1135 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
1137 mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
1141 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
1144 // queue a message to add the property
1145 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty ); // Message takes ownership
1150 void Object::RegisterAnimatableProperty( const TypeInfo& typeInfo,
1151 Property::Index index,
1152 const Property::Value* value ) const
1154 // If the property is not a component of a base property, register the whole property itself.
1155 const std::string& propertyName = typeInfo.GetPropertyName( index );
1156 Property::Value initialValue;
1159 initialValue = *value;
1163 initialValue = typeInfo.GetPropertyDefaultValue( index ); // recurses type hierarchy
1164 if( Property::NONE == initialValue.GetType() )
1166 initialValue = Property::Value( typeInfo.GetPropertyType( index ) ); // recurses type hierarchy
1169 RegisterSceneGraphProperty( propertyName, Property::INVALID_KEY, index, initialValue );
1170 AddUniformMapping( index, propertyName );
1173 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty( Property::Index index, const Property::Value* value ) const
1175 // property range already checked by calling methods
1176 // check whether the animatable property is registered already, if not then register one.
1177 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1178 if( !animatableProperty )
1180 const TypeInfo* typeInfo( GetTypeInfo() );
1183 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex( index );
1184 if( basePropertyIndex == Property::INVALID_INDEX )
1186 // If the property is not a component of a base property, register the whole property itself.
1187 RegisterAnimatableProperty( *typeInfo, index, value );
1191 // Since the property is a component of a base property, check whether the base property is registered.
1192 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1193 if( !animatableProperty )
1195 // If the base property is not registered yet, register the base property first.
1196 RegisterAnimatableProperty( *typeInfo, basePropertyIndex, value );
1197 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1200 // Create the metadata for the property component.
1201 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1204 // The metadata has just been added and therefore should be in the end of the vector.
1205 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1209 return animatableProperty;
1212 void Object::ResolveChildProperties()
1214 // Resolve index for the child property
1215 Object* parent = GetParentObject();
1218 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1219 if( parentTypeInfo )
1221 // Go through each custom property
1222 for( auto&& entry : mCustomProperties )
1224 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
1226 if( customProperty->name.empty() )
1228 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1230 // Resolve name for any child property with no name
1231 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1236 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1237 if( childPropertyIndex != Property::INVALID_INDEX )
1239 // Resolve index for any property with a name that matches the parent's child property name
1240 customProperty->childPropertyIndex = childPropertyIndex;
1248 void Object::SetDefaultProperty( Property::Index index, const Property::Value& property )
1253 Property::Value Object::GetDefaultProperty(Property::Index index) const
1255 return Property::Value();
1258 Property::Value Object::GetDefaultPropertyCurrentValue( Property::Index index ) const
1260 return GetDefaultProperty( index );
1263 void Object::EnablePropertyNotifications()
1265 if( mPropertyNotifications )
1267 for( auto&& element : *mPropertyNotifications )
1269 GetImplementation( element ).Enable();
1274 void Object::DisablePropertyNotifications()
1276 if( mPropertyNotifications )
1278 for( auto&& element : *mPropertyNotifications )
1280 GetImplementation( element ).Disable();
1285 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata& entry ) const
1287 Property::Value value;
1289 if( !entry.IsAnimatable() )
1291 value = entry.GetPropertyValue();
1295 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1297 switch ( entry.GetType() )
1299 case Property::BOOLEAN:
1301 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1302 DALI_ASSERT_DEBUG( property );
1304 value = (*property)[ bufferIndex ];
1308 case Property::INTEGER:
1310 const AnimatableProperty<int32_t>* property = static_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1311 DALI_ASSERT_DEBUG( property );
1313 value = (*property)[ bufferIndex ];
1317 case Property::FLOAT:
1319 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1320 DALI_ASSERT_DEBUG( property );
1322 value = (*property)[ bufferIndex ];
1326 case Property::VECTOR2:
1328 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1329 DALI_ASSERT_DEBUG( property );
1331 if(entry.componentIndex == 0)
1333 value = (*property)[ bufferIndex ].x;
1335 else if(entry.componentIndex == 1)
1337 value = (*property)[ bufferIndex ].y;
1341 value = (*property)[ bufferIndex ];
1346 case Property::VECTOR3:
1348 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1349 DALI_ASSERT_DEBUG( property );
1351 if(entry.componentIndex == 0)
1353 value = (*property)[ bufferIndex ].x;
1355 else if(entry.componentIndex == 1)
1357 value = (*property)[ bufferIndex ].y;
1359 else if(entry.componentIndex == 2)
1361 value = (*property)[ bufferIndex ].z;
1365 value = (*property)[ bufferIndex ];
1370 case Property::VECTOR4:
1372 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( 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;
1387 else if(entry.componentIndex == 3)
1389 value = (*property)[ bufferIndex ].w;
1393 value = (*property)[ bufferIndex ];
1398 case Property::MATRIX:
1400 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1401 DALI_ASSERT_DEBUG( property );
1403 value = (*property)[ bufferIndex ];
1407 case Property::MATRIX3:
1409 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1410 DALI_ASSERT_DEBUG( property );
1412 value = (*property)[ bufferIndex ];
1416 case Property::ROTATION:
1418 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1419 DALI_ASSERT_DEBUG( property );
1421 value = (*property)[ bufferIndex ];
1427 // unreachable code due to higher level logic
1435 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1437 switch ( entry.GetType() )
1439 case Property::BOOLEAN:
1441 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1442 DALI_ASSERT_DEBUG( property );
1444 // property is being used in a separate thread; queue a message to set the property
1445 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1449 case Property::INTEGER:
1451 const AnimatableProperty<int32_t>* property = dynamic_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1452 DALI_ASSERT_DEBUG( property );
1454 // property is being used in a separate thread; queue a message to set the property
1455 BakeMessage<int32_t>( GetEventThreadServices(), *property, value.Get<int32_t>() );
1459 case Property::FLOAT:
1461 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1462 DALI_ASSERT_DEBUG( property );
1464 // property is being used in a separate thread; queue a message to set the property
1465 BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1469 case Property::VECTOR2:
1471 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1472 DALI_ASSERT_DEBUG( property );
1474 // property is being used in a separate thread; queue a message to set the property
1475 if(entry.componentIndex == 0)
1477 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1479 else if(entry.componentIndex == 1)
1481 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1485 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1490 case Property::VECTOR3:
1492 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1493 DALI_ASSERT_DEBUG( property );
1495 // property is being used in a separate thread; queue a message to set the property
1496 if(entry.componentIndex == 0)
1498 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1500 else if(entry.componentIndex == 1)
1502 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1504 else if(entry.componentIndex == 2)
1506 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1510 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1516 case Property::VECTOR4:
1518 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1519 DALI_ASSERT_DEBUG( property );
1521 // property is being used in a separate thread; queue a message to set the property
1522 if(entry.componentIndex == 0)
1524 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1526 else if(entry.componentIndex == 1)
1528 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1530 else if(entry.componentIndex == 2)
1532 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1534 else if(entry.componentIndex == 3)
1536 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1540 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1545 case Property::ROTATION:
1547 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1548 DALI_ASSERT_DEBUG( property );
1550 // property is being used in a separate thread; queue a message to set the property
1551 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1555 case Property::MATRIX:
1557 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1558 DALI_ASSERT_DEBUG( property );
1560 // property is being used in a separate thread; queue a message to set the property
1561 BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1565 case Property::MATRIX3:
1567 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1568 DALI_ASSERT_DEBUG( property );
1570 // property is being used in a separate thread; queue a message to set the property
1571 BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1577 // non-animatable scene graph property, do nothing
1582 } // namespace Internal