END_TEST;
}
+int UtcDaliActorCaptureAllTouchAfterStartPropertyP(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ DALI_TEST_EQUALS(actor.GetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START).Get<bool>(), false, TEST_LOCATION);
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, true);
+ DALI_TEST_EQUALS(actor.GetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START).Get<bool>(), true, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliActorCaptureAllTouchAfterStartPropertyN(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+
+ // Make sure setting invalid types does not cause a crash
+ try
+ {
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, 1.0f);
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, Vector2::ONE);
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, Vector3::ONE);
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, Vector4::ONE);
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, Property::Map());
+ actor.SetProperty(DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, Property::Array());
+ tet_result(TET_PASS);
+ }
+ catch(...)
+ {
+ tet_result(TET_FAIL);
+ }
+ END_TEST;
+}
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/render-task-list-integ.h>
#include <dali-test-suite-utils.h>
+#include <dali/devel-api/actors/actor-devel.h>
using namespace Dali;
END_TEST;
}
+int UtcDaliTouchDataCapturePropertySet(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetProperty( Actor::Property::SIZE, Vector2( 100.0f, 100.0f ) );
+ actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT);
+ application.GetScene().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Connect to actor's touched signal
+ SignalData data;
+ TouchDataFunctor functor( data );
+ actor.TouchSignal().Connect( &application, functor );
+
+ // Emit a down signal
+ application.ProcessEvent( GenerateSingleTouch( PointState::STARTED, Vector2( 10.0f, 10.0f ) ) );
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ data.Reset();
+
+ // Now motion outside of actor, we should not receive the event
+ application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, Vector2( 110.0f, 110.0f ) ) );
+ DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+ data.Reset();
+
+ // Up event, should receive an interrupted
+ application.ProcessEvent( GenerateSingleTouch( PointState::FINISHED, Vector2( 110.0f, 110.0f ) ) );
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ DALI_TEST_EQUALS( data.touchData.GetPoint(0).state, PointState::INTERRUPTED, TEST_LOCATION );
+
+ // Now set the capture property
+ actor.SetProperty( DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START, true);
+
+ // Emit a down signal
+ application.ProcessEvent( GenerateSingleTouch( PointState::STARTED, Vector2( 10.0f, 10.0f ) ) );
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ data.Reset();
+
+ // Now motion outside of actor, we now SHOULD receive the event
+ application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, Vector2( 110.0f, 110.0f ) ) );
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ data.Reset();
+
+ // Up event, we should receive it again, but as ended rather than interrupted
+ application.ProcessEvent( GenerateSingleTouch( PointState::FINISHED, Vector2( 110.0f, 110.0f ) ) );
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ DALI_TEST_EQUALS( data.touchData.GetPoint(0).state, PointState::FINISHED, TEST_LOCATION );
+
+ END_TEST;
+}
* @note Raise, Lower, RaiseToTop, LowerToBottom, RaiseAbove and LowerBelow will override the
* sibling order. The values set by this Property will likely change.
*/
- SIBLING_ORDER = KEYBOARD_FOCUSABLE + 1,
+ SIBLING_ORDER,
/**
* @brief Sets the update size hint of the actor.
* @details Name "updateSizeHint", type Property::VECTOR2.
* @note Overrides the size used for the actor damaged area calculation. Affected by the actor model view matrix.
*/
- UPDATE_SIZE_HINT = SIBLING_ORDER + 1,
+ UPDATE_SIZE_HINT,
+
+ /**
+ * @brief If this actor receives a touch-start event, then all following touch events are sent to this actor until a touch-end.
+ * @details Name "captureAllTouchAfterStart", type Property::BOOLEAN
+ * @note Default is false, i.e. actor under touch event will receive the touch even if touch started on this actor
+ */
+ CAPTURE_ALL_TOUCH_AFTER_START
};
} // namespace Property
DALI_PROPERTY( "keyboardFocusable", BOOLEAN, true, false, false, Dali::Actor::Property::KEYBOARD_FOCUSABLE )
DALI_PROPERTY( "siblingOrder", INTEGER, true, false, false, Dali::DevelActor::Property::SIBLING_ORDER )
DALI_PROPERTY( "updateSizeHint", VECTOR2, true, false, false, Dali::DevelActor::Property::UPDATE_SIZE_HINT )
+DALI_PROPERTY( "captureAllTouchAfterStart", VECTOR2, true, false, false, Dali::DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START )
DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX, ActorDefaultProperties )
// Signals
break;
}
+ case Dali::DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START:
+ {
+ bool boolValue = false;
+ if ( property.Get( boolValue ) )
+ {
+ mCaptureAllTouchAfterStart = boolValue;
+ }
+ break;
+ }
+
default:
{
// this can happen in the case of a non-animatable default property so just do nothing
break;
}
+ case Dali::DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START:
+ {
+ value = mCaptureAllTouchAfterStart;
+ break;
+ }
+
default:
{
// Must be a scene-graph only property
#define DALI_INTERNAL_ACTOR_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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.
*/
bool IsHittable() const;
+ /**
+ * Query whether the actor captures all touch after it starts even if touch leaves its boundary.
+ * @return true, if it captures all touch after start
+ */
+ bool CapturesAllTouchAfterStart() const
+ {
+ return mCaptureAllTouchAfterStart;
+ }
+
// Gestures
/**
bool mPositionUsesAnchorPoint : 1; ///< Cached: Whether the position uses the anchor point or not.
bool mVisible : 1; ///< Cached: Whether the actor is visible or not.
bool mInheritLayoutDirection : 1; ///< Whether the actor inherits the layout direction from parent.
+ bool mCaptureAllTouchAfterStart : 1; ///< Whether the actor should capture all touch after touch starts even if the motion moves outside of the actor area.
LayoutDirection::Type mLayoutDirection : 2; ///< Layout direction, Left to Right or Right to Left.
DrawMode::Type mDrawMode : 3; ///< Cached: How the actor and its children should be drawn
ColorMode mColorMode : 3; ///< Cached: Determines whether mWorldColor is inherited
return consumingActor;
}
+/**
+ * @brief Parses the primary touch point by performing a hit-test if necessary
+ *
+ * @param[out] hitTestResults The hit test results are put into this variable
+ * @param[in/out] capturingTouchActorObserver The observer for the capturing touch actor member
+ * @param[in] lastRenderTask The last render task member
+ * @param[in] currentPoint The current point information
+ * @param[in] scene The scene that this touch is related to
+ */
+void ParsePrimaryTouchPoint(
+ HitTestAlgorithm::Results& hitTestResults,
+ ActorObserver& capturingTouchActorObserver,
+ const RenderTaskPtr& lastRenderTask,
+ const Integration::Point& currentPoint,
+ const Internal::Scene& scene )
+{
+ Actor* capturingTouchActor = capturingTouchActorObserver.GetActor();
+
+ // We only set the capturing touch actor when the first touch-started actor captures all touch so if it's set, just use it
+ if( capturingTouchActor && lastRenderTask )
+ {
+ hitTestResults.actor = Dali::Actor( capturingTouchActor );
+ hitTestResults.renderTask = lastRenderTask;
+ const Vector2& screenPosition = currentPoint.GetScreenPosition();
+ capturingTouchActor->ScreenToLocal( *lastRenderTask, hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y, screenPosition.x, screenPosition.y );
+ }
+ else
+ {
+ HitTestAlgorithm::HitTest( scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults );
+
+ if( currentPoint.GetState() == PointState::STARTED && hitTestResults.actor )
+ {
+ // If we've just started touch, then check whether the actor has requested to capture all touch events
+ Actor* hitActor = &GetImplementation( hitTestResults.actor );
+ if( hitActor->CapturesAllTouchAfterStart() )
+ {
+ capturingTouchActorObserver.SetActor( hitActor );
+ }
+ }
+ }
+}
+
} // unnamed namespace
TouchEventProcessor::TouchEventProcessor( Scene& scene )
: mScene( scene ),
mLastPrimaryHitActor( MakeCallback( this, &TouchEventProcessor::OnObservedActorDisconnected ) ),
mLastConsumedActor(),
+ mCapturingTouchActor(),
mTouchDownConsumedActor(),
mLastRenderTask()
{
AllocAndEmitTouchSignals( event.time, touchDownConsumedActorHandle, currentPoint );
}
- mLastPrimaryHitActor.SetActor( NULL );
- mLastConsumedActor.SetActor( NULL );
- mTouchDownConsumedActor.SetActor( NULL );
+ mLastPrimaryHitActor.SetActor( nullptr );
+ mLastConsumedActor.SetActor( nullptr );
+ mCapturingTouchActor.SetActor( nullptr );
+ mTouchDownConsumedActor.SetActor( nullptr );
mLastRenderTask.Reset();
currentPoint.SetHitActor( Dali::Actor() );
DALI_LOG_INFO( gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount() );
RenderTaskPtr currentRenderTask;
+ bool firstPointParsed = false;
- for ( Integration::PointContainerConstIterator iter = event.points.begin(), beginIter = event.points.begin(), endIter = event.points.end(); iter != endIter; ++iter )
+ for ( auto&& currentPoint : event.points )
{
HitTestAlgorithm::Results hitTestResults;
- HitTestAlgorithm::HitTest( mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), iter->GetScreenPosition(), hitTestResults );
+ if( !firstPointParsed )
+ {
+ firstPointParsed = true;
+ ParsePrimaryTouchPoint( hitTestResults, mCapturingTouchActor, mLastRenderTask, currentPoint, mScene );
+
+ // Only set the currentRenderTask for the primary hit actor.
+ currentRenderTask = hitTestResults.renderTask;
+ }
+ else
+ {
+ HitTestAlgorithm::HitTest( mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults );
+ }
- Integration::Point newPoint( *iter );
+ Integration::Point newPoint( currentPoint );
newPoint.SetHitActor( hitTestResults.actor );
newPoint.SetLocalPosition( hitTestResults.actorCoordinates );
touchData->AddPoint( newPoint );
DALI_LOG_INFO( gLogFilter, Debug::General, " State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n",
- TOUCH_POINT_STATE[iter->GetState()], iter->GetScreenPosition().x, iter->GetScreenPosition().y,
+ TOUCH_POINT_STATE[currentPoint.GetState()], currentPoint.GetScreenPosition().x, currentPoint.GetScreenPosition().y,
( hitTestResults.actor ? reinterpret_cast< void* >( &hitTestResults.actor.GetBaseObject() ) : NULL ),
( hitTestResults.actor ? hitTestResults.actor.GetProperty< std::string >( Dali::Actor::Property::NAME ).c_str() : "" ),
hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y );
- // Only set the currentRenderTask for the primary hit actor.
- if ( iter == beginIter && hitTestResults.renderTask )
- {
- currentRenderTask = hitTestResults.renderTask;
- }
}
// 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
if ( primaryPointState == PointState::UP )
{
- mLastPrimaryHitActor.SetActor( NULL );
- mLastConsumedActor.SetActor( NULL );
+ mLastPrimaryHitActor.SetActor( nullptr );
+ mLastConsumedActor.SetActor( nullptr );
+ mCapturingTouchActor.SetActor( nullptr );
mLastRenderTask.Reset();
}
else
}
else
{
- mLastPrimaryHitActor.SetActor( NULL );
- mLastConsumedActor.SetActor( NULL );
+ mLastPrimaryHitActor.SetActor( nullptr );
+ mLastConsumedActor.SetActor( nullptr );
+ mCapturingTouchActor.SetActor( nullptr );
mLastRenderTask.Reset();
}
}
#define DALI_INTERNAL_TOUCH_EVENT_PROCESSOR_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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.
ActorObserver mLastPrimaryHitActor; ///< Stores the last primary point hit actor
ActorObserver mLastConsumedActor; ///< Stores the last consumed actor
+ ActorObserver mCapturingTouchActor; ///< Stored the actor that captures touch
ActorObserver mTouchDownConsumedActor; ///< Stores the touch-down consumed actor
RenderTaskPtr mLastRenderTask; ///< The RenderTask used for the last hit actor
};