diff -r 000000000000 -r 2f259fa3e83a uifw/EikStd/coctlsrc/aknedwinphysicshandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/EikStd/coctlsrc/aknedwinphysicshandler.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,649 @@ +/* + * Copyright (c) 2009 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: EikEdwin physics handler + * + */ + +#include +#include +#include + +#include "eikedwin.h" +#include "aknedwinphysicshandler.h" + + +const TInt KMaxWorldSize( 100000000 ); // Maximum world size + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::NewL +// --------------------------------------------------------------------------- +// +CAknEdwinPhysicsHandler* CAknEdwinPhysicsHandler::NewL( CEikEdwin& aEdwin ) + { + CAknEdwinPhysicsHandler* self = CAknEdwinPhysicsHandler::NewLC( aEdwin ); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::NewLC +// --------------------------------------------------------------------------- +// +CAknEdwinPhysicsHandler* CAknEdwinPhysicsHandler::NewLC( CEikEdwin& aEdwin ) + { + CAknEdwinPhysicsHandler* self = new ( ELeave ) CAknEdwinPhysicsHandler( + aEdwin ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::~CAknEdwinPhysicsHandler +// --------------------------------------------------------------------------- +// +CAknEdwinPhysicsHandler::~CAknEdwinPhysicsHandler() + { + delete iPhysics; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::HandlePointerEvent +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::HandlePointerEvent( + const TPointerEvent& aPointerEvent ) + { + if ( aPointerEvent.iType == TPointerEvent::EButton1Down && + iViewRect.Contains( aPointerEvent.iPosition ) && + iEventUnblockingAllowed ) + { + BlockEvents( EFalse ); + iPreviousYCoordinate = - KMaxWorldSize; + } + if ( iEventsBlocked ) + { + return; + } + + // Dragging/flicking logic + + if ( aPointerEvent.iType == TPointerEvent::EButton1Down && + iViewRect.Contains( aPointerEvent.iPosition ) ) + { + // Pointer down inside view rect, set flag to allow dragging + // and initialize values + iFlags.Set( EFlagDraggingAllowed ); + iPrevPosition = aPointerEvent.iPosition; + iStartPosition = aPointerEvent.iPosition; + StopPhysics(); + + iStartTime.HomeTime(); + iDragThresholdExceeded = EFalse; + iFlags.Clear( EFlagBouncingUp ); + iFlags.Clear( EFlagBouncingDown ); + return; + } + if ( iFlags.IsClear( EFlagDraggingAllowed ) ) + { + return; + } + + if ( aPointerEvent.iType == TPointerEvent::EDrag ) + { + if ( !iDragThresholdExceeded ) + { + TInt drag( iStartPosition.iY - aPointerEvent.iPosition.iY ); + if ( Abs( drag ) > DragThreshold() ) + { + iDragThresholdExceeded = ETrue; + } + } + + if ( iDragThresholdExceeded ) + { + TInt deltaY( iPrevPosition.iY - aPointerEvent.iPosition.iY ); + iPrevPosition = aPointerEvent.iPosition; + + TPoint deltaPoint( 0, deltaY ); + iPhysics->RegisterPanningPosition( deltaPoint ); + } + } + else if ( aPointerEvent.iType == TPointerEvent::EButton1Up ) + { + iFlags.Clear( EFlagDraggingAllowed ); + TPoint drag( 0, iStartPosition.iY - aPointerEvent.iPosition.iY ); + iPhysics->StartPhysics( drag, iStartTime ); + } + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::SetViewRect +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::SetViewRect( const TRect& aRect ) + { + iViewRect = aRect; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::InitPhysicsL +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::InitPhysicsL() + { + TSize totalSize( iViewRect.Width(), iViewRect.Height() + KMaxWorldSize ); + TSize viewSize( iViewRect.Width(), iViewRect.Height() ); + + iPhysics->InitPhysicsL( totalSize, viewSize, EFalse ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::MoveScrollIndex +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::MoveScrollIndex( TInt aPixelsToMove ) + { + // This is called when user moves content using scrollbar + + // Do nothing if handler itself is updating the view + if ( iFlags.IsSet( EFlagUpdatingView ) ) + { + return; + } + + iWorldIndex += aPixelsToMove; + ScrollView( EFalse ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::EmulationOngoing +// --------------------------------------------------------------------------- +// +TBool CAknEdwinPhysicsHandler::EmulationOngoing() + { + return IsFlicking() || IsBouncing(); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::DragThreshold +// --------------------------------------------------------------------------- +// +TInt CAknEdwinPhysicsHandler::DragThreshold() const + { + return iPhysics->DragThreshold(); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ViewPositionChanged +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::ViewPositionChanged( const TPoint& aNewPosition, + TBool /*aDrawNow*/, TUint /*aFlags*/) + { + // Skip equal sequential values. + if ( aNewPosition.iY == iPreviousYCoordinate ) + { + return; + } + iPreviousYCoordinate = aNewPosition.iY; + + TInt y( 0 ); + if ( iFlags.IsSet( EFlagBouncingDown ) ) + { + // We are at the beginning of world + y = aNewPosition.iY + iBounceDownIndex; + } + else if ( iFlags.IsSet( EFlagBouncingUp ) ) + { + // We are at the end of world + y = aNewPosition.iY + iBounceUpIndex - KMaxWorldSize; + } + else + { + // We are at the middle of world + y = aNewPosition.iY - KMaxWorldSize / 2; + } + + iWorldIndex = y - iViewRect.Height() / 2; + + // If bounce is ongoing, block all pointer events. + if ( IsBouncing() ) + { + BlockEvents( ETrue ); + } + // Scroll view based on values from aknphysics + ScrollView( ETrue ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::PhysicEmulationEnded +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::PhysicEmulationEnded() + { + TInt offset = iEdwin.PixelsOutOfBorder(); + if ( offset != 0 ) + { + // If physics emulation ends and view position is not moved + // back to original position (to position where bounce started) + // we adjust it here. This is because aknphysics won't return + // always to original position. + + TPoint newPosition( 0, iPreviousYCoordinate + offset ); + ViewPositionChanged( newPosition, ETrue, 0 ); + } + + // Enable pointer events when next pointer down received + iEventUnblockingAllowed = ETrue; + + // Show cursor again if needed + iEdwin.RestoreCursorState(); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ViewPosition +// --------------------------------------------------------------------------- +// +TPoint CAknEdwinPhysicsHandler::ViewPosition() const + { + // Aknphysics calls this function to get current view position. + // We adjust the position based on information if we + // are are bouncing up or down (in other words we + // have exceeded end- or beginning of real editor content). + // In these situations we adjust returned value so that + // from aknphysic's point of view we seem to be at the beginning + // or end of almost infinite large world. If we have not exceeded + // borders of editor content, we are at the middle of this world. + // So, when we are at the middle of this almost infinite large world, + // we can in practice add and remove content to editor + // and we must not tell correct position to aknphysics (we also can't because + // it seems to be impossible to calculate excatly correct position and size + // of world if we haven't formatted yet the whole editor content). + + TInt y( 0 ); + + if ( iFlags.IsClear( EFlagBouncingDown ) + && iFlags.IsClear( EFlagBouncingUp ) ) + { + // We are at the middle of world + y = iWorldIndex + KMaxWorldSize / 2; + } + else if ( iFlags.IsSet( EFlagBouncingDown ) ) + { + // We are at the beginning of world + y = iWorldIndex - iBounceDownIndex; + } + else if ( iFlags.IsSet( EFlagBouncingUp ) ) + { + // We are at the end of world + y = iWorldIndex - iBounceUpIndex + KMaxWorldSize; + } + + return TPoint( iViewRect.Width() / 2, y + iViewRect.Height() / 2 ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::CAknEdwinPhysicsHandler +// --------------------------------------------------------------------------- +// +CAknEdwinPhysicsHandler::CAknEdwinPhysicsHandler( CEikEdwin& aEdwin ) : + iWorldIndex( 0 ), + iPreviousWorldIndex( 0 ), + iPhysics( NULL ), + iEdwin( aEdwin ) + { + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ConstructL +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::ConstructL() + { + iPhysics = CAknPhysics::NewL( *this, &iEdwin ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ScrollView +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::ScrollView( TBool aAllowBounce ) + { + iFlags.Set( EFlagUpdatingView ); + if ( iPreviousWorldIndex != iWorldIndex ) + { + // Calculate amount of pixels to scroll based on previous position + TInt pixelsToScroll( iPreviousWorldIndex - iWorldIndex ); + if ( pixelsToScroll != 0 ) + { + if ( iFlags.IsSet( EFlagBouncingDown ) || + iFlags.IsSet( EFlagBouncingUp ) ) + { + // Bounce ongoing, use function that supports scrolling + // over the content borders (there can be empty space above or + // below the editor content) + TInt restOfPixels( 0 ); + ScrollStepWithBounce( pixelsToScroll, restOfPixels ); + + // If restOfPixels is not zero, we were bouncing back + // and exceeded the border again. In this situation + // we must scroll rest of pixels using function + // that stops if we again exceed the border. This is needed + // because we need to know if we exceed the border again + // (for example if length of content is short) to adjust + // position on aknphysics world correctly. + + if ( restOfPixels != 0) + { + ScrollStep( pixelsToScroll, ETrue ); + } + } + else + { + // Bounce not ongoing, use function that stops if we exceed the border + ScrollStep( pixelsToScroll, aAllowBounce ); + } + } + } + iFlags.Clear( EFlagUpdatingView ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ScrollStep +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::ScrollStep( TInt aPixelsToScroll, + TBool aAllowBounce ) + { + TInt restOfPixels( 0 ); + TBool borderExceeded( EFalse ); + + TInt scrolledPixels = iEdwin.ScrollView( aPixelsToScroll, borderExceeded, + restOfPixels ); + + if ( borderExceeded && aAllowBounce ) + { + if ( aPixelsToScroll != 0 ) + { + MoveWorldIndex( scrolledPixels ); + + if ( IsFlicking() ) + { + // Flicking is ongoing and end of content is arrived. + // In this situation we stop physics, adjust the view position in the + // aknphysics (in function ViewPosition) and restart physics with + // current force and velocity. + + iPhysics->SuspendPhysics(); + InitBounce( aPixelsToScroll > 0 ); + iPhysics->ResumePhysics(); + } + else + { + InitBounce( aPixelsToScroll > 0 ); + ScrollRestOfPixels( restOfPixels ); + } + } + return; + } + + MoveWorldIndex( scrolledPixels ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ScrollStepWithBounce +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::ScrollStepWithBounce( TInt aPixelsToScroll, + TInt& aRestOfPixels ) + { + TBool endOfBounce( EFalse ); + TInt scrolledPixels = iEdwin.ScrollViewWithBounce( + aPixelsToScroll, endOfBounce, aRestOfPixels ); + + MoveWorldIndex( scrolledPixels ); + + if ( endOfBounce ) + { + iFlags.Clear( EFlagBouncingDown ); + iFlags.Clear( EFlagBouncingUp ); + } + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::MoveWorldIndex +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::MoveWorldIndex( TInt aDelta ) + { + iWorldIndex = iPreviousWorldIndex - aDelta; + iPreviousWorldIndex = iWorldIndex; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::ScrollRestOfPixels +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::ScrollRestOfPixels( TInt aRestOfPixels ) + { + // Scroll rest of pixels + TBool endOfBounce; + TInt restOfPixels( 0 ); + + TInt scrolledPixels = iEdwin.ScrollViewWithBounce( aRestOfPixels, + endOfBounce, restOfPixels ); + + MoveWorldIndex( scrolledPixels ); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::StopPhysics +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::StopPhysics() + { + iPhysics->StopPhysics(); + iPhysics->ResetFriction(); + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::BlockEvents +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::BlockEvents( TBool aBlocked ) + { + iEventsBlocked = aBlocked; + iEventUnblockingAllowed = EFalse; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::IsFlicking +// --------------------------------------------------------------------------- +// +TBool CAknEdwinPhysicsHandler::IsFlicking() const + { + return iPhysics->OngoingPhysicsAction() + == CAknPhysics::EAknPhysicsActionFlicking; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::IsBouncing +// --------------------------------------------------------------------------- +// +TBool CAknEdwinPhysicsHandler::IsBouncing() const + { + return iPhysics->OngoingPhysicsAction() + == CAknPhysics::EAknPhysicsActionBouncing; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::InitBounce +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::InitBounce( TBool aBouncingDown ) + { + if ( aBouncingDown ) + { + iFlags.Clear( EFlagBouncingUp ); + iFlags.Set( EFlagBouncingDown ); + iBounceDownIndex = iWorldIndex; + } + else + { + iFlags.Set( EFlagBouncingUp ); + iFlags.Clear( EFlagBouncingDown ); + iBounceUpIndex = iWorldIndex; + } + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::InitKineticScrolling +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::InitKineticScrolling( + const TPoint& aStartPosition ) + { + iSelectionStarted = EFalse; + iDraggingStarted = EFalse; + iStartPosition = aStartPosition; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::HandleKineticScrolling +// --------------------------------------------------------------------------- +// +void CAknEdwinPhysicsHandler::HandleKineticScrolling( + const TPointerEvent& aPointerEvent, TBool& aShouldReturn ) + { + aShouldReturn = EFalse; + + // If editor content is empty, it is not possible to drag, + // flick or select text and we return here. Other events + // are passed because they are handled later. + if ( aPointerEvent.iType == TPointerEvent::EDrag + && iEdwin.TextLength() == 0 ) + { + aShouldReturn = ETrue; + return; + } + + // If dragging or selection not started, + // check if it should be started + if ( aPointerEvent.iType == TPointerEvent::EDrag && !iSelectionStarted + && !iDraggingStarted ) + { + // Get delta values for pointer movement + TInt deltaX( aPointerEvent.iPosition.iX - iStartPosition.iX ); + TInt deltaY( aPointerEvent.iPosition.iY - iStartPosition.iY ); + + // If drag threshold not exceeded, return. + if ( Abs( deltaX ) < DragThreshold() + && Abs( deltaY ) < DragThreshold() ) + { + HandlePointerEvent( aPointerEvent ); + aShouldReturn = ETrue; + return; + } + + // If dragged horizontally more than vertically, + // text selection started. Otherwise dragging started. + if ( Abs( deltaX ) > Abs( deltaY ) ) + { + iSelectionStarted = ETrue; + } + else + { + iDraggingStarted = ETrue; + + // If cursor is visible, disable it and store + // cursor visibility info when dragging starts. + iEdwin.StoreCursorState(); + } + } + + // Forward all events to physics handler, except: + // If text selection started, don't forward drag and up events + // because kinetic scrolling can't be used when selecting text. + // However, fast scrolling can be used when we are selecting text. + + if ( !( iSelectionStarted && + ( aPointerEvent.iType == TPointerEvent::EDrag || + aPointerEvent.iType == TPointerEvent::EButton1Up ) ) ) + { + HandlePointerEvent( aPointerEvent ); + } + + if ( aPointerEvent.iType == TPointerEvent::EButton1Up ) + { + // If flick or bounce effect was started, check if there + // is need to hide cursor. + // If flick or bounce was not started, show cursor again if needed. + if ( EmulationOngoing() ) + { + iEdwin.StoreCursorState(); + } + else + { + iEdwin.RestoreCursorState(); + } + } + + // If selection not started, don't handle drag events but return + // All other events must be handled anyway. + if ( !iSelectionStarted && aPointerEvent.iType + == TPointerEvent::EDrag ) + { + aShouldReturn = ETrue; + return; + } + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::SelectionStarted +// --------------------------------------------------------------------------- +// +TBool CAknEdwinPhysicsHandler::SelectionStarted() const + { + return iSelectionStarted; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::DraggingStarted +// --------------------------------------------------------------------------- +// +TBool CAknEdwinPhysicsHandler::DraggingStarted() const + { + return iDraggingStarted; + } + +// --------------------------------------------------------------------------- +// CAknEdwinPhysicsHandler::DragThresholdExceeded +// --------------------------------------------------------------------------- +// +TBool CAknEdwinPhysicsHandler::DragThresholdExceeded( + const TPoint& aCurrentPosition ) const + { + // Get delta values for pointer movement + TInt deltaX( aCurrentPosition.iX - iStartPosition.iX ); + TInt deltaY( aCurrentPosition.iY - iStartPosition.iY ); + + if ( Abs( deltaX ) >= DragThreshold() || Abs( deltaY ) >= DragThreshold() ) + { + return ETrue; + } + return EFalse; + }