Skins API: Using Skins API

Enabling skin support in an application

Generally, if the entire layout area (i.e. status pane, control pane, main pane or pop-up window) is drawn by a single AVKON control, which already provides the necessary parameters, there is no need for significant application changes at all. Always enable skins in application level. This can be done either application-wide or on a component-by-component basis:

void CMyAppUi::ConstructL()
    {
    // Enables skins in all the optionally skin-providing controls in this application
    BaseConstructL( EAknEnableSkin );
    // …
    }

It is also possible to enable skins for a skin providing control, but not all controls supports this method.

void CMyContainer::ConstructL()
    {
    // …
    // Enables skin for control
    iSomeOptSkinAwareCtrl->SetSkinEnabledL( ETrue );
    // …
    }

Accessing application skin instance

The skins enabled S60 application framework constructs a singleton object called a skin instance for every application. It performs several fundamental operations related to skin support.

Firstly, the skin instance performs skin item lookup and data construction. This involves querying the item definition from Skins Server and using the item data factory to construct the item data object.

Secondly, the skin instance maintains the item data cache. If the caller requests a cached item data object, it is stored in the cache and any skin change triggers automatic reconstruction.

Thirdly, local item definitions are managed by the skin instance. An application may set local item definitions that are visible only within its own thread.

In this example, application supports skins, and a pointer to the application’s skin instance is requested.

void CMyControl::ConstructL()
    {
    // …
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    // …
    }

Providing control context and drawing background

AknsDrawUtils provides methods to draw a background bitmap for UI controls. If the application is non-skin-aware (or the control context specifies that no bitmap can be used), these methods clear the area without any bitmap..

The container may optionally provide a data context to ensure that skin items reserved by it and its child controls are released properly when the container goes out of scope.

To provide data context, the container must override the MopSupplyObject method and own an object implementing the data context interface.

class CMyContainer : public CCoeControl
     {
     //…
     /**
     * Pass skin information if needed.
     */
     TTypeUid::Ptr MopSupplyObject(TTypeUid aId);

public:
     CAknsBasicBackgroundControlContext* iBackground;    
     //…
    };

Creates the control context with a defined background ID.

void CMyContainer::ConstructL(const TRect& aRect )
    {
    //…
    TRect rect(0, 0, 0, 0); 
    // Temporary rect is passed. Correct rect is set in SizeChanged.
    // Create the new context with image: KAknsIIDQsnBgAreaMain, and parent absolute layout is not used.
    iBackground = CAknsBasicBackgroundControlContext::NewL(KAknsIIDQsnBgAreaMain, rect, EFalse );
    //…
    SetRect(aRect);    
    ActivateL();
    }

Modifies the container’s Draw() method to draw the background.

void CMyContainer::Draw( )
    {
    //…
    // Drawing skin
    if ( iBackground )
        {
        MAknsSkinInstance* skin = AknsUtils::SkinInstance();        
        if ( !AknsDrawUtils::Background( skin, iBackground, this, gc, rect) )
             {
             // The background was not drawn….
             }
        }
    //…
    }

Updates the position in container’s SizeChanged() method.

void CMyContainer::SizeChanged()
    {
    //…
    if ( iBackground )
        {
        iBackground->SetRect(Rect());
        }
    //…    
    }

MopSupplyObject must provide a pointer to the control context, in this example the CAknsBasicBackgroundControlContext instance.

TTypeUid::Ptr CMyContainer::MopSupplyObject(TTypeUid aId)
    {
    if (aId.iUid == MAknsControlContext::ETypeId && iBackground)
        {
        return MAknsControlContext::SupplyMopObject(aId, iBackground);
        }

    return CCoeControl::MopSupplyObject(aId);
    }

Accessing item data objects

Skin item data is constructed and cached if necessary, based on the item definition available from the local definition list or, if not found there, the shared memory chunk lookup provided by AVKON Skins Server. A pointer to the cached item data object is returned to the caller.

In this example scrollbar's top background skin element is accessed. The returned CAknsItemData pointer can be casted for example to pointer CAknsMaskedBitmapItemData in order to get access to the bitmap objects themselves.

class CMyContainer : public CCoeControl
    {
    // …
    CAknsItemData* iItemData;
    // …
    }

Accesses the bitmap in skin item data.

// Gets skin item
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
iItemData = skin->CreateUncachedItemDataL( KAknsIIDQsnCpScrollBgTop );

if ( iItemData )
     {
     // Accesses bitmap objectin skin item
     CAknsBitmapItemData* bitmapContex=(CAknsBitmapItemData*)iItemData;
     CFbsBitmap* bitmap = bitmapContex->Bitmap();
     }

In the case of a bitmap item, the same can be performed with much less code by using AknsUtils::CreateBitmapL.

MAknsSkinInstance* skin = AknsUtils::SkinInstance();
if( skin )
     {
     iBmp = AknsUtils::CreateBitmapL( KAknsIIDQsnCpScrollBgTop );
     }

Accessing cached item data objects

Utility methods should be used to facilitate, for example, fetching bitmap type skin item data.

void CMyControl::Draw(const TRect& aRect) const
    {
    // …
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    CFbsBitmap* bitmap = AknsUtils::GetCachedBitmap( skin, KAknsIIDQsnBgAreaMain );
    if( bitmap )
        {
        // Draw the bitmap.
        }
    else
        {
        // Not found or an error occurred. Draw without the bitmap.
        }
     // …
    }

Skin items of the image type (such as bitmaps) can also be drawn directly using the AknsDrawUtils::DrawCachedImage method.

void CMyControl::Draw(const TRect& aRect) const
    {
    // …
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    AknsDrawUtils::DrawCachedImage( skin, gc, rect, KAknsIIDQsnBgAreaMain );
    // …
   }

Setting idle state wallpaper

AknsWallpaperUtils::SetIdleWallpaper() changes the actual idle state wallpaper. If KNullDesC is set as a wallpaper file name, the method removes the current wallpaper.

_LIT( KWallpaperFile,"c:\\wallpaperimage.jpg" );
User::LeaveIfError( AknsWallpaperUtils::SetIdleWallpaper( KWallpaperFilename, NULL ) );

Using other skin utilities

Creates an independent copy by the given item ID, and creates a CGulIcon object. AknIconUtils::SetSize() must be called before drawing the bitmap.

CGulIcon* newIcon;
CFbsBitmap *newIconBmp;
CFbsBitmap *newIconMaskBmp;

MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::CreateIconL( skin, KMyBmpIID, newIconBmp, newIconMaskBmp, iconFile, iconIndex, iconMaskIndex );    
newIcon = CGulIcon::NewL( newIconBmp, newIconMaskBmp);

A faster method to create a CGulIcon object.

CGulIcon* newIcon;

MAknsSkinInstance* skin = AknsUtils::SkinInstance();
newIcon = AknsUtils:: CreateGulIconL( skin, KMyBmpIID, iconFile, iconIndex, iconMaskIndex );

Gets an application icon supporting scalable graphics. This example gets the icon of the calculator application.

CFbsBitmap* bitmap;
CFbsBitmap* mask;

AknsUtils::CreateAppIconLC(skin, TUid::Uid(0x01FEDCBA), EAknsAppIconTypeContext, bitmap, mask);

// CreateAppIconLC puts both bitmap to stack
CleanupStack::Pop(); // bitmap
CleanupStack::Pop(); // mask

// Sets the size of the bitmap before displaying
TSize size( 100, 100 );
AknIconUtils::SetSize( bitmap, size );

This utility method creates an independent (in terms of instance ownership) copy of a masked bitmap by the given item ID and applies color-based skinning to it.

CFbsBitmap* bitmap;
CFbsBitmap* mask;

MAknsSkinInstance* skin = AknsUtils::SkinInstance();

AknsUtils::CreateColorIconL( skin, KMyBmpID, KAknsIIDQsnComponentColors, EAknsCIQsnComponentColorsCG5, bitmap, mask, KAvkonBitmapFile, EMbmAvkonQgn_note_warning, EMbmAvkonQgn_note_warning_mask, KRgbBlack );

// Set the size of the bitmap before displaying
TSize size( 100, 100 );
AknIconUtils::SetSize( iBitmap, size );

This example gets the text color of the main area in the current skin context. Color groups and indexes can be found in the file AknsConstants.h.

MAknsSkinInstance* skin = AknsUtils::SkinInstance();
TRgb color;

AknsUtils::GetCachedColor( skin, color, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6 );

Error handling

Skins API uses standard Symbian OS error reporting mechanism. Possible panic circumstances and panic codes are indicated in class or method descriptions.

There are also API methods that cannot be allowed to leave, e.g. utility methods used during drawing operations. These methods either fail silently or return an error value as specified in their documentation in C++ header file comments.

Memory overhead

A skin instance object is allocated for every application thread. This causes minor heap consumption, estimated to be approximately 100 bytes per application thread. In addition, local item definitions and cached item data objects demand heap causing variable heap consumption depending on the size and number of objects allocated. The application should consider deleting bitmaps when no longer needed.

Limitations of the API

Skins API supports only S60 skins. If application needs skinning of its own bitmaps, it has to implement skinning. Local item definitions should not be used. Clients should not create instances of item data classes.


Copyright © Nokia Corporation 2001-2008
Back to top