2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/event/common/object-impl.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/object/handle-devel.h>
27 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
28 #include <dali/internal/update/common/animatable-property.h>
29 #include <dali/internal/update/common/property-owner.h>
30 #include <dali/internal/update/common/property-owner-messages.h>
31 #include <dali/internal/update/common/uniform-map.h>
32 #include <dali/internal/event/animation/constraint-impl.h>
33 #include <dali/internal/event/common/property-helper.h>
34 #include <dali/internal/event/common/property-notification-impl.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/type-registry-impl.h>
38 using Dali::Internal::SceneGraph::AnimatableProperty;
39 using Dali::Internal::SceneGraph::PropertyBase;
47 namespace // unnamed namespace
49 const int32_t SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // Object provides this capability
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
55 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
57 } // unnamed namespace
59 IntrusivePtr<Object> Object::New()
61 return new Object( nullptr ); // no scene object by default
64 void Object::AddObserver(Observer& observer)
66 // make sure an observer doesn't observe the same object twice
67 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
68 DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70 mObservers.PushBack( &observer );
73 void Object::RemoveObserver(Observer& observer)
75 // Find the observer...
76 const auto endIter = mObservers.End();
77 for( auto iter = mObservers.Begin(); iter != endIter; ++iter)
79 if( (*iter) == &observer)
81 mObservers.Erase( iter );
85 DALI_ASSERT_DEBUG(endIter != mObservers.End());
88 bool Object::Supports( Capability capability ) const
90 return (capability & SUPPORTED_CAPABILITIES);
93 uint32_t Object::GetPropertyCount() const
96 const TypeInfo* typeInfo( GetTypeInfo() );
99 count = typeInfo->GetPropertyCount();
101 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Registered Properties: %d\n", count );
104 uint32_t custom = static_cast<uint32_t>( mCustomProperties.Count() );
106 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
108 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
113 std::string Object::GetPropertyName( Property::Index index ) const
115 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
117 // is this a per class or per instance property
118 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
120 const TypeInfo* typeInfo( GetTypeInfo() );
123 return typeInfo->GetPropertyName( index );
126 else // child property or custom property
128 CustomPropertyMetadata* custom = FindCustomProperty( index );
135 DALI_LOG_ERROR( "Property index %d not found\n", index );
136 return std::string();
139 Property::Index Object::GetPropertyIndex( Property::Key key ) const
141 Property::Index index = Property::INVALID_INDEX;
143 if( key.type == Property::Key::STRING )
145 const TypeInfo* typeInfo( GetTypeInfo() );
148 index = typeInfo->GetPropertyIndex( key.stringKey );
152 if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
154 Property::Index count = PROPERTY_CUSTOM_START_INDEX;
155 const auto end = mCustomProperties.End();
156 for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
158 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
160 if( ( key.type == Property::Key::STRING && custom->name == key.stringKey) ||
161 ( key.type == Property::Key::INDEX && custom->key == key.indexKey ) )
163 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
165 // If it is a child property, return the child property index
166 index = custom->childPropertyIndex;
180 bool Object::IsPropertyWritable( Property::Index index ) const
182 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
184 bool writable = false;
186 // is this a per class or per instance property
187 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
189 const TypeInfo* typeInfo( GetTypeInfo() );
192 writable = typeInfo->IsPropertyWritable( index );
197 CustomPropertyMetadata* custom = FindCustomProperty( index );
200 writable = custom->IsWritable();
207 bool Object::IsPropertyAnimatable( Property::Index index ) const
209 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
211 bool animatable = false;
213 // is this a per class or per instance property
214 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
216 const TypeInfo* typeInfo( GetTypeInfo() );
219 animatable = typeInfo->IsPropertyAnimatable( index );
224 CustomPropertyMetadata* custom = FindCustomProperty( index );
227 animatable = custom->IsAnimatable();
234 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
236 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
238 bool isConstraintInput = false;
240 // is this a per class or per instance property
241 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
243 const TypeInfo* typeInfo( GetTypeInfo() );
246 isConstraintInput = typeInfo->IsPropertyAConstraintInput( index );
251 CustomPropertyMetadata* custom = FindCustomProperty( index );
254 // ... custom properties can be used as input to a constraint.
255 isConstraintInput = true;
259 return isConstraintInput;
262 Property::Type Object::GetPropertyType( Property::Index index ) const
264 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
266 // is this a per class or per instance property
267 if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
269 const TypeInfo* typeInfo( GetTypeInfo() );
272 return typeInfo->GetPropertyType( index );
276 CustomPropertyMetadata* custom = FindCustomProperty( index );
279 return custom->GetType();
282 return Property::NONE;
285 void Object::SetProperty(Property::Index index, Property::Value propertyValue)
287 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
289 bool propertySet( true );
291 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
293 SetDefaultProperty( index, propertyValue );
295 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
297 const TypeInfo* typeInfo( GetTypeInfo() );
300 typeInfo->SetProperty( this, index, propertyValue );
304 // cannot register this property as there is no setter for it.
305 // event side properties must have a setter for now so need to be registered
306 DALI_LOG_ERROR( "Property index %d not found\n", index );
310 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
312 // check whether the animatable property is registered already, if not then register one.
313 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, &propertyValue );
314 if( !animatableProperty )
316 DALI_LOG_ERROR( "Property index %d not found\n", index );
321 // update the cached property value
322 animatableProperty->SetPropertyValue( propertyValue );
324 // set the scene graph property value
325 SetSceneGraphProperty( index, *animatableProperty, propertyValue );
330 CustomPropertyMetadata* custom = FindCustomProperty( index );
332 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
336 // If the child property is not registered yet, register it.
337 custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
338 mCustomProperties.PushBack( custom );
341 custom->childPropertyIndex = index;
343 // Resolve name for the child property
344 Object* parent = GetParentObject();
347 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
350 custom->name = parentTypeInfo->GetChildPropertyName( index );
357 if( custom->IsAnimatable() )
359 // update the cached property value
360 custom->SetPropertyValue( propertyValue );
362 // set the scene graph property value
363 SetSceneGraphProperty( index, *custom, propertyValue );
365 else if( custom->IsWritable() )
367 // update the cached property value
368 custom->SetPropertyValue( propertyValue );
372 // trying to set value on read only property is no-op
378 DALI_LOG_ERROR( "Property index %d not found\n", index );
383 // Let derived classes know that a property has been set
384 // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
387 OnPropertySet( index, propertyValue );
388 if(!mPropertySetSignal.Empty())
390 Dali::Handle handle(this);
391 mPropertySetSignal.Emit(handle, index, propertyValue);
396 Property::Value Object::GetProperty( Property::Index index ) const
398 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
400 Property::Value value;
402 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
404 value = GetDefaultProperty( index );
406 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
408 const TypeInfo* typeInfo( GetTypeInfo() );
411 value = typeInfo->GetProperty( this, index );
415 DALI_LOG_ERROR( "Property index %d not found\n", index );
418 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
420 // check whether the animatable property is registered already, if not then register one.
421 // this is needed because property value may have been set as full property and get as a property component
422 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
423 if( animatableProperty )
425 // get the cached animatable property value
426 value = animatableProperty->GetPropertyValue();
430 DALI_LOG_ERROR( "Property index %d not found\n", index );
433 else if(mCustomProperties.Count() > 0)
435 CustomPropertyMetadata* custom = FindCustomProperty( index );
438 // get the cached custom property value
439 value = custom->GetPropertyValue();
443 DALI_LOG_ERROR( "Property index %d not found\n", index );
450 Property::Value Object::GetCurrentProperty( Property::Index index ) const
452 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
454 Property::Value value;
456 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
458 value = GetDefaultPropertyCurrentValue( index );
460 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
462 const TypeInfo* typeInfo( GetTypeInfo() );
465 value = typeInfo->GetProperty( this, index );
469 DALI_LOG_ERROR( "Property index %d not found\n", index );
472 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
474 // check whether the animatable property is registered already, if not then register one.
475 // this is needed because property value may have been set as full property and get as a property component
476 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
477 if( animatableProperty )
479 // get the animatable property value
480 value = GetCurrentPropertyValue( *animatableProperty );
484 DALI_LOG_ERROR( "Property index %d not found\n", index );
487 else if(mCustomProperties.Count() > 0)
489 CustomPropertyMetadata* custom = FindCustomProperty( index );
492 // get the custom property value
493 value = GetCurrentPropertyValue( *custom );
497 DALI_LOG_ERROR( "Property index %d not found\n", index );
504 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
509 const TypeInfo* typeInfo( GetTypeInfo() );
512 typeInfo->GetPropertyIndices( indices );
516 if ( mCustomProperties.Count() > 0 )
518 indices.Reserve( indices.Size() + mCustomProperties.Count() );
520 auto iter = mCustomProperties.Begin();
521 const auto endIter = mCustomProperties.End();
523 for ( ; iter != endIter; ++iter, ++i )
525 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
526 if ( custom->childPropertyIndex != Property::INVALID_INDEX )
528 // If it is a child property, add the child property index
529 indices.PushBack( custom->childPropertyIndex );
533 indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
539 Property::Index Object::RegisterProperty(std::string name, Property::Value propertyValue)
541 return RegisterProperty(std::move(name), Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE);
544 Property::Index Object::RegisterProperty(std::string name, Property::Index key, Property::Value propertyValue)
546 return RegisterProperty(std::move(name), key, std::move(propertyValue), Property::ANIMATABLE);
549 void Object::SetProperties( const Property::Map& properties )
551 const auto count = properties.Count();
552 for( auto position = 0u; position < count; ++position )
554 // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
555 // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
557 const auto& key = properties.GetKeyAt( position );
558 const auto propertyIndex = ( key.type == Property::Key::INDEX ) ? key.indexKey : GetPropertyIndex( key );
560 if( propertyIndex != Property::INVALID_INDEX )
562 const auto& value = properties.GetValue( position );
563 SetProperty( propertyIndex, value );
568 void Object::GetProperties( Property::Map& properties )
572 Property::IndexContainer indexContainer;
573 GetPropertyIndices( indexContainer );
575 for( auto index : indexContainer )
577 properties[ index ] = GetProperty( index );
581 Property::Index Object::RegisterProperty(std::string name,
582 Property::Value propertyValue,
583 Property::AccessMode accessMode)
585 return RegisterProperty(std::move(name), Property::INVALID_KEY, std::move(propertyValue), accessMode);
588 Property::Index Object::RegisterProperty(std::string name,
590 Property::Value propertyValue,
591 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, std::move(propertyValue));
610 // Otherwise register the property
611 if( Property::ANIMATABLE == accessMode )
613 index = RegisterSceneGraphProperty(
616 PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
617 std::move(propertyValue));
618 AddUniformMapping(index, std::move(name));
622 // Add entry to the property lookup
623 index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
625 CustomPropertyMetadata* customProperty =
626 new CustomPropertyMetadata(name, std::move(propertyValue), accessMode);
628 // Resolve index for the child property
629 Object* parent = GetParentObject();
632 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
635 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
636 if( childPropertyIndex != Property::INVALID_INDEX )
638 customProperty->childPropertyIndex = childPropertyIndex;
639 index = childPropertyIndex;
644 mCustomProperties.PushBack( customProperty );
651 bool Object::DoesCustomPropertyExist( Property::Index index )
653 auto metadata = FindCustomProperty( index );
654 return metadata != nullptr;
657 Dali::PropertyNotification Object::AddPropertyNotification( Property::Index index,
658 int32_t componentIndex,
659 const Dali::PropertyCondition& condition)
661 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
663 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
665 DALI_ABORT( "Property notification added to event side only property." );
667 else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
669 // check whether the animatable property is registered already, if not then register one.
670 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
671 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
673 else if ( mCustomProperties.Count() > 0 )
675 CustomPropertyMetadata* custom = FindCustomProperty( index );
676 DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
677 DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
681 Dali::Handle self(this);
682 Property target( self, index );
684 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
685 Dali::PropertyNotification propertyNotification(internal.Get());
687 if( !mPropertyNotifications )
689 mPropertyNotifications = new PropertyNotificationContainer;
691 mPropertyNotifications->push_back(propertyNotification);
693 return propertyNotification;
696 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
698 if( mPropertyNotifications )
700 auto iter = mPropertyNotifications->begin();
701 while(iter != mPropertyNotifications->end() )
703 if(*iter == propertyNotification)
705 mPropertyNotifications->erase(iter);
706 // As we can't ensure all references are removed, we can just disable
708 GetImplementation(propertyNotification).Disable();
716 void Object::RemovePropertyNotifications()
718 if( mPropertyNotifications )
720 auto iter = mPropertyNotifications->begin();
721 while(iter != mPropertyNotifications->end() )
723 // As we can't ensure all references are removed, we can just disable
725 GetImplementation(*iter).Disable();
729 mPropertyNotifications->clear();
733 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
735 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
737 OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
741 PropertyMetadata* propertyMetadata = nullptr;
742 if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
744 propertyMetadata = FindAnimatableProperty( index );
748 CustomPropertyMetadata* custom = FindCustomProperty( index );
749 if( custom && custom->IsAnimatable() )
751 propertyMetadata = custom;
755 if( propertyMetadata )
757 switch( animationType )
760 case Animation::BETWEEN:
762 // Update the cached property value
763 propertyMetadata->SetPropertyValue( value );
768 // Adjust the cached property value
769 propertyMetadata->AdjustPropertyValueBy( value );
777 void Object::AddUniformMapping(Property::Index propertyIndex, std::string uniformName) const
779 // Get the address of the property if it's a scene property
780 const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
782 // Check instead for newly registered properties
783 if( propertyPtr == nullptr )
785 PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
788 propertyPtr = animatable->GetSceneGraphProperty();
792 if( propertyPtr == nullptr )
794 PropertyMetadata* custom = FindCustomProperty( propertyIndex );
797 propertyPtr = custom->GetSceneGraphProperty();
803 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
805 OwnerPointer<SceneGraph::UniformPropertyMapping> map =
806 new SceneGraph::UniformPropertyMapping(std::move(uniformName), propertyPtr);
807 // Message takes ownership of Uniform map (and will delete it after copy)
808 AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map );
812 void Object::RemoveUniformMapping( const std::string& uniformName ) const
814 const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
815 RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, uniformName);
818 void Object::ApplyConstraint( ConstraintBase& constraint )
822 mConstraints = new ConstraintContainer;
824 mConstraints->push_back( Dali::Constraint( &constraint ) );
827 void Object::RemoveConstraint( ConstraintBase& constraint )
829 // nullptr if the Constraint sources are destroyed before Constraint::Apply()
832 ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
833 if( it != mConstraints->end() )
835 mConstraints->erase( it );
840 void Object::RemoveConstraints()
842 // guard against constraint sending messages during core destruction
843 if( mConstraints && Stage::IsInstalled() )
845 for ( auto&& item : *mConstraints )
847 GetImplementation( item ).RemoveInternal();
851 mConstraints = nullptr;
855 void Object::RemoveConstraints( uint32_t tag )
857 // guard against constraint sending messages during core destruction
858 if( mConstraints && Stage::IsInstalled() )
860 auto iter( mConstraints->begin() );
861 while(iter != mConstraints->end() )
863 ConstraintBase& constraint = GetImplementation( *iter );
864 if( constraint.GetTag() == tag )
866 GetImplementation( *iter ).RemoveInternal();
867 iter = mConstraints->erase( iter );
875 if ( mConstraints->empty() )
878 mConstraints = nullptr;
883 void Object::SetTypeInfo( const TypeInfo* typeInfo )
885 mTypeInfo = typeInfo;
888 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
892 auto sceneObject = SceneGraph::PropertyOwner::New();
893 OwnerPointer< SceneGraph::PropertyOwner > transferOwnership( sceneObject );
894 mUpdateObject = sceneObject;
895 AddObjectMessage( const_cast<EventThreadServices&>( GetEventThreadServices() ).GetUpdateManager(), transferOwnership );
897 DALI_ASSERT_DEBUG( mUpdateObject && "there must always be a scene object" );
898 return *mUpdateObject;
901 const PropertyBase* Object::GetSceneObjectAnimatableProperty( Property::Index index ) const
903 const SceneGraph::PropertyBase* property = nullptr;
904 if ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX )
906 AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
907 DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
909 property = animatable->GetSceneGraphProperty();
911 else if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && // Child properties are also stored as custom properties
912 ( index <= PROPERTY_CUSTOM_MAX_INDEX ) )
914 CustomPropertyMetadata* custom = FindCustomProperty( index );
915 DALI_ASSERT_ALWAYS( custom && "Property index is invalid" );
917 property = custom->GetSceneGraphProperty();
922 const PropertyInputImpl* Object::GetSceneObjectInputProperty( Property::Index index ) const
924 // reuse animatable version as they are inputs as well
925 return GetSceneObjectAnimatableProperty( index );
928 int32_t Object::GetPropertyComponentIndex( Property::Index index ) const
930 int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
932 if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
934 // check whether the animatable property is registered already, if not then register one.
935 AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
936 if( animatableProperty )
938 componentIndex = animatableProperty->componentIndex;
941 if( Property::INVALID_COMPONENT_INDEX == componentIndex )
943 const TypeInfo* typeInfo( GetTypeInfo() );
946 componentIndex = typeInfo->GetComponentIndex(index);
950 return componentIndex;
953 Handle::PropertySetSignalType& Object::PropertySetSignal()
955 return mPropertySetSignal;
958 Object::Object( const SceneGraph::PropertyOwner* sceneObject )
959 : mEventThreadServices( EventThreadServices::Get() ),
960 mUpdateObject( sceneObject ),
961 mTypeInfo( nullptr ),
962 mConstraints( nullptr ),
963 mPropertyNotifications( nullptr )
969 // Notification for observers
970 for( auto&& item : mObservers )
972 item->ObjectDestroyed( *this );
975 delete mPropertyNotifications;
977 // Guard to allow handle destruction after Core has been destroyed
978 if( Stage::IsInstalled() )
980 if( nullptr != mUpdateObject )
982 RemoveObjectMessage( GetEventThreadServices().GetUpdateManager(), mUpdateObject );
987 void Object::OnSceneObjectAdd()
989 // Notification for observers
990 for( auto&& item : mObservers )
992 item->SceneObjectAdded(*this);
995 // enable property notifications in scene graph
996 EnablePropertyNotifications();
999 void Object::OnSceneObjectRemove()
1001 // Notification for observers
1002 for( auto&& item : mObservers )
1004 item->SceneObjectRemoved(*this);
1007 // disable property notifications in scene graph
1008 DisablePropertyNotifications();
1011 const TypeInfo* Object::GetTypeInfo() const
1015 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1016 // especially as the type-info does not change during the life-time of an application
1018 TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1019 if ( typeInfoHandle )
1021 mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1028 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1030 CustomPropertyMetadata* property = nullptr;
1031 if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1033 for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1035 CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1036 if( custom->childPropertyIndex == index )
1044 int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1045 if( arrayIndex >= 0 )
1047 if( arrayIndex < static_cast<int32_t>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
1049 property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1056 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1058 for( auto&& entry : mAnimatableProperties )
1060 AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( entry );
1061 if( property->index == index )
1069 Property::Index Object::RegisterSceneGraphProperty( const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue ) const
1071 // Create a new property
1072 Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1074 switch ( propertyValue.GetType() )
1076 case Property::BOOLEAN:
1078 newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
1082 case Property::INTEGER:
1084 newProperty = new AnimatableProperty<int32_t>( propertyValue.Get<int32_t>() );
1088 case Property::FLOAT:
1090 newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
1094 case Property::VECTOR2:
1096 newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
1100 case Property::VECTOR3:
1102 newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
1106 case Property::VECTOR4:
1108 newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
1112 case Property::MATRIX:
1114 newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
1118 case Property::MATRIX3:
1120 newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
1124 case Property::ROTATION:
1126 newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
1130 case Property::RECTANGLE:
1131 case Property::STRING:
1132 case Property::ARRAY:
1134 case Property::EXTENTS:
1135 case Property::NONE:
1137 DALI_ASSERT_ALWAYS( !"Property type is not animatable" );
1142 // get the scene property owner
1143 const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1144 // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1145 const PropertyBase* property = newProperty.Get();
1146 if(index >= PROPERTY_CUSTOM_START_INDEX)
1148 DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
1150 mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
1154 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
1157 // queue a message to add the property
1158 InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty ); // Message takes ownership
1163 void Object::RegisterAnimatableProperty( const TypeInfo& typeInfo,
1164 Property::Index index,
1165 const Property::Value* value ) const
1167 // If the property is not a component of a base property, register the whole property itself.
1168 const std::string& propertyName = typeInfo.GetPropertyName( index );
1169 Property::Value initialValue;
1172 initialValue = *value;
1176 initialValue = typeInfo.GetPropertyDefaultValue( index ); // recurses type hierarchy
1177 if( Property::NONE == initialValue.GetType() )
1179 initialValue = Property::Value( typeInfo.GetPropertyType( index ) ); // recurses type hierarchy
1182 RegisterSceneGraphProperty( propertyName, Property::INVALID_KEY, index, initialValue );
1183 AddUniformMapping( index, propertyName );
1186 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty( Property::Index index, const Property::Value* value ) const
1188 // property range already checked by calling methods
1189 // check whether the animatable property is registered already, if not then register one.
1190 AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1191 if( !animatableProperty )
1193 const TypeInfo* typeInfo( GetTypeInfo() );
1196 Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex( index );
1197 if( basePropertyIndex == Property::INVALID_INDEX )
1199 // If the property is not a component of a base property, register the whole property itself.
1200 RegisterAnimatableProperty( *typeInfo, index, value );
1204 // Since the property is a component of a base property, check whether the base property is registered.
1205 animatableProperty = FindAnimatableProperty( basePropertyIndex );
1206 if( !animatableProperty )
1208 // If the base property is not registered yet, register the base property first.
1209 RegisterAnimatableProperty( *typeInfo, basePropertyIndex, value );
1210 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1213 // Create the metadata for the property component.
1214 mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1217 // The metadata has just been added and therefore should be in the end of the vector.
1218 animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1222 return animatableProperty;
1225 void Object::ResolveChildProperties()
1227 // Resolve index for the child property
1228 Object* parent = GetParentObject();
1231 const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1232 if( parentTypeInfo )
1234 // Go through each custom property
1235 for( auto&& entry : mCustomProperties )
1237 CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
1239 if( customProperty->name.empty() )
1241 if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1243 // Resolve name for any child property with no name
1244 customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1249 Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1250 if( childPropertyIndex != Property::INVALID_INDEX )
1252 // Resolve index for any property with a name that matches the parent's child property name
1253 customProperty->childPropertyIndex = childPropertyIndex;
1261 void Object::SetDefaultProperty( Property::Index index, const Property::Value& property )
1266 Property::Value Object::GetDefaultProperty(Property::Index index) const
1268 return Property::Value();
1271 Property::Value Object::GetDefaultPropertyCurrentValue( Property::Index index ) const
1273 return GetDefaultProperty( index );
1276 void Object::EnablePropertyNotifications()
1278 if( mPropertyNotifications )
1280 for( auto&& element : *mPropertyNotifications )
1282 GetImplementation( element ).Enable();
1287 void Object::DisablePropertyNotifications()
1289 if( mPropertyNotifications )
1291 for( auto&& element : *mPropertyNotifications )
1293 GetImplementation( element ).Disable();
1298 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata& entry ) const
1300 Property::Value value;
1302 if( !entry.IsAnimatable() )
1304 value = entry.GetPropertyValue();
1308 BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1310 switch ( entry.GetType() )
1312 case Property::BOOLEAN:
1314 const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1315 DALI_ASSERT_DEBUG( property );
1317 value = (*property)[ bufferIndex ];
1321 case Property::INTEGER:
1323 const AnimatableProperty<int32_t>* property = static_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1324 DALI_ASSERT_DEBUG( property );
1326 value = (*property)[ bufferIndex ];
1330 case Property::FLOAT:
1332 const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1333 DALI_ASSERT_DEBUG( property );
1335 value = (*property)[ bufferIndex ];
1339 case Property::VECTOR2:
1341 const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1342 DALI_ASSERT_DEBUG( property );
1344 if(entry.componentIndex == 0)
1346 value = (*property)[ bufferIndex ].x;
1348 else if(entry.componentIndex == 1)
1350 value = (*property)[ bufferIndex ].y;
1354 value = (*property)[ bufferIndex ];
1359 case Property::VECTOR3:
1361 const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1362 DALI_ASSERT_DEBUG( property );
1364 if(entry.componentIndex == 0)
1366 value = (*property)[ bufferIndex ].x;
1368 else if(entry.componentIndex == 1)
1370 value = (*property)[ bufferIndex ].y;
1372 else if(entry.componentIndex == 2)
1374 value = (*property)[ bufferIndex ].z;
1378 value = (*property)[ bufferIndex ];
1383 case Property::VECTOR4:
1385 const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( 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;
1400 else if(entry.componentIndex == 3)
1402 value = (*property)[ bufferIndex ].w;
1406 value = (*property)[ bufferIndex ];
1411 case Property::MATRIX:
1413 const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1414 DALI_ASSERT_DEBUG( property );
1416 value = (*property)[ bufferIndex ];
1420 case Property::MATRIX3:
1422 const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1423 DALI_ASSERT_DEBUG( property );
1425 value = (*property)[ bufferIndex ];
1429 case Property::ROTATION:
1431 const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1432 DALI_ASSERT_DEBUG( property );
1434 value = (*property)[ bufferIndex ];
1440 // unreachable code due to higher level logic
1448 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1450 switch ( entry.GetType() )
1452 case Property::BOOLEAN:
1454 const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1455 DALI_ASSERT_DEBUG( property );
1457 // property is being used in a separate thread; queue a message to set the property
1458 BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1462 case Property::INTEGER:
1464 const AnimatableProperty<int32_t>* property = dynamic_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1465 DALI_ASSERT_DEBUG( property );
1467 // property is being used in a separate thread; queue a message to set the property
1468 BakeMessage<int32_t>( GetEventThreadServices(), *property, value.Get<int32_t>() );
1472 case Property::FLOAT:
1474 const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1475 DALI_ASSERT_DEBUG( property );
1477 // property is being used in a separate thread; queue a message to set the property
1478 BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1482 case Property::VECTOR2:
1484 const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1485 DALI_ASSERT_DEBUG( property );
1487 // property is being used in a separate thread; queue a message to set the property
1488 if(entry.componentIndex == 0)
1490 SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1492 else if(entry.componentIndex == 1)
1494 SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1498 BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1503 case Property::VECTOR3:
1505 const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1506 DALI_ASSERT_DEBUG( property );
1508 // property is being used in a separate thread; queue a message to set the property
1509 if(entry.componentIndex == 0)
1511 SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1513 else if(entry.componentIndex == 1)
1515 SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1517 else if(entry.componentIndex == 2)
1519 SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1523 BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1529 case Property::VECTOR4:
1531 const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1532 DALI_ASSERT_DEBUG( property );
1534 // property is being used in a separate thread; queue a message to set the property
1535 if(entry.componentIndex == 0)
1537 SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1539 else if(entry.componentIndex == 1)
1541 SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1543 else if(entry.componentIndex == 2)
1545 SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1547 else if(entry.componentIndex == 3)
1549 SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1553 BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1558 case Property::ROTATION:
1560 const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1561 DALI_ASSERT_DEBUG( property );
1563 // property is being used in a separate thread; queue a message to set the property
1564 BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1568 case Property::MATRIX:
1570 const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1571 DALI_ASSERT_DEBUG( property );
1573 // property is being used in a separate thread; queue a message to set the property
1574 BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1578 case Property::MATRIX3:
1580 const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1581 DALI_ASSERT_DEBUG( property );
1583 // property is being used in a separate thread; queue a message to set the property
1584 BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1590 // non-animatable scene graph property, do nothing
1595 } // namespace Internal