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/integration-api/debug.h>
25 #include <dali/internal/event/common/stage-impl.h>
26 #include <dali/internal/update/common/animatable-property.h>
27 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
28 #include <dali/internal/update/common/property-owner-messages.h>
29 #include <dali/internal/event/animation/active-constraint-base.h>
30 #include <dali/internal/event/animation/constraint-impl.h>
31 #include <dali/internal/event/common/property-notification-impl.h>
32 #include <dali/internal/event/common/property-index-ranges.h>
33 #include <dali/internal/event/common/type-registry-impl.h>
35 using Dali::Internal::SceneGraph::AnimatableProperty;
36 using Dali::Internal::SceneGraph::PropertyBase;
44 namespace // unnamed namespace
46 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES; // ProxyObject provides this capability
47 typedef Dali::Vector<ProxyObject::Observer*>::Iterator ObserverIter;
48 typedef Dali::Vector<ProxyObject::Observer*>::ConstIterator ConstObserverIter;
50 static std::string EMPTY_PROPERTY_NAME;
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_PROXY_OBJECT" );
55 } // unnamed namespace
57 const int INVALID_PROPERTY_COMPONENT_INDEX = -1;
59 ProxyObject::ProxyObject()
61 mNextCustomPropertyIndex( 0u ),
62 mCustomProperties( NULL ),
64 mRemovedConstraints( NULL ),
65 mPropertyNotifications( NULL )
69 void ProxyObject::AddObserver(Observer& observer)
71 // make sure an observer doesn't observe the same object twice
72 // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ProxyDestroyed()
73 DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
75 mObservers.PushBack( &observer );
78 void ProxyObject::RemoveObserver(Observer& observer)
80 // Find the observer...
81 const ConstObserverIter endIter = mObservers.End();
82 for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
84 if( (*iter) == &observer)
86 mObservers.Erase( iter );
90 DALI_ASSERT_DEBUG(endIter != mObservers.End());
93 void ProxyObject::OnSceneObjectAdd()
95 // Notification for observers
96 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
98 (*iter)->SceneObjectAdded(*this);
101 // enable property notifications in scene graph
102 EnablePropertyNotifications();
105 void ProxyObject::OnSceneObjectRemove()
107 // Notification for observers
108 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
110 (*iter)->SceneObjectRemoved(*this);
113 // disable property notifications in scene graph
114 DisablePropertyNotifications();
117 int ProxyObject::GetPropertyComponentIndex( Property::Index index ) const
119 return INVALID_PROPERTY_COMPONENT_INDEX;
122 bool ProxyObject::Supports( Capability capability ) const
124 return (capability & SUPPORTED_CAPABILITIES);
127 unsigned int ProxyObject::GetPropertyCount() const
129 unsigned int count = GetDefaultPropertyCount();
131 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
133 TypeInfo* typeInfo( GetTypeInfo() );
136 unsigned int manual( typeInfo->GetPropertyCount() );
139 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties: %d\n", manual );
142 if( mCustomProperties )
144 unsigned int custom( mCustomProperties->size() );
147 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties: %d\n", custom );
150 DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties: %d\n", count );
155 const std::string& ProxyObject::GetPropertyName( Property::Index index ) const
157 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
159 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
161 return GetDefaultPropertyName( index );
164 if ( ( index >= PropertyRegistration::START_INDEX ) && ( index <= PropertyRegistration::MAX_INDEX ) )
166 TypeInfo* typeInfo( GetTypeInfo() );
169 return typeInfo->GetPropertyName( index );
173 DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
177 if( mCustomProperties )
179 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
180 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Property index is invalid" );
182 return entry->second.name;
184 return EMPTY_PROPERTY_NAME;
187 Property::Index ProxyObject::GetPropertyIndex(const std::string& name) const
189 Property::Index index = Property::INVALID_INDEX;
191 index = GetDefaultPropertyIndex( name );
193 if ( index == Property::INVALID_INDEX )
195 TypeInfo* typeInfo( GetTypeInfo() );
198 index = typeInfo->GetPropertyIndex( name );
202 if( index == Property::INVALID_INDEX && mCustomProperties )
204 // This is slow, but we're not (supposed to be) using property names frequently
205 for ( CustomPropertyLookup::const_iterator iter = mCustomProperties->begin(); mCustomProperties->end() != iter; ++iter )
207 if (iter->second.name == name)
218 bool ProxyObject::IsPropertyWritable( Property::Index index ) const
220 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
222 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
224 return IsDefaultPropertyWritable( index );
227 if ( ( index >= PropertyRegistration::START_INDEX ) && ( index <= PropertyRegistration::MAX_INDEX ) )
229 TypeInfo* typeInfo( GetTypeInfo() );
232 return typeInfo->IsPropertyWritable( index );
236 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
240 if( mCustomProperties)
242 // Check that the index is valid
243 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
244 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
246 return entry->second.IsWritable();
251 bool ProxyObject::IsPropertyAnimatable( Property::Index index ) const
253 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
255 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
257 return IsDefaultPropertyAnimatable( index );
260 if ( ( index >= PropertyRegistration::START_INDEX ) && ( index <= PropertyRegistration::MAX_INDEX ) )
262 // Type Registry event-thread only properties are not animatable.
266 if( mCustomProperties )
268 // Check custom property
269 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
270 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
272 return entry->second.IsAnimatable();
277 Property::Type ProxyObject::GetPropertyType( Property::Index index ) const
279 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
281 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
283 return GetDefaultPropertyType( index );
286 if ( ( index >= PropertyRegistration::START_INDEX ) && ( index <= PropertyRegistration::MAX_INDEX ) )
288 TypeInfo* typeInfo( GetTypeInfo() );
291 return typeInfo->GetPropertyType( index );
295 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
299 if( mCustomProperties )
301 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
302 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find Property index" );
304 return entry->second.type;
306 return Property::NONE;
309 void ProxyObject::SetProperty( Property::Index index, const Property::Value& propertyValue )
311 DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
313 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
315 DALI_ASSERT_ALWAYS( IsDefaultPropertyWritable(index) && "Property is read-only" );
317 SetDefaultProperty( index, propertyValue );
319 else if ( ( index >= PropertyRegistration::START_INDEX ) && ( index <= PropertyRegistration::MAX_INDEX ) )
321 TypeInfo* typeInfo( GetTypeInfo() );
324 typeInfo->SetProperty( this, index, propertyValue );
328 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
331 else if( mCustomProperties )
333 CustomPropertyLookup::iterator entry = mCustomProperties->find( index );
334 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
335 DALI_ASSERT_ALWAYS( entry->second.IsWritable() && "Property is read-only" );
337 // this is only relevant for non animatable properties
338 if(entry->second.IsWritable())
340 entry->second.value = propertyValue;
343 SetCustomProperty(index, entry->second, propertyValue);
347 Property::Value ProxyObject::GetProperty(Property::Index index) const
349 DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
351 Property::Value value;
353 if ( index < DEFAULT_PROPERTY_MAX_COUNT )
355 value = GetDefaultProperty( index );
357 else if ( ( index >= PropertyRegistration::START_INDEX ) && ( index <= PropertyRegistration::MAX_INDEX ) )
359 TypeInfo* typeInfo( GetTypeInfo() );
362 value = typeInfo->GetProperty( this, index );
366 DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
369 else if( mCustomProperties )
371 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
372 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
374 if( !entry->second.IsAnimatable() )
376 value = entry->second.value;
380 BufferIndex bufferIndex( Stage::GetCurrent()->GetEventBufferIndex() );
382 switch ( entry->second.type )
384 case Property::BOOLEAN:
386 AnimatableProperty<bool>* property = dynamic_cast< AnimatableProperty<bool>* >( entry->second.GetSceneGraphProperty() );
387 DALI_ASSERT_DEBUG( NULL != property );
389 value = (*property)[ bufferIndex ];
393 case Property::FLOAT:
395 AnimatableProperty<float>* property = dynamic_cast< AnimatableProperty<float>* >( entry->second.GetSceneGraphProperty() );
396 DALI_ASSERT_DEBUG( NULL != property );
398 value = (*property)[ bufferIndex ];
402 case Property::VECTOR2:
404 AnimatableProperty<Vector2>* property = dynamic_cast< AnimatableProperty<Vector2>* >( entry->second.GetSceneGraphProperty() );
405 DALI_ASSERT_DEBUG( NULL != property );
407 value = (*property)[ bufferIndex ];
411 case Property::VECTOR3:
413 AnimatableProperty<Vector3>* property = dynamic_cast< AnimatableProperty<Vector3>* >( entry->second.GetSceneGraphProperty() );
414 DALI_ASSERT_DEBUG( NULL != property );
416 value = (*property)[ bufferIndex ];
420 case Property::VECTOR4:
422 AnimatableProperty<Vector4>* property = dynamic_cast< AnimatableProperty<Vector4>* >( entry->second.GetSceneGraphProperty() );
423 DALI_ASSERT_DEBUG( NULL != property );
425 value = (*property)[ bufferIndex ];
429 case Property::MATRIX:
431 AnimatableProperty<Matrix>* property = dynamic_cast< AnimatableProperty<Matrix>* >( entry->second.GetSceneGraphProperty() );
432 DALI_ASSERT_DEBUG( NULL != property );
434 value = (*property)[ bufferIndex ];
438 case Property::MATRIX3:
440 AnimatableProperty<Matrix3>* property = dynamic_cast< AnimatableProperty<Matrix3>* >( entry->second.GetSceneGraphProperty() );
441 DALI_ASSERT_DEBUG( NULL != property );
443 value = (*property)[ bufferIndex ];
447 case Property::ROTATION:
449 AnimatableProperty<Quaternion>* property = dynamic_cast< AnimatableProperty<Quaternion>* >( entry->second.GetSceneGraphProperty() );
450 DALI_ASSERT_DEBUG( NULL != property );
452 value = (*property)[ bufferIndex ];
458 DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
469 void ProxyObject::GetPropertyIndices( Property::IndexContainer& indices ) const
473 // Default Properties
474 GetDefaultPropertyIndices( indices );
477 TypeInfo* typeInfo( GetTypeInfo() );
480 typeInfo->GetPropertyIndices( indices );
484 if ( mCustomProperties )
486 indices.reserve( indices.size() + mCustomProperties->size() );
488 const CustomPropertyLookup::const_iterator endIter = mCustomProperties->end();
489 for ( CustomPropertyLookup::const_iterator iter = mCustomProperties->begin(); iter != endIter; ++iter )
491 indices.push_back( iter->first );
496 Property::Index ProxyObject::RegisterProperty( std::string name, const Property::Value& propertyValue)
498 // Assert that property name is unused
499 DALI_ASSERT_ALWAYS( Property::INVALID_INDEX == GetPropertyIndex(name) && "Property index is out of bounds" );
501 // Create a new property
502 std::auto_ptr<PropertyBase> newProperty;
504 switch ( propertyValue.GetType() )
506 case Property::BOOLEAN:
508 newProperty.reset(new AnimatableProperty<bool>( propertyValue.Get<bool>()));
512 case Property::FLOAT:
514 newProperty.reset(new AnimatableProperty<float>( propertyValue.Get<float>()));
518 case Property::VECTOR2:
520 newProperty.reset(new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>()));
524 case Property::VECTOR3:
526 newProperty.reset(new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>()));
530 case Property::VECTOR4:
532 newProperty.reset(new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>()));
536 case Property::MATRIX:
538 newProperty.reset(new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>()));
542 case Property::MATRIX3:
544 newProperty.reset(new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>()));
548 case Property::ROTATION:
550 newProperty.reset(new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>()));
556 DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
557 DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
562 // Default properties start from index zero
563 if ( 0u == mNextCustomPropertyIndex )
565 mNextCustomPropertyIndex = CUSTOM_PROPERTY_START;
568 // Add entry to the property lookup
569 const Property::Index index = mNextCustomPropertyIndex++;
571 CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
572 DALI_ASSERT_ALWAYS( mCustomProperties->end() == entry && "Custom property already registered" );
574 (*mCustomProperties)[ index ] = CustomProperty( name, propertyValue.GetType(), newProperty.get() );
576 // The derived class now passes ownership of this new property to a scene-object
577 InstallSceneObjectProperty( *(newProperty.release()), name, index );
582 Property::Index ProxyObject::RegisterProperty( std::string name, const Property::Value& propertyValue, Property::AccessMode accessMode)
584 Property::Index index = Property::INVALID_INDEX;
586 if(Property::ANIMATABLE == accessMode)
588 index = RegisterProperty(name, propertyValue);
592 // Default properties start from index zero
593 if ( 0u == mNextCustomPropertyIndex )
595 mNextCustomPropertyIndex = CUSTOM_PROPERTY_START;
598 // Add entry to the property lookup
599 index = mNextCustomPropertyIndex++;
600 GetCustomPropertyLookup()[ index ] = CustomProperty( name, propertyValue, accessMode );
606 Dali::PropertyNotification ProxyObject::AddPropertyNotification(Property::Index index,
608 const Dali::PropertyCondition& condition)
610 if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
612 if ( index <= PropertyRegistration::MAX_INDEX )
614 DALI_ASSERT_ALWAYS( false && "Property notification added to non animatable property." );
616 else if ( mCustomProperties )
618 CustomPropertyLookup::const_iterator entry = mCustomProperties->find( index );
619 DALI_ASSERT_ALWAYS( mCustomProperties->end() != entry && "Cannot find property index" );
621 DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "Property notification added to non animatable property (currently not suppported )");
625 Dali::Handle self(this);
626 Property target( self, index );
628 PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
629 Dali::PropertyNotification propertyNotification(internal.Get());
631 if( !mPropertyNotifications )
633 mPropertyNotifications = new PropertyNotificationContainer;
635 mPropertyNotifications->push_back(propertyNotification);
637 return propertyNotification;
640 void ProxyObject::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
642 if( mPropertyNotifications )
644 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
645 while(iter != mPropertyNotifications->end() )
647 if(*iter == propertyNotification)
649 mPropertyNotifications->erase(iter);
650 // As we can't ensure all references are removed, we can just disable
652 GetImplementation(propertyNotification).Disable();
660 void ProxyObject::RemovePropertyNotifications()
662 if( mPropertyNotifications )
664 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
665 while(iter != mPropertyNotifications->end() )
667 // As we can't ensure all references are removed, we can just disable
669 GetImplementation(*iter).Disable();
673 mPropertyNotifications->clear();
677 void ProxyObject::EnablePropertyNotifications()
679 if( mPropertyNotifications )
681 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
682 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
684 for( ; iter != endIter; ++iter )
686 GetImplementation(*iter).Enable();
691 void ProxyObject::DisablePropertyNotifications()
693 if( mPropertyNotifications )
695 PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
696 PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
698 for( ; iter != endIter; ++iter )
700 GetImplementation(*iter).Disable();
705 Dali::ActiveConstraint ProxyObject::ApplyConstraint( Constraint& constraint )
707 return Dali::ActiveConstraint(DoApplyConstraint( constraint, NULL/*callback is optional*/ ));
710 Dali::ActiveConstraint ProxyObject::ApplyConstraint( Constraint& constraint, ActiveConstraintCallbackType callback )
712 return Dali::ActiveConstraint(DoApplyConstraint( constraint, &callback ));
715 ActiveConstraintBase* ProxyObject::DoApplyConstraint( Constraint& constraint, ActiveConstraintCallbackType* callback )
717 ActiveConstraintBase* activeConstraintImpl = constraint.CreateActiveConstraint();
718 DALI_ASSERT_DEBUG( NULL != activeConstraintImpl );
720 Dali::ActiveConstraint activeConstraint( activeConstraintImpl );
724 mConstraints = new ActiveConstraintContainer;
726 mConstraints->push_back( activeConstraint );
728 activeConstraintImpl->FirstApply( *this, constraint.GetApplyTime(), callback );
730 return activeConstraintImpl;
733 void ProxyObject::DeleteRemovedConstraints()
735 if( ! mRemovedConstraints )
740 // Discard constraints which are fully removed
741 for ( ActiveConstraintIter iter = mRemovedConstraints->begin(); mRemovedConstraints->end() != iter ;)
743 if ( !( GetImplementation( *iter ).IsRemoving() ) )
745 iter = mRemovedConstraints->erase( iter );
754 CustomPropertyLookup& ProxyObject::GetCustomPropertyLookup() const
757 if( !mCustomProperties )
759 mCustomProperties = new CustomPropertyLookup;
761 return *mCustomProperties;
764 TypeInfo* ProxyObject::GetTypeInfo() const
768 // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
769 // especially as the type-info does not change during the life-time of an application
771 Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
772 if ( typeInfoHandle )
774 mTypeInfo = &GetImplementation( typeInfoHandle );
781 void ProxyObject::RemoveConstraint( Dali::ActiveConstraint activeConstraint )
785 // If we have nothing in the scene-graph, just remove the activeConstraint from container
786 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
787 if ( NULL == propertyOwner )
789 ActiveConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), activeConstraint ) );
790 if( it != mConstraints->end() )
792 mConstraints->erase( it );
794 delete mRemovedConstraints;
795 mRemovedConstraints = NULL;
799 // Discard constraints which are fully removed
800 DeleteRemovedConstraints();
802 ActiveConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), activeConstraint ) );
803 if( it != mConstraints->end() )
805 ActiveConstraintBase& constraint = GetImplementation( *it );
807 constraint.BeginRemove();
808 mConstraints->erase( it );
810 if ( constraint.IsRemoving() )
812 if( !mRemovedConstraints )
814 mRemovedConstraints = new ActiveConstraintContainer;
816 // Wait for remove animation before destroying active-constraints
817 mRemovedConstraints->push_back( *it );
823 void ProxyObject::RemoveConstraints()
827 // If we have nothing in the scene-graph, just clear constraint containers
828 const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
829 if ( NULL == propertyOwner )
833 delete mRemovedConstraints;
834 mRemovedConstraints = NULL;
838 // Discard constraints which are fully removed
839 DeleteRemovedConstraints();
841 const ActiveConstraintConstIter endIter = mConstraints->end();
842 for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
844 ActiveConstraintBase& constraint = GetImplementation( *iter );
846 constraint.BeginRemove();
848 if ( constraint.IsRemoving() )
850 if( !mRemovedConstraints )
852 mRemovedConstraints = new ActiveConstraintContainer;
854 // Wait for remove animation before destroying active-constraints
855 mRemovedConstraints->push_back( *iter );
864 ProxyObject::~ProxyObject()
866 // Notification for observers
867 for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter)
869 (*iter)->ProxyDestroyed(*this);
872 delete mCustomProperties;
874 delete mRemovedConstraints;
875 delete mPropertyNotifications;
878 } // namespace Internal