diff -r 000000000000 -r dd21522fd290 webengine/webkitutils/rt_gesturehelper/src/gesturehelperimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/webkitutils/rt_gesturehelper/src/gesturehelperimpl.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,817 @@ +/* +* 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 the License "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 "gesturehelperimpl.h" + +#include +#include +#include + +#include "gesture.h" +#include "gesturedefs.h" +#include "utils.h" +#include "pointercapturer.h" +#include "gestureeventfilter.h" +#include "gesturehelpereventsender.h" +#include "flogger.h" +#include "gestureevent.h" + +using namespace RT_GestureHelper; + +namespace RT_GestureHelper +{ + +/// type of function in gesture helper to be called by the timer +/// when timer triggers +typedef void (CGestureHelperImpl::*CallbackFunctionL)(); + +NONSHARABLE_CLASS( CCallbackTimer ) : public CTimer + { +public: + /** Two-phase constructor */ + static CCallbackTimer* NewL( CGestureHelperImpl& aHelper, + CallbackFunctionL aCallbackFunctionL, TInt aDelay, TBool aIsEnabled ) + { + CCallbackTimer* self = new ( ELeave ) CCallbackTimer( aHelper, + aCallbackFunctionL, aDelay, aIsEnabled ); + CleanupStack::PushL( self ); + self->ConstructL(); // construct base class + CActiveScheduler::Add( self ); + CleanupStack::Pop( self ); + return self; + } + + /** Destructor */ + ~CCallbackTimer() + { + Cancel(); + } + + /** Set whether sending holding events is currently enabled */ + void SetEnabled( TBool aEnabled ) + { + iIsEnabled = aEnabled; + // cancel in case hold timer is already running + Cancel(); + } + + /** @return whether sending holding events is currently enabled */ + TBool IsEnabled() const + { + return iIsEnabled; + } + + /** Start the timer. Calls CGestureHelperImpl::StartHoldingL upon completion */ + void Start() + { + // if sending hold events is disabled, do not ever start the hold timer, and + // hence hold events will never be triggered + if ( iIsEnabled ) + { + Cancel(); + After( iDelay ); + } + } + void SetDelay(TInt aDelay) { iDelay = aDelay; } + TInt GetDelay() { return iDelay; } + +private: + /** Constructor */ + CCallbackTimer( CGestureHelperImpl& aHelper, + CallbackFunctionL aCallbackFunctionL, TInt aDelay, TBool aIsEnabled ) + : CTimer( EPriorityUserInput - 1 ), // give higher priority to new pointer events with - 1 + iHelper( aHelper ), iCallbackFunctionL( aCallbackFunctionL ), + iDelay( aDelay ), iIsEnabled( aIsEnabled ) + { + } + + void RunL() // From CActive + { + (iHelper.*iCallbackFunctionL)(); + } + +private: + /// helper object that will be called back when timer is triggered + CGestureHelperImpl& iHelper; + /// Function in the iHelper object call + CallbackFunctionL iCallbackFunctionL; + /// How long a time to wait befor calling back after Start() + TInt iDelay; + /// whether sending holding events is currently enabled + TBool iIsEnabled; + }; + +} // namespace GestureHelper + +/** + * @return position from event. Use this instead of using aEvent direction to + * avoid accidentally using TPointerEvent::iPosition + */ +inline TPoint Position( const TPointerEvent& aEvent ) + { + // use parent position, since the capturer is using full screen area, + // and because the (Alfred) drag events are not local to visual even when + // coming from the client + + return aEvent.iParentPosition; + } + +// ---------------------------------------------------------------------------- +// Two-phase constructor +// ---------------------------------------------------------------------------- +// +CGestureHelperImpl* CGestureHelperImpl::NewL( MGestureObserver& aObserver ) + { + CGestureHelperImpl* self = new ( ELeave ) CGestureHelperImpl( aObserver ); + CleanupStack::PushL( self ); + self->iEventSender = CGestureEventSender::NewL( aObserver ); + self->iDoubleTapTimer = CCallbackTimer::NewL( *self, EmitFirstTapEventL, + KMaxTapDuration, EFalse ); // double tap is disabled by default + self->iHoldingTimer = CCallbackTimer::NewL( *self, StartHoldingL, + KHoldDuration, EFalse ); // holding is enabled by default + + self->iLongTouchTimer = CCallbackTimer::NewL( *self, HandleLongTouchL, + KLongTapDuration, ETrue ); // holding is enabled by default + self->iPointerCapturer = CPointerCapturer::NewL(); + self->iGesture = new ( ELeave ) CGesture(); + self->iUnusedGesture = new ( ELeave ) CGesture(); + TInt tapLimit = Mm2Pixels(KFingerSize_mm) / 2; + self->iEventFilter = new (ELeave) CGestureEventFilter(tapLimit); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- +// +CGestureHelperImpl::CGestureHelperImpl( MGestureObserver& aObserver ) + : iObserver( aObserver ) + { + } + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- +// +CGestureHelperImpl::~CGestureHelperImpl() + { + delete iDoubleTapTimer; + delete iHoldingTimer; + delete iGesture; + delete iPreviousTapGesture; + delete iUnusedGesture; + delete iPointerCapturer; + delete iLongTouchTimer; + delete iEventFilter; + delete iEventSender; + } + + +// ---------------------------------------------------------------------------- +// SetHoldingEnabled +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::SetHoldingEnabled( TBool aEnabled ) + { + iHoldingTimer->SetEnabled( aEnabled ); + } + +// ---------------------------------------------------------------------------- +// IsHoldingEnabled +// ---------------------------------------------------------------------------- +// +TBool CGestureHelperImpl::IsHoldingEnabled() const + { + return iHoldingTimer->IsEnabled(); + } + +// ---------------------------------------------------------------------------- +// SetHoldingEnabled +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::SetDoubleTapEnabled( TBool aEnabled ) + { + iDoubleTapTimer->SetEnabled( aEnabled ); + } + +// ---------------------------------------------------------------------------- +// IsHoldingEnabled +// ---------------------------------------------------------------------------- +// +TBool CGestureHelperImpl::IsDoubleTapEnabled() const + { + return iDoubleTapTimer->IsEnabled(); + } + +// ---------------------------------------------------------------------------- +// InitAlfredPointerEventCaptureL +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::InitAlfredPointerCaptureL( CAlfEnv& aEnv, + CAlfDisplay& aDisplay, TInt aFreeControlGroupId ) + { + iPointerCapturer->InitForAlfredL(*this, aEnv, aDisplay, aFreeControlGroupId ); + } + +// ---------------------------------------------------------------------------- +// Reset state +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::Reset() + { + iHoldingTimer->Cancel(); + iLongTouchTimer->Cancel(); + iGesture->Reset(); + iPointerCapturer->Stop(); + } + +/** + * Helper function that calls Reset on the pointer to CGestureHelperImpl + */ +static void ResetHelper( TAny* aHelper ) + { + static_cast< CGestureHelperImpl* >( aHelper )->Reset(); + } + +// ---------------------------------------------------------------------------- +// Handle a pointer event +// ---------------------------------------------------------------------------- +// +TBool CGestureHelperImpl::HandlePointerEventL( const TPointerEvent& aEvent ) + { + TInt filterReason; + SetLastEventTime(); + if (!iEventFilter->FilterDrag(aEvent, iLastEventTime, filterReason)) + { + iGesture->SetVisual( NULL ); + return noneAlf_HandlePointerEventL( aEvent ); + } + else + { + /* + TBuf<10> num; + num.Num( filterReason ); + TBuf<128> str; + str.AppendFormat(_L("Filter reason: %d"), filterReason); + RFileLogger::Write( _L("gh"), _L("gh.txt"), EFileLoggingModeAppend, str); + */ + return EFalse; + } + } + +// ---------------------------------------------------------------------------- +// OfferEventL +// ---------------------------------------------------------------------------- +// +TBool CGestureHelperImpl::OfferEventL( const TAlfEvent& aEvent ) + { + if ( aEvent.IsPointerEvent() ) + { + return HandlePointerEventL( aEvent.PointerEvent(), aEvent.Visual() ); + } + return EFalse; + } + + + + + + +// ---------------------------------------------------------------------------- +// Handle a pointer event +// ---------------------------------------------------------------------------- +// + + +TBool CGestureHelperImpl::noneAlf_HandlePointerEventL( const TPointerEvent& aEvent) + { + + switch ( aEvent.iType ) + { + case TPointerEvent::EButton1Down: + { + + iPointerCapturer->StartL(); + HandleTouchDownL(aEvent); + break; + } + case TPointerEvent::EDrag: + { + HandleMoveL(aEvent); + break; + } + case TPointerEvent::EButton1Up: + { + CleanupStack::PushL( TCleanupItem( &ResetHelper, this ) ); + if (KErrNone == AddPoint( aEvent )) + { + HandleTouchUpL(aEvent); + } + else + { + EmitCancelEventL(); + } + CleanupStack::PopAndDestroy( this ); + break; + } + default: + break; + } + return ETrue; + } + + +TBool CGestureHelperImpl::HandlePointerEventL( const TPointerEvent& aEvent, + CAlfVisual* aVisual ) + { + // filter out events that do not start with button down. It is a stray + // event from another visual + if ( IsIdle() && aEvent.iType != TPointerEvent::EButton1Down ) + { + return EFalse; // don't consume + } + + switch ( aEvent.iType ) + { + case TPointerEvent::EButton1Down: + // If no up event was received during previous gesture, cancel + // previous event and reset state + if ( !IsIdle() ) + { + // ambiguous what is the right thing when "cancel" event leaves + // and "start" does not. Leaving for cancel *after* "start" could + // be unexpected to client, as client would have handled start + // event successfully. Assume that leaving upon cancellation + // can be ignored. + TRAP_IGNORE( EmitCancelEventL() ); + Reset(); + } + // as long as down event of a double tap comes within the double + // tap timeout, it does not matter how long the user keeps the finger + // pressed for the gesture to be a double tap. Therefore, cancel + // the timeout, as it is no longer relevant. (Of course, this call + // will only do something if the timer is actually running, which + // is only if received a tap event very recently.) + iDoubleTapTimer->Cancel(); + // adding the first point implicitly makes the state "not idle" + AddPointL( aEvent ); + iGesture->SetVisual( aVisual ); + // if pointer capturer leaves, the remaining pointer events will + // not be captured if stylus is dragged outside the capturing visual + // an error note will be shown, so the potential problem is irrelevant, + // assuming client does not (incorrectly) block the leave from reaching + // the framework + iPointerCapturer->StartL(); + // Delay emitting a down event _until_ it is known that this beginning + // gesture is _not_ the second tap of a double tap event. + // iPreviousTapGesture is only non-null if very recently received + // a tap event and double tap is enabled. + if ( !iPreviousTapGesture ) + { + EmitEventL( *iGesture ); + } + // else delay emitting an event, as it might be a double tap + // (allow the second tap of a double tap to be anywhere, so don't check + // for start pos here) + break; + + case TPointerEvent::EDrag: + // While stylus down, the same event is received repeatedly + // even if stylus does not move. Filter out by checking if point + // is the same as the latest point + if ( !iGesture->IsLatestPoint( Position( aEvent ) ) ) + { + AddPointL( aEvent ); + + // as long as the starting gesture is seen as a tap, do not emit any + // drag events + if ( !iGesture->IsTap() ) + { + // if there is a previous tap gesture, getting drag events means that + // the previous gesture is not a double tap. So emit the previous gesture. + if ( iPreviousTapGesture ) + { + // this is a second gesture after a tap (double tap is enabled) + EmitFirstTapEventL(); + // emit down event for the current gesture (since its down was delayed, until + // it was to be known if the event is a tap. That is known now.) + EmitStartEventL( *iGesture ); + } + // restart holding timer every time the current stylus pos changes + StartHoldingTimer( aEvent ); + // emit the drag event to client + EmitEventL( *iGesture ); + } + // else: do not emit drag events until it is known that the gesture is not a tap + // (or the second tap of double tap) + } + break; + + case TPointerEvent::EButton1Up: + // reset in case the down event for next gesture is not received for a reason + // in client, and instead drag or up events are received. + // reset via cleanup stack to ensure Reset is run even if + // observer leaves + CleanupStack::PushL( TCleanupItem( &ResetHelper, this ) ); + // if adding of the point fails, notify client with a + // cancelled event. It would be wrong to send another + // gesture code when the up point is not known + if ( KErrNone == AddPoint( aEvent ) ) + { + + // if the gesture is a tap, the gesture is either the first tap of a _potential_ + // double tap, or the second tap of a double tap + if ( iDoubleTapTimer->IsEnabled() && iGesture->IsTap() ) + { + __ASSERT_DEBUG( !iGesture->IsHolding(), Panic( EGesturePanicIllegalLogic ) ); + if ( !iPreviousTapGesture ) + { + // First tap. Delay emitting its code evemt and released events until it is known + // whether the tap is a double tap + iPreviousTapGesture = iGesture; + iGesture = NewGesture(); + iDoubleTapTimer->Start(); + } + else + { + // This is a second tap of a double tap. Do not emit anything for the second + // tap. Only down event has been emitted for the first tap. Emit the code + // event (double tap) and released for the first tap. + iPreviousTapGesture->SetDoubleTap(); + EmitFirstTapEventL(); + } + } + + else + { + // modified iGesture to be "released" + CompleteAndEmitL( *iGesture ); + } + } + else + { // adding a point failed + EmitCancelEventL(); + } + // reset state + CleanupStack::PopAndDestroy( this ); + break; + + default: + break; + } + return ETrue; // consume + } + + +TBool CGestureHelperImpl::IsMovementGesture(TGestureCode aCode) + { + return (aCode == EGestureDrag || aCode == EGestureFlick || aCode == EGestureSwipeUp || + aCode == EGestureSwipeDown || aCode == EGestureSwipeRight || aCode == EGestureSwipeLeft); + } + +void CGestureHelperImpl::HandleLongTouchL() + { + iDoubleTapTimer->Cancel(); + iGesture->SetLongTap(ETrue); + iGesture->SetComplete(); + TPoint startPos = iGesture->StartPos(); + EmitEventL(*iGesture); + iGesture->Reset(); + iGesture->AddPoint( startPos, GetLastEventTime() ); + } + +void CGestureHelperImpl::HandleTouchDownL(const TPointerEvent& aEvent) + { + TGestureCode prevCode = iGesture->PreviousGestureCode(); + if (prevCode == EGestureStart) return; + AddPointL( aEvent ); + + iLongTouchTimer->Start(); + if (!iDoubleTapTimer->IsActive()) + { + EmitEventL( *iGesture ); + } + } + +void CGestureHelperImpl::HandleMoveL(const TPointerEvent& aEvent) + { + if (iGesture->IsLatestPoint( iGesture->Visual() ? Position ( aEvent ) : aEvent.iPosition)) return; // I'm not sure we need this + //Cancel double tap time - it's neither tap nor double tap + iDoubleTapTimer->Cancel(); + iLongTouchTimer->Cancel(); + + TBool isFirstPoint = IsIdle(); + + AddPointL( aEvent ); + + if (iPreviousTapGesture) + { + RecycleGesture(iPreviousTapGesture); + } + + if (!isFirstPoint) + { + EmitEventL( *iGesture ); + } + } + +void CGestureHelperImpl::HandleTouchUpL(const TPointerEvent& /*aEvent*/) + { + TGestureCode prevCode = iGesture->PreviousGestureCode(); + iLongTouchTimer->Cancel(); + iDoubleTapTimer->Cancel(); + TInt64 fromLastTouchUp = iLastEventTime.MicroSecondsFrom(iLastTouchUpTime).Int64(); + TInt64 fromLastDoubleTap = iLastEventTime.MicroSecondsFrom(iLastDoubleTapTime).Int64(); + /* + TBuf<1024> str; + str.AppendFormat(_L("fromLastTouchUp: %d, "), fromLastTouchUp); + str.AppendFormat(_L("fromLastDoubleTap: %d, "), fromLastTouchUp); + str.AppendFormat(_L("iPreviousTapGesture: %d, "), iPreviousTapGesture); + RFileLogger::Write( _L("gh"), _L("gh.txt"), EFileLoggingModeAppend, str); + */ + if ( prevCode == EGestureLongTap ) + { + EmitReleasedEventL(); + } + else if (IsMovementGesture(prevCode) || + !iDoubleTapTimer->IsEnabled() /* || !iGesture->IsTap()*/ ) + { + iGesture->SetComplete(); + EmitEventL(*iGesture); + } + + else + { + if ( iPreviousTapGesture && + (fromLastTouchUp > KDoubleTapMinActivationInterval) && + (fromLastTouchUp < KDoubleTapMaxActivationInterval) && + (fromLastDoubleTap > KDoubleTapIdleInterval)) + { + // it's a double tap + iLastTouchUpTime = iLastEventTime; + iLastDoubleTapTime = iLastEventTime; + EmitDoubleTapEventL(); + } + else + { + // it's a first tap + iLastTouchUpTime = iLastEventTime; + if (iPreviousTapGesture) + { + RecycleGesture(iPreviousTapGesture); + } + + iPreviousTapGesture = iGesture; + iGesture = NewGesture(); + iDoubleTapTimer->Start(); + } + } + } + + + +void CGestureHelperImpl::EmitDoubleTapEventL() + { + iPreviousTapGesture->SetDoubleTap(); + EmitFirstTapEventL(); + } + + +void CGestureHelperImpl::EmitReleasedEventL() + { + iGesture->SetComplete(); + iGesture->SetReleased(); + EmitEventL(*iGesture); + } + + +// ---------------------------------------------------------------------------- +// Is the helper idle? +// inline ok in cpp file for a private member function +// ---------------------------------------------------------------------------- +// +inline TBool CGestureHelperImpl::IsIdle() const + { + return iGesture->IsEmpty(); + } + +// ---------------------------------------------------------------------------- +// Add a point to the sequence of points that together make up the gesture +// inline ok in cpp file for a private member function +// ---------------------------------------------------------------------------- +// +inline void CGestureHelperImpl::AddPointL( const TPointerEvent& aEvent ) + { + User::LeaveIfError( AddPoint( aEvent ) ); + } + +// ---------------------------------------------------------------------------- +// Add a point to the sequence of points that together make up the gesture +// inline ok in cpp file for a private member function +// ---------------------------------------------------------------------------- +// +inline TInt CGestureHelperImpl::AddPoint( const TPointerEvent& aEvent ) + { + TPoint pos = iGesture->Visual() ? Position ( aEvent ) : aEvent.iPosition; + return iGesture->AddPoint( pos, GetLastEventTime() ); + } + +// ---------------------------------------------------------------------------- +// StartHoldingTimer +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::StartHoldingTimer( const TPointerEvent& aNewEvent ) + { + if ( !( iGesture->IsHolding() || + iGesture->IsNearHoldingPoint( Position( aNewEvent ) ) ) ) + { + // restart hold timer, since pointer has moved + iHoldingTimer->Start(); + // Remember the point in which holding was started + iGesture->SetHoldingPoint(); + } + } + +/** + * Helper function that calls ContinueHolding on the pointer to TGesture + */ +static void ContinueHolding( TAny* aGesture ) + { + static_cast< CGesture* >( aGesture )->ContinueHolding(); + } + +// ---------------------------------------------------------------------------- +// Add a point to the sequence of points that together make up the gesture +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::StartHoldingL() + { + // hold & tap event is specifically filtered out. Use case: in list fast + // scrolling activation (e.g. enhanced coverflow), tap & hold should not + // start fast scroll. In addition, after long tap on start position, + // drag and drag & hold swiping should emit normal swipe and swipe&hold + // events. Therefore, tap & hold is not supported. + __ASSERT_DEBUG( !iGesture->IsTap() && !iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) ); + + // holding has just started, and gesture code should be provided to client. + // set gesture state so that it produces a gesture code (other than drag) + iGesture->StartHolding(); + + // create an item in the cleanup stack that will set the gesture state + // to holding-was-started-earlier state. NotifyL may leave, but the + // holding-was-started-earlier state must still be successfully set, + // otherwise, the holding gesture code will be sent twice + CleanupStack::PushL( TCleanupItem( &ContinueHolding, iGesture ) ); + + EmitEventL( *iGesture ); + + // set holding state to "post holding" + CleanupStack::PopAndDestroy( iGesture ); + } + +// ---------------------------------------------------------------------------- +// RecyclePreviousTapGesture +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::RecyclePreviousTapGesture( TAny* aSelf ) + { + CGestureHelperImpl& self = *reinterpret_cast( aSelf ); + self.RecycleGesture( self.iPreviousTapGesture ); + } + +// ---------------------------------------------------------------------------- +// Emit the remainder of the previous tap event (tap + released) +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::EmitFirstTapEventL() + { + // when this function is called, a tap has turned out to _not_ be a double tap + __ASSERT_DEBUG( IsDoubleTapEnabled(), Panic( EGesturePanicIllegalLogic ) ); + __ASSERT_DEBUG( iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) ); + + iDoubleTapTimer->Cancel(); + + // ensure previous tap gesture is reset even if client leaves + CleanupStack::PushL( TCleanupItem( &RecyclePreviousTapGesture, this ) ); + + CompleteAndEmitL( *iPreviousTapGesture ); + + // recycle the emitted gesture + CleanupStack::PopAndDestroy( this ); + } + +// ---------------------------------------------------------------------------- +// EmitStartEventL +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::EmitStartEventL( const CGesture& aGesture ) + { + CGesture* startGesture = aGesture.AsStartEventLC(); + EmitEventL( *startGesture ); + CleanupStack::PopAndDestroy( startGesture ); + } + +// ---------------------------------------------------------------------------- +// EmitCompletionEventsL +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::CompleteAndEmitL( CGesture& aGesture ) + { + aGesture.SetComplete(); + // send gesture code if holding has not been started. If holding has + // been started, client has already received a "hold swipe left" e.g. event, in which + // case don't another "swipe left" event + if ( !aGesture.IsHolding() ) + { + // if client leaves, the state is automatically reset. + // In this case the client will not get the released event + EmitEventL( aGesture ); + } + + // send an event that stylus was lifted + aGesture.SetReleased(); + EmitEventL( aGesture ); + } + +// ---------------------------------------------------------------------------- +// EmitCancelEventL +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::EmitCancelEventL() + { + iDoubleTapTimer->Cancel(); + + // ensure previous tap gesture is reset even if client leaves + CleanupStack::PushL( TCleanupItem( &RecyclePreviousTapGesture, this ) ); + + CGesture& gestureToCancel = iPreviousTapGesture ? *iPreviousTapGesture : *iGesture; + gestureToCancel.SetCancelled(); + EmitEventL( gestureToCancel ); + + // recycle the emitted gesture + CleanupStack::PopAndDestroy( this ); + } + +// ---------------------------------------------------------------------------- +// Notify observer +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::EmitEventL( const CGesture& aGesture ) + { + // deallocation of the event is happening in CGestureEventSender::RunL() + CGestureEvent* event = new(ELeave) CGestureEvent(); + event->iCode = const_cast(aGesture).Code(MGestureEvent::EAxisBoth); + event->iCurrPos = aGesture.CurrentPos(); + event->iDistance = aGesture.Distance(); + event->iStartPos = aGesture.StartPos(); + event->iIsHolding = aGesture.IsHolding(); + event->iSpeed = aGesture.Speed(); + event->iVisual = aGesture.Visual(); + iEventSender->AddEvent(event); + } + +// ---------------------------------------------------------------------------- +// Return a fresh gesture from the gesture pool (pool of one gesture) +// ---------------------------------------------------------------------------- +// +CGesture* CGestureHelperImpl::NewGesture() + { + __ASSERT_DEBUG( iUnusedGesture, Panic( EGesturePanicIllegalLogic ) ); // pool should no be empty + + iUnusedGesture->Reset(); + CGesture* freshGesture = iUnusedGesture; + iUnusedGesture = NULL; + return freshGesture; + } + +// ---------------------------------------------------------------------------- +// Return a fresh gesture from the gesture pool (pool of one gesture) +// ---------------------------------------------------------------------------- +// +void CGestureHelperImpl::RecycleGesture( CGesture*& aGesturePointer ) + { + // only one object fits into the pool, and that should currently be enough + // one pointer must be null, one non-null + __ASSERT_DEBUG( !iUnusedGesture != !aGesturePointer, Panic( EGesturePanicIllegalLogic ) ); + if ( aGesturePointer ) + { + iUnusedGesture = aGesturePointer; + aGesturePointer = NULL; + } + }