diff -r 4526337fb576 -r 3eca7e70b1b8 mulwidgets/gesturehelper/src/gesture.cpp --- a/mulwidgets/gesturehelper/src/gesture.cpp Tue Feb 02 00:28:09 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,931 +0,0 @@ -/* -* Copyright (c) 2008-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 class -* -*/ - -#include "gesture.h" - -#include - -#include "gesturedefs.h" -#include "utils.h" - -using namespace GestureHelper; - -/** - * Point array for which only x axis is relevant - */ -class TXAxisPointArray : public TPointArray - { -public: - TXAxisPointArray( const RArray< TPointEntry >& aPoints ) - : TPointArray( aPoints ) {} - - // from TPointArray - TPoint operator[]( TInt aIndex ) const - { - return TPoint( Raw( aIndex ).iX, 0 ); - } - }; - -/** - * Point array for which only y axis is relevant - */ -class TYAxisPointArray : public TPointArray - { -public: - TYAxisPointArray( const RArray< TPointEntry >& aPoints ) - : TPointArray( aPoints ) {} - - // from TPointArray - TPoint operator[]( TInt aIndex ) const - { - return TPoint( 0, Raw( aIndex ).iY ); - } - }; - -namespace - { - /** @return the current time */ - TTime CurrentTime() - { - TTime time; - time.UniversalTime(); - return time; - } - - /** - * @param aRelevantAxis See @ref MGestureEvent::Code - * @return gesture code by analysing the sequence of points - */ - TGestureCode CodeFromPoints( const RArray< TPointEntry >& aPoints, - MGestureEvent::TAxis aRelevantAxis ) - { - // select the correct filter based on aRelevantAxis - // these filter_ objects are array decorators that will eliminate either - // x, y or neither coordinate of each point - TXAxisPointArray filterY( aPoints ); - TYAxisPointArray filterX( aPoints ); - TPointArray filterNone( aPoints ); - TPointArray& filter = - aRelevantAxis == MGestureEvent::EAxisHorizontal ? static_cast< TPointArray& >( filterY ) : - aRelevantAxis == MGestureEvent::EAxisVertical ? static_cast< TPointArray& >( filterX ) : - /* otherwise EAxisBoth */ filterNone; - - // currently the gesture recogniser does not have any state, so it is fast - // to instantiate. The call is not static however, to allow the recogniser - // to be replaced by a more complicated implementation that has state. - // then it may make sense to make the recogniser a member variable. - return TGestureRecogniser().GestureCode( filter, aRelevantAxis ); - } - - /** - * @param aPoints Sequence of points representing 1st pointer movement - * @param aSecondaryPoints Sequence of points representing 2nd pointer movement - * @param aPreviousDistance contains the previous distance aftre this function execution - * @return gesture code by analysing the sequence of points - */ - TGestureCode MultiTouchCode( const RArray< TPointEntry >& aPoints, - const RArray< TPointEntry >& aSecondaryPoints, TInt aPreviousDistance, TBool aIsFirstPinch ) - { - TPointArray filter(aPoints); - TPointArray secondaryFilter(aSecondaryPoints); - return TGestureRecogniser().MultiTouchGestureCode( filter, secondaryFilter, aPreviousDistance, aIsFirstPinch ); - } - } // unnamed namespace - -// ---------------------------------------------------------------------------- -// constructor -// ---------------------------------------------------------------------------- -// -CGesture::CGesture() - { - iPinchStartDistance = -1; - iPinchEndDistance = -1; - iPinchDetected = EFalse ; - } - -// ---------------------------------------------------------------------------- -// destructor -// ---------------------------------------------------------------------------- -// -CGesture::~CGesture() - { - iPoints.Close(); - iSecondaryPoints.Close(); - } - -// ---------------------------------------------------------------------------- -// AsStartEventL -// ---------------------------------------------------------------------------- -// -CGesture* CGesture::AsStartEventLC() const - { - __ASSERT_DEBUG( 0 < iPoints.Count(), Panic( EGesturePanicIllegalLogic ) ); - CGesture* gesture = new ( ELeave ) CGesture; - CleanupStack::PushL( gesture ); - User::LeaveIfError( gesture->AddPoint( iPoints[0].iPos ) ); - return gesture; - } - -// ---------------------------------------------------------------------------- -// ResetToLastPoint -// ---------------------------------------------------------------------------- -// -void CGesture::ResetToLastPoint(TBool aSetPointerZero,TBool aSetToZero) - { - TPointEntry lastEntry(TPoint(0,0),TTime()); - if( aSetToZero ) - { - __ASSERT_DEBUG( 0 < iPoints.Count(), Panic( EGesturePanicIllegalLogic ) ); - lastEntry = LastPoint( iPoints); - } - else - { - __ASSERT_DEBUG( 0 < iSecondaryPoints.Count(), Panic( EGesturePanicIllegalLogic ) ); - lastEntry = LastPoint( iSecondaryPoints); - } - Reset(); - if( aSetPointerZero ) - { - iPoints.Append(lastEntry); - } - else - { - iSecondaryPoints.Append(lastEntry); - } - } - -// ---------------------------------------------------------------------------- -// LastPoint -// ---------------------------------------------------------------------------- -// -inline const TPointEntry CGesture::LastPoint( const RArray< TPointEntry >& aPoints ) const - { - return aPoints[aPoints.Count() - 1]; - } - -// ---------------------------------------------------------------------------- -// IsPinchToleranceHigh -// ---------------------------------------------------------------------------- -// -inline TBool CGesture::IsHighPinchTolerance() const - { - - if( iPinchEndDistance == -1 ) - { - return ETrue; - } - else - { - TInt currentDistance = TGestureRecogniser().Length( LastPoint(iPoints).iPos, LastPoint(iSecondaryPoints).iPos ); - // if previously zooming out and current distance corresponds to zooming in or viceversa - if( ( iZoomState == EZoomOut && currentDistance < iPinchStartDistance) || - ( iZoomState == EZoomIn && currentDistance > iPinchStartDistance)) - { - return ETrue; - } - } - return EFalse; - } -// ---------------------------------------------------------------------------- -// Reset -// ---------------------------------------------------------------------------- -// -void CGesture::Reset() - { - iPoints.Reset(); - iSecondaryPoints.Reset(); - iHoldingState = ENotHolding; - iState = ENotActive; - iHoldingPointIndex = 0; - iVisual = NULL; - iIsDoubleTap = EFalse; - iPinchStartDistance = -1; - iPinchEndDistance = -1; - iPinchDetected = EFalse; - iZoomState = ENoZoom; - } - -// ---------------------------------------------------------------------------- -// IsEmpty -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsEmpty() const - { - return iPoints.Count() == 0; - } - -// ---------------------------------------------------------------------------- -// IsMultiTouch -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsMultiTouch() const - { - return iSecondaryPoints.Count() == 0; - } - -// ---------------------------------------------------------------------------- -// Add a point to the sequence of points that together make up the gesture -// ---------------------------------------------------------------------------- -// -TInt CGesture::AddPoint( const TPoint& aPoint ) - { - if ( !IsLatestPoint( aPoint ) ) - { - return iPoints.Append( TPointEntry( aPoint, CurrentTime() ) ); - } - return KErrNone; - } - -// ---------------------------------------------------------------------------- -// AddSecondaryPoint -// ---------------------------------------------------------------------------- -// -TInt CGesture::AddSecondaryPoint( const TPoint& aPoint ) - { - if ( !IsLatestSecondaryPoint( aPoint ) ) - { - return iSecondaryPoints.Append( TPointEntry( aPoint, CurrentTime() ) ); - } - return KErrNone; - } - -// ---------------------------------------------------------------------------- -// SetVisual -// ---------------------------------------------------------------------------- -// -void CGesture::SetVisual( CAlfVisual* aVisual ) - { - iVisual = aVisual; - } - -// ---------------------------------------------------------------------------- -// IsNearHoldingPoint -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsNearHoldingPoint( const TPoint& aPoint ) const - { - return ToleranceRect( iPoints[ iHoldingPointIndex ].iPos ).Contains( aPoint ); - } - -// ---------------------------------------------------------------------------- -// IsLatestPoint -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsLatestPoint( const TPoint& aPoint ) const - { - if ( iPoints.Count() > 0 ) - { - return aPoint == CurrentPos(); - } - return EFalse; - } -// ---------------------------------------------------------------------------- -// IsLatestSecondaryPoint -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsLatestSecondaryPoint( const TPoint& aPoint ) const - { - if ( iSecondaryPoints.Count() > 0 ) - { - return aPoint == iSecondaryPoints[ iSecondaryPoints.Count() - 1 ].iPos; - } - return EFalse; - } - -// ---------------------------------------------------------------------------- -// StartHolding -// ---------------------------------------------------------------------------- -// -void CGesture::StartHolding() - { - iHoldingState = EHoldStarting; - - // remove all points that were introduced after holding started - for ( TInt i = iPoints.Count() - 1; i > iHoldingPointIndex; i-- ) - { - iPoints.Remove( i ); - } - } - -// ---------------------------------------------------------------------------- -// SetHoldingPoint -// ---------------------------------------------------------------------------- -// -void CGesture::SetHoldingPoint() - { - iHoldingPointIndex = iPoints.Count() - 1; - } - -// ---------------------------------------------------------------------------- -// ContinueHolding -// ---------------------------------------------------------------------------- -// -void CGesture::ContinueHolding() - { - iHoldingState = EHolding; - } - -// ---------------------------------------------------------------------------- -// SetSingleTouchActive -// ---------------------------------------------------------------------------- -// -void CGesture::SetSingleTouchActive() - { - __ASSERT_DEBUG( ENotActive == iState, Panic( EGesturePanicIllegalLogic ) ); - iState = ESingleTouchActive; - } -// ---------------------------------------------------------------------------- -// SetMultiTouchActive -// ---------------------------------------------------------------------------- -// -void CGesture::SetMultiTouchActive() - { - iState = EMultiTouchActive; - iIsMultiTouched = ETrue; - } -// ---------------------------------------------------------------------------- -// SetSingleTouchReleased -// ---------------------------------------------------------------------------- -// -void CGesture::SetSingleTouchReleased() - { - // IsMovementStopped expects corresponding SetComplete to be called before SetRelease - __ASSERT_DEBUG( ESingleTouchComplete == iState, Panic( EGesturePanicIllegalLogic ) ); - iState = ESingleTouchReleased; - iIsMultiTouched = EFalse; - } -// ---------------------------------------------------------------------------- -// SetMultiTouchReleased -// ---------------------------------------------------------------------------- -// -void CGesture::SetMultiTouchReleased() - { - // IsMovementStopped expects corresponding SetComplete to be called before SetRelease - __ASSERT_DEBUG( EMultiTouchComplete == iState, Panic( EGesturePanicIllegalLogic ) ); - iState = EMultiTouchReleased; - } - -/** - * @return elapsed time between aStartTime and aEndTime - */ -inline TTimeIntervalMicroSeconds32 Elapsed( const TTime& aStartTime, - const TTime& aEndTime ) - { - return aEndTime.MicroSecondsFrom( aStartTime ).Int64(); - } - -// ---------------------------------------------------------------------------- -// SetSingleTouchComplete -// ---------------------------------------------------------------------------- -// -void CGesture::SetSingleTouchComplete() - { - __ASSERT_DEBUG( iPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); - iState = ESingleTouchComplete; - iCompletionTime = CurrentTime(); - } - -// ---------------------------------------------------------------------------- -// SetMultiTouchComplete -// ---------------------------------------------------------------------------- -// -void CGesture::SetMultiTouchComplete() - { - __ASSERT_DEBUG( iSecondaryPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); - iState = EMultiTouchComplete; - } - -// ---------------------------------------------------------------------------- -// SetCancelled -// ---------------------------------------------------------------------------- -// -void CGesture::SetCancelled() - { - iState = ECancelled; - } - -// ---------------------------------------------------------------------------- -// SetDoubleTap -// ---------------------------------------------------------------------------- -// -void CGesture::SetDoubleTap() - { - iIsDoubleTap = ETrue; - } - -// ---------------------------------------------------------------------------- -// IsTap -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsTap() const - { - if(iIsMultiTouched) - { - return EFalse; - } - return CodeFromPoints( iPoints, EAxisBoth ) == EGestureTap; - } - -// ---------------------------------------------------------------------------- -// IsPinch -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsPinch() - { - if (iPinchStartDistance == -1 ) - { - iPinchStartDistance = TGestureRecogniser().Length( iPoints[0].iPos, iSecondaryPoints[0].iPos ) ; - } - // if there is a pinch detected in the last attempt then update the start distance. - // henceforth this new distance is used as reference for calculating the pinch. - - if( iPinchDetected ) - { - iPinchStartDistance = iPinchEndDistance; - } - iPinchDetected = MultiTouchCode( iPoints, iSecondaryPoints, iPinchStartDistance,IsHighPinchTolerance()) == EGesturePinch; - if( iPinchDetected ) - { - // This end distance is updated the first time the pinch is detected. - // This is done the save the value of pinch end distnce for further refernce to - // update the pinch start distance next time any pointer position changes. - iPinchEndDistance = TGestureRecogniser().Length( - LastPoint(iPoints).iPos,LastPoint(iSecondaryPoints).iPos ); - iZoomState = iPinchEndDistance > iPinchStartDistance ? EZoomOut : EZoomIn; - } - return iPinchDetected; - } - -/** - * Translates a non-holding code into a holding code - * @param aCode original gesture code - * @return a gesture code with hold flag applied - */ -inline TGestureCode Hold( TGestureCode aCode ) - { - if ( aCode != EGestureStart && - aCode != EGestureDrag && - aCode != EGestureReleased && - aCode != EGestureUnknown ) - { - return static_cast< TGestureCode >( aCode | EFlagHold ); - } - return aCode; - } - -// ---------------------------------------------------------------------------- -// Code -// ---------------------------------------------------------------------------- -// -TGestureCode CGesture::Code( TAxis aRelevantAxis ) const - { - switch ( iState ) - { - case ESingleTouchActive: - // "start" event if only first point received - // need to check that not holding, in case user pressed stylus - // down, and activated holding without moving the stylus - if ( iPoints.Count() == 1 && !IsHolding() ) - { - return EGestureStart; - } - // "drag" event if holding not started or holding started earlier - else if ( iHoldingState != EHoldStarting ) - { - // select the correct filter based on aRelevantAxis - // these filter_ objects are array decorators that will eliminate either - // x, y or neither coordinate of each point - TXAxisPointArray filterY( iPoints ); - TYAxisPointArray filterX( iPoints ); - TPointArray filterNone( iPoints ); - TPointArray& filter = - aRelevantAxis == MGestureEvent::EAxisHorizontal ? static_cast< TPointArray& >( filterY ) : - aRelevantAxis == MGestureEvent::EAxisVertical ? static_cast< TPointArray& >( filterX ) : - /* otherwise EAxisBoth */ filterNone; - - return TGestureRecogniser().ValidateDrag( filter, aRelevantAxis ); - } - // holding was just started - else - { - return Hold( CodeFromPoints( iPoints, aRelevantAxis ) ); - } - - case EMultiTouchActive: - // Only if there are some points in secondary array - if ( iSecondaryPoints.Count() == 1 && iPoints.Count() == 1 ) - { - return EGestureMultiTouchStart; - } - else - { - return MultiTouchCode( iPoints, iSecondaryPoints, iPinchStartDistance,IsHighPinchTolerance() ); - } - - case ESingleTouchComplete: - { - if ( iIsDoubleTap ) - { - return EGestureDoubleTap; - } - - // If there was a mulitouch within the last gesture then ignore the tap - TGestureCode gestureCode = CodeFromPoints( iPoints, aRelevantAxis ); - if( gestureCode == EGestureTap && iIsMultiTouched) - { - return EGestureUnknown; - } - return gestureCode; - } - case EMultiTouchComplete: - return MultiTouchCode( iPoints, iSecondaryPoints, iPinchStartDistance,IsHighPinchTolerance()); - - case ESingleTouchReleased: - return EGestureReleased; - case EMultiTouchReleased: - return EGestureMultiTouchReleased; - - case ECancelled: // fallthrough - case ENotActive: - default: - return EGestureUnknown; - } - } - -// ---------------------------------------------------------------------------- -// IsHolding -// ---------------------------------------------------------------------------- -// -TBool CGesture::IsHolding() const - { - return iHoldingState >= EHoldStarting; - } - -// ---------------------------------------------------------------------------- -// StartPos -// ---------------------------------------------------------------------------- -// -TPoint CGesture::StartPos() const - { - // at least one point will be in the array during callback (pointer down pos) - return iPoints[ 0 ].iPos; - } - -// ---------------------------------------------------------------------------- -// CurrentPos -// ---------------------------------------------------------------------------- -// -TPoint CGesture::CurrentPos() const - { - // at least on point will be in the array during callback (pointer down pos) - return iPoints[ iPoints.Count() - 1 ].iPos; - } - -// ---------------------------------------------------------------------------- -// IsMovementStopped -// ---------------------------------------------------------------------------- -// -inline TBool CGesture::IsMovementStopped() const - { - // iCompletionTime is only only valid if client has called SetComplete - if ( iState >= ESingleTouchComplete ) - { - return Elapsed( NthLastEntry( 1 ).iTime, iCompletionTime ).Int() > KSpeedStopTime; - } - return EFalse; - } - -namespace - { - const TInt KFloatingPointAccuracy = 0.000001; - - /** @return percentage (0.0-1.0) how far aPos is from aEdge1 towards aEdge2 */ - inline TReal32 Proportion( TReal32 aPos, TReal32 aEdge1, TReal32 aEdge2 ) - { - if ( Abs( aEdge2 - aEdge1 ) > KFloatingPointAccuracy ) - { - return ( aPos - aEdge1 ) / ( aEdge2 - aEdge1 ); - } - return 0; // avoid division by zero - } - - /** Edges (pixels) at which speed should be -100% or 100% */ - NONSHARABLE_STRUCT( TEdges ) - { - TReal32 iMin; - TReal32 iMax; - }; - - /** - * scale which allows different (coordinate -> percentage) mapping - * between -100% to 0% and 0 and 100% - */ - NONSHARABLE_STRUCT( TScale ) - { - TScale( TInt aZero, const TEdges& aEdges ) - : iMin( aEdges.iMin ), iZero( aZero ), iMax( aEdges.iMax ) - { - } - - /** @return aPos as a percentage between -100% and 100% in aScale */ - TReal32 Percent( TReal32 aPos ) const; - - /// coordinate where speed is -100% - TReal32 iMin; - /// coordinate where speed is 0% - TReal32 iZero; - /// coordinate where speed is 100% - TReal32 iMax; - }; - - /** @convert aPos into a percentage between -100% and 100% in aScale */ - TReal32 TScale::Percent( TReal32 aPos ) const - { - TReal32 percent; - if ( aPos < iZero ) - { - // return negative percentages on the lower side of zero point - percent = -1 * Proportion( aPos, iZero, iMin ); - } - else - { - percent = Proportion( aPos, iZero, iMax ); - } - // constrain between -100% and 100% - return Min( Max( percent, -1.0F ), 1.0F ); - } - - /** Scale in x and y dimensions */ - NONSHARABLE_STRUCT( TScale2D ) - { - TRealPoint Percent( const TPoint& aPos ) const - { - return TRealPoint( iX.Percent( aPos.iX ), - iY.Percent( aPos.iY ) ); - } - - TScale iX; - TScale iY; - }; - - enum TDirection { ESmaller, ELarger }; - - /** @return the direction of pos compared to the previous pos */ - inline TDirection Direction( TInt aPos, TInt aPreviousPos ) - { - return aPos < aPreviousPos ? ESmaller : ELarger; - } - - /** Direction in x and y dimensions */ - NONSHARABLE_STRUCT( TDirection2D ) - { - TDirection iX; - TDirection iY; - }; - - /** Return the direction (up/down) of signal at aIndex */ - inline TDirection2D Direction( TInt aIndex, const RArray< TPointEntry >& aPoints ) - { - const TPoint& pos = aPoints[ aIndex ].iPos; - const TPoint& prevPos = aPoints[ aIndex - 1 ].iPos; - TDirection2D dir = { Direction( pos.iX, prevPos.iX ), - Direction( pos.iY, prevPos.iY ) }; - return dir; - } - /** - * @return a position in the aLow and aHigh, so that it aProportion of - * of length is above the pos - */ - TReal32 ProportionalLength( TReal32 aLow, TReal32 aHigh, TReal32 aProportion ) - { - return ( aHigh - aLow ) * aProportion / ( 1 + aProportion ); - } - - /** - * @return aVariableEdge scaled to new position, when the other edge changes - * from aOldEdge to aNewEdge, so that aOrigin maintains the *same relative - * position* between aVariableEdge and the other edge - */ - inline TReal32 ScaledEdge( TReal32 aOrigin, TReal32 aVariableEdge, - TReal32 aOldEdge, TReal aNewEdge ) - { - TReal32 proportion = Proportion( aOrigin, aVariableEdge, aOldEdge ); - return ( proportion * aNewEdge - aOrigin ) / ( proportion - 1 ); - } - - TScale Rescale( TReal32 aPos, TDirection aDir, TDirection aPrevDir, - const TScale& aPrevScale, const TEdges& aEdges ) - { - TScale scale( aPrevScale ); - if ( aPrevDir != aDir ) - { - // the code duplication is accepted here, since it is difficult to factor out - // while maintaining the understandability of this anyway complex algorithm - if ( aDir == ESmaller ) - { - scale.iMin = aEdges.iMin; - if ( aPrevScale.iZero < aPos ) - { - TReal32 proportionAboveZero = Proportion( aPos, aPrevScale.iZero, aPrevScale.iMax ); - scale.iZero = aPos - ProportionalLength( aEdges.iMin, aPos, proportionAboveZero ); - } - else - { - // adjust zero pos so that proportion between aPos, Min, and Zero pos - // stay the same (Min will move to 0, aPos stays the same) - scale.iZero = ScaledEdge( aPos, aPrevScale.iZero, - aPrevScale.iMin, aEdges.iMin ); - } - // adjust the upper edge to take into account the movement of zero pos - scale.iMax = ScaledEdge( aPos, aPrevScale.iMax, - aPrevScale.iZero, scale.iZero ); - } - else // ELarger - { - scale.iMax = aEdges.iMax; - if ( aPos < aPrevScale.iZero ) - { - TReal32 proportionBelowZero = Proportion( aPos, aPrevScale.iZero, aPrevScale.iMin ); - scale.iZero = aPos + ProportionalLength( aPos, aEdges.iMax, proportionBelowZero ); - } - else - { - // adjust zero pos so that proportion between aPos, Max, and Zero pos - // stay the same (Max will move edge, aPos stays the same) - scale.iZero = ScaledEdge( aPos, aPrevScale.iZero, - aPrevScale.iMax, aEdges.iMax ); - } - // adjust the lower edge to take into account the movement of zero pos - scale.iMin = ScaledEdge( aPos, aPrevScale.iMin, - aPrevScale.iZero, scale.iZero ); - } - } - return scale; - } - - /** Edges in x and y dimensions */ - NONSHARABLE_STRUCT( TEdges2D ) - { - TEdges iX; - TEdges iY; - }; - - /** - * @param aEdges edges of the area in which gesture points are accepted - * @return the scale of latest point in the list of points - */ - TScale2D Scale( const RArray< TPointEntry >& aPoints, const TEdges2D& aEdges ) - { - TScale2D scale = { TScale( aPoints[0].iPos.iX, aEdges.iX ), - TScale( aPoints[0].iPos.iY, aEdges.iY ) }; - TInt count = aPoints.Count(); - if ( count > 1 ) - { - // iterate the whole point list to arrive to the current scale - TDirection2D dir( Direction( 1, aPoints ) ); - for ( TInt i = 1; i < count; i++ ) - { - // get direction at i - TDirection2D newDir( Direction( i, aPoints ) ); - // get new scale at i - scale.iX = Rescale( aPoints[i - 1].iPos.iX, newDir.iX, dir.iX, scale.iX, aEdges.iX ); - scale.iY = Rescale( aPoints[i - 1].iPos.iY, newDir.iY, dir.iY, scale.iY, aEdges.iY ); - dir = newDir; - } - } - return scale; - } - } // unnamed namespace - -TRealPoint CGesture::SpeedPercent( const TRect& aEdges ) const - { - // x and y coordinates are easier to handle separately, extract from TRect: - // ((iMinX, iMinY), (iMaxX, iMaxY)) -> ((iMinX, iMaxX), (iMinY, iMaxY)) - TEdges2D edges = { { aEdges.iTl.iX, aEdges.iBr.iX }, - { aEdges.iTl.iY, aEdges.iBr.iY } }; - // work out the current scale (coordinate -> percentage mapping) from - // the history of points (i.e., points of current gesture). Then - // calculate the percentage of the current position. - return Scale( iPoints, edges ).Percent( CurrentPos() ); - } - -// ---------------------------------------------------------------------------- -// Speed -// ---------------------------------------------------------------------------- -// -TRealPoint CGesture::Speed() const - { - const TReal32 KMicroSecondsInSecond = 1000000; - - // Speed is only evaluated at the end of the swipe - // if user stops at the end of the swipe before lifting stylus, - // speed is zero. If time is zero, return 0 speed (infinite does - // not make sense either). Will need to consider also earlier points - // and their times or start time, if this zero-speed behavior is a problem - TRealPoint speed; - TReal32 time = static_cast( TimeFromPreviousPoint().Int() ) - / KMicroSecondsInSecond; - if ( !IsMovementStopped() && time > 0 ) - { - TPoint distance = CurrentPos() - PreviousPos(); - speed.iX = static_cast( distance.iX ) / time; - speed.iY = static_cast( distance.iY ) / time; - } - return speed; - } - -// ---------------------------------------------------------------------------- -// Distance -// ---------------------------------------------------------------------------- -// -TPoint CGesture::Distance() const - { - return CurrentPos() - StartPos(); - } - -// ---------------------------------------------------------------------------- -// Visual -// ---------------------------------------------------------------------------- -// -CAlfVisual* CGesture::Visual() const - { - return iVisual; - } - -// ---------------------------------------------------------------------------- -// TimeFromPreviousPoint -// ---------------------------------------------------------------------------- -// -inline TTimeIntervalMicroSeconds32 CGesture::TimeFromPreviousPoint() const - { - const TInt KLatestEntryOffset = 1; - return Elapsed( PreviousEntry().iTime, NthLastEntry( KLatestEntryOffset ).iTime ); - } - -// ---------------------------------------------------------------------------- -// return nth point from the end of the points array -// ---------------------------------------------------------------------------- -// -inline const TPointEntry& CGesture::NthLastEntry( TInt aOffset ) const - { - return iPoints[ Max( iPoints.Count() - aOffset, 0 ) ]; - } - -// ---------------------------------------------------------------------------- -// PreviousEntry -// ---------------------------------------------------------------------------- -// -inline const TPointEntry& CGesture::PreviousEntry() const - { - return NthLastEntry( KPreviousPointOffset ); - } - -// ---------------------------------------------------------------------------- -// PreviousPos -// ---------------------------------------------------------------------------- -// -inline TPoint CGesture::PreviousPos() const - { - return PreviousEntry().iPos; - } - -// ---------------------------------------------------------------------------- -// PinchPercent -// ---------------------------------------------------------------------------- -// -TInt CGesture::PinchPercent() const - { - return (iPinchEndDistance*100/iPinchStartDistance); - } - -// ---------------------------------------------------------------------------- -// PinchCentrePoint -// ---------------------------------------------------------------------------- -// -TPoint CGesture::PinchCentrePoint() const - { - if( iPoints.Count() <= 0 || iSecondaryPoints.Count() <= 0 ) - { - return TPoint(0,0); - } - TInt greaterX = iPoints[0].iPos.iX > iSecondaryPoints[0].iPos.iX ? iPoints[0].iPos.iX : iSecondaryPoints[0].iPos.iX; - TInt greaterY = iPoints[0].iPos.iY > iSecondaryPoints[0].iPos.iY ? iPoints[0].iPos.iY : iSecondaryPoints[0].iPos.iY; - return TPoint( (Abs(iPoints[0].iPos.iX - iSecondaryPoints[0].iPos.iX)/2 + greaterX), (Abs(iPoints[0].iPos.iY - iSecondaryPoints[0].iPos.iY)/2 + greaterY)); - } - -// end of file -