uifw/EikStd/coctlsrc/AknDoubleSpanScrollIndicator.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:00:49 +0200
changeset 0 2f259fa3e83a
child 4 8ca85d2f0db7
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2004 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:  Indicator for double span scroll bar.
*    
*
*/


#include "AknDoubleSpanScrollIndicator.h"
#include "AknDoubleSpanScrollIndicatorItem.h"
#include <aknconsts.h>
#include <avkon.mbg>
#include <AknUtils.h>
#include <AknsDrawUtils.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <aknappui.h>
#include <AknDef.h>
#include <AknPriv.hrh>
#include <AknTasHook.h>
#include <AknsDrawUtils.h>
// Do not use these constants directly, use implemented private methods instead.
// const TInt KScrollBackgroundMinVisibleSizeInPixels = 4; // minimum distance handle and scb bottom. 
//const TInt KHandleBackgroundMinSizeInPixels = 24; // double spanned non focused handle minimum size
//const TInt KHandleMinSizeInPixels = 12; // focused handle minimum size
const TInt KPrecision = 8; // Used in pixel effect calculations

CAknDoubleSpanScrollIndicator* CAknDoubleSpanScrollIndicator::NewL(CEikScrollBar::TOrientation aOrientation)
    {
    CAknDoubleSpanScrollIndicator* self = new (ELeave) CAknDoubleSpanScrollIndicator();
    CleanupStack::PushL(self);
    self->ConstructL(aOrientation);
    CleanupStack::Pop();
    return self;
    }

CAknDoubleSpanScrollIndicator::CAknDoubleSpanScrollIndicator() 
: iOwnsWindow(EFalse), iTransparentBackground(EFalse), iDrawBackground(ETrue), 
    iBackgroundHighlight(EFalse),iDrawBackgroundBitmap(EFalse)
    {
    AKNTASHOOK_ADD( this, "CAknDoubleSpanScrollIndicator" );
    }

CAknDoubleSpanScrollIndicator::~CAknDoubleSpanScrollIndicator()
    {
    AKNTASHOOK_REMOVE();
    AknsUtils::DeregisterControlPosition( this );
    
    delete iBackgroundBar;
    delete iHighlightBackgroundBar;
    delete iHandleBar;
    delete iHighlightHandleBar;
    
 
    }

void CAknDoubleSpanScrollIndicator::ConstructL(CEikScrollBar::TOrientation aOrientation)
    {
    iOrientation = aOrientation;
    CreateScrollBarItemsL();
    UpdateScrollBarLayout();
    }

void CAknDoubleSpanScrollIndicator::Draw(const TRect& /*aRect*/) const
    {
    CWindowGc& gc = SystemGc();

    if(iDrawBackground)
        {
        DrawBackground();
        }
    
    CAknDoubleSpanScrollIndicatorItem* handleBackgroundBar = 
        iBackgroundHighlight && iHighlightBackgroundBar ?
            iHighlightBackgroundBar : iBackgroundBar;
    
    DrawTiled(gc, iBackgroundRect, handleBackgroundBar);

    TBool showHandleBarBackground = iFieldPosition >= 0 && iFieldSize > 0; 
    if(showHandleBarBackground)
        {
        DrawTiled(gc, iHandleBackgroundRect, iHighlightBackgroundBar);
        }

    CAknDoubleSpanScrollIndicatorItem* handleBar = 
        iHandleHighlight && iHighlightHandleBar ?
        iHighlightHandleBar : iHandleBar;

    DrawTiled(gc, iHandleRect, handleBar);
    }
void CAknDoubleSpanScrollIndicator::UpdateScrollBarLayout()
    {
    iHeadItemSize = 12;
    iMidItemSize = 12 * 5;
    iTailItemSize = 12;
    
    TRect rect = Rect();
    if(rect.IsEmpty())
        {        
        return;
        }
    
    TInt varietyIndex ( 0 );
    if ( iOrientation == CEikScrollBar::EHorizontal )
        {
        varietyIndex = 1;
        }

    TAknLayoutRect layRect;
    TAknWindowComponentLayout layout = AknLayoutScalable_Avkon::scroll_bg_pane_g1( varietyIndex ); //top
    layRect.LayoutRect( rect, layout.LayoutLine() );    
    TSize newSize = layRect.Rect().Size();  
    iHeadItemSize = (iOrientation == CEikScrollBar::EVertical?newSize.iHeight:newSize.iWidth);
    
    layout = AknLayoutScalable_Avkon::scroll_bg_pane_g3(varietyIndex); // bottom
    layRect.LayoutRect(rect, layout.LayoutLine());
    newSize = layRect.Rect().Size();
    iTailItemSize =  (iOrientation == CEikScrollBar::EVertical?newSize.iHeight:newSize.iWidth);
        
    layout = AknLayoutScalable_Avkon::scroll_bg_pane_g2(varietyIndex); //middle
    layRect.LayoutRect(rect, layout.LayoutLine());
    newSize = layRect.Rect().Size();    
 //   iMidItemSize = (iOrientation == CEikScrollBar::EVertical?newSize.iHeight:newSize.iWidth) * 5;
    }

void CAknDoubleSpanScrollIndicator::DrawTiled(
        CWindowGc& aGc, const TRect& aRect, 
        CAknDoubleSpanScrollIndicatorItem *aIndicatorItem) const
    {
    if (aRect.IsEmpty())
        return;

    TRect headRect = aRect;
    TRect tailRect = aRect;
    TRect midRect = aRect;
    TInt midDrawLength;
    TSize midSize;
    if (iOrientation == CEikScrollBar::EVertical)
        {
        if ((iHeadItemSize + iTailItemSize) <= aRect.Height())
            {
            headRect.SetHeight(iHeadItemSize);
            tailRect.iTl.iY = tailRect.iBr.iY - iTailItemSize;
            }
        else
            {
            headRect.SetHeight((aRect.Height() >> 1));
            tailRect.iTl.iY = tailRect.iBr.iY - headRect.Height();
            }
        midRect.iTl.iY += headRect.Height();
        midRect.iBr.iY -= tailRect.Height();
        midDrawLength = midRect.Height();
        midSize.SetSize(midRect.Width(), iMidItemSize);
        }
    else
        {
        headRect.SetWidth( iHeadItemSize );
        tailRect.iTl.iX = tailRect.iBr.iX - iTailItemSize;

        midRect.iTl.iX += iHeadItemSize;
        midRect.iBr.iX -= iTailItemSize;
        midDrawLength = midRect.Width();
        midSize.SetSize(iMidItemSize, midRect.Height());
        }
   
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();

    CFbsBitmap *bmp = NULL; 
    CFbsBitmap *mask = NULL;
    AknsUtils::GetCachedMaskedBitmap(skin, aIndicatorItem->iTopId, bmp, mask);
    AknIconUtils::SetSize(bmp, headRect.Size(), EAspectRatioNotPreserved);
    AknIconUtils::SetSize(mask, headRect.Size(), EAspectRatioNotPreserved);
    aGc.BitBltMasked(headRect.iTl, bmp, TRect(TPoint(0, 0), headRect.Size()), mask, ETrue);
    
    AknsUtils::GetCachedMaskedBitmap(skin, aIndicatorItem->iMidId, bmp, mask);
    AknIconUtils::SetSize(bmp, midSize, EAspectRatioNotPreserved);
    AknIconUtils::SetSize(mask, midSize, EAspectRatioNotPreserved);

    TInt count = midDrawLength / iMidItemSize;
    TPoint destPos(midRect.iTl.iX, midRect.iTl.iY);
    TRect sourRect(TPoint(0, 0), bmp->SizeInPixels());
    for(TInt i = 0; i < count; i++)
        {
        aGc.BitBltMasked(destPos, bmp, sourRect, mask, ETrue);
        iOrientation == CEikScrollBar::EVertical?destPos.iY += iMidItemSize : destPos.iX += iMidItemSize;
        }
    iOrientation == CEikScrollBar::EVertical?sourRect.iBr.iY = midRect.Height() % iMidItemSize
                    :sourRect.iBr.iX = midRect.Width() % iMidItemSize;
    aGc.BitBltMasked(destPos, bmp, sourRect, mask, ETrue);

    AknsUtils::GetCachedMaskedBitmap(skin, aIndicatorItem->iBottomId, bmp, mask);
    AknIconUtils::SetSize(bmp, tailRect.Size(), EAspectRatioNotPreserved);
    AknIconUtils::SetSize(mask, tailRect.Size(), EAspectRatioNotPreserved);
    aGc.BitBltMasked(tailRect.iTl, bmp, TRect(TPoint(0, 0), tailRect.Size()), mask, ETrue);
    }

void CAknDoubleSpanScrollIndicator::CalculateRects()
    {
    iBackgroundRect = Rect();
    
    // 
    // sanity checks for values used in drawing   
    //
    TInt checkedScrollSpan    = iScrollSpan; // all items
    TInt checkedFocusPosition = iFocusPosition; // current item
    TInt checkedWindowSize    = iWindowSize; // number of visible items
    TInt checkedFieldPosition = iFieldPosition; // position in sub list
    TInt checkedFieldSize     = iFieldSize; // number of visible items in sub list
       
    CheckValues(checkedScrollSpan, 
        checkedFocusPosition, 
        checkedWindowSize, 
        checkedFieldPosition, 
        checkedFieldSize);
    
    // If span (max number of items) is zero, then draw only the background
    if (checkedScrollSpan == 0)
        {
        iHandleBackgroundRect = TRect(0,0,0,0);
        iHandleRect = TRect(0,0,0,0);
        return;
        }

    // 
    // Transform values into pixels and rects.
    //
    TInt scrollBarHeightInPixels( 0 );
    
    if ( iOrientation == CEikScrollBar::EHorizontal )
        {
        scrollBarHeightInPixels = iBackgroundRect.Width();
        }
    else
        {
        scrollBarHeightInPixels = iBackgroundRect.Height();
        }
    
    // The code block below was probably used to prevent
    // a truncation-vs-rounding error from happening
    /*
    if ((checkedWindowSize > 0) && (checkedScrollSpan > 0))
        {
        if((checkedFocusPosition + checkedWindowSize) == checkedScrollSpan)
            windowSizeInPixels = scrollBarHeightInPixels - focusPositionInPixels;
        else
            windowSizeInPixels = scrollBarHeightInPixels*checkedWindowSize/checkedScrollSpan;
        }
    */
    
    TInt windowSizeInPixels = 
        Max( checkedWindowSize * scrollBarHeightInPixels / checkedScrollSpan,
             HandleBackgroundMinSizeInPixels() );
    
    TInt roomForMovementInSpan   = checkedScrollSpan - checkedWindowSize;
    TInt roomForMovementInPixels = 
        scrollBarHeightInPixels - windowSizeInPixels;    
    
    TInt focusPositionInPixels( 0 );
        
    if ( roomForMovementInSpan > 0 && roomForMovementInPixels > 0 )
        {
        focusPositionInPixels =
            checkedFocusPosition * roomForMovementInPixels /
            roomForMovementInSpan;
        }

    // If window would cover whole scrollbar, then modify 
    // it to leave the thumb little short from bottom
    TInt scrollBarHandleMaxSizeInPixels =  ScrollHandleMaxVisibleSizeInPixels();
    if (windowSizeInPixels >= scrollBarHeightInPixels)
        {
        windowSizeInPixels = scrollBarHandleMaxSizeInPixels;    
        }

    TBool doubleSpanInUse = (checkedFieldPosition >= 0) && (checkedFieldSize > 0);
    TInt minHandleBackgroundSize = 0;
    TInt fieldSizeInPixels = 0; // sub field size
    TInt fieldPositionInPixels = 0;
    if (doubleSpanInUse)
        {
        fieldSizeInPixels = windowSizeInPixels/checkedFieldSize;
        fieldPositionInPixels = windowSizeInPixels*checkedFieldPosition/checkedFieldSize;
        minHandleBackgroundSize = HandleBackgroundMinSizeInPixels();
        }
    else
        {
        minHandleBackgroundSize = HandleMinSizeInPixels();
        }
    
    TInt handleMinSize = HandleMinSizeInPixels();
    // Similar compensation for handle if double span is in use
    if (doubleSpanInUse && (fieldSizeInPixels < handleMinSize))
        {
        TInt extraPixels = 0;
        TInt extraPixelCompensationInterval = 0;
        TInt extraPixelCompensation = 0;
        extraPixels = handleMinSize - fieldSizeInPixels;
        extraPixelCompensationInterval = windowSizeInPixels/extraPixels;
        if (extraPixelCompensationInterval != 0)
            {
            extraPixelCompensation = fieldPositionInPixels/extraPixelCompensationInterval;
            if (extraPixelCompensation > handleMinSize)
                {
                extraPixelCompensation = handleMinSize;
                }
            }

        if ((fieldPositionInPixels - extraPixelCompensation) > 0)
            {
            fieldPositionInPixels -= extraPixelCompensation;
            }
        
        // Additional compensation at the end is sometimes needed as above compensation is not
        // always accurate because the fieldPositionInPixels is not anymore in "right" place. 
        if (checkedFieldPosition < (checkedFieldSize - 1))
            {           
            if ((fieldPositionInPixels + handleMinSize) >= windowSizeInPixels - 1)
                {
                fieldPositionInPixels = windowSizeInPixels - (handleMinSize + 2);
                }
            }            
        fieldSizeInPixels = handleMinSize;
        }
    
    
    // If orientation is horizontal, then rotate rects here first
    // 90 degrees. At the end of this function rotate them back again.
    if (iOrientation == CEikScrollBar::EHorizontal)
        {
        TRect original = iBackgroundRect;
        iBackgroundRect.iBr.iX = original.iTl.iX + original.Height();
        iBackgroundRect.iBr.iY = original.iTl.iY + original.Width();
        iHandleBackgroundRect = TRect(0,0,0,0);
        iHandleRect = TRect(0,0,0,0);
        }
    
    // handle background
    iHandleBackgroundRect = iBackgroundRect;
    iHandleBackgroundRect.iTl.iY += focusPositionInPixels;
    iHandleBackgroundRect.iBr.iY = iHandleBackgroundRect.iTl.iY + windowSizeInPixels; 
  
    if (iHandleBackgroundRect.iBr.iY > iBackgroundRect.iBr.iY)
        {
        iHandleBackgroundRect.iBr.iY = iBackgroundRect.iBr.iY;
        iHandleBackgroundRect.iTl.iY = iBackgroundRect.iBr.iY - windowSizeInPixels;
        }

    // fields
    iHandleRect= iHandleBackgroundRect;
    iHandleRect.iTl.iY += fieldPositionInPixels;
    iHandleRect.iBr.iY = iHandleRect.iTl.iY + fieldSizeInPixels;
    if (iHandleRect.iTl.iY < iHandleBackgroundRect.iTl.iY)
        {
        iHandleRect.iTl.iY = iHandleBackgroundRect.iTl.iY;
        }

    if (iHandleRect.iBr.iY > iHandleBackgroundRect.iBr.iY)
        {
        iHandleRect.iBr.iY = iHandleBackgroundRect.iBr.iY;
        }    

    // if double span is not used, set the handle to cover whole handle background area.
    if (!doubleSpanInUse)
        {
        iHandleRect.SetHeight(iHandleBackgroundRect.Height());
        }
        
    // check overflow 
    if (iHandleBackgroundRect.iBr.iY > iBackgroundRect.iBr.iY)
        {
        
        iHandleBackgroundRect.iBr.iY = iBackgroundRect.iBr.iY;
        iHandleBackgroundRect.iTl.iY = iBackgroundRect.iBr.iY - minHandleBackgroundSize;
        }
    if (iHandleBackgroundRect.iTl.iY < iBackgroundRect.iTl.iY)
        {
        iHandleBackgroundRect.iTl.iY = iBackgroundRect.iTl.iY;
        }

    // check overflow
    if (iHandleRect.iBr.iY > iHandleBackgroundRect.iBr.iY)
        {
        iHandleRect.iBr.iY = iHandleBackgroundRect.iBr.iY;
        iHandleRect.iTl.iY = iHandleBackgroundRect.iBr.iY - handleMinSize;
        }
    if (iHandleRect.iTl.iY < iHandleBackgroundRect.iTl.iY)
        {
        iHandleRect.iTl.iY = iHandleBackgroundRect.iTl.iY;
        }
    
    // If calculations were done to 90 degrees rotated rects, rotate those back here. 
    if (iOrientation == CEikScrollBar::EHorizontal)
        {
        TRect originalBackgroundRect = iBackgroundRect;
        iBackgroundRect.SetWidth(originalBackgroundRect.Height());
        iBackgroundRect.SetHeight(originalBackgroundRect.Width());
        
        TRect originalHandleBackgroundRect = iHandleBackgroundRect;
        iHandleBackgroundRect = iBackgroundRect;

        iHandleBackgroundRect.iTl.iX += originalHandleBackgroundRect.iTl.iY - originalBackgroundRect.iTl.iY;
        iHandleBackgroundRect.iBr.iX = iHandleBackgroundRect.iTl.iX + originalHandleBackgroundRect.Height();

        TRect originalHandleRect = iHandleRect;
        iHandleRect = iBackgroundRect;
 
        iHandleRect.iTl.iX += originalHandleRect.iTl.iY - originalBackgroundRect.iTl.iY;
        iHandleRect.iBr.iX = iHandleRect.iTl.iX + originalHandleRect.Height();
        }
    }


void CAknDoubleSpanScrollIndicator::CheckValues(TInt& aScrollSpan, TInt& aFocusPosition, TInt& aWindowSize, TInt& aFieldPosition, TInt& aFieldSize) const
    {
    // Scrollspan
    if (aScrollSpan <= 0)
        {
        // Default values, only background will be drawn
        aScrollSpan = 0; 
        aWindowSize = 0;
        aFocusPosition = 0;
        aFieldSize = 0;
        aFieldPosition = 0;
        return;
        }

    // Window size
    if (aWindowSize < 1)
        {
        aWindowSize = 1;
        }
    if (aWindowSize > aScrollSpan)
        {
        aWindowSize = aScrollSpan;
        }

    // FocusPosition
    if (aFocusPosition < 0)
        {
        aFocusPosition = 0;
        }
    if (aFocusPosition + aWindowSize > aScrollSpan)
        {
        aFocusPosition = aScrollSpan - aWindowSize;
        }

    // Field size & position
    if (aFieldSize <= 0)
        {
        aFieldSize = 0;
        aFieldPosition = 0;
        }
    else
        {
        // Field position
        if (aFieldPosition < 0)
            {
            aFieldPosition = 0;
            }
        if (aFieldPosition > aFieldSize - 1)
            {
            aFieldPosition = aFieldSize - 1;
            }

        }
    }


void CAknDoubleSpanScrollIndicator::SizeChanged()
    {
    TRect rect( Rect() );
    if(iOldRect != rect)
        {
        iOldRect = rect;        
        AknsUtils::RegisterControlPosition( this );
        CalculateRects();

        if (iOwnsWindow)
            {
            TRAP_IGNORE(CreateBackgroundBitmapL());
            }
        
        UpdateScrollBarLayout();
        
        if (IsVisible() & iOwnsWindow)
            DrawDeferred();
        }
    }

void CAknDoubleSpanScrollIndicator::SetIndicatorValues(TInt aScrollSpan, TInt aFocusPosition, TInt aWindowSize, TInt aFieldPosition, TInt aFieldSize)
    {
    // if nothing changed
    if((iScrollSpan == aScrollSpan) &&
    (iFocusPosition == aFocusPosition) &&
    (iWindowSize == aWindowSize) &&
    (iFieldPosition == aFieldPosition) &&
    (iFieldSize == aFieldSize))
        return;
    
    iScrollSpan = aScrollSpan;
    iFocusPosition = aFocusPosition;
    iWindowSize = aWindowSize;
    iFieldPosition = aFieldPosition;
    iFieldSize = aFieldSize;
    
    // Calculate the sizes for graphics
    CalculateRects();            
    if( iWindowSize > 0 )
        {   
        // layout handle graphics
        LayoutHandleGraphics();
        }
    }

TInt CAknDoubleSpanScrollIndicator::ScrollSpan()
    {
    return iScrollSpan;
    }

TInt CAknDoubleSpanScrollIndicator::FocusPosition()
    {
    return iFocusPosition;
    }

TInt CAknDoubleSpanScrollIndicator::WindowSize()
    {
    return iWindowSize;
    }

TInt CAknDoubleSpanScrollIndicator::FieldPosition()
    {
    return iFieldPosition;
    }

TInt CAknDoubleSpanScrollIndicator::FieldSize()
    {
    return iFieldSize;
    }

void CAknDoubleSpanScrollIndicator::SetTransparentBackground(TBool aTransparentBackground)
    {
    iTransparentBackground = aTransparentBackground;
    }

TBool CAknDoubleSpanScrollIndicator::TransparentBackground()
    {
    return iTransparentBackground;
    }

void CAknDoubleSpanScrollIndicator::HandleResourceChange(TInt aType)
    {
    if ( aType == KAknsMessageSkinChange )
        {
        iDrawBackgroundBitmap = ETrue;
        }
    else if( aType == KAknMessageFocusLost || KEikMessageUnfadeWindows == aType)
        {
        if( HandleHighlight() )
            {
            SetHandleHighlight(EFalse);
            DrawDeferred();
            }
        if( BackgroudHighlight() )
            {
        	SetBackgroudHighlight( EFalse );
            }
        
        }
    
    // SizeChanged handles this. The Scb is always layouted by its parent
    // if(aType == KEikDynamicLayoutVariantSwitch)

        
    CCoeControl::HandleResourceChange(aType);
    }

CAknDoubleSpanScrollIndicatorItem* CAknDoubleSpanScrollIndicator::LoadScrollIndicatorItemL(
        const TAknsItemID &aTopId,
        const TAknsItemID &aMidId,
        const TAknsItemID &aBottomId)
    {
    return CAknDoubleSpanScrollIndicatorItem::NewL(ETrue,
        aTopId, 0, 0,
        aMidId, 0, 0,
        aBottomId, 0, 0); 
    }


void CAknDoubleSpanScrollIndicator::CreateScrollBarItemsL()
    {
    // create items
    if(iOrientation == CEikScrollBar::EVertical)
        {
        iBackgroundBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollBgTop,
                KAknsIIDQsnCpScrollBgMiddle,
                KAknsIIDQsnCpScrollBgBottom);
        
        iHandleBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollHandleTop,
                KAknsIIDQsnCpScrollHandleMiddle,
                KAknsIIDQsnCpScrollHandleBottom);
        
        
       
        if(AknLayoutUtils::PenEnabled())
            {
            iHighlightBackgroundBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollHandleBgTop,
                KAknsIIDQsnCpScrollHandleBgMiddle,
                KAknsIIDQsnCpScrollHandleBgBottom);
            
            iHighlightHandleBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollHandleTopPressed,
                KAknsIIDQsnCpScrollHandleMiddlePressed,
                KAknsIIDQsnCpScrollHandleBottomPressed);
            }
        }
    else
        {
        iBackgroundBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollHorizontalBgTop,
                KAknsIIDQsnCpScrollHorizontalBgMiddle,
                KAknsIIDQsnCpScrollHorizontalBgBottom);
        
        iHandleBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollHorizontalHandleTop,
                KAknsIIDQsnCpScrollHorizontalHandleMiddle,
                KAknsIIDQsnCpScrollHorizontalHandleBottom);

        
        
        if(AknLayoutUtils::PenEnabled())
            {
            //Handle background bar image missing....
            /*
            iHandleBackgroundBar = LoadScrollIndicatorItem(
                KAknsIIDQsnCpScrollHorizontalHandleBgTop,
                KAknsIIDQsnCpScrollHorizontalHandleBgMiddle,
                KAknsIIDQsnCpScrollHorizontalHandleBgBottom);
            */
            
            iHighlightHandleBar = LoadScrollIndicatorItemL(
                KAknsIIDQsnCpScrollHorizontalHandleTopPressed,
                KAknsIIDQsnCpScrollHorizontalHandleMiddlePressed,
                KAknsIIDQsnCpScrollHorizontalHandleBottomPressed);
            }
        }    
    }

TInt CAknDoubleSpanScrollIndicator::IndicatorWidth()
    {
    TAknWindowComponentLayout layout;
    
    if(iOrientation == CEikScrollBar::EHorizontal)
        layout = AknLayoutScalable_Avkon::scroll_pane(1);
    else
        layout = AknLayoutScalable_Avkon::scroll_pane(0);
    
    TAknLayoutRect layRect;
    TRect mainpaneRect;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EMainPane, mainpaneRect );
    layRect.LayoutRect(mainpaneRect, layout.LayoutLine());
    
    if(iOrientation == CEikScrollBar::EHorizontal)
        return layRect.Rect().Height();
    else
        return layRect.Rect().Width();
    }

TInt CAknDoubleSpanScrollIndicator::ScrollHandleMaxVisibleSizeInPixels()
    {
    TRect scbRect = Rect();
    if ( iOrientation == CEikScrollBar::EHorizontal )
        scbRect.SetRect(scbRect.iTl, TSize(scbRect.Height(), scbRect.Width()));
    
    TAknLayoutRect layRect;
    TAknWindowComponentLayout layout = AknLayoutScalable_Avkon::aid_size_max_handle();
    layRect.LayoutRect(scbRect, layout.LayoutLine());
    return layRect.Rect().Height();
    }

TInt CAknDoubleSpanScrollIndicator::HandleBackgroundMinSizeInPixels()
    {
    return HandleMinSizeInPixels();
    }

TInt CAknDoubleSpanScrollIndicator::HandleMinSizeInPixels()
    {
    // We have the minimum size as aid value, do not layout to the handle layout as it is not correct
    // on behalf of height argument (not set as maximum)
    TRect scbRect = Rect();
    if ( iOrientation == CEikScrollBar::EHorizontal )
        scbRect.SetRect(scbRect.iTl, TSize(scbRect.Height(), scbRect.Width()));
    
    TAknLayoutRect layRect;
    TAknWindowComponentLayout layout = AknLayoutScalable_Avkon::aid_size_min_handle();
    layRect.LayoutRect(scbRect, layout.LayoutLine());
    
    return layRect.Rect().Height();
    }


void CAknDoubleSpanScrollIndicator::SetAsWindowOwning(TBool aOwnsWindow)
    {
    iOwnsWindow = aOwnsWindow;
    }
    
void CAknDoubleSpanScrollIndicator::SetDrawBackgroundState(TBool aDraw)
    {
    iDrawBackground = aDraw;
    }
    
TBool CAknDoubleSpanScrollIndicator::DrawBackgroundState()
    {
    return iDrawBackground;
    }

// Prepares background for window-owning scrollbar 
void CAknDoubleSpanScrollIndicator::CreateBackgroundBitmapL()
    {
   
    }

void CAknDoubleSpanScrollIndicator::DrawBackground() const
    {
    CWindowGc& gc=SystemGc();
    TPoint pos = Position();
    TRect rect = Rect();
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    MAknsControlContext* cc = AknsDrawUtils::ControlContext( this );
    
    if(!iTransparentBackground)
        {
        if (iOwnsWindow ) // owns window
            {
            // Redraw the background to bitmap if the skin or the size is changed.
            // Note that the indicator itself is not window owning but the actual window owning 
            // component is the scrollbar class, therefore the window may be in different position
            // and size than the indicator itself
            RWindow& win = Window();
            iDrawBackgroundBitmap = EFalse;
            TRect bmpRect(win.Position() + pos, rect.Size()); // There may be an arrow on top of scb
            if ( CAknEnv::Static()->TransparencyEnabled() )
                {
                AknsDrawUtils::DrawBackground( skin, cc, NULL, gc,
                    rect.iTl, bmpRect, KAknsDrawParamNoClearUnderImage );
                }
            else
                {
                AknsDrawUtils::DrawBackground( skin, cc, NULL, gc, 
                    TPoint(0,0), bmpRect , KAknsDrawParamNoClearUnderImage );
                    
                         
                }
            }
        else             //SB is non-window-owning
            {
            if ( CAknEnv::Static()->TransparencyEnabled() )
                {
                AknsDrawUtils::Background( skin, cc, this, gc, rect, KAknsDrawParamNoClearUnderImage );
                }
            else
                {
                AknsDrawUtils::Background( skin, cc, this, gc, rect );
                }
            }
        }
    }

void CAknDoubleSpanScrollIndicator::LayoutHandleGraphics()
    {
    
    // We layout the handle middle graphics here according to the given inidcator values
    TRect rect = Rect();
    
    if (!iHandleBar || rect.IsEmpty())
        return;
    
    TInt varietyIndex = 0;
    TInt varietyIndexForHandle = 0;
    if (iOrientation == CEikScrollBar::EHorizontal)
        {        
        varietyIndex = 1;
        varietyIndexForHandle = 2;
        }
    
    TAknLayoutRect layRect;
    TAknWindowComponentLayout // layout handle bottom & top as they do not scale according to handle size
    layout = AknLayoutScalable_Avkon::scroll_handle_pane(varietyIndexForHandle); // handle (the shadow if two handles)
    layRect.LayoutRect(rect, layout.LayoutLine());
    layout = AknLayoutScalable_Avkon::scroll_handle_focus_pane(varietyIndex); // focus handle
    // The horizontal data for focus handle is missing so switch the values from the vertical data
    TAknWindowLineLayout layoutLine = layout.LayoutLine();
    if (iOrientation == CEikScrollBar::EHorizontal)
        {
        TInt height = layoutLine.iH;
        TInt width = layoutLine.iW;
        layoutLine.iW = height;
        layoutLine.iH = width;
        }
    layRect.LayoutRect(layRect.Rect(), layoutLine);
    rect = layRect.Rect(); // parent rect is now the focus handle
    
    // the retangle includes the variated length of the middle, 
    // the top and bottom graphics must subtracted from the value
    
    // do not change the handle retangle, the full size is needed in drawing
    // set the width or height to be correct
    if (iOrientation == CEikScrollBar::EVertical)
        {
        iHandleRect.iTl.iX = rect.iTl.iX;
        iHandleRect.iBr.iX = rect.iBr.iX;
        }
    else
        {
        iHandleRect.iTl.iY = rect.iTl.iY;
        iHandleRect.iBr.iY = rect.iBr.iY;
        }
    
   
    }

TInt CAknDoubleSpanScrollIndicator::GetCurrentThumbSpanInPixels()
    {
    return ( iOrientation == CEikScrollBar::EVertical ?
             iHandleBackgroundRect.Height() :
             iHandleBackgroundRect.Width() );
    }
    
TInt CAknDoubleSpanScrollIndicator::GetCurrentThumbPositionInPixels()
    {
    TInt ret;
    
    if ( iOrientation == CEikScrollBar::EHorizontal )
        {
        ret = iHandleBackgroundRect.iTl.iX -
            iBackgroundRect.iTl.iX;
        }
    else
        {
        ret = iHandleBackgroundRect.iTl.iY -
            iBackgroundRect.iTl.iY;
        }
        
    return ret;
    }

void CAknDoubleSpanScrollIndicator::SetHandleHighlight( TBool aHandleHighlight )
    {
    // This does nothing in non-touch
    iHandleHighlight = aHandleHighlight;
    SetBackgroudHighlight(aHandleHighlight);
    }
    
TBool CAknDoubleSpanScrollIndicator::HandleHighlight() const
    {
    return iHandleHighlight;
    }
    
void CAknDoubleSpanScrollIndicator::SetTouchAreaControl( CCoeControl* aTouchAreaControl )
    {
    iTouchAreaControl = aTouchAreaControl;
    }
  
 void CAknDoubleSpanScrollIndicator::SetBackgroudHighlight( TBool aBackgroudHighlight )
    {
    // This does nothing in non-touch
    iBackgroundHighlight = aBackgroudHighlight;

    }
    
TBool CAknDoubleSpanScrollIndicator::BackgroudHighlight() const
    {
    return iBackgroundHighlight;
    }
CFbsBitmap* CAknDoubleSpanScrollIndicator::CopyAndApplyEffectL(
    const CFbsBitmap* aSource, TBool aCopyOnly )
    {
    CFbsBitmap* newBitmap = NULL;
    
    
        newBitmap = new ( ELeave ) CFbsBitmap; 
    
    
    
    TInt err = newBitmap->Create( aSource->SizeInPixels(), aSource->DisplayMode() );
    
    // We still have to return a dummy bitmap object, even if
    // the creation fails.
    if ( err == KErrNone )
        {
        SEpocBitmapHeader header = aSource->Header();
        
        // We support only 16-bit (5-6-5), since this is the default
        // display mode icons are created in. Otherwise just copy.
        if ( !aCopyOnly && aSource->DisplayMode() == EColor64K )
            {
            // Don't modify header data.
            TInt size = ( header.iBitmapSize - header.iStructSize ) /
                        sizeof( TUint16 );
                        
            aSource->BeginDataAccess();
        
            TUint16* source = (TUint16*)aSource->DataAddress();
            TUint16* dest = (TUint16*)newBitmap->DataAddress();
            
            for ( TInt i = 0; i < size; ++i )
                {
                *dest = *source++;
                TBitmapFx::PixelEffect( dest++ );
                }
            
            aSource->EndDataAccess( ETrue );
            }
        else
            {
            // This is probably faster than blitting it. Copy
            // the header data in the same run to minimize size
            // calculations, although it's already correct in the
            // new bitmap.
            TInt size = aSource->Header().iBitmapSize;

            aSource->BeginDataAccess();
            
            Mem::Copy( newBitmap->DataAddress(),
                       aSource->DataAddress(),
                       size );
                       
            aSource->EndDataAccess( ETrue );
            }
        }
    
    
    return newBitmap;
    }


void TBitmapFx::PixelEffect( TUint16* aPixelData )
    {
    // Note: the calculations in this function are based on
    // graphic designers' conception of what Photoshop does
    // to images with certain values. There might also be some
    // room for optimizations.
    
    TRGB rgb;
    
    rgb.iR = ( *aPixelData & 0xF800 ) >> 11;
    rgb.iG = ( *aPixelData & 0x7E0 ) >> 5;
    rgb.iB = ( *aPixelData & 0x1F );
    
    // Scale to 65280 (0xFF00). Under no circumstances should these
    // values end up being > 0xFF00 or < 0x00
    rgb.iR *= 2105.82f;
    rgb.iG *= 1036.20f;
    rgb.iB *= 2105.82f;
    
    // Convert RGB to HSL
    TInt min = Min( rgb.iR, Min( rgb.iG, rgb.iB ) );
    TInt max = Max( rgb.iR, Max( rgb.iG, rgb.iB ) );
    TInt delta = max - min;

    THSL hsl = { 0, 0, 0 } ;
    
    // Lightness
    hsl.iL = ( max + min ) >> 1;
    
    if ( delta == 0 )
        {
        hsl.iH = 0;
        hsl.iS = 0;
        }
    else
        {
        // Hue
        if ( max == rgb.iR )
            {
            hsl.iH = 10880 * ( rgb.iG - rgb.iB ) / delta;
            }
        else if ( max == rgb.iG )
            {
            hsl.iH = 10880 * ( rgb.iB - rgb.iR ) / delta + 21760;
            }
        else if ( max == rgb.iB )
            {
            hsl.iH = 10880 * ( rgb.iR - rgb.iG ) / delta + 43520;
            }
        
        // Saturation
        if ( hsl.iL <= 32640 )
            {
            hsl.iS = ( delta << KPrecision ) / ( ( max + min ) >> KPrecision );
            }
        else
            {
            hsl.iS = ( delta << KPrecision ) / ( ( 0x1FE00 - ( max + min ) ) >> KPrecision );
            }
        }

    // Apply hue shift, moved to proper range in HueToRGB()
    hsl.iH += 0x715;
        
    // Apply saturation
    // +10 in -100..100 in Photoshop terms. According to related material
    // corresponds to 0xCC0 when applied to 0x00..0xFF00
    hsl.iS += 0xCC0;
    
    if ( hsl.iS > 0xFF00 )
        {
        hsl.iS = 0xFF00;
        }

    // Convert back to RGB
    TInt v1;
    TInt v2;
    
    if ( hsl.iS == 0 )
        {
        rgb.iR = ( hsl.iL * 255 ) >> KPrecision;
        rgb.iG = ( hsl.iL * 255 ) >> KPrecision;
        rgb.iB = ( hsl.iL * 255 ) >> KPrecision;
        }
    else
        {
        if ( hsl.iL < 32640 )
            {
            v2 = ( hsl.iL  * ( ( 0xFF00 + hsl.iS ) >> KPrecision ) ) >> KPrecision;
            }
        else
            {
            v2 = ( hsl.iL + hsl.iS ) - ( ( hsl.iS >> KPrecision ) * ( hsl.iL >> KPrecision ) );
            }
        
        v1 = 2 * hsl.iL - v2;
      
        rgb.iR = ( HueToRGB( v1, v2, hsl.iH + 0x54FF ) );
        rgb.iG = ( HueToRGB( v1, v2, hsl.iH ) );
        rgb.iB = ( HueToRGB( v1, v2, hsl.iH - 0x54FF ) );
        }

    rgb.iR /= 2105.82f;
    rgb.iG /= 1036.20f;
    rgb.iB /= 2105.82f;

    // Apply contrast.. However, the original req stated that the
    // contrast value should be +6 in a range of -100..100.
    // With 5 and 6 bit values and fixed point math such a small value has
    // no effect, so it has been left out. The code is here in case
    // the contrast value is updated at some point.
    /*
    const TInt contrast   = ( 6 * 65536 / 200 ) + 65536;
    
    rgb.iR -= 15;
    rgb.iG -= 31;
    rgb.iB -= 15;
    
    rgb.iR *= contrast;
    rgb.iG *= contrast;
    rgb.iB *= contrast;
    
    rgb.iR /= 65536;
    rgb.iG /= 65536;
    rgb.iB /= 65536;

    rgb.iR += 15;
    rgb.iG += 31;
    rgb.iB += 15;
    */

    // Apply brightness, -40 in a range of -100..100 for
    // 0..255 rgb values, which corresponds to -5 for 5 bit
    // and -10 for 6 bit rgb values.
    rgb.iR -= 5;
    rgb.iG -= 10;
    rgb.iB -= 5;

    if ( rgb.iR < 0 ) rgb.iR = 0;
    if ( rgb.iG < 0 ) rgb.iG = 0;
    if ( rgb.iB < 0 ) rgb.iB = 0;
    
    if ( rgb.iR > 31 ) rgb.iR = 31;
    if ( rgb.iG > 63 ) rgb.iG = 63;
    if ( rgb.iB > 31 ) rgb.iB = 31;

    *aPixelData =
        ( rgb.iB | ( rgb.iG << 5 ) | ( rgb.iR << 11 ) );
    }
    
TInt TBitmapFx::HueToRGB( TInt v1, TInt v2, TInt aH )
    {
    while ( aH < 0 )
        {
        aH += 0xFF00;
        }
        
    while ( aH >= 0xFF00 )
        {
        aH -= 0xFF00;
        }
        
    if ( ( ( 6 * aH ) ) < 0xFF00 )
        {
        return v1 + ( ( v2 - v1 ) * ( ( 6 * aH ) >> KPrecision ) >> KPrecision );
        }

    if ( ( ( 2 * aH ) ) < 0xFF00 )
        {
        return v2;
        }

    if ( ( ( 3 * aH ) ) < 0x1FE00 )
        {
        return v1 + ( ( v2 - v1 ) * ( ( ( 0xA9FF - aH ) * 6 ) >> KPrecision ) >> KPrecision );
        }
    
    return v1;
    }