--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mulwidgets/gesturehelper/src/gesturerecogniser.cpp Thu Dec 17 08:56:02 2009 +0200
@@ -0,0 +1,285 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Gesture helper implementation
+*
+*/
+
+#include "gesturerecogniser.h"
+
+#include <e32math.h>
+
+#include "gesturedefs.h"
+#include "gestureobserver.h"
+#include "pointarray.h"
+#include "utils.h"
+
+#include <w32std.h> // pointerevents
+
+using namespace GestureHelper;
+
+/**
+ * Vector class (math)
+ */
+NONSHARABLE_CLASS( TVector )
+ {
+public:
+ /**
+ * Constructor
+ * @param aFrom starting point of the vector
+ * @param aTo ending point of the vector
+ */
+ TVector( const TPoint& aFrom, const TPoint& aTo )
+ : iX( aTo.iX - aFrom.iX ),
+ iY( aTo.iY - aFrom.iY )
+ {
+ }
+
+ /** @return angle of the vector */
+ TReal Angle() const
+ {
+ TReal angle = 0;
+ TReal length = Length();
+ if ( length != 0 )
+ {
+ Math::ACos( angle, iX / Length() );
+ if ( iY < 0 )
+ {
+ angle = 2 * KPi - angle;
+ }
+ }
+ return Degrees( angle );
+ }
+
+ /** @return length of the vector */
+ TReal Length() const
+ {
+ TReal length = 0;
+ Math::Sqrt( length, iX * iX + iY * iY );
+ return length;
+ }
+
+private:
+ /** @return radians in degrees */
+ inline TReal Degrees( TReal aRadians ) const
+ {
+ return aRadians * 180 / KPi;
+ }
+
+public:
+ /// x coordinate that represent the vector
+ TReal iX;
+ /// y coordinate that represent the vector
+ TReal iY;
+ };
+
+inline TPoint LastPoint( const TPointArray& aPoints )
+ {
+ __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+ return aPoints[ aPoints.Count() - 1 ] ;
+ }
+
+/**
+ * @return Length of the gesture in points
+ */
+inline TReal GestureLength( const TPointArray& aPoints )
+ {
+ return TVector( aPoints[0], LastPoint( aPoints ) ).Length();
+ }
+
+/**
+ * @return ETrue if aAngleUnderTest is almost aAngle
+ * Closeness of the angles is controlled by KAngleTolerance
+ */
+static TBool IsNear( TReal aAngleUnderTest, TReal aAngle )
+ {
+ return aAngle - KAngleTolerance <= aAngleUnderTest &&
+ aAngleUnderTest <= aAngle + KAngleTolerance;
+ }
+
+/**
+ * @return the angle as a direction flags of TGesture
+ */
+inline TGestureCode Direction( TReal aAngle )
+ {
+ TGestureCode direction = EGestureUnknown;
+
+ if ( IsNear( aAngle, 90.0 ) )
+ {
+ direction = EGestureSwipeDown;
+ }
+ else if ( IsNear( aAngle, 180.0 ) )
+ {
+ direction = EGestureSwipeLeft;
+ }
+ else if ( IsNear( aAngle, 270.0 ) )
+ {
+ direction = EGestureSwipeUp;
+ }
+ else if ( 360.0 - KAngleTolerance <= aAngle || aAngle <= KAngleTolerance )
+ {
+ direction = EGestureSwipeRight;
+ }
+ else // for lint warning
+ {
+ // unknown angle
+ }
+
+ return direction;
+ }
+
+/** @return direction between points */
+inline TGestureCode Direction( const TPoint& aFromPoint, const TPoint& aToPoint )
+ {
+ return Direction( TVector( aFromPoint, aToPoint ).Angle() );
+ }
+
+// function type to get a point in the point array
+typedef TPoint (TPointArray::*PointByIndexFunc)( TInt aIndex ) const;
+
+/// @return latest point outside tolerance area or KErrNotFound if not point outside it
+TInt LatestCertainPointIndex( const TPointArray& aPoints, PointByIndexFunc aPointByIndex, TRect aToleranceRect )
+ {
+ int i = aPoints.Count();
+ // Find out the first point from the end of the array
+ // that is not contained in the tolerance rect.
+ while( 0 <= --i )
+ {
+ // if the point does not belong inside tolerance rect, it is the first point
+ // outside the rect
+ if( !aToleranceRect.Contains( (aPoints.*aPointByIndex)(i) ) )
+ {
+ break;
+ }
+ }
+ return i;
+ }
+
+/** @return last direction of dragging */
+inline TGestureCode LastDirection( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis )
+ {
+ __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+
+ TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::operator[])(aPoints.Count() - 1), aRelevantAxis );
+
+ TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[],toleranceRect );
+ if ( KErrNotFound != latestPointIndex )
+ {
+ return Direction( aPoints[latestPointIndex], LastPoint( aPoints ) );
+ }
+ // no points were outside the rect, and hence the direction is unknown
+ return EGestureUnknown;
+ }
+
+/**
+ * @return ETrue if points for a tap event
+ */
+inline TBool IsTap( const TPointArray& aPoints )
+ {
+ __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+
+ TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::Raw)(0) );
+
+ return KErrNotFound == LatestCertainPointIndex( aPoints, TPointArray::Raw,toleranceRect );
+ }
+
+// ----------------------------------------------------------------------------
+// Return gesture code of a gesture formed by a sequence of points
+// ----------------------------------------------------------------------------
+//
+TGestureCode TGestureRecogniser::GestureCode( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) const
+ {
+ __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+
+ // tap needs to be treated separately, because recognising that needs to consider
+ // raw points (and not points in which x or y axis has been filtered out)
+ if ( IsTap( aPoints ) )
+ {
+ return EGestureTap;
+ }
+
+ return LastDirection( aPoints, aRelevantAxis );
+ }
+
+// ----------------------------------------------------------------------------
+// Return gesture code of a gesture formed by a sequence of points
+// ----------------------------------------------------------------------------
+//
+TGestureCode TGestureRecogniser::MultiTouchGestureCode( const TPointArray& aPoints, const TPointArray& aSecondaryPoints,
+ TInt aPreviousDistance, TBool aIsFirstPinch ) const
+ {
+ __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+ __ASSERT_DEBUG( aSecondaryPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+ __ASSERT_DEBUG( aPreviousDistance > 0, Panic( EGesturePanicIllegalLogic ) );
+
+ TInt currentDistance = TVector( LastPoint( aPoints ), LastPoint( aSecondaryPoints ) ).Length();
+
+ // currently gesture tolerance is used as reference to identify the pinch
+ // and it is same for first time recognition and also for pinch thereon
+ // This can be changed to an independent constant if required
+ // This is now implemeted. We have different tolerance for intial pinch and pinhc theron
+
+ // We need to have different tolerance at the time of changing direction.
+ // When user is pinching in and then starts pinching out the tolerance should be different.
+ // This is implemented in CGesture class. aIsFirstPinch will take care of all this
+ TInt pinchTolerance = aIsFirstPinch ? KInitialPinchTolerance : KPinchTolerance;
+ if (Abs( currentDistance - aPreviousDistance ) >= pinchTolerance )
+ {
+ return EGesturePinch;
+ }
+ return EGestureUnknown;
+ }
+
+// ----------------------------------------------------------------------------
+// Validate the drag formed by a sequence of points. If all the points are
+// within the tolerance rect then the gesture is not recognised.
+// ----------------------------------------------------------------------------
+//
+TGestureCode TGestureRecogniser::ValidateDrag( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) const
+ {
+ __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) );
+
+ TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::operator[])(aPoints.Count() - 1), aRelevantAxis );
+
+ TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[],toleranceRect );
+ if ( KErrNotFound != latestPointIndex )
+ {
+ return EGestureDrag;
+ }
+ // no points were outside the rect, and hence the direction is unknown
+ return EGestureUnknown;
+ }
+
+// ----------------------------------------------------------------------------
+// Return the length between the given two points
+// ----------------------------------------------------------------------------
+//
+TInt TGestureRecogniser::Length( const TPoint aPoint, const TPoint aSecondaryPoint ) const
+ {
+ return TVector(aPoint,aSecondaryPoint).Length();
+ }
+
+// ----------------------------------------------------------------------------
+// Return pointer number fetched from the given event
+// ----------------------------------------------------------------------------
+//
+TInt TGestureRecogniser::PointerNumber( const TPointerEvent& aEvent )
+ {
+ if( aEvent.IsAdvancedPointerEvent() )
+ {
+ return aEvent.AdvancedPointerEvent()->PointerNumber();
+ }
+ return 0;
+ }
+// end of file
+