2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/event/common/object-impl.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/object/handle-devel.h>
27 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
28 #include <dali/internal/update/common/animatable-property.h>
29 #include <dali/internal/update/common/property-owner.h>
30 #include <dali/internal/update/common/property-owner-messages.h>
31 #include <dali/internal/update/common/uniform-map.h>
32 #include <dali/internal/event/animation/constraint-impl.h>
33 #include <dali/internal/event/common/property-helper.h>
34 #include <dali/internal/event/common/property-notification-impl.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/type-registry-impl.h>
38 using Dali::Internal::SceneGraph::AnimatableProperty;
39 using Dali::Internal::SceneGraph::PropertyBase;
47 namespace // unnamed namespace
49 const int32_t SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
55 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
57 } // unnamed namespace
59 IntrusivePtr<Object> Object::New()
61 return new Object( nullptr ); // no scene object by default
64 void Object::AddObserver(Observer& observer)
66 // make sure an observer doesn't observe the same object twice
67 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
68 DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70 mObservers.PushBack( &observer );
73 void Object::RemoveObserver(Observer& observer)
75 // Find the observer...
76 const auto endIter = mObservers.End();
77 for( auto iter = mObservers.Begin(); iter != endIter; ++iter)
79 if( (*iter) == &observer)
81 mObservers.Erase( iter );
85 DALI_ASSERT_DEBUG(endIter != mObservers.End());
88 bool Object::Supports( Capability capability ) const
90 return (capability & SUPPORTED_CAPABILITIES);
93 uint32_t Object::GetPropertyCount() const
96 const TypeInfo* typeInfo( GetTypeInfo() );
99 count = typeInfo->GetPropertyCount();
101 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count );
104 uint32_t custom = static_cast<uint32_t>( mCustomProperties.Count() );
106 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
108 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
113 std::string Object::GetPropertyName( Property::Index index ) const
115 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
117 // is this a per class or per instance property
118 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
120 const TypeInfo* typeInfo( GetTypeInfo() );
123 return typeInfo->GetPropertyName( index );
126 else // child property or custom property
128 CustomPropertyMetadata* custom = FindCustomProperty( index );
135 DALI_LOG_ERROR( "Property index %d not found\n", index );
136 return std::string();
139 Property::Index Object::GetPropertyIndex( const std::string& name ) const
141 Property::Index index = Property::INVALID_INDEX;
143 const TypeInfo* typeInfo( GetTypeInfo() );
146 index = typeInfo->GetPropertyIndex( name );
148 if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
150 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
151 const auto end = mCustomProperties.End();
152 for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
154 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
155 if ( custom->name == name )
157 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
159 // If it is a child property, return the child property index
160 index = custom->childPropertyIndex;
174 Property::Index Object::GetPropertyIndex( Property::Index key ) const
176 Property::Index index = Property::INVALID_INDEX;
178 if( mCustomProperties.Count() > 0 )
180 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
181 const auto end = mCustomProperties.End();
182 for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
184 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
185 if( custom->key == key )
187 if( custom->childPropertyIndex != Property::INVALID_INDEX )
189 // If it is a child property, return the child property index
190 index = custom->childPropertyIndex;
204 Property::Index Object::GetPropertyIndex( Property::Key key ) const
206 Property::Index index = Property::INVALID_INDEX;
207 if( key.type == Property::Key::INDEX )
209 index = GetPropertyIndex( key.indexKey );
213 index = GetPropertyIndex( key.stringKey );
218 bool Object::IsPropertyWritable( Property::Index index ) const
220 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
222 bool writable = false;
224 // is this a per class or per instance property
225 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
227 const TypeInfo* typeInfo( GetTypeInfo() );
230 writable = typeInfo->IsPropertyWritable( index );
235 CustomPropertyMetadata* custom = FindCustomProperty( index );
238 writable = custom->IsWritable();
245 bool Object::IsPropertyAnimatable( Property::Index index ) const
247 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
249 bool animatable = false;
251 // is this a per class or per instance property
252 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
254 const TypeInfo* typeInfo( GetTypeInfo() );
257 animatable = typeInfo->IsPropertyAnimatable( index );
262 CustomPropertyMetadata* custom = FindCustomProperty( index );
265 animatable = custom->IsAnimatable();
272 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
274 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
276 bool isConstraintInput = false;
278 // is this a per class or per instance property
279 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
281 const TypeInfo* typeInfo( GetTypeInfo() );
284 isConstraintInput = typeInfo->IsPropertyAConstraintInput( index );
289 CustomPropertyMetadata* custom = FindCustomProperty( index );
292 // ... custom properties can be used as input to a constraint.
293 isConstraintInput = true;
297 return isConstraintInput;
300 Property::Type Object::GetPropertyType( Property::Index index ) const
302 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
304 // is this a per class or per instance property
305 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
307 const TypeInfo* typeInfo( GetTypeInfo() );
310 return typeInfo->GetPropertyType( index );
314 CustomPropertyMetadata* custom = FindCustomProperty( index );
317 return custom->GetType();
320 return Property::NONE;
323 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
325 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
327 bool propertySet( true );
329 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
331 SetDefaultProperty( index, propertyValue );
333 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
335 const TypeInfo* typeInfo( GetTypeInfo() );
338 typeInfo->SetProperty( this, index, propertyValue );
342 // cannot register this property as there is no setter for it.
343 // event side properties must have a setter for now so need to be registered
344 DALI_LOG_ERROR( "Property index %d not found\n", index );
348 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
350 // check whether the animatable property is registered already, if not then register one.
351 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, &propertyValue );
352 if( !animatableProperty )
354 DALI_LOG_ERROR( "Property index %d not found\n", index );
359 // update the cached property value
360 animatableProperty->SetPropertyValue( propertyValue );
362 // set the scene graph property value
363 SetSceneGraphProperty( index, *animatableProperty, propertyValue );
368 CustomPropertyMetadata* custom = FindCustomProperty( index );
370 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
374 // If the child property is not registered yet, register it.
375 custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
376 mCustomProperties.PushBack( custom );
379 custom->childPropertyIndex = index;
381 // Resolve name for the child property
382 Object* parent = GetParentObject();
385 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
388 custom->name = parentTypeInfo->GetChildPropertyName( index );
395 if( custom->IsAnimatable() )
397 // update the cached property value
398 custom->SetPropertyValue( propertyValue );
400 // set the scene graph property value
401 SetSceneGraphProperty( index, *custom, propertyValue );
403 else if( custom->IsWritable() )
405 // update the cached property value
406 custom->SetPropertyValue( propertyValue );
410 // trying to set value on read only property is no-op
416 DALI_LOG_ERROR( "Property index %d not found\n", index );
421 // Let derived classes know that a property has been set
422 // 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
425 OnPropertySet( index, propertyValue );
426 Dali::Handle handle( this );
427 mPropertySetSignal.Emit( handle, index, propertyValue );
431 Property::Value Object::GetProperty( Property::Index index ) const
433 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
435 Property::Value value;
437 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
439 value = GetDefaultProperty( index );
441 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
443 const TypeInfo* typeInfo( GetTypeInfo() );
446 value = typeInfo->GetProperty( this, index );
450 DALI_LOG_ERROR( "Property index %d not found\n", index );
453 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
455 // check whether the animatable property is registered already, if not then register one.
456 // this is needed because property value may have been set as full property and get as a property component
457 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
458 if( animatableProperty )
460 // get the cached animatable property value
461 value = animatableProperty->GetPropertyValue();
465 DALI_LOG_ERROR( "Property index %d not found\n", index );
468 else if(mCustomProperties.Count() > 0)
470 CustomPropertyMetadata* custom = FindCustomProperty( index );
473 // get the cached custom property value
474 value = custom->GetPropertyValue();
478 DALI_LOG_ERROR( "Property index %d not found\n", index );
485 Property::Value Object::GetCurrentProperty( Property::Index index ) const
487 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
489 Property::Value value;
491 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
493 value = GetDefaultPropertyCurrentValue( index );
495 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
497 const TypeInfo* typeInfo( GetTypeInfo() );
500 value = typeInfo->GetProperty( this, index );
504 DALI_LOG_ERROR( "Property index %d not found\n", index );
507 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
509 // check whether the animatable property is registered already, if not then register one.
510 // this is needed because property value may have been set as full property and get as a property component
511 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
512 if( animatableProperty )
514 // get the animatable property value
515 value = GetCurrentPropertyValue( *animatableProperty );
519 DALI_LOG_ERROR( "Property index %d not found\n", index );
522 else if(mCustomProperties.Count() > 0)
524 CustomPropertyMetadata* custom = FindCustomProperty( index );
527 // get the custom property value
528 value = GetCurrentPropertyValue( *custom );
532 DALI_LOG_ERROR( "Property index %d not found\n", index );
539 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
544 const TypeInfo* typeInfo( GetTypeInfo() );
547 typeInfo->GetPropertyIndices( indices );
551 if ( mCustomProperties.Count() > 0 )
553 indices.Reserve( indices.Size() + mCustomProperties.Count() );
555 auto iter = mCustomProperties.Begin();
556 const auto endIter = mCustomProperties.End();
558 for ( ; iter != endIter; ++iter, ++i )
560 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
561 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
563 // If it is a child property, add the child property index
564 indices.PushBack( custom->childPropertyIndex );
568 indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
574 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
576 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
579 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
581 return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
584 void Object::SetProperties( const Property::Map& properties )
586 const auto count = properties.Count();
587 for( auto position = 0u; position < count; ++position )
589 // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
590 // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
592 const auto& key = properties.GetKeyAt( position );
593 const auto propertyIndex = ( key.type == Property::Key::INDEX ) ? key.indexKey : GetPropertyIndex( key.stringKey );
595 if( propertyIndex != Property::INVALID_INDEX )
597 const auto& value = properties.GetValue( position );
598 SetProperty( propertyIndex, value );
603 void Object::GetProperties( Property::Map& properties )
607 Property::IndexContainer indexContainer;
608 GetPropertyIndices( indexContainer );
610 for( auto index : indexContainer )
612 properties[ index ] = GetProperty( index );
616 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
618 return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
621 Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
623 // If property with the required key already exists, then just set it.
624 Property::Index index = Property::INVALID_INDEX;
625 if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
627 index = GetPropertyIndex( key );
629 if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
631 index = GetPropertyIndex( name );
634 if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
636 SetProperty( index, propertyValue );
640 // Otherwise register the property
641 if( Property::ANIMATABLE == accessMode )
643 index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() ), propertyValue );
644 AddUniformMapping( index, name );
648 // Add entry to the property lookup
649 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
651 CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
653 // Resolve index for the child property
654 Object* parent = GetParentObject();
657 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
660 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
661 if( childPropertyIndex != Property::INVALID_INDEX )
663 customProperty->childPropertyIndex = childPropertyIndex;
664 index = childPropertyIndex;
669 mCustomProperties.PushBack( customProperty );
676 bool Object::DoesCustomPropertyExist( Property::Index index )
678 auto metadata = FindCustomProperty( index );
679 return metadata != nullptr;
682 Dali::PropertyNotification Object::AddPropertyNotification( Property::Index index,
683 int32_t componentIndex,
684 const Dali::PropertyCondition& condition)
686 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
688 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
690 DALI_ABORT( "Property notification added to event side only property." );
692 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
694 // check whether the animatable property is registered already, if not then register one.
695 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
696 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
698 else if ( mCustomProperties.Count() > 0 )
700 CustomPropertyMetadata* custom = FindCustomProperty( index );
701 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
702 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
706 Dali::Handle self(this);
707 Property target( self, index );
709 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
710 Dali::PropertyNotification propertyNotification(internal.Get());
712 if( !mPropertyNotifications )
714 mPropertyNotifications = new PropertyNotificationContainer;
716 mPropertyNotifications->push_back(propertyNotification);
718 return propertyNotification;
721 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
723 if( mPropertyNotifications )
725 auto iter = mPropertyNotifications->begin();
726 while(iter != mPropertyNotifications->end() )
728 if(*iter == propertyNotification)
730 mPropertyNotifications->erase(iter);
731 // As we can't ensure all references are removed, we can just disable
733 GetImplementation(propertyNotification).Disable();
741 void Object::RemovePropertyNotifications()
743 if( mPropertyNotifications )
745 auto iter = mPropertyNotifications->begin();
746 while(iter != mPropertyNotifications->end() )
748 // As we can't ensure all references are removed, we can just disable
750 GetImplementation(*iter).Disable();
754 mPropertyNotifications->clear();
758 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
760 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
762 OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
766 PropertyMetadata* propertyMetadata = nullptr;
767 if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
769 propertyMetadata = FindAnimatableProperty( index );
773 CustomPropertyMetadata* custom = FindCustomProperty( index );
774 if( custom && custom->IsAnimatable() )
776 propertyMetadata = custom;
780 if( propertyMetadata )
782 switch( animationType )
785 case Animation::BETWEEN:
787 // Update the cached property value
788 propertyMetadata->SetPropertyValue( value );
793 // Adjust the cached property value
794 propertyMetadata->AdjustPropertyValueBy( value );
802 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
804 // Get the address of the property if it's a scene property
805 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
807 // Check instead for newly registered properties
808 if( propertyPtr == nullptr )
810 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
813 propertyPtr = animatable->GetSceneGraphProperty();
817 if( propertyPtr == nullptr )
819 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
822 propertyPtr = custom->GetSceneGraphProperty();
828 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
830 OwnerPointer< SceneGraph::UniformPropertyMapping > map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
831 // Message takes ownership of Uniform map (and will delete it after copy)
832 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map );
836 void Object::RemoveUniformMapping( const std::string& uniformName ) const
838 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
839 RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, uniformName);
842 void Object::ApplyConstraint( ConstraintBase& constraint )
846 mConstraints = new ConstraintContainer;
848 mConstraints->push_back( Dali::Constraint( &constraint ) );
851 void Object::RemoveConstraint( ConstraintBase& constraint )
853 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
856 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
857 if( it != mConstraints->end() )
859 mConstraints->erase( it );
864 void Object::RemoveConstraints()
866 // guard against constraint sending messages during core destruction
867 if( mConstraints && Stage::IsInstalled() )
869 for ( auto&& item : *mConstraints )
871 GetImplementation( item ).RemoveInternal();
875 mConstraints = nullptr;
879 void Object::RemoveConstraints( uint32_t tag )
881 // guard against constraint sending messages during core destruction
882 if( mConstraints && Stage::IsInstalled() )
884 auto iter( mConstraints->begin() );
885 while(iter != mConstraints->end() )
887 ConstraintBase& constraint = GetImplementation( *iter );
888 if( constraint.GetTag() == tag )
890 GetImplementation( *iter ).RemoveInternal();
891 iter = mConstraints->erase( iter );
899 if ( mConstraints->empty() )
902 mConstraints = nullptr;
907 void Object::SetTypeInfo( const TypeInfo* typeInfo )
909 mTypeInfo = typeInfo;
912 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
916 auto sceneObject = SceneGraph::PropertyOwner::New();
917 OwnerPointer< SceneGraph::PropertyOwner > transferOwnership( sceneObject );
918 mUpdateObject = sceneObject;
919 AddObjectMessage( const_cast<EventThreadServices&>( GetEventThreadServices() ).GetUpdateManager(), transferOwnership );
921 DALI_ASSERT_DEBUG( mUpdateObject && "there must always be a scene object" );
922 return *mUpdateObject;
925 const PropertyBase* Object::GetSceneObjectAnimatableProperty( Property::Index index ) const
927 const SceneGraph::PropertyBase* property = nullptr;
928 if ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX )
930 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
931 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
933 property = animatable->GetSceneGraphProperty();
935 else if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && // Child properties are also stored as custom properties
936 ( index <= PROPERTY_CUSTOM_MAX_INDEX ) )
938 CustomPropertyMetadata* custom = FindCustomProperty( index );
939 DALI_ASSERT_ALWAYS( custom && "Property index is invalid" );
941 property = custom->GetSceneGraphProperty();
946 const PropertyInputImpl* Object::GetSceneObjectInputProperty( Property::Index index ) const
948 // reuse animatable version as they are inputs as well
949 return GetSceneObjectAnimatableProperty( index );
952 int32_t Object::GetPropertyComponentIndex( Property::Index index ) const
954 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
956 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
958 // check whether the animatable property is registered already, if not then register one.
959 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
960 if( animatableProperty )
962 componentIndex = animatableProperty->componentIndex;
965 if( Property::INVALID_COMPONENT_INDEX == componentIndex )
967 const TypeInfo* typeInfo( GetTypeInfo() );
970 componentIndex = typeInfo->GetComponentIndex(index);
974 return componentIndex;
977 DevelHandle::PropertySetSignalType& Object::PropertySetSignal()
979 return mPropertySetSignal;
982 Object::Object( const SceneGraph::PropertyOwner* sceneObject )
983 : mEventThreadServices( EventThreadServices::Get() ),
984 mUpdateObject( sceneObject ),
985 mTypeInfo( nullptr ),
986 mConstraints( nullptr ),
987 mPropertyNotifications( nullptr )
993 // Notification for observers
994 for( auto&& item : mObservers )
996 item->ObjectDestroyed( *this );
999 delete mPropertyNotifications;
1001 // Guard to allow handle destruction after Core has been destroyed
1002 if( Stage::IsInstalled() )
1004 if( nullptr != mUpdateObject )
1006 RemoveObjectMessage( GetEventThreadServices().GetUpdateManager(), mUpdateObject );
1011 void Object::OnSceneObjectAdd()
1013 // Notification for observers
1014 for( auto&& item : mObservers )
1016 item->SceneObjectAdded(*this);
1019 // enable property notifications in scene graph
1020 EnablePropertyNotifications();
1023 void Object::OnSceneObjectRemove()
1025 // Notification for observers
1026 for( auto&& item : mObservers )
1028 item->SceneObjectRemoved(*this);
1031 // disable property notifications in scene graph
1032 DisablePropertyNotifications();
1035 const TypeInfo* Object::GetTypeInfo() const
1039 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1040 // especially as the type-info does not change during the life-time of an application
1042 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1043 if ( typeInfoHandle )
1045 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1052 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1054 CustomPropertyMetadata* property = nullptr;
1055 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1057 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1059 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1060 if( custom->childPropertyIndex == index )
1068 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1069 if( arrayIndex >= 0 )
1071 if( arrayIndex < static_cast<int32_t>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
1073 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1080 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1082 for( auto&& entry : mAnimatableProperties )
1084 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( entry );
1085 if( property->index == index )
1093 Property::Index Object::RegisterSceneGraphProperty( const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue ) const
1095 // Create a new property
1096 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1098 switch ( propertyValue.GetType() )
1100 case Property::BOOLEAN:
1102 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
1106 case Property::INTEGER:
1108 newProperty = new AnimatableProperty<int32_t>( propertyValue.Get<int32_t>() );
1112 case Property::FLOAT:
1114 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
1118 case Property::VECTOR2:
1120 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
1124 case Property::VECTOR3:
1126 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
1130 case Property::VECTOR4:
1132 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
1136 case Property::MATRIX:
1138 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
1142 case Property::MATRIX3:
1144 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
1148 case Property::ROTATION:
1150 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
1154 case Property::RECTANGLE:
1155 case Property::STRING:
1156 case Property::ARRAY:
1158 case Property::EXTENTS:
1159 case Property::NONE:
1161 DALI_ASSERT_ALWAYS( !"Property type is not animatable" );
1166 // get the scene property owner
1167 const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1168 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1169 const PropertyBase* property = newProperty.Get();
1170 if(index >= PROPERTY_CUSTOM_START_INDEX)
1172 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
1174 mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
1178 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
1181 // queue a message to add the property
1182 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty ); // Message takes ownership
1187 void Object::RegisterAnimatableProperty( const TypeInfo& typeInfo,
1188 Property::Index index,
1189 const Property::Value* value ) const
1191 // If the property is not a component of a base property, register the whole property itself.
1192 const std::string& propertyName = typeInfo.GetPropertyName( index );
1193 Property::Value initialValue;
1196 initialValue = *value;
1200 initialValue = typeInfo.GetPropertyDefaultValue( index ); // recurses type hierarchy
1201 if( Property::NONE == initialValue.GetType() )
1203 initialValue = Property::Value( typeInfo.GetPropertyType( index ) ); // recurses type hierarchy
1206 RegisterSceneGraphProperty( propertyName, Property::INVALID_KEY, index, initialValue );
1207 AddUniformMapping( index, propertyName );
1210 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty( Property::Index index, const Property::Value* value ) const
1212 // property range already checked by calling methods
1213 // check whether the animatable property is registered already, if not then register one.
1214 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1215 if( !animatableProperty )
1217 const TypeInfo* typeInfo( GetTypeInfo() );
1220 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex( index );
1221 if( basePropertyIndex == Property::INVALID_INDEX )
1223 // If the property is not a component of a base property, register the whole property itself.
1224 RegisterAnimatableProperty( *typeInfo, index, value );
1228 // Since the property is a component of a base property, check whether the base property is registered.
1229 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1230 if( !animatableProperty )
1232 // If the base property is not registered yet, register the base property first.
1233 RegisterAnimatableProperty( *typeInfo, basePropertyIndex, value );
1234 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1237 // Create the metadata for the property component.
1238 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1241 // The metadata has just been added and therefore should be in the end of the vector.
1242 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1246 return animatableProperty;
1249 void Object::ResolveChildProperties()
1251 // Resolve index for the child property
1252 Object* parent = GetParentObject();
1255 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1256 if( parentTypeInfo )
1258 // Go through each custom property
1259 for( auto&& entry : mCustomProperties )
1261 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
1263 if( customProperty->name.empty() )
1265 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1267 // Resolve name for any child property with no name
1268 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1273 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1274 if( childPropertyIndex != Property::INVALID_INDEX )
1276 // Resolve index for any property with a name that matches the parent's child property name
1277 customProperty->childPropertyIndex = childPropertyIndex;
1285 void Object::SetDefaultProperty( Property::Index index, const Property::Value& property )
1290 Property::Value Object::GetDefaultProperty(Property::Index index) const
1292 return Property::Value();
1295 Property::Value Object::GetDefaultPropertyCurrentValue( Property::Index index ) const
1297 return GetDefaultProperty( index );
1300 void Object::EnablePropertyNotifications()
1302 if( mPropertyNotifications )
1304 for( auto&& element : *mPropertyNotifications )
1306 GetImplementation( element ).Enable();
1311 void Object::DisablePropertyNotifications()
1313 if( mPropertyNotifications )
1315 for( auto&& element : *mPropertyNotifications )
1317 GetImplementation( element ).Disable();
1322 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata& entry ) const
1324 Property::Value value;
1326 if( !entry.IsAnimatable() )
1328 value = entry.GetPropertyValue();
1332 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1334 switch ( entry.GetType() )
1336 case Property::BOOLEAN:
1338 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1339 DALI_ASSERT_DEBUG( property );
1341 value = (*property)[ bufferIndex ];
1345 case Property::INTEGER:
1347 const AnimatableProperty<int32_t>* property = static_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1348 DALI_ASSERT_DEBUG( property );
1350 value = (*property)[ bufferIndex ];
1354 case Property::FLOAT:
1356 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1357 DALI_ASSERT_DEBUG( property );
1359 value = (*property)[ bufferIndex ];
1363 case Property::VECTOR2:
1365 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1366 DALI_ASSERT_DEBUG( property );
1368 if(entry.componentIndex == 0)
1370 value = (*property)[ bufferIndex ].x;
1372 else if(entry.componentIndex == 1)
1374 value = (*property)[ bufferIndex ].y;
1378 value = (*property)[ bufferIndex ];
1383 case Property::VECTOR3:
1385 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1386 DALI_ASSERT_DEBUG( property );
1388 if(entry.componentIndex == 0)
1390 value = (*property)[ bufferIndex ].x;
1392 else if(entry.componentIndex == 1)
1394 value = (*property)[ bufferIndex ].y;
1396 else if(entry.componentIndex == 2)
1398 value = (*property)[ bufferIndex ].z;
1402 value = (*property)[ bufferIndex ];
1407 case Property::VECTOR4:
1409 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1410 DALI_ASSERT_DEBUG( property );
1412 if(entry.componentIndex == 0)
1414 value = (*property)[ bufferIndex ].x;
1416 else if(entry.componentIndex == 1)
1418 value = (*property)[ bufferIndex ].y;
1420 else if(entry.componentIndex == 2)
1422 value = (*property)[ bufferIndex ].z;
1424 else if(entry.componentIndex == 3)
1426 value = (*property)[ bufferIndex ].w;
1430 value = (*property)[ bufferIndex ];
1435 case Property::MATRIX:
1437 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1438 DALI_ASSERT_DEBUG( property );
1440 value = (*property)[ bufferIndex ];
1444 case Property::MATRIX3:
1446 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1447 DALI_ASSERT_DEBUG( property );
1449 value = (*property)[ bufferIndex ];
1453 case Property::ROTATION:
1455 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1456 DALI_ASSERT_DEBUG( property );
1458 value = (*property)[ bufferIndex ];
1464 // unreachable code due to higher level logic
1472 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1474 switch ( entry.GetType() )
1476 case Property::BOOLEAN:
1478 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1479 DALI_ASSERT_DEBUG( property );
1481 // property is being used in a separate thread; queue a message to set the property
1482 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1486 case Property::INTEGER:
1488 const AnimatableProperty<int32_t>* property = dynamic_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1489 DALI_ASSERT_DEBUG( property );
1491 // property is being used in a separate thread; queue a message to set the property
1492 BakeMessage<int32_t>( GetEventThreadServices(), *property, value.Get<int32_t>() );
1496 case Property::FLOAT:
1498 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1499 DALI_ASSERT_DEBUG( property );
1501 // property is being used in a separate thread; queue a message to set the property
1502 BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1506 case Property::VECTOR2:
1508 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1509 DALI_ASSERT_DEBUG( property );
1511 // property is being used in a separate thread; queue a message to set the property
1512 if(entry.componentIndex == 0)
1514 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1516 else if(entry.componentIndex == 1)
1518 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1522 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1527 case Property::VECTOR3:
1529 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1530 DALI_ASSERT_DEBUG( property );
1532 // property is being used in a separate thread; queue a message to set the property
1533 if(entry.componentIndex == 0)
1535 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1537 else if(entry.componentIndex == 1)
1539 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1541 else if(entry.componentIndex == 2)
1543 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1547 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1553 case Property::VECTOR4:
1555 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1556 DALI_ASSERT_DEBUG( property );
1558 // property is being used in a separate thread; queue a message to set the property
1559 if(entry.componentIndex == 0)
1561 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1563 else if(entry.componentIndex == 1)
1565 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1567 else if(entry.componentIndex == 2)
1569 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1571 else if(entry.componentIndex == 3)
1573 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1577 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1582 case Property::ROTATION:
1584 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1585 DALI_ASSERT_DEBUG( property );
1587 // property is being used in a separate thread; queue a message to set the property
1588 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1592 case Property::MATRIX:
1594 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1595 DALI_ASSERT_DEBUG( property );
1597 // property is being used in a separate thread; queue a message to set the property
1598 BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1602 case Property::MATRIX3:
1604 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1605 DALI_ASSERT_DEBUG( property );
1607 // property is being used in a separate thread; queue a message to set the property
1608 BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1614 // non-animatable scene graph property, do nothing
1619 } // namespace Internal