2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include <dali/internal/event/common/proxy-object.h>
24 #include <dali/public-api/object/property-index.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/event/common/stage-impl.h>
27 #include <dali/internal/update/common/animatable-property.h>
28 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
29 #include <dali/internal/update/common/property-owner-messages.h>
30 #include <dali/internal/event/animation/active-constraint-base.h>
31 #include <dali/internal/event/animation/constraint-impl.h>
32 #include <dali/internal/event/common/property-notification-impl.h>
33 #include <dali/internal/event/common/property-index-ranges.h>
34 #include <dali/internal/event/common/type-registry-impl.h>
36 using Dali::Internal::SceneGraph::AnimatableProperty;
37 using Dali::Internal::SceneGraph::PropertyBase;
45 namespace // unnamed namespace
47 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // ProxyObject provides this capability
48 typedef Dali::Vector<ProxyObject::Observer*>::Iterator ObserverIter;
49 typedef Dali::Vector<ProxyObject::Observer*>::ConstIterator ConstObserverIter;
51 static std::string EMPTY_PROPERTY_NAME;
53 #if defined(DEBUG_ENABLED)
54 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_PROXY_OBJECT" );
56 } // unnamed namespace
58 const int INVALID_PROPERTY_COMPONENT_INDEX = -1;
60 ProxyObject::ProxyObject()
62 mNextCustomPropertyIndex( 0u ),
63 mCustomProperties( NULL ),
65 mRemovedConstraints( NULL ),
66 mPropertyNotifications( NULL )
70 void ProxyObject::AddObserver(Observer& observer)
72 // make sure an observer doesn't observe the same object twice
73 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ProxyDestroyed()
74 DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
76 mObservers.PushBack( &observer );
79 void ProxyObject::RemoveObserver(Observer& observer)
81 // Find the observer...
82 const ConstObserverIter endIter = mObservers.End();
83 for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
85 if( (*iter) == &observer)
87 mObservers.Erase( iter );
91 DALI_ASSERT_DEBUG(endIter != mObservers.End());
94 void ProxyObject::OnSceneObjectAdd()
96 // Notification for observers
97 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
99 (*iter)->SceneObjectAdded(*this);
102 // enable property notifications in scene graph
103 EnablePropertyNotifications();
106 void ProxyObject::OnSceneObjectRemove()
108 // Notification for observers
109 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
111 (*iter)->SceneObjectRemoved(*this);
114 // disable property notifications in scene graph
115 DisablePropertyNotifications();
118 int ProxyObject::GetPropertyComponentIndex( Property::Index index ) const
120 return INVALID_PROPERTY_COMPONENT_INDEX;
123 bool ProxyObject::Supports( Capability capability ) const
125 return (capability & SUPPORTED_CAPABILITIES);
128 unsigned int ProxyObject::GetPropertyCount() const
130 unsigned int count = GetDefaultPropertyCount();
132 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
134 TypeInfo* typeInfo( GetTypeInfo() );
137 unsigned int manual( typeInfo->GetPropertyCount() );
140 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties: %d\n", manual );
143 if( mCustomProperties )
145 unsigned int custom( mCustomProperties->size() );
148 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
151 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
156 const std::string& ProxyObject::GetPropertyName( Property::Index index ) const
158 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
160 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
162 return GetDefaultPropertyName( index );
165 if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
167 TypeInfo* typeInfo( GetTypeInfo() );
170 return typeInfo->GetPropertyName( index );
174 DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
178 if( mCustomProperties )
180 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
181 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Property index is invalid" );
183 return entry->second.name;
185 return EMPTY_PROPERTY_NAME;
188 Property::Index ProxyObject::GetPropertyIndex(const std::string& name) const
190 Property::Index index = Property::INVALID_INDEX;
192 index = GetDefaultPropertyIndex( name );
194 if ( index == Property::INVALID_INDEX )
196 TypeInfo* typeInfo( GetTypeInfo() );
199 index = typeInfo->GetPropertyIndex( name );
203 if( index == Property::INVALID_INDEX && mCustomProperties )
205 // This is slow, but we're not (supposed to be) using property names frequently
206 for ( CustomPropertyLookup::const_iterator iter = mCustomProperties->begin(); mCustomProperties->end() != iter; ++iter )
208 if (iter->second.name == name)
219 bool ProxyObject::IsPropertyWritable( Property::Index index ) const
221 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
223 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
225 return IsDefaultPropertyWritable( index );
228 if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
230 TypeInfo* typeInfo( GetTypeInfo() );
233 return typeInfo->IsPropertyWritable( index );
237 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
241 if( mCustomProperties)
243 // Check that the index is valid
244 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
245 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
247 return entry->second.IsWritable();
252 bool ProxyObject::IsPropertyAnimatable( Property::Index index ) const
254 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
256 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
258 return IsDefaultPropertyAnimatable( index );
261 if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
263 // Type Registry event-thread only properties are not animatable.
267 if( mCustomProperties )
269 // Check custom property
270 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
271 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
273 return entry->second.IsAnimatable();
278 Property::Type ProxyObject::GetPropertyType( Property::Index index ) const
280 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
282 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
284 return GetDefaultPropertyType( index );
287 if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
289 TypeInfo* typeInfo( GetTypeInfo() );
292 return typeInfo->GetPropertyType( index );
296 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
300 if( mCustomProperties )
302 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
303 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find Property index" );
305 return entry->second.type;
307 return Property::NONE;
310 void ProxyObject::SetProperty( Property::Index index, const Property::Value& propertyValue )
312 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
314 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
316 DALI_ASSERT_ALWAYS( IsDefaultPropertyWritable(index) && "Property is read-only" );
318 SetDefaultProperty( index, propertyValue );
320 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
322 TypeInfo* typeInfo( GetTypeInfo() );
325 typeInfo->SetProperty( this, index, propertyValue );
329 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
332 else if( mCustomProperties )
334 CustomPropertyLookup::iterator entry = mCustomProperties->find( index );
335 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
336 DALI_ASSERT_ALWAYS( entry->second.IsWritable() && "Property is read-only" );
338 // this is only relevant for non animatable properties
339 if(entry->second.IsWritable())
341 entry->second.value = propertyValue;
344 SetCustomProperty(index, entry->second, propertyValue);
348 Property::Value ProxyObject::GetProperty(Property::Index index) const
350 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
352 Property::Value value;
354 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
356 value = GetDefaultProperty( index );
358 else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
360 TypeInfo* typeInfo( GetTypeInfo() );
363 value = typeInfo->GetProperty( this, index );
367 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
370 else if( mCustomProperties )
372 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
373 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
375 if( !entry->second.IsAnimatable() )
377 value = entry->second.value;
381 BufferIndex bufferIndex( Stage::GetCurrent()->GetEventBufferIndex() );
383 switch ( entry->second.type )
385 case Property::BOOLEAN:
387 AnimatableProperty<bool>* property = dynamic_cast< AnimatableProperty<bool>* >( entry->second.GetSceneGraphProperty() );
388 DALI_ASSERT_DEBUG( NULL != property );
390 value = (*property)[ bufferIndex ];
394 case Property::FLOAT:
396 AnimatableProperty<float>* property = dynamic_cast< AnimatableProperty<float>* >( entry->second.GetSceneGraphProperty() );
397 DALI_ASSERT_DEBUG( NULL != property );
399 value = (*property)[ bufferIndex ];
403 case Property::VECTOR2:
405 AnimatableProperty<Vector2>* property = dynamic_cast< AnimatableProperty<Vector2>* >( entry->second.GetSceneGraphProperty() );
406 DALI_ASSERT_DEBUG( NULL != property );
408 value = (*property)[ bufferIndex ];
412 case Property::VECTOR3:
414 AnimatableProperty<Vector3>* property = dynamic_cast< AnimatableProperty<Vector3>* >( entry->second.GetSceneGraphProperty() );
415 DALI_ASSERT_DEBUG( NULL != property );
417 value = (*property)[ bufferIndex ];
421 case Property::VECTOR4:
423 AnimatableProperty<Vector4>* property = dynamic_cast< AnimatableProperty<Vector4>* >( entry->second.GetSceneGraphProperty() );
424 DALI_ASSERT_DEBUG( NULL != property );
426 value = (*property)[ bufferIndex ];
430 case Property::MATRIX:
432 AnimatableProperty<Matrix>* property = dynamic_cast< AnimatableProperty<Matrix>* >( entry->second.GetSceneGraphProperty() );
433 DALI_ASSERT_DEBUG( NULL != property );
435 value = (*property)[ bufferIndex ];
439 case Property::MATRIX3:
441 AnimatableProperty<Matrix3>* property = dynamic_cast< AnimatableProperty<Matrix3>* >( entry->second.GetSceneGraphProperty() );
442 DALI_ASSERT_DEBUG( NULL != property );
444 value = (*property)[ bufferIndex ];
448 case Property::ROTATION:
450 AnimatableProperty<Quaternion>* property = dynamic_cast< AnimatableProperty<Quaternion>* >( entry->second.GetSceneGraphProperty() );
451 DALI_ASSERT_DEBUG( NULL != property );
453 value = (*property)[ bufferIndex ];
459 DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
470 void ProxyObject::GetPropertyIndices( Property::IndexContainer& indices ) const
474 // Default Properties
475 GetDefaultPropertyIndices( indices );
478 TypeInfo* typeInfo( GetTypeInfo() );
481 typeInfo->GetPropertyIndices( indices );
485 if ( mCustomProperties )
487 indices.reserve( indices.size() + mCustomProperties->size() );
489 const CustomPropertyLookup::const_iterator endIter = mCustomProperties->end();
490 for ( CustomPropertyLookup::const_iterator iter = mCustomProperties->begin(); iter != endIter; ++iter )
492 indices.push_back( iter->first );
497 Property::Index ProxyObject::RegisterProperty( std::string name, const Property::Value& propertyValue)
499 // Assert that property name is unused
500 DALI_ASSERT_ALWAYS( Property::INVALID_INDEX == GetPropertyIndex(name) && "Property index is out of bounds" );
502 // Create a new property
503 std::auto_ptr<PropertyBase> newProperty;
505 switch ( propertyValue.GetType() )
507 case Property::BOOLEAN:
509 newProperty.reset(new AnimatableProperty<bool>( propertyValue.Get<bool>()));
513 case Property::FLOAT:
515 newProperty.reset(new AnimatableProperty<float>( propertyValue.Get<float>()));
519 case Property::VECTOR2:
521 newProperty.reset(new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>()));
525 case Property::VECTOR3:
527 newProperty.reset(new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>()));
531 case Property::VECTOR4:
533 newProperty.reset(new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>()));
537 case Property::MATRIX:
539 newProperty.reset(new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>()));
543 case Property::MATRIX3:
545 newProperty.reset(new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>()));
549 case Property::ROTATION:
551 newProperty.reset(new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>()));
557 DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
558 DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
563 // Default properties start from index zero
564 if ( 0u == mNextCustomPropertyIndex )
566 mNextCustomPropertyIndex = CUSTOM_PROPERTY_START;
569 // Add entry to the property lookup
570 const Property::Index index = mNextCustomPropertyIndex++;
572 CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
573 DALI_ASSERT_ALWAYS( mCustomProperties->end() == entry && "Custom property already registered" );
575 (*mCustomProperties)[ index ] = CustomProperty( name, propertyValue.GetType(), newProperty.get() );
577 // The derived class now passes ownership of this new property to a scene-object
578 InstallSceneObjectProperty( *(newProperty.release()), name, index );
583 Property::Index ProxyObject::RegisterProperty( std::string name, const Property::Value& propertyValue, Property::AccessMode accessMode)
585 Property::Index index = Property::INVALID_INDEX;
587 if(Property::ANIMATABLE == accessMode)
589 index = RegisterProperty(name, propertyValue);
593 // Default properties start from index zero
594 if ( 0u == mNextCustomPropertyIndex )
596 mNextCustomPropertyIndex = CUSTOM_PROPERTY_START;
599 // Add entry to the property lookup
600 index = mNextCustomPropertyIndex++;
601 GetCustomPropertyLookup()[ index ] = CustomProperty( name, propertyValue, accessMode );
607 Dali::PropertyNotification ProxyObject::AddPropertyNotification(Property::Index index,
609 const Dali::PropertyCondition& condition)
611 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
613 if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
615 DALI_ASSERT_ALWAYS( false && "Property notification added to non animatable property." );
617 else if ( mCustomProperties )
619 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
620 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
622 DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "Property notification added to non animatable property (currently not suppported )");
626 Dali::Handle self(this);
627 Property target( self, index );
629 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
630 Dali::PropertyNotification propertyNotification(internal.Get());
632 if( !mPropertyNotifications )
634 mPropertyNotifications = new PropertyNotificationContainer;
636 mPropertyNotifications->push_back(propertyNotification);
638 return propertyNotification;
641 void ProxyObject::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
643 if( mPropertyNotifications )
645 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
646 while(iter != mPropertyNotifications->end() )
648 if(*iter == propertyNotification)
650 mPropertyNotifications->erase(iter);
651 // As we can't ensure all references are removed, we can just disable
653 GetImplementation(propertyNotification).Disable();
661 void ProxyObject::RemovePropertyNotifications()
663 if( mPropertyNotifications )
665 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
666 while(iter != mPropertyNotifications->end() )
668 // As we can't ensure all references are removed, we can just disable
670 GetImplementation(*iter).Disable();
674 mPropertyNotifications->clear();
678 void ProxyObject::EnablePropertyNotifications()
680 if( mPropertyNotifications )
682 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
683 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
685 for( ; iter != endIter; ++iter )
687 GetImplementation(*iter).Enable();
692 void ProxyObject::DisablePropertyNotifications()
694 if( mPropertyNotifications )
696 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
697 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
699 for( ; iter != endIter; ++iter )
701 GetImplementation(*iter).Disable();
706 Dali::ActiveConstraint ProxyObject::ApplyConstraint( Constraint& constraint )
708 return Dali::ActiveConstraint(DoApplyConstraint( constraint, NULL/*callback is optional*/ ));
711 Dali::ActiveConstraint ProxyObject::ApplyConstraint( Constraint& constraint, ActiveConstraintCallbackType callback )
713 return Dali::ActiveConstraint(DoApplyConstraint( constraint, &callback ));
716 ActiveConstraintBase* ProxyObject::DoApplyConstraint( Constraint& constraint, ActiveConstraintCallbackType* callback )
718 ActiveConstraintBase* activeConstraintImpl = constraint.CreateActiveConstraint();
719 DALI_ASSERT_DEBUG( NULL != activeConstraintImpl );
721 Dali::ActiveConstraint activeConstraint( activeConstraintImpl );
725 mConstraints = new ActiveConstraintContainer;
727 mConstraints->push_back( activeConstraint );
729 activeConstraintImpl->FirstApply( *this, constraint.GetApplyTime(), callback );
731 return activeConstraintImpl;
734 void ProxyObject::DeleteRemovedConstraints()
736 if( ! mRemovedConstraints )
741 // Discard constraints which are fully removed
742 for ( ActiveConstraintIter iter = mRemovedConstraints->begin(); mRemovedConstraints->end() != iter ;)
744 if ( !( GetImplementation( *iter ).IsRemoving() ) )
746 iter = mRemovedConstraints->erase( iter );
755 CustomPropertyLookup& ProxyObject::GetCustomPropertyLookup() const
758 if( !mCustomProperties )
760 mCustomProperties = new CustomPropertyLookup;
762 return *mCustomProperties;
765 TypeInfo* ProxyObject::GetTypeInfo() const
769 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
770 // especially as the type-info does not change during the life-time of an application
772 Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
773 if ( typeInfoHandle )
775 mTypeInfo = &GetImplementation( typeInfoHandle );
782 void ProxyObject::RemoveConstraint( Dali::ActiveConstraint activeConstraint )
786 // If we have nothing in the scene-graph, just remove the activeConstraint from container
787 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
788 if ( NULL == propertyOwner )
790 ActiveConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), activeConstraint ) );
791 if( it != mConstraints->end() )
793 mConstraints->erase( it );
795 delete mRemovedConstraints;
796 mRemovedConstraints = NULL;
800 // Discard constraints which are fully removed
801 DeleteRemovedConstraints();
803 ActiveConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), activeConstraint ) );
804 if( it != mConstraints->end() )
806 ActiveConstraintBase& constraint = GetImplementation( *it );
808 constraint.BeginRemove();
809 mConstraints->erase( it );
811 if ( constraint.IsRemoving() )
813 if( !mRemovedConstraints )
815 mRemovedConstraints = new ActiveConstraintContainer;
817 // Wait for remove animation before destroying active-constraints
818 mRemovedConstraints->push_back( *it );
824 void ProxyObject::RemoveConstraints()
828 // If we have nothing in the scene-graph, just clear constraint containers
829 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
830 if ( NULL == propertyOwner )
834 delete mRemovedConstraints;
835 mRemovedConstraints = NULL;
839 // Discard constraints which are fully removed
840 DeleteRemovedConstraints();
842 const ActiveConstraintConstIter endIter = mConstraints->end();
843 for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
845 ActiveConstraintBase& constraint = GetImplementation( *iter );
847 constraint.BeginRemove();
849 if ( constraint.IsRemoving() )
851 if( !mRemovedConstraints )
853 mRemovedConstraints = new ActiveConstraintContainer;
855 // Wait for remove animation before destroying active-constraints
856 mRemovedConstraints->push_back( *iter );
865 ProxyObject::~ProxyObject()
867 // Notification for observers
868 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
870 (*iter)->ProxyDestroyed(*this);
873 delete mCustomProperties;
875 delete mRemovedConstraints;
876 delete mPropertyNotifications;
879 } // namespace Internal