#include <cstdio>
#include <iostream>
#include <cstring>
+#include <string>
// INTERNAL INCLUDES
#include <dali/public-api/dali-core.h>
#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
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
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;}
GetImplementation( actor ).LowerBelow( GetImplementation( target ) );
}
+VisibilityChangedSignalType& VisibilityChangedSignal( Actor actor )
+{
+ return GetImplementation( actor ).VisibilityChangedSignal();
+}
+
} // namespace DevelActor
} // namespace Dali
} // 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).
*
*/
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
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()
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 );
}
}
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;
return mOnRelayoutSignal;
}
+DevelActor::VisibilityChangedSignalType& Actor::VisibilityChangedSignal()
+{
+ return mVisibilityChangedSignal;
+}
+
bool Actor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
{
bool connected( true );
mInheritOrientation( true ),
mInheritScale( true ),
mPositionUsesAnchorPoint( true ),
+ mVisible( true ),
mDrawMode( DrawMode::NORMAL ),
mPositionInheritanceMode( Node::DEFAULT_POSITION_INHERITANCE_MODE ),
mColorMode( Node::DEFAULT_COLOR_MODE ),
// 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>
* 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()
{
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();
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.
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
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)
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