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/property-helper.h>
33 #include <dali/internal/event/common/property-notification-impl.h>
34 #include <dali/internal/event/common/stage-impl.h>
35 #include <dali/internal/event/common/type-registry-impl.h>
37 using Dali::Internal::SceneGraph::AnimatableProperty;
38 using Dali::Internal::SceneGraph::PropertyBase;
46 namespace // unnamed namespace
48 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
54 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
56 } // unnamed namespace
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 auto endIter = mObservers.End();
79 for( auto iter = mObservers.Begin(); iter != endIter; ++iter)
81 if( (*iter) == &observer)
83 mObservers.Erase( iter );
87 DALI_ASSERT_DEBUG(endIter != mObservers.End());
90 bool Object::Supports( Capability capability ) const
92 return (capability & SUPPORTED_CAPABILITIES);
95 uint32_t Object::GetPropertyCount() const
98 const TypeInfo* typeInfo( GetTypeInfo() );
101 count = typeInfo->GetPropertyCount();
103 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count );
106 uint32_t custom = static_cast<uint32_t>( mCustomProperties.Count() );
108 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
110 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
115 std::string Object::GetPropertyName( Property::Index index ) const
117 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
119 // is this a per class or per instance property
120 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
122 const TypeInfo* typeInfo( GetTypeInfo() );
125 return typeInfo->GetPropertyName( index );
128 else // child property or custom property
130 CustomPropertyMetadata* custom = FindCustomProperty( index );
137 DALI_LOG_ERROR( "Property index %d not found\n", index );
138 return std::string();
141 Property::Index Object::GetPropertyIndex( const std::string& name ) const
143 Property::Index index = Property::INVALID_INDEX;
145 const TypeInfo* typeInfo( GetTypeInfo() );
148 index = typeInfo->GetPropertyIndex( name );
150 if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
152 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
153 const auto end = mCustomProperties.End();
154 for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
156 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
157 if ( custom->name == name )
159 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
161 // If it is a child property, return the child property index
162 index = custom->childPropertyIndex;
176 Property::Index Object::GetPropertyIndex( Property::Index key ) const
178 Property::Index index = Property::INVALID_INDEX;
180 if( mCustomProperties.Count() > 0 )
182 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
183 const auto end = mCustomProperties.End();
184 for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
186 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
187 if( custom->key == key )
189 if( custom->childPropertyIndex != Property::INVALID_INDEX )
191 // If it is a child property, return the child property index
192 index = custom->childPropertyIndex;
206 Property::Index Object::GetPropertyIndex( Property::Key key ) const
208 Property::Index index = Property::INVALID_INDEX;
209 if( key.type == Property::Key::INDEX )
211 index = GetPropertyIndex( key.indexKey );
215 index = GetPropertyIndex( key.stringKey );
220 bool Object::IsPropertyWritable( Property::Index index ) const
222 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
224 bool writable = false;
226 // is this a per class or per instance property
227 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
229 const TypeInfo* typeInfo( GetTypeInfo() );
232 writable = typeInfo->IsPropertyWritable( index );
237 CustomPropertyMetadata* custom = FindCustomProperty( index );
240 writable = custom->IsWritable();
247 bool Object::IsPropertyAnimatable( Property::Index index ) const
249 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
251 bool animatable = false;
253 // is this a per class or per instance property
254 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
256 const TypeInfo* typeInfo( GetTypeInfo() );
259 animatable = typeInfo->IsPropertyAnimatable( index );
264 CustomPropertyMetadata* custom = FindCustomProperty( index );
267 animatable = custom->IsAnimatable();
274 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
276 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
278 bool isConstraintInput = false;
280 // is this a per class or per instance property
281 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
283 const TypeInfo* typeInfo( GetTypeInfo() );
286 isConstraintInput = typeInfo->IsPropertyAConstraintInput( index );
291 CustomPropertyMetadata* custom = FindCustomProperty( index );
294 // ... custom properties can be used as input to a constraint.
295 isConstraintInput = true;
299 return isConstraintInput;
302 Property::Type Object::GetPropertyType( Property::Index index ) const
304 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
306 // is this a per class or per instance property
307 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
309 const TypeInfo* typeInfo( GetTypeInfo() );
312 return typeInfo->GetPropertyType( index );
316 CustomPropertyMetadata* custom = FindCustomProperty( index );
319 return custom->GetType();
322 return Property::NONE;
325 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
327 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
329 bool propertySet( true );
331 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
333 SetDefaultProperty( index, propertyValue );
335 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
337 const TypeInfo* typeInfo( GetTypeInfo() );
340 typeInfo->SetProperty( this, index, propertyValue );
344 // cannot register this property as there is no setter for it.
345 // event side properties must have a setter for now so need to be registered
346 DALI_LOG_ERROR( "Property index %d not found\n", index );
350 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
352 // check whether the animatable property is registered already, if not then register one.
353 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, &propertyValue );
354 if( !animatableProperty )
356 DALI_LOG_ERROR( "Property index %d not found\n", index );
361 // update the cached property value
362 animatableProperty->SetPropertyValue( propertyValue );
364 // set the scene graph property value
365 SetSceneGraphProperty( index, *animatableProperty, propertyValue );
370 CustomPropertyMetadata* custom = FindCustomProperty( index );
372 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
376 // If the child property is not registered yet, register it.
377 custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
378 mCustomProperties.PushBack( custom );
381 custom->childPropertyIndex = index;
383 // Resolve name for the child property
384 Object* parent = GetParentObject();
387 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
390 custom->name = parentTypeInfo->GetChildPropertyName( index );
397 if( custom->IsAnimatable() )
399 // update the cached property value
400 custom->SetPropertyValue( propertyValue );
402 // set the scene graph property value
403 SetSceneGraphProperty( index, *custom, propertyValue );
405 else if( custom->IsWritable() )
407 // update the cached property value
408 custom->SetPropertyValue( propertyValue );
412 // trying to set value on read only property is no-op
418 DALI_LOG_ERROR( "Property index %d not found\n", index );
423 // Let derived classes know that a property has been set
424 // 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
427 OnPropertySet( index, propertyValue );
428 Dali::Handle handle( this );
429 mPropertySetSignal.Emit( handle, index, propertyValue );
433 Property::Value Object::GetProperty(Property::Index index) const
435 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
437 Property::Value value;
439 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
441 value = GetDefaultProperty( index );
443 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
445 const TypeInfo* typeInfo( GetTypeInfo() );
448 value = typeInfo->GetProperty( this, index );
452 DALI_LOG_ERROR( "Property index %d not found\n", index );
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 // this is needed because property value may have been set as full property and get as a property component
459 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
460 if( animatableProperty )
462 // get the cached animatable property value
463 value = animatableProperty->GetPropertyValue();
467 DALI_LOG_ERROR( "Property index %d not found\n", index );
470 else if(mCustomProperties.Count() > 0)
472 CustomPropertyMetadata* custom = FindCustomProperty( index );
475 // get the cached custom property value
476 value = custom->GetPropertyValue();
480 DALI_LOG_ERROR( "Property index %d not found\n", index );
487 Property::Value Object::GetCurrentProperty( Property::Index index ) const
489 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
491 Property::Value value;
493 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
495 value = GetDefaultPropertyCurrentValue( index );
497 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
499 const TypeInfo* typeInfo( GetTypeInfo() );
502 value = typeInfo->GetProperty( this, index );
506 DALI_LOG_ERROR( "Property index %d not found\n", index );
509 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
511 // check whether the animatable property is registered already, if not then register one.
512 // this is needed because property value may have been set as full property and get as a property component
513 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
514 if( animatableProperty )
516 // get the animatable property value
517 value = GetCurrentPropertyValue( *animatableProperty );
521 DALI_LOG_ERROR( "Property index %d not found\n", index );
524 else if(mCustomProperties.Count() > 0)
526 CustomPropertyMetadata* custom = FindCustomProperty( index );
529 // get the custom property value
530 value = GetCurrentPropertyValue( *custom );
534 DALI_LOG_ERROR( "Property index %d not found\n", index );
541 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
546 const TypeInfo* typeInfo( GetTypeInfo() );
549 typeInfo->GetPropertyIndices( indices );
553 if ( mCustomProperties.Count() > 0 )
555 indices.Reserve( indices.Size() + mCustomProperties.Count() );
557 auto iter = mCustomProperties.Begin();
558 const auto endIter = mCustomProperties.End();
560 for ( ; iter != endIter; ++iter, ++i )
562 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
563 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
565 // If it is a child property, add the child property index
566 indices.PushBack( custom->childPropertyIndex );
570 indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
576 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
578 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
581 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
583 return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
586 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
588 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
591 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
593 // If property with the required key already exists, then just set it.
594 Property::Index index = Property::INVALID_INDEX;
595 if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
597 index = GetPropertyIndex( key );
599 if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
601 index = GetPropertyIndex( name );
604 if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
606 SetProperty( index, propertyValue );
610 // Otherwise register the property
612 if( Property::ANIMATABLE == accessMode )
614 index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() ), propertyValue );
615 AddUniformMapping( index, name );
619 // Add entry to the property lookup
620 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
622 CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
624 // Resolve index for the child property
625 Object* parent = GetParentObject();
628 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
631 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
632 if( childPropertyIndex != Property::INVALID_INDEX )
634 customProperty->childPropertyIndex = childPropertyIndex;
635 index = childPropertyIndex;
640 mCustomProperties.PushBack( customProperty );
647 bool Object::DoesCustomPropertyExist( Property::Index index )
649 auto metadata = FindCustomProperty( index );
650 return metadata != nullptr;
653 Dali::PropertyNotification Object::AddPropertyNotification( Property::Index index,
654 int32_t componentIndex,
655 const Dali::PropertyCondition& condition)
657 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
659 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
661 DALI_ABORT( "Property notification added to event side only property." );
663 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
665 // check whether the animatable property is registered already, if not then register one.
666 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
667 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
669 else if ( mCustomProperties.Count() > 0 )
671 CustomPropertyMetadata* custom = FindCustomProperty( index );
672 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
673 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
677 Dali::Handle self(this);
678 Property target( self, index );
680 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
681 Dali::PropertyNotification propertyNotification(internal.Get());
683 if( !mPropertyNotifications )
685 mPropertyNotifications = new PropertyNotificationContainer;
687 mPropertyNotifications->push_back(propertyNotification);
689 return propertyNotification;
692 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
694 if( mPropertyNotifications )
696 auto iter = mPropertyNotifications->begin();
697 while(iter != mPropertyNotifications->end() )
699 if(*iter == propertyNotification)
701 mPropertyNotifications->erase(iter);
702 // As we can't ensure all references are removed, we can just disable
704 GetImplementation(propertyNotification).Disable();
712 void Object::RemovePropertyNotifications()
714 if( mPropertyNotifications )
716 auto iter = mPropertyNotifications->begin();
717 while(iter != mPropertyNotifications->end() )
719 // As we can't ensure all references are removed, we can just disable
721 GetImplementation(*iter).Disable();
725 mPropertyNotifications->clear();
729 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
731 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
733 OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
737 PropertyMetadata* propertyMetadata = NULL;
738 if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
740 propertyMetadata = FindAnimatableProperty( index );
744 CustomPropertyMetadata* custom = FindCustomProperty( index );
745 if( custom && custom->IsAnimatable() )
747 propertyMetadata = custom;
751 if( propertyMetadata )
753 switch( animationType )
756 case Animation::BETWEEN:
758 // Update the cached property value
759 propertyMetadata->SetPropertyValue( value );
764 // Adjust the cached property value
765 propertyMetadata->AdjustPropertyValueBy( value );
773 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
775 // Get the address of the property if it's a scene property
776 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
778 // Check instead for newly registered properties
779 if( propertyPtr == NULL )
781 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
782 if( animatable != NULL )
784 propertyPtr = animatable->GetSceneGraphProperty();
788 if( propertyPtr == NULL )
790 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
793 propertyPtr = custom->GetSceneGraphProperty();
797 if( propertyPtr != NULL )
799 const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
801 if( sceneObject != NULL )
803 OwnerPointer< SceneGraph::UniformPropertyMapping > map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
804 // Message takes ownership of Uniform map (and will delete it after copy)
805 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map );
809 DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
814 void Object::RemoveUniformMapping( const std::string& uniformName )
816 const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
817 RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
820 void Object::ApplyConstraint( ConstraintBase& constraint )
824 mConstraints = new ConstraintContainer;
826 mConstraints->push_back( Dali::Constraint( &constraint ) );
829 void Object::RemoveConstraint( ConstraintBase& constraint )
831 // NULL if the Constraint sources are destroyed before Constraint::Apply()
834 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
835 if( it != mConstraints->end() )
837 mConstraints->erase( it );
842 void Object::RemoveConstraints()
844 // guard against constraint sending messages during core destruction
845 if( mConstraints && Stage::IsInstalled() )
847 // If we have nothing in the scene-graph, just clear constraint containers
848 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
849 if ( NULL != propertyOwner )
851 const auto endIter = mConstraints->end();
852 for ( auto iter = mConstraints->begin(); endIter != iter; ++iter )
854 GetImplementation( *iter ).RemoveInternal();
863 void Object::RemoveConstraints( uint32_t tag )
865 // guard against constraint sending messages during core destruction
866 if( mConstraints && Stage::IsInstalled() )
868 auto iter( mConstraints->begin() );
869 while(iter != mConstraints->end() )
871 ConstraintBase& constraint = GetImplementation( *iter );
872 if( constraint.GetTag() == tag )
874 GetImplementation( *iter ).RemoveInternal();
875 iter = mConstraints->erase( iter );
883 if ( mConstraints->empty() )
891 void Object::SetTypeInfo( const TypeInfo* typeInfo )
893 mTypeInfo = typeInfo;
896 int32_t Object::GetPropertyComponentIndex( Property::Index index ) const
898 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
900 const TypeInfo* typeInfo( GetTypeInfo() );
903 componentIndex = typeInfo->GetComponentIndex(index);
906 return componentIndex;
909 DevelHandle::PropertySetSignalType& Object::PropertySetSignal()
911 return mPropertySetSignal;
916 // Notification for observers
917 for( auto iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
919 (*iter)->ObjectDestroyed(*this);
923 delete mPropertyNotifications;
926 void Object::OnSceneObjectAdd()
928 // Notification for observers
929 for( auto iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
931 (*iter)->SceneObjectAdded(*this);
934 // enable property notifications in scene graph
935 EnablePropertyNotifications();
938 void Object::OnSceneObjectRemove()
940 // Notification for observers
941 for( auto iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
943 (*iter)->SceneObjectRemoved(*this);
946 // disable property notifications in scene graph
947 DisablePropertyNotifications();
950 const TypeInfo* Object::GetTypeInfo() const
954 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
955 // especially as the type-info does not change during the life-time of an application
957 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
958 if ( typeInfoHandle )
960 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
967 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
969 CustomPropertyMetadata* property( NULL );
970 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
972 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
974 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
975 if( custom->childPropertyIndex == index )
983 int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
984 if( arrayIndex >= 0 )
986 if( arrayIndex < static_cast<int>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
988 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
995 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
997 for( auto&& entry : mAnimatableProperties )
999 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( entry );
1000 if( property->index == index )
1008 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue) const
1010 // Create a new property
1011 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1013 switch ( propertyValue.GetType() )
1015 case Property::BOOLEAN:
1017 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
1021 case Property::INTEGER:
1023 newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
1027 case Property::FLOAT:
1029 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
1033 case Property::VECTOR2:
1035 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
1039 case Property::VECTOR3:
1041 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
1045 case Property::VECTOR4:
1047 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
1051 case Property::MATRIX:
1053 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
1057 case Property::MATRIX3:
1059 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
1063 case Property::ROTATION:
1065 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
1069 case Property::RECTANGLE:
1070 case Property::STRING:
1071 case Property::ARRAY:
1073 case Property::EXTENTS:
1074 case Property::NONE:
1076 DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
1081 // get the scene property owner from derived class
1082 const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
1083 // we can only pass properties to scene graph side if there is a scene object
1084 if( scenePropertyOwner )
1086 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1087 const PropertyBase* property = newProperty.Get();
1088 if(index >= PROPERTY_CUSTOM_START_INDEX)
1090 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
1092 mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
1096 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
1099 // queue a message to add the property
1100 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty ); // Message takes ownership
1106 // property was orphaned and killed so return invalid index
1107 return Property::INVALID_INDEX;
1111 void Object::RegisterAnimatableProperty( const TypeInfo& typeInfo,
1112 Property::Index index,
1113 const Property::Value* value ) const
1115 // If the property is not a component of a base property, register the whole property itself.
1116 const std::string& propertyName = typeInfo.GetPropertyName( index );
1117 Property::Value initialValue;
1120 initialValue = *value;
1124 initialValue = typeInfo.GetPropertyDefaultValue( index ); // recurses type hierarchy
1125 if( Property::NONE == initialValue.GetType() )
1127 initialValue = Property::Value( typeInfo.GetPropertyType( index ) ); // recurses type hierarchy
1130 RegisterSceneGraphProperty( propertyName, Property::INVALID_KEY, index, initialValue );
1131 AddUniformMapping( index, propertyName );
1134 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty( Property::Index index, const Property::Value* value ) const
1136 // property range already checked by calling methods
1137 // check whether the animatable property is registered already, if not then register one.
1138 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1139 if( !animatableProperty )
1141 const TypeInfo* typeInfo( GetTypeInfo() );
1144 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex( index );
1145 if( basePropertyIndex == Property::INVALID_INDEX )
1147 // If the property is not a component of a base property, register the whole property itself.
1148 RegisterAnimatableProperty( *typeInfo, index, value );
1152 // Since the property is a component of a base property, check whether the base property is registered.
1153 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1154 if( !animatableProperty )
1156 // If the base property is not registered yet, register the base property first.
1157 RegisterAnimatableProperty( *typeInfo, basePropertyIndex, value );
1158 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1161 // Create the metadata for the property component.
1162 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1165 // The metadata has just been added and therefore should be in the end of the vector.
1166 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1170 return animatableProperty;
1173 void Object::ResolveChildProperties()
1175 // Resolve index for the child property
1176 Object* parent = GetParentObject();
1179 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1180 if( parentTypeInfo )
1182 // Go through each custom property
1183 for( auto&& entry : mCustomProperties )
1185 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
1187 if( customProperty->name.empty() )
1189 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1191 // Resolve name for any child property with no name
1192 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1197 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1198 if( childPropertyIndex != Property::INVALID_INDEX )
1200 // Resolve index for any property with a name that matches the parent's child property name
1201 customProperty->childPropertyIndex = childPropertyIndex;
1209 void Object::EnablePropertyNotifications()
1211 if( mPropertyNotifications )
1213 for( auto&& element : *mPropertyNotifications )
1215 GetImplementation( element ).Enable();
1220 void Object::DisablePropertyNotifications()
1222 if( mPropertyNotifications )
1224 for( auto&& element : *mPropertyNotifications )
1226 GetImplementation( element ).Disable();
1231 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata& entry ) const
1233 Property::Value value;
1235 if( !entry.IsAnimatable() )
1237 value = entry.GetPropertyValue();
1241 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1243 switch ( entry.GetType() )
1245 case Property::BOOLEAN:
1247 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1248 DALI_ASSERT_DEBUG( NULL != property );
1250 value = (*property)[ bufferIndex ];
1254 case Property::INTEGER:
1256 const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1257 DALI_ASSERT_DEBUG( NULL != property );
1259 value = (*property)[ bufferIndex ];
1263 case Property::FLOAT:
1265 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1266 DALI_ASSERT_DEBUG( NULL != property );
1268 value = (*property)[ bufferIndex ];
1272 case Property::VECTOR2:
1274 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1275 DALI_ASSERT_DEBUG( NULL != property );
1277 if(entry.componentIndex == 0)
1279 value = (*property)[ bufferIndex ].x;
1281 else if(entry.componentIndex == 1)
1283 value = (*property)[ bufferIndex ].y;
1287 value = (*property)[ bufferIndex ];
1292 case Property::VECTOR3:
1294 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1295 DALI_ASSERT_DEBUG( NULL != property );
1297 if(entry.componentIndex == 0)
1299 value = (*property)[ bufferIndex ].x;
1301 else if(entry.componentIndex == 1)
1303 value = (*property)[ bufferIndex ].y;
1305 else if(entry.componentIndex == 2)
1307 value = (*property)[ bufferIndex ].z;
1311 value = (*property)[ bufferIndex ];
1316 case Property::VECTOR4:
1318 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1319 DALI_ASSERT_DEBUG( NULL != property );
1321 if(entry.componentIndex == 0)
1323 value = (*property)[ bufferIndex ].x;
1325 else if(entry.componentIndex == 1)
1327 value = (*property)[ bufferIndex ].y;
1329 else if(entry.componentIndex == 2)
1331 value = (*property)[ bufferIndex ].z;
1333 else if(entry.componentIndex == 3)
1335 value = (*property)[ bufferIndex ].w;
1339 value = (*property)[ bufferIndex ];
1344 case Property::MATRIX:
1346 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1347 DALI_ASSERT_DEBUG( NULL != property );
1349 value = (*property)[ bufferIndex ];
1353 case Property::MATRIX3:
1355 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1356 DALI_ASSERT_DEBUG( NULL != property );
1358 value = (*property)[ bufferIndex ];
1362 case Property::ROTATION:
1364 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1365 DALI_ASSERT_DEBUG( NULL != property );
1367 value = (*property)[ bufferIndex ];
1373 // unreachable code due to higher level logic
1381 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1383 switch ( entry.GetType() )
1385 case Property::BOOLEAN:
1387 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1388 DALI_ASSERT_DEBUG( NULL != property );
1390 // property is being used in a separate thread; queue a message to set the property
1391 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1395 case Property::INTEGER:
1397 const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1398 DALI_ASSERT_DEBUG( NULL != property );
1400 // property is being used in a separate thread; queue a message to set the property
1401 BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
1405 case Property::FLOAT:
1407 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1408 DALI_ASSERT_DEBUG( NULL != property );
1410 // property is being used in a separate thread; queue a message to set the property
1411 BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1415 case Property::VECTOR2:
1417 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1418 DALI_ASSERT_DEBUG( NULL != property );
1420 // property is being used in a separate thread; queue a message to set the property
1421 if(entry.componentIndex == 0)
1423 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1425 else if(entry.componentIndex == 1)
1427 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1431 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1436 case Property::VECTOR3:
1438 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1439 DALI_ASSERT_DEBUG( NULL != property );
1441 // property is being used in a separate thread; queue a message to set the property
1442 if(entry.componentIndex == 0)
1444 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1446 else if(entry.componentIndex == 1)
1448 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1450 else if(entry.componentIndex == 2)
1452 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1456 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1462 case Property::VECTOR4:
1464 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1465 DALI_ASSERT_DEBUG( NULL != property );
1467 // property is being used in a separate thread; queue a message to set the property
1468 if(entry.componentIndex == 0)
1470 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1472 else if(entry.componentIndex == 1)
1474 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1476 else if(entry.componentIndex == 2)
1478 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1480 else if(entry.componentIndex == 3)
1482 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1486 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1491 case Property::ROTATION:
1493 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1494 DALI_ASSERT_DEBUG( NULL != property );
1496 // property is being used in a separate thread; queue a message to set the property
1497 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1501 case Property::MATRIX:
1503 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1504 DALI_ASSERT_DEBUG( NULL != property );
1506 // property is being used in a separate thread; queue a message to set the property
1507 BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1511 case Property::MATRIX3:
1513 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1514 DALI_ASSERT_DEBUG( NULL != property );
1516 // property is being used in a separate thread; queue a message to set the property
1517 BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1523 // non-animatable scene graph property, do nothing
1528 } // namespace Internal