Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / constraint-base.cpp
index f781543..d41825d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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/internal/event/animation/constraint-base.h>
 
 // INTERNAL INCLUDES
-#include <dali/public-api/object/handle.h>
-#include <dali/public-api/object/type-registry.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/event/common/property-helper.h>
 #include <dali/internal/event/common/stage-impl.h>
 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
 #include <dali/internal/update/common/animatable-property.h>
 #include <dali/internal/update/common/property-owner-messages.h>
+#include <dali/public-api/object/handle.h>
+#include <dali/public-api/object/type-registry.h>
 
 using Dali::Internal::SceneGraph::AnimatableProperty;
 
 namespace Dali
 {
-
 namespace Internal
 {
+namespace
+{
+/**
+ * Helper to add only unique entries to the propertyOwner container
+ * @param propertyOwners to add the entries to
+ * @param object to add
+ */
+inline void AddUnique(SceneGraph::PropertyOwnerContainer& propertyOwners, SceneGraph::PropertyOwner* object)
+{
+  const SceneGraph::PropertyOwnerIter iter = std::find(propertyOwners.Begin(), propertyOwners.End(), object);
+  if(iter == propertyOwners.End())
+  {
+    // each owner should only be added once
+    propertyOwners.PushBack(object);
+  }
+}
+} // unnamed namespace
 
-ConstraintBase::ConstraintBase( Object& object, Property::Index targetPropertyIndex, SourceContainer& sources )
-: mEventThreadServices( *Stage::GetCurrent() ),
-  mTargetObject( &object ),
-  mSceneGraphConstraint( NULL ),
-  mSources( sources ),
+ConstraintBase::ConstraintBase(Object& object, Property::Index targetPropertyIndex, SourceContainer& sources)
+: mEventThreadServices(EventThreadServices::Get()),
+  mTargetObject(&object),
+  mSceneGraphConstraint(nullptr),
+  mSources(sources),
   mObservedObjects(),
-  mTargetPropertyIndex( targetPropertyIndex ),
-  mRemoveAction( Dali::Constraint::DEFAULT_REMOVE_ACTION ),
-  mTag( 0 ),
-  mApplied( false ),
-  mSourceDestroyed( false )
+  mTargetPropertyIndex(targetPropertyIndex),
+  mRemoveAction(Dali::Constraint::DEFAULT_REMOVE_ACTION),
+  mTag(0),
+  mApplied(false),
+  mSourceDestroyed(false),
+  mIsPreConstraint(true)
 {
-  ObserveObject( object );
+  ObserveObject(object);
+}
+
+ConstraintBase* ConstraintBase::Clone(Object& object)
+{
+  DALI_ASSERT_ALWAYS(!mSourceDestroyed && "An input source object has been destroyed");
+
+  // create the type specific object
+  ConstraintBase* clone = DoClone(object);
+  clone->SetRemoveAction(mRemoveAction);
+  clone->SetTag(mTag);
+  return clone;
 }
 
 ConstraintBase::~ConstraintBase()
@@ -58,64 +86,79 @@ ConstraintBase::~ConstraintBase()
   RemoveInternal();
 }
 
-void ConstraintBase::AddSource( Source source )
+void ConstraintBase::AddSource(Source source)
 {
-  mSources.push_back( source );
+  mSources.push_back(source);
 
   // Observe the object providing this property
-  if ( OBJECT_PROPERTY == source.sourceType )
+  if(OBJECT_PROPERTY == source.sourceType)
   {
-    if ( source.object != NULL )
+    if(source.object != nullptr)
     {
-      ObserveObject( *source.object );
+      ObserveObject(*source.object);
     }
     else
     {
-      DALI_LOG_ERROR( "Constraint source object not found" );
+      DALI_LOG_ERROR("Constraint source object not found\n");
     }
   }
 }
 
-void ConstraintBase::Apply()
+void ConstraintBase::Apply(bool isPreConstraint)
 {
-  if ( mTargetObject && !mApplied && !mSourceDestroyed )
+  if(mTargetObject && !mApplied && !mSourceDestroyed)
   {
     mApplied = true;
-    ConnectConstraint();
+    mIsPreConstraint = isPreConstraint;
+    ConnectConstraint(mIsPreConstraint);
 
-    mTargetObject->ApplyConstraint( *this );
+    mTargetObject->ApplyConstraint(*this);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Fail to apply constraint\n");
   }
 }
 
+void ConstraintBase::ApplyPost()
+{
+  Apply(false);
+}
+
 void ConstraintBase::Remove()
 {
   RemoveInternal();
 
-  if( mTargetObject )
+  if(mTargetObject)
   {
-    mTargetObject->RemoveConstraint( *this );
+    mTargetObject->RemoveConstraint(*this);
   }
+  mIsPreConstraint = true;
 }
 
 void ConstraintBase::RemoveInternal()
 {
-  if ( mApplied )
+  if(mApplied)
   {
     mApplied = false;
 
     // Guard against constraint sending messages during core destruction
-    if( Stage::IsInstalled() )
+    if(Stage::IsInstalled())
     {
-      const SceneGraph::PropertyOwner* propertyOwner = mTargetObject ? mTargetObject->GetSceneObject() : NULL;
-
-      if ( propertyOwner &&
-           mSceneGraphConstraint )
+      if(mTargetObject && mSceneGraphConstraint)
       {
+        const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
         // Remove from scene-graph
-        RemoveConstraintMessage( GetEventThreadServices(), *propertyOwner, *(mSceneGraphConstraint) );
-
+        if(mIsPreConstraint)
+        {
+          RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
+        }
+        else
+        {
+          RemovePostConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
+        }
         // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
-        mSceneGraphConstraint = NULL;
+        mSceneGraphConstraint = nullptr;
       }
     }
   }
@@ -128,7 +171,7 @@ Object* ConstraintBase::GetParent()
 
 Dali::Handle ConstraintBase::GetTargetObject()
 {
-  return Dali::Handle( mTargetObject );
+  return Dali::Handle(mTargetObject);
 }
 
 Property::Index ConstraintBase::GetTargetProperty()
@@ -136,7 +179,7 @@ Property::Index ConstraintBase::GetTargetProperty()
   return mTargetPropertyIndex;
 }
 
-void ConstraintBase::SetRemoveAction( ConstraintBase::RemoveAction action )
+void ConstraintBase::SetRemoveAction(ConstraintBase::RemoveAction action)
 {
   mRemoveAction = action;
 }
@@ -146,53 +189,52 @@ ConstraintBase::RemoveAction ConstraintBase::GetRemoveAction() const
   return mRemoveAction;
 }
 
-void ConstraintBase::SetTag(const unsigned int tag)
+void ConstraintBase::SetTag(uint32_t tag)
 {
   mTag = tag;
 }
 
-unsigned int ConstraintBase::GetTag() const
+uint32_t ConstraintBase::GetTag() const
 {
   return mTag;
 }
 
-void ConstraintBase::SceneObjectAdded( Object& object )
+void ConstraintBase::SceneObjectAdded(Object& object)
 {
-  if ( mApplied &&
-       ( NULL == mSceneGraphConstraint ) &&
-       mTargetObject )
+  if(mApplied &&
+     (nullptr == mSceneGraphConstraint) &&
+     mTargetObject)
   {
-    ConnectConstraint();
+    ConnectConstraint(mIsPreConstraint);
   }
 }
 
-void ConstraintBase::SceneObjectRemoved( Object& object )
+void ConstraintBase::SceneObjectRemoved(Object& object)
 {
-  if ( mSceneGraphConstraint )
+  if(mSceneGraphConstraint)
   {
     // An input property owning source has been deleted, need to tell the scene-graph-constraint owner to remove it
-    if ( &object != mTargetObject )
+    if(&object != mTargetObject)
     {
-      const SceneGraph::PropertyOwner* propertyOwner = mTargetObject ? mTargetObject->GetSceneObject() : NULL;
-
-      if( propertyOwner )
+      if(mTargetObject)
       {
+        const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
         // Remove from scene-graph
-        RemoveConstraintMessage( GetEventThreadServices(), *propertyOwner, *(mSceneGraphConstraint) );
+        RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
       }
     }
 
     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
-    mSceneGraphConstraint = NULL;
+    mSceneGraphConstraint = nullptr;
   }
 }
 
-void ConstraintBase::ObjectDestroyed( Object& object )
+void ConstraintBase::ObjectDestroyed(Object& object)
 {
   // Remove object pointer from observation set
-  ObjectIter iter = std::find( mObservedObjects.Begin(), mObservedObjects.End(), &object );
-  DALI_ASSERT_DEBUG( mObservedObjects.End() != iter );
-  mObservedObjects.Erase( iter );
+  ObjectIter iter = std::find(mObservedObjects.Begin(), mObservedObjects.End(), &object);
+  DALI_ASSERT_DEBUG(mObservedObjects.End() != iter);
+  mObservedObjects.Erase(iter);
 
   // Constraint is not useful anymore as an input-source has been destroyed
   mSourceDestroyed = true;
@@ -204,31 +246,82 @@ void ConstraintBase::ObjectDestroyed( Object& object )
   mSources.clear();
 
   // Discard all object & scene-graph pointers
-  mSceneGraphConstraint = NULL;
-  mTargetObject = NULL;
+  mSceneGraphConstraint = nullptr;
+  mTargetObject         = nullptr;
 }
 
-void ConstraintBase::ObserveObject( Object& object )
+void ConstraintBase::ObserveObject(Object& object)
 {
-  ObjectIter iter = std::find( mObservedObjects.Begin(), mObservedObjects.End(), &object );
-  if ( mObservedObjects.End() == iter )
+  ObjectIter iter = std::find(mObservedObjects.Begin(), mObservedObjects.End(), &object);
+  if(mObservedObjects.End() == iter)
   {
-    object.AddObserver( *this );
-    mObservedObjects.PushBack( &object );
+    object.AddObserver(*this);
+    mObservedObjects.PushBack(&object);
   }
 }
 
 void ConstraintBase::StopObservation()
 {
   const ObjectIter end = mObservedObjects.End();
-  for( ObjectIter iter = mObservedObjects.Begin(); iter != end; ++iter )
+  for(ObjectIter iter = mObservedObjects.Begin(); iter != end; ++iter)
   {
-    (*iter)->RemoveObserver( *this );
+    (*iter)->RemoveObserver(*this);
   }
 
   mObservedObjects.Clear();
 }
 
+PropertyInputImpl* ConstraintBase::AddInputProperty(Source& source, SceneGraph::PropertyOwnerContainer& propertyOwners, int32_t& componentIndex)
+{
+  PropertyInputImpl* inputProperty = nullptr;
+
+  if(OBJECT_PROPERTY == source.sourceType)
+  {
+    DALI_ASSERT_ALWAYS(source.object->IsPropertyAConstraintInput(source.propertyIndex));
+
+    SceneGraph::PropertyOwner& owner = const_cast<SceneGraph::PropertyOwner&>(source.object->GetSceneObject());
+
+    AddUnique(propertyOwners, &owner);
+    inputProperty  = const_cast<PropertyInputImpl*>(source.object->GetSceneObjectInputProperty(source.propertyIndex));
+    componentIndex = source.object->GetPropertyComponentIndex(source.propertyIndex);
+
+    // The scene-object property should exist, when the property owner exists
+    DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
+  }
+  else if(LOCAL_PROPERTY == source.sourceType)
+  {
+    DALI_ASSERT_ALWAYS(mTargetObject->IsPropertyAConstraintInput(source.propertyIndex));
+
+    inputProperty  = const_cast<PropertyInputImpl*>(mTargetObject->GetSceneObjectInputProperty(source.propertyIndex));
+    componentIndex = mTargetObject->GetPropertyComponentIndex(source.propertyIndex);
+
+    // The target scene-object should provide this property
+    DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS(PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid");
+
+    Object* objectParent = dynamic_cast<Actor&>(*mTargetObject).GetParent();
+
+    // This will not exist, if the target object is off-stage
+    if(objectParent)
+    {
+      DALI_ASSERT_ALWAYS(objectParent->IsPropertyAConstraintInput(source.propertyIndex));
+
+      SceneGraph::PropertyOwner& owner = const_cast<SceneGraph::PropertyOwner&>(objectParent->GetSceneObject());
+
+      AddUnique(propertyOwners, &owner);
+      inputProperty  = const_cast<PropertyInputImpl*>(objectParent->GetSceneObjectInputProperty(source.propertyIndex));
+      componentIndex = objectParent->GetPropertyComponentIndex(source.propertyIndex);
+
+      // The scene-object property should exist, when the property owner exists
+      DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
+    }
+  }
+  return inputProperty;
+}
+
 } // namespace Internal
 
 } // namespace Dali