uifw/EikStd/coctlsrc/aknedwinphysicshandler.cpp
changeset 0 2f259fa3e83a
child 4 8ca85d2f0db7
--- /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 <aknphysics.h>
+#include <aknphysicsobserveriface.h>
+#include <babitflags.h>
+
+#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;
+    }