/*
* Copyright (c) 2006-2007 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: Implementation of CHuiS60Skin. CHuiS60Skin is a HUITK skin
* that uses resources from the current S60 skin.
*
*/
#include "uiacceltk/HuiS60Skin.h" // Class definition
#include "uiacceltk/HuiStatic.h"
#include "HuiRenderPlugin.h"
#include "uiacceltk/HuiTextureManager.h"
#include "uiacceltk/HuiTexture.h"
#include "uiacceltk/HuiEnv.h"
#include "uiacceltk/HuiGc.h"
#include "uiacceltk/HuiUtil.h"
#include "uiacceltk/HuiDisplay.h"
#include <AknsDrawUtils.h>
#include <AknUtils.h>
#include "huiskinbackroundlayout.h"
struct TBackgroundTexture
{
TAknsItemID iID;
CHuiTexture* iBackgroundTexture; //not owned
};
struct TPrivData
{
RArray<TBackgroundTexture> iBackgrounds;
};
EXPORT_C CHuiS60Skin::CHuiS60Skin(CHuiEnv& aEnv)
: CHuiSkin(aEnv)
{
iSpare = NULL;
}
EXPORT_C void CHuiS60Skin::ConstructL()
{
iSkinControlContext = CAknsBasicBackgroundControlContext::NewL(
KAknsIIDQsnBgScreen, TRect(TPoint(0, 0), HuiUtil::ScreenSize()), ETrue);
iSpare = new (ELeave) TPrivData;
iSkinChanged = ETrue;
}
EXPORT_C CHuiS60Skin::~CHuiS60Skin()
{
FreeBackgrounds();
delete (TPrivData*)(iSpare);
delete iSkinControlContext;
delete iBackgroundTexture;
if (iSkinSrvConnected)
iSkinSrvSession.Close();
delete iBackgroundBitmap;
iCachedSkinItems.ResetAndDestroy();
iCachedSkinItems.Close();
}
EXPORT_C THuiSkinLocation CHuiS60Skin::Location(THuiSkinElement aElement)
{
// Changed so that correct cba location is asked from AknLayouUtils
switch(aElement)
{
case EHuiSkinElementSoftKeys:
{
THuiSkinLocation retValue;
AknLayoutUtils::TAknCbaLocation skLocation;
skLocation = (AknLayoutUtils::TAknCbaLocation)CHuiStatic::CbaLocation();
switch ( skLocation )
{
default:
// falltrough
case AknLayoutUtils::EAknCbaLocationBottom:
{
retValue = EHuiSkinLocationBottom;
break;
}
case AknLayoutUtils::EAknCbaLocationRight:
{
retValue = EHuiSkinLocationRight;
break;
}
case AknLayoutUtils::EAknCbaLocationLeft:
{
retValue = EHuiSkinLocationLeft;
break;
}
}
return retValue;
}
default:
{
return EHuiSkinLocationNone;
}
}
}
MAknsSkinInstance* CHuiS60Skin::SkinInstance() const
{
MAknsSkinInstance* skin = 0;
if ( CCoeEnv::Static())
{
skin = AknsUtils::SkinInstance();
if(!skin )
{
TRAP_IGNORE( AknsUtils::InitSkinSupportL() )
skin = AknsUtils::SkinInstance();
}
}
return skin;
}
void CHuiS60Skin::UpdateBackgroundL()
{
if(!iBackgroundTexture)
{
iBackgroundTexture = CreateSkinBackgroundL(KAknsIIDQsnBgScreen);
iBackgroundTexture->SetSkinContent(ETrue);
iBackgroundTexture->iContentObservers.AppendL(*this);
}
else if(iSkinChanged)
{
iBackgroundTexture->Reset();
delete iBackgroundBitmap;
iBackgroundBitmap = NULL;
iBackgroundBitmap = CHuiStatic::GetBgBitmapLC(KAknsIIDQsnBgScreen);
CleanupStack::Pop(iBackgroundBitmap);
// update iBackgroundRect as well
TRect dummy;
GetRectForItem(KAknsIIDQsnBgScreen, dummy, iBackgroundRect);
iBackgroundTexture->UploadL(*iBackgroundBitmap,NULL,EHuiTextureUploadFlagRetainResolution );
iBackgroundTexture->SetSkinContent(ETrue);
}
else
{
// there should be already up-to-date background texture
}
HUI_DEBUG1(_L("CHuiS60Skin::UpdateBackgroundL - Free memory at exit: %i"), HuiUtil::FreeMemory());
}
EXPORT_C void CHuiS60Skin::SkinContentChanged()
{
iSkinChanged = ETrue;
}
EXPORT_C void CHuiS60Skin::SkinConfigurationChanged(
const TAknsSkinStatusConfigurationChangeReason aReason )
{
}
EXPORT_C void CHuiS60Skin::SkinPackageChanged(
const TAknsSkinStatusPackageChangeReason aReason )
{
}
EXPORT_C const CHuiTexture& CHuiS60Skin::TextureL(TInt aSkinTextureId)
{
// Create S60 theme specific background texture
// If Bitgdi renderer is used, do not create a copy of background
// image, but return the default dummy texture.
if(aSkinTextureId == EHuiSkinBackgroundTexture &&
CHuiStatic::Renderer().Id () != EHuiRenderPluginBitgdi)
{
if(!iBackgroundTexture || iReloadBackground || iSkinChanged)
{
UpdateBackgroundL();
iReloadBackground = EFalse;
}
return *iBackgroundTexture;
}
// Otherwise use the default textures
return CHuiSkin::TextureL(aSkinTextureId);
}
EXPORT_C void CHuiS60Skin::ReleaseTexture(TInt aSkinTextureResource)
{
HUI_DEBUG(_L("CHuiS60Skin::ReleaseTexture() - Called."));
// Release background texture
if(aSkinTextureResource == EHuiSkinBackgroundTexture)
{
HUI_DEBUG(_L("CHuiS60Skin::ReleaseTexture() - Destroying background texture."));
delete iBackgroundTexture;
iBackgroundTexture = NULL;
}
else
{
// Otherwise use the default method
return CHuiSkin::ReleaseTexture(aSkinTextureResource);
}
}
EXPORT_C void CHuiS60Skin::NotifyDisplaySizeChangedL()
{
// The background is now different.
SkinContentChanged(); // for changing the iSkinChanged flag
Env().NotifySkinChangedL();
Env().TextStyleManager().NotifyDisplaySizeChangedL();
ReloadBgTexturesL();
iSkinChanged = EFalse;
}
EXPORT_C TRgb CHuiS60Skin::StyleTextColor(THuiPreconfiguredTextStyle aStyle,
THuiBackgroundType aBackgroundType) const
{
// Default text color depends directly on the background type.
TRgb defaultColor = (aBackgroundType == EHuiBackgroundTypeLight? KRgbBlack : KRgbWhite);
switch(aStyle)
{
default:
break;
case EHuiTextStyleSupplement:
return TRgb(128, 128, 128);
}
return defaultColor;
}
EXPORT_C void CHuiS60Skin::RestoreTextureContentL(CHuiTexture& aTexture)
{
if(&aTexture == iBackgroundTexture)
{
iReloadBackground = ETrue;
TextureL(EHuiSkinBackgroundTexture);
}
else
{
CHuiSkin::RestoreTextureContentL(aTexture);
}
}
EXPORT_C void CHuiS60Skin::SkinExtension(const TUid& aExtensionUid, TAny** aExtensionParameters)
{
CHuiSkin::SkinExtension(aExtensionUid,aExtensionParameters);
}
EXPORT_C THuiSkinOrientation CHuiS60Skin::Orientation() const
{
return CHuiSkin::Orientation();
}
EXPORT_C void CHuiS60Skin::SetContext(CHuiGc& aGc)
{
CHuiSkin::SetContext(aGc);
}
EXPORT_C CHuiGc& CHuiS60Skin::Context() const
{
return CHuiSkin::Context();
}
EXPORT_C TInt CHuiS60Skin::GetTexture(TInt aSkinTextureResource, const CHuiTexture*& aOutTexture)
{
return CHuiSkin::GetTexture(aSkinTextureResource, aOutTexture);
}
void CHuiS60Skin::FreeBackgrounds()
{
if (CHuiStatic::Renderer().Id () == EHuiRenderPluginBitgdi)
{
// no need to render the skin backgrounds separately on shitgdi
return;
}
if (!iSpare)
{
return;
}
TBackgroundTexture bgTexture;
TInt itemCount = ((TPrivData*)(iSpare))->iBackgrounds.Count();
for (TInt index = 0; index < itemCount; index++)
{
bgTexture = ((TPrivData*)(iSpare))->iBackgrounds[index];
delete bgTexture.iBackgroundTexture;
bgTexture.iBackgroundTexture = NULL;
}
((TPrivData*)(iSpare))->iBackgrounds.Reset();
iCachedSkinItems.ResetAndDestroy(); // reset cached bg images & rects
}
CHuiTexture* CHuiS60Skin::CreateSkinBackgroundL(const TAknsItemID& aID)
{
// Update the background image.
if (!iSkinSrvConnected)
{
User::LeaveIfError(iSkinSrvSession.Connect(this));
iSkinSrvConnected = ETrue;
}
MAknsSkinInstance* skin = SkinInstance();
CHuiTexture* texture = CHuiTexture::NewL();
CleanupStack::PushL(texture);
if (skin)
{
TRect skinrect;
TRect dummy;
GetRectForItem(aID, dummy, skinrect);
CFbsBitmap* bitmap = new (ELeave) CFbsBitmap();
CleanupStack::PushL(bitmap);
User::LeaveIfError( bitmap->Create(skinrect.Size(), EColor64K) );
CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(bitmap);
CleanupStack::PushL(device);
CFbsBitGc* gc = 0;
User::LeaveIfError( device->CreateContext(gc) );
CleanupStack::PushL(gc);
iSkinControlContext->SetRect(skinrect);
iSkinControlContext->SetBitmap(aID);
AknsDrawUtils::DrawBackground(skin, iSkinControlContext, NULL, *gc, TPoint(0,0), skinrect,
KAknsDrawParamDefault);
CleanupStack::PopAndDestroy(gc);
CleanupStack::PopAndDestroy(device);
texture->UploadL(*bitmap,NULL,EHuiTextureUploadFlagRetainResolution );
CleanupStack::PopAndDestroy(bitmap);
}
else
{
CFbsBitmap* bitmap = SearchCachedSkinItemBitmap(aID);
if(iSkinChanged || !bitmap)
{
TRect skinrect;
TRect dummy;
GetRectForItem(aID, dummy, skinrect);
if( aID == KAknsIIDQsnBgScreen) // handle normal background id differently
{
delete iBackgroundBitmap;
iBackgroundBitmap = NULL;
bitmap = CHuiStatic::GetBgBitmapLC(aID);
CleanupStack::Pop(bitmap);
iBackgroundBitmap = bitmap;
iBackgroundRect = skinrect;
}
else // others are cached in skin item array
{
bitmap = CHuiStatic::GetBgBitmapLC(aID);
TInt index = SearchCachedSkinItemIndex(aID);
if( index == KErrNotFound ) // add new
{
CSkinItem* newSkinItem = new (ELeave) CHuiS60Skin::CSkinItem();
CleanupStack::PushL(newSkinItem);
newSkinItem->iId = aID;
newSkinItem->iSkinRect = skinrect;
newSkinItem->iBitmap = bitmap;
User::LeaveIfError(iCachedSkinItems.Append(newSkinItem));
CleanupStack::Pop(newSkinItem);
}
else // modify existing
{
iCachedSkinItems[index]->iSkinRect = skinrect;
delete iCachedSkinItems[index]->iBitmap;
iCachedSkinItems[index]->iBitmap = NULL;
iCachedSkinItems[index]->iBitmap = bitmap;
}
CleanupStack::Pop(bitmap);
}
}
texture->UploadL(*bitmap,NULL,EHuiTextureUploadFlagRetainResolution );
}
CleanupStack::Pop(texture);
return texture;
}
void CHuiS60Skin::ReloadBgTexturesL()
{
if (CHuiStatic::Renderer().Id () == EHuiRenderPluginBitgdi )
{
// no need to render the skin backgrounds separately on bitgdi
return;
}
iCachedSkinItems.ResetAndDestroy(); // reset cached bg images & rects
TBackgroundTexture bgTexture;
TInt itemCount = ((TPrivData*)(iSpare))->iBackgrounds.Count();
for (TInt index = 0; index < itemCount; index++)
{
bgTexture = ((TPrivData*)(iSpare))->iBackgrounds[index];
delete bgTexture.iBackgroundTexture;
bgTexture.iBackgroundTexture = CreateSkinBackgroundL(bgTexture.iID);
((TPrivData*)(iSpare))->iBackgrounds[index] = bgTexture;
}
}
void CHuiS60Skin::UpdateBackgroundsL(const RArray<THuiDisplayBackgroundItem>& aItems)
{
if (CHuiStatic::Renderer().Id () == EHuiRenderPluginBitgdi)
{
// no need to render the skin backgrounds separately on shitgdi
return;
}
FreeBackgrounds();
THuiDisplayBackgroundItem bgItem;
TBackgroundTexture bgTexture;
for (TInt index = 0; index < aItems.Count(); index++)
{
bgItem = aItems[index];
if (bgItem.ClearMode() == CHuiDisplay::EClearWithSkinBackground)
{
bgTexture.iID = bgItem.SkinBackground();
bgTexture.iBackgroundTexture = CreateSkinBackgroundL(bgItem.SkinBackground());
((TPrivData*)(iSpare))->iBackgrounds.Append(bgTexture);
}
}
}
EXPORT_C CHuiTexture* CHuiS60Skin::BackgroundTexture(const TAknsItemID& aID)
{
if (CHuiStatic::Renderer().Id () == EHuiRenderPluginBitgdi)
{
// only opengl has separate skin bg textures.
return NULL;
}
if (!iSpare)
{
return NULL;
}
TBackgroundTexture bgTexture;
TInt itemCount = ((TPrivData*)(iSpare))->iBackgrounds.Count();
for (TInt index = 0; index < itemCount; index++)
{
bgTexture = ((TPrivData*)(iSpare))->iBackgrounds[index];
if (bgTexture.iID == aID)
{
return bgTexture.iBackgroundTexture;
}
}
return NULL;
}
TInt CHuiS60Skin::SearchCachedSkinItemIndex(const TAknsItemID& aId)
{
TInt cacheditemsCount = iCachedSkinItems.Count();
for(TInt i = 0; i < cacheditemsCount; i++ )
{
if( iCachedSkinItems[i]->iId == aId )
{
return i;
}
}
HUI_DEBUG2(_L("CHuiS60Skin::SeachCachedSkinItemIndex - cached TAknsItemID %i %i (iMajor, iMinor) not found"), aId.iMajor, aId.iMinor );
return KErrNotFound;
}
TRect CHuiS60Skin::SearchCachedSkinItemRect(const TAknsItemID& aId)
{
TRect returnRect = TRect();
if(aId == KAknsIIDQsnBgScreen)
{
returnRect = iBackgroundRect;
}
else
{
TInt index = SearchCachedSkinItemIndex(aId);
if(index != KErrNotFound )
{
returnRect = iCachedSkinItems[index]->iSkinRect;
}
}
return returnRect;
}
CFbsBitmap* CHuiS60Skin::SearchCachedSkinItemBitmap(const TAknsItemID& aId)
{
CFbsBitmap* bitmap = NULL;
if(aId == KAknsIIDQsnBgScreen)
{
bitmap = iBackgroundBitmap;
}
else
{
TInt index = SearchCachedSkinItemIndex(aId);
if(index != KErrNotFound )
{
bitmap = iCachedSkinItems[index]->iBitmap;
}
}
return bitmap;
}
TRect CHuiS60Skin::SkinRect(const TAknsItemID& aID)
{
return SearchCachedSkinItemRect(aID);
}