From 6d08ede3a8e9fcfd9c4ca23f5d3fb9b35357f0a4 Mon Sep 17 00:00:00 2001 From: Joogab Yun Date: Tue, 6 Oct 2020 15:38:33 +0900 Subject: [PATCH] Add intercept touch event The Touch event calls the TouchEvent callback by going back from the last child actor to the parent via hitTest. InterceptTouchEvent checks the touch event in the parent first. Returning false from interceptTouchEvent allows child actors to receive TouchEvents. If it returns true, the actor will receive a TouchEvent. for example Actor parent = Actor::New(); Actor actor = Actor::New(); parent.Add(actor); actor.TouchedSignal().Connect(&application, functor); parent.TouchedSignal().Connect(&application, parentFunctor); The callbacks are called in the order functor -> parentFunctor. If you connect interceptTouchSignal to parentActor. Dali::DevelActor::InterceptTouchedSignal(parent).Connect(&application, interceptFunctor); When interceptFunctor returns false, it is called in the same order functor -> parentFunctor. If it returns true, it means that the TouchEvent was intercepted. So the child actor will not be able to receive touch events. Only the parentFunctor is called. Change-Id: Ib6887adbcee59168a7caf7f36bcc400500c626e8 --- .../src/dali/utc-Dali-TouchProcessing.cpp | 53 +++++++++++++++++++ dali/devel-api/actors/actor-devel.cpp | 5 ++ dali/devel-api/actors/actor-devel.h | 34 ++++++++++++ dali/internal/event/actors/actor-impl.cpp | 6 +++ dali/internal/event/actors/actor-impl.h | 26 +++++++++ .../event/events/touch-event-processor.cpp | 41 +++++++++++++- 6 files changed, 164 insertions(+), 1 deletion(-) mode change 100644 => 100755 automated-tests/src/dali/utc-Dali-TouchProcessing.cpp mode change 100644 => 100755 dali/devel-api/actors/actor-devel.cpp mode change 100644 => 100755 dali/devel-api/actors/actor-devel.h mode change 100644 => 100755 dali/internal/event/actors/actor-impl.cpp mode change 100644 => 100755 dali/internal/event/actors/actor-impl.h mode change 100644 => 100755 dali/internal/event/events/touch-event-processor.cpp diff --git a/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp b/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp old mode 100644 new mode 100755 index 2aaf3e261..3c01346e3 --- a/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp +++ b/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp @@ -2068,3 +2068,56 @@ int UtcDaliTouchEventIntegNewTouchEvent(void) END_TEST; } + + +int UtcDaliTouchEventIntercept(void) +{ + TestApplication application; + + Actor parent = Actor::New(); + parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + application.GetScene().Add(parent); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + parent.Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Connect to actor's touched signal + SignalData data; + TouchEventFunctor functor(data, false /* Do not consume */); + actor.TouchedSignal().Connect(&application, functor); + + + // Connect to parent's touched signal + SignalData parentData; + TouchEventFunctor parentFunctor(parentData, false /* Do not consume */); + parent.TouchedSignal().Connect(&application, parentFunctor); + // Connect to parent's intercept touched signal + SignalData interceptData; + TouchEventFunctor interceptFunctor(interceptData, true /* Do intercept */); + Dali::DevelActor::InterceptTouchedSignal(parent).Connect(&application, interceptFunctor); + + // Emit a down signal + application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); + // The actor touched signal is not called because the touch is intercepted in the parent. + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(true, interceptData.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::DOWN, interceptData.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_CHECK(actor == interceptData.receivedTouch.points[0].hitActor); + DALI_TEST_CHECK(parent == interceptData.touchedActor); + DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::DOWN, parentData.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor); + DALI_TEST_CHECK(parent == parentData.touchedActor); + data.Reset(); + parentData.Reset(); + + END_TEST; +} + diff --git a/dali/devel-api/actors/actor-devel.cpp b/dali/devel-api/actors/actor-devel.cpp old mode 100644 new mode 100755 index 68a5205c1..fd0843467 --- a/dali/devel-api/actors/actor-devel.cpp +++ b/dali/devel-api/actors/actor-devel.cpp @@ -48,6 +48,11 @@ ChildOrderChangedSignalType& ChildOrderChangedSignal(Actor actor) return GetImplementation(actor).ChildOrderChangedSignal(); } +Actor::TouchEventSignalType& InterceptTouchedSignal(Actor actor) +{ + return GetImplementation(actor).InterceptTouchedSignal(); +} + } // namespace DevelActor } // namespace Dali diff --git a/dali/devel-api/actors/actor-devel.h b/dali/devel-api/actors/actor-devel.h old mode 100644 new mode 100755 index 43b44f75e..cda374f6b --- a/dali/devel-api/actors/actor-devel.h +++ b/dali/devel-api/actors/actor-devel.h @@ -215,6 +215,40 @@ using ChildOrderChangedSignalType = Signal; ///< Used when the acto */ DALI_CORE_API ChildOrderChangedSignalType& ChildOrderChangedSignal(Actor actor); +/** + * @brief This signal is emitted when intercepting the actor's touch event. + * + * A callback of the following type may be connected: + * @code + * void MyCallbackName( Actor actor ); + * @endcode + * actor The actor to intercept + * + * @note TouchEvent callbacks are called from the last child in the order of the parent's actor. + * The InterceptTouchEvent callback is to intercept the touch event in the parent. + * So, if the parent interepts the touch event, the child cannot receive the touch event. + * + * @note example + * Actor parent = Actor::New(); + * Actor child = Actor::New(); + * parent.Add(child); + * child.TouchedSignal().Connect(&application, childFunctor); + * parent.TouchedSignal().Connect(&application, parentFunctor); + * The touch event callbacks are called in the order childFunctor -> parentFunctor. + * + * If you connect interceptTouchSignal to parentActor. + * Dali::DevelActor::InterceptTouchedSignal(parent).Connect(&application, interceptFunctor); + * + * When interceptFunctor returns false, the touch event callbacks are called in the same order childFunctor -> parentFunctor. + * If interceptFunctor returns true, it means that the TouchEvent was intercepted. + * So the child actor will not be able to receive touch events. + * Only the parentFunctor is called. + * + * @return The signal to connect to + * @pre The Actor has been initialized + */ +DALI_CORE_API Actor::TouchEventSignalType& InterceptTouchedSignal(Actor actor); + } // namespace DevelActor } // namespace Dali diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp old mode 100644 new mode 100755 index 321b11116..0e0342da6 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -1319,6 +1319,11 @@ bool Actor::IsGestureRequired( GestureType::Value type ) const return mGestureData && mGestureData->IsGestureRequired( type ); } +bool Actor::EmitInterceptTouchEventSignal( const Dali::TouchEvent& touch ) +{ + return EmitConsumingSignal( *this, mInterceptTouchedSignal, touch ); +} + bool Actor::EmitTouchEventSignal( const Dali::TouchEvent& touch ) { return EmitConsumingSignal( *this, mTouchedSignal, touch ); @@ -1418,6 +1423,7 @@ Actor::Actor( DerivedType derivedType, const SceneGraph::Node& node ) mAnchorPoint( nullptr ), mRelayoutData( nullptr ), mGestureData( nullptr ), + mInterceptTouchedSignal(), mTouchedSignal(), mHoveredSignal(), mWheelEventSignal(), diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h old mode 100644 new mode 100755 index 5a11cd074..a982904b6 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -1326,6 +1326,16 @@ public: return mKeyboardFocusable; } + + /** + * Query whether the application or derived actor type requires intercept touch events. + * @return True if intercept touch events are required. + */ + bool GetInterceptTouchRequired() const + { + return !mInterceptTouchedSignal.Empty(); + } + /** * Query whether the application or derived actor type requires touch events. * @return True if touch events are required. @@ -1393,6 +1403,13 @@ public: // Signals + /** + * Used by the EventProcessor to emit intercept touch event signals. + * @param[in] touch The touch data. + * @return True if the event was intercepted. + */ + bool EmitInterceptTouchEventSignal( const Dali::TouchEvent& touch ); + /** * Used by the EventProcessor to emit touch event signals. * @param[in] touch The touch data. @@ -1439,6 +1456,14 @@ public: */ void EmitChildRemovedSignal( Actor& child ); + /** + * @copydoc DevelActor::InterceptTouchedSignal() + */ + Dali::Actor::TouchEventSignalType& InterceptTouchedSignal() + { + return mInterceptTouchedSignal; + } + /** * @copydoc Dali::Actor::TouchedSignal() */ @@ -1982,6 +2007,7 @@ protected: ActorGestureData* mGestureData; ///< Optional Gesture data. Only created when actor requires gestures // Signals + Dali::Actor::TouchEventSignalType mInterceptTouchedSignal; Dali::Actor::TouchEventSignalType mTouchedSignal; Dali::Actor::HoverSignalType mHoveredSignal; Dali::Actor::WheelEventSignalType mWheelEventSignal; diff --git a/dali/internal/event/events/touch-event-processor.cpp b/dali/internal/event/events/touch-event-processor.cpp old mode 100644 new mode 100755 index 864ce8c9d..146387cbe --- a/dali/internal/event/events/touch-event-processor.cpp +++ b/dali/internal/event/events/touch-event-processor.cpp @@ -60,6 +60,36 @@ const char * TOUCH_POINT_STATE[ 6 ] = #endif // defined(DEBUG_ENABLED) +Dali::Actor EmitInterceptTouchSignals( Dali::Actor actor, const Dali::TouchEvent& touchEvent ) +{ + Dali::Actor interceptedActor; + + if( actor ) + { + Dali::Actor parent = actor.GetParent(); + if( parent ) + { + // Recursively deliver events to the actor and its parents for intercept touch event. + interceptedActor = EmitInterceptTouchSignals( parent, touchEvent ); + } + + if( !interceptedActor ) + { + bool intercepted = false; + Actor& actorImpl( GetImplementation(actor) ); + if( actorImpl.GetInterceptTouchRequired() ) + { + intercepted = actorImpl.EmitInterceptTouchEventSignal( touchEvent ); + if( intercepted ) + { + interceptedActor = Dali::Actor( &actorImpl ); + } + } + } + } + + return interceptedActor; +} /** * Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached. @@ -315,7 +345,16 @@ bool TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even Dali::Actor consumedActor; if ( currentRenderTask ) { - consumedActor = EmitTouchSignals( touchEventImpl->GetPoint( 0 ).GetHitActor(), touchEventHandle ); + // Emit the intercept touch signal + Dali::Actor interceptedActor = EmitInterceptTouchSignals( touchEventImpl->GetPoint( 0 ).GetHitActor(), touchEventHandle ); + if( interceptedActor ) + { + consumedActor = EmitTouchSignals( interceptedActor, touchEventHandle ); + } + else + { + consumedActor = EmitTouchSignals( touchEventImpl->GetPoint( 0 ).GetHitActor(), touchEventHandle ); + } consumed = consumedActor ? true : false; } -- 2.34.1