uifw/EikStd/coctlsrc/AknDoubleSpanScrollIndicator.cpp
changeset 0 2f259fa3e83a
child 4 8ca85d2f0db7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/EikStd/coctlsrc/AknDoubleSpanScrollIndicator.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,1128 @@
+/*
+* 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;
+    }
+