utc-Dali-RenderTask.cpp
utc-Dali-RenderTaskList.cpp
utc-Dali-ResourceImage.cpp
+ utc-Dali-RotationGesture.cpp
+ utc-Dali-RotationGestureDetector.cpp
utc-Dali-Sampler.cpp
utc-Dali-Scene.cpp
utc-Dali-Scripting.cpp
application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( x1, y1 ), PointState::UP, Vector2( x2, y2 ), time_down + 20 ) );
}
+void TestGenerateRotation( TestApplication& application )
+{
+ application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), PointState::DOWN, Vector2( 20.0f, 90.0f ), 150 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 25.0f, 95.0f ), 160 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 30.0f, 100.0f ), 170 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 35.0f, 105.0f ), 180 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 40.0f, 110.0f ), 190 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( 20.0f, 20.0f ), PointState::UP, Vector2( 45.0f, 115.0f ), 200 ) );
+}
+
+void TestStartRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+ application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, a1, PointState::DOWN, b1, time ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 50 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 150 ) );
+}
+
+void TestContinueRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time + 50 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time +150 ) );
+}
+
+void TestEndRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+ application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+ application.ProcessEvent( GenerateDoubleTouch( PointState::UP, a2, PointState::UP, b2, time +50 ) );
+}
+
} // namespace Dali
*/
void TestGenerateTwoPointTap( TestApplication& application, float x1, float y1, float x2, float y2, uint32_t time_down );
+/**
+ * Produces a rotation gesture.
+ */
+void TestGenerateRotation( TestApplication& application );
+
+/**
+ * Produces the gesture started event of a rotation, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestStartRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture continuing event of a rotation, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestContinueRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture finished event of a rotation, using 2 touches, 50ms apart
+ */
+void TestEndRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
} // namespace Dali
#endif // DALI_TEST_GESTURE_GENERATOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/events/gesture-devel.h>
+#include <dali/devel-api/events/rotation-gesture.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_rotation_gesture_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_rotation_gesture_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+// Positive test case for a method
+int UtcDaliRotationGestureConstructor(void)
+{
+ TestApplication application; // Reset all test adapter return codes
+
+ RotationGesture gesture(Gesture::Started);
+ DALI_TEST_EQUALS(Gesture::Started, gesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.0f, gesture.rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture.type ), TEST_LOCATION);
+
+ RotationGesture gesture2(Gesture::Continuing);
+ DALI_TEST_EQUALS(Gesture::Continuing, gesture2.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.0f, gesture2.rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture2.type ), TEST_LOCATION);
+
+ RotationGesture gesture3(Gesture::Finished);
+ DALI_TEST_EQUALS(Gesture::Finished, gesture3.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.0f, gesture3.rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture3.type ), TEST_LOCATION);
+
+ // Test copy constructor
+ gesture3.rotation = 3.0f;
+
+ RotationGesture rotation(gesture3);
+ DALI_TEST_EQUALS(Gesture::Finished, rotation.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(3.0f, rotation.rotation.radian, TEST_LOCATION);
+DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( rotation.type ), TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureAssignment(void)
+{
+ // Test Assignment operator
+ RotationGesture gesture(Gesture::Started);
+ DALI_TEST_EQUALS(Gesture::Started, gesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.0f, gesture.rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture.type ), TEST_LOCATION);
+
+ RotationGesture gesture2(Gesture::Continuing);
+ DALI_TEST_EQUALS(Gesture::Continuing, gesture2.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.0f, gesture2.rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture2.type ), TEST_LOCATION);
+
+ gesture2.rotation.radian = 3.0f;
+
+ gesture = gesture2;
+ DALI_TEST_EQUALS(Gesture::Continuing, gesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(3.0f, gesture.rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture.type ), TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureDynamicAllocation(void)
+{
+ RotationGesture* gesture = new RotationGesture( Gesture::Started );
+ DALI_TEST_EQUALS(Gesture::Started, gesture->state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.0f, gesture->rotation.radian, TEST_LOCATION);
+ DALI_TEST_EQUALS(DevelGesture::Rotation, static_cast< DevelGesture::Type >( gesture->type ), TEST_LOCATION);
+ delete gesture;
+
+ END_TEST;
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/render-task-list-integ.h>
+#include <dali/devel-api/events/gesture-devel.h>
+#include <dali/devel-api/events/rotation-gesture.h>
+#include <dali/devel-api/events/rotation-gesture-detector.h>
+#include <dali-test-suite-utils.h>
+#include <test-touch-utils.h>
+
+using namespace Dali;
+
+void utc_dali_rotation_gesture_detector_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_rotation_gesture_detector_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+namespace
+{
+
+// Stores data that is populated in the callback and will be read by the TET cases
+struct SignalData
+{
+ SignalData()
+ : functorCalled(false),
+ voidFunctorCalled(false),
+ receivedGesture(Gesture::Started)
+ {}
+
+ void Reset()
+ {
+ functorCalled = false;
+ voidFunctorCalled = false;
+
+ receivedGesture.state = Gesture::Started;
+ receivedGesture.rotation = 0.0f;
+ receivedGesture.screenCenterPoint = Vector2(0.0f, 0.0f);
+ receivedGesture.localCenterPoint = Vector2(0.0f, 0.0f);
+
+ rotatedActor.Reset();
+ }
+
+ bool functorCalled;
+ bool voidFunctorCalled;
+ RotationGesture receivedGesture;
+ Actor rotatedActor;
+};
+
+// Functor that sets the data when called
+struct GestureReceivedFunctor
+{
+ GestureReceivedFunctor(SignalData& data) : signalData(data) { }
+
+ void operator()(Actor actor, const RotationGesture& rotation)
+ {
+ signalData.functorCalled = true;
+ signalData.receivedGesture = rotation;
+ signalData.rotatedActor = actor;
+ }
+
+ void operator()()
+ {
+ signalData.voidFunctorCalled = true;
+ }
+
+ SignalData& signalData;
+};
+
+// Functor that removes the gestured actor from stage
+struct UnstageActorFunctor : public GestureReceivedFunctor
+{
+ UnstageActorFunctor( SignalData& data, Gesture::State& stateToUnstage )
+ : GestureReceivedFunctor( data ),
+ stateToUnstage( stateToUnstage )
+ {
+ }
+
+ void operator()( Actor actor, const RotationGesture& rotation )
+ {
+ GestureReceivedFunctor::operator()( actor, rotation );
+
+ if ( rotation.state == stateToUnstage )
+ {
+ Stage::GetCurrent().Remove( actor );
+ }
+ }
+
+ Gesture::State& stateToUnstage;
+};
+
+// Functor for receiving a touch event
+struct TouchEventFunctor
+{
+ bool operator()(Actor actor, const TouchEvent& touch)
+ {
+ return false;
+ }
+};
+
+} // anon namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliRotationGestureDetectorConstructor(void)
+{
+ TestApplication application;
+
+ RotationGestureDetector detector;
+ DALI_TEST_CHECK(!detector);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureDetectorCopyConstructorP(void)
+{
+ TestApplication application;
+
+ RotationGestureDetector detector = RotationGestureDetector::New();;
+
+ RotationGestureDetector copy( detector );
+ DALI_TEST_CHECK( detector );
+ END_TEST;
+}
+
+int UtcDaliRotationGestureDetectorAssignmentOperatorP(void)
+{
+ TestApplication application;
+
+ RotationGestureDetector detector = RotationGestureDetector::New();;
+
+ RotationGestureDetector assign;
+ assign = detector;
+ DALI_TEST_CHECK( detector );
+
+ DALI_TEST_CHECK( detector == assign );
+ END_TEST;
+}
+
+int UtcDaliRotationGestureDetectorNew(void)
+{
+ TestApplication application;
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+
+ DALI_TEST_CHECK(detector);
+
+ // Attach an actor and emit a touch event on the actor to ensure complete line coverage
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ detector.Attach(actor);
+
+ Integration::TouchEvent touchEvent(1);
+ Integration::Point point;
+ point.SetDeviceId( 1 );
+ point.SetState( PointState::DOWN );
+ point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+ touchEvent.AddPoint(point);
+ application.ProcessEvent(touchEvent);
+
+ Integration::Point point2;
+ point.SetDeviceId( 1 );
+ point.SetState( PointState::DOWN );
+ point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+ touchEvent.AddPoint(point2);
+ application.ProcessEvent(touchEvent);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureDetectorDownCast(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::RotationGestureDetector::DownCast()");
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+
+ BaseHandle object(detector);
+
+ RotationGestureDetector detector2 = RotationGestureDetector::DownCast(object);
+ DALI_TEST_CHECK(detector2);
+
+ RotationGestureDetector detector3 = DownCast< RotationGestureDetector >(object);
+ DALI_TEST_CHECK(detector3);
+
+ BaseHandle unInitializedObject;
+ RotationGestureDetector detector4 = RotationGestureDetector::DownCast(unInitializedObject);
+ DALI_TEST_CHECK(!detector4);
+
+ RotationGestureDetector detector5 = DownCast< RotationGestureDetector >(unInitializedObject);
+ DALI_TEST_CHECK(!detector5);
+
+ GestureDetector detector6 = RotationGestureDetector::New();
+ RotationGestureDetector detector7 = RotationGestureDetector::DownCast(detector6);
+ DALI_TEST_CHECK(detector7);
+ END_TEST;
+}
+
+// Negative test case for a method
+int UtcDaliRotationGestureSignalReceptionNegative(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Do a rotation outside actor's area
+ TestStartRotation( application, Vector2( 112.0f, 62.0f ), Vector2( 112.0f, 162.0f ),
+ Vector2( 112.0f, 100.0f ), Vector2( 112.0f, 124.0f ), 100 );
+
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+
+ // Continue rotation into actor's area - we should still not receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 112.0f, 100.0f ), Vector2( 112.0f, 124.0f ),
+ Vector2( 5.0f, 5.0f ), Vector2( 35.0f, 35.0f ), 200 );
+
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+
+ // Stop rotating - we should still not receive the signal
+ data.Reset();
+ TestEndRotation( application, Vector2( 6.0f, 6.0f ), Vector2( 18.0f, 18.0f ),
+ Vector2( 10.0f, 8.0f ), Vector2( 14.0f, 16.0f ), 300 );
+
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionDownMotionLeave(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Start pan within the actor's area
+ TestStartRotation( application, Vector2( 5.0f, 5.0f ), Vector2( 20.0f, 20.0f ),
+ Vector2( 5.0f, 5.0f ), Vector2( 20.0f, 30.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.244f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(12.5f, 17.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Continue the pan within the actor's area - we should still receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 17.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 400 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Continuing, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.785398f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(21.0f, 20.0f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Pan Gesture leaves actor's area - we should still receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 17.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 300.0f, 10.0f ), Vector2( 340.0f, 10.0f ), 1000 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Continuing, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.785398f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(320.0f, 10.0f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Gesture ends - we would receive a finished state
+ data.Reset();
+ TestEndRotation( application, Vector2( 300.0f, 10.0f ), Vector2( 340.0f, 10.0f ),
+ Vector2( 305.0f, 10.0f ), Vector2( 315.0f, 10.0f ), 1500);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Finished, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.785398f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(310.0f, 10.0f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionDownMotionUp(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Start rotation within the actor's area
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 31.0f, 29.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.404892f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(20.5f, 24.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Continue the rotation within the actor's area - we should still receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 29.0f, 15.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Continuing, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.343024f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(22.0f, 17.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Gesture ends within actor's area - we would receive a finished state
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 29.0f, 15.0f ), 1000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Finished, data.receivedGesture.state, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.463648f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(24.0f, 17.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionDetach(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Start rotation within the actor's area
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION);
+
+
+ // Continue the rotation within the actor's area - we should still receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Continuing, data.receivedGesture.state, TEST_LOCATION);
+
+ // Gesture ends within actor's area
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Finished, data.receivedGesture.state, TEST_LOCATION);
+
+ // Detach actor
+ detector.DetachAll();
+
+ // Ensure we are no longer signalled
+ data.Reset();
+ TestGenerateRotation( application );
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionDetachWhileRotationing(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Start rotation within the actor's area
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION);
+
+ // Continue the rotation within the actor's area - we should still receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Continuing, data.receivedGesture.state, TEST_LOCATION);
+
+ // Detach actor during the rotation, we should not receive the next event
+ detector.DetachAll();
+
+ // Gesture ends within actor's area
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionActorDestroyedWhileRotationing(void)
+{
+ TestApplication application;
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Attach a temporary actor to stop detector being removed from RotationGestureProcessor when main actor
+ // is destroyed.
+ Actor tempActor = Actor::New();
+ tempActor.SetSize(100.0f, 100.0f);
+ tempActor.SetAnchorPoint(AnchorPoint::BOTTOM_RIGHT);
+ Stage::GetCurrent().Add(tempActor);
+ detector.Attach(tempActor);
+
+ // Actor lifetime is scoped
+ {
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ detector.Attach(actor);
+
+ // Start rotation within the actor's area
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION);
+
+ // Continue the rotation within the actor's area - we should still receive the signal
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(Gesture::Continuing, data.receivedGesture.state, TEST_LOCATION);
+
+ // Remove the actor from stage and reset the data
+ Stage::GetCurrent().Remove(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+ }
+
+ // Actor should now have been destroyed
+
+ // Gesture ends within the area where the actor used to be
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionRotatedActor(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetOrientation(Dali::Degree(90.0f), Vector3::ZAXIS);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify a couple of times
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Do an entire rotation, only check finished value
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 27.0f, 15.0f ), 1000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.558599f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(23.0f, 17.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Rotate actor again and render and notify
+ actor.SetOrientation(Dali::Degree(180.0f), Vector3::ZAXIS);
+ application.SendNotification();
+ application.Render();
+
+ // Do an entire rotation, only check finished value
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 2100 );
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 27.0f, 15.0f ), 3000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.558599f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(23.0f, 17.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Rotate actor again and render and notify
+ actor.SetOrientation(Dali::Degree(270.0f), Vector3::ZAXIS);
+ application.SendNotification();
+ application.Render();
+
+ // Do an entire rotation, only check finished value
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 4100 );
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 27.0f, 15.0f ), 5000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(-0.558599f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(23.0f, 17.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionChildHit(void)
+{
+ TestApplication application;
+
+ Actor parent = Actor::New();
+ parent.SetSize(100.0f, 100.0f);
+ parent.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(parent);
+
+ // Set child to completely cover parent.
+ // Change rotation of child to be different from parent so that we can check if our local coordinate
+ // conversion of the parent actor is correct.
+ Actor child = Actor::New();
+ child.SetSize(100.0f, 100.0f);
+ child.SetAnchorPoint(AnchorPoint::CENTER);
+ child.SetParentOrigin(ParentOrigin::CENTER);
+ child.SetOrientation(Dali::Degree(90.0f), Vector3::ZAXIS);
+ parent.Add(child);
+
+ TouchEventFunctor touchFunctor;
+ child.TouchedSignal().Connect(&application, touchFunctor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(parent);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Do an entire pan, only check finished value - hits child area but parent should still receive it
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 29.0f, 25.0f ), 1000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, parent == data.rotatedActor, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.463648f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(24.0f, 22.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+
+ // Attach child and generate same touch points to yield same results
+ // (Also proves that you can detach and then re-attach another actor)
+ detector.Attach(child);
+ detector.Detach(parent);
+
+ // Do an entire pan, only check finished value
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 2100 );
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 29.0f, 35.0f ), 3000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, child == data.rotatedActor, TEST_LOCATION);
+ DALI_TEST_EQUALS(0.982794f, data.receivedGesture.rotation.radian, 0.01f, TEST_LOCATION);
+ DALI_TEST_EQUALS(Vector2(24.0f, 27.5f), data.receivedGesture.screenCenterPoint, 0.01f, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionAttachDetachMany(void)
+{
+ TestApplication application;
+
+ Actor first = Actor::New();
+ first.SetSize(100.0f, 100.0f);
+ first.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(first);
+
+ Actor second = Actor::New();
+ second.SetSize(100.0f, 100.0f);
+ second.SetX(100.0f);
+ second.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(second);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(first);
+ detector.Attach(second);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Start rotation within second actor's area
+ TestStartRotation( application, Vector2( 102.0f, 20.0f ), Vector2( 138.0f, 20.0f ),
+ Vector2( 110.0f, 20.0f ), Vector2( 130.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, second == data.rotatedActor, TEST_LOCATION);
+
+ // Rotation moves into first actor's area - second actor should receive the rotation
+ data.Reset();
+ TestContinueRotation( application, Vector2( 110.0f, 20.0f ), Vector2( 130.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, second == data.rotatedActor, TEST_LOCATION);
+
+ // Detach the second actor during the rotation, we should not receive the next event
+ detector.Detach(second);
+
+ // Gesture ends within actor's area
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 119.0f, 20.0f ), Vector2( 121.0f, 20.0f ), 3000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionActorBecomesUntouchable(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect(&application, functor);
+
+ // Start rotation in actor's area
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+
+ // Pan continues within actor's area
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+
+ // Actor become invisible - actor should not receive the next rotation
+ actor.SetVisible(false);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Gesture ends within actor's area
+ data.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 3000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionMultipleDetectorsOnActor(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ Actor actor2 = Actor::New();
+ actor2.SetSize(100.0f, 100.0f);
+ actor2.SetAnchorPoint(AnchorPoint::BOTTOM_RIGHT);
+ Stage::GetCurrent().Add(actor2);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Attach actor to one detector
+ SignalData firstData;
+ GestureReceivedFunctor firstFunctor(firstData);
+ RotationGestureDetector firstDetector = RotationGestureDetector::New();
+ firstDetector.Attach(actor);
+ firstDetector.DetectedSignal().Connect(&application, firstFunctor);
+
+ // Attach actor to another detector
+ SignalData secondData;
+ GestureReceivedFunctor secondFunctor(secondData);
+ RotationGestureDetector secondDetector = RotationGestureDetector::New();
+ secondDetector.Attach(actor);
+ secondDetector.DetectedSignal().Connect(&application, secondFunctor);
+
+ // Add second actor to second detector, when we remove the actor, this will make sure that this
+ // gesture detector is not removed from the GestureDetectorProcessor. In this scenario, the
+ // functor should still not be called (which is what we're also testing).
+ secondDetector.Attach(actor2);
+
+ // Rotation in actor's area - both detector's functors should be called
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, firstData.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, secondData.functorCalled, TEST_LOCATION);
+
+ // Rotation continues in actor's area - both detector's functors should be called
+ firstData.Reset();
+ secondData.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, firstData.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, secondData.functorCalled, TEST_LOCATION);
+
+ // Detach actor from firstDetector and emit rotation on actor, only secondDetector's functor should be called.
+ firstDetector.Detach(actor);
+ firstData.Reset();
+ secondData.Reset();
+ TestEndRotation( application, Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(false, firstData.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, secondData.functorCalled, TEST_LOCATION);
+
+ // New rotation on actor, only secondDetector has actor attached
+ firstData.Reset();
+ secondData.Reset();
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 1500 );
+ DALI_TEST_EQUALS(false, firstData.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, secondData.functorCalled, TEST_LOCATION);
+
+ // Detach actor from secondDetector
+ secondDetector.Detach(actor);
+ firstData.Reset();
+ secondData.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 2000 );
+ DALI_TEST_EQUALS(false, firstData.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, secondData.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureSignalReceptionEnsureCorrectSignalling(void)
+{
+ TestApplication application;
+
+ Actor actor1 = Actor::New();
+ actor1.SetSize(100.0f, 100.0f);
+ actor1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor1);
+ SignalData data1;
+ GestureReceivedFunctor functor1(data1);
+ RotationGestureDetector detector1 = RotationGestureDetector::New();
+ detector1.Attach(actor1);
+ detector1.DetectedSignal().Connect(&application, functor1);
+
+ Actor actor2 = Actor::New();
+ actor2.SetSize(100.0f, 100.0f);
+ actor2.SetAnchorPoint(AnchorPoint::BOTTOM_RIGHT);
+ actor2.SetParentOrigin(ParentOrigin::BOTTOM_RIGHT);
+ Stage::GetCurrent().Add(actor2);
+ SignalData data2;
+ GestureReceivedFunctor functor2(data2);
+ RotationGestureDetector detector2 = RotationGestureDetector::New();
+ detector2.Attach(actor2);
+ detector2.DetectedSignal().Connect(&application, functor2);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Start pan in actor1's area, only data1 should be set
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data1.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, data2.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureActorUnstaged(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // State to remove actor in.
+ Gesture::State stateToUnstage( Gesture::Started );
+
+ // Attach actor to detector
+ SignalData data;
+ UnstageActorFunctor functor( data, stateToUnstage );
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect( &application, functor );
+
+ // Emit signals
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Re-add actor to stage
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Change state to Gesture::Continuing to remove
+ stateToUnstage = Gesture::Continuing;
+
+ // Emit signals
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Re-add actor to stage
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Change state to Gesture::Continuing to remove
+ stateToUnstage = Gesture::Finished;
+
+ // Emit signals
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ tet_result( TET_PASS ); // If we get here then we have handled actor stage removal gracefully.
+ END_TEST;
+}
+
+int UtcDaliRotationGestureActorStagedAndDestroyed(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Create and add a second actor so that GestureDetector destruction does not come into play.
+ Actor dummyActor( Actor::New() );
+ dummyActor.SetSize( 100.0f, 100.0f );
+ dummyActor.SetPosition( 100.0f, 100.0f );
+ dummyActor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(dummyActor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // State to remove actor in.
+ Gesture::State stateToUnstage( Gesture::Started );
+
+ // Attach actor to detector
+ SignalData data;
+ UnstageActorFunctor functor( data, stateToUnstage );
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.Attach(dummyActor);
+ detector.DetectedSignal().Connect( &application, functor );
+
+ // Here we are testing a Started actor which is removed in the Started callback, but then added back
+ // before we get a continuing state. As we were removed from the stage, even if we're at the same
+ // position, we should still not be signalled.
+
+ // Emit signals
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Re add to the stage, we should not be signalled
+ Stage::GetCurrent().Add(actor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Continue signal emission
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 );
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ // Here we delete an actor in started, we should not receive any subsequent signalling.
+
+ // Emit signals
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 1500 );
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Delete actor as well
+ actor.Reset();
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Continue signal emission
+ TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 2000 );
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 3000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliRotationGestureLayerConsumesTouch(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Add a detector
+ SignalData data;
+ GestureReceivedFunctor functor(data);
+ RotationGestureDetector detector = RotationGestureDetector::New();
+ detector.Attach(actor);
+ detector.DetectedSignal().Connect( &application, functor );
+
+ // Add a layer to overlap the actor
+ Layer layer = Layer::New();
+ layer.SetSize(100.0f, 100.0f);
+ layer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add( layer );
+ layer.RaiseToTop();
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Emit signals, should receive
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 );
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 1000);
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ // Set layer to consume all touch
+ layer.SetTouchConsumed( true );
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Emit the same signals again, should not receive
+ TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ),
+ Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 1500 );
+ TestEndRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ),
+ Vector2( 19.0f, 20.0f ), Vector2( 21.0f, 20.0f ), 2000);
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ data.Reset();
+
+ END_TEST;
+}
+
#include <dali/internal/event/common/type-info-impl.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/devel-api/events/rotation-gesture-detector.h>
using namespace Dali;
END_TEST;
}
+int UtcDaliRotationGestureDetectorTypeRegistry(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ actor.SetSize(100.0f, 100.0f);
+ actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ Stage::GetCurrent().Add(actor);
+
+ // Register Type
+ TypeInfo type;
+ type = TypeRegistry::Get().GetTypeInfo( "RotationGestureDetector" );
+ DALI_TEST_CHECK( type );
+ BaseHandle handle = type.CreateInstance();
+ DALI_TEST_CHECK( handle );
+ RotationGestureDetector detector = RotationGestureDetector::DownCast( handle );
+ DALI_TEST_CHECK( detector );
+
+ // Attach actor to detector
+ SignalData data;
+ GestureReceivedFunctor functor( data );
+ detector.Attach(actor);
+
+ // Connect to signal through type
+ handle.ConnectSignal( &application, "rotationDetected", functor );
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Emit gesture
+ TestGenerateRotation( application );
+
+ DALI_TEST_EQUALS(true, data.voidFunctorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
int UtcDaliTapGestureDetectorTypeRegistry(void)
{
TestApplication application;
--- /dev/null
+#ifndef DALI_GESTURE_DEVEL_H
+#define DALI_GESTURE_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#include <dali/public-api/events/gesture.h>
+
+namespace Dali
+{
+
+namespace DevelGesture
+{
+
+/**
+ * @copydoc Dali::Gesture::Type
+ */
+enum Type
+{
+ Pinch = Gesture::Pinch,
+ Pan = Gesture::Pan,
+ Tap = Gesture::Tap,
+ LongPress = Gesture::LongPress,
+
+ // Devel Gesture Types
+ Rotation = 1 << 4, ///< When the user rotates two fingers around a particular ares of the screen.
+};
+
+} // namespace DevelGesture
+
+} // namespace Dali
+
+#endif // DALI_GESTURE_DEVEL_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/events/rotation-gesture-detector.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h>
+
+namespace Dali
+{
+
+RotationGestureDetector::RotationGestureDetector( Internal::RotationGestureDetector* internal )
+: GestureDetector( internal )
+{
+}
+
+RotationGestureDetector::RotationGestureDetector()
+{
+}
+
+RotationGestureDetector RotationGestureDetector::New()
+{
+ Internal::RotationGestureDetectorPtr internal = Internal::RotationGestureDetector::New();
+
+ return RotationGestureDetector( internal.Get() );
+}
+
+RotationGestureDetector RotationGestureDetector::DownCast( BaseHandle handle )
+{
+ return RotationGestureDetector( dynamic_cast<Dali::Internal::RotationGestureDetector*>( handle.GetObjectPtr() ) );
+}
+
+RotationGestureDetector::~RotationGestureDetector()
+{
+}
+
+RotationGestureDetector::RotationGestureDetector( const RotationGestureDetector& handle )
+: GestureDetector( handle )
+{
+}
+
+RotationGestureDetector& RotationGestureDetector::operator=( const RotationGestureDetector& rhs )
+{
+ BaseHandle::operator=( rhs );
+ return *this;
+}
+
+RotationGestureDetector::DetectedSignalType& RotationGestureDetector::DetectedSignal()
+{
+ return GetImplementation( *this ).DetectedSignal();
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_ROTATION_GESTURE_DETECTOR_H
+#define DALI_ROTATION_GESTURE_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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/public-api/events/gesture-detector.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+class RotationGestureDetector;
+}
+
+struct RotationGesture;
+
+/**
+ * @brief This class looks for a rotation gesture involving two touches.
+ *
+ * It measures the relative rotation of two touch points & emits a signal
+ * when this changes. Please see RotationGesture for more information.
+ *
+ * The application programmer can use this gesture detector as follows:
+ * @code
+ * RotationGestureDetector detector = RotationGestureDetector::New();
+ * detector.Attach( myActor );
+ * detector.DetectedSignal().Connect( this, &MyApplication::OnRotation );
+ * @endcode
+ *
+ * @see RotationGesture
+ *
+ * Signals
+ * | %Signal Name | Method |
+ * |-------------------|-----------------------|
+ * | rotationDetected | @ref DetectedSignal() |
+ */
+class DALI_CORE_API RotationGestureDetector : public GestureDetector
+{
+public: // Typedefs
+
+ /**
+ * @brief Signal type.
+ */
+ typedef Signal< void ( Actor, const RotationGesture& ) > DetectedSignalType;
+
+public: // Creation & Destruction
+
+ /**
+ * @brief Creates an uninitialized RotationGestureDetector; this can be initialized with RotationGestureDetector::New().
+ *
+ * Calling member functions with an uninitialized RotationGestureDetector handle is not allowed.
+ */
+ RotationGestureDetector();
+
+ /**
+ * @brief Creates an initialized RotationGestureDetector.
+ *
+ * @return A handle to a newly allocated Dali resource
+ */
+ static RotationGestureDetector New();
+
+ /**
+ * @brief Downcasts a handle to RotationGestureDetector handle.
+ *
+ * If handle points to a RotationGestureDetector object, the
+ * downcast produces valid handle. If not, the returned handle is left uninitialized.
+ * @param[in] handle Handle to an object
+ * @return Handle to a RotationGestureDetector object or an uninitialized handle
+ */
+ static RotationGestureDetector DownCast( BaseHandle handle );
+
+ /**
+ * @brief Destructor.
+ *
+ * This is non-virtual since derived Handle types must not contain data or virtual methods.
+ */
+ ~RotationGestureDetector();
+
+ /**
+ * @brief This copy constructor is required for (smart) pointer semantics.
+ *
+ * @param[in] handle A reference to the copied handle
+ */
+ RotationGestureDetector(const RotationGestureDetector& handle);
+
+ /**
+ * @brief This assignment operator is required for (smart) pointer semantics.
+ *
+ * @param[in] rhs A reference to the copied handle
+ * @return A reference to this
+ */
+ RotationGestureDetector& operator=(const RotationGestureDetector& rhs);
+
+public: // Signals
+
+ /**
+ * @brief This signal is emitted when the rotation gesture is detected on the attached actor.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ * void YourCallbackName( Actor actor, const RotationGesture& gesture );
+ * @endcode
+ * @return The signal to connect to
+ * @pre The gesture detector has been initialized.
+ */
+ DetectedSignalType& DetectedSignal();
+
+public: // Not intended for Application developers
+
+ /// @cond internal
+ /**
+ * @brief This constructor is used by RotationGestureDetector::New() methods.
+ *
+ * @param[in] internal A pointer to a newly allocated Dali resource
+ */
+ explicit DALI_INTERNAL RotationGestureDetector(Internal::RotationGestureDetector* internal);
+ /// @endcond
+
+};
+
+} // namespace Dali
+
+#endif // DALI_ROTATION_GESTURE_DETECTOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/events/rotation-gesture.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/devel-api/events/gesture-devel.h>
+
+namespace Dali
+{
+
+RotationGesture::RotationGesture( Gesture::State state )
+: Gesture( static_cast< Gesture::Type >( DevelGesture::Rotation ), state )
+{
+}
+
+RotationGesture::RotationGesture( const RotationGesture& rhs )
+: Gesture( rhs ),
+ rotation( rhs.rotation ),
+ screenCenterPoint( rhs.screenCenterPoint ),
+ localCenterPoint( rhs.localCenterPoint )
+{
+}
+
+RotationGesture& RotationGesture::operator=( const RotationGesture& rhs )
+{
+ if( this != &rhs )
+ {
+ Gesture::operator=( rhs );
+ rotation = rhs.rotation;
+ screenCenterPoint = rhs.screenCenterPoint;
+ localCenterPoint = rhs.localCenterPoint;
+ }
+
+ return *this;
+}
+
+RotationGesture::~RotationGesture()
+{
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_ROTATION_GESTURE_H
+#define DALI_ROTATION_GESTURE_H
+
+/*
+ * Copyright (c) 2019 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/public-api/events/gesture.h>
+#include <dali/public-api/math/radian.h>
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+/**
+ * @brief A RotationGesture is emitted when the user moves two fingers that are opposite each other
+ * in a rotational/circular gesture.
+ *
+ * This gesture can be in one of three states; when the rotation gesture is first detected, its
+ * state is set to Gesture::Started. After this, if there is change in the gesture, the state will
+ * be Gesture::Continuing. Finally, when the gesture ends, the state of the gesture changes to
+ * Gesture::Finished.
+ *
+ * A rotation gesture will continue to be sent to the actor under the center point of the rotation
+ * until the rotation ends.
+ */
+struct DALI_CORE_API RotationGesture: public Gesture
+{
+ // Construction & Destruction
+
+ /**
+ * @brief Default Constructor.
+ *
+ * @param[in] state The state of the gesture
+ */
+ RotationGesture( Gesture::State state );
+
+ /**
+ * @brief Copy constructor.
+ * @param[in] rhs A reference to the copied handle
+ */
+ RotationGesture( const RotationGesture& rhs );
+
+ /**
+ * @brief Assignment operator.
+ * @param[in] rhs A reference to the copied handle
+ * @return A reference to this
+ */
+ RotationGesture& operator=( const RotationGesture& rhs );
+
+ /**
+ * @brief Virtual destructor.
+ */
+ virtual ~RotationGesture();
+
+ // Data
+
+ /**
+ * @brief The overall rotation from the start of the rotation gesture till the latest rotation gesture.
+ */
+ Radian rotation;
+
+ /**
+ * @brief The center point of the two points that caused the rotation gesture in screen coordinates.
+ */
+ Vector2 screenCenterPoint;
+
+ /**
+ * @brief The center point of the two points that caused the rotation gesture in local actor coordinates.
+ */
+ Vector2 localCenterPoint;
+};
+
+} // namespace Dali
+
+#endif // DALI_ROTATION_GESTURE_H
${devel_api_src_dir}/animation/path-constrainer.cpp
${devel_api_src_dir}/common/hash.cpp
${devel_api_src_dir}/common/stage-devel.cpp
+ ${devel_api_src_dir}/events/rotation-gesture.cpp
+ ${devel_api_src_dir}/events/rotation-gesture-detector.cpp
${devel_api_src_dir}/events/hit-test-algorithm.cpp
${devel_api_src_dir}/events/touch-data-devel.cpp
${devel_api_src_dir}/events/key-event-devel.cpp
SET( devel_api_core_events_header_files
+ ${devel_api_src_dir}/events/rotation-gesture.h
+ ${devel_api_src_dir}/events/rotation-gesture-detector.h
${devel_api_src_dir}/events/hit-test-algorithm.h
${devel_api_src_dir}/events/touch-data-devel.h
${devel_api_src_dir}/events/key-event-devel.h
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
return *mGestureData;
}
-bool Actor::IsGestureRequred( Gesture::Type type ) const
+bool Actor::IsGestureRequred( DevelGesture::Type type ) const
{
return mGestureData && mGestureData->IsGestureRequred( type );
}
#define DALI_INTERNAL_ACTOR_H
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
#include <dali/public-api/math/viewport.h>
#include <dali/public-api/object/ref-object.h>
#include <dali/public-api/size-negotiation/relayout-container.h>
+#include <dali/devel-api/events/gesture-devel.h>
#include <dali/internal/common/memory-pool-object-allocator.h>
#include <dali/internal/event/actors/actor-declarations.h>
#include <dali/internal/event/common/object-impl.h>
/**
* Queries whether the actor requires the gesture type.
* @param[in] type The gesture type.
+ * @return True if the gesture is required, false otherwise.
*/
- bool IsGestureRequred( Gesture::Type type ) const;
+ bool IsGestureRequred( DevelGesture::Type type ) const;
// Signals
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
{
ActorGestureData::ActorGestureData()
-: gesturesRequired( Gesture::Type( 0 ) ),
- panDetectors( NULL ),
- pinchDetectors( NULL ),
- longPressDetectors( NULL ),
- tapDetectors( NULL )
+: gesturesRequired( DevelGesture::Type( 0 ) ),
+ panDetectors( nullptr ),
+ pinchDetectors( nullptr ),
+ longPressDetectors( nullptr ),
+ tapDetectors( nullptr ),
+ rotationDetectors( nullptr )
{
}
delete pinchDetectors;
delete longPressDetectors;
delete tapDetectors;
+ delete rotationDetectors;
}
void ActorGestureData::AddGestureDetector( GestureDetector& detector )
{
- const Gesture::Type type( detector.GetType() );
+ const DevelGesture::Type type( detector.GetType() );
GestureDetectorContainer*& containerPtr( GetContainerPtr( type ) );
if ( NULL == containerPtr )
}
containerPtr->push_back( &detector );
- gesturesRequired = Gesture::Type( gesturesRequired | type );
+ gesturesRequired = DevelGesture::Type( gesturesRequired | type );
}
void ActorGestureData::RemoveGestureDetector( GestureDetector& detector )
{
- const Gesture::Type type( detector.GetType() );
+ const DevelGesture::Type type( detector.GetType() );
GestureDetectorContainer*& containerPtr( GetContainerPtr( type ) );
DALI_ASSERT_DEBUG( containerPtr && "Container had not been created" );
if ( container.empty() )
{
- gesturesRequired = Gesture::Type( gesturesRequired & ~type );
+ gesturesRequired = DevelGesture::Type( gesturesRequired & ~type );
delete containerPtr;
containerPtr = NULL;
}
}
-GestureDetectorContainer& ActorGestureData::GetGestureDetectorContainer( Gesture::Type type )
+GestureDetectorContainer& ActorGestureData::GetGestureDetectorContainer( DevelGesture::Type type )
{
return *GetContainerPtr( type );
}
-GestureDetectorContainer*& ActorGestureData::GetContainerPtr( Gesture::Type type )
+GestureDetectorContainer*& ActorGestureData::GetContainerPtr( DevelGesture::Type type )
{
switch ( type )
{
- case Gesture::Pan:
+ case DevelGesture::Pan:
{
return panDetectors;
}
- case Gesture::Pinch:
+ case DevelGesture::Pinch:
{
return pinchDetectors;
}
- case Gesture::LongPress:
+ case DevelGesture::LongPress:
{
return longPressDetectors;
}
- case Gesture::Tap:
+ case DevelGesture::Tap:
{
return tapDetectors;
}
+
+ case DevelGesture::Rotation:
+ {
+ return rotationDetectors;
+ }
}
DALI_ASSERT_DEBUG( ! "Invalid Type" );
*/
// INTERNAL INCLUDES
+#include <dali/devel-api/events/gesture-devel.h>
#include <dali/internal/event/events/gesture-detector-impl.h>
namespace Dali
* @param[in] type The gesture type.
* @return true if the gesture is required, false otherwise.
*/
- inline bool IsGestureRequred( Gesture::Type type ) const
+ inline bool IsGestureRequred( DevelGesture::Type type ) const
{
return type & gesturesRequired;
}
* @param[in] type The container type required
* @pre Ensure IsGestureRequired() is used to check if the container is actually available.
*/
- GestureDetectorContainer& GetGestureDetectorContainer( Gesture::Type type );
+ GestureDetectorContainer& GetGestureDetectorContainer( DevelGesture::Type type );
private:
* Helper to retrieve the appropriate container type.
* @param[in] type The container type required.
*/
- inline GestureDetectorContainer*& GetContainerPtr( Gesture::Type type );
+ inline GestureDetectorContainer*& GetContainerPtr( DevelGesture::Type type );
private:
- Gesture::Type gesturesRequired; ///< Stores which gestures are required
+ DevelGesture::Type gesturesRequired; ///< Stores which gestures are required
GestureDetectorContainer* panDetectors; ///< Pointer to a container of pan-detectors
GestureDetectorContainer* pinchDetectors; ///< Pointer to a container of pinch-detectors
GestureDetectorContainer* longPressDetectors; ///< Pointer to a container of long-press-detectors
GestureDetectorContainer* tapDetectors; ///< Pointer to a container of tap-detectors
+ GestureDetectorContainer* rotationDetectors; ///< Pointer to a container of tap-detectors
};
} // namespace Internal
namespace Internal
{
-GestureDetector::GestureDetector(Gesture::Type type, const SceneGraph::PropertyOwner* sceneObject )
+GestureDetector::GestureDetector( DevelGesture::Type type, const SceneGraph::PropertyOwner* sceneObject )
: Object( sceneObject ),
mType( type ),
mGestureEventProcessor( ThreadLocalStorage::Get().GetGestureEventProcessor() )
{
}
+GestureDetector::GestureDetector( Gesture::Type type, const SceneGraph::PropertyOwner* sceneObject )
+: GestureDetector( static_cast< DevelGesture::Type >( type ), sceneObject )
+{
+}
+
GestureDetector::~GestureDetector()
{
if ( !mPendingAttachActors.empty() )
* Retrieves the type of GestureDetector
* @return The GestureDetector Type
*/
- Gesture::Type GetType() const
+ DevelGesture::Type GetType() const
{
return mType;
}
* @param pointer to the scene object, nullptr if none
* by default GestureDetectors don't have our own scene object
*/
- GestureDetector(Gesture::Type type, const SceneGraph::PropertyOwner* sceneObject = nullptr );
+ GestureDetector( DevelGesture::Type type, const SceneGraph::PropertyOwner* sceneObject = nullptr );
+
+ /**
+ * @copydoc GestureDetector( DevelGesture::Type, const SceneGraph::PropertyOwner* )
+ */
+ GestureDetector( Gesture::Type type, const SceneGraph::PropertyOwner* sceneObject = nullptr );
/**
* A reference counted object may only be deleted by calling Unreference()
protected:
- Gesture::Type mType; ///< The gesture detector will detect this type of gesture.
+ DevelGesture::Type mType; ///< The gesture detector will detect this type of gesture.
GestureDetectorActorContainer mAttachedActors; ///< Object::Observer is used to provide weak-pointer behaviour
GestureDetectorActorContainer mPendingAttachActors; ///< Object::Observer is used to provide weak-pointer behaviour
GestureEventProcessor& mGestureEventProcessor; ///< A reference to the gesture event processor.
mPanGestureProcessor( updateManager ),
mPinchGestureProcessor(),
mTapGestureProcessor(),
+ mRotationGestureProcessor(),
mRenderController( renderController ),
envOptionMinimumPanDistance(-1),
envOptionMinimumPanEvents(-1)
mPanGestureProcessor.ProcessTouch(scene, event);
mPinchGestureProcessor.ProcessTouch(scene, event);
mTapGestureProcessor.ProcessTouch(scene, event);
+ mRotationGestureProcessor.ProcessTouch(scene, event);
}
void GestureEventProcessor::AddGestureDetector(GestureDetector* gestureDetector, Scene& scene)
{
switch (gestureDetector->GetType())
{
- case Gesture::LongPress:
+ case DevelGesture::LongPress:
{
LongPressGestureDetector* longPress = static_cast<LongPressGestureDetector*>(gestureDetector);
mLongPressGestureProcessor.AddGestureDetector(longPress, scene);
break;
}
- case Gesture::Pan:
+ case DevelGesture::Pan:
{
PanGestureDetector* pan = static_cast<PanGestureDetector*>(gestureDetector);
mPanGestureProcessor.AddGestureDetector(pan, scene, envOptionMinimumPanDistance, envOptionMinimumPanEvents);
break;
}
- case Gesture::Pinch:
+ case DevelGesture::Pinch:
{
PinchGestureDetector* pinch = static_cast<PinchGestureDetector*>(gestureDetector);
mPinchGestureProcessor.AddGestureDetector(pinch, scene);
break;
}
- case Gesture::Tap:
+ case DevelGesture::Tap:
{
TapGestureDetector* tap = static_cast<TapGestureDetector*>(gestureDetector);
mTapGestureProcessor.AddGestureDetector(tap, scene);
break;
}
+
+ case DevelGesture::Rotation:
+ {
+ RotationGestureDetector* rotation = static_cast<RotationGestureDetector*>(gestureDetector);
+ mRotationGestureProcessor.AddGestureDetector(rotation, scene);
+ break;
+ }
}
}
{
switch (gestureDetector->GetType())
{
- case Gesture::LongPress:
+ case DevelGesture::LongPress:
{
LongPressGestureDetector* longPress = static_cast<LongPressGestureDetector*>(gestureDetector);
mLongPressGestureProcessor.RemoveGestureDetector(longPress);
break;
}
- case Gesture::Pan:
+ case DevelGesture::Pan:
{
PanGestureDetector* pan = static_cast<PanGestureDetector*>(gestureDetector);
mPanGestureProcessor.RemoveGestureDetector(pan);
break;
}
- case Gesture::Pinch:
+ case DevelGesture::Pinch:
{
PinchGestureDetector* pinch = static_cast<PinchGestureDetector*>(gestureDetector);
mPinchGestureProcessor.RemoveGestureDetector(pinch);
break;
}
- case Gesture::Tap:
+ case DevelGesture::Tap:
{
TapGestureDetector* tap = static_cast<TapGestureDetector*>(gestureDetector);
mTapGestureProcessor.RemoveGestureDetector(tap);
break;
}
+
+ case DevelGesture::Rotation:
+ {
+ RotationGestureDetector* rotation = static_cast<RotationGestureDetector*>(gestureDetector);
+ mRotationGestureProcessor.RemoveGestureDetector(rotation);
+ break;
+ }
}
}
{
switch (gestureDetector->GetType())
{
- case Gesture::LongPress:
+ case DevelGesture::LongPress:
{
LongPressGestureDetector* longPress = static_cast<LongPressGestureDetector*>(gestureDetector);
mLongPressGestureProcessor.GestureDetectorUpdated(longPress);
break;
}
- case Gesture::Pan:
+ case DevelGesture::Pan:
{
PanGestureDetector* pan = static_cast<PanGestureDetector*>(gestureDetector);
mPanGestureProcessor.GestureDetectorUpdated(pan);
break;
}
- case Gesture::Pinch:
+ case DevelGesture::Pinch:
{
PinchGestureDetector* pinch = static_cast<PinchGestureDetector*>(gestureDetector);
mPinchGestureProcessor.GestureDetectorUpdated(pinch);
break;
}
- case Gesture::Tap:
+ case DevelGesture::Tap:
{
TapGestureDetector* tap = static_cast<TapGestureDetector*>(gestureDetector);
mTapGestureProcessor.GestureDetectorUpdated(tap);
break;
}
+
+ case DevelGesture::Rotation:
+ {
+ // Nothing to do
+ break;
+ }
}
}
{
bool requestUpdate = false;
- switch ( gesture.type )
+ switch ( static_cast< DevelGesture::Type >( gesture.type ) )
{
- case Gesture::Pan:
+ case DevelGesture::Pan:
{
const PanGesture& pan = static_cast< const PanGesture& >( gesture );
requestUpdate = mPanGestureProcessor.SetPanGestureProperties( pan );
break;
}
- case Gesture::LongPress:
- case Gesture::Pinch:
- case Gesture::Tap:
+ case DevelGesture::LongPress:
+ case DevelGesture::Pinch:
+ case DevelGesture::Tap:
+ case DevelGesture::Rotation:
{
DALI_ASSERT_DEBUG( false && "Gesture type does not have scene object\n" );
break;
updateRequired |= mPanGestureProcessor.NeedsUpdate();
updateRequired |= mPinchGestureProcessor.NeedsUpdate();
updateRequired |= mTapGestureProcessor.NeedsUpdate();
+ updateRequired |= mRotationGestureProcessor.NeedsUpdate();
return updateRequired;
}
#include <dali/internal/event/events/long-press-gesture/long-press-gesture-processor.h>
#include <dali/internal/event/events/pan-gesture/pan-gesture-processor.h>
#include <dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h>
#include <dali/internal/event/events/tap-gesture/tap-gesture-processor.h>
namespace Dali
PanGestureProcessor mPanGestureProcessor;
PinchGestureProcessor mPinchGestureProcessor;
TapGestureProcessor mTapGestureProcessor;
+ RotationGestureProcessor mRotationGestureProcessor;
Integration::RenderController& mRenderController;
int32_t envOptionMinimumPanDistance;
{
}
-GestureEvent::GestureEvent(Gesture::Type gesture, Gesture::State gestureState)
-: gestureType(gesture),
- state(gestureState),
- time(0)
+GestureEvent::GestureEvent( DevelGesture::Type gesture, Gesture::State gestureState )
+: gestureType( gesture ),
+ state( gestureState ),
+ time( 0 )
{
}
+GestureEvent::GestureEvent(Gesture::Type gesture, Gesture::State gestureState)
+: GestureEvent( static_cast< DevelGesture::Type >( gesture ), gestureState )
+{
+}
} // namespace Internal
} // namespace Dali
// INTERNAL INCLUDES
#include <dali/public-api/events/gesture.h>
+#include <dali/devel-api/events/gesture-devel.h>
#include <dali/integration-api/events/event.h>
namespace Dali
/**
* Gesture Type.
*/
- Gesture::Type gestureType;
+ DevelGesture::Type gestureType;
/**
* The state of the gesture.
* @param[in] gesture The type of gesture event.
* @param[in] gestureState The state of the gesture event.
*/
- GestureEvent(Gesture::Type gesture, Gesture::State gestureState);
+ GestureEvent( DevelGesture::Type gesture, Gesture::State gestureState);
+
+ /**
+ * @copydoc GestureEvent( DevelGesture::Type, Gesture::State )
+ */
+ GestureEvent( Gesture::Type gesture, Gesture::State gestureState );
};
} // namespace Internal
*/
struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
{
- GestureHitTestCheck( Gesture::Type type )
+ GestureHitTestCheck( DevelGesture::Type type )
: mType( type )
{
}
+ GestureHitTestCheck( Gesture::Type type )
+ : GestureHitTestCheck( static_cast< DevelGesture::Type >( type ) )
+ {
+ }
+
virtual bool IsActorHittable( Actor* actor )
{
return actor->IsGestureRequred( mType ) && // Does the Application or derived actor type require the gesture?
return layer->IsTouchConsumed();
}
- Gesture::Type mType;
+ DevelGesture::Type mType;
};
} // unnamed namespace
-GestureProcessor::GestureProcessor( Gesture::Type type )
+GestureProcessor::GestureProcessor( DevelGesture::Type type )
: mGestureRecognizer(),
mNeedsUpdate( false ),
mType( type ),
{
}
+GestureProcessor::GestureProcessor( Gesture::Type type )
+: GestureProcessor( static_cast< DevelGesture::Type >( type ) )
+{
+}
+
+
GestureProcessor::~GestureProcessor()
{
ResetActor();
*/
// INTERNAL INCLUDES
+#include <dali/devel-api/events/gesture-devel.h>
#include <dali/internal/event/events/gesture-detector-impl.h>
#include <dali/internal/event/events/hit-test-algorithm-impl.h>
#include <dali/internal/event/events/gesture-recognizer.h>
/**
* Protected constructor. Cannot create an instance of GestureProcessor
*/
+ GestureProcessor( DevelGesture::Type type );
+
+ /**
+ * Protected constructor. Cannot create an instance of GestureProcessor
+ */
GestureProcessor( Gesture::Type type );
/**
private: // Data
- Gesture::Type mType; ///< Type of GestureProcessor
+ DevelGesture::Type mType; ///< Type of GestureProcessor
Actor* mCurrentGesturedActor; ///< The current actor that has been gestured.
bool mGesturedActorDisconnected:1; ///< Indicates whether the gestured actor has been disconnected from the scene
};
#include <dali/public-api/events/gesture.h>
#include <dali/public-api/math/vector2.h>
#include <dali/public-api/object/ref-object.h>
+#include <dali/devel-api/events/gesture-devel.h>
#include <dali/internal/event/events/gesture-event.h>
namespace Dali
class GestureRecognizer : public RefObject
{
public:
+
/**
* Called when it gets a touch event. The gesture recognizer should
* evaluate this event along with previously received events to determine
* Returns the type of gesture detector.
* @return Type of gesture detector.
*/
- Gesture::Type GetType() const { return mType; }
+ DevelGesture::Type GetType() const { return mType; }
- void SendEvent(Scene& scene, const Integration::TouchEvent& event)
+ /**
+ * Called when we get a touch event.
+ * @param[in] scene The scene the touch event has occurred on
+ * @param[in] event The latest touch event
+ */
+ void SendEvent( Scene& scene, const Integration::TouchEvent& event )
{
mScene = &scene;
- SendEvent(event);
+ SendEvent( event );
}
protected:
/**
- * Protected Constructor. Should only be able to create derived class objects.
+ * Protected Constructor. Should only be able to create derived class objects.
* @param[in] screenSize The size of the screen.
* @param[in] detectorType The type of gesture detector.
*/
+ GestureRecognizer( Vector2 screenSize, DevelGesture::Type detectorType )
+ : mScreenSize( screenSize ),
+ mType( detectorType ),
+ mScene( nullptr )
+ {
+ }
+
+ /**
+ * copydoc GestureRecognizer( Vector2, DevelGesture::Type )
+ */
GestureRecognizer( Vector2 screenSize, Gesture::Type detectorType )
- : mScreenSize(screenSize),
- mType(detectorType),
- mScene(nullptr)
+ : GestureRecognizer( screenSize, static_cast< DevelGesture::Type >( detectorType ) )
+ {
+ }
+
+ /**
+ * Protected Constructor. Should only be able to create derived class objects.
+ *
+ * Use this constructor with the screen size is not used in the dereived class.
+ * @param[in] detectorType The type of gesture detector.
+ */
+ GestureRecognizer( DevelGesture::Type detectorType )
+ : GestureRecognizer( Vector2::ZERO, detectorType )
{
}
protected:
Vector2 mScreenSize;
- Gesture::Type mType;
+ DevelGesture::Type mType;
Scene* mScene;
};
// INTERNAL INCLUDES
#include <dali/public-api/events/gesture.h>
+#include <dali/devel-api/events/gesture-devel.h>
namespace Dali
{
* Default Constructor
* @param[in] typeRequired The gesture type required
*/
- GestureRequest(Gesture::Type typeRequired) : type(typeRequired)
+ GestureRequest( DevelGesture::Type typeRequired )
+ : type( typeRequired )
{
}
/**
- * Virtual destructor
+ * @copydoc GestureRequest( DevelGesture::Type )
*/
- virtual ~GestureRequest()
+ GestureRequest( Gesture::Type typeRequired )
+ : GestureRequest( static_cast< DevelGesture::Type >( typeRequired ) )
{
}
+ /**
+ * Virtual destructor
+ */
+ virtual ~GestureRequest() = default;
+
// Data Members
- Gesture::Type type; ///< The type of gesture required.
+ DevelGesture::Type type; ///< The type of gesture required.
};
/**
};
/**
- * This is used by Core when a pinch gesture is required.
- */
-struct PinchGestureRequest : public GestureRequest
-{
- // Creation & Destruction
-
- /**
- * Default Constructor
- */
- PinchGestureRequest()
- : GestureRequest(Gesture::Pinch)
- {
- }
-
- /**
- * Virtual destructor
- */
- virtual ~PinchGestureRequest()
- {
- }
-};
-
-/**
* This is used by Core when a tap gesture is required.
*/
struct TapGestureRequest : public GestureRequest
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/events/gesture-devel.h>
+#include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/events/rotation-gesture.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Signals
+
+const char* const SIGNAL_ROTATION_DETECTED = "rotationDetected";
+
+BaseHandle Create()
+{
+ return Dali::RotationGestureDetector::New();
+}
+
+TypeRegistration mType( typeid( Dali::RotationGestureDetector ), typeid( Dali::GestureDetector ), Create );
+
+SignalConnectorType signalConnector1( mType, SIGNAL_ROTATION_DETECTED, &RotationGestureDetector::DoConnectSignal );
+
+}
+
+
+RotationGestureDetectorPtr RotationGestureDetector::New()
+{
+ return new RotationGestureDetector;
+}
+
+RotationGestureDetector::RotationGestureDetector()
+: GestureDetector( DevelGesture::Rotation )
+{
+}
+
+void RotationGestureDetector::EmitRotationGestureSignal( Dali::Actor actor, const RotationGesture& rotation )
+{
+ // Guard against destruction during signal emission
+ Dali::RotationGestureDetector handle( this );
+
+ mDetectedSignal.Emit( actor, rotation );
+}
+
+bool RotationGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+ bool connected( true );
+ RotationGestureDetector* gesture = static_cast< RotationGestureDetector* >( object ); // TypeRegistry guarantees that this is the correct type.
+
+ if ( 0 == strcmp( signalName.c_str(), SIGNAL_ROTATION_DETECTED ) )
+ {
+ gesture->DetectedSignal().Connect( tracker, functor );
+ }
+ else
+ {
+ // signalName does not match any signal
+ connected = false;
+ }
+
+ return connected;
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ROTATION_GESTURE_DETECTOR_H
+#define DALI_INTERNAL_ROTATION_GESTURE_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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/internal/event/events/gesture-detector-impl.h>
+#include <dali/devel-api/events/rotation-gesture-detector.h>
+
+namespace Dali
+{
+
+class RotationGesture;
+
+namespace Internal
+{
+
+class RotationGestureDetector;
+
+typedef IntrusivePtr<RotationGestureDetector> RotationGestureDetectorPtr;
+typedef DerivedGestureDetectorContainer<RotationGestureDetector>::type RotationGestureDetectorContainer;
+
+/**
+ * @copydoc Dali::RotationGestureDetector
+ */
+class RotationGestureDetector : public GestureDetector
+{
+public: // Creation
+
+ /**
+ * Create a new gesture detector.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static RotationGestureDetectorPtr New();
+
+ /**
+ * Construct a new GestureDetector.
+ */
+ RotationGestureDetector();
+
+ // Not copyable
+
+ RotationGestureDetector( const RotationGestureDetector& ) = delete; ///< Deleted copy constructor
+ RotationGestureDetector& operator=(const RotationGestureDetector& rhs) = delete; ///< Deleted copy assignment operator
+
+public:
+
+ /**
+ * Called by the RotationGestureProcessor when a rotation gesture event occurs within the bounds of our
+ * attached actor.
+ * @param[in] actor The rotated actor
+ * @param[in] rotation The rotation gesture
+ */
+ void EmitRotationGestureSignal( Dali::Actor actor, const RotationGesture& rotation );
+
+public: // Signals
+
+ /**
+ * @copydoc Dali::RotationGestureDetector::DetectedSignal()
+ */
+ Dali::RotationGestureDetector::DetectedSignalType& DetectedSignal()
+ {
+ return mDetectedSignal;
+ }
+
+ /**
+ * 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.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~RotationGestureDetector() = default;
+
+private: // GestureDetector overrides
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
+ */
+ virtual void OnActorAttach( Actor& actor ) { /* Nothing to do */ }
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
+ */
+ virtual void OnActorDetach( Actor& actor ) { /* Nothing to do */ }
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
+ */
+ virtual void OnActorDestroyed( Object& object ) { /* Nothing to do */ }
+
+private:
+
+ Dali::RotationGestureDetector::DetectedSignalType mDetectedSignal;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::RotationGestureDetector& GetImplementation( Dali::RotationGestureDetector& detector )
+{
+ DALI_ASSERT_ALWAYS( detector && "RotationGestureDetector handle is empty" );
+
+ BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<Internal::RotationGestureDetector&>( handle );
+}
+
+inline const Internal::RotationGestureDetector& GetImplementation( const Dali::RotationGestureDetector& detector )
+{
+ DALI_ASSERT_ALWAYS( detector && "RotationGestureDetector handle is empty" );
+
+ const BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<const Internal::RotationGestureDetector&>( handle );
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ROTATION_GESTURE_DETECTOR_H
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_ROTATION_GESTURE_EVENT_H
+#define DALI_INTERNAL_EVENT_ROTATION_GESTURE_EVENT_H
+
+/*
+ * Copyright (c) 2019 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/public-api/math/radian.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/devel-api/events/gesture-devel.h>
+#include <dali/internal/event/events/gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+/**
+ * When a rotation gesture is detected, this structure holds information regarding the gesture.
+ *
+ * A Rotation Gesture event should be in one of four states:
+ * - Started: If a rotation is detected.
+ * - Continuing: If after a rotation is detected, it continues.
+ * - Finished: If after a rotation, the user lifts their finger(s).
+ * - Cancelled: If there is a system interruption.
+ */
+struct RotationGestureEvent : public GestureEvent
+{
+ // Construction & Destruction
+
+ /**
+ * Default Constructor
+ * @param[in] state The state of the gesture
+ */
+ RotationGestureEvent( Gesture::State state )
+ : GestureEvent( DevelGesture::Rotation, state )
+ {
+ }
+
+ /**
+ * Virtual destructor
+ */
+ virtual ~RotationGestureEvent() = default;
+
+ // Data
+
+ /**
+ * @copydoc Dali::RotationGesture::rotation
+ */
+ Radian rotation;
+
+ /**
+ * @copydoc Dali::RotationGesture::screenCenterPoint
+ */
+ Vector2 centerPoint;
+};
+
+} // namespace Integration
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_ROTATION_GESTURE_EVENT_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/devel-api/events/gesture-devel.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h>
+#include <dali/internal/event/events/gesture-requests.h>
+#include <dali/devel-api/events/rotation-gesture.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+/**
+ * Creates a RotationGesture and asks the specified detector to emit its detected signal.
+ * @param[in] actor The actor that has been rotationed.
+ * @param[in] gestureDetectors The gesture detector container that should emit the signal.
+ * @param[in] rotationEvent The rotationEvent received from the adaptor.
+ * @param[in] localCenter Relative to the actor attached to the detector.
+ */
+void EmitRotationSignal(
+ Actor* actor,
+ const GestureDetectorContainer& gestureDetectors,
+ const RotationGestureEvent& rotationEvent,
+ Vector2 localCenter)
+{
+ RotationGesture rotation(rotationEvent.state);
+ rotation.time = rotationEvent.time;
+ rotation.rotation = rotationEvent.rotation;
+ rotation.screenCenterPoint = rotationEvent.centerPoint;
+ rotation.localCenterPoint = localCenter;
+
+ Dali::Actor actorHandle( actor );
+ const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
+ for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
+ {
+ static_cast< RotationGestureDetector* >( *iter )->EmitRotationGestureSignal( actorHandle, rotation );
+ }
+}
+
+/**
+ * Functor which checks whether the specified actor is attached to the gesture detector.
+ * It returns true if it is no longer attached. This can be used in remove_if functions.
+ */
+struct IsNotAttachedFunctor
+{
+ /**
+ * Constructor
+ * @param[in] actor The actor to check whether it is attached.
+ */
+ IsNotAttachedFunctor(Actor* actor)
+ : actorToCheck(actor)
+ {
+ }
+
+ /**
+ * Returns true if not attached, false if it is still attached.
+ * @param[in] detector The detector to check.
+ * @return true, if not attached, false otherwise.
+ */
+ bool operator()(const GestureDetector* detector) const
+ {
+ return !detector->IsAttached(*actorToCheck);
+ }
+
+ Actor* actorToCheck; ///< The actor to check whether it is attached or not.
+};
+
+} // unnamed namespace
+
+RotationGestureProcessor::RotationGestureProcessor()
+: GestureProcessor( DevelGesture::Rotation ),
+ mRotationGestureDetectors(),
+ mCurrentRotationEmitters(),
+ mCurrentRotationEvent( nullptr )
+{
+}
+
+void RotationGestureProcessor::Process( Scene& scene, const RotationGestureEvent& rotationEvent )
+{
+ switch ( rotationEvent.state )
+ {
+ case Gesture::Started:
+ {
+ // The rotation gesture should only be sent to the gesture detector which first received it so that
+ // it can be told when the gesture ends as well.
+
+ mCurrentRotationEmitters.clear();
+ ResetActor();
+
+ HitTestAlgorithm::Results hitTestResults;
+ if( HitTest( scene, rotationEvent.centerPoint, hitTestResults ) )
+ {
+ // Record the current render-task for Screen->Actor coordinate conversions
+ mCurrentRenderTask = hitTestResults.renderTask;
+
+ // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
+ mCurrentRotationEvent = &rotationEvent;
+ ProcessAndEmit( hitTestResults );
+ mCurrentRotationEvent = NULL;
+ }
+ break;
+ }
+
+ case Gesture::Continuing:
+ case Gesture::Finished:
+ case Gesture::Cancelled:
+ {
+ // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started.
+ // Check if actor is still touchable.
+
+ Actor* currentGesturedActor = GetCurrentGesturedActor();
+ if ( currentGesturedActor )
+ {
+ if ( currentGesturedActor->IsHittable() && !mCurrentRotationEmitters.empty() && mCurrentRenderTask )
+ {
+ // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
+ GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
+ mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
+
+ if ( !mCurrentRotationEmitters.empty() )
+ {
+ Vector2 actorCoords;
+ RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
+ currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y );
+
+ EmitRotationSignal( currentGesturedActor, mCurrentRotationEmitters, rotationEvent, actorCoords );
+ }
+ else
+ {
+ // If we have no current emitters then clear rotated actor as well.
+ ResetActor();
+ }
+
+ // Clear current emitters if rotation gesture has ended or been cancelled.
+ if ( rotationEvent.state == Gesture::Finished || rotationEvent.state == Gesture::Cancelled )
+ {
+ mCurrentRotationEmitters.clear();
+ ResetActor();
+ }
+ }
+ else
+ {
+ mCurrentRotationEmitters.clear();
+ ResetActor();
+ }
+ }
+ break;
+ }
+
+ case Gesture::Clear:
+ case Gesture::Possible:
+ {
+ // Nothing to do
+ break;
+ }
+ }
+}
+
+void RotationGestureProcessor::AddGestureDetector( RotationGestureDetector* gestureDetector, Scene& /* scene */ )
+{
+ bool createRecognizer(mRotationGestureDetectors.empty());
+
+ mRotationGestureDetectors.push_back(gestureDetector);
+
+ if (createRecognizer)
+ {
+ mGestureRecognizer = new RotationGestureRecognizer( *this );
+ }
+}
+
+void RotationGestureProcessor::RemoveGestureDetector( RotationGestureDetector* gestureDetector )
+{
+ if ( !mCurrentRotationEmitters.empty() )
+ {
+ // Check if the removed detector was one that is currently being rotated and remove it from emitters.
+ GestureDetectorContainer::iterator endIter = std::remove( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), gestureDetector );
+ mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
+
+ // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
+ if ( mCurrentRotationEmitters.empty() )
+ {
+ ResetActor();
+ }
+ }
+
+ // Find the detector...
+ RotationGestureDetectorContainer::iterator endIter = std::remove( mRotationGestureDetectors.begin(), mRotationGestureDetectors.end(), gestureDetector );
+ DALI_ASSERT_DEBUG( endIter != mRotationGestureDetectors.end() );
+
+ // ...and remove it
+ mRotationGestureDetectors.erase(endIter, mRotationGestureDetectors.end());
+
+ if (mRotationGestureDetectors.empty())
+ {
+ mGestureRecognizer.Detach();
+ }
+}
+
+void RotationGestureProcessor::OnGesturedActorStageDisconnection()
+{
+ mCurrentRotationEmitters.clear();
+}
+
+bool RotationGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
+{
+ // No special case required for rotation.
+ return true;
+}
+
+void RotationGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
+{
+ DALI_ASSERT_DEBUG( mCurrentRotationEvent );
+
+ EmitRotationSignal( actor, gestureDetectors, *mCurrentRotationEvent, actorCoordinates );
+
+ if ( actor->OnStage() )
+ {
+ mCurrentRotationEmitters = gestureDetectors;
+ SetActor( actor );
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ROTATION_GESTURE_EVENT_PROCESSOR_H
+#define DALI_INTERNAL_ROTATION_GESTURE_EVENT_PROCESSOR_H
+
+/*
+ * Copyright (c) 2019 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/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h>
+#include <dali/internal/event/events/gesture-processor.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+class Scene;
+class Stage;
+
+struct RotationGestureEvent;
+
+/**
+ * Rotation Gesture Event Processing:
+ *
+ * When we receive a rotation gesture event, we do the following:
+ * - Find the hit actor that requires a rotation underneath the center-point of the rotation.
+ * - Emit the gesture if the event satisfies the detector conditions.
+ *
+ * The above is only checked when our gesture starts. We continue sending the rotation gesture to this
+ * detector until the rotation ends or is cancelled.
+ */
+class RotationGestureProcessor : public GestureProcessor, public RecognizerObserver<RotationGestureEvent>
+{
+public:
+
+ /**
+ * Create a rotation gesture processor.
+ */
+ RotationGestureProcessor();
+
+ /**
+ * Non-virtual destructor; RotationGestureProcessor is not a base class
+ */
+ ~RotationGestureProcessor() = default;
+
+ RotationGestureProcessor( const RotationGestureProcessor& ) = delete; ///< Deleted copy constructor.
+ RotationGestureProcessor& operator=( const RotationGestureProcessor& rhs ) = delete; ///< Deleted copy assignment operator.
+
+public: // To be called by GestureEventProcessor
+
+ /**
+ * This method is called whenever a rotation gesture event occurs.
+ * @param[in] scene The scene the rotation gesture event occurs in.
+ * @param[in] rotationEvent The event that has occurred.
+ */
+ void Process( Scene& scene, const RotationGestureEvent& rotationEvent );
+
+ /**
+ * Adds a gesture detector to this gesture processor.
+ * If this is the first gesture detector being added, then this method registers the required
+ * gesture with the adaptor.
+ * @param[in] gestureDetector The gesture detector being added
+ * @param[in] scene The scene the rotation gesture occurred in
+ */
+ void AddGestureDetector( RotationGestureDetector* gestureDetector, Scene& scene );
+
+ /**
+ * Removes the specified gesture detector from this gesture processor. If, after removing this
+ * gesture detector, there are no more gesture detectors registered, then this method unregisters
+ * the gesture from the adaptor.
+ * @param[in] gestureDetector The gesture detector being removed.
+ */
+ void RemoveGestureDetector( RotationGestureDetector* gestureDetector );
+
+private:
+
+ // GestureProcessor overrides
+
+ /**
+ * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
+ */
+ void OnGesturedActorStageDisconnection();
+
+ /**
+ * @copydoc GestureProcessor::CheckGestureDetector()
+ */
+ bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
+
+ /**
+ * @copydoc GestureProcessor::EmitGestureSignal()
+ */
+ void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
+
+private:
+
+ RotationGestureDetectorContainer mRotationGestureDetectors;
+ GestureDetectorContainer mCurrentRotationEmitters;
+ RenderTaskPtr mCurrentRenderTask;
+
+ const RotationGestureEvent* mCurrentRotationEvent; ///< Pointer to current RotationEvent, used when calling ProcessAndEmit()
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ROTATION_GESTURE_EVENT_PROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/devel-api/events/gesture-devel.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
+#include <dali/internal/event/common/scene-impl.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED = 4;
+const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4;
+
+inline float GetAngle( const Integration::Point& point1, const Integration::Point& point2 )
+{
+ const Vector2& point1ScreenPosition = point1.GetScreenPosition();
+ const Vector2& point2ScreenPosition = point2.GetScreenPosition();
+ return atan2( point2ScreenPosition.y - point1ScreenPosition.y, point2ScreenPosition.x - point1ScreenPosition.x );
+}
+
+inline Vector2 GetCenterPoint( const Integration::Point& point1, const Integration::Point& point2 )
+{
+ return Vector2( point1.GetScreenPosition() + point2.GetScreenPosition() ) * 0.5f;
+}
+
+} // unnamed namespace
+
+RotationGestureRecognizer::RotationGestureRecognizer( Observer& observer )
+: GestureRecognizer( DevelGesture::Rotation ),
+ mObserver( observer ),
+ mState( Clear ),
+ mTouchEvents(),
+ mStartingAngle( 0.0f )
+{
+}
+
+void RotationGestureRecognizer::SendEvent( const Integration::TouchEvent& event )
+{
+ int pointCount = event.GetPointCount();
+
+ switch( mState )
+ {
+ case Clear:
+ {
+ if( pointCount == 2 )
+ {
+ // Change state to possible as we have two touch points.
+ mState = Possible;
+ mTouchEvents.push_back( event );
+ }
+ break;
+ }
+
+ case Possible:
+ {
+ if ( pointCount != 2 )
+ {
+ // We no longer have two touch points so change state back to Clear.
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ const Integration::Point& currentPoint1 = event.points[0];
+ const Integration::Point& currentPoint2 = event.points[1];
+
+ if( currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP )
+ {
+ // One of our touch points has an Up event so change our state back to Clear.
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ mTouchEvents.push_back( event );
+
+ // We can only determine a rotation after a certain number of touch points have been collected.
+ if( mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED )
+ {
+ // Remove the first few events from the vector otherwise values are exaggerated
+ mTouchEvents.erase( mTouchEvents.begin(), mTouchEvents.end() - MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START );
+
+ if( !mTouchEvents.empty() )
+ {
+ mStartingAngle = GetAngle( mTouchEvents.begin()->points[0], mTouchEvents.begin()->points[1] );
+
+ // Send rotation started
+ SendRotation( Gesture::Started, event );
+
+ mState = Started;
+ }
+
+ mTouchEvents.clear();
+
+ if( mState == Possible )
+ {
+ // No rotation, so restart detection
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case Started:
+ {
+ if( pointCount != 2 )
+ {
+ // Send rotation finished event
+ SendRotation( Gesture::Finished, event );
+
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ const Integration::Point& currentPoint1 = event.points[0];
+ const Integration::Point& currentPoint2 = event.points[1];
+
+ if( ( currentPoint1.GetState() == PointState::UP ) ||
+ ( currentPoint2.GetState() == PointState::UP ) )
+ {
+ mTouchEvents.push_back( event );
+ // Send rotation finished event
+ SendRotation( Gesture::Finished, event );
+
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ mTouchEvents.push_back( event );
+
+ if( mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
+ {
+ // Send rotation continuing
+ SendRotation( Gesture::Continuing, event );
+
+ mTouchEvents.clear();
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+void RotationGestureRecognizer::SendRotation( Gesture::State state, const Integration::TouchEvent& currentEvent )
+{
+ RotationGestureEvent gesture( state );
+
+ if( !mTouchEvents.empty() )
+ {
+ // Assert if we have been holding TouchEvents that do not have 2 points
+ DALI_ASSERT_DEBUG( mTouchEvents[0].GetPointCount() == 2 );
+
+ // We should use the current event in our calculations unless it does not have two points.
+ // If it does not have two points, then we should use the last point in mTouchEvents.
+ Integration::TouchEvent event( currentEvent );
+ if( event.GetPointCount() != 2 )
+ {
+ event = *mTouchEvents.rbegin();
+ }
+
+ const Integration::Point& currentPoint1( event.points[0] );
+ const Integration::Point& currentPoint2( event.points[1] );
+
+ gesture.rotation = GetAngle( currentPoint1, currentPoint2 ) - mStartingAngle;
+ gesture.centerPoint = GetCenterPoint( currentPoint1, currentPoint2 );
+ }
+ else
+ {
+ // Something has gone wrong, just cancel the gesture.
+ gesture.state = Gesture::Cancelled;
+ }
+
+ gesture.time = currentEvent.time;
+
+ if( mScene )
+ {
+ // Create another handle so the recognizer cannot be destroyed during process function
+ GestureRecognizerPtr recognizerHandle = this;
+
+ mObserver.Process( *mScene, gesture );
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_ROTATION_GESTURE_RECOGNIZER_H
+#define DALI_INTERNAL_EVENT_ROTATION_GESTURE_RECOGNIZER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-recognizer.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+}
+
+namespace Internal
+{
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a rotation gesture has taken place.
+ */
+class RotationGestureRecognizer : public GestureRecognizer
+{
+public:
+
+ using Observer = RecognizerObserver< RotationGestureEvent >;
+
+ /**
+ * Constructor
+ * @param[in] observer The observer to send gesture too when it's detected
+ */
+ RotationGestureRecognizer( Observer& observer );
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~RotationGestureRecognizer() = default;
+
+public:
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+ */
+ virtual void SendEvent( const Integration::TouchEvent& event );
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+ */
+ virtual void Update( const GestureRequest& request ) { /* Nothing to do */ }
+
+private:
+
+ /**
+ * Emits the rotation gesture event to the core.
+ * @param[in] state The state of the rotation (whether it's starting, continuing or finished).
+ * @param[in] currentEvent The latest touch event.
+ */
+ void SendRotation( Gesture::State state, const Integration::TouchEvent& currentEvent );
+
+private:
+
+ // Reference to the gesture processor for this recognizer
+ Observer& mObserver;
+
+ /**
+ * Internal state machine.
+ */
+ enum State
+ {
+ Clear, ///< No gesture detected.
+ Possible, ///< The current touch event data suggests that a gesture is possible.
+ Started, ///< A gesture has been detected.
+ };
+
+ State mState; ///< The current state of the detector.
+ std::vector< Integration::TouchEvent > mTouchEvents; ///< The touch events since initial touch down.
+
+ float mStartingAngle; ///< The angle between the two touch points when the rotation is first detected.
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_ROTATION_GESTURE_RECOGNIZER_H
${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-event.cpp
${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-processor.cpp
${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-recognizer.cpp
+ ${internal_src_dir}/event/events/rotation-gesture/rotation-gesture-detector-impl.cpp
+ ${internal_src_dir}/event/events/rotation-gesture/rotation-gesture-processor.cpp
+ ${internal_src_dir}/event/events/rotation-gesture/rotation-gesture-recognizer.cpp
${internal_src_dir}/event/events/tap-gesture/tap-gesture-detector-impl.cpp
${internal_src_dir}/event/events/tap-gesture/tap-gesture-event.cpp
${internal_src_dir}/event/events/tap-gesture/tap-gesture-processor.cpp