/*
* 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:  MR listpane physics impl
*
*/

#include "cmrlistpanephysics.h"
#include "cmrlistpane.h"
#include "nmrlayoutmanager.h"
#include "cmrfieldcontainer.h"

#include <aknphysics.h>

//DEBUG
#include "emailtrace.h"


// ---------------------------------------------------------------------------
// CMRListPanePhysics::CMRListPanePhysics
// ---------------------------------------------------------------------------
//
CMRListPanePhysics::CMRListPanePhysics(
        CCoeControl& aParent,
        CMRFieldContainer& aViewControl,
        MMRPhysicsObserver& aPhysicsObserver )
    : iParent( aParent ),
      iViewControl( aViewControl ),
      iPhysicsObserver( aPhysicsObserver )
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::ConstructL
// ---------------------------------------------------------------------------
//
void CMRListPanePhysics::ConstructL()
    {
    FUNC_LOG;
    iFeatureEnabled = CAknPhysics::FeatureEnabled();
    if ( iFeatureEnabled )
        {
        // Physics: Create physics
        // Give pointer to control that should be able to flick/drag
        iPhysics = CAknPhysics::NewL( *this, &iViewControl );
        }
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::NewL
// ---------------------------------------------------------------------------
//
CMRListPanePhysics* CMRListPanePhysics::NewL(
        CCoeControl& aParent,
        CMRFieldContainer& aViewControl,
        MMRPhysicsObserver& aPhysicsObserver )
    {
    FUNC_LOG;
    CMRListPanePhysics* self =
        new ( ELeave ) CMRListPanePhysics(
                aParent,
                aViewControl,
                aPhysicsObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::~CMRListPanePhysics
// ---------------------------------------------------------------------------
//
CMRListPanePhysics::~CMRListPanePhysics()
    {
    FUNC_LOG;
    delete iPhysics;
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::HandlePointerEventL
// ---------------------------------------------------------------------------
//
TBool CMRListPanePhysics::HandlePointerEventL(
        const TPointerEvent& aPointerEvent, TBool& aEventsBlocked )
    {
    FUNC_LOG;
    TBool physicsStarted( EFalse );
    if ( !iFeatureEnabled || iPhysics->OngoingPhysicsAction() ==
            CAknPhysics::EAknPhysicsActionBouncing )
        {
        return physicsStarted;
        }

    // Down
    if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
        {
        if ( iPhysics->OngoingPhysicsAction()
             != CAknPhysics::EAknPhysicsActionNone )
            {
            iPhysics->StopPhysics();
            }
        
        // Save start time and start point
        iStartTime.HomeTime();
        iStartPoint = aPointerEvent.iPosition;
        iDragPoint = iStartPoint;
        }

    // Drag
    else if ( aPointerEvent.iType == TPointerEvent::EDrag )
        {
        // Check how position was changed and report to physics
        TPoint deltaPoint( iDragPoint - aPointerEvent.iPosition );
        if( Abs( deltaPoint.iY ) > iPhysics->DragThreshold() )
        	{
			iDragPoint = aPointerEvent.iPosition;
			iPhysics->RegisterPanningPosition( deltaPoint );
        	}
        }

    // Up
    else if ( aPointerEvent.iType == TPointerEvent::EButton1Up )
        {
        // Calculate dragging distance
        TPoint drag( iStartPoint - aPointerEvent.iPosition );

        if( Abs( drag.iY ) > iPhysics->DragThreshold() )
        	{
            // Start physics
            physicsStarted = iPhysics->StartPhysics( drag, iStartTime );
        	}

        if( physicsStarted )
        	{
			aEventsBlocked = ETrue;
        	}
        else
        	{
			aEventsBlocked = EFalse;
        	}
        }

    // Record previous pointer event
    iPreviousPointerEvent = aPointerEvent;

    return physicsStarted;
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::InitPhysicsL
// ---------------------------------------------------------------------------
//
void CMRListPanePhysics::InitPhysics()
    {
    FUNC_LOG;
    if ( !iFeatureEnabled )
        {
        return;
        }
    TRect parentRect( iParent.Rect() );

    iWorldSize.iHeight = iViewControl.MinimumSize().iHeight;
    iWorldSize.iWidth = iViewControl.MinimumSize().iWidth;

    iViewSize.iHeight = parentRect.Height();
    iViewSize.iWidth = parentRect.Width();

    if( iWorldSize.iHeight < iViewSize.iHeight )
        {
    	iWorldSize.iHeight = iViewSize.iHeight;
        }



    iPhysics->ResetFriction();

    TRAP_IGNORE( iPhysics->InitPhysicsL( iWorldSize, iViewSize, EFalse ) );
    iPhysics->UpdateViewWindowControl( &iParent );
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::SetWorldHeight
// ---------------------------------------------------------------------------
//
void CMRListPanePhysics::SetWorldHeight( TInt aWorldHeight )
    {
    FUNC_LOG;
    if ( !iFeatureEnabled )
        {
        return;
        }
    iWorldSize.iHeight = aWorldHeight;
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::ViewPositionChanged
// ---------------------------------------------------------------------------
//
void CMRListPanePhysics::ViewPositionChanged( const TPoint& aNewPosition,
                          TBool aDrawNow,
                          TUint /*aFlags*/ )
    {
    FUNC_LOG;
    if ( !iFeatureEnabled )
        {
        return;
        }
    if ( iPhysics->OngoingPhysicsAction() ==
            CAknPhysics::EAknPhysicsActionBouncing )
        {
        return;
        }

    iVerScrollIndex = aNewPosition.iY - iViewSize.iHeight / 2;

    // Parents position is taken into account, by
    // adding the extra x and y coordinates to field containers
    // new position.
    TPoint pos(
            iParent.Position().iX,
            -iVerScrollIndex + iParent.Position().iY );
    iViewControl.ScrollContainer( pos );

    // Draw only when drawing is allowed
    if ( aDrawNow )
        {
        iParent.DrawNow();
        }

    // Vertical scroll index has changed, we need to update scroll bar also
    iPhysicsObserver.UpdateScrollBarDuringOngoingPhysics();
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::PhysicEmulationEnded
// ---------------------------------------------------------------------------
//
void CMRListPanePhysics::PhysicEmulationEnded()
    {
    FUNC_LOG;
    iPhysicsObserver.PhysicsEmulationEnded();
    
    // Synchronize field container position
    iViewControl.Synchronize();
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::ViewPosition
// ---------------------------------------------------------------------------
//
TPoint CMRListPanePhysics::ViewPosition() const
    {
    FUNC_LOG;
    if ( !iFeatureEnabled )
        {
        return TPoint( iParent.Position() );
        }

    // This is the default implementation
    TPoint viewPosition(
            iViewSize.iWidth / 2,
            iViewSize.iHeight / 2 + iVerScrollIndex );

    return viewPosition;
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::UpdateVerticalScrollIndex
// ---------------------------------------------------------------------------
//
void CMRListPanePhysics::UpdateVerticalScrollIndex( TInt aVerScrollIndex )
    {
    FUNC_LOG;
    if ( iFeatureEnabled )
        {
        // Physics' new position is updated to this member, when field
        // container is scrolled by someone else than physics.
        iVerScrollIndex = aVerScrollIndex;
        }
    }

// ---------------------------------------------------------------------------
// CMRListPanePhysics::VerticalScrollIndex
// ---------------------------------------------------------------------------
//
TInt CMRListPanePhysics::VerticalScrollIndex()
    {
    return iVerScrollIndex;
    }
// End of file

