2 * Copyright (c) 2018 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-messages.h>
30 #include <dali/internal/update/common/uniform-map.h>
31 #include <dali/internal/event/animation/constraint-impl.h>
32 #include <dali/internal/event/common/stage-impl.h>
33 #include <dali/internal/event/common/property-notification-impl.h>
34 #include <dali/internal/event/common/type-registry-impl.h>
36 using Dali::Internal::SceneGraph::AnimatableProperty;
37 using Dali::Internal::SceneGraph::PropertyBase;
45 namespace // unnamed namespace
47 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
48 typedef Dali::Vector<Object::Observer*>::Iterator ObserverIter;
49 typedef Dali::Vector<Object::Observer*>::ConstIterator ConstObserverIter;
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
56 } // unnamed namespace
59 : mEventThreadServices( *Stage::GetCurrent() ),
62 mPropertyNotifications( NULL )
66 void Object::AddObserver(Observer& observer)
68 // make sure an observer doesn't observe the same object twice
69 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
70 DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
72 mObservers.PushBack( &observer );
75 void Object::RemoveObserver(Observer& observer)
77 // Find the observer...
78 const ConstObserverIter endIter = mObservers.End();
79 for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
81 if( (*iter) == &observer)
83 mObservers.Erase( iter );
87 DALI_ASSERT_DEBUG(endIter != mObservers.End());
90 void Object::OnSceneObjectAdd()
92 // Notification for observers
93 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
95 (*iter)->SceneObjectAdded(*this);
98 // enable property notifications in scene graph
99 EnablePropertyNotifications();
102 void Object::OnSceneObjectRemove()
104 // Notification for observers
105 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
107 (*iter)->SceneObjectRemoved(*this);
110 // disable property notifications in scene graph
111 DisablePropertyNotifications();
114 int Object::GetPropertyComponentIndex( Property::Index index ) const
116 int componentIndex = Property::INVALID_COMPONENT_INDEX;
118 const TypeInfo* typeInfo( GetTypeInfo() );
121 componentIndex = typeInfo->GetComponentIndex(index);
124 // For animatable property, check whether it is registered already and register it if not yet.
125 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) && ( NULL == RegisterAnimatableProperty(index) ) )
127 componentIndex = Property::INVALID_COMPONENT_INDEX;
130 return componentIndex;
133 bool Object::Supports( Capability capability ) const
135 return (capability & SUPPORTED_CAPABILITIES);
138 unsigned int Object::GetPropertyCount() const
140 unsigned int count = GetDefaultPropertyCount();
142 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
144 const TypeInfo* typeInfo( GetTypeInfo() );
147 unsigned int manual( typeInfo->GetPropertyCount() );
150 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties: %d\n", manual );
153 unsigned int custom( mCustomProperties.Count() );
155 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
157 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
162 std::string Object::GetPropertyName( Property::Index index ) const
164 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
166 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
170 const char * propertyName = GetDefaultPropertyName( index );
173 string = propertyName;
178 if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
179 || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
181 const TypeInfo* typeInfo( GetTypeInfo() );
184 return typeInfo->GetPropertyName( index );
188 DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
192 CustomPropertyMetadata* custom = FindCustomProperty( index );
200 Property::Index Object::GetPropertyIndex(const std::string& name) const
202 Property::Index index = GetDefaultPropertyIndex( name );
204 if(index == Property::INVALID_INDEX)
206 const TypeInfo* typeInfo( GetTypeInfo() );
209 index = typeInfo->GetPropertyIndex( name );
210 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
212 // check whether the animatable property is registered already, if not then register one.
213 if ( NULL == RegisterAnimatableProperty(index) )
215 index = Property::INVALID_INDEX;
221 if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
223 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
224 const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
225 for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
227 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
228 if ( custom->name == name )
230 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
232 // If it is a child property, return the child property index
233 index = custom->childPropertyIndex;
247 Property::Index Object::GetPropertyIndex( Property::Index key ) const
249 Property::Index index = Property::INVALID_INDEX;
251 if( mCustomProperties.Count() > 0 )
253 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
254 const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
255 for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
257 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
258 if( custom->key == key )
260 if( custom->childPropertyIndex != Property::INVALID_INDEX )
262 // If it is a child property, return the child property index
263 index = custom->childPropertyIndex;
277 Property::Index Object::GetPropertyIndex( Property::Key key ) const
279 Property::Index index = Property::INVALID_INDEX;
280 if( key.type == Property::Key::INDEX )
282 index = GetPropertyIndex( key.indexKey );
286 index = GetPropertyIndex( key.stringKey );
291 bool Object::IsPropertyWritable( Property::Index index ) const
293 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
295 bool writable = false;
297 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
299 writable = IsDefaultPropertyWritable( index );
301 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
303 const TypeInfo* typeInfo( GetTypeInfo() );
306 writable = typeInfo->IsPropertyWritable( index );
310 DALI_ASSERT_ALWAYS( ! "Invalid property index" );
313 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
315 // Type Registry scene-graph properties are writable.
320 CustomPropertyMetadata* custom = FindCustomProperty( index );
323 writable = custom->IsWritable();
330 bool Object::IsPropertyAnimatable( Property::Index index ) const
332 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
334 bool animatable = false;
336 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
338 animatable = IsDefaultPropertyAnimatable( index );
340 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
342 // Type Registry event-thread only properties are not animatable.
345 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
347 // Type Registry scene-graph properties are animatable.
352 CustomPropertyMetadata* custom = FindCustomProperty( index );
355 animatable = custom->IsAnimatable();
362 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
364 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
366 bool isConstraintInput = false;
368 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
370 isConstraintInput = IsDefaultPropertyAConstraintInput( index );
372 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
374 // Type Registry event-thread only properties cannot be used as an input to a constraint.
375 isConstraintInput = false;
377 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
379 // scene graph properties can be used as input to a constraint.
380 isConstraintInput = true;
384 CustomPropertyMetadata* custom = FindCustomProperty( index );
387 // ... custom properties can be used as input to a constraint.
388 isConstraintInput = true;
392 return isConstraintInput;
395 Property::Type Object::GetPropertyType( Property::Index index ) const
397 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
399 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
401 return GetDefaultPropertyType( index );
404 if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
405 || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
407 const TypeInfo* typeInfo( GetTypeInfo() );
410 return typeInfo->GetPropertyType( index );
414 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
418 CustomPropertyMetadata* custom = FindCustomProperty( index );
421 return custom->GetType();
424 return Property::NONE;
427 DevelHandle::PropertySetSignalType& Object::PropertySetSignal()
429 return mPropertySetSignal;
432 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
434 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
436 bool propertySet( true );
438 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
440 SetDefaultProperty( index, propertyValue );
442 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
444 const TypeInfo* typeInfo( GetTypeInfo() );
447 typeInfo->SetProperty( this, index, propertyValue );
451 DALI_LOG_ERROR("Cannot find property index\n");
455 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
457 // check whether the animatable property is registered already, if not then register one.
458 AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
459 if(!animatableProperty)
461 DALI_LOG_ERROR("Cannot find property index\n");
466 // update the cached property value
467 animatableProperty->SetPropertyValue( propertyValue );
469 // set the scene graph property value
470 SetSceneGraphProperty( index, *animatableProperty, propertyValue );
475 CustomPropertyMetadata* custom = FindCustomProperty( index );
477 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
481 // If the child property is not registered yet, register it.
482 custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
483 mCustomProperties.PushBack( custom );
486 custom->childPropertyIndex = index;
488 // Resolve name for the child property
489 Object* parent = GetParentObject();
492 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
495 custom->name = parentTypeInfo->GetChildPropertyName( index );
502 if( custom->IsAnimatable() )
504 // update the cached property value
505 custom->SetPropertyValue( propertyValue );
507 // set the scene graph property value
508 SetSceneGraphProperty( index, *custom, propertyValue );
510 else if( custom->IsWritable() )
512 // update the cached property value
513 custom->SetPropertyValue( propertyValue );
517 // trying to set value on read only property is no-op
523 DALI_LOG_ERROR("Invalid property index\n");
528 // Let derived classes know that a property has been set
529 // 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
532 OnPropertySet( index, propertyValue );
533 Dali::Handle handle( this );
534 mPropertySetSignal.Emit( handle, index, propertyValue );
538 Property::Value Object::GetProperty(Property::Index index) const
540 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
542 Property::Value value;
544 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
546 value = GetDefaultProperty( index );
548 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
550 const TypeInfo* typeInfo( GetTypeInfo() );
553 value = typeInfo->GetProperty( this, index );
557 DALI_LOG_ERROR("Cannot find property index\n");
560 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
562 // check whether the animatable property is registered already, if not then register one.
563 AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
564 if(!animatableProperty)
566 DALI_LOG_ERROR("Cannot find property index\n");
570 // get the cached animatable property value
571 value = animatableProperty->GetPropertyValue();
574 else if(mCustomProperties.Count() > 0)
576 CustomPropertyMetadata* custom = FindCustomProperty( index );
579 // get the cached custom property value
580 value = custom->GetPropertyValue();
584 DALI_LOG_ERROR("Invalid property index\n");
591 Property::Value Object::GetCurrentProperty( Property::Index index ) const
593 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
595 Property::Value value;
597 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
599 value = GetDefaultPropertyCurrentValue( index );
601 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
603 const TypeInfo* typeInfo( GetTypeInfo() );
606 value = typeInfo->GetProperty( this, index );
610 DALI_LOG_ERROR("Cannot find property index\n");
613 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
615 // check whether the animatable property is registered already, if not then register one.
616 AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
617 if(!animatableProperty)
619 DALI_LOG_ERROR("Cannot find property index\n");
623 // get the animatable property value
624 value = GetCurrentPropertyValue( animatableProperty );
627 else if(mCustomProperties.Count() > 0)
629 CustomPropertyMetadata* custom = FindCustomProperty( index );
632 // get the custom property value
633 value = GetCurrentPropertyValue( custom );
637 DALI_LOG_ERROR("Invalid property index\n");
644 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
648 // Default Properties
649 GetDefaultPropertyIndices( indices );
652 const TypeInfo* typeInfo( GetTypeInfo() );
655 typeInfo->GetPropertyIndices( indices );
659 if ( mCustomProperties.Count() > 0 )
661 indices.Reserve( indices.Size() + mCustomProperties.Count() );
663 PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
664 const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
666 for ( ; iter != endIter; ++iter, ++i )
668 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
669 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
671 // If it is a child property, add the child property index
672 indices.PushBack( custom->childPropertyIndex );
676 indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
682 bool Object::DoesCustomPropertyExist( Property::Index index )
684 auto metadata = FindCustomProperty( index );
685 return metadata != nullptr;
688 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue) const
690 // Create a new property
691 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
693 switch ( propertyValue.GetType() )
695 case Property::BOOLEAN:
697 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
701 case Property::INTEGER:
703 newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
707 case Property::FLOAT:
709 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
713 case Property::VECTOR2:
715 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
719 case Property::VECTOR3:
721 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
725 case Property::VECTOR4:
727 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
731 case Property::MATRIX:
733 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
737 case Property::MATRIX3:
739 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
743 case Property::ROTATION:
745 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
749 case Property::RECTANGLE:
750 case Property::STRING:
751 case Property::ARRAY:
753 case Property::EXTENTS:
756 DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
761 // get the scene property owner from derived class
762 const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
763 // we can only pass properties to scene graph side if there is a scene object
764 if( scenePropertyOwner )
766 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
767 const PropertyBase* property = newProperty.Get();
768 if(index >= PROPERTY_CUSTOM_START_INDEX)
770 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
772 mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
776 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
779 // queue a message to add the property
780 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty ); // Message takes ownership
782 // notify the derived class (optional) method in case it needs to do some more work on the new property
783 // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
784 NotifyScenePropertyInstalled( *property, name, index );
790 // property was orphaned and killed so return invalid index
791 return Property::INVALID_INDEX;
795 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
797 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
800 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
802 return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
805 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
807 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
810 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
812 // If property with the required key already exists, then just set it.
813 Property::Index index = Property::INVALID_INDEX;
814 if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
816 index = GetPropertyIndex( key );
818 if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
820 index = GetPropertyIndex( name );
823 if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
825 SetProperty( index, propertyValue );
829 // Otherwise register the property
831 if( Property::ANIMATABLE == accessMode )
833 index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue );
834 AddUniformMapping( index, name );
838 // Add entry to the property lookup
839 index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
841 CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
843 // Resolve index for the child property
844 Object* parent = GetParentObject();
847 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
850 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
851 if( childPropertyIndex != Property::INVALID_INDEX )
853 customProperty->childPropertyIndex = childPropertyIndex;
854 index = childPropertyIndex;
859 mCustomProperties.PushBack( customProperty );
866 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
868 const Dali::PropertyCondition& condition)
870 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
872 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
874 DALI_ABORT( "Property notification added to event side only property." );
876 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
878 // check whether the animatable property is registered already, if not then register one.
879 AnimatablePropertyMetadata* animatable = RegisterAnimatableProperty( index );
880 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
882 else if ( mCustomProperties.Count() > 0 )
884 CustomPropertyMetadata* custom = FindCustomProperty( index );
885 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
886 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
890 Dali::Handle self(this);
891 Property target( self, index );
893 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
894 Dali::PropertyNotification propertyNotification(internal.Get());
896 if( !mPropertyNotifications )
898 mPropertyNotifications = new PropertyNotificationContainer;
900 mPropertyNotifications->push_back(propertyNotification);
902 return propertyNotification;
905 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
907 if( mPropertyNotifications )
909 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
910 while(iter != mPropertyNotifications->end() )
912 if(*iter == propertyNotification)
914 mPropertyNotifications->erase(iter);
915 // As we can't ensure all references are removed, we can just disable
917 GetImplementation(propertyNotification).Disable();
925 void Object::RemovePropertyNotifications()
927 if( mPropertyNotifications )
929 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
930 while(iter != mPropertyNotifications->end() )
932 // As we can't ensure all references are removed, we can just disable
934 GetImplementation(*iter).Disable();
938 mPropertyNotifications->clear();
942 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
944 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
946 OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
950 PropertyMetadata* propertyMetadata = NULL;
951 if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
953 propertyMetadata = FindAnimatableProperty( index );
957 CustomPropertyMetadata* custom = FindCustomProperty( index );
958 if( custom && custom->IsAnimatable() )
960 propertyMetadata = custom;
964 if( propertyMetadata )
966 switch( animationType )
969 case Animation::BETWEEN:
971 // Update the cached property value
972 propertyMetadata->SetPropertyValue( value );
977 // Adjust the cached property value
978 propertyMetadata->AdjustPropertyValueBy( value );
986 void Object::EnablePropertyNotifications()
988 if( mPropertyNotifications )
990 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
991 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
993 for( ; iter != endIter; ++iter )
995 GetImplementation(*iter).Enable();
1000 void Object::DisablePropertyNotifications()
1002 if( mPropertyNotifications )
1004 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
1005 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
1007 for( ; iter != endIter; ++iter )
1009 GetImplementation(*iter).Disable();
1014 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
1016 // Get the address of the property if it's a scene property
1017 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
1019 // Check instead for newly registered properties
1020 if( propertyPtr == NULL )
1022 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
1023 if( animatable != NULL )
1025 propertyPtr = animatable->GetSceneGraphProperty();
1029 if( propertyPtr == NULL )
1031 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
1032 if( custom != NULL )
1034 propertyPtr = custom->GetSceneGraphProperty();
1038 if( propertyPtr != NULL )
1040 const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
1042 if( sceneObject != NULL )
1044 OwnerPointer< SceneGraph::UniformPropertyMapping > map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
1045 // Message takes ownership of Uniform map (and will delete it after copy)
1046 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map );
1050 DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
1055 void Object::RemoveUniformMapping( const std::string& uniformName )
1057 const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
1058 RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
1061 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata* entry ) const
1063 Property::Value value;
1065 DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
1067 if( !entry->IsAnimatable() )
1069 value = entry->GetPropertyValue();
1073 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1075 switch ( entry->GetType() )
1077 case Property::BOOLEAN:
1079 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
1080 DALI_ASSERT_DEBUG( NULL != property );
1082 value = (*property)[ bufferIndex ];
1086 case Property::INTEGER:
1088 const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
1089 DALI_ASSERT_DEBUG( NULL != property );
1091 value = (*property)[ bufferIndex ];
1095 case Property::FLOAT:
1097 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
1098 DALI_ASSERT_DEBUG( NULL != property );
1100 value = (*property)[ bufferIndex ];
1104 case Property::VECTOR2:
1106 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
1107 DALI_ASSERT_DEBUG( NULL != property );
1109 if(entry->componentIndex == 0)
1111 value = (*property)[ bufferIndex ].x;
1113 else if(entry->componentIndex == 1)
1115 value = (*property)[ bufferIndex ].y;
1119 value = (*property)[ bufferIndex ];
1124 case Property::VECTOR3:
1126 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
1127 DALI_ASSERT_DEBUG( NULL != property );
1129 if(entry->componentIndex == 0)
1131 value = (*property)[ bufferIndex ].x;
1133 else if(entry->componentIndex == 1)
1135 value = (*property)[ bufferIndex ].y;
1137 else if(entry->componentIndex == 2)
1139 value = (*property)[ bufferIndex ].z;
1143 value = (*property)[ bufferIndex ];
1148 case Property::VECTOR4:
1150 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
1151 DALI_ASSERT_DEBUG( NULL != property );
1153 if(entry->componentIndex == 0)
1155 value = (*property)[ bufferIndex ].x;
1157 else if(entry->componentIndex == 1)
1159 value = (*property)[ bufferIndex ].y;
1161 else if(entry->componentIndex == 2)
1163 value = (*property)[ bufferIndex ].z;
1165 else if(entry->componentIndex == 3)
1167 value = (*property)[ bufferIndex ].w;
1171 value = (*property)[ bufferIndex ];
1176 case Property::MATRIX:
1178 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
1179 DALI_ASSERT_DEBUG( NULL != property );
1181 value = (*property)[ bufferIndex ];
1185 case Property::MATRIX3:
1187 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
1188 DALI_ASSERT_DEBUG( NULL != property );
1190 value = (*property)[ bufferIndex ];
1194 case Property::ROTATION:
1196 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
1197 DALI_ASSERT_DEBUG( NULL != property );
1199 value = (*property)[ bufferIndex ];
1205 // unreachable code due to higher level logic
1213 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1215 switch ( entry.GetType() )
1217 case Property::BOOLEAN:
1219 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1220 DALI_ASSERT_DEBUG( NULL != property );
1222 // property is being used in a separate thread; queue a message to set the property
1223 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1227 case Property::INTEGER:
1229 const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1230 DALI_ASSERT_DEBUG( NULL != property );
1232 // property is being used in a separate thread; queue a message to set the property
1233 BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
1237 case Property::FLOAT:
1239 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1240 DALI_ASSERT_DEBUG( NULL != property );
1242 // property is being used in a separate thread; queue a message to set the property
1243 BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1247 case Property::VECTOR2:
1249 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1250 DALI_ASSERT_DEBUG( NULL != property );
1252 // property is being used in a separate thread; queue a message to set the property
1253 if(entry.componentIndex == 0)
1255 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1257 else if(entry.componentIndex == 1)
1259 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1263 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1268 case Property::VECTOR3:
1270 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1271 DALI_ASSERT_DEBUG( NULL != property );
1273 // property is being used in a separate thread; queue a message to set the property
1274 if(entry.componentIndex == 0)
1276 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1278 else if(entry.componentIndex == 1)
1280 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1282 else if(entry.componentIndex == 2)
1284 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1288 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1294 case Property::VECTOR4:
1296 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1297 DALI_ASSERT_DEBUG( NULL != property );
1299 // property is being used in a separate thread; queue a message to set the property
1300 if(entry.componentIndex == 0)
1302 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1304 else if(entry.componentIndex == 1)
1306 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1308 else if(entry.componentIndex == 2)
1310 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1312 else if(entry.componentIndex == 3)
1314 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1318 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1323 case Property::ROTATION:
1325 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1326 DALI_ASSERT_DEBUG( NULL != property );
1328 // property is being used in a separate thread; queue a message to set the property
1329 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1333 case Property::MATRIX:
1335 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1336 DALI_ASSERT_DEBUG( NULL != property );
1338 // property is being used in a separate thread; queue a message to set the property
1339 BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1343 case Property::MATRIX3:
1345 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1346 DALI_ASSERT_DEBUG( NULL != property );
1348 // property is being used in a separate thread; queue a message to set the property
1349 BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1355 // non-animatable scene graph property, do nothing
1360 const TypeInfo* Object::GetTypeInfo() const
1364 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1365 // especially as the type-info does not change during the life-time of an application
1367 Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1368 if ( typeInfoHandle )
1370 mTypeInfo = &GetImplementation( typeInfoHandle );
1377 void Object::ApplyConstraint( ConstraintBase& constraint )
1381 mConstraints = new ConstraintContainer;
1383 mConstraints->push_back( Dali::Constraint( &constraint ) );
1386 void Object::RemoveConstraint( ConstraintBase& constraint )
1388 // NULL if the Constraint sources are destroyed before Constraint::Apply()
1391 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1392 if( it != mConstraints->end() )
1394 mConstraints->erase( it );
1399 void Object::RemoveConstraints()
1401 // guard against constraint sending messages during core destruction
1402 if( mConstraints && Stage::IsInstalled() )
1404 // If we have nothing in the scene-graph, just clear constraint containers
1405 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1406 if ( NULL != propertyOwner )
1408 const ConstraintConstIter endIter = mConstraints->end();
1409 for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1411 GetImplementation( *iter ).RemoveInternal();
1415 delete mConstraints;
1416 mConstraints = NULL;
1420 void Object::RemoveConstraints( unsigned int tag )
1422 // guard against constraint sending messages during core destruction
1423 if( mConstraints && Stage::IsInstalled() )
1425 ConstraintIter iter( mConstraints->begin() );
1426 while(iter != mConstraints->end() )
1428 ConstraintBase& constraint = GetImplementation( *iter );
1429 if( constraint.GetTag() == tag )
1431 GetImplementation( *iter ).RemoveInternal();
1432 iter = mConstraints->erase( iter );
1440 if ( mConstraints->empty() )
1442 delete mConstraints;
1443 mConstraints = NULL;
1448 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1450 mTypeInfo = typeInfo;
1455 // Notification for observers
1456 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
1458 (*iter)->ObjectDestroyed(*this);
1461 delete mConstraints;
1462 delete mPropertyNotifications;
1465 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1467 CustomPropertyMetadata* property( NULL );
1468 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1470 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1472 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1473 if( custom->childPropertyIndex == index )
1481 int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1482 if( arrayIndex >= 0 )
1484 if( arrayIndex < static_cast<int>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
1486 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1493 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1495 const PropertyMetadataLookup::SizeType count = mAnimatableProperties.Count();
1496 for ( PropertyMetadataLookup::SizeType arrayIndex = 0; arrayIndex < count; ++arrayIndex )
1498 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1499 if( property->index == index )
1507 AnimatablePropertyMetadata* Object::RegisterAnimatableProperty(Property::Index index) const
1509 DALI_ASSERT_ALWAYS( (( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ))
1510 && "Property index is out of bounds" );
1512 // check whether the animatable property is registered already, if not then register one.
1513 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1514 if( !animatableProperty )
1516 const TypeInfo* typeInfo( GetTypeInfo() );
1519 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1520 if( basePropertyIndex == Property::INVALID_INDEX )
1522 // If the property is not a component of a base property, register the whole property itself.
1523 const std::string& propertyName = typeInfo->GetPropertyName(index);
1524 RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, typeInfo->GetPropertyDefaultValue(index));
1525 AddUniformMapping( index, propertyName );
1529 // Since the property is a component of a base property, check whether the base property is registered.
1530 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1531 if( !animatableProperty )
1533 // If the base property is not registered yet, register the base property first.
1534 const std::string& basePropertyName = typeInfo->GetPropertyName(basePropertyIndex);
1536 if( Property::INVALID_INDEX != RegisterSceneGraphProperty( basePropertyName, Property::INVALID_KEY, basePropertyIndex, typeInfo->GetPropertyDefaultValue( basePropertyIndex ) ) )
1538 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1539 AddUniformMapping( basePropertyIndex, basePropertyName );
1543 if(animatableProperty)
1545 // Create the metadata for the property component.
1546 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1550 // The metadata has just been added and therefore should be in the end of the vector.
1551 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1555 return animatableProperty;
1558 void Object::ResolveChildProperties()
1560 // Resolve index for the child property
1561 Object* parent = GetParentObject();
1564 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1565 if( parentTypeInfo )
1567 // Go through each custom property
1568 const PropertyMetadataLookup::SizeType count = mCustomProperties.Count();
1569 for ( PropertyMetadataLookup::SizeType arrayIndex = 0; arrayIndex < count; ++arrayIndex )
1571 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1573 if( customProperty->name == "" )
1575 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1577 // Resolve name for any child property with no name
1578 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1583 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1584 if( childPropertyIndex != Property::INVALID_INDEX )
1586 // Resolve index for any property with a name that matches the parent's child property name
1587 customProperty->childPropertyIndex = childPropertyIndex;
1595 } // namespace Internal