-#ifndef __DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H__
-#define __DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H__
+#ifndef DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H
+#define DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/public-api/animation/constraint.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/internal/common/message.h>
-#include <dali/internal/common/event-to-update.h>
+#include <dali/internal/event/common/event-thread-services.h>
#include <dali/internal/update/common/animatable-property.h>
#include <dali/internal/update/common/property-owner.h>
#include <dali/internal/update/common/scene-graph-buffers.h>
namespace SceneGraph
{
+using PropertyOwnerContainer = Dali::Vector<PropertyOwner*>;
+using PropertyOwnerIter = PropertyOwnerContainer::Iterator;
/**
* An abstract base class for Constraints.
* This can be used to constrain a property of a scene-object, after animations have been applied.
*/
-class ConstraintBase : public PropertyOwner, public PropertyOwner::Observer
+class ConstraintBase : public PropertyOwner::Observer
{
public:
+ /**
+ * Observer to determine when the constraint is no longer present
+ */
+ class LifecycleObserver
+ {
+ public:
+ /**
+ * Called shortly before the constraint is destroyed.
+ */
+ virtual void ObjectDestroyed() = 0;
+
+ protected:
+ /**
+ * Virtual destructor, no deletion through this interface
+ */
+ virtual ~LifecycleObserver() = default;
+ };
- typedef Dali::Constraint::RemoveAction RemoveAction;
+public:
+ using RemoveAction = Dali::Constraint::RemoveAction;
/**
* Constructor
+ * @param ownerContainer the properties to constraint
+ * @oparam removeAction perform when removed
*/
- ConstraintBase( PropertyOwnerSet& ownerSet );
+ ConstraintBase( PropertyOwnerContainer& ownerContainer, RemoveAction removeAction );
/**
* Virtual destructor.
virtual ~ConstraintBase();
/**
+ * Property resetter observes the lifecycle of this object
+ */
+ void AddLifecycleObserver( LifecycleObserver& observer )
+ {
+ mLifecycleObserver = &observer;
+ }
+
+ /**
+ * Property resetter observers the lifecycle of this object
+ */
+ void RemoveLifecycleObserver( LifecycleObserver& observer )
+ {
+ mLifecycleObserver = nullptr;
+ }
+
+ /**
* Initialize the constraint.
* This should by called by a scene-object, when the constraint is connected.
*/
}
/**
- * Bake the weight property.
+ * Constrain the associated scene object.
* @param[in] updateBufferIndex The current update buffer index.
- * @param[in] weight The new weight.
*/
- void BakeWeight( BufferIndex updateBufferIndex, float weight )
- {
- mWeight.Bake( updateBufferIndex, weight );
- }
-
- /**
- * Set the initial weight.
- * @pre The constraint has not been connected to the scene-graph.
- * @param[in] weight The new weight.
- */
- void SetInitialWeight( float weight )
- {
- mWeight.SetInitial( weight );
- }
+ virtual void Apply( BufferIndex updateBufferIndex ) = 0;
/**
- * Retrieve the weight property.
- * @param[in] bufferIndex The buffer index to read from.
- * @return The current weight.
+ * Helper for internal test cases; only available for debug builds.
+ * @return The current number of Constraint instances in existence.
*/
- float GetWeight( BufferIndex bufferIndex ) const
- {
- return mWeight[ bufferIndex ];
- }
+ static uint32_t GetCurrentInstanceCount();
/**
- * Constrain the associated scene object.
- * @param[in] updateBufferIndex The current update buffer index.
+ * Helper for internal test cases; only available for debug builds.
+ * @return The total number of Constraint instances created during the Dali core lifetime.
*/
- virtual void Apply( BufferIndex updateBufferIndex ) = 0;
+ static uint32_t GetTotalInstanceCount();
private:
*/
void StartObservation()
{
- for( PropertyOwnerIter iter = mObservedOwners.begin(); mObservedOwners.end() != iter; ++iter )
+ const PropertyOwnerIter end = mObservedOwners.End();
+ for( PropertyOwnerIter iter = mObservedOwners.Begin(); end != iter; ++iter )
{
(*iter)->AddObserver( *this );
}
*/
void StopObservation()
{
- for( PropertyOwnerIter iter = mObservedOwners.begin(); mObservedOwners.end() != iter; ++iter )
+ const PropertyOwnerIter end = mObservedOwners.End();
+ for( PropertyOwnerIter iter = mObservedOwners.Begin(); end != iter; ++iter )
{
(*iter)->RemoveObserver( *this );
}
- mObservedOwners.clear();
+ mObservedOwners.Clear();
}
/**
- * @copydoc PropertyOwner::Observer::PropertyOwnerDestroyed()
+ * @copydoc PropertyOwner::Observer::PropertyOwnerConnected()
*/
- virtual void PropertyOwnerDestroyed( PropertyOwner& owner )
+ virtual void PropertyOwnerConnected( PropertyOwner& owner )
{
- // Discard pointer to destroyed property owner
- PropertyOwnerIter iter = mObservedOwners.find( &owner );
- DALI_ASSERT_DEBUG( mObservedOwners.end() != iter );
- mObservedOwners.erase( iter );
+ }
- // Stop observing the remaining property owners
- StopObservation();
+ /**
+ * @copydoc PropertyOwner::Observer::PropertyOwnerDisconnected()
+ */
+ virtual void PropertyOwnerDisconnected( BufferIndex bufferIndex, PropertyOwner& owner )
+ {
+ if ( !mDisconnected )
+ {
+ // Stop observing property owners
+ StopObservation();
- // Notification for derived class
- OnDisconnect();
+ // Notification for derived class
+ OnDisconnect();
- mDisconnected = true;
+ mDisconnected = true;
+ }
}
/**
- * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties()
+ * @copydoc PropertyOwner::Observer::PropertyOwnerDestroyed()
*/
- virtual void ResetDefaultProperties( BufferIndex updateBufferIndex );
+ virtual void PropertyOwnerDestroyed( PropertyOwner& owner )
+ {
+ if ( !mDisconnected )
+ {
+ // Discard pointer to destroyed property owner. Otherwise StopObservation() would crash when trying to remove
+ //the constraint from the destroyed PropertyOwner's observers list
+ PropertyOwnerIter iter = std::find( mObservedOwners.Begin(), mObservedOwners.End(), &owner );
+ if( mObservedOwners.End() != iter )
+ {
+ mObservedOwners.Erase( iter );
+ }
+
+ // Stop observing the rest of property owners
+ StopObservation();
+
+ // Notification for derived class
+ OnDisconnect();
+
+ mDisconnected = true;
+
+ }
+ }
/**
* Notify the derived class to disconnect from property owners
*/
virtual void OnDisconnect() = 0;
-public:
-
- AnimatableProperty<float> mWeight; ///< The constraint is "fully-applied" when weight = 1
-
protected:
RemoveAction mRemoveAction;
private:
- PropertyOwnerSet mObservedOwners; ///< A set of pointers to each observed object. Not owned.
+ PropertyOwnerContainer mObservedOwners; ///< A set of pointers to each observed object. Not owned.
+ LifecycleObserver* mLifecycleObserver; ///< Resetter observers this object
+
+#ifdef DEBUG_ENABLED
+ static uint32_t mCurrentInstanceCount; ///< The current number of Constraint instances in existence.
+ static uint32_t mTotalInstanceCount; ///< The total number of Constraint instances created during the Dali core lifetime.
+#endif
};
// Messages for ConstraintBase
-inline void BakeWeightMessage( EventToUpdate& eventToUpdate, const ConstraintBase& constraint, float weight )
-{
- typedef MessageDoubleBuffered1< ConstraintBase, float > LocalType;
-
- // Reserve some memory inside the message queue
- unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
-
- // Construct message in the message queue memory; note that delete should not be called on the return value
- new (slot) LocalType( &constraint, &ConstraintBase::BakeWeight, weight );
-}
-
-inline void SetRemoveActionMessage( EventToUpdate& eventToUpdate, const ConstraintBase& constraint, Dali::Constraint::RemoveAction removeAction )
+inline void SetRemoveActionMessage( EventThreadServices& eventThreadServices, const ConstraintBase& constraint, Dali::Constraint::RemoveAction removeAction )
{
- typedef MessageValue1< ConstraintBase, Dali::Constraint::RemoveAction > LocalType;
+ using LocalType = MessageValue1<ConstraintBase, Dali::Constraint::RemoveAction>;
// Reserve some memory inside the message queue
- unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
+ uint32_t* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
// Construct message in the message queue memory; note that delete should not be called on the return value
new (slot) LocalType( &constraint, &ConstraintBase::SetRemoveAction, removeAction );
} // namespace Dali
-#endif // __DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H__
+#endif // DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H