Added Visibility Change Signal & added macro to print meaningful line numbers in... 59/126459/4
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 21 Apr 2017 11:44:33 +0000 (12:44 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 21 Apr 2017 13:57:11 +0000 (14:57 +0100)
Change-Id: I4120f711f78446153cb9552018f4fc1d6e3ddfd3

automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h
automated-tests/src/dali/utc-Dali-Actor.cpp
dali/devel-api/actors/actor-devel.cpp
dali/devel-api/actors/actor-devel.h
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h

index 03c788c..2b84d39 100644 (file)
@@ -23,6 +23,7 @@
 #include <cstdio>
 #include <iostream>
 #include <cstring>
+#include <string>
 
 // INTERNAL INCLUDES
 #include <dali/public-api/dali-core.h>
@@ -44,6 +45,7 @@ using namespace Dali;
 #define TOKENPASTE(x,y) x y
 #define TOKENPASTE2(x,y) TOKENPASTE( x, y )
 #define TEST_LOCATION TOKENPASTE2( "Test failed in ", TOKENPASTE2( __FILE__, TOKENPASTE2( ", line ", STRINGIZE(__LINE__) ) ) )
+#define TEST_INNER_LOCATION(x) ( std::string(x) + " (" + STRINGIZE(__LINE__) + ")" ).c_str()
 
 #define TET_UNDEF 2
 #define TET_FAIL 1
index 0009ca7..c636758 100644 (file)
@@ -177,6 +177,58 @@ void OnRelayoutCallback( Actor actor )
   gActorNamesRelayout.push_back( actor.GetName() );
 }
 
+struct VisibilityChangedFunctorData
+{
+  VisibilityChangedFunctorData()
+  : actor(),
+    visible( false ),
+    type( DevelActor::VisibilityChange::SELF ),
+    called( false )
+  {
+  }
+
+  void Reset()
+  {
+    actor.Reset();
+    visible = false;
+    type = DevelActor::VisibilityChange::SELF;
+    called = false;
+  }
+
+  void Check( bool compareCalled, Actor compareActor, bool compareVisible, DevelActor::VisibilityChange::Type compareType, const char * location )
+  {
+    DALI_TEST_EQUALS( called, compareCalled, TEST_INNER_LOCATION( location ) );
+    DALI_TEST_EQUALS( actor, compareActor, TEST_INNER_LOCATION( location ) );
+    DALI_TEST_EQUALS( visible, compareVisible, TEST_INNER_LOCATION( location ) );
+    DALI_TEST_EQUALS( (int)type, (int)compareType, TEST_INNER_LOCATION( location ) );
+  }
+
+  void Check( bool compareCalled, const std::string& location )
+  {
+    DALI_TEST_EQUALS( called, compareCalled, TEST_INNER_LOCATION( location ) );
+  }
+
+  Actor actor;
+  bool visible;
+  DevelActor::VisibilityChange::Type type;
+  bool called;
+};
+
+struct VisibilityChangedFunctor
+{
+  VisibilityChangedFunctor( VisibilityChangedFunctorData& dataVar ) : data( dataVar ) { }
+
+  void operator()( Actor actor, bool visible, DevelActor::VisibilityChange::Type type )
+  {
+    data.actor = actor;
+    data.visible = visible;
+    data.type = type;
+    data.called = true;
+  }
+
+  VisibilityChangedFunctorData& data;
+};
+
 } // anonymous namespace
 
 
@@ -5790,3 +5842,86 @@ int utcDaliActorPositionUsesAnchorPointOnlyInheritPosition(void)
   END_TEST;
 }
 
+int utcDaliActorVisibilityChangeSignalSelf(void)
+{
+  TestApplication application;
+  tet_infoline( "Check that the visibility change signal is called when the visibility changes for the actor itself" );
+
+  Actor actor = Actor::New();
+
+  VisibilityChangedFunctorData data;
+  DevelActor::VisibilityChangedSignal( actor ).Connect( &application, VisibilityChangedFunctor( data ) );
+
+  actor.SetVisible( false );
+
+  data.Check( true /* called */, actor, false /* not visible */, DevelActor::VisibilityChange::SELF, TEST_LOCATION );
+
+  tet_infoline( "Ensure functor is not called if we attempt to change the visibility to what it already is at" );
+  data.Reset();
+
+  actor.SetVisible( false );
+  data.Check( false /* not called */, TEST_LOCATION );
+
+  tet_infoline( "Change the visibility using properties, ensure called" );
+  data.Reset();
+
+  actor.SetProperty( Actor::Property::VISIBLE, true );
+  data.Check( true /* called */, actor, true /* visible */, DevelActor::VisibilityChange::SELF, TEST_LOCATION );
+
+  tet_infoline( "Set the visibility to current using properties, ensure not called" );
+  data.Reset();
+
+  actor.SetProperty( Actor::Property::VISIBLE, true );
+  data.Check( false /* not called */, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliActorVisibilityChangeSignalChildren(void)
+{
+  TestApplication application;
+  tet_infoline( "Check that the visibility change signal is called for the children when the visibility changes for the parent" );
+
+  Actor parent = Actor::New();
+  Actor child = Actor::New();
+  parent.Add( child );
+
+  Actor grandChild = Actor::New();
+  child.Add( grandChild );
+
+  VisibilityChangedFunctorData parentData;
+  VisibilityChangedFunctorData childData;
+  VisibilityChangedFunctorData grandChildData;
+
+  tet_infoline( "Only connect the child and grandchild, ensure they are called and not the parent" );
+  DevelActor::VisibilityChangedSignal( child ).Connect( &application, VisibilityChangedFunctor( childData ) );
+  DevelActor::VisibilityChangedSignal( grandChild ).Connect( &application, VisibilityChangedFunctor( grandChildData ) );
+
+  parent.SetVisible( false );
+  parentData.Check( false /* not called */, TEST_LOCATION );
+  childData.Check( true /* called */, child, false /* not visible */, DevelActor::VisibilityChange::PARENT, TEST_LOCATION );
+  grandChildData.Check( true /* called */, grandChild, false /* not visible */, DevelActor::VisibilityChange::PARENT, TEST_LOCATION );
+
+  tet_infoline( "Connect to the parent's signal as well and ensure all three are called" );
+  parentData.Reset();
+  childData.Reset();
+  grandChildData.Reset();
+
+  DevelActor::VisibilityChangedSignal( parent ).Connect( &application, VisibilityChangedFunctor( parentData ) );
+
+  parent.SetVisible( true );
+  parentData.Check( true /* called */, parent, true /* visible */, DevelActor::VisibilityChange::SELF, TEST_LOCATION );
+  childData.Check( true /* called */, child, true /* visible */, DevelActor::VisibilityChange::PARENT, TEST_LOCATION );
+  grandChildData.Check( true /* called */, grandChild, true /* visible */, DevelActor::VisibilityChange::PARENT, TEST_LOCATION );
+
+  tet_infoline( "Ensure none of the functors are called if we attempt to change the visibility to what it already is at" );
+  parentData.Reset();
+  childData.Reset();
+  grandChildData.Reset();
+
+  parent.SetVisible( true );
+  parentData.Check( false /* not called */, TEST_LOCATION );
+  childData.Check( false /* not called */, TEST_LOCATION );
+  grandChildData.Check( false /* not called */, TEST_LOCATION );
+
+  END_TEST;}
index d61216c..38f081e 100644 (file)
@@ -55,6 +55,11 @@ void LowerBelow( Actor actor, Actor target )
   GetImplementation( actor ).LowerBelow( GetImplementation( target ) );
 }
 
+VisibilityChangedSignalType& VisibilityChangedSignal( Actor actor )
+{
+  return GetImplementation( actor ).VisibilityChangedSignal();
+}
+
 } // namespace DevelActor
 
 } // namespace Dali
index 1f0192b..58d0d5d 100644 (file)
@@ -121,6 +121,19 @@ enum Type
 
 } // namespace Property
 
+namespace VisibilityChange
+{
+
+enum Type
+{
+  SELF,   ///< The visibility of the actor itself has changed.
+  PARENT  ///< The visibility of a parent has changed.
+};
+
+} // namespace VisibilityChange
+
+typedef Signal< void ( Actor, bool, VisibilityChange::Type ) > VisibilityChangedSignalType; ///< Signal type of VisibilityChangedSignal
+
 /**
  * @brief Raise actor above the next highest level of actor(s).
  *
@@ -190,6 +203,22 @@ DALI_IMPORT_API void RaiseAbove( Actor actor, Dali::Actor target );
  */
 DALI_IMPORT_API void LowerBelow( Actor actor, Dali::Actor target );
 
+/**
+ * @brief This signal is emitted when the visible property of this or a parent actor is changed.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( Actor actor, bool visible, VisibilityChange::Type& type );
+ * @endcode
+ * actor: The actor, or child of actor, whose visibility has changed
+ * visible: Whether the actor is now visible or not
+ * type: Whether the actor's visible property has changed or a parent's.
+ * @return The signal to connect to
+ * @pre The Actor has been initialized.
+ * @note This signal is NOT emitted if the actor becomes transparent (or the reverse), it's only linked with Actor::Property::VISIBLE.
+ */
+DALI_IMPORT_API VisibilityChangedSignalType& VisibilityChangedSignal( Actor actor );
+
 } // namespace DevelActor
 
 } // namespace Dali
index e24b229..8ba7790 100644 (file)
@@ -390,6 +390,29 @@ unsigned int GetDepthIndex( uint16_t depth, uint16_t siblingOrder )
   return depth * Dali::DevelLayer::ACTOR_DEPTH_MULTIPLIER + siblingOrder * Dali::DevelLayer::SIBLING_ORDER_MULTIPLIER;
 }
 
+/**
+ * @brief Recursively emits the visibility-changed-signal on the actor tree.
+ * @param[in] actor The actor to emit the signal on
+ * @param[in] visible The new visibility of the actor
+ * @param[in] type Whether the actor's visible property has changed or a parent's
+ */
+void EmitVisibilityChangedSignalRecursively( ActorPtr actor, bool visible, DevelActor::VisibilityChange::Type type )
+{
+  if( actor )
+  {
+    actor->EmitVisibilityChangedSignal( visible, type );
+
+    if( actor->GetChildCount() > 0 )
+    {
+      ActorContainer& children = actor->GetChildrenInternal();
+      for( ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter )
+      {
+        EmitVisibilityChangedSignalRecursively( *iter, visible, DevelActor::VisibilityChange::PARENT );
+      }
+    }
+  }
+}
+
 } // unnamed namespace
 
 ActorPtr Actor::New()
@@ -1020,10 +1043,18 @@ Matrix Actor::GetCurrentWorldMatrix() const
 
 void Actor::SetVisible( bool visible )
 {
-  if( NULL != mNode )
+  if( mVisible != visible )
   {
-    // mNode is being used in a separate thread; queue a message to set the value & base value
-    SceneGraph::NodePropertyMessage<bool>::Send( GetEventThreadServices(), mNode, &mNode->mVisible, &AnimatableProperty<bool>::Bake, visible );
+    if( NULL != mNode )
+    {
+      // mNode is being used in a separate thread; queue a message to set the value & base value
+      SceneGraph::NodePropertyMessage<bool>::Send( GetEventThreadServices(), mNode, &mNode->mVisible, &AnimatableProperty<bool>::Bake, visible );
+    }
+
+    mVisible = visible;
+
+    // Emit the signal on this actor and all its children
+    EmitVisibilityChangedSignalRecursively( this, visible, DevelActor::VisibilityChange::SELF );
   }
 }
 
@@ -1981,6 +2012,15 @@ bool Actor::EmitWheelEventSignal( const WheelEvent& event )
   return consumed;
 }
 
+void Actor::EmitVisibilityChangedSignal( bool visible, DevelActor::VisibilityChange::Type type )
+{
+  if( ! mVisibilityChangedSignal.Empty() )
+  {
+    Dali::Actor handle( this );
+    mVisibilityChangedSignal.Emit( handle, visible, type );
+  }
+}
+
 Dali::Actor::TouchSignalType& Actor::TouchedSignal()
 {
   return mTouchedSignal;
@@ -2016,6 +2056,11 @@ Dali::Actor::OnRelayoutSignalType& Actor::OnRelayoutSignal()
   return mOnRelayoutSignal;
 }
 
+DevelActor::VisibilityChangedSignalType& Actor::VisibilityChangedSignal()
+{
+  return mVisibilityChangedSignal;
+}
+
 bool Actor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
 {
   bool connected( true );
@@ -2087,6 +2132,7 @@ Actor::Actor( DerivedType derivedType )
   mInheritOrientation( true ),
   mInheritScale( true ),
   mPositionUsesAnchorPoint( true ),
+  mVisible( true ),
   mDrawMode( DrawMode::NORMAL ),
   mPositionInheritanceMode( Node::DEFAULT_POSITION_INHERITANCE_MODE ),
   mColorMode( Node::DEFAULT_COLOR_MODE ),
index c9c78f9..23d4fb0 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/actors/actor.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/events/gesture.h>
@@ -210,6 +211,7 @@ public:
    * Retrieve a reference to Actor's children.
    * @note Not for public use.
    * @return A reference to the container of children.
+   * @note The internal container is lazily initialized so ensure you check the child count before using the value returned by this method.
    */
   ActorContainer& GetChildrenInternal()
   {
@@ -1388,6 +1390,13 @@ public:
   bool EmitWheelEventSignal( const WheelEvent& event );
 
   /**
+   * @brief Emits the visibility change signal for this actor and all its children.
+   * @param[in] visible Whether the actor has become visible or not.
+   * @param[in] type Whether the actor's visible property has changed or a parent's.
+   */
+  void EmitVisibilityChangedSignal( bool visible, DevelActor::VisibilityChange::Type type );
+
+  /**
    * @copydoc Dali::Actor::TouchedSignal()
    */
   Dali::Actor::TouchSignalType& TouchedSignal();
@@ -1423,6 +1432,11 @@ public:
   Dali::Actor::OnRelayoutSignalType& OnRelayoutSignal();
 
   /**
+   * @copydoc DevelActor::VisibilityChangedSignal
+   */
+  DevelActor::VisibilityChangedSignalType& VisibilityChangedSignal();
+
+  /**
    * Connects a callback function with the object's signals.
    * @param[in] object The object providing the signal.
    * @param[in] tracker Used to disconnect the signal.
@@ -1857,7 +1871,7 @@ private:
 protected:
 
   Actor* mParent;                 ///< Each actor (except the root) can have one parent
-  ActorContainer* mChildren;      ///< Container of referenced actors
+  ActorContainer* mChildren;      ///< Container of referenced actors, lazily initialized
   RendererContainer* mRenderers;   ///< Renderer container
 
   const SceneGraph::Node* mNode;  ///< Not owned
@@ -1877,6 +1891,7 @@ protected:
   Dali::Actor::OnStageSignalType           mOnStageSignal;
   Dali::Actor::OffStageSignalType          mOffStageSignal;
   Dali::Actor::OnRelayoutSignalType        mOnRelayoutSignal;
+  DevelActor::VisibilityChangedSignalType  mVisibilityChangedSignal;
 
   Vector3         mTargetSize;       ///< Event-side storage for size (not a pointer as most actors will have a size)
   Vector3         mTargetPosition;   ///< Event-side storage for position (not a pointer as most actors will have a position)
@@ -1902,6 +1917,7 @@ protected:
   bool mInheritOrientation                         : 1; ///< Cached: Whether the parent's orientation should be inherited.
   bool mInheritScale                               : 1; ///< Cached: Whether the parent's scale should be inherited.
   bool mPositionUsesAnchorPoint                    : 1; ///< Cached: Whether the position uses the anchor point or not.
+  bool mVisible                                    : 1; ///< Cached: Whether the actor is visible or not.
   DrawMode::Type mDrawMode                         : 2; ///< Cached: How the actor and its children should be drawn
   PositionInheritanceMode mPositionInheritanceMode : 2; ///< Cached: Determines how position is inherited
   ColorMode mColorMode                             : 2; ///< Cached: Determines whether mWorldColor is inherited