/*
* 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:     
*
*/


#include "HgScrollbar.h"
#include <ganes/HgScrollbarObserverIface.h>
#include "HgConstants.h"

#include <AknsUtils.h>
#include <AknUtils.h>
#include <AknsDrawUtils.h>

#include <layoutmetadata.cdl.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <aknlayoutscalable_apps.cdl.h>

#include <bitstd.h>
#include <gulicon.h>

#include <AknIconUtils.h>
#include <AknsUtils.h>
#include <AknsConstants.h>
#include <w32std.h>

// -----------------------------------------------------------------------------
// CHgScrollbar::NewL()
// -----------------------------------------------------------------------------
//
CHgScrollbar* CHgScrollbar::NewL( MHgScrollbarObserver& aObserver )
    {
    CHgScrollbar* self = new (ELeave) CHgScrollbar( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::~CHgScrollbar()
// -----------------------------------------------------------------------------
//
CHgScrollbar::~CHgScrollbar()
    {
    delete iScrollbarBg;
    delete iScrollbarHandle;
    delete iScrollbarHandleBg;
    delete iScrollbarBgSelected;
    delete iScrollbarHandleSelected;
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::CHgScrollbar()
// -----------------------------------------------------------------------------
//
CHgScrollbar::CHgScrollbar( MHgScrollbarObserver& aObserver )
    : iObserver( aObserver ), 
      iStatic( ETrue )
    {
    
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::ConstructL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::ConstructL()
    {
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::SetScrollbarL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::InitScrollBarL(
        TRect aRect,
        TSize aTotalSize,
        TSize aViewSize,
        TBool aLandscapeScrolling )
    {
    if( iTotalSize == aTotalSize 
            && iViewSize == aViewSize 
            && iLandscapeScrolling == aLandscapeScrolling )
        {
        return;
        }
    
    TInt variety = aLandscapeScrolling ? 1 : 0;
    
    TAknLayoutRect layout;
    layout.LayoutRect(aRect, AknLayoutScalable_Avkon::scroll_pane( variety ));
    iScrollbarRect = layout.Rect();
    
    TBool prevStatic = iStatic;

    if((aTotalSize.iHeight <= aViewSize.iHeight && !aLandscapeScrolling)
            || (aTotalSize.iWidth <= aViewSize.iWidth && aLandscapeScrolling) )
        {
        iTotalSize = aViewSize;
        iStatic = ETrue;
        }
    else
        {
        iTotalSize = aTotalSize;
        iStatic = EFalse;
        }
    
    // Do we need to init the bg graphics
    TBool initBg = (iViewSize != aViewSize) // view size has been changed 
                    || (prevStatic != iStatic) // static value changed
                    || (iLandscapeScrolling != aLandscapeScrolling); // different scrolling direction

    iViewSize = aViewSize;
    iLandscapeScrolling = aLandscapeScrolling;
    iHandlePosition.SetXY(0,0);

    if(iLandscapeScrolling)
        {
        iTotalLength = iTotalSize.iWidth - iViewSize.iWidth;
        }
    else
        {
        iTotalLength = iTotalSize.iHeight - iViewSize.iHeight;
        }

    // Don't init icons in static mode since they are not drawn
    if(!iStatic)
        InitIconsL( initBg );    
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::SetViewPosition()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::SetViewPosition( TPoint aPosition )
    {
    if(!iStatic)
        {
        if(iLandscapeScrolling)
            {
            if (AknLayoutUtils::LayoutMirrored())
                {
                iHandlePosition.iX = (iScrollLength) * (1.0 - aPosition.iX / TReal(iTotalLength));
                }
            else
                {
                iHandlePosition.iX = (iScrollLength) * (aPosition.iX / TReal(iTotalLength));            
                }
            }
        else
            {
            iHandlePosition.iY = (iScrollLength) * (aPosition.iY / TReal(iTotalLength));
            }
        CheckHandlePosition( EFalse );
        }
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::HandlePointerEventL()
// -----------------------------------------------------------------------------
//
TBool CHgScrollbar::HandlePointerEventL( const TPointerEvent& aEvent )
    {
    return HandleScrollBarPointerEvent( aEvent );
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::HandleScrollBarPointerEvent()
// -----------------------------------------------------------------------------
//
TBool CHgScrollbar::HandleScrollBarPointerEvent( const TPointerEvent& aEvent )
    {
    TBool ret = EFalse;
    // Quick and dirty hack, remove when logic for fetching the correct drag rect is available
    TRect dragArea( iScrollbarRect );
    dragArea.iBr.iX += KScrollAreaOffset; 
    dragArea.iTl.iX -= KScrollAreaOffset;

    // Start drag
    if( aEvent.iType == TPointerEvent::EButton1Down && dragArea.Contains(aEvent.iPosition))
        {
        TSize size(iHandleSize);
        size.iWidth += KScrollAreaOffset*2;
        TRect handleRect( dragArea.iTl + iHandlePosition, size );
        iDragging = handleRect.Contains( aEvent.iPosition );
        iPrevDrag = aEvent.iPosition;
        iHandler = ret = ETrue;
        CheckHandlePosition( !iStatic );
        }

    // Drag
    if( aEvent.iType == TPointerEvent::EDrag && iHandler)
        {
        if( iDragging )
            {
            if(iLandscapeScrolling)
                {
                iHandlePosition.iX -= iPrevDrag.iX - aEvent.iPosition.iX;
                }
            else
                {
                iHandlePosition.iY -= iPrevDrag.iY - aEvent.iPosition.iY;
                }
            CheckHandlePosition( !iStatic );
            
            iPrevDrag = aEvent.iPosition;
            }
        ret = ETrue;
        }

    // End drag
    if( aEvent.iType == TPointerEvent::EButton1Up && iHandler)
        {
        if(!iDragging)
            {
            TBool below = iLandscapeScrolling ? 
                    aEvent.iPosition.iX > iHandlePosition.iX 
                    : aEvent.iPosition.iY > iHandlePosition.iY;
            iHandlePosition += below ? iHandleSize.AsPoint() : -iHandleSize.AsPoint();
            }
        CheckHandlePosition( !iStatic );
        iHandler = iDragging = EFalse; 
        ret = ETrue;
        }

    return ret;    
    }


// -----------------------------------------------------------------------------
// CHgScrollbar::Draw()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::Draw( CWindowGc& aGc )
    {
    if(!iStatic)
        DrawScrollbar( aGc );
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::DrawScrollbar()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::DrawScrollbar( CWindowGc& aGc )
    {
    if(iScrollbarBg && iScrollbarHandle && iScrollbarHandleBg)
        {
        if(iHandler)
            {
            aGc.BitBltMasked(iScrollbarRect.iTl, 
                    iScrollbarHandleBg->Bitmap(),
                    iScrollbarHandleBg->Bitmap()->SizeInPixels(),
                    iScrollbarHandleBg->Mask(),
                    EFalse);
            
            aGc.BitBltMasked(iScrollbarRect.iTl + iHandlePosition, 
                    iScrollbarHandleSelected->Bitmap(),
                    iScrollbarHandleSelected->Bitmap()->SizeInPixels(),
                    iScrollbarHandleSelected->Mask(),
                    EFalse);
            }
        else
            {
            aGc.BitBltMasked(iScrollbarRect.iTl, 
                    iScrollbarBg->Bitmap(),
                    iScrollbarBg->Bitmap()->SizeInPixels(),
                    iScrollbarBg->Mask(),
                    EFalse);

            aGc.BitBltMasked(iScrollbarRect.iTl + iHandlePosition, 
                    iScrollbarHandle->Bitmap(),
                    iScrollbarHandle->Bitmap()->SizeInPixels(),
                    iScrollbarHandle->Mask(),
                    EFalse);
            }
        }
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::CheckHandlePosition()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::CheckHandlePosition( TBool aReportChange )
    {

    if(iLandscapeScrolling)
        {
        iHandlePosition.iY = 0;
        if(iHandlePosition.iX < 0 )
            iHandlePosition.iX = 0;
        if(iHandlePosition.iX > iScrollLength)
            iHandlePosition.iX = iScrollLength;
        }
    else
        {
        iHandlePosition.iX = 0;
        if(iHandlePosition.iY < 0 )
            iHandlePosition.iY = 0;
        if(iHandlePosition.iY > iScrollLength)
            iHandlePosition.iY = iScrollLength;
        }
    if( aReportChange )
        {
        TPoint pos (iViewSize.iWidth/2, iViewSize.iHeight/2);
        if(iLandscapeScrolling)
            {
            if (AknLayoutUtils::LayoutMirrored())
                {
                pos.iX += (1.0 - iHandlePosition.iX / TReal(iScrollLength)) * (iTotalLength);
                }
            else
                {
                pos.iX += (iHandlePosition.iX / TReal(iScrollLength)) * (iTotalLength);            
                }
            }
        else
            {
            pos.iY += (iHandlePosition.iY / TReal(iScrollLength)) * (iTotalLength);
            }
        
        iObserver.ScrollBarPositionChanged( pos );
        }
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::InitIconsL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::InitIconsL( TBool aInitBgIcons )
    {
    if(aInitBgIcons)
        {
        delete iScrollbarBg; iScrollbarBg = NULL;
        delete iScrollbarBgSelected; iScrollbarBgSelected = NULL;
        delete iScrollbarHandleBg; iScrollbarHandleBg = NULL;
    
        CreateIconL(iScrollbarBg, iScrollbarRect.Size());
        CreateIconL(iScrollbarBgSelected, iScrollbarRect.Size());
        CreateIconL(iScrollbarHandleBg, iScrollbarRect.Size());
        }
    
    TReal xFactor = iScrollbarRect.Width()/TReal(iTotalSize.iWidth);
    TReal yFactor = iScrollbarRect.Height()/TReal(iTotalSize.iHeight); 
    
    iHandleSize = TSize ( iViewSize.iWidth * xFactor, iViewSize.iHeight * yFactor );

    if(iLandscapeScrolling)
        {
        TInt min = 2*iHandleSize.iHeight;
        if( iHandleSize.iWidth < min )
            {
            iHandleSize.iWidth = min;
            }
        iScrollLength = iScrollbarRect.Width() - iHandleSize.iWidth;
        }
    else
        {
        TInt min = 2*iHandleSize.iWidth;
        if( iHandleSize.iHeight < min )
            {
            iHandleSize.iHeight = min;
            }
        iScrollLength = iScrollbarRect.Height() - iHandleSize.iHeight;
        }
    
    delete iScrollbarHandle; iScrollbarHandle = NULL;
    delete iScrollbarHandleSelected; iScrollbarHandleSelected = NULL;

    CreateIconL(iScrollbarHandle, iHandleSize );
    CreateIconL(iScrollbarHandleSelected, iHandleSize );
    
    if( iLandscapeScrolling )
        {
        if( aInitBgIcons )
            {
            DrawIconL( *iScrollbarBg, 
                    KAknsIIDQsnCpScrollHorizontalBgTop, 
                    KAknsIIDQsnCpScrollHorizontalBgMiddle, 
                    KAknsIIDQsnCpScrollHorizontalBgBottom );
    
            // TODO, check if this is needed.
    //        DrawIconL( *iScrollbarHandleBg, 
    //                KAknsIIDQsnCpScrollHorizontalHandleBgTop, 
    //                KAknsIIDQsnCpScrollHorizontalHandleBgMiddle, 
    //                KAknsIIDQsnCpScrollHorizontalHandleBgBottom );
            
            DrawIconL( *iScrollbarBgSelected, 
                    KAknsIIDQsnCpScrollHorizontalBgTopPressed, 
                    KAknsIIDQsnCpScrollHorizontalBgMiddlePressed, 
                    KAknsIIDQsnCpScrollHorizontalBgBottomPressed );
            }
        
        DrawIconL( *iScrollbarHandle, 
                KAknsIIDQsnCpScrollHorizontalHandleTop, 
                KAknsIIDQsnCpScrollHorizontalHandleMiddle, 
                KAknsIIDQsnCpScrollHorizontalHandleBottom);

        DrawIconL( *iScrollbarHandleSelected, 
                KAknsIIDQsnCpScrollHorizontalHandleTopPressed, 
                KAknsIIDQsnCpScrollHorizontalHandleMiddlePressed, 
                KAknsIIDQsnCpScrollHorizontalHandleBottomPressed );        
        }
    else
        {
        if(aInitBgIcons)
            {
            DrawIconL( *iScrollbarBg, 
                    KAknsIIDQsnCpScrollBgTop, 
                    KAknsIIDQsnCpScrollBgMiddle, 
                    KAknsIIDQsnCpScrollBgBottom );
            
            DrawIconL( *iScrollbarHandleBg, 
                    KAknsIIDQsnCpScrollHandleBgTop, 
                    KAknsIIDQsnCpScrollHandleBgMiddle, 
                    KAknsIIDQsnCpScrollHandleBgBottom );
            
            DrawIconL( *iScrollbarBgSelected, 
                    KAknsIIDQsnCpScrollBgTopPressed, 
                    KAknsIIDQsnCpScrollBgMiddlePressed, 
                    KAknsIIDQsnCpScrollBgBottomPressed );
            }
        
        DrawIconL( *iScrollbarHandle, 
                KAknsIIDQsnCpScrollHandleTop, 
                KAknsIIDQsnCpScrollHandleMiddle, 
                KAknsIIDQsnCpScrollHandleBottom);

        DrawIconL( *iScrollbarHandleSelected, 
                KAknsIIDQsnCpScrollHandleTopPressed, 
                KAknsIIDQsnCpScrollHandleMiddlePressed, 
                KAknsIIDQsnCpScrollHandleBottomPressed );        
        }
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::CreateIconL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::CreateIconL( CGulIcon*& aIcon, TSize aSize)
    {
    CFbsBitmap* bmap = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( bmap );
    User::LeaveIfError( bmap->Create( aSize , EColor64K));
    
    CFbsBitmap* mask = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( mask );
    User::LeaveIfError( mask->Create( aSize , EGray256));
    
    aIcon = CGulIcon::NewL( bmap, mask );
    
    CleanupStack::Pop(2, bmap);
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::DrawIconL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::DrawIconL( CGulIcon& aIcon,
        const TAknsItemID& aTop,
        const TAknsItemID& aMiddle,
        const TAknsItemID& aBottom )
    {
    TRect rect;
    TSize iconSize(aIcon.Bitmap()->SizeInPixels());
    TSize tSize;
    TPoint point(0,0);
    if(iLandscapeScrolling)
        {
        tSize.SetSize(iconSize.iHeight, iconSize.iHeight);
        }
    else
        {
        tSize.SetSize(iconSize.iWidth, iconSize.iWidth);
        }
    
    // TOP
    rect.SetRect(point, tSize);
    DrawBitmapL( aIcon, aTop, rect );

    // MIDDLE
    TSize middlesize(iconSize);
    if(iLandscapeScrolling)
        {
        point.iX = tSize.iWidth;
        middlesize.iWidth -= 2*tSize.iWidth;
        }
    else
        {
        point.iY = tSize.iHeight;
        middlesize.iHeight -= 2*tSize.iHeight;
        }
    rect.SetRect(point, middlesize);
    DrawBitmapL( aIcon, aMiddle, rect);
    
    // BOTTOM
    point = iconSize.AsPoint()-tSize;
    rect.SetRect(point, tSize);
    DrawBitmapL( aIcon, aBottom, rect );
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::DrawBitmapL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::DrawBitmapL( CGulIcon& aIcon,
        const TAknsItemID& aItem,
        const TRect& aDestRect )
    {
    CFbsBitmap* bitmap = NULL;
    CFbsBitmap* mask = NULL;
    TRAP_IGNORE( AknsUtils::CreateIconL(AknsUtils::SkinInstance(), aItem, bitmap, mask, KNullDesC, -1, -1); )

    if(!bitmap)
        {
        AknsUtils::CreateIconL(AknsUtils::SkinInstance(), aItem, bitmap, KNullDesC, -1);        
        }
    
    AknIconUtils::SetSize(bitmap, aDestRect.Size(), EAspectRatioNotPreserved);
    ScaleBitmapL(aDestRect, aIcon.Bitmap(), bitmap);
    
    if(mask)
        {
        AknIconUtils::SetSize(mask, aDestRect.Size(), EAspectRatioNotPreserved);
        ScaleBitmapL(aDestRect, aIcon.Mask(), mask);
        }
    
    delete bitmap; bitmap = NULL;
    delete mask; mask = NULL;
    }


// -----------------------------------------------------------------------------
// CHgScrollbar::ScaleBitmapL()
// -----------------------------------------------------------------------------
//
void CHgScrollbar::ScaleBitmapL( const TRect& aDestRect,
        CFbsBitmap* aDest,
        const CFbsBitmap* aSrc)
    {
    CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(aDest);
    CleanupStack::PushL(device);

    CFbsBitGc* gc = NULL;
    User::LeaveIfError(device->CreateContext(gc));
    CleanupStack::PushL(gc);
    
    gc->DrawBitmap(aDestRect, aSrc);
    
    CleanupStack::PopAndDestroy(2, device);
    }

// -----------------------------------------------------------------------------
// CHgScrollbar::ScrollbarBg()
// -----------------------------------------------------------------------------
//
const CGulIcon* CHgScrollbar::ScrollbarBg() const
    {
    return iScrollbarBg;
    }   


const CGulIcon* CHgScrollbar::ScrollbarHandleBg() const
    {
    return iScrollbarHandleBg;
    }

const CGulIcon* CHgScrollbar::ScrollbarHandle() const
    {
    return iScrollbarHandle;
    }

const CGulIcon* CHgScrollbar::ScrollbarBgSelected() const
    {
    return iScrollbarBgSelected;
    }

const CGulIcon* CHgScrollbar::ScrollbarHandleSelected() const
    {
    return iScrollbarHandleSelected;
    }

const TRect& CHgScrollbar::ScrollbarRect() const
    {
    return iScrollbarRect;
    }

const TPoint& CHgScrollbar::HandlePosition() const
    {
    return iHandlePosition;
    }

TBool CHgScrollbar::IsStatic() const
    {
    return iStatic;
    }

TBool CHgScrollbar::IsDragging() const
    {
    return iDragging;
    }

TBool CHgScrollbar::Handler() const
    {
    return iHandler;
    }

void CHgScrollbar::Reset()
    {
    iHandler = iDragging = EFalse; 
    }

// End of file
