2 * Copyright (c) 2017 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/internal/update/animation/scene-graph-constraint-base.h>
27 #include <dali/internal/update/common/animatable-property.h>
28 #include <dali/internal/update/common/property-owner-messages.h>
29 #include <dali/internal/update/common/uniform-map.h>
30 #include <dali/internal/event/animation/constraint-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/property-notification-impl.h>
33 #include <dali/internal/event/common/type-registry-impl.h>
35 using Dali::Internal::SceneGraph::AnimatableProperty;
36 using Dali::Internal::SceneGraph::PropertyBase;
44 namespace // unnamed namespace
46 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
47 typedef Dali::Vector<Object::Observer*>::Iterator ObserverIter;
48 typedef Dali::Vector<Object::Observer*>::ConstIterator ConstObserverIter;
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
55 } // unnamed namespace
58 : mEventThreadServices( *Stage::GetCurrent() ),
61 mPropertyNotifications( NULL )
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 ConstObserverIter endIter = mObservers.End();
78 for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
80 if( (*iter) == &observer)
82 mObservers.Erase( iter );
86 DALI_ASSERT_DEBUG(endIter != mObservers.End());
89 void Object::OnSceneObjectAdd()
91 // Notification for observers
92 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
94 (*iter)->SceneObjectAdded(*this);
97 // enable property notifications in scene graph
98 EnablePropertyNotifications();
101 void Object::OnSceneObjectRemove()
103 // Notification for observers
104 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
106 (*iter)->SceneObjectRemoved(*this);
109 // disable property notifications in scene graph
110 DisablePropertyNotifications();
113 int Object::GetPropertyComponentIndex( Property::Index index ) const
115 int componentIndex = Property::INVALID_COMPONENT_INDEX;
117 const TypeInfo* typeInfo( GetTypeInfo() );
120 componentIndex = typeInfo->GetComponentIndex(index);
123 // For animatable property, check whether it is registered already and register it if not yet.
124 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) && ( NULL == RegisterAnimatableProperty(index) ) )
126 componentIndex = Property::INVALID_COMPONENT_INDEX;
129 return componentIndex;
132 bool Object::Supports( Capability capability ) const
134 return (capability & SUPPORTED_CAPABILITIES);
137 unsigned int Object::GetPropertyCount() const
139 unsigned int count = GetDefaultPropertyCount();
141 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
143 const TypeInfo* typeInfo( GetTypeInfo() );
146 unsigned int manual( typeInfo->GetPropertyCount() );
149 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties: %d\n", manual );
152 unsigned int custom( mCustomProperties.Count() );
154 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
156 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
161 std::string Object::GetPropertyName( Property::Index index ) const
163 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
165 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
169 const char * propertyName = GetDefaultPropertyName( index );
172 string = propertyName;
177 if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
178 || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
180 const TypeInfo* typeInfo( GetTypeInfo() );
183 return typeInfo->GetPropertyName( index );
187 DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
191 CustomPropertyMetadata* custom = FindCustomProperty( index );
199 Property::Index Object::GetPropertyIndex(const std::string& name) const
201 Property::Index index = GetDefaultPropertyIndex( name );
203 if(index == Property::INVALID_INDEX)
205 const TypeInfo* typeInfo( GetTypeInfo() );
208 index = typeInfo->GetPropertyIndex( name );
209 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
211 // check whether the animatable property is registered already, if not then register one.
212 if ( NULL == RegisterAnimatableProperty(index) )
214 index = Property::INVALID_INDEX;
220 if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
222 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
223 const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
224 for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
226 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
227 if ( custom->name == name )
229 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
231 // If it is a child property, return the child property index
232 index = custom->childPropertyIndex;
246 Property::Index Object::GetPropertyIndex( Property::Index key ) const
248 Property::Index index = Property::INVALID_INDEX;
250 if( mCustomProperties.Count() > 0 )
252 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
253 const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
254 for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
256 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
257 if( custom->key == key )
259 if( custom->childPropertyIndex != Property::INVALID_INDEX )
261 // If it is a child property, return the child property index
262 index = custom->childPropertyIndex;
276 Property::Index Object::GetPropertyIndex( Property::Key key ) const
278 Property::Index index = Property::INVALID_INDEX;
279 if( key.type == Property::Key::INDEX )
281 index = GetPropertyIndex( key.indexKey );
285 index = GetPropertyIndex( key.stringKey );
290 bool Object::IsPropertyWritable( Property::Index index ) const
292 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
294 bool writable = false;
296 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
298 writable = IsDefaultPropertyWritable( index );
300 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
302 const TypeInfo* typeInfo( GetTypeInfo() );
305 writable = typeInfo->IsPropertyWritable( index );
309 DALI_ASSERT_ALWAYS( ! "Invalid property index" );
312 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
314 // Type Registry scene-graph properties are writable.
319 CustomPropertyMetadata* custom = FindCustomProperty( index );
322 writable = custom->IsWritable();
329 bool Object::IsPropertyAnimatable( Property::Index index ) const
331 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
333 bool animatable = false;
335 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
337 animatable = IsDefaultPropertyAnimatable( index );
339 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
341 // Type Registry event-thread only properties are not animatable.
344 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
346 // Type Registry scene-graph properties are animatable.
351 CustomPropertyMetadata* custom = FindCustomProperty( index );
354 animatable = custom->IsAnimatable();
361 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
363 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
365 bool isConstraintInput = false;
367 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
369 isConstraintInput = IsDefaultPropertyAConstraintInput( index );
371 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
373 // Type Registry event-thread only properties cannot be used as an input to a constraint.
374 isConstraintInput = false;
376 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
378 // scene graph properties can be used as input to a constraint.
379 isConstraintInput = true;
383 CustomPropertyMetadata* custom = FindCustomProperty( index );
386 // ... custom properties can be used as input to a constraint.
387 isConstraintInput = true;
391 return isConstraintInput;
394 Property::Type Object::GetPropertyType( Property::Index index ) const
396 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
398 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
400 return GetDefaultPropertyType( index );
403 if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
404 || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
406 const TypeInfo* typeInfo( GetTypeInfo() );
409 return typeInfo->GetPropertyType( index );
413 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
417 CustomPropertyMetadata* custom = FindCustomProperty( index );
420 return custom->GetType();
423 return Property::NONE;
426 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
428 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
430 bool propertySet( true );
432 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
434 SetDefaultProperty( index, propertyValue );
436 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
438 const TypeInfo* typeInfo( GetTypeInfo() );
441 typeInfo->SetProperty( this, index, propertyValue );
445 DALI_LOG_ERROR("Cannot find property index\n");
449 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
451 // check whether the animatable property is registered already, if not then register one.
452 AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
453 if(!animatableProperty)
455 DALI_LOG_ERROR("Cannot find property index\n");
460 // update the cached property value
461 animatableProperty->SetPropertyValue( propertyValue );
463 // set the scene graph property value
464 SetSceneGraphProperty( index, *animatableProperty, propertyValue );
469 CustomPropertyMetadata* custom = FindCustomProperty( index );
471 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
475 // If the child property is not registered yet, register it.
476 custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
477 mCustomProperties.PushBack( custom );
480 custom->childPropertyIndex = index;
482 // Resolve name for the child property
483 Object* parent = GetParentObject();
486 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
489 custom->name = parentTypeInfo->GetChildPropertyName( index );
496 if( custom->IsAnimatable() )
498 // update the cached property value
499 custom->SetPropertyValue( propertyValue );
501 // set the scene graph property value
502 SetSceneGraphProperty( index, *custom, propertyValue );
504 else if( custom->IsWritable() )
506 // update the cached property value
507 custom->SetPropertyValue( propertyValue );
511 // trying to set value on read only property is no-op
517 DALI_LOG_ERROR("Invalid property index\n");
522 // Let derived classes know that a property has been set
523 // 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
526 OnPropertySet(index, propertyValue);
530 Property::Value Object::GetProperty(Property::Index index) const
532 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
534 Property::Value value;
536 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
538 value = GetDefaultProperty( index );
540 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
542 const TypeInfo* typeInfo( GetTypeInfo() );
545 value = typeInfo->GetProperty( this, index );
549 DALI_LOG_ERROR("Cannot find property index\n");
552 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
554 // check whether the animatable property is registered already, if not then register one.
555 AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
556 if(!animatableProperty)
558 DALI_LOG_ERROR("Cannot find property index\n");
562 // get the cached animatable property value
563 value = animatableProperty->GetPropertyValue();
566 else if(mCustomProperties.Count() > 0)
568 CustomPropertyMetadata* custom = FindCustomProperty( index );
571 // get the cached custom property value
572 value = custom->GetPropertyValue();
576 DALI_LOG_ERROR("Invalid property index\n");
583 Property::Value Object::GetCurrentProperty( Property::Index index ) const
585 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
587 Property::Value value;
589 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
591 value = GetDefaultPropertyCurrentValue( index );
593 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
595 const TypeInfo* typeInfo( GetTypeInfo() );
598 value = typeInfo->GetProperty( this, index );
602 DALI_LOG_ERROR("Cannot find property index\n");
605 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
607 // check whether the animatable property is registered already, if not then register one.
608 AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
609 if(!animatableProperty)
611 DALI_LOG_ERROR("Cannot find property index\n");
615 // get the animatable property value
616 value = GetCurrentPropertyValue( animatableProperty );
619 else if(mCustomProperties.Count() > 0)
621 CustomPropertyMetadata* custom = FindCustomProperty( index );
624 // get the custom property value
625 value = GetCurrentPropertyValue( custom );
629 DALI_LOG_ERROR("Invalid property index\n");
636 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
640 // Default Properties
641 GetDefaultPropertyIndices( indices );
644 const TypeInfo* typeInfo( GetTypeInfo() );
647 typeInfo->GetPropertyIndices( indices );
651 if ( mCustomProperties.Count() > 0 )
653 indices.Reserve( indices.Size() + mCustomProperties.Count() );
655 PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
656 const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
658 for ( ; iter != endIter; ++iter, ++i )
660 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
661 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
663 // If it is a child property, add the child property index
664 indices.PushBack( custom->childPropertyIndex );
668 indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
674 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue) const
676 // Create a new property
677 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
679 switch ( propertyValue.GetType() )
681 case Property::BOOLEAN:
683 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
687 case Property::INTEGER:
689 newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
693 case Property::FLOAT:
695 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
699 case Property::VECTOR2:
701 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
705 case Property::VECTOR3:
707 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
711 case Property::VECTOR4:
713 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
717 case Property::MATRIX:
719 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
723 case Property::MATRIX3:
725 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
729 case Property::ROTATION:
731 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
735 case Property::RECTANGLE:
736 case Property::STRING:
737 case Property::ARRAY:
741 DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
746 // get the scene property owner from derived class
747 const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
748 // we can only pass properties to scene graph side if there is a scene object
749 if( scenePropertyOwner )
751 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
752 const PropertyBase* property = newProperty.Get();
753 if(index >= PROPERTY_CUSTOM_START_INDEX)
755 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
757 mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
761 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
764 // queue a message to add the property
765 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
767 // notify the derived class (optional) method in case it needs to do some more work on the new property
768 // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
769 NotifyScenePropertyInstalled( *property, name, index );
775 // property was orphaned and killed so return invalid index
776 return Property::INVALID_INDEX;
780 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
782 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
785 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
787 return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
790 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
792 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
795 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
797 // If property with the required key already exists, then just set it.
798 Property::Index index = Property::INVALID_INDEX;
799 if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
801 index = GetPropertyIndex( key );
803 if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
805 index = GetPropertyIndex( name );
808 if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
810 SetProperty( index, propertyValue );
814 // Otherwise register the property
816 if( Property::ANIMATABLE == accessMode )
818 index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue );
819 AddUniformMapping( index, name );
823 // Add entry to the property lookup
824 index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
826 CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
828 // Resolve index for the child property
829 Object* parent = GetParentObject();
832 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
835 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
836 if( childPropertyIndex != Property::INVALID_INDEX )
838 customProperty->childPropertyIndex = childPropertyIndex;
839 index = childPropertyIndex;
844 mCustomProperties.PushBack( customProperty );
851 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
853 const Dali::PropertyCondition& condition)
855 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
857 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
859 DALI_ABORT( "Property notification added to event side only property." );
861 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
863 // check whether the animatable property is registered already, if not then register one.
864 AnimatablePropertyMetadata* animatable = RegisterAnimatableProperty( index );
865 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
867 else if ( mCustomProperties.Count() > 0 )
869 CustomPropertyMetadata* custom = FindCustomProperty( index );
870 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
871 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
875 Dali::Handle self(this);
876 Property target( self, index );
878 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
879 Dali::PropertyNotification propertyNotification(internal.Get());
881 if( !mPropertyNotifications )
883 mPropertyNotifications = new PropertyNotificationContainer;
885 mPropertyNotifications->push_back(propertyNotification);
887 return propertyNotification;
890 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
892 if( mPropertyNotifications )
894 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
895 while(iter != mPropertyNotifications->end() )
897 if(*iter == propertyNotification)
899 mPropertyNotifications->erase(iter);
900 // As we can't ensure all references are removed, we can just disable
902 GetImplementation(propertyNotification).Disable();
910 void Object::RemovePropertyNotifications()
912 if( mPropertyNotifications )
914 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
915 while(iter != mPropertyNotifications->end() )
917 // As we can't ensure all references are removed, we can just disable
919 GetImplementation(*iter).Disable();
923 mPropertyNotifications->clear();
927 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, PropertyChange::Type propertyChangeType )
929 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
931 OnNotifyDefaultPropertyAnimation( animation, index, value, propertyChangeType );
933 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
935 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
936 if( animatableProperty )
938 switch( propertyChangeType )
940 case PropertyChange::SET:
942 // update the cached property value
943 animatableProperty->SetPropertyValue( value );
946 case PropertyChange::ADJUST_VALUE_BY:
948 // adjust the cached property value
949 animatableProperty->AdjustPropertyValueBy( value );
957 CustomPropertyMetadata* custom = FindCustomProperty( index );
958 if( custom && custom->IsAnimatable() )
960 switch( propertyChangeType )
962 case PropertyChange::SET:
964 // update the cached property value
965 custom->SetPropertyValue( value );
968 case PropertyChange::ADJUST_VALUE_BY:
970 // adjust the cached property value
971 custom->AdjustPropertyValueBy( value );
979 void Object::EnablePropertyNotifications()
981 if( mPropertyNotifications )
983 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
984 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
986 for( ; iter != endIter; ++iter )
988 GetImplementation(*iter).Enable();
993 void Object::DisablePropertyNotifications()
995 if( mPropertyNotifications )
997 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
998 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
1000 for( ; iter != endIter; ++iter )
1002 GetImplementation(*iter).Disable();
1007 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
1009 // Get the address of the property if it's a scene property
1010 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
1012 // Check instead for newly registered properties
1013 if( propertyPtr == NULL )
1015 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
1016 if( animatable != NULL )
1018 propertyPtr = animatable->GetSceneGraphProperty();
1022 if( propertyPtr == NULL )
1024 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
1025 if( custom != NULL )
1027 propertyPtr = custom->GetSceneGraphProperty();
1031 if( propertyPtr != NULL )
1033 const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
1035 if( sceneObject != NULL )
1037 SceneGraph::UniformPropertyMapping* map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
1038 // Message takes ownership of Uniform map (and will delete it after copy)
1039 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map);
1043 DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
1048 void Object::RemoveUniformMapping( const std::string& uniformName )
1050 const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
1051 RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
1054 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata* entry ) const
1056 Property::Value value;
1058 DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
1060 if( !entry->IsAnimatable() )
1062 value = entry->GetPropertyValue();
1066 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1068 switch ( entry->GetType() )
1070 case Property::BOOLEAN:
1072 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
1073 DALI_ASSERT_DEBUG( NULL != property );
1075 value = (*property)[ bufferIndex ];
1079 case Property::INTEGER:
1081 const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
1082 DALI_ASSERT_DEBUG( NULL != property );
1084 value = (*property)[ bufferIndex ];
1088 case Property::FLOAT:
1090 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
1091 DALI_ASSERT_DEBUG( NULL != property );
1093 value = (*property)[ bufferIndex ];
1097 case Property::VECTOR2:
1099 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
1100 DALI_ASSERT_DEBUG( NULL != property );
1102 if(entry->componentIndex == 0)
1104 value = (*property)[ bufferIndex ].x;
1106 else if(entry->componentIndex == 1)
1108 value = (*property)[ bufferIndex ].y;
1112 value = (*property)[ bufferIndex ];
1117 case Property::VECTOR3:
1119 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
1120 DALI_ASSERT_DEBUG( NULL != property );
1122 if(entry->componentIndex == 0)
1124 value = (*property)[ bufferIndex ].x;
1126 else if(entry->componentIndex == 1)
1128 value = (*property)[ bufferIndex ].y;
1130 else if(entry->componentIndex == 2)
1132 value = (*property)[ bufferIndex ].z;
1136 value = (*property)[ bufferIndex ];
1141 case Property::VECTOR4:
1143 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
1144 DALI_ASSERT_DEBUG( NULL != property );
1146 if(entry->componentIndex == 0)
1148 value = (*property)[ bufferIndex ].x;
1150 else if(entry->componentIndex == 1)
1152 value = (*property)[ bufferIndex ].y;
1154 else if(entry->componentIndex == 2)
1156 value = (*property)[ bufferIndex ].z;
1158 else if(entry->componentIndex == 3)
1160 value = (*property)[ bufferIndex ].w;
1164 value = (*property)[ bufferIndex ];
1169 case Property::MATRIX:
1171 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
1172 DALI_ASSERT_DEBUG( NULL != property );
1174 value = (*property)[ bufferIndex ];
1178 case Property::MATRIX3:
1180 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
1181 DALI_ASSERT_DEBUG( NULL != property );
1183 value = (*property)[ bufferIndex ];
1187 case Property::ROTATION:
1189 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
1190 DALI_ASSERT_DEBUG( NULL != property );
1192 value = (*property)[ bufferIndex ];
1198 // unreachable code due to higher level logic
1206 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1208 switch ( entry.GetType() )
1210 case Property::BOOLEAN:
1212 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1213 DALI_ASSERT_DEBUG( NULL != property );
1215 // property is being used in a separate thread; queue a message to set the property
1216 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1220 case Property::INTEGER:
1222 const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1223 DALI_ASSERT_DEBUG( NULL != property );
1225 // property is being used in a separate thread; queue a message to set the property
1226 BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
1230 case Property::FLOAT:
1232 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1233 DALI_ASSERT_DEBUG( NULL != property );
1235 // property is being used in a separate thread; queue a message to set the property
1236 BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1240 case Property::VECTOR2:
1242 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1243 DALI_ASSERT_DEBUG( NULL != property );
1245 // property is being used in a separate thread; queue a message to set the property
1246 if(entry.componentIndex == 0)
1248 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1250 else if(entry.componentIndex == 1)
1252 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1256 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1261 case Property::VECTOR3:
1263 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1264 DALI_ASSERT_DEBUG( NULL != property );
1266 // property is being used in a separate thread; queue a message to set the property
1267 if(entry.componentIndex == 0)
1269 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1271 else if(entry.componentIndex == 1)
1273 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1275 else if(entry.componentIndex == 2)
1277 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1281 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1287 case Property::VECTOR4:
1289 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1290 DALI_ASSERT_DEBUG( NULL != property );
1292 // property is being used in a separate thread; queue a message to set the property
1293 if(entry.componentIndex == 0)
1295 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1297 else if(entry.componentIndex == 1)
1299 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1301 else if(entry.componentIndex == 2)
1303 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1305 else if(entry.componentIndex == 3)
1307 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1311 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1316 case Property::ROTATION:
1318 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1319 DALI_ASSERT_DEBUG( NULL != property );
1321 // property is being used in a separate thread; queue a message to set the property
1322 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1326 case Property::MATRIX:
1328 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1329 DALI_ASSERT_DEBUG( NULL != property );
1331 // property is being used in a separate thread; queue a message to set the property
1332 BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1336 case Property::MATRIX3:
1338 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1339 DALI_ASSERT_DEBUG( NULL != property );
1341 // property is being used in a separate thread; queue a message to set the property
1342 BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1348 // non-animatable scene graph property, do nothing
1353 const TypeInfo* Object::GetTypeInfo() const
1357 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1358 // especially as the type-info does not change during the life-time of an application
1360 Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1361 if ( typeInfoHandle )
1363 mTypeInfo = &GetImplementation( typeInfoHandle );
1370 void Object::ApplyConstraint( ConstraintBase& constraint )
1374 mConstraints = new ConstraintContainer;
1376 mConstraints->push_back( Dali::Constraint( &constraint ) );
1379 void Object::RemoveConstraint( ConstraintBase& constraint )
1381 // NULL if the Constraint sources are destroyed before Constraint::Apply()
1384 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1385 if( it != mConstraints->end() )
1387 mConstraints->erase( it );
1392 void Object::RemoveConstraints()
1394 // guard against constraint sending messages during core destruction
1395 if( mConstraints && Stage::IsInstalled() )
1397 // If we have nothing in the scene-graph, just clear constraint containers
1398 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1399 if ( NULL != propertyOwner )
1401 const ConstraintConstIter endIter = mConstraints->end();
1402 for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1404 GetImplementation( *iter ).RemoveInternal();
1408 delete mConstraints;
1409 mConstraints = NULL;
1413 void Object::RemoveConstraints( unsigned int tag )
1415 // guard against constraint sending messages during core destruction
1416 if( mConstraints && Stage::IsInstalled() )
1418 ConstraintIter iter( mConstraints->begin() );
1419 while(iter != mConstraints->end() )
1421 ConstraintBase& constraint = GetImplementation( *iter );
1422 if( constraint.GetTag() == tag )
1424 GetImplementation( *iter ).RemoveInternal();
1425 iter = mConstraints->erase( iter );
1433 if ( mConstraints->empty() )
1435 delete mConstraints;
1436 mConstraints = NULL;
1441 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1443 mTypeInfo = typeInfo;
1448 // Notification for observers
1449 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
1451 (*iter)->ObjectDestroyed(*this);
1454 delete mConstraints;
1455 delete mPropertyNotifications;
1458 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1460 CustomPropertyMetadata* property( NULL );
1461 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1463 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1465 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1466 if( custom->childPropertyIndex == index )
1474 int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1475 if( arrayIndex >= 0 )
1477 if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1479 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1486 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1488 for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1490 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1491 if( property->index == index )
1499 AnimatablePropertyMetadata* Object::RegisterAnimatableProperty(Property::Index index) const
1501 DALI_ASSERT_ALWAYS( (( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ))
1502 && "Property index is out of bounds" );
1504 // check whether the animatable property is registered already, if not then register one.
1505 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1506 if( !animatableProperty )
1508 const TypeInfo* typeInfo( GetTypeInfo() );
1511 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1512 if( basePropertyIndex == Property::INVALID_INDEX )
1514 // If the property is not a component of a base property, register the whole property itself.
1515 const std::string& propertyName = typeInfo->GetPropertyName(index);
1516 RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, typeInfo->GetPropertyDefaultValue(index));
1517 AddUniformMapping( index, propertyName );
1521 // Since the property is a component of a base property, check whether the base property is registered.
1522 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1523 if( !animatableProperty )
1525 // If the base property is not registered yet, register the base property first.
1526 const std::string& basePropertyName = typeInfo->GetPropertyName(basePropertyIndex);
1528 if( Property::INVALID_INDEX != RegisterSceneGraphProperty( basePropertyName, Property::INVALID_KEY, basePropertyIndex, typeInfo->GetPropertyDefaultValue( basePropertyIndex ) ) )
1530 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1531 AddUniformMapping( basePropertyIndex, basePropertyName );
1535 if(animatableProperty)
1537 // Create the metadata for the property component.
1538 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1542 // The metadata has just been added and therefore should be in the end of the vector.
1543 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1547 return animatableProperty;
1550 void Object::ResolveChildProperties()
1552 // Resolve index for the child property
1553 Object* parent = GetParentObject();
1556 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1557 if( parentTypeInfo )
1559 // Go through each custom property
1560 for ( int arrayIndex = 0; arrayIndex < (int)mCustomProperties.Count(); arrayIndex++ )
1562 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1564 if( customProperty->name == "" )
1566 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1568 // Resolve name for any child property with no name
1569 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1574 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1575 if( childPropertyIndex != Property::INVALID_INDEX )
1577 // Resolve index for any property with a name that matches the parent's child property name
1578 customProperty->childPropertyIndex = childPropertyIndex;
1586 } // namespace Internal