diff -r fcdfafb36fe7 -r aecbbf00d063 uifw/EikStd/coctlsrc/AknDoubleSpanScrollIndicator.cpp --- a/uifw/EikStd/coctlsrc/AknDoubleSpanScrollIndicator.cpp Thu Aug 19 10:11:06 2010 +0300 +++ b/uifw/EikStd/coctlsrc/AknDoubleSpanScrollIndicator.cpp Tue Aug 31 15:28:30 2010 +0300 @@ -29,6 +29,11 @@ #include #include #include +// 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) { @@ -41,7 +46,7 @@ CAknDoubleSpanScrollIndicator::CAknDoubleSpanScrollIndicator() : iOwnsWindow(EFalse), iTransparentBackground(EFalse), iDrawBackground(ETrue), - iBackgroundHighlight(EFalse) + iBackgroundHighlight(EFalse),iDrawBackgroundBitmap(EFalse) { AKNTASHOOK_ADD( this, "CAknDoubleSpanScrollIndicator" ); } @@ -69,8 +74,8 @@ void CAknDoubleSpanScrollIndicator::Draw(const TRect& /*aRect*/) const { CWindowGc& gc = SystemGc(); - if( iDrawBackground || iForceDrawBackground ) + if(iDrawBackground) { DrawBackground(); } @@ -93,13 +98,13 @@ DrawTiled(gc, iHandleRect, handleBar); } - void CAknDoubleSpanScrollIndicator::UpdateScrollBarLayout() { iHeadItemSize = 12; + iMidItemSize = 12 * 5; iTailItemSize = 12; - TRect rect( Rect() ); + TRect rect = Rect(); if(rect.IsEmpty()) { return; @@ -114,13 +119,18 @@ TAknLayoutRect layRect; TAknWindowComponentLayout layout = AknLayoutScalable_Avkon::scroll_bg_pane_g1( varietyIndex ); //top layRect.LayoutRect( rect, layout.LayoutLine() ); - TSize newSize( layRect.Rect().Size() ); + 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( @@ -150,7 +160,7 @@ midRect.iTl.iY += headRect.Height(); midRect.iBr.iY -= tailRect.Height(); midDrawLength = midRect.Height(); - midSize.SetSize(midRect.Width(), midDrawLength); + midSize.SetSize(midRect.Width(), iMidItemSize); } else { @@ -160,7 +170,7 @@ midRect.iTl.iX += iHeadItemSize; midRect.iBr.iX -= iTailItemSize; midDrawLength = midRect.Width(); - midSize.SetSize(midDrawLength, midRect.Height()); + midSize.SetSize(iMidItemSize, midRect.Height()); } MAknsSkinInstance* skin = AknsUtils::SkinInstance(); @@ -170,20 +180,28 @@ 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(headRect.Size()), mask, ETrue); + 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(bmp->SizeInPixels()); + 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(tailRect.Size()), mask, ETrue); + aGc.BitBltMasked(tailRect.iTl, bmp, TRect(TPoint(0, 0), tailRect.Size()), mask, ETrue); } void CAknDoubleSpanScrollIndicator::CalculateRects() @@ -205,29 +223,11 @@ checkedFieldPosition, checkedFieldSize); - TBool wasEmpty = iBackgroundRect.IsEmpty(); - TBool isEmpty = EFalse; - // If span (max number of items) is zero, then draw only the background - if ( checkedScrollSpan == 0 || ( checkedScrollSpan <= checkedWindowSize ) ) + if (checkedScrollSpan == 0) { - iBackgroundRect = TRect( 0, 0, 0, 0 ); iHandleBackgroundRect = TRect(0,0,0,0); iHandleRect = TRect(0,0,0,0); - iForceDrawBackground = ETrue; // to enable background drawing - isEmpty = ETrue; - } - else - { - iForceDrawBackground = EFalse; - } - if ( wasEmpty != isEmpty || iForceDrawBackground ) - { - DrawDeferred(); - } - - if ( isEmpty ) - { return; } @@ -245,9 +245,21 @@ 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, - iHandleMinSize ); + HandleBackgroundMinSizeInPixels() ); TInt roomForMovementInSpan = checkedScrollSpan - checkedWindowSize; TInt roomForMovementInPixels = @@ -264,25 +276,28 @@ // If window would cover whole scrollbar, then modify // it to leave the thumb little short from bottom - TInt scrollBarHandleMaxSizeInPixels = iHandleMaxSize; - + TInt scrollBarHandleMaxSizeInPixels = ScrollHandleMaxVisibleSizeInPixels(); if (windowSizeInPixels >= scrollBarHeightInPixels) { windowSizeInPixels = scrollBarHandleMaxSizeInPixels; } TBool doubleSpanInUse = (checkedFieldPosition >= 0) && (checkedFieldSize > 0); - TInt minHandleBackgroundSize = iHandleMinSize; + TInt minHandleBackgroundSize = 0; TInt fieldSizeInPixels = 0; // sub field size TInt fieldPositionInPixels = 0; - TInt handleMinSize = iHandleMinSize; - 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)) { @@ -468,11 +483,15 @@ { iOldRect = rect; AknsUtils::RegisterControlPosition( this ); - iHandleMinSize = HandleMinSizeInPixels(); - iHandleMaxSize = HandleMaxSizeInPixels(); CalculateRects(); + + if (iOwnsWindow) + { + TRAP_IGNORE(CreateBackgroundBitmapL()); + } + UpdateScrollBarLayout(); - + if (IsVisible() & iOwnsWindow) DrawDeferred(); } @@ -493,9 +512,14 @@ iWindowSize = aWindowSize; iFieldPosition = aFieldPosition; iFieldSize = aFieldSize; - + // Calculate the sizes for graphics CalculateRects(); + if( iWindowSize > 0 ) + { + // layout handle graphics + LayoutHandleGraphics(); + } } TInt CAknDoubleSpanScrollIndicator::ScrollSpan() @@ -535,7 +559,11 @@ void CAknDoubleSpanScrollIndicator::HandleResourceChange(TInt aType) { - if ( aType == KAknMessageFocusLost || KEikMessageUnfadeWindows == aType ) + if ( aType == KAknsMessageSkinChange ) + { + iDrawBackgroundBitmap = ETrue; + } + else if( aType == KAknMessageFocusLost || KEikMessageUnfadeWindows == aType) { if( HandleHighlight() ) { @@ -650,10 +678,9 @@ return layRect.Rect().Width(); } - -TInt CAknDoubleSpanScrollIndicator::HandleMaxSizeInPixels() +TInt CAknDoubleSpanScrollIndicator::ScrollHandleMaxVisibleSizeInPixels() { - TRect scbRect( Rect() ); + TRect scbRect = Rect(); if ( iOrientation == CEikScrollBar::EHorizontal ) scbRect.SetRect(scbRect.iTl, TSize(scbRect.Height(), scbRect.Width())); @@ -663,6 +690,10 @@ return layRect.Rect().Height(); } +TInt CAknDoubleSpanScrollIndicator::HandleBackgroundMinSizeInPixels() + { + return HandleMinSizeInPixels(); + } TInt CAknDoubleSpanScrollIndicator::HandleMinSizeInPixels() { @@ -695,12 +726,17 @@ return iDrawBackground; } +// Prepares background for window-owning scrollbar +void CAknDoubleSpanScrollIndicator::CreateBackgroundBitmapL() + { + + } void CAknDoubleSpanScrollIndicator::DrawBackground() const { CWindowGc& gc=SystemGc(); - TPoint pos( Position() ); - TRect rect( Rect() ); + TPoint pos = Position(); + TRect rect = Rect(); MAknsSkinInstance* skin = AknsUtils::SkinInstance(); MAknsControlContext* cc = AknsDrawUtils::ControlContext( this ); @@ -713,19 +749,87 @@ // 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 - - AknsDrawUtils::DrawBackground( skin, cc, NULL, gc, - rect.iTl, bmpRect, KAknsDrawParamNoClearUnderImage ); + 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 { - AknsDrawUtils::Background( skin, cc, this, gc, rect, - KAknsDrawParamNoClearUnderImage ); + 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() { @@ -764,15 +868,261 @@ 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; + } +