Adding Raise Lower API to Actor 22/114722/18
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Tue, 14 Feb 2017 19:44:12 +0000 (19:44 +0000)
committerAgnelo Vaz <agnelo.vaz@samsung.com>
Fri, 24 Feb 2017 14:39:44 +0000 (06:39 -0800)
Devel API to allow the raising and lowering of the Actor's sibbling level.

Change-Id: I86c03d43d962441fd295dbf024092d42e78d9c0e

automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h
automated-tests/src/dali/dali-test-suite-utils/test-trace-call-stack.h
automated-tests/src/dali/utc-Dali-Actor.cpp
dali/devel-api/actors/actor-devel.cpp [new file with mode: 0644]
dali/devel-api/actors/actor-devel.h
dali/devel-api/file.list
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h

index 1613bb5..5e71779 100644 (file)
@@ -1135,9 +1135,12 @@ public:
     mTextureTrace.PushCall("TexSubImage2D", out.str(), namedParams);
   }
 
-  inline void Uniform1f(GLint location, GLfloat x)
+  inline void Uniform1f(GLint location, GLfloat value )
   {
-    if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, x ) )
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, value ) )
     {
       mGetErrorResult = GL_INVALID_OPERATION;
     }
@@ -1145,6 +1148,14 @@ public:
 
   inline void Uniform1fv(GLint location, GLsizei count, const GLfloat* v)
   {
+    std::string params;
+    for( int i = 0; i < count; ++i )
+    {
+      params = params + ToString( v[i] ) + ",";
+    }
+
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, v[i] ) )
@@ -1157,6 +1168,10 @@ public:
 
   inline void Uniform1i(GLint location, GLint x)
   {
+    std::string params = ToString( x );
+
+    AddUniformCallToTraceStack( location,  params );
+
     if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram, location, x ) )
     {
       mGetErrorResult = GL_INVALID_OPERATION;
@@ -1165,6 +1180,9 @@ public:
 
   inline void Uniform1iv(GLint location, GLsizei count, const GLint* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram,
@@ -1179,6 +1197,9 @@ public:
 
   inline void Uniform2f(GLint location, GLfloat x, GLfloat y)
   {
+    std::string params = ToString( x ) + "," + ToString( y );
+    AddUniformCallToTraceStack( location, params );
+
     if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
                                                location,
                                                Vector2( x, y ) ) )
@@ -1189,6 +1210,9 @@ public:
 
   inline void Uniform2fv(GLint location, GLsizei count, const GLfloat* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
@@ -1203,14 +1227,21 @@ public:
 
   inline void Uniform2i(GLint location, GLint x, GLint y)
   {
+    std::string params = ToString( x ) + "," + ToString( y );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void Uniform2iv(GLint location, GLsizei count, const GLint* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
   {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z );
+    AddUniformCallToTraceStack( location, params );
+
     if( ! mProgramUniforms3f.SetUniformValue( mCurrentProgram,
                                                location,
                                                Vector3( x, y, z ) ) )
@@ -1221,6 +1252,9 @@ public:
 
   inline void Uniform3fv(GLint location, GLsizei count, const GLfloat* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniforms3f.SetUniformValue(
@@ -1236,14 +1270,21 @@ public:
 
   inline void Uniform3i(GLint location, GLint x, GLint y, GLint z)
   {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void Uniform3iv(GLint location, GLsizei count, const GLint* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
   {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z ) + "," + ToString( w );
+    AddUniformCallToTraceStack( location, params );
+
     if( ! mProgramUniforms4f.SetUniformValue( mCurrentProgram,
                                               location,
                                               Vector4( x, y, z, w ) ) )
@@ -1254,6 +1295,9 @@ public:
 
   inline void Uniform4fv(GLint location, GLsizei count, const GLfloat* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniforms4f.SetUniformValue(
@@ -1269,18 +1313,27 @@ public:
 
   inline void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
   {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z ) + "," + ToString( w );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void Uniform4iv(GLint location, GLsizei count, const GLint* v)
   {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
   {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
   }
 
   inline void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
   {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniformsMat3.SetUniformValue(
@@ -1296,6 +1349,9 @@ public:
 
   inline void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
   {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
     for( int i = 0; i < count; ++i )
     {
       if( ! mProgramUniformsMat4.SetUniformValue(
@@ -1789,6 +1845,31 @@ public:
   {
   }
 
+private:
+
+  inline void AddUniformCallToTraceStack( GLint location, std::string& value )
+    {
+    std::string name = "<not found>";
+    bool matched = false;
+
+    UniformIDMap& map = mUniforms[mCurrentProgram];
+    for (UniformIDMap::iterator it=map.begin(); it!=map.end(); ++it)
+    {
+      if( it->second == location )
+      {
+        name = it->first;
+        matched = true;
+        break;
+      }
+    }
+
+    if ( matched )
+    {
+      mSetUniformTrace.PushCall( name, value );
+    }
+  }
+
+
 public: // TEST FUNCTIONS
   inline void SetCompileStatus( GLuint value ) { mCompileStatus = value; }
   inline void SetLinkStatus( GLuint value ) { mLinkStatus = value; }
@@ -1859,6 +1940,11 @@ public: // TEST FUNCTIONS
   inline void ResetStencilFunctionCallStack() { mStencilFunctionTrace.Reset(); }
   inline TraceCallStack& GetStencilFunctionTrace() { return mStencilFunctionTrace; }
 
+  //Methods for Uniform function verification
+  inline void EnableSetUniformCallTrace(bool enable) { mSetUniformTrace.Enable(enable); }
+  inline void ResetSetUniformCallStack() { mSetUniformTrace.Reset(); }
+  inline TraceCallStack& GetSetUniformTrace() { return mSetUniformTrace; }
+
   template <typename T>
   inline bool GetUniformValue( const char* name, T& value ) const
   {
@@ -2091,6 +2177,7 @@ private:
   TraceCallStack mDrawTrace;
   TraceCallStack mDepthFunctionTrace;
   TraceCallStack mStencilFunctionTrace;
+  TraceCallStack mSetUniformTrace;
 
   // Shaders & Uniforms
   GLuint mLastShaderIdUsed;
@@ -2178,9 +2265,6 @@ private:
   ProgramUniformValue<Matrix> mProgramUniformsMat4;
   ProgramUniformValue<Matrix3> mProgramUniformsMat3;
 
-
-
-
   inline const ProgramUniformValue<int>& GetProgramUniformsForType( const int ) const
   {
     return mProgramUniforms1i;
index c3f3358..d32f619 100644 (file)
 
 namespace Dali
 {
+
+template<typename T>
+std::string ToString(const T& x)
+{
+  return "undefined";
+}
+
 std::string ToString(int x);
 std::string ToString(unsigned int x);
 std::string ToString(float x);
index cb353df..0dfc7e3 100644 (file)
@@ -44,6 +44,9 @@ void utc_dali_actor_cleanup(void)
 namespace
 {
 bool gTouchCallBackCalled=false;
+bool gTouchCallBackCalled2=false;
+bool gTouchCallBackCalled3=false;
+
 bool gHoverCallBackCalled=false;
 
 static bool gTestConstraintCalled;
@@ -86,6 +89,34 @@ static bool TestCallback(Actor actor, const TouchEvent& event)
   END_TEST;
 }
 
+static bool TestTouchCallback(Actor actor, const TouchData& touchData )
+{
+  gTouchCallBackCalled = true;
+  return true;
+  END_TEST;
+}
+
+static bool TestTouchCallback2(Actor actor, const TouchData& touchData )
+{
+  gTouchCallBackCalled2 = true;
+  return true;
+  END_TEST;
+}
+
+static bool TestTouchCallback3(Actor actor, const TouchData& touchData )
+{
+  gTouchCallBackCalled3 = true;
+  return true;
+  END_TEST;
+}
+
+static void ResetTouchCallbacks()
+{
+  gTouchCallBackCalled = false;
+  gTouchCallBackCalled2 = false;
+  gTouchCallBackCalled3 = false;
+}
+
 static bool TestCallback3(Actor actor, const HoverEvent& event)
 {
   gHoverCallBackCalled = true;
@@ -2287,7 +2318,7 @@ int UtcDaliActorTouchedSignal(void)
 {
   TestApplication application;
 
-  gTouchCallBackCalled = false;
+  ResetTouchCallbacks();
 
   // get the root layer
   Actor actor = Stage::GetCurrent().GetRootLayer();
@@ -2523,7 +2554,7 @@ int UtcDaliActorHitTest(void)
 
   Stage::GetCurrent().Add( actor );
 
-  gTouchCallBackCalled = false;
+  ResetTouchCallbacks();
 
   unsigned int index = 0;
   while( NULL != hitTestData[index] )
@@ -2559,7 +2590,7 @@ int UtcDaliActorHitTest(void)
                  hitTestData[index]->mTouchPoint.x, hitTestData[index]->mTouchPoint.y,
                  hitTestData[index]->mResult );
 
-    gTouchCallBackCalled = false;
+    ResetTouchCallbacks();
     ++index;
   }
   END_TEST;
@@ -4065,3 +4096,642 @@ int UtcDaliGetPropertyN(void)
   DALI_TEST_EQUALS( actor.GetProperty( Property::Index(propertyCount)).GetType(), Property::NONE, TEST_LOCATION );
   END_TEST;
 }
+
+int UtcDaliActorRaiseLower(void)
+{
+  tet_infoline( "UtcDaliActor Raise and Lower test\n" );
+
+  TestApplication application;
+
+  Stage stage( Stage::GetCurrent() );
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  actorA.SetAnchorPoint( AnchorPoint::CENTER );
+  actorA.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorB.SetAnchorPoint( AnchorPoint::CENTER );
+  actorB.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorC.SetAnchorPoint( AnchorPoint::CENTER );
+  actorC.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorA.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorA.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorB.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorB.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorC.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorC.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  stage.Add( actorA );
+  stage.Add( actorB );
+  stage.Add( actorC );
+
+  ResetTouchCallbacks();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, false, TEST_LOCATION );
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchSignal().Connect( TestTouchCallback );
+  actorB.TouchSignal().Connect( TestTouchCallback2 );
+  actorC.TouchSignal().Connect( TestTouchCallback3 );
+
+  Dali::Integration::Point point;
+  point.SetDeviceId( 1 );
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.f, 10.f ) );
+  Dali::Integration::TouchEvent event;
+  event.AddPoint( point );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  true , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "Testing Raising of Actor\n" );
+
+  int preActorOrder( 0 );
+  int postActorOrder( 0 );
+
+  Property::Value value  = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+  value.Get( preActorOrder );
+
+  DevelActor::Raise( actorB );
+
+  value  = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+  value.Get( postActorOrder );
+
+  tet_printf( "Raised ActorB from (%d) to (%d) \n", preActorOrder, postActorOrder );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  true , TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  false, TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "Testing Lowering of Actor\n" );
+
+  value  = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+  value.Get( preActorOrder );
+
+  DevelActor::Lower( actorB );
+
+  value  = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+  value.Get( postActorOrder );
+
+  tet_printf( "Lowered ActorB from (%d) to (%d) \n", preActorOrder, postActorOrder );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false , TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  true, TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  END_TEST;
+}
+
+int UtcDaliActorRaiseToTopLowerToBottom(void)
+{
+  tet_infoline( "UtcDaliActorRaiseToTop and LowerToBottom test \n" );
+
+  TestApplication application;
+
+  Stage stage( Stage::GetCurrent() );
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+  // enables checking of which actor the uniform is assigned too
+  Shader shaderA = CreateShader();
+  shaderA.RegisterProperty( "uRendererColor",1.f);
+
+  Shader shaderB = CreateShader();
+  shaderB.RegisterProperty( "uRendererColor", 2.f );
+
+  Shader shaderC = CreateShader();
+  shaderC.RegisterProperty( "uRendererColor", 3.f );
+
+  Geometry geometry = CreateQuadGeometry();
+
+  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+  Renderer rendererA = Renderer::New(geometry, shaderA);
+  actorA.AddRenderer(rendererA);
+
+  Renderer rendererB = Renderer::New(geometry, shaderB);
+  actorB.AddRenderer(rendererB);
+
+  Renderer rendererC = Renderer::New(geometry, shaderC);
+  actorC.AddRenderer(rendererC);
+
+  actorA.SetAnchorPoint( AnchorPoint::CENTER );
+  actorA.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorB.SetAnchorPoint( AnchorPoint::CENTER );
+  actorB.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorC.SetAnchorPoint( AnchorPoint::CENTER );
+  actorC.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorA.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorA.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorB.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorB.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorC.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorC.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  stage.Add( actorA );
+  stage.Add( actorB );
+  stage.Add( actorC );
+
+  ResetTouchCallbacks();
+
+  // Set up gl abstraction trace so can query the set uniform order
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableSetUniformCallTrace(true);
+  glAbstraction.ResetSetUniformCallStack();
+
+  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Trace Output:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+
+  // Test order of uniforms in stack
+  int indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  int indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  int indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  bool CBA = ( indexC > indexB) &&  ( indexB > indexA );
+
+  DALI_TEST_EQUALS( CBA, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, false, TEST_LOCATION );
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchSignal().Connect( TestTouchCallback );
+  actorB.TouchSignal().Connect( TestTouchCallback2 );
+  actorC.TouchSignal().Connect( TestTouchCallback3 );
+
+  Dali::Integration::Point point;
+  point.SetDeviceId( 1 );
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.f, 10.f ) );
+  Dali::Integration::TouchEvent event;
+  event.AddPoint( point );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  true , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "RaiseToTop ActorA\n" );
+
+  DevelActor::RaiseToTop( actorA );
+
+  application.ProcessEvent( event );
+
+  glAbstraction.ResetSetUniformCallStack();
+  glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Trace:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  tet_infoline( "Testing A above C and B at bottom\n" );
+  bool ACB = ( indexA > indexC) && ( indexC > indexB );
+
+  DALI_TEST_EQUALS( ACB, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  false , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "RaiseToTop ActorB\n" );
+
+  DevelActor::RaiseToTop( actorB );
+
+  application.ProcessEvent( event );
+
+  glAbstraction.ResetSetUniformCallStack();
+  glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Trace:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  tet_infoline( "Testing B above A and C at bottom\n" );
+  bool BAC = ( indexB > indexA ) && ( indexA > indexC );
+
+  DALI_TEST_EQUALS( BAC, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  false , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "LowerToBottom ActorA then ActorB leaving Actor C at Top\n" );
+
+  DevelActor::LowerToBottom( actorA );
+  application.SendNotification();
+  application.Render();
+
+  DevelActor::LowerToBottom( actorB );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( event );
+
+  glAbstraction.ResetSetUniformCallStack();
+  glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Trace:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  tet_infoline( "Testing C above A and B at bottom\n" );
+  bool CAB = ( indexC > indexA ) && ( indexA > indexB );
+
+  DALI_TEST_EQUALS( CAB, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  true , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  END_TEST;
+}
+
+int UtcDaliActorRaiseAboveLowerBelow(void)
+{
+  tet_infoline( "UtcDaliActor RaiseToAbove and LowerBelow test \n" );
+
+  TestApplication application;
+
+  Stage stage( Stage::GetCurrent() );
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  actorA.SetAnchorPoint( AnchorPoint::CENTER );
+  actorA.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorB.SetAnchorPoint( AnchorPoint::CENTER );
+  actorB.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorC.SetAnchorPoint( AnchorPoint::CENTER );
+  actorC.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorA.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorA.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorB.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorB.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorC.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorC.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  stage.Add( actorA );
+  stage.Add( actorB );
+  stage.Add( actorC );
+
+  ResetTouchCallbacks();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, false, TEST_LOCATION );
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchSignal().Connect( TestTouchCallback );
+  actorB.TouchSignal().Connect( TestTouchCallback2 );
+  actorC.TouchSignal().Connect( TestTouchCallback3 );
+
+  Dali::Integration::Point point;
+  point.SetDeviceId( 1 );
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.f, 10.f ) );
+  Dali::Integration::TouchEvent event;
+  event.AddPoint( point );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  true , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "Raise actor B Above Actor C\n" );
+
+  DevelActor::RaiseAbove( actorB, actorC );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  false , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "Raise actor A Above Actor B\n" );
+
+  DevelActor::RaiseAbove( actorA, actorB );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled,  true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2,  false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3,  false , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  END_TEST;
+}
+
+int UtcDaliActorLowerBelow(void)
+{
+  tet_infoline( "UtcDaliActor LowerBelow test \n" );
+
+  TestApplication application;
+
+  Stage stage( Stage::GetCurrent() );
+
+  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+  // enables checking of which actor the uniform is assigned too
+  Shader shaderA = CreateShader();
+  shaderA.RegisterProperty( "uRendererColor",1.f);
+
+  Shader shaderB = CreateShader();
+  shaderB.RegisterProperty( "uRendererColor", 2.f );
+
+  Shader shaderC = CreateShader();
+  shaderC.RegisterProperty( "uRendererColor", 3.f );
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+  Geometry geometry = CreateQuadGeometry();
+
+  Renderer rendererA = Renderer::New(geometry, shaderA);
+  actorA.AddRenderer(rendererA);
+
+  Renderer rendererB = Renderer::New(geometry, shaderB);
+  actorB.AddRenderer(rendererB);
+
+  Renderer rendererC = Renderer::New(geometry, shaderC);
+  actorC.AddRenderer(rendererC);
+
+  actorA.SetAnchorPoint( AnchorPoint::CENTER );
+  actorA.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorB.SetAnchorPoint( AnchorPoint::CENTER );
+  actorB.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorC.SetAnchorPoint( AnchorPoint::CENTER );
+  actorC.SetParentOrigin( ParentOrigin::CENTER );
+
+  actorA.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorA.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorB.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorB.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  actorC.SetProperty( Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT" );
+  actorC.SetProperty( Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT" );
+
+  stage.Add( actorA );
+  stage.Add( actorB );
+  stage.Add( actorC );
+
+  ResetTouchCallbacks();
+
+  // Set up gl abstraction trace so can query the set uniform order
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableSetUniformCallTrace(true);
+  glAbstraction.ResetSetUniformCallStack();
+  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  glAbstraction.ResetSetUniformCallStack();
+
+  application.SendNotification();
+  application.Render();
+
+  glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  tet_printf( "Trace:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+  // Test order of uniforms in stack
+  int indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  int indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  int indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  tet_infoline( "Testing C above B and A at bottom\n" );
+  bool CBA = ( indexC > indexB) &&  ( indexB > indexA );
+
+  DALI_TEST_EQUALS( CBA, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, false, TEST_LOCATION );
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchSignal().Connect( TestTouchCallback );
+  actorB.TouchSignal().Connect( TestTouchCallback2 );
+  actorC.TouchSignal().Connect( TestTouchCallback3 );
+
+  Dali::Integration::Point point;
+  point.SetDeviceId( 1 );
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.f, 10.f ) );
+  Dali::Integration::TouchEvent event;
+  event.AddPoint( point );
+
+  tet_infoline( "UtcDaliActor Test Set up completed \n" );
+
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, true , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n" );
+
+  DevelActor::LowerBelow( actorC, actorB );
+
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( event );
+
+  glAbstraction.ResetSetUniformCallStack();
+  glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Trace:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  tet_infoline( "Testing B above A and C at bottom\n" );
+  bool BAC = ( indexB > indexA) &&  ( indexA > indexC );
+
+  DALI_TEST_EQUALS( BAC, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, false , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  tet_printf( "Lower actor B below Actor C leaving A on top\n" );
+
+  DevelActor::LowerBelow( actorB, actorC );
+
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( event );
+
+  glAbstraction.ResetSetUniformCallStack();
+  glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  application.Render();
+  tet_printf( "Trace:%s \n", glSetUniformStack.GetTraceString().c_str() );
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "3" );
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "2" );
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams( "uRendererColor",  "1" );
+
+  bool ACB = ( indexA > indexC) &&  ( indexC > indexB );
+
+  DALI_TEST_EQUALS( ACB, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gTouchCallBackCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gTouchCallBackCalled3, false , TEST_LOCATION );
+
+  ResetTouchCallbacks();
+
+  END_TEST;
+}
+
+int UtcDaliActorMaxSiblingOrder(void)
+{
+  tet_infoline( "UtcDaliActor De-fragment of sibling order once max index reached\n" );
+
+  TestApplication application;
+
+  int testOrders[] = { 0,1,3,5,17,998, 999 };
+  int resultingOrders[] = { 0,1,2,3,4,6,5 };
+
+  const int TEST_ORDERS_COUNT = sizeof( testOrders ) / sizeof( testOrders[0] );
+
+  Stage stage( Stage::GetCurrent() );
+
+  Actor parent = Actor::New();
+
+  for ( int index = 0; index < TEST_ORDERS_COUNT; index++ )
+  {
+    Actor newActor = Actor::New();
+    newActor.SetProperty(Dali::DevelActor::Property::SIBLING_ORDER, testOrders[index] );
+    parent.Add( newActor );
+  }
+  stage.Add( parent );
+
+  tet_printf( "Sibling Order %d children :",  parent.GetChildCount() );
+  for ( unsigned int index = 0; index < parent.GetChildCount(); index ++)
+  {
+    Actor sibling = parent.GetChildAt( index );
+    int siblingOrder = 0;
+    Property::Value value = sibling.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+    value.Get( siblingOrder );
+    tet_printf( "%d, ", siblingOrder );
+  }
+  tet_printf( "\n" );
+
+  Actor sibling = parent.GetChildAt( 5 );
+  DevelActor::RaiseToTop( sibling );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Sibling Order %d children :",  parent.GetChildCount() );
+  for ( unsigned int index = 0; index < parent.GetChildCount(); index ++)
+  {
+    Actor sibling = parent.GetChildAt( index );
+    int siblingOrder = 0;
+    Property::Value value = sibling.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+    value.Get( siblingOrder );
+    tet_printf( "%d, ", siblingOrder );
+    DALI_TEST_EQUALS( siblingOrder,  resultingOrders[ index] , TEST_LOCATION );
+  }
+
+  tet_printf( "\n" );
+
+  END_TEST;
+}
diff --git a/dali/devel-api/actors/actor-devel.cpp b/dali/devel-api/actors/actor-devel.cpp
new file mode 100644 (file)
index 0000000..5b63c86
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/internal/event/actors/actor-impl.h>
+
+namespace Dali
+{
+
+namespace DevelActor
+{
+
+void Raise( Actor actor )
+{
+  GetImplementation( actor ).Raise();
+}
+
+void Lower( Actor actor )
+{
+  GetImplementation( actor ).Lower();
+}
+
+void RaiseToTop( Actor actor )
+{
+  GetImplementation( actor ).RaiseToTop();
+}
+
+void LowerToBottom( Actor actor )
+{
+  GetImplementation( actor ).LowerToBottom();
+}
+
+void RaiseAbove( Actor actor, Dali::Actor target )
+{
+  GetImplementation( actor ).RaiseAbove( target );
+}
+
+void LowerBelow( Actor actor, Actor target )
+{
+  GetImplementation( actor ).LowerBelow( target);
+}
+
+} // namespace DevelActor
+
+} // namespace Dali
index 270767e..11229e4 100644 (file)
@@ -87,6 +87,14 @@ enum Type
   INHERIT_POSITION     = Dali::Actor::Property::INHERIT_POSITION,
   CLIPPING_MODE        = Dali::Actor::Property::CLIPPING_MODE,
 
+  /**
+   * @brief name "siblingOrder", type INTEGER
+   *
+   * @details Sets the sibling order of the actor so depth position can be defined within the same parent.
+   *
+   * @note Raise, Lower, RaiseToTop, LowerToBottom, RaiseAbove and LowerBelow will override the
+   * sibling order. The values set by this Property will likey change.
+   */
   SIBLING_ORDER        = CLIPPING_MODE + 1,
 
   /**
@@ -99,6 +107,75 @@ enum Type
 
 } // namespace Property
 
+/**
+ * @brief Raise actor above the next highest level of actor(s)
+ *
+ * @param[in] actor the Actor to lower
+ * @note Sibling order of actors within the parent will be updated automatically.
+ * Using this API means a limit of DevelLayer::SIBLING_ORDER_MULTIPLIER Actors.
+ * Initially actors added to a parent will have the same sibling order and shown in relation to insertion order.
+ * Raising this actor above actors with the same sibling order as each other will raise this actor above them.
+ * Once a raise or lower API is used that actor will then have an exclusive sibling order independent of insertion.
+ *
+ */
+DALI_IMPORT_API void Raise( Actor actor );
+
+/**
+ * @brief Lower the actor to underneath the level below actor(s)
+ *
+ * @param[in] actor the Actor to lower
+ * @note Sibling order of actors within the parent will be updated automatically.
+ * Using this API means a limit of DevelLayer::SIBLING_ORDER_MULTIPLIER Actors.
+ * Lowering this actor below actors with the same sibling order as each other will lower this actor above them.
+ * Once a raise or lower API is used that actor will then have an exclusive sibling order independent of insertion.
+ */
+DALI_IMPORT_API void Lower( Actor actor );
+
+/**
+ * @brief Raise actor above all other actors
+ *
+ * @param[in] actor the Actor to lower
+ * @note Sibling order of actors within the parent will be updated automatically.
+ * Using this API means a limit of DevelLayer::SIBLING_ORDER_MULTIPLIER Actors.
+ * Once a raise or lower API is used that actor will then have an exclusive sibling order independent of insertion.
+ */
+DALI_IMPORT_API void RaiseToTop( Actor actor );
+
+/**
+ * @brief Lower actor to the bottom of all actors
+ *
+ * @param[in] actor the Actor to lower
+ * @note Sibling order of actors within the parent will be updated automatically.
+ * Using this API means a limit of DevelLayer::SIBLING_ORDER_MULTIPLIER Actors.
+ * Once a raise or lower API is used that actor will then have an exclusive sibling order independent of insertion.
+ */
+DALI_IMPORT_API void LowerToBottom( Actor actor );
+
+/**
+ * @brief Raise the actor to above the target actor
+ *
+ * @param[in] actor the Actor to lower
+ * @param[in] target the target Actor to raise above
+ * @note Sibling order of actors within the parent will be updated automatically.
+ * Actors on the level above the target actor will still be shown above this actor.
+ * Raising this actor above actors with the same sibling order as each other will raise this actor above them.
+ * Using this API means a limit of DevelLayer::SIBLING_ORDER_MULTIPLIER Actors.
+ * Once a raise or lower API is used that actor will then have an exclusive sibling order independent of insertion.
+ */
+DALI_IMPORT_API void RaiseAbove( Actor actor, Dali::Actor target );
+
+/**
+ * @brief Lower the actor to below the target actor
+ *
+ * @param[in] actor the Actor to lower
+ * @param[in] target the target Actor to lower below
+ * @note Sibling order of actors within the parent will be updated automatically.
+ * Using this API means a limit of DevelLayer::SIBLING_ORDER_MULTIPLIER Actors.
+ * Lowering this actor below actors with the same sibling order as each other will lower this actor above them.
+ * Once a raise or lower API is used that actor will then have an exclusive sibling order independent of insertion.
+ */
+DALI_IMPORT_API void LowerBelow( Actor actor, Dali::Actor target );
+
 } // namespace DevelActor
 
 } // namespace Dali
index 394fd97..7d2eb05 100644 (file)
@@ -1,5 +1,6 @@
 # Add devel source files here for DALi internal developer files used by Adaptor & Toolkit
 devel_api_src_files = \
+  $(devel_api_src_dir)/actors/actor-devel.cpp \
   $(devel_api_src_dir)/animation/animation-data.cpp \
   $(devel_api_src_dir)/animation/path-constrainer.cpp \
   $(devel_api_src_dir)/common/hash.cpp \
index 9f6b86d..5869699 100644 (file)
@@ -87,6 +87,14 @@ inline const Vector2& GetDefaultDimensionPadding()
 
 const SizeScalePolicy::Type DEFAULT_SIZE_SCALE_POLICY = SizeScalePolicy::USE_SIZE_SET;
 
+int GetSiblingOrder( ActorPtr actor )
+{
+  Property::Value value  = actor->GetProperty(Dali::DevelActor::Property::SIBLING_ORDER );
+  int order;
+  value.Get( order );
+  return order;
+}
+
 } // unnamed namespace
 
 /**
@@ -2699,11 +2707,7 @@ void Actor::SetDefaultProperty( Property::Index index, const Property::Value& pr
       {
         if( static_cast<unsigned int>(value) != mSiblingOrder )
         {
-          mSiblingOrder = value;
-          if( mIsOnStage )
-          {
-            SetDepthIndexMessage( GetEventThreadServices(), *mNode, GetDepthIndex( mDepth, mSiblingOrder ) );
-          }
+          SetSiblingOrder( value );
         }
       }
       break;
@@ -4419,6 +4423,453 @@ Object* Actor::GetParentObject() const
   return mParent;
 }
 
+void Actor::SetSiblingOrder( unsigned int order )
+{
+  mSiblingOrder = std::min( order, static_cast<unsigned int>( DevelLayer::SIBLING_ORDER_MULTIPLIER ) );
+  if( mIsOnStage )
+  {
+    SetDepthIndexMessage( GetEventThreadServices(), *mNode, GetDepthIndex( mDepth, mSiblingOrder ) );
+  }
+}
+
+void Actor::DefragmentSiblingIndexes( ActorContainer& siblings )
+{
+  // Sibling index may not be in consecutive order as the sibling range is limited ( DevelLayer::SIBLING_ORDER_MULTIPLIER )
+  // we need to remove the gaps and ensure the number start from 0 and consecutive hence have a full range.
+
+  // Start at index 0, while index <= highest order
+  // Find next index higher than 0
+  //   if nextHigher > index+1
+  //      set all nextHigher orders to index+1
+
+  // Limitation: May reach the ceiling of DevelLayer::SIBLING_ORDER_MULTIPLIER with highest sibling.
+
+  ActorIter end = siblings.end();
+  int highestOrder = 0;
+  for( ActorIter iter = siblings.begin(); iter != end; ++iter )
+  {
+    ActorPtr sibling = (*iter);
+    int siblingOrder = sibling->mSiblingOrder;
+    highestOrder = std::max( highestOrder, siblingOrder );
+  }
+
+  for ( int index = 0; index <= highestOrder; index++ )
+  {
+    int nextHighest = -1;
+
+    // Find Next highest
+    for( ActorIter iter = siblings.begin(); iter != end; ++iter )
+    {
+      ActorPtr sibling = (*iter);
+      int siblingOrder = sibling->mSiblingOrder;
+
+      if ( siblingOrder > index )
+      {
+        if ( nextHighest == -1 )
+        {
+          nextHighest = siblingOrder;
+        }
+        nextHighest = std::min( nextHighest, siblingOrder );
+      }
+    }
+
+    // Check if a gap exists between indexes, if so set next index to consecutive number
+    if ( ( nextHighest - index ) > 1 )
+    {
+      for( ActorIter iter = siblings.begin(); iter != end; ++iter )
+      {
+        ActorPtr sibling = (*iter);
+        int siblingOrder = sibling->mSiblingOrder;
+        if ( siblingOrder == nextHighest )
+        {
+          sibling->mSiblingOrder =  index + 1;
+          if ( sibling->mSiblingOrder >= Dali::DevelLayer::SIBLING_ORDER_MULTIPLIER )
+          {
+            DALI_LOG_WARNING( "Reached max sibling order level for raising / lowering actors\n" );
+            sibling->mSiblingOrder = Dali::DevelLayer::SIBLING_ORDER_MULTIPLIER;
+          }
+          sibling->SetSiblingOrder( sibling->mSiblingOrder );
+        }
+      }
+    }
+  }
+}
+
+bool Actor::ShiftSiblingsLevels( ActorContainer& siblings, int targetLevelToShiftFrom )
+{
+  // Allows exclusive levels for an actor by shifting all sibling levels at the target and above by 1
+  bool defragmentationRequired( false );
+  ActorIter end = siblings.end();
+  for( ActorIter iter = siblings.begin(); ( iter != end ) ; ++iter )
+  {
+    // Move actors at nearest order and above up by 1
+    ActorPtr sibling = (*iter);
+    if ( sibling != this )
+    {
+      // Iterate through container of actors, any actor with a sibling order of the target or greater should
+      // be incremented by 1.
+      if ( sibling->mSiblingOrder >= targetLevelToShiftFrom )
+      {
+        sibling->mSiblingOrder++;
+        if ( sibling->mSiblingOrder + 1 >= DevelLayer::SIBLING_ORDER_MULTIPLIER )
+        {
+          // If a sibling order raises so that it is only 1 from the maximum allowed then set flag so
+          // can re-order all sibling orders.
+          defragmentationRequired = true;
+        }
+        sibling->SetSiblingOrder( sibling->mSiblingOrder );
+      }
+    }
+  }
+  return defragmentationRequired;
+}
+
+void Actor::Raise()
+{
+  /*
+     1) Check if already at top and nothing to be done.
+        This Actor can have highest sibling order but if not exclusive then another actor at same sibling
+        order can be positioned above it due to insertion order of actors.
+     2) Find nearest sibling level above, these are the siblings this actor needs to be above
+     3) a) There may be other levels above this target level
+        b) Increment all sibling levels at the level above nearest(target)
+        c) Now have a vacant sibling level
+     4) Set this actor's sibling level to nearest +1 as now vacated.
+
+     Note May not just be sibling level + 1 as could be empty levels in-between
+
+     Example:
+
+     1 ) Initial order
+        ActorC ( sibling level 4 )
+        ActorB ( sibling level 3 )
+        ActorA ( sibling level 1 )
+
+     2 )  ACTION: Raise A above B
+        a) Find nearest level above A = Level 3
+        b) Increment levels above Level 3
+
+           ActorC ( sibling level 5 )
+           ActorB ( sibling level 3 )  NEAREST
+           ActorA ( sibling level 1 )
+
+     3 ) Set Actor A sibling level to nearest +1 as vacant
+
+         ActorC ( sibling level 5 )
+         ActorA ( sibling level 4 )
+         ActorB ( sibling level 3 )
+
+     4 ) Sibling order levels have a maximum defined in DevelLayer::SIBLING_ORDER_MULTIPLIER
+         If shifting causes this ceiling to be reached. then a defragmentation can be performed to
+         remove any empty sibling order gaps and start from sibling level 0 again.
+         If the number of actors reaches this maximum and all using exclusive sibling order values then
+         defragmention will stop and new sibling orders will be set to same max value.
+  */
+  if ( mParent )
+  {
+    int nearestLevel = mSiblingOrder;
+    int shortestDistanceToNextLevel = DevelLayer::SIBLING_ORDER_MULTIPLIER;
+    bool defragmentationRequired( false );
+
+    ActorContainer* siblings = mParent->mChildren;
+
+    // Find Nearest sibling level above this actor
+    ActorIter end = siblings->end();
+    for( ActorIter iter = siblings->begin(); iter != end; ++iter )
+    {
+      ActorPtr sibling = (*iter);
+      if ( sibling != this )
+      {
+        int order = GetSiblingOrder( sibling );
+
+        if ( ( order >= mSiblingOrder ) )
+        {
+          int distanceToNextLevel =  order - mSiblingOrder;
+          if ( distanceToNextLevel < shortestDistanceToNextLevel )
+          {
+            nearestLevel = order;
+            shortestDistanceToNextLevel = distanceToNextLevel;
+          }
+        }
+      }
+    }
+
+    if ( nearestLevel < DevelLayer::SIBLING_ORDER_MULTIPLIER ) // Actor is not already exclusively at top
+    {
+      mSiblingOrder = nearestLevel + 1; // Set sibling level to that above the nearest level
+      defragmentationRequired = ShiftSiblingsLevels( *siblings, mSiblingOrder );
+      // Move current actor to newly vacated order level
+      SetSiblingOrder( mSiblingOrder );
+      if ( defragmentationRequired )
+      {
+        DefragmentSiblingIndexes( *siblings );
+      }
+    }
+    SetSiblingOrder( mSiblingOrder );
+  }
+}
+
+void Actor::Lower()
+{
+  /**
+    1) Check if actor already at bottom and if nothing needs to be done
+       This Actor can have lowest sibling order but if not exclusive then another actor at same sibling
+       order can be positioned above it due to insertion order of actors so need to move this actor below it.
+    2) Find nearest sibling level below, this Actor needs to be below it
+    3) a) Need to vacate a sibling level below nearest for this actor to occupy
+       b) Shift up all sibling order values of actor at the nearest level and levels above it to vacate a level.
+       c) Set this actor's sibling level to this newly vacated level.
+    4 ) Sibling order levels have a maximum defined in DevelLayer::SIBLING_ORDER_MULTIPLIER
+       If shifting causes this ceiling to be reached. then a defragmentation can be performed to
+       remove any empty sibling order gaps and start from sibling level 0 again.
+       If the number of actors reaches this maximum and all using exclusive sibling order values then
+       defragmention will stop and new sibling orders will be set to same max value.
+  */
+
+  if ( mParent )
+  {
+    // 1) Find nearest level below
+    int nearestLevel = mSiblingOrder;
+    int shortestDistanceToNextLevel = DevelLayer::SIBLING_ORDER_MULTIPLIER;
+
+    ActorContainer* siblings = mParent->mChildren;
+
+    ActorIter end = siblings->end();
+    for( ActorIter iter = siblings->begin(); iter != end; ++iter )
+    {
+      ActorPtr sibling = (*iter);
+      if ( sibling != this )
+      {
+        int order = GetSiblingOrder( sibling );
+
+        if ( order <= mSiblingOrder )
+        {
+          int distanceToNextLevel =  mSiblingOrder - order;
+          if ( distanceToNextLevel < shortestDistanceToNextLevel )
+          {
+            nearestLevel = order;
+            shortestDistanceToNextLevel = distanceToNextLevel;
+          }
+        }
+      }
+    }
+
+    bool defragmentationRequired ( false );
+
+    // 2) If actor already not at bottom, raise all actors at required level and above
+    if ( shortestDistanceToNextLevel < DevelLayer::SIBLING_ORDER_MULTIPLIER ) // Actor is not already exclusively at bottom
+    {
+      mSiblingOrder = nearestLevel;
+      defragmentationRequired = ShiftSiblingsLevels( *siblings, mSiblingOrder );
+      // Move current actor to newly vacated order
+      SetSiblingOrder( mSiblingOrder );
+      if ( defragmentationRequired )
+      {
+        DefragmentSiblingIndexes( *siblings );
+      }
+    }
+  }
+}
+
+void Actor::RaiseToTop()
+{
+  /**
+    1 ) Find highest sibling order actor
+    2 ) If highest sibling level not itself then set sibling order to that + 1
+    3 ) highest sibling order can be same as itself so need to increment over that
+    4 ) Sibling order levels have a maximum defined in DevelLayer::SIBLING_ORDER_MULTIPLIER
+        If shifting causes this ceiling to be reached. then a defragmentation can be performed to
+        remove any empty sibling order gaps and start from sibling level 0 again.
+        If the number of actors reaches this maximum and all using exclusive sibling order values then
+        defragmention will stop and new sibling orders will be set to same max value.
+   */
+
+  if ( mParent )
+  {
+    int maxOrder = 0;
+
+    ActorContainer* siblings = mParent->mChildren;
+
+    ActorIter end = siblings->end();
+    for( ActorIter iter = siblings->begin(); iter != end; ++iter )
+    {
+      ActorPtr sibling = (*iter);
+      if ( sibling != this )
+      {
+        maxOrder = std::max( GetSiblingOrder( sibling ), maxOrder );
+      }
+    }
+
+    bool defragmentationRequired( false );
+
+    if ( maxOrder >= mSiblingOrder )
+    {
+      mSiblingOrder = maxOrder + 1;
+      if ( mSiblingOrder + 1 >= DevelLayer::SIBLING_ORDER_MULTIPLIER )
+      {
+        defragmentationRequired = true;
+      }
+    }
+
+    SetSiblingOrder( mSiblingOrder );
+
+    if ( defragmentationRequired )
+    {
+      DefragmentSiblingIndexes( *siblings );
+    }
+  }
+}
+
+void Actor::LowerToBottom()
+{
+  /**
+    See Actor::LowerToBottom()
+
+    1 ) Check if this actor already at exclusively at the bottom, if so then no more to be done.
+    2 ) a ) Check if the bottom position 0 is vacant.
+        b ) If 0 position is not vacant then shift up all sibling order values from 0 and above
+        c ) 0 sibling position is vacant.
+    3 ) Set this actor to vacant sibling order 0;
+    4 ) Sibling order levels have a maximum defined in DevelLayer::SIBLING_ORDER_MULTIPLIER
+        If shifting causes this ceiling to be reached. then a defragmentation can be performed to
+        remove any empty sibling order gaps and start from sibling level 0 again.
+        If the number of actors reaches this maximum and all using exclusive sibling order values then
+        defragmention will stop and new sibling orders will be set to same max value.
+   */
+
+  if ( mParent )
+  {
+    bool defragmentationRequired( false );
+    bool orderZeroFree ( true );
+
+    ActorContainer* siblings = mParent->mChildren;
+
+    bool actorAtLowestOrder = true;
+    ActorIter end = siblings->end();
+    for( ActorIter iter = siblings->begin(); ( iter != end ) ; ++iter )
+    {
+      ActorPtr sibling = (*iter);
+      if ( sibling != this )
+      {
+        int siblingOrder = GetSiblingOrder( sibling );
+        if ( siblingOrder <= mSiblingOrder )
+        {
+          actorAtLowestOrder = false;
+        }
+
+        if ( siblingOrder == 0 )
+        {
+          orderZeroFree = false;
+        }
+      }
+    }
+
+    if ( ! actorAtLowestOrder  )
+    {
+      if ( ! orderZeroFree )
+      {
+        defragmentationRequired = ShiftSiblingsLevels( *siblings, 0 );
+      }
+      mSiblingOrder = 0;
+      SetSiblingOrder( mSiblingOrder );
+
+      if ( defragmentationRequired )
+      {
+        DefragmentSiblingIndexes( *siblings );
+      }
+    }
+  }
+}
+
+void Actor::RaiseAbove( Dali::Actor target )
+{
+  /**
+    1 ) a) Find target actor's sibling order
+        b) If sibling order of target is the same as this actor then need to this Actor's sibling order
+           needs to be above it or the insertion order will determine which is drawn on top.
+    2 ) Shift up by 1 all sibling order greater than target sibling order
+    3 ) Set this actor to the sibling order to target +1 as will be a newly vacated gap above
+    4 ) Sibling order levels have a maximum defined in DevelLayer::SIBLING_ORDER_MULTIPLIER
+        If shifting causes this ceiling to be reached. then a defragmentation can be performed to
+        remove any empty sibling order gaps and start from sibling level 0 again.
+        If the number of actors reaches this maximum and all using exclusive sibling order values then
+        defragmention will stop and new sibling orders will be set to same max value.
+   */
+
+  if ( this != target )
+  {
+     // Find target's sibling order
+     // Set actor sibling order to this number +1
+    int targetSiblingOrder = GetSiblingOrder( &GetImplementation( target ) );
+    ActorContainer* siblings = mParent->mChildren;
+    mSiblingOrder = targetSiblingOrder + 1;
+    bool defragmentationRequired = ShiftSiblingsLevels( *siblings, mSiblingOrder );
+
+    SetSiblingOrder( mSiblingOrder );
+
+    if ( defragmentationRequired )
+    {
+      DefragmentSiblingIndexes( *(mParent->mChildren) );
+    }
+  }
+}
+
+void Actor::LowerBelow( Dali::Actor target )
+{
+  /**
+     1 ) a) Find target actor's sibling order
+         b) If sibling order of target is the same as this actor then need to this Actor's sibling order
+            needs to be below it or the insertion order will determine which is drawn on top.
+     2 ) Shift the target sibling order and all sibling orders at that level or above by 1
+     3 ) Set this actor to the sibling order of the target before it changed.
+     4 ) Sibling order levels have a maximum defined in DevelLayer::SIBLING_ORDER_MULTIPLIER
+         If shifting causes this ceiling to be reached. then a defragmentation can be performed to
+         remove any empty sibling order gaps and start from sibling level 0 again.
+         If the number of actors reaches this maximum and all using exclusive sibling order values then
+         defragmention will stop and new sibling orders will be set to same max value.
+   */
+
+  if ( this != target  )
+  {
+    bool defragmentationRequired ( false );
+    // Find target's sibling order
+    // Set actor sibling order to target sibling order - 1
+    int targetSiblingOrder = GetSiblingOrder( &GetImplementation( target ) );
+    ActorContainer* siblings = mParent->mChildren;
+    if ( targetSiblingOrder == 0 )
+    {
+      //lower to botton
+      ActorIter end = siblings->end();
+      for( ActorIter iter = siblings->begin(); ( iter != end ) ; ++iter )
+      {
+        ActorPtr sibling = (*iter);
+        if ( sibling != this )
+        {
+          sibling->mSiblingOrder++;
+          if ( sibling->mSiblingOrder + 1 >= DevelLayer::SIBLING_ORDER_MULTIPLIER )
+          {
+            defragmentationRequired = true;
+          }
+          sibling->SetSiblingOrder( sibling->mSiblingOrder );
+        }
+      }
+      mSiblingOrder = 0;
+    }
+    else
+    {
+      defragmentationRequired = ShiftSiblingsLevels( *siblings, targetSiblingOrder );
+
+      mSiblingOrder = targetSiblingOrder;
+    }
+    SetSiblingOrder( mSiblingOrder );
+
+    if ( defragmentationRequired )
+    {
+      DefragmentSiblingIndexes( *(mParent->mChildren) );
+    }
+  }
+}
+
 } // namespace Internal
 
 } // namespace Dali
index 0782565..9345f23 100644 (file)
@@ -1652,6 +1652,36 @@ public:
    */
   virtual int GetPropertyComponentIndex( Property::Index index ) const;
 
+  /**
+   * @copydoc Dali::DevelActor::Raise()
+   */
+  void Raise();
+
+  /**
+   * @copydoc Dali::DevelActor::Lower()
+   */
+  void Lower();
+
+  /**
+   * @copydoc Dali::DevelActor::RaiseToTop()
+   */
+  void RaiseToTop();
+
+  /**
+   * @copydoc Dali::DevelActor::LowerToBottom()
+   */
+  void LowerToBottom();
+
+  /**
+   * @copydoc Dali::DevelActor::RaiseAbove()
+   */
+  void RaiseAbove( Dali::Actor target );
+
+  /**
+   * @copydoc Dali::DevelActor::LowerBelow()
+   */
+  void LowerBelow( Dali::Actor target );
+
 private:
 
   // Undefined
@@ -1793,6 +1823,30 @@ private:
    */
   virtual Object* GetParentObject() const;
 
+  /**
+   * Set Sibling order
+   * @param[in] order The sibling order this Actor should be
+   */
+  void SetSiblingOrder( unsigned int order);
+
+  /**
+   * @brief Re-orders the sibling order when any actor raised to the max level
+   * @param[in] siblings the container of sibling actors
+   */
+  void DefragmentSiblingIndexes( ActorContainer& siblings );
+
+  /**
+   * @brief Shifts all siblings levels from the target level up by 1 to make space for a newly insert sibling
+   * at an exclusive level.
+   *
+   * @note Used with Raise and Lower API
+   *
+   * @param[in] siblings the actor container of the siblings
+   * @param[in] targetLevelToShiftFrom the sibling level to start shifting from
+   */
+  bool ShiftSiblingsLevels( ActorContainer& siblings, int targetLevelToShiftFrom );
+
+
 protected:
 
   Actor* mParent;                 ///< Each actor (except the root) can have one parent