diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/src/akntabgrp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/AvKon/src/akntabgrp.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,4460 @@ +/* +* Copyright (c) 2002-2008 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 for tab navigation control. +* +*/ + + +// SYSTEM INCLUDE FILES +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// USER INCLUDE FILES +#include "aknappui.h" +#include "avkon.hrh" +#include "AknNaviObserver.h" +#include "AknPanic.h" +#include "akntabgrp.h" +#include "AknTabObserver.h" +#include "aknenv.h" +#include "AknBitmapMirrorUtils.h" +#include "AknTabGrpGraphics.h" +#include "aknnavide.h" +#include "AknNaviDecoratorObserver.h" + +// GLOBAL CONSTANTS + +const TInt KTabArrayGranularity = 4; +const TInt KAknTabGroupNoTabs = KErrNotFound; +const TInt KTabColorBitmapQueueGranularity = 2; +const TInt KTabColorBitmapActiveColorIndex = 0; +const TInt KTabColorBitmapPassiveColorIndex = 1; + +/** Maximum number of tabs that can be shown in the tab group at a time. */ +const TInt KMaxNumberOfVisibleTabs = 4; + +/** Maximum number of frames in the tab group animations. */ +const TInt KMaxAmountOfAnimationEvents = 80; + +/** Interval used between the frames in tab group animations. */ +const TInt KAnimationEventInterval = 25000; // 40 events/s + +/** Speed value for the layout switch animation, smaller value is faster. */ +const TInt KLayoutSwitchAnimationSpeed = 25; + +/** Minimum horizontal step size value for the tab cycle animation. */ +const TInt KMinimumCycleAnimationStepSize = 3; + +/** Tolerance used for pointer event position's x-value in tab navigation. */ +const TInt KDragNavigationTolerance = 5; + +// +// Extension to CAknTab +// + +NONSHARABLE_CLASS( CAknTabExtension ) : public CBase + { +public: + static CAknTabExtension* NewL(); + ~CAknTabExtension(); + +private: + CAknTabExtension(); + +public: + + /** Indicates whether or not the tab is shown in narrow tab group layout. */ + TBool iNarrowTabLayout; + + /** Total amount of tab in the tab group, needed to decide right layoutlines. */ + TInt iNumberOfTabsInTabGroup; + + /** Indicates whether or not this tab is drawn using multi-color mode. */ + TBool iMultiColorMode; + + /** Indicates whether or not the tab is shown in long tab group layout. */ + TBool iLongTab; + }; + +CAknTabExtension* CAknTabExtension::NewL() + { + CAknTabExtension* self = new ( ELeave ) CAknTabExtension(); + return self; + } + + +CAknTabExtension::CAknTabExtension() + { + } + +CAknTabExtension::~CAknTabExtension() + { + } + +// +// CAknTab +// + +CAknTab::~CAknTab() + { + AKNTASHOOK_REMOVE(); + delete iLabel; + delete iBitmap; + delete iBitmapMask; + + if ( iColorBitmaps ) + { + iColorBitmaps->ResetAndDestroy(); + delete iColorBitmaps; + iColorBitmaps = NULL; + } + + delete iExtension; + } + +CAknTab* CAknTab::NewL( const CCoeControl& aParent, TResourceReader& aReader ) + { + CAknTab* self = CAknTab::NewLC( aParent, aReader ); + CleanupStack::Pop( self ); + return self; + } + +CAknTab* CAknTab::NewLC( const CCoeControl& aParent, TResourceReader& aReader ) + { + CAknTab* self = new (ELeave) CAknTab( 0 ); // default tab id + CleanupStack::PushL( self ); + self->SetContainerWindowL( aParent ); + self->ConstructFromResourceL( aReader ); + AKNTASHOOK_ADDL( self, "CAknTab" ); + return self; + } + +CAknTab* CAknTab::NewL( TInt aId, + const CCoeControl& aParent, + const TDesC& aTabText ) + { + CAknTab* self = CAknTab::NewLC( aId, aParent, aTabText ); + CleanupStack::Pop( self ); + return self; + } + +CAknTab* CAknTab::NewLC( TInt aId, + const CCoeControl& aParent, + const TDesC& aTabText ) + { + CAknTab* self = new (ELeave) CAknTab( aId ); + CleanupStack::PushL( self ); + self->SetContainerWindowL( aParent ); + self->ConstructL( aTabText ); + AKNTASHOOK_ADDL( self, "CAknTab" ); + return self; + } + +CAknTab* CAknTab::NewL( TInt aId, + const CCoeControl& aParent, + const TDesC& aTabText, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + CAknTab* self = CAknTab::NewLC( aId, aParent, aTabText, aTabBitmap, aMask ); + CleanupStack::Pop( self ); + return self; + } + +CAknTab* CAknTab::NewLC( TInt aId, + const CCoeControl& aParent, + const TDesC& aTabText, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + CAknTab* self = new (ELeave) CAknTab( aId ); + CleanupStack::PushL( self ); + self->SetContainerWindowL( aParent ); + self->ConstructL( aTabText ); + self->ConstructL( aTabBitmap, aMask ); + AKNTASHOOK_ADDL( self, "CAknTab" ); + return self; + } + +CAknTab* CAknTab::NewL( TInt aId, + const CCoeControl& aParent, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + CAknTab* self = CAknTab::NewLC( aId, aParent, aTabBitmap, aMask ); + CleanupStack::Pop( self ); + return self; + } + +CAknTab* CAknTab::NewLC( TInt aId, + const CCoeControl& aParent, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + CAknTab* self = new (ELeave) CAknTab( aId ); + CleanupStack::PushL( self ); + self->SetContainerWindowL( aParent ); + self->ConstructL( aTabBitmap, aMask ); + AKNTASHOOK_ADDL( self, "CAknTab" ); + return self; + } + +CAknTab::CAknTab( TInt aId ) : iId( aId ) + { + } + +void CAknTab::ConstructFromResourceL( TResourceReader& aReader ) + { + if ( !iExtension ) + { + iExtension = CAknTabExtension::NewL(); + } + + iId = aReader.ReadInt16(); // tab id + + HBufC* txt = aReader.ReadHBufCL(); // tab text + if ( txt ) + { + CleanupStack::PushL( txt ); + ConstructL( *txt ); + CleanupStack::PopAndDestroy( txt ); + } + + HBufC* bitmapFile = aReader.ReadHBufCL(); // bmp filename + TInt bitmapId = aReader.ReadInt16(); // bmp id + TInt maskId = aReader.ReadInt16(); // bmp mask id + + if ( bitmapFile ) + { + CleanupStack::PushL( bitmapFile ); + TFileName fileName( *bitmapFile ); + CompleteWithAppPath( fileName ); + if ( bitmapId != KErrNotFound ) + { + CFbsBitmap* bitmap; + if ( maskId != KErrNotFound ) + { + CFbsBitmap* mask; + AknIconUtils::CreateIconLC( bitmap, + mask, + fileName, + bitmapId, + maskId ); + CleanupStack::Pop( mask ); + CleanupStack::Pop( bitmap ); + // moves ownership of bitmap and mask at beginning => + // no need to have bitmap/mask in cleanupstack + ConstructL( bitmap, mask ); + } + else + { + bitmap = AknIconUtils::CreateIconL( fileName, bitmapId ); + // moves ownership of bitmap and mask at beginning => + // no need to have bitmap/mask in cleanupstack + ConstructL( bitmap ); + } + } + CleanupStack::PopAndDestroy( bitmapFile ); // bitmapFile + } + + LoadColorBitmapL(); + } + +void CAknTab::ConstructL( const TDesC& aTabText ) + { + if ( !iExtension ) + { + iExtension = CAknTabExtension::NewL(); + } + + iLabel = new (ELeave) CEikLabel; + iLabel->SetContainerWindowL( *this ); + iLabel->SetTextL( aTabText ); + iLabel->SetAlignment( EHCenterVCenter ); + iLabel->SetAllMarginsTo( KNaviTabMargins ); + + if ( AknLayoutUtils::Variant() == EEuropeanVariant ) + { + iLabel->SetFont( LatinBold12() ); + } + else // APAC + { + iLabel->SetFont( ApacPlain12() ); + } + + LoadColorBitmapL(); + } + +void CAknTab::ConstructL( const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + if ( !iExtension ) + { + iExtension = CAknTabExtension::NewL(); + } + + iBitmap = aTabBitmap; + iBitmapMask = aMask; + LoadColorBitmapL(); + } + +void CAknTab::ReplaceTextL( const TDesC& aTabText ) + { + if ( iLabel ) + { + iLabel->SetTextL( aTabText ); + } + } + +void CAknTab::SetActive( TBool aActive, TDrawNow aDrawNow ) + { + iActive = aActive; + + if ( aDrawNow == EDrawNow ) + { + DrawNow(); + } + } + +TBool CAknTab::Active() const + { + return iActive; + } + + +TInt CAknTab::Id() const + { + return iId; + } + + +enum CAknTab::TAknTabDataType CAknTab::TabType() const + { + TAknTabDataType tabType( EAknTabNone ); + + if ( iLabel && iBitmap ) + { + tabType = EAknTabTextAndIcon; + } + else if ( iBitmap ) + { + tabType = EAknTabIcon; + } + else if ( iLabel ) + { + tabType = EAknTabText; + } + + return tabType; + } + + +TSize CAknTab::MinimumSize() + { + TSize minSize; + + if ( iLabel ) + { + minSize += iLabel->MinimumSize(); + } + if ( iBitmap ) + { + minSize += iBitmap->SizeInPixels(); + } + + return minSize; + } + + +void CAknTab::SetDimmed( TBool aDimmed ) + { + CCoeControl::SetDimmed( aDimmed ); + + if ( iLabel ) + { + iLabel->SetDimmed( aDimmed ); + } + } + + +void CAknTab::GetColorUseListL( CArrayFix& aColorUseList ) const + { + TCoeColorUse colorUse; + colorUse.SetLogicalColor( EColorDialogBackground ); + colorUse.SetUse( TCoeColorUse::EBack | + TCoeColorUse::ESurrounds | + TCoeColorUse::EActive | + TCoeColorUse::ENormal | + TCoeColorUse::ENeutral ); + aColorUseList.AppendL( colorUse ); + } + + +void CAknTab::SizeChanged() + { + if ( AknStatuspaneUtils::FlatLayoutActive() && + !iExtension->iNarrowTabLayout ) + { + SizeChangedInFlatLayout(); + } + else if ( iExtension->iNarrowTabLayout ) + { + SizeChangedInNarrowLayout(); + } + else + { + SizeChangedInNormalLayout(); + } + } + + +void CAknTab::SizeChangedInNormalLayout() + { + if ( !iColorBitmaps ) + { + TRAP_IGNORE( LoadColorBitmapL() ); + } + + TBool landscape( Layout_Meta_Data::IsLandscapeOrientation() ); + TBool staconPaneActive( AknStatuspaneUtils::StaconPaneActive() ); + TBool longTab( iExtension && iExtension->iLongTab ); + TRect rect( Rect() ); + + if ( iLabel && iBitmap ) + { + iBitmapRect.LayoutRect( + rect, + AknLayoutScalable_Avkon::navi_navi_icon_text_pane_g1() ); + AknIconUtils::SetSize( const_cast ( iBitmap ), + iBitmapRect.Rect().Size() ); + + AknLayoutUtils::LayoutLabel( + iLabel, + rect, + AknLayoutScalable_Avkon::navi_navi_icon_text_pane_t1() ); + + iLabel->CropText(); + } + else + { + if ( iLabel ) + { + TAknTextComponentLayout textLayout; + + switch ( iExtension->iNumberOfTabsInTabGroup ) + { + case 1: + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_long_active_pane_t1( + landscape ); + break; + } + + case 2: + { + if ( longTab ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_long_active_pane_t1( + landscape ); + } + else + { + if ( iActive ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_active_pane_t1( + landscape ); + } + else + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_passive_pane_t1( + landscape ); + } + } + break; + } + + case 3: + { + if ( longTab ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_long_active_pane_t1( + landscape ); + } + else + { + if ( iActive ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_active_pane_t1( + landscape ); + } + else + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_passive_pane_t1( + landscape ); + } + } + break; + } + + case 4: + default: + { + textLayout = + AknLayoutScalable_Avkon::tabs_4_active_pane_t1( + landscape ); + break; + } + } + + AknLayoutUtils::LayoutLabel( iLabel, rect, textLayout ); + + iLabel->CropText(); + } + + if ( iBitmap ) + { + TAknWindowComponentLayout l1( TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::navi_tabs_2_pane(), + TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::tabs_2_active_pane( 0 ), + AknLayoutScalable_Avkon::tabs_2_active_pane_g1() ) ) ); + + TAknWindowComponentLayout l2( TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::navi_tabs_3_pane(), + TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::tabs_3_active_pane( 0 ), + AknLayoutScalable_Avkon::tabs_3_active_pane_g1() ) ) ); + + TAknWindowComponentLayout l3( TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::navi_tabs_4_pane(), + TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::tabs_4_active_pane( 0 ), + AknLayoutScalable_Avkon::tabs_4_active_pane_g1() ) ) ); + + TAknLayoutRect layoutRect; + + layoutRect.LayoutRect( rect, l1 ); + TRect r1( layoutRect.Rect() ); + layoutRect.LayoutRect( rect, l2 ); + TRect r2( layoutRect.Rect() ); + layoutRect.LayoutRect( rect, l3 ); + TRect r3( layoutRect.Rect() ); + + TInt w = rect.Size().iWidth; + TSize size; + + if ( w < r2.Width() ) // smaller than 3 icon layout - use 4 icon layout + { + size.iWidth = r3.Width(); + size.iHeight = r3.Height(); + } + else if ( w >= r2.Width() && w < r1.Width() ) // use 3 icon layout + { + size.iWidth = r2.Width(); + size.iHeight = r2.Height(); + } + else // same or larger than 2 icon layout - use 2 icon layout + { + size.iWidth = r1.Width(); + size.iHeight = r1.Height(); + } + + AknIconUtils::SetSize( const_cast (iBitmap), size ); + + TInt imageWidth = iBitmap->SizeInPixels().iWidth; + TInt imageXPos = rect.Width() - imageWidth; + TInt imageHeight = iBitmap->SizeInPixels().iHeight; + TInt imageYPos = rect.Height() - imageHeight; + + TRect nRect( 0,0, rect.Width(), rect.Height() ); + + if ( imageXPos < 0 || imageYPos < 0 ) + { + iBitmapRect.LayoutRect( nRect, + ELayoutEmpty, + rect.iTl.iX, + rect.iTl.iY, + ELayoutEmpty, + ELayoutEmpty, + rect.Width(), + rect.Height()); + } + else + { + // Center image. + imageXPos = imageXPos >> 1; + imageXPos += rect.iTl.iX; + imageYPos = imageYPos >> 1; + imageYPos += rect.iTl.iY; + + iBitmapRect.LayoutRect( nRect, + ELayoutEmpty, + imageXPos, + imageYPos, + ELayoutEmpty, + ELayoutEmpty, + imageWidth, + imageHeight ); + } + } + } + } + + +void CAknTab::SizeChangedInNarrowLayout() + { + if ( !iColorBitmaps ) + { + TRAP_IGNORE( LoadColorBitmapL() ); + } + + TBool isStaconPaneActive( AknStatuspaneUtils::StaconPaneActive() ); + TBool longTab( iExtension && iExtension->iLongTab ); + + TRect rect( Rect() ); + + if ( iLabel && iBitmap ) + { + iBitmapRect.LayoutRect( + rect, + AknLayoutScalable_Avkon::navi_navi_icon_text_pane_srt_g1() ); + AknIconUtils::SetSize( const_cast ( iBitmap ), + iBitmapRect.Rect().Size() ); + AknLayoutUtils::LayoutLabel( + iLabel, + rect, + AknLayoutScalable_Avkon::navi_navi_icon_text_pane_srt_t1( 0 ) ); + + iLabel->CropText(); + } + else + { + if ( iLabel ) + { + TAknTextComponentLayout textLayout; + + switch ( iExtension->iNumberOfTabsInTabGroup ) + { + case 1: + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_long_active_pane_t1( + isStaconPaneActive ); + break; + } + + case 2: + { + if ( longTab ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_long_active_pane_srt_t1( + isStaconPaneActive ); + } + else + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_active_pane_srt_t1( + isStaconPaneActive ); + } + break; + } + + case 3: + { + if ( longTab ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_long_active_pane_srt_t1( + isStaconPaneActive ); + } + else + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_active_pane_srt_t1( + isStaconPaneActive ); + } + break; + } + + case 4: + default: + { + textLayout = + AknLayoutScalable_Avkon::tabs_4_active_pane_srt_t1( + isStaconPaneActive ); + break; + } + } + + AknLayoutUtils::LayoutLabel( iLabel, rect, textLayout ); + + iLabel->CropText(); + } + + if ( iBitmap ) + { + TAknWindowComponentLayout l1( + AknLayoutScalable_Avkon::tabs_2_active_pane_srt_g1() ); + TAknWindowComponentLayout l2( + AknLayoutScalable_Avkon::tabs_3_active_pane_srt_g1() ); + TAknWindowComponentLayout l3( + AknLayoutScalable_Avkon::tabs_4_active_pane_srt_g1() ); + + TAknLayoutRect layoutRect; + + layoutRect.LayoutRect( rect, l1 ); + TRect r1 = layoutRect.Rect(); + layoutRect.LayoutRect( rect, l2 ); + TRect r2 = layoutRect.Rect(); + layoutRect.LayoutRect( rect, l3 ); + TRect r3 = layoutRect.Rect(); + + TInt w = rect.Size().iWidth; + TSize size; + + if ( w < r2.Width() ) // smaller than 3 icon layout - use 4 icon layout + { + size.iWidth = r3.Width(); + size.iHeight = r3.Height(); + } + else if ( w >= r2.Width() && w < r1.Width() ) // use 3 icon layout + { + size.iWidth = r2.Width(); + size.iHeight = r2.Height(); + } + else // same or larger than 2 icon layout - use 2 icon layout + { + size.iWidth = r1.Width(); + size.iHeight = r1.Height(); + } + + AknIconUtils::SetSize( const_cast (iBitmap), size ); + + TInt imageWidth = iBitmap->SizeInPixels().iWidth; + TInt imageXPos = rect.Width() - imageWidth; + TInt imageHeight = iBitmap->SizeInPixels().iHeight; + TInt imageYPos = rect.Height() - imageHeight; + + TRect nRect( 0,0, rect.Width(), rect.Height() ); + + if ( imageXPos < 0 || imageYPos < 0 ) + { + iBitmapRect.LayoutRect( nRect, + ELayoutEmpty, + rect.iTl.iX, + rect.iTl.iY, + ELayoutEmpty, + ELayoutEmpty, + rect.Width(), + rect.Height() ); + } + else + { + // Center image. + imageXPos = imageXPos >> 1; + imageXPos += rect.iTl.iX; + imageYPos = imageYPos >> 1; + imageYPos += rect.iTl.iY; + iBitmapRect.LayoutRect( nRect, + ELayoutEmpty, + imageXPos, + imageYPos, + ELayoutEmpty, + ELayoutEmpty, + imageWidth, + imageHeight ); + } + } + } + + } + + +// --------------------------------------------------------------------------- +// Handles size change events in flat status pane layouts. +// --------------------------------------------------------------------------- +// +void CAknTab::SizeChangedInFlatLayout() + { + if ( !iColorBitmaps ) + { + TRAP_IGNORE( LoadColorBitmapL() ); + } + + TBool longTab( iExtension && iExtension->iLongTab ); + + TRect rect( Rect() ); + + if ( iLabel && iBitmap ) + { + iBitmapRect.LayoutRect( rect, AknLayoutScalable_Avkon::navi_navi_icon_text_pane_g1() ); + + AknIconUtils::SetSize( const_cast ( iBitmap ), + iBitmapRect.Rect().Size() ); + + AknLayoutUtils::LayoutLabel( + iLabel, + rect, + AknLayoutScalable_Avkon::navi_navi_icon_text_pane_t1() ); + + iLabel->CropText(); + } + else + { + if ( iLabel ) + { + TAknTextComponentLayout textLayout; + + switch ( iExtension->iNumberOfTabsInTabGroup ) + { + case 1: + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_long_active_pane_t1( 0 ); + break; + } + + case 2: + { + if ( longTab ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_long_active_pane_t1( 0 ); + } + else + { + if ( iActive ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_active_pane_t1( 0 ); + } + else + { + textLayout = + AknLayoutScalable_Avkon::tabs_2_passive_pane_t1( 0 ); + } + } + break; + } + + case 3: + { + if ( longTab ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_long_active_pane_t1( 0 ); + } + else + { + if ( iActive ) + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_active_pane_t1( 0 ); + } + else + { + textLayout = + AknLayoutScalable_Avkon::tabs_3_passive_pane_t1( 0 ); + } + } + break; + } + + case 4: + default: + { + textLayout = + AknLayoutScalable_Avkon::tabs_4_active_pane_t1( 0 ); + break; + } + } + + AknLayoutUtils::LayoutLabel( iLabel, rect, textLayout ); + + iLabel->CropText(); + } + + if ( iBitmap ) + { + TAknWindowComponentLayout l1( + AknLayoutScalable_Avkon::tabs_2_active_pane_g1() ); + TAknWindowComponentLayout l2( + AknLayoutScalable_Avkon::tabs_3_active_pane_g1() ); + TAknWindowComponentLayout l3( + AknLayoutScalable_Avkon::tabs_4_active_pane_g1() ); + + TAknLayoutRect layoutRect; + + layoutRect.LayoutRect( rect, l1 ); + TRect r1 = layoutRect.Rect(); + layoutRect.LayoutRect( rect, l2 ); + TRect r2 = layoutRect.Rect(); + layoutRect.LayoutRect( rect, l3 ); + TRect r3 = layoutRect.Rect(); + + TInt w = rect.Size().iWidth; + TSize size; + + if ( w < r2.Width() ) // smaller than 3 icon layout - use 4 icon layout + { + size.iWidth = r3.Width(); + size.iHeight = r3.Height(); + } + else if ( w >= r2.Width() && w < r1.Width() ) // use 3 icon layout + { + size.iWidth = r2.Width(); + size.iHeight = r2.Height(); + } + else // same or larger than 2 icon layout - use 2 icon layout + { + size.iWidth = r1.Width(); + size.iHeight = r1.Height(); + } + + AknIconUtils::SetSize( const_cast (iBitmap), size ); + + TInt imageWidth = iBitmap->SizeInPixels().iWidth; + TInt imageXPos = rect.Width() - imageWidth; + TInt imageHeight = iBitmap->SizeInPixels().iHeight; + TInt imageYPos = rect.Height() - imageHeight; + + TRect nRect( 0,0, rect.Width(), rect.Height() ); + + if ( imageXPos < 0 || imageYPos < 0 ) + { + iBitmapRect.LayoutRect( nRect, + ELayoutEmpty, + rect.iTl.iX, + rect.iTl.iY, + ELayoutEmpty, + ELayoutEmpty, + rect.Width(), + rect.Height() ); + } + else + { + // Center image. + imageXPos = imageXPos >> 1; + imageXPos += rect.iTl.iX; + imageYPos = imageYPos >> 1; + imageYPos += rect.iTl.iY; + iBitmapRect.LayoutRect( nRect, + ELayoutEmpty, + imageXPos, + imageYPos, + ELayoutEmpty, + ELayoutEmpty, + imageWidth, + imageHeight ); + } + } + } + } + + +// --------------------------------------------------------------------------- +// Returns the amount of component controls. +// --------------------------------------------------------------------------- +// +TInt CAknTab::CountComponentControls() const + { + TInt count( 0 ); + + if ( iLabel ) + { + count++; + } + + return count; + } + + +CCoeControl* CAknTab::ComponentControl( TInt /*aIndex*/ ) const + { + return iLabel; + } + +void CAknTab::Draw( const TRect& /*aRect*/ ) const + { + if ( iLabel ) + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + TRgb color; + + + if ( iExtension->iNumberOfTabsInTabGroup == 1 ) // >= EAknTabWidthWithOneTab + { + TInt error = AknsUtils::GetCachedColor( skin, color, + KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG2 ); + if ( !error ) + { + // Ignore error + TRAP_IGNORE( AknLayoutUtils::OverrideControlColorL( *iLabel, + EColorLabelText, color ) ); + } + } + else + { + if ( iActive ) + { + TInt error = AknsUtils::GetCachedColor( skin, color, + KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG3 ); + if ( !error ) + { + // Ignore error + TRAP_IGNORE( AknLayoutUtils::OverrideControlColorL( *iLabel, + EColorLabelText, color ) ); + } + } + else + { + TInt error = AknsUtils::GetCachedColor( skin, color, + KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG4 ); + if ( !error ) + { + // Ignore error + TRAP_IGNORE( AknLayoutUtils::OverrideControlColorL( *iLabel, + EColorLabelText, color ) ); + } + } + } + + } + + if ( iBitmap ) + { + TBool legacyDraw = EFalse; + CWindowGc& gc=SystemGc(); + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + if ( skin && !iExtension->iMultiColorMode ) + { + CFbsBitmap* colorBitmap = NULL; + if (iColorBitmaps && + iColorBitmaps->At(KTabColorBitmapActiveColorIndex) && + iColorBitmaps->At(KTabColorBitmapPassiveColorIndex) ) + { + if( iActive ) + { + colorBitmap = iColorBitmaps->At(KTabColorBitmapActiveColorIndex); + } + else + { + colorBitmap = iColorBitmaps->At(KTabColorBitmapPassiveColorIndex); + } + } + + if ( colorBitmap && iBitmapMask ) + { + iBitmapRect.DrawImage( gc, + colorBitmap, + const_cast ( iBitmapMask ) ); + } + else + { + legacyDraw = ETrue; + } + } + else // No skin (legacy drawing) or multi-colored drawing. + { + legacyDraw = ETrue; + } + if ( legacyDraw ) + { + iBitmapRect.DrawImage( gc, + const_cast( iBitmap ), + const_cast( iBitmapMask ) ); + } + } + } + +void CAknTab::HandlePointerEventL( const TPointerEvent& aPointerEvent ) + { + if ( aPointerEvent.iType==TPointerEvent::EButton1Down && + !iActive && + !IsDimmed() ) + { + ReportEventL( MCoeControlObserver::EEventStateChanged ); + } + } + +EXPORT_C void* CAknTab::ExtensionInterface( TUid /*aInterface*/ ) + { + return NULL; + } + +// --------------------------------------------------------------------------- +// Loads the bitmap used in drawing the tab icon with correct color. +// --------------------------------------------------------------------------- +// +void CAknTab::LoadColorBitmapL() + { + if ( iColorBitmaps ) + { + iColorBitmaps->ResetAndDestroy(); + delete iColorBitmaps; + iColorBitmaps = NULL; + } + + TRect rect( Rect() ); + + if ( rect.IsEmpty() ) + { + // We cannot decide the right color. + // This method will be called again when the rect is set. + return; + } + + if ( !iColorBitmaps ) + { + iColorBitmaps = new (ELeave) CAknTabColorBitmapArray( + KTabColorBitmapQueueGranularity ); + CFbsBitmap* activeColorBitmap = new (ELeave) CFbsBitmap(); + CleanupStack::PushL(activeColorBitmap); + CFbsBitmap* passiveColorBitmap = new (ELeave) CFbsBitmap(); + CleanupStack::PushL( passiveColorBitmap ); + iColorBitmaps->AppendL( activeColorBitmap ); + iColorBitmaps->AppendL( passiveColorBitmap ); + CleanupStack::Pop( 2, activeColorBitmap ); + } + + TBool isStaconPaneActive( AknStatuspaneUtils::StaconPaneActive() ); + TBool isFlatLayoutActive( + isStaconPaneActive ? EFalse : AknStatuspaneUtils::FlatLayoutActive() ); + + TAknLayoutRect layoutRect; + // LAF does not contain line for EAknTabWidthWithOneTab + // so we use this instead. + layoutRect.LayoutRect( rect, AknLayoutScalable_Avkon::navi_tabs_2_pane() ); + TRect tabRect = layoutRect.Rect(); + if ( tabRect.Width() < 0 || tabRect.Height() < 0 ) + { + tabRect.SetRect( 0, 0, 0, 0 ); + } + + if ( !( iColorBitmaps && + iColorBitmaps->At( KTabColorBitmapActiveColorIndex ) && + iColorBitmaps->At( KTabColorBitmapPassiveColorIndex ) ) ) + { + return; + } + + // Note 64K or 16M mode seems to have some issues with some HW possibly + // related to bitmap compression, so we use display's color mode + // here instead for now instead of the AknIconConfig's preferred + // display mode. + TDisplayMode screenDisplayMode( iEikonEnv->ScreenDevice()->DisplayMode() ); + iColorBitmaps->At( KTabColorBitmapActiveColorIndex )->Create( + Size(), screenDisplayMode ); + iColorBitmaps->At( KTabColorBitmapPassiveColorIndex )->Create( + Size(), screenDisplayMode ); + + TRgb color( KRgbGray ); + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + // First active color... + TAknsQsnIconColorsIndex colorIndex; + if (iExtension->iNumberOfTabsInTabGroup == 1) + { + colorIndex = EAknsCIQsnIconColorsCG7; + } + else + { + colorIndex = EAknsCIQsnIconColorsCG8; + } + AknsUtils::GetCachedColor( skin, + color, + KAknsIIDQsnIconColors, + colorIndex ); + + CFbsBitmapDevice* destinationDevice = + CFbsBitmapDevice::NewL( + iColorBitmaps->At( KTabColorBitmapActiveColorIndex ) ); + CleanupStack::PushL( destinationDevice ); + CFbsBitGc* destinationGc; + User::LeaveIfError( destinationDevice->CreateContext( destinationGc ) ); + destinationGc->SetPenColor( color ); + destinationGc->SetPenStyle( CGraphicsContext::ESolidPen ); + destinationGc->SetBrushColor( color ); + destinationGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); + destinationGc->DrawRect( + TRect( iColorBitmaps->At( KTabColorBitmapActiveColorIndex )->SizeInPixels() ) ); + + delete destinationGc; + CleanupStack::PopAndDestroy( destinationDevice ); + + // ...then passive color. + AknsUtils::GetCachedColor( skin, + color, + KAknsIIDQsnIconColors, + EAknsCIQsnIconColorsCG9 ); + + destinationDevice = + CFbsBitmapDevice::NewL( + iColorBitmaps->At( KTabColorBitmapPassiveColorIndex ) ); + CleanupStack::PushL(destinationDevice); + User::LeaveIfError( destinationDevice->CreateContext( destinationGc ) ); + destinationGc->SetPenColor( color ); + destinationGc->SetPenStyle( CGraphicsContext::ESolidPen ); + destinationGc->SetBrushColor( color ); + destinationGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); + destinationGc->DrawRect( + TRect( iColorBitmaps->At( KTabColorBitmapPassiveColorIndex )->SizeInPixels() ) ); + + delete destinationGc; + CleanupStack::PopAndDestroy( destinationDevice ); + } + + +void CAknTab::HandleResourceChange( TInt aType ) + { + CCoeControl::HandleResourceChange( aType ); + + if ( aType == KEikDynamicLayoutVariantSwitch || + aType == KEikColorResourceChange || + aType == KAknsMessageSkinChange ) + { + TRAP_IGNORE( LoadColorBitmapL() ); + DrawDeferred(); + } + } + +void CAknTab::SetTotalAmountOfTabs( TInt aAmount ) + { + iExtension->iNumberOfTabsInTabGroup = aAmount; + + if ( !iColorBitmaps ) + { + LoadColorBitmapL(); + } + } + +void CAknTab::SetNarrowTabLayout( TBool aNarrow ) + { + iExtension->iNarrowTabLayout = aNarrow; + } + + +// --------------------------------------------------------------------------- +// CAknTab::SetMultiColorMode +// --------------------------------------------------------------------------- +// +void CAknTab::SetMultiColorMode( TBool aMultiColor ) + { + if ( iExtension ) + { + iExtension->iMultiColorMode = aMultiColor; + } + } + + +// --------------------------------------------------------------------------- +// CAknTab::MultiColorMode +// --------------------------------------------------------------------------- +// +TBool CAknTab::MultiColorMode() const + { + if ( iExtension ) + { + return iExtension->iMultiColorMode; + } + else + { + return EFalse; + } + } + + +// --------------------------------------------------------------------------- +// CAknTab::SetLongTabLayout +// Sets this tab to use long layout. +// --------------------------------------------------------------------------- +// +void CAknTab::SetLongTabLayout( TBool aLongTab ) + { + if ( iExtension ) + { + iExtension->iLongTab = aLongTab; + } + } + + +// ================= PRIVATE CLASS ======================= + +class CAknTabGroupExtension : public CBase + { +public: + + /** Types of supported tab group animations. */ + enum TTabAnimationType + { + /** + * No animation is currently used. + */ + ENoAnimation = 0, + /** + * Animation type used when switching between + * normal and flat tab group layout. + */ + ELayoutSwitchAnimation, + /** + * Animation type used when cycling between tabs in three tab layout + * when there are more than three tabs in the tab group. + */ + ETabCycleAnimation + }; + + CAknTabGroupExtension(); + ~CAknTabGroupExtension(){}; + +public: // Member data. + + CFbsBitmap* iStaconTabBitmaps[KTabNumberOfTabBitmaps]; + CFbsBitmap* iStaconTabMaskBitmaps[KTabNumberOfTabBitmaps]; + CAknTabGroupGraphics* iTabSvgGraphics; + + /** Layout used for the tab background graphics. */ + CAknTabGroupGraphics::SAknTabGroupBackgroundLayout iTabBackgroundLayout; + + /** Layout used for the tab background graphics during tab animation. */ + CAknTabGroupGraphics::SAknTabGroupBackgroundLayout iNextTabBackgroundLayout; + + /** Timer used in tab animations. */ + CPeriodic* iTabAnimationTimer; + + /** Type of the current tab animation. */ + TTabAnimationType iTabAnimationType; + + /** Amount of completed tab animation steps. */ + TInt iAmountOfDoneAnimationEvents; + + /** Direction of the current tab cycle animation (left or right). */ + CAknTabGroup::TDirection iTabCycleAnimationDirection; + + /** Horizontal distance left in the tab cycle animation. */ + TInt iTabCycleAnimationDistanceLeft; + + /** Is the tab cycle animation in process. */ + TBool iTabCycleAnimationOngoing; + + /** + * Specifies on which side of the tab group there are tabs + * that don't fit in the set of currently displayed tabs. + */ + CAknTabGroupGraphics::TTabsHidden iTabsHidden; + + TBool iTabAnimationDoubleBufferNarrowTabLayout; + TBool iTabAnimationDoubleBufferLongTabs; + TInt iTabAnimationDoubleBufferNumberOfTabsShown; + TInt iTabAnimationDoubleBufferpositionActive; + + TBool iNarrowTabLayout; + TBool iNarrowTabLayoutNext; + + /** Are navigation arrows shown in the current tab layout. */ + TBool iNaviArrowsUsed; + + /** Index of the tab where pointer down event happened. */ + TInt iPointerDownTab; + + /** X-value of the pointer down event position. */ + TInt iPointerDownXPosition; + + /** This is the tab width that is set by the application. */ + TInt iRequestedTabWidth; + }; + + +CAknTabGroupExtension::CAknTabGroupExtension() + { + iPointerDownTab = -1; + iPointerDownXPosition = -1; + } + + +// +// CAknTabGroup +// + +EXPORT_C CAknTabGroup::CAknTabGroup() : iActiveTab(KAknTabGroupNoTabs) + { + iTabFixedWidth = -1; + iFirstShownTab = 0; + iNumberOfTabsShown = 0; + + // Tab bitmaps and masks for every tab group layouts + iBitmapNames[0] = EMbmAvkonQgn_graf_tab_21; + iBitmapNames[1] = EMbmAvkonQgn_graf_tab_22; + iBitmapNames[2] = EMbmAvkonQgn_graf_tab_long_21; + iBitmapNames[3] = EMbmAvkonQgn_graf_tab_long_22; + iBitmapNames[4] = EMbmAvkonQgn_graf_tab_long_31; + iBitmapNames[5] = EMbmAvkonQgn_graf_tab_long_32; + iBitmapNames[6] = EMbmAvkonQgn_graf_tab_long_33; + iBitmapNames[7] = EMbmAvkonQgn_graf_tab_31; + iBitmapNames[8] = EMbmAvkonQgn_graf_tab_32; + iBitmapNames[9] = EMbmAvkonQgn_graf_tab_33; + iBitmapNames[10] = EMbmAvkonQgn_graf_tab_41; + iBitmapNames[11] = EMbmAvkonQgn_graf_tab_42; + iBitmapNames[12] = EMbmAvkonQgn_graf_tab_43; + iBitmapNames[13] = EMbmAvkonQgn_graf_tab_44; + + iBitmapMaskNames[0] = EMbmAvkonQgn_graf_tab_21_mask; + iBitmapMaskNames[1] = EMbmAvkonQgn_graf_tab_22_mask; + iBitmapMaskNames[2] = EMbmAvkonQgn_graf_tab_long_21_mask; + iBitmapMaskNames[3] = EMbmAvkonQgn_graf_tab_long_22_mask; + iBitmapMaskNames[4] = EMbmAvkonQgn_graf_tab_long_31_mask; + iBitmapMaskNames[5] = EMbmAvkonQgn_graf_tab_long_32_mask; + iBitmapMaskNames[6] = EMbmAvkonQgn_graf_tab_long_33_mask; + iBitmapMaskNames[7] = EMbmAvkonQgn_graf_tab_31_mask; + iBitmapMaskNames[8] = EMbmAvkonQgn_graf_tab_32_mask; + iBitmapMaskNames[9] = EMbmAvkonQgn_graf_tab_33_mask; + iBitmapMaskNames[10] = EMbmAvkonQgn_graf_tab_41_mask; + iBitmapMaskNames[11] = EMbmAvkonQgn_graf_tab_42_mask; + iBitmapMaskNames[12] = EMbmAvkonQgn_graf_tab_43_mask; + iBitmapMaskNames[13] = EMbmAvkonQgn_graf_tab_44_mask; + + iMirrored = AknLayoutUtils::LayoutMirrored(); + } + +EXPORT_C CAknTabGroup::~CAknTabGroup() + { + AKNTASHOOK_REMOVE(); + if ( iTabArray ) + { + iTabArray->ResetAndDestroy(); + } + delete iTabArray; + + for ( TInt i = 0; i < KTabNumberOfTabBitmaps; i++ ) + { + delete( iTabBitmaps[i] ); + delete( iTabMaskBitmaps[i] ); + } + + if ( iExtension ) + { + for ( TInt j = 0; j < KTabNumberOfTabBitmaps; j++ ) + { + delete( iExtension->iStaconTabBitmaps[j] ); + delete( iExtension->iStaconTabMaskBitmaps[j] ); + } + + delete iExtension->iTabSvgGraphics; + if ( iExtension->iTabAnimationTimer ) + { + iExtension->iTabAnimationTimer->Cancel(); + delete iExtension->iTabAnimationTimer; + } + } + + delete iExtension; + + } + +EXPORT_C CAknTabGroup* CAknTabGroup::NewL( const CCoeControl& aParent ) + { + CAknTabGroup* self = CAknTabGroup::NewLC( aParent ); + CleanupStack::Pop( self ); + return self; + } + +EXPORT_C CAknTabGroup* CAknTabGroup::NewLC( const CCoeControl& aParent ) + { + CAknTabGroup* self = new (ELeave) CAknTabGroup; + CleanupStack::PushL( self ); + self->SetContainerWindowL( aParent ); + self->ConstructL(); + AKNTASHOOK_ADDL( self, "CAknTabGroup" ); + return self; + } + +EXPORT_C TInt CAknTabGroup::AddTabL( TResourceReader& aReader ) + { + CAknTab* newTab = CAknTab::NewL( *this, aReader ); + CommonAddTabL( newTab ); // Takes ownership of newTab safely. + return newTab->Id(); + } + +EXPORT_C void CAknTabGroup::AddTabL( TInt aTabId, const TDesC& aTabText ) + { + CAknTab* newTab = CAknTab::NewL( aTabId, *this, aTabText ); + CommonAddTabL( newTab ); // Takes ownership of newTab safely. + } + + +EXPORT_C void CAknTabGroup::AddTabL( TInt aTabId, + const TDesC& aTabText, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask) + { + CAknTab* newTab = CAknTab::NewL( aTabId, *this, aTabText, aTabBitmap, aMask ); + CommonAddTabL( newTab ); // Takes ownership of newTab safely. + } + + +EXPORT_C void CAknTabGroup::AddTabL( TInt aTabId, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask) + { + CAknTab* newTab = CAknTab::NewL( aTabId, *this, aTabBitmap, aMask ); + CommonAddTabL( newTab ); // Takes ownership of newTab safely. + } + +void CAknTabGroup::CommonAddTabL( CAknTab* aTab ) + { + CleanupStack::PushL( aTab ); + aTab->SetObserver( this ); + aTab->SetControlContext( this ); + + if ( iMirrored && iTabObserver ) + { + // If tab group is mirrored then tabs are inserted in + // reverse order. + iTabArray->InsertL( 0, aTab ); + } + else + { + iTabArray->AppendL( aTab ); + } + + CleanupStack::Pop( aTab ); + + if ( iTabFixedWidth < 0 && TabCount() > 1 ) + { + SetTabFixedWidthL( KTabWidthWithTwoTabs ); + } + } + +EXPORT_C void CAknTabGroup::ReplaceTabL( TResourceReader& aReader ) + { + CAknTab* newTab = CAknTab::NewL( *this, aReader ); + CommonReplaceTabL( newTab ); // Takes ownership of the newTab safely + } + +EXPORT_C void CAknTabGroup::ReplaceTabL( TInt aTabId,const TDesC& aTabText ) + { + CAknTab* newTab=CAknTab::NewL( aTabId, *this, aTabText ); + CommonReplaceTabL( newTab ); // Takes ownership of the newTab safely + } + +EXPORT_C void CAknTabGroup::ReplaceTabL( TInt aTabId, + const TDesC& aTabText, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + CAknTab* newTab = CAknTab::NewL( aTabId, *this, aTabText, aTabBitmap, aMask ); + CommonReplaceTabL( newTab ); // Takes ownership of the newTab safely + } + +EXPORT_C void CAknTabGroup::ReplaceTabL( TInt aTabId, + const CFbsBitmap* aTabBitmap, + const CFbsBitmap* aMask ) + { + CAknTab* newTab = CAknTab::NewL( aTabId, *this, aTabBitmap, aMask ); + CommonReplaceTabL( newTab ); // Takes ownership of the newTab safely + } + +void CAknTabGroup::CommonReplaceTabL( CAknTab* aTab ) + { + CleanupStack::PushL( aTab ); + aTab->SetObserver( this ); + TInt tabIndex = ConvertTabIndex( TabIndexFromId( aTab->Id() ) ); + __ASSERT_ALWAYS( tabIndex >= 0, Panic( EAknPanicOutOfRange ) ); + + // Is replaced tab active tab or not + TBool isActiveTab = iTabArray->At( tabIndex )->Active(); + TBool isMultiColor = iTabArray->At( tabIndex )->MultiColorMode(); + delete iTabArray->At( tabIndex ); + iTabArray->Delete( tabIndex ); + iTabArray->InsertL( tabIndex, aTab ); + CleanupStack::Pop( aTab ); + + aTab->SetMultiColorMode( isMultiColor ); + aTab->SetControlContext( this ); + aTab->SetActive( isActiveTab, ENoDrawNow ); + SizeChanged(); + TInt event = MAknNavigationObserver::ENaviEventRedrawNeeded; + ReportEventL( static_cast( event ) ); + } + +EXPORT_C void CAknTabGroup::ReplaceTabTextL( TInt aTabId, const TDesC& aTabText ) + { + TInt tabIndex = ConvertTabIndex( TabIndexFromId( aTabId ) ); + __ASSERT_ALWAYS( tabIndex >= 0, Panic( EAknPanicOutOfRange ) ); + iTabArray->At( tabIndex )->ReplaceTextL( aTabText ); + SizeChanged(); + TInt event = MAknNavigationObserver::ENaviEventRedrawNeeded; + ReportEventL( STATIC_CAST( MCoeControlObserver::TCoeEvent, event ) ); + } + +EXPORT_C void CAknTabGroup::DeleteTabL( TInt aTabId ) + { + TInt oldActiveTab = iActiveTab; + TInt tabIndex = ConvertTabIndex( TabIndexFromId( aTabId ) ); + __ASSERT_ALWAYS( tabIndex >= 0, Panic( EAknPanicOutOfRange ) ); + delete iTabArray->At( tabIndex ); + iTabArray->Delete( tabIndex ); + TInt tabCount = TabCount(); + if ( tabCount == 0 ) + { + iActiveTab = KAknTabGroupNoTabs; + } + if ( tabIndex < iActiveTab ) + { + iActiveTab--; + } + else if ( tabIndex == iActiveTab && iActiveTab == tabCount ) + { + iActiveTab--; + if ( iFirstShownTab > 0 ) + { + iFirstShownTab--; + } + } + + SizeChanged(); + + TInt event = MAknNavigationObserver::ENaviEventRedrawNeeded; + if ( tabCount <= 1 ) + { + event = MAknNavigationObserver::ENaviEventOneItemExists; + } + else if ( iActiveTab == 0 && oldActiveTab != 0 ) + { + event = MAknNavigationObserver::ENaviEventLeftMostItemReached; + } + else if ( iActiveTab == ( tabCount - 1 ) && + oldActiveTab != tabCount ) + { + event = MAknNavigationObserver::ENaviEventRightMostItemReached; + } + + ReportEventL( static_cast( event ) ); + } + +void CAknTabGroup::ConstructL() + { + iExtension = new (ELeave) CAknTabGroupExtension(); + iExtension->iTabSvgGraphics = CAknTabGroupGraphics::NewL(); + iExtension->iTabAnimationTimer = CPeriodic::NewL( CActive::EPriorityIdle ); + iTabArray = new (ELeave) CArrayPtrFlat( KTabArrayGranularity ); + } + +EXPORT_C void CAknTabGroup::SetActiveTabById( TInt aTabId ) + { + TInt tabIndex = Index( aTabId ); + SetActiveTabByIndex( ConvertTabIndex( tabIndex ) ); + } + + +// --------------------------------------------------------------------------- +// Sets the active tab by tab index. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknTabGroup::SetActiveTabByIndex( TInt aTabIndex ) + { + const TInt numTabs = TabCount(); + + TInt realIndex = ConvertTabIndex( aTabIndex ); + + // When iActiveTab doesn't change, nothing need to do. + if ( realIndex == iActiveTab ) + { + return; + } + + if ( realIndex >= 0 && realIndex < numTabs ) + { + CArrayPtr& tabArray = *iTabArray; + if ( iActiveTab >= 0 ) + { + tabArray[iActiveTab]->SetFocus( EFalse, ENoDrawNow ); + tabArray[iActiveTab]->SetActive( EFalse, ENoDrawNow ); + } + iActiveTab = realIndex; + tabArray[iActiveTab]->SetFocus( ETrue, ENoDrawNow ); + tabArray[iActiveTab]->SetActive( ETrue, ENoDrawNow ); + + if ( AknLayoutUtils::PenEnabled() && + iTabFixedWidth == KTabWidthWithThreeTabs ) + { + if ( realIndex != RightMostTabIndex() && + realIndex != LeftMostTabIndex() ) + { + iFirstShownTab = realIndex - 1; + } + else if ( realIndex < iFirstShownTab ) + { + iFirstShownTab = realIndex; + } + else if ( realIndex >= ( iFirstShownTab + iNumberOfTabsShown ) ) + { + iFirstShownTab = realIndex - iNumberOfTabsShown + 1; + } + } + else + { + if ( realIndex < iFirstShownTab ) + { + iFirstShownTab = realIndex; + } + + if ( realIndex >= ( iFirstShownTab + iNumberOfTabsShown ) ) + { + iFirstShownTab = realIndex - iNumberOfTabsShown + 1; + } + } + + SizeChanged(); + + if ( !AknStatuspaneUtils::FlatLayoutActive() && + iExtension->iTabAnimationType == + CAknTabGroupExtension::ELayoutSwitchAnimation ) + { + CancelTabAnimationEventTimer(); + } + + SetDecoratorLayout( EFalse ); + TRAP_IGNORE( InitTabAnimationL() ); + + ReportNavigationEvent(); + } + } + +EXPORT_C TInt CAknTabGroup::ActiveTabId() const + { + if ( iActiveTab >= 0 ) + { + return iTabArray->At( iActiveTab )->Id(); + } + + return KErrNotFound; + } + +EXPORT_C TInt CAknTabGroup::ActiveTabIndex() const + { + return ConvertTabIndex( iActiveTab ); + } + + +// --------------------------------------------------------------------------- +// Sets the width (used layout) of the tabs. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknTabGroup::SetTabFixedWidthL( TInt aWidth ) + { + if ( iExtension ) + { + // Store the requested width in case it's mapped here to another + // width but usable in some other layout. + iExtension->iRequestedTabWidth = aWidth; + } + + TInt numberOfTabsShown = iNumberOfTabsShown; + TInt tabFixedWidth = iTabFixedWidth; + TBool longTabs = iLongTabs; + + iLongTabs = EFalse; + + if ( aWidth <= KTabWidthWithTwoTabs && aWidth > KTabWidthWithThreeTabs ) + { + iNumberOfTabsShown = 2; + iTabFixedWidth = KTabWidthWithTwoTabs; + } + else if ( AknLayoutUtils::PenEnabled() ) + { + if ( aWidth <= KTabWidthWithThreeTabs ) + { + iNumberOfTabsShown = 3; + iTabFixedWidth = KTabWidthWithThreeTabs; + } + else + { + iNumberOfTabsShown = 1; + iTabFixedWidth = KTabWidthWithOneTab; + } + } + else + { + if ( aWidth <= KTabWidthWithThreeTabs && + aWidth > KTabWidthWithFourTabs ) + { + iNumberOfTabsShown = 3; + iTabFixedWidth = KTabWidthWithThreeTabs; + } + else if ( aWidth <= KTabWidthWithFourTabs ) + { + iNumberOfTabsShown = 4; + iTabFixedWidth = KTabWidthWithFourTabs; + } + else if ( aWidth <= KTabWidthWithThreeLongTabs ) + { + iNumberOfTabsShown = 3; + iTabFixedWidth = KTabWidthWithThreeLongTabs; + iLongTabs = ETrue; + } + else if ( aWidth <= KTabWidthWithTwoLongTabs ) + { + iNumberOfTabsShown = 2; + iTabFixedWidth = KTabWidthWithTwoLongTabs; + iLongTabs = ETrue; + } + else + { + iNumberOfTabsShown = 1; + iTabFixedWidth = KTabWidthWithOneTab; + } + } + + // When iNumberOfTabsShown, iTabFixedWidth, iLongTabs don't change, + // there's no reason to do LoadTabBitmapsL(), etc. + if ( numberOfTabsShown == iNumberOfTabsShown && + tabFixedWidth == iTabFixedWidth && + longTabs == iLongTabs ) + { + return; + } + + TInt tabCount = TabCount(); + + for ( TInt ii = 0; ii < tabCount; ii++ ) + { + // Tell the tabs about the long tab layout + // for them to be able to layout their content + // correctly. + CAknTab* tab = iTabArray->At( ii ); + tab->SetLongTabLayout( iLongTabs ); + } + + SizeChanged(); + + if ( iExtension && + iExtension->iTabSvgGraphics && + iExtension->iTabSvgGraphics->TabGroupBackgroundAvailable() ) + { + iExtension->iTabBackgroundLayout.iUse = EFalse; + + iExtension->iTabSvgGraphics->DrawTabGroupBackgroundL( + CAknTabGroupGraphics::ENoDraw, + iLongTabs, + iNumberOfTabsShown, + 1, + NULL, + iExtension->iTabBackgroundLayout, + CAknTabGroupGraphics::ENone ); + + iExtension->iTabBackgroundLayout.iUse = ETrue; + SetDecoratorLayout( EFalse ); + } + + LoadTabBitmapsL( iNumberOfTabsShown, iLongTabs ); + } + + +EXPORT_C void CAknTabGroup::DimTab( TInt aTabId, TBool aDimmed ) + { + TInt index = Index( aTabId ); + if ( index >= 0 ) + { + CAknTab* tabToDim = iTabArray->At( index ); + tabToDim->SetDimmed( aDimmed ); + } + } + +EXPORT_C TBool CAknTabGroup::IsTabDimmed( TInt aTabId ) const + { + TInt index = Index( aTabId ); + if ( index < 0 ) + { + return EFalse; + } + CAknTab* tabToCheck = iTabArray->At( index ); + return tabToCheck->IsDimmed(); + } + +EXPORT_C TInt CAknTabGroup::TabIndexFromId( TInt aTabId ) const + { + const TInt numTabs = TabCount(); + + for ( TInt ii = 0; ii < numTabs; ii++ ) + { + if ( aTabId == iTabArray->At(ii)->Id() ) + { + return ConvertTabIndex( ii ); + } + } + + return KErrNotFound; + } + +EXPORT_C TInt CAknTabGroup::TabIdFromIndex( TInt aTabIndex ) const + { + TInt realIndex = ConvertTabIndex( aTabIndex ); + const TInt numTabs = TabCount(); + if( ( realIndex >= 0 ) && ( realIndex < numTabs ) ) + { + return iTabArray->At( realIndex )->Id(); + } + + return KErrNotFound; + } + +EXPORT_C TInt CAknTabGroup::TabCount() const + { + return iTabArray->Count(); + } + + +EXPORT_C void CAknTabGroup::SetObserver( MAknTabObserver* aObserver ) + { + if ( !iTabObserver && iTabArray && TabCount() > 0 && iMirrored ) + { + // + // If there isn't observer set but there is tabs already in array + // then the order of tabs must be changed if layout is mirrored. + // + TRAP_IGNORE( ReverseTabOrderL() ); + iTabObserver = aObserver; + iActiveTab = ConvertTabIndex( iActiveTab ); + SetActiveTabByIndex( ConvertTabIndex( iActiveTab ) ); + } + else + { + iTabObserver = aObserver; + } + } + +void CAknTabGroup::ReverseTabOrderL() + { + if ( !iTabArray ) + { + return; + } + + CArrayPtr* oldArray = iTabArray; + iTabArray = new(ELeave) CArrayPtrFlat( KTabArrayGranularity ); + CleanupStack::PushL( oldArray ); + for ( TInt i = 0; i < oldArray->Count(); i++ ) + { + iTabArray->InsertL( 0, oldArray->At(i) ); + } + + oldArray->Reset(); + CleanupStack::PopAndDestroy( oldArray ); + SizeChanged(); + } + + +EXPORT_C TSize CAknTabGroup::MinimumSize() + { + TAknWindowLineLayout layout; + CurrentLayout( layout ); + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( ParentRect( iExtension->iNaviArrowsUsed ), layout ); + TRect rect( layoutRect.Rect() ); + + return rect.Size(); + } + + +EXPORT_C TKeyResponse CAknTabGroup::OfferKeyEventL( const TKeyEvent& aKeyEvent, + TEventCode aType ) + { + if ( aType != EEventKey ) + { + return EKeyWasNotConsumed; + } + + TKeyResponse keyResponse = EKeyWasNotConsumed; + + switch ( aKeyEvent.iCode ) + { + case EKeyLeftArrow: + if ( iActiveTab != LeftMostTabIndex() || aKeyEvent.iRepeats == 0 ) + { + if ( CycleFocus( ELeft,EDrawNow ) ) + { + keyResponse = EKeyWasConsumed; + } + } + break; + + case EKeyRightArrow: + if ( iActiveTab != RightMostTabIndex() || aKeyEvent.iRepeats == 0 ) + { + if ( CycleFocus( ERight,EDrawNow ) ) + { + keyResponse = EKeyWasConsumed; + } + } + break; + + default: + break; + } + + if ( iTabObserver && keyResponse != EKeyWasNotConsumed ) + { + iTabObserver->TabChangedL( ConvertTabIndex( iActiveTab ) ); + } + + return keyResponse; + } + + +EXPORT_C void CAknTabGroup::GetColorUseListL( + CArrayFix& aColorUseList ) const + { + TCoeColorUse colorUse; + colorUse.SetLogicalColor( EColorDialogBackground ); + colorUse.SetUse( TCoeColorUse::EBack | + TCoeColorUse::ESurrounds | + TCoeColorUse::EActive | + TCoeColorUse::ENormal | + TCoeColorUse::ENeutral ); + aColorUseList.AppendL( colorUse ); + } + + +EXPORT_C void CAknTabGroup::HandleControlEventL( CCoeControl* aControl, + TCoeEvent aEventType ) + { + switch ( aEventType ) + { + case EEventStateChanged: + HandleTabStateChanged( aControl ); + break; + default: + break; + } + } + + +EXPORT_C void CAknTabGroup::PrepareContext( CWindowGc& /*aGc*/ ) const + { + } + + +EXPORT_C void CAknTabGroup::SizeChanged() + { + // In flat statuspane we do things differently because the layout may vary. + if ( AknStatuspaneUtils::FlatLayoutActive() && !NarrowTabLayout() ) + { + SizeChangedInFlatLayout(); + } + if ( NarrowTabLayout() ) + { + SizeChangedInNarrowLayout(); + } + else + { + SizeChangedInNormalLayout(); + } + } + + +// --------------------------------------------------------------------------- +// Handles size change events in normal tab group layout. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SizeChangedInNormalLayout() + { + TRect rect( ParentRect( iExtension->iNaviArrowsUsed ) ); + + TInt tabsDrawn = iNumberOfTabsShown; + TInt numTabs = TabCount(); + + if ( tabsDrawn > numTabs ) + { + tabsDrawn = numTabs; + } + + if ( ( iFirstShownTab + iNumberOfTabsShown ) > numTabs ) + { + iFirstShownTab = 0; + } + + // set bitmap sizes + TAknWindowLineLayout defaultLayout; + CurrentLayout( defaultLayout ); + TAknLayoutRect r; + r.LayoutRect( rect, defaultLayout ); + TRect tabPaneRect( r.Rect() ); + TSize size( tabPaneRect.Size() ); + + for ( TInt i = 0; i < iNumberOfTabsShown; i++ ) + { + AknIconUtils::SetSize( iTabBitmaps[i], size ); + } + + if ( iExtension->iTabCycleAnimationOngoing ) + { + TRect emptyRect( 0, 0, 0, 0 ); + for ( TInt j = 0; j < numTabs; j++) + { + CAknTab* thisTab = iTabArray->At( j ); + thisTab->SetRect( emptyRect ); + } + + for ( TInt ii = 0; ii < tabsDrawn + 1; ii++ ) + { + TInt tabIndex = + iExtension->iTabCycleAnimationDirection == ELeft ? iActiveTab - 1 + ii : + iActiveTab - 2 + ii; + + if ( tabIndex >= numTabs || + tabIndex < 0 ) + { + break; + } + + CAknTab* thisTab = iTabArray->At( tabIndex ); + thisTab->SetNarrowTabLayout( EFalse ); // set to normal layout mode + thisTab->SetTotalAmountOfTabs( iNumberOfTabsShown ); + + switch ( ii ) + { + case 0: + { + if ( iExtension->iTabCycleAnimationDirection == ELeft ) + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iHiddenTabLeft ) ); + thisTab->SetRect( tabRect ); + } + else + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iFirstTab ) ); + thisTab->SetRect( tabRect ); + } + break; + } + + case 1: + { + if ( iExtension->iTabCycleAnimationDirection == ELeft ) + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iFirstTab ) ); + thisTab->SetRect( tabRect ); + } + else + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iSecondTab ) ); + thisTab->SetRect( tabRect ); + } + break; + } + + case 2: + { + if ( iExtension->iTabCycleAnimationDirection == ELeft ) + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iSecondTab ) ); + thisTab->SetRect( tabRect ); + } + else + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iThirdTab ) ); + thisTab->SetRect( tabRect ); + } + break; + } + + case 3: + { + if ( iExtension->iTabCycleAnimationDirection == ELeft ) + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iThirdTab ) ); + thisTab->SetRect( tabRect ); + } + else + { + TRect tabRect( iExtension->iTabSvgGraphics->TabRectFromLayout( + iExtension->iNextTabBackgroundLayout.iHiddenTabRight ) ); + thisTab->SetRect( tabRect ); + } + break; + } + } + } + } + else + { + for ( TInt ii=0; ii < tabsDrawn; ii++ ) + { + CAknTab* thisTab = iTabArray->At( ii + iFirstShownTab ); + thisTab->SetNarrowTabLayout( EFalse ); // set to normal layout mode + thisTab->SetTotalAmountOfTabs( iNumberOfTabsShown ); + + TAknLayoutRect tabLayoutRect; + + switch ( iNumberOfTabsShown ) + { + case 1: + { + thisTab->SetRect( tabPaneRect ); + break; + } + + case 2: + { + if ( iLongTabs ) + { + tabLayoutRect.LayoutRect( + tabPaneRect, + AknLayoutScalable_Avkon::tabs_2_long_active_pane( ii ) ); + thisTab->SetRect( tabLayoutRect.Rect() ); + } + else + { + tabLayoutRect.LayoutRect( + tabPaneRect, + AknLayoutScalable_Avkon::tabs_2_active_pane( ii ) ); + thisTab->SetRect( tabLayoutRect.Rect() ); + } + + break; + } + + case 3: + { + if ( iLongTabs ) + { + tabLayoutRect.LayoutRect( + tabPaneRect, + AknLayoutScalable_Avkon::tabs_3_long_active_pane( ii ) ); + thisTab->SetRect( tabLayoutRect.Rect() ); + } + else + { + tabLayoutRect.LayoutRect( + tabPaneRect, + AknLayoutScalable_Avkon::tabs_3_active_pane( ii ) ); + thisTab->SetRect( tabLayoutRect.Rect() ); + } + + break; + } + + case 4: + { + tabLayoutRect.LayoutRect( + tabPaneRect, + AknLayoutScalable_Avkon::tabs_4_active_pane( ii ) ); + thisTab->SetRect( tabLayoutRect.Rect() ); + break; + } + } + } + } + } + + +// --------------------------------------------------------------------------- +// Handles size change events in narrow tab group layout. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SizeChangedInNarrowLayout() + { + TRect rect( ParentRect( iExtension->iNaviArrowsUsed ) ); + + TRect containerNarrowRect( + CAknNavigationDecorator::DecoratedControlNarrowRect( + CAknNavigationDecorator::ETabGroup ) ); + + TInt tabsDrawn = iNumberOfTabsShown; + TInt numTabs = TabCount(); + + if ( tabsDrawn > numTabs ) + { + tabsDrawn = numTabs; + } + + if ( ( iFirstShownTab + iNumberOfTabsShown ) > numTabs ) + { + iFirstShownTab = 0; + } + + // set bitmap sizes + TAknWindowLineLayout defaultLayout; + CurrentLayout( defaultLayout ); + TAknLayoutRect r; + r.LayoutRect( rect, defaultLayout ); + TRect tabPaneRect( r.Rect() ); + TSize size( tabPaneRect.Size() ); + + for ( TInt i = 0; i < iNumberOfTabsShown; i++ ) + { + AknIconUtils::SetSize( iTabBitmaps[i], size ); + } + + for ( TInt ii = 0; ii < tabsDrawn; ii++ ) + { + CAknTab* thisTab = iTabArray->At( ii + iFirstShownTab ); + CAknTab::TAknTabDataType type = thisTab->TabType(); + thisTab->SetNarrowTabLayout( ETrue ); // set to narrow layout mode + thisTab->SetTotalAmountOfTabs( iNumberOfTabsShown ); + + // In flat statuspane we do things differently because the layout may vary. + if ( AknStatuspaneUtils::FlatLayoutActive() && NarrowTabLayout() ) + { + // only active tab shows content in narrow layout + if ( thisTab->Active() || iNumberOfTabsShown == 1 ) + { + CAknTabGroupGraphics::SAknTabLayout activeTabLayout; + TInt positionActive = iActiveTab - iFirstShownTab; + + if ( positionActive == 0 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iFirstTab; + } + else if ( positionActive == 1 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iSecondTab; + } + else if ( positionActive == 2 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iThirdTab; + } + else if ( positionActive == 3 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iFourthTab; + } + + TRect parentRect( activeTabLayout.iLeft ); + parentRect.BoundingRect( activeTabLayout.iMiddle ); + parentRect.BoundingRect( activeTabLayout.iRight ); + + if ( iNumberOfTabsShown == 1 ) + { + thisTab->SetRect( containerNarrowRect ); + } + else + { + thisTab->SetRect( parentRect ); + } + } + else + { + thisTab->SetSize( TSize( 0, 0 ) ); + } + + continue; + } + } + } + + +// --------------------------------------------------------------------------- +// Handles size change events in flat status pane layout. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SizeChangedInFlatLayout() + { + TRect rect( ParentRect( iExtension->iNaviArrowsUsed ) ); + + TRect containerNarrowRect( + CAknNavigationDecorator::DecoratedControlRect( + CAknNavigationDecorator::ETabGroup, + iExtension->iNaviArrowsUsed ) ); + + TInt tabsDrawn = iNumberOfTabsShown; + TInt numTabs = TabCount(); + + if ( tabsDrawn > numTabs ) + { + tabsDrawn = numTabs; + } + + if ( ( iFirstShownTab + iNumberOfTabsShown ) > numTabs ) + { + iFirstShownTab = 0; + } + + // set bitmap sizes + TAknWindowLineLayout defaultLayout; + CurrentLayout( defaultLayout ); + TAknLayoutRect r; + r.LayoutRect( containerNarrowRect, defaultLayout ); + TRect tabPaneRect( r.Rect() ); + TSize size( tabPaneRect.Size() ); + + for ( TInt i = 0; i < iNumberOfTabsShown; i++ ) + { + AknIconUtils::SetSize( iTabBitmaps[i], size ); + } + + for ( TInt ii = 0; ii < tabsDrawn; ii++ ) + { + CAknTab* thisTab = iTabArray->At( ii + iFirstShownTab ); + CAknTab::TAknTabDataType type = thisTab->TabType(); + thisTab->SetNarrowTabLayout( ETrue ); // set to narrow layout mode + thisTab->SetTotalAmountOfTabs( iNumberOfTabsShown ); + + if ( AknStatuspaneUtils::FlatLayoutActive() ) + { + CAknTabGroupGraphics::SAknTabLayout activeTabLayout; + TInt positionActive = iActiveTab - iFirstShownTab; + + if ( positionActive == 0 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iFirstTab; + } + else if ( positionActive == 1 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iSecondTab; + } + else if ( positionActive == 2 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iThirdTab; + } + else if ( positionActive == 3 ) + { + activeTabLayout = iExtension->iTabBackgroundLayout.iFourthTab; + } + + TRect parentRect( activeTabLayout.iLeft ); + parentRect.BoundingRect( activeTabLayout.iMiddle ); + parentRect.BoundingRect( activeTabLayout.iRight ); + + if ( iNumberOfTabsShown == 1 ) + { + thisTab->SetRect( containerNarrowRect ); + } + else + { + thisTab->SetRect( parentRect ); + } + } + } + } + + +// --------------------------------------------------------------------------- +// Returns the amount of component controls. +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAknTabGroup::CountComponentControls() const + { + TInt count( 0 ); + + // Check if tabs are supposed to be visible in current layout. + if ( !TabsVisibleInCurrentLayout() || + iActiveTab < 0 ) + { + count = 0; + } + else + { + TInt numTabs = TabCount(); + if ( iLongTabs && iActiveTab >= 0 ) + { + // In long tab layout only one tab is drawn at a time. + count = 1; + } + else if ( numTabs < iNumberOfTabsShown || + iExtension->iTabCycleAnimationOngoing ) + { + // It's required that all tabs can be drawn during + // the tab cycle animation, so return the + // entire amount of tabs. + count = numTabs; + } + else + { + // Else return amount of the displayed tabs. + count = iNumberOfTabsShown; + } + } + + return count; + } + + +// --------------------------------------------------------------------------- +// Gets a component control (tab control) by the control index. +// --------------------------------------------------------------------------- +// +EXPORT_C CCoeControl* CAknTabGroup::ComponentControl( TInt aIndex ) const + { + CCoeControl* control = NULL; + + if ( iLongTabs ) + { + control = iTabArray->At( iActiveTab ); + } + else + { + TInt index( aIndex ); + if ( !iExtension->iTabCycleAnimationOngoing ) + { + index += iFirstShownTab; + } + control = iTabArray->At( index ); + } + + return control; + } + +EXPORT_C void CAknTabGroup::FocusChanged( TDrawNow aDrawNow ) + { + if ( iActiveTab >= 0 ) + { + iTabArray->At( iActiveTab )->SetFocus( IsFocused(), aDrawNow ); + } + } + + +// --------------------------------------------------------------------------- +// Converts a mirrored tab index to it's non-mirrored index. +// --------------------------------------------------------------------------- +// +TInt CAknTabGroup::ConvertTabIndex( TInt aIndex ) const + { + if ( iMirrored && iTabObserver && aIndex >= 0 ) + { + return TabCount() - 1 - aIndex; + } + + return aIndex; + } + + +// --------------------------------------------------------------------------- +// Draws the tab group background graphics. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknTabGroup::Draw( const TRect& /*aRect*/ ) const + { + TRect rect( ParentRect( iExtension->iNaviArrowsUsed ) ); + + // Are tabs supposed to be visible in current layout. + if ( !TabsVisibleInCurrentLayout() ) + { + return; // No tabs shown + } + + if ( iActiveTab < 0 || iNumberOfTabsShown == 1 ) + { + return; + } + + TInt bitmapNo = 0; + TInt positionActive = iActiveTab - iFirstShownTab; + + // Find out a correct background bitmap for tabs + if ( iNumberOfTabsShown == 2 ) + if ( iLongTabs ) + { + bitmapNo = positionActive + KTabIndexOfFirstTabBitmapInTwoLongTabsSet; + } + else + { + bitmapNo = positionActive + KTabIndexOfFirstTabBitmapInTwoTabsSet; + } + if ( iNumberOfTabsShown == 3 ) + if ( iLongTabs ) + { + bitmapNo = positionActive + KTabIndexOfFirstTabBitmapInThreeLongTabsSet; + } + else + { + bitmapNo = positionActive + KTabIndexOfFirstTabBitmapInThreeTabsSet; + } + if ( iNumberOfTabsShown == 4 ) + { + bitmapNo = positionActive + KTabIndexOfFirstTabBitmapInFourTabsSet; + } + + CWindowGc& gc = SystemGc(); + + if (iExtension && iExtension->iTabSvgGraphics + && iExtension->iTabSvgGraphics->TabGroupBackgroundAvailable()) + { + + if (iExtension->iNarrowTabLayout) + { + iExtension->iTabSvgGraphics->DrawTabGroupNarrowBackgroundL( + CAknTabGroupGraphics::ENormal, iLongTabs, + iNumberOfTabsShown, positionActive + 1, &gc, + iExtension->iTabBackgroundLayout); + + iExtension->iTabSvgGraphics->DrawTabGroupNarrowBackgroundL( + CAknTabGroupGraphics::EMaskOnly, iLongTabs, + iNumberOfTabsShown, positionActive + 1, &gc, + iExtension->iTabBackgroundLayout); + } + else + { + CAknTabGroupGraphics::TTabAnimationType animation( + CAknTabGroupGraphics::ENoAnimation); + TBool animationOngoing( iExtension->iTabCycleAnimationOngoing ); + + if ( animationOngoing ) + { + animation + = iExtension->iTabCycleAnimationDirection == ELeft + ? CAknTabGroupGraphics::ECycleToLeft + : CAknTabGroupGraphics::ECycleToRight; + } + iExtension->iTabSvgGraphics->DrawTabGroupBackgroundL( + CAknTabGroupGraphics::ENormal, iLongTabs, + iNumberOfTabsShown, positionActive + 1, &gc, + animationOngoing ? iExtension->iNextTabBackgroundLayout + : iExtension->iTabBackgroundLayout, + iExtension->iTabsHidden, animation); + + iExtension->iTabSvgGraphics->DrawTabGroupBackgroundL( + CAknTabGroupGraphics::EMaskOnly, + iLongTabs, + iNumberOfTabsShown, + positionActive + 1, + &gc, + animationOngoing ? iExtension->iNextTabBackgroundLayout + : iExtension->iTabBackgroundLayout, + iExtension->iTabsHidden, animation); + } + } + else + { + // Old legacy draw code + if (iTabBitmaps[bitmapNo] && iTabMaskBitmaps[bitmapNo]) + { + gc.BitBltMasked(rect.iTl, iTabBitmaps[bitmapNo], rect, + iTabMaskBitmaps[bitmapNo], ETrue); + } + } + } + + +// --------------------------------------------------------------------------- +// Handles the pointer events that happen inside tab group control. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknTabGroup::HandlePointerEventL( + const TPointerEvent& aPointerEvent ) + { + if ( AknLayoutUtils::PenEnabled() && iNumberOfTabsShown > 0 ) + { + TInt newTab = -1; + + // If the tab background graphics are not drawn, then we can't + // use it to calculate tab rects and use only the x-value of + // the pointer event position. + TBool tabBackgroundUsed( iTabFixedWidth != KTabWidthWithOneTab ); + + if ( tabBackgroundUsed ) + { + CAknTabGroupGraphics::SAknTabGroupBackgroundLayout* layout = + &iExtension->iTabBackgroundLayout; + + CAknTabGroupGraphics::SAknTabLayout* tabLayout[KMaxNumberOfVisibleTabs]; + Mem::FillZ( tabLayout, sizeof( TUint ) * KMaxNumberOfVisibleTabs ); + + // Sort the layout array into right order. Tabs need to be tested + // according to their "z-order" so that the currently active tab + // is tested last. + + TInt currentTab = iActiveTab - iFirstShownTab; + + switch ( iNumberOfTabsShown ) + { + case 1: + { + tabLayout[0] = &layout->iFirstTab; + break; + } + + case 2: + { + if ( currentTab == 0 ) + { + tabLayout[0] = &layout->iSecondTab; + tabLayout[1] = &layout->iFirstTab; + } + else + { + tabLayout[0] = &layout->iFirstTab; + tabLayout[1] = &layout->iSecondTab; + } + break; + } + + case 3: + { + switch ( currentTab ) + { + case 0: + tabLayout[0] = &layout->iThirdTab; + tabLayout[1] = &layout->iSecondTab; + tabLayout[2] = &layout->iFirstTab; + break; + + case 1: + tabLayout[0] = &layout->iThirdTab; + tabLayout[1] = &layout->iFirstTab; + tabLayout[2] = &layout->iSecondTab; + break; + + default: + tabLayout[0] = &layout->iFirstTab; + tabLayout[1] = &layout->iSecondTab; + tabLayout[2] = &layout->iThirdTab; + } + break; + } + + case 4: + { + if ( NarrowTabLayout() ) + { + switch ( currentTab ) + { + case 0: + tabLayout[0] = &layout->iFourthTab; + tabLayout[1] = &layout->iThirdTab; + tabLayout[2] = &layout->iSecondTab; + tabLayout[3] = &layout->iFirstTab; + break; + + case 1: + tabLayout[0] = &layout->iFourthTab; + tabLayout[1] = &layout->iThirdTab; + tabLayout[2] = &layout->iFirstTab; + tabLayout[3] = &layout->iSecondTab; + break; + + case 2: + tabLayout[0] = &layout->iFourthTab; + tabLayout[1] = &layout->iFirstTab; + tabLayout[2] = &layout->iSecondTab; + tabLayout[3] = &layout->iThirdTab; + break; + + default: + tabLayout[0] = &layout->iFirstTab; + tabLayout[1] = &layout->iSecondTab; + tabLayout[2] = &layout->iThirdTab; + tabLayout[3] = &layout->iFourthTab; + } + } + else + { + switch ( currentTab ) + { + case 0: + tabLayout[0] = &layout->iFourthTab; + tabLayout[1] = &layout->iThirdTab; + tabLayout[2] = &layout->iSecondTab; + tabLayout[3] = &layout->iFirstTab; + break; + + case 1: + tabLayout[0] = &layout->iFourthTab; + tabLayout[1] = &layout->iThirdTab; + tabLayout[2] = &layout->iFirstTab; + tabLayout[3] = &layout->iSecondTab; + break; + + case 2: + tabLayout[0] = &layout->iFourthTab; + tabLayout[1] = &layout->iSecondTab; + tabLayout[2] = &layout->iFirstTab; + tabLayout[3] = &layout->iThirdTab; + break; + + default: + tabLayout[0] = &layout->iThirdTab; + tabLayout[1] = &layout->iSecondTab; + tabLayout[2] = &layout->iFirstTab; + tabLayout[3] = &layout->iFourthTab; + } + } + break; + } + + default: + { + User::Leave( KErrArgument ); + } + } + + // Loop through the layout array & pick the last suitable tab. + TRect* rect; + + for ( TInt tab = 0; tab < iNumberOfTabsShown; ++tab ) + { + rect = &tabLayout[tab]->iLeft; + + for ( TInt part = CAknTabGroupGraphics::ELeft; + part <= CAknTabGroupGraphics::ERight; + ++part ) + { + if ( rect->Contains( aPointerEvent.iPosition ) ) + { + if ( iExtension->iTabSvgGraphics->TabClickedL( + part, *rect, aPointerEvent.iPosition, + tab == KMaxNumberOfVisibleTabs - 1 ) ) + { + if ( tabLayout[tab] == &layout->iFirstTab ) + { + newTab = iFirstShownTab; + } + else if ( tabLayout[tab] == &layout->iSecondTab ) + { + newTab = iFirstShownTab + 1; + } + else if ( tabLayout[tab] == &layout->iThirdTab ) + { + newTab = iFirstShownTab + 2; + } + else + { + newTab = iFirstShownTab + 3; + } + break; + } + } + + // advance pointer to the next tab component + if ( part < CAknTabGroupGraphics::ERight ) + { + rect++; + } + } + } + } + + if ( aPointerEvent.iType == TPointerEvent::EButton1Down ) + { + if( newTab> -1 ) + { + MTouchFeedback* feedback = MTouchFeedback::Instance(); + + // Feedback is given only if new tab wasn't already active + // Use two convertTabIndex to cancel the mirror effects, because the newTab is always the phsical index. + TBool isActiveTab = iTabArray->At( ConvertTabIndex( ConvertTabIndex( newTab ) ) )->Active(); + TTouchFeedbackType type = static_cast(ETouchFeedbackAudio | ETouchFeedbackVibra); + if ( feedback && !isActiveTab ) + { + feedback->InstantFeedback( this, + ETouchFeedbackTab, + type, + aPointerEvent ); + } + } + if ( !tabBackgroundUsed ) + { + // In one tab layout handle the navigation always by + // pointer position. + newTab = iActiveTab; + } + iExtension->iPointerDownTab = newTab; + iExtension->iPointerDownXPosition = aPointerEvent.iPosition.iX; + return; + } + else if ( aPointerEvent.iType == TPointerEvent::EButton1Up ) + { + if( newTab> -1 ) + { + MTouchFeedback* feedback = MTouchFeedback::Instance(); + + // Feedback is given only if new tab wasn't already active + // Use two convertTabIndex to cancel the mirror effects, because the newTab is always the phsical index. + TBool isActiveTab = iTabArray->At( ConvertTabIndex( ConvertTabIndex( newTab ) ) )->Active(); + if ( feedback && !isActiveTab ) + { + feedback->InstantFeedback( this, + ETouchFeedbackTab, + ETouchFeedbackVibra, + aPointerEvent ); + } + } + if ( !tabBackgroundUsed ) + { + // In one tab layout handle the navigation always by + // pointer position. + newTab = -1; + } + + // if the button up event occurs ouside tabgroup, ignore it. + if ( !Rect().Contains( aPointerEvent.iPosition ) || iExtension->iPointerDownTab != newTab ) + { + iExtension->iPointerDownTab = -1; + iExtension->iPointerDownXPosition = -1; + return ; + } + + if ( newTab != iActiveTab && + newTab > -1 && + newTab == iExtension->iPointerDownTab && + iNumberOfTabsShown > 1 ) + { + if ( iTabObserver ) + { + TDirection direction = newTab > iActiveTab ? ERight : ELeft; + + CancelTabAnimationEventTimer(); + + StartCycleAnimationL( direction, newTab ); + + SetActiveTabByIndex( ConvertTabIndex( newTab ) ); + + iTabObserver->TabChangedL( ConvertTabIndex( newTab ) ); + } + + else + { + // Kludge: if there is no tab observer, we need to + // generate a keyevent to the application so it knows + // to activate the correct view. + // + // The real fix would be to update applications to + // implement MAknTabObserver::TabChangedL and to + // activate the correct view there. + TInt tabsToSkip = newTab - iActiveTab; + TKeyEvent code; + code.iCode = EKeyRightArrow; + code.iModifiers = iEikonEnv->WsSession().GetModifierState(); + code.iRepeats = 0; // some applications are ignoring repeated events + if ( tabsToSkip < 0 ) + { + code.iCode = EKeyLeftArrow; + tabsToSkip = -tabsToSkip; + } + + for ( TInt i = 0; i < tabsToSkip; i++ ) + { + iEikonEnv->SimulateKeyEventL( code, EEventKey ); + } + } + } + else + { + if ( newTab != iExtension->iPointerDownTab && iExtension->iPointerDownTab > -1 ) + { + if ( newTab == -1 ) + { + if ( iExtension->iPointerDownXPosition + KDragNavigationTolerance < + aPointerEvent.iPosition.iX ) + { + newTab = iExtension->iPointerDownTab + 1; + } + else if ( iExtension->iPointerDownXPosition - KDragNavigationTolerance > + aPointerEvent.iPosition.iX ) + { + newTab = iExtension->iPointerDownTab - 1; + } + else + { + newTab = iExtension->iPointerDownTab; + } + } + + if ( iExtension->iPointerDownTab < newTab && + iActiveTab > LeftMostTabIndex() ) + { + if ( iTabObserver ) + { + CycleFocus( ELeft, EDrawNow ); + iTabObserver->TabChangedL( ConvertTabIndex( iActiveTab ) ); + } + else + { + // Kludge: if there is no tab observer generate a keyevent to + // instruct the application to change the view. + TKeyEvent code; + code.iCode = EKeyLeftArrow; + iEikonEnv->SimulateKeyEventL( code, EEventKey ); + } + } + else if ( iExtension->iPointerDownTab > newTab && + iActiveTab < RightMostTabIndex() ) + { + if ( iTabObserver ) + { + CycleFocus( ERight, EDrawNow ); + iTabObserver->TabChangedL( ConvertTabIndex( iActiveTab ) ); + } + else + { + // Kludge: if there is no tab observer generate a keyevent to + // instruct the application to change the view. + TKeyEvent code; + code.iCode = EKeyRightArrow; + iEikonEnv->SimulateKeyEventL( code, EEventKey ); + } + } + } + } + + iExtension->iPointerDownTab = -1; + iExtension->iPointerDownXPosition = -1; + } + } + } + + +EXPORT_C void* CAknTabGroup::ExtensionInterface( TUid /*aInterface*/ ) + { + return NULL; + } + + +// --------------------------------------------------------------------------- +// CAknTabGroup::SetTabMultiColorMode +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknTabGroup::SetTabMultiColorMode( TInt aTabId, + TBool aMultiColor ) + { + TInt tabIndex = ConvertTabIndex( TabIndexFromId( aTabId ) ); + if ( tabIndex >= 0 && tabIndex < TabCount() ) + { + iTabArray->At( tabIndex )->SetMultiColorMode( aMultiColor ); + } + } + + +TBool CAknTabGroup::CycleFocus( TDirection aDirection, TDrawNow /*aDrawNow*/ ) + { + if ( iActiveTab < 0 ) + { + return EFalse; + } + + if ( AknStatuspaneUtils::FlatLayoutActive() ) + { + SetDecoratorLayout( EFalse ); + } + else + { + CancelTabAnimationEventTimer(); + } + + TInt numTabs = TabCount(); + + if ( ( iActiveTab <= 0 ) && ( aDirection==ELeft ) ) + { + TInt event = MAknNavigationObserver::ENaviEventAlreadyLeftmostItem; + TRAP_IGNORE( ReportEventL( + static_cast( event ) ) ); + return EFalse; + } + else if ( ( iActiveTab >= ( numTabs - 1 ) ) && ( aDirection==ERight ) ) + { + TInt event = MAknNavigationObserver::ENaviEventAlreadyRightmostItem; + TRAP_IGNORE( ReportEventL( + static_cast( event ) ) ); + return EFalse; + } + + TInt tabIndex = ( aDirection == ERight ) ? iActiveTab + 1 : iActiveTab - 1; + + CAknTab* thisTab = (*iTabArray)[tabIndex]; + + // This starts the animation only if required. + TRAP_IGNORE( StartCycleAnimationL( aDirection, tabIndex ) ); + + (*iTabArray)[iActiveTab]->SetFocus( EFalse, ENoDrawNow ); + thisTab->SetFocus( ETrue, ENoDrawNow ); + + SetActiveTabByIndex( ConvertTabIndex( tabIndex ) ); + + return ETrue; + } + + +void CAknTabGroup::HandleTabStateChanged( CCoeControl* aControl ) + { + const TInt numTabs = TabCount(); + + if ( numTabs > 1 ) + { + CAknTab* newTab = static_cast( aControl ); + CArrayPtr& tabArray = *iTabArray; + + TInt ii = 0; + for( ; ii < numTabs; ii++ ) + { + if( tabArray[ii] == newTab ) + { + break; + } + } + + tabArray[iActiveTab]->SetFocus( EFalse, EDrawNow ); + SetActiveTabByIndex( ConvertTabIndex( ii ) ); + } + else + { + ReportNavigationEvent(); + } + } + + +TInt CAknTabGroup::Index( TInt aTabId ) const + { + const TInt numTabs = iTabArray->Count(); + + for (TInt ii = 0; ii < numTabs; ii++ ) + { + CAknTab* thisTab=iTabArray->At(ii); + if ( thisTab->Id() == aTabId ) + { + return ii; + } + } + return KErrNotFound; + } + + +// -------------------------------------------------------------------------- +// Returns the index of the leftmost tab in the tab group. +// -------------------------------------------------------------------------- +// +TInt CAknTabGroup::LeftMostTabIndex() const + { + TInt index = 0; + const TInt numTabs = TabCount(); + + while ( iTabArray->At( index )->IsDimmed() ) + { + if ( ++index >= numTabs ) + { + return KErrNotFound; + } + } + + return index; + } + + +// -------------------------------------------------------------------------- +// Returns the index of the rightmost tab in the tab group. +// -------------------------------------------------------------------------- +// +TInt CAknTabGroup::RightMostTabIndex() const + { + TInt index = TabCount() - 1; + + if ( index >= 0 ) + { + while ( iTabArray->At( index )->IsDimmed() ) + { + if ( --index < 0 ) + { + return KErrNotFound; + } + } + return index; + } + else + { + return KErrNotFound; + } + } + + +// --------------------------------------------------------------------------- +// Reports a navigation event to the navi pane decorator. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::ReportNavigationEvent() + { + TInt active = ConvertTabIndex( ActiveTabIndex() ); + TInt tabCount = TabCount(); + + TInt event = MAknNavigationObserver::ENaviEventHandleNavigation; + + if ( tabCount <= 1 ) + { + event = MAknNavigationObserver::ENaviEventOneItemExists; + } + else if ( active == 0 ) + { + event = MAknNavigationObserver::ENaviEventLeftMostItemReached; + } + else if ( active >= ( tabCount - 1 ) ) + { + event = MAknNavigationObserver::ENaviEventRightMostItemReached; + } + + TRAP_IGNORE( ReportEventL( + static_cast( event ) ) ); + } + + +void CAknTabGroup::LoadTabBitmapsL( TInt aNumberOfTabsShown, TBool aLongTabs ) + { + TInt i = 0; + for ( i = 0; i < KTabNumberOfTabBitmaps; i++ ) + { + delete( iTabBitmaps[i] ); + iTabBitmaps[i] = NULL; + delete( iTabMaskBitmaps[i] ); + iTabMaskBitmaps[i] = NULL; + } + + TInt first = KErrNotFound; // Bitmap indexes to bitmap name array + TInt last = KErrNotFound; + + // Figures out what tab background bitmaps are needed. + if ( aNumberOfTabsShown == 1 ) + { + return; + } + else if ( aNumberOfTabsShown == 2 ) + { + if ( aLongTabs ) + { + first = KTabIndexOfFirstTabBitmapInTwoLongTabsSet; + last = KTabIndexOfLastTabBitmapInTwoLongTabsSet; + } + else + { + first = KTabIndexOfFirstTabBitmapInTwoTabsSet; + last = KTabIndexOfLastTabBitmapInTwoTabsSet; + } + } + else if ( aNumberOfTabsShown == 3 ) + { + if ( aLongTabs ) + { + first = KTabIndexOfFirstTabBitmapInThreeLongTabsSet; + last = KTabIndexOfLastTabBitmapInThreeLongTabsSet; + } + else + { + first = KTabIndexOfFirstTabBitmapInThreeTabsSet; + last = KTabIndexOfLastTabBitmapInThreeTabsSet; + } + } + else if ( aNumberOfTabsShown == 4 ) + { + first = KTabIndexOfFirstTabBitmapInFourTabsSet; + last = KTabIndexOfLastTabBitmapInFourTabsSet; + } + + if ( first < 0 ) + { + return; + } + + TRect rect( ParentRect( iExtension->iNaviArrowsUsed ) ); + + if ( iExtension && + iExtension->iTabSvgGraphics && + iExtension->iTabSvgGraphics->TabGroupBackgroundAvailable() ) + { + // The background graphics are no more created in this case, instead + // backgrounds are drawn to a single double buffer + // (and other double buffer for stacon). + CAknTabGroupGraphics* tabgraphics = iExtension->iTabSvgGraphics; + + tabgraphics->SetTabGroupBackgroundParent( + ParentRect( iExtension->iNaviArrowsUsed ) ); + } + else + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + TAknWindowLineLayout layout; + CurrentLayout( layout ); + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( rect, layout ); + TSize size ( layoutRect.Rect().Size() ); + + // This code is for legacy bitmaps, we should newer go here anymore. + if ( skin ) + { + for ( i = first; i <= last; i++ ) + { + TAknsItemID iid; + iid.Set( EAknsMajorAvkon, iBitmapNames[i] ); + AknsUtils::CreateIconL( skin, + iid, + iTabBitmaps[i], + iTabMaskBitmaps[i], + KAvkonBitmapFile, + iBitmapNames[i], + iBitmapMaskNames[i] ); + + AknIconUtils::SetSize( iTabBitmaps[i], + size, + EAspectRatioNotPreserved ); + } + } + else + { + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( rect, + AknLayoutScalable_Avkon::navi_tabs_2_pane() ); + + // Loads only those tab background bitmaps that are needed. + for ( i = first; i <= last; i++ ) + { + // Delete (in case skin loading created some bitmaps) + delete iTabBitmaps[i]; + iTabBitmaps[i] = NULL; + delete iTabMaskBitmaps[i]; + iTabMaskBitmaps[i] = NULL; + + AknIconUtils::CreateIconL( iTabBitmaps[i], + iTabMaskBitmaps[i], + KAvkonBitmapFile, + iBitmapNames[i], + iBitmapMaskNames[i] ); + + // Validate all loaded bitmaps by setting their sizes. + AknIconUtils::SetSize( iTabBitmaps[i], + layoutRect.Rect().Size(), + EAspectRatioNotPreserved ); + } + } + } + + InitTabAnimationL(); + } + + +void CAknTabGroup::HandleResourceChange( TInt aType ) + { + // First forward event to child controls, + // skin change must be forwarded to ALL tabs... + if( aType == KAknsMessageSkinChange || aType == KEikColorResourceChange ) + { + TInt numTabs = TabCount(); + for ( TInt i = 0; i < numTabs; i++ ) + { + iTabArray->At(i)->HandleResourceChange( aType ); + } + } + else + { + CCoeControl::HandleResourceChange( aType ); + } + + // ...now handle events + if ( aType == KAknsMessageSkinChange ) + { + // If this fails, svg tab graphics are not available. + // Then defaults to bitmaps if possible. + TRAP_IGNORE( InitTabGroupGraphicsL() ); + TRAP_IGNORE( LoadTabBitmapsL( iNumberOfTabsShown, iLongTabs ) ); + } + + if ( aType == KEikDynamicLayoutVariantSwitch ) + { + // If double buffers are used in this layout, + // then initialize its layouts at this point. + if ( iExtension && + iExtension->iTabSvgGraphics && + iExtension->iTabSvgGraphics->TabGroupBackgroundAvailable() ) + { + TRAP_IGNORE( SwitchTabLayoutL() ); + + iExtension->iTabSvgGraphics->SetTabGroupBackgroundParent( + ParentRect( iExtension->iNaviArrowsUsed ) ); + + iExtension->iTabBackgroundLayout.iUse = EFalse; + TRAP_IGNORE( iExtension->iTabSvgGraphics->DrawTabGroupBackgroundL( + CAknTabGroupGraphics::ENoDraw, + iLongTabs, + iNumberOfTabsShown, + 1, + NULL, + iExtension->iTabBackgroundLayout, + CAknTabGroupGraphics::ENone ) ); + iExtension->iTabBackgroundLayout.iUse = ETrue; + SetDecoratorLayout( EFalse ); + } + + if ( iExtension ) + { + iExtension->iNarrowTabLayout = EFalse; + } + + if ( !COMPARE_BOOLS( iMirrored, AknLayoutUtils::LayoutMirrored() ) ) + { + TInt active = ActiveTabIndex(); + TRAPD( err, ReverseTabOrderL() ); + if ( err == KErrNone ) + { + iMirrored = AknLayoutUtils::LayoutMirrored(); + SetActiveTabByIndex( active ); + } + } + + SizeChanged(); + TRAP_IGNORE( LoadTabBitmapsL( iNumberOfTabsShown, iLongTabs ) ); + } + } + + +TBool CAknTabGroup::TabsVisibleInCurrentLayout() const + { + TBool tabsVisible = ETrue; + + // Tabs are not shown in idle layouts and in portrait flat + // status pane layout because there's not enough space. + if ( AknStatuspaneUtils::IdleLayoutActive() || + ( AknStatuspaneUtils::FlatLayoutActive() && + !Layout_Meta_Data::IsLandscapeOrientation() ) ) + { + tabsVisible = EFalse; // No tabs shown + } + + return tabsVisible; + } + + +void CAknTabGroup::CurrentLayout( TAknWindowLineLayout& aLayout ) const + { + TAknWindowLineLayout layout( AknLayoutScalable_Avkon::navi_tabs_2_pane() ); + + if ( iLongTabs ) + { + switch ( iNumberOfTabsShown ) + { + case 3: + { + layout = AknLayoutScalable_Avkon::navi_tabs_3_long_pane(); + break; + } + default: + { + layout = AknLayoutScalable_Avkon::navi_tabs_2_long_pane(); + break; + } + } + } + else + { + switch ( iNumberOfTabsShown ) + { + case 4: + { + layout = AknLayoutScalable_Avkon::navi_tabs_4_pane(); + break; + } + case 3: + { + layout = AknLayoutScalable_Avkon::navi_tabs_3_pane(); + break; + } + default: + { + break; + } + } + } + + aLayout = layout; + } + + +// --------------------------------------------------------------------------- +// Handles navication decorator events scrolling tabs to left/right +// Depending on event +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknTabGroup::HandleNaviDecoratorEventL( TInt aEventID ) + { + if ( AknLayoutUtils::PenEnabled() ) + { + switch ( aEventID ) + { + case MAknNaviDecoratorObserver::EAknNaviDecoratorEventLeftTabArrow: + { + if ( iTabObserver ) + { + if ( iActiveTab != LeftMostTabIndex() ) + { + CycleFocus( ELeft, EDrawNow ); + } + iTabObserver->TabChangedL( ConvertTabIndex( iActiveTab ) ); + } + else + { + // Kludge: if there is no tab observer generate a keyevent to + // instruct the application to change the view. + TKeyEvent code; + code.iCode = EKeyLeftArrow; + iEikonEnv->SimulateKeyEventL( code, EEventKey ); + } + } + break; + + case MAknNaviDecoratorObserver::EAknNaviDecoratorEventRightTabArrow: + { + if ( iTabObserver ) + { + if ( iActiveTab != RightMostTabIndex() ) + { + CycleFocus( ERight, EDrawNow ); + } + iTabObserver->TabChangedL( ConvertTabIndex( iActiveTab ) ); + } + else + { + // Kludge: if there is no tab observer generate a keyevent to + // instruct the application to change the view. + TKeyEvent code; + code.iCode = EKeyRightArrow; + iEikonEnv->SimulateKeyEventL( code, EEventKey ); + } + } + break; + + default: + break; + } + } + } + +EXPORT_C void CAknTabGroup::Reserved1() + { + } + +EXPORT_C void CAknTabGroup::Reserved2() + { + } + +EXPORT_C void CAknTabGroup::Reserved3() + { + } + +void CAknTabGroup::InitTabGroupGraphicsL() + { + if ( iExtension && iExtension->iTabSvgGraphics ) + { + delete iExtension->iTabSvgGraphics; + iExtension->iTabSvgGraphics = NULL; + iExtension->iTabSvgGraphics = CAknTabGroupGraphics::NewL(); + } + } + + +// --------------------------------------------------------------------------- +// Starts the animation timer. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::InitTabAnimationEventTimer() + { + TInt delay = 1; + iExtension->iTabAnimationTimer->Cancel(); + iExtension->iTabAnimationTimer->Start( + TTimeIntervalMicroSeconds32( delay ), + TTimeIntervalMicroSeconds32( KAnimationEventInterval ), + TCallBack( CAknTabGroup::TabAnimationEvent, this ) ); + } + + +// --------------------------------------------------------------------------- +// Cancels the animation timer. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::CancelTabAnimationEventTimer() + { + if ( iExtension && + iExtension->iTabAnimationTimer && + iExtension->iTabAnimationTimer->IsActive() ) + { + iExtension->iTabAnimationTimer->Cancel(); + iExtension->iAmountOfDoneAnimationEvents = 0; + + if ( iExtension->iTabAnimationType == + CAknTabGroupExtension::ETabCycleAnimation ) + { + iExtension->iTabCycleAnimationOngoing = EFalse; + + iExtension->iTabsHidden = CAknTabGroupGraphics::EOnBothSides; + if ( iFirstShownTab == 0 ) + { + iExtension->iTabsHidden = CAknTabGroupGraphics::EOnRightSide; + } + else if ( iFirstShownTab == TabCount() - iNumberOfTabsShown ) + { + iExtension->iTabsHidden = CAknTabGroupGraphics::EOnLeftSide; + } + } + + iExtension->iTabAnimationType = + CAknTabGroupExtension::ENoAnimation; + } + } + +TInt CAknTabGroup::TabAnimationEvent( TAny* aPtr ) + { + static_cast( aPtr )->DoTabAnimationEvent(); + return ETrue; + } + + +// --------------------------------------------------------------------------- +// Animation timer callback. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::DoTabAnimationEvent() + { + // In this method we calculate the new positions of tabs during + // the animation cycle. + + // We do this safety check because of possible problems with layout data. + iExtension->iAmountOfDoneAnimationEvents++; + if ( iExtension->iAmountOfDoneAnimationEvents > KMaxAmountOfAnimationEvents ) + { + CancelTabAnimationEventTimer(); + SizeChanged(); + TRAP_IGNORE( InitTabAnimationL() ); + DrawDeferred(); + return; + } + + TBool firstDone = EFalse; + TBool secondDone = EFalse; + TBool thirdDone = EFalse; + TBool fourthDone = EFalse; + + if ( iExtension->iTabAnimationType == + CAknTabGroupExtension::ETabCycleAnimation ) + { + if ( iExtension->iAmountOfDoneAnimationEvents == 1 ) + { + // Calculate the initial distance to go on the first event. + iExtension->iTabCycleAnimationDistanceLeft = + iExtension->iTabBackgroundLayout.iSecondTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iLeft.iTl.iX; + } + + // Calculate the step size used in this frame, currently + // using ease-out. + TInt stepSize = iExtension->iTabCycleAnimationDistanceLeft / + KMinimumCycleAnimationStepSize; + + // Sanity check, ensure that animation doesn't move too slow. + if ( stepSize < KMinimumCycleAnimationStepSize ) + { + stepSize = KMinimumCycleAnimationStepSize; + } + + if ( iExtension->iTabCycleAnimationDirection == + CAknTabGroup::ERight ) + { + // Adjust the step size sign according to the direction + // we're moving to. + stepSize = -stepSize; + } + + // Decrease the distance left by the step size. + iExtension->iTabCycleAnimationDistanceLeft -= Abs( stepSize ); + + // Move the tabs. + iExtension->iTabSvgGraphics->AdjustTabLayoutRect( + iExtension->iNextTabBackgroundLayout.iHiddenTabLeft, stepSize, 0 ); + iExtension->iTabSvgGraphics->AdjustTabLayoutRect( + iExtension->iNextTabBackgroundLayout.iFirstTab, stepSize, 0 ); + iExtension->iTabSvgGraphics->AdjustTabLayoutRect( + iExtension->iNextTabBackgroundLayout.iSecondTab, stepSize, 0 ); + iExtension->iTabSvgGraphics->AdjustTabLayoutRect( + iExtension->iNextTabBackgroundLayout.iThirdTab, stepSize, 0 ); + iExtension->iTabSvgGraphics->AdjustTabLayoutRect( + iExtension->iNextTabBackgroundLayout.iHiddenTabRight, stepSize, 0 ); + } + else + { + // This seems to be quite ok speed for the animation. + TInt defaultStepSize = Rect().Width() / KLayoutSwitchAnimationSpeed; + + // Sanity check + if ( defaultStepSize == 0 ) + { + defaultStepSize = 1; + } + + // First find out where we are moving, how far is the destination. + TInt firstTabHorizontalDistanceLeft = + iExtension->iNextTabBackgroundLayout.iFirstTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iLeft.iTl.iX; + + TInt secondTabHorizontalDistanceLeft = + iExtension->iNextTabBackgroundLayout.iSecondTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iSecondTab.iLeft.iTl.iX; + + TInt thirdTabHorizontalDistanceLeft = + iExtension->iNextTabBackgroundLayout.iThirdTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iThirdTab.iLeft.iTl.iX; + + TInt fourthTabHorizontalDistanceLeft = + iExtension->iNextTabBackgroundLayout.iFourthTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iFourthTab.iLeft.iTl.iX; + + TInt firstTabHorizontalDistanceMiddle = + iExtension->iNextTabBackgroundLayout.iFirstTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iMiddle.iTl.iX; + + TInt secondTabHorizontalDistanceMiddle = + iExtension->iNextTabBackgroundLayout.iSecondTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iSecondTab.iMiddle.iTl.iX; + + TInt thirdTabHorizontalDistanceMiddle = + iExtension->iNextTabBackgroundLayout.iThirdTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iThirdTab.iMiddle.iTl.iX; + + TInt fourthTabHorizontalDistanceMiddle = + iExtension->iNextTabBackgroundLayout.iFourthTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iFourthTab.iMiddle.iTl.iX; + + TInt firstTabHorizontalDistanceRight = + iExtension->iNextTabBackgroundLayout.iFirstTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iRight.iTl.iX; + + TInt secondTabHorizontalDistanceRight = + iExtension->iNextTabBackgroundLayout.iSecondTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iSecondTab.iRight.iTl.iX; + + TInt thirdTabHorizontalDistanceRight = + iExtension->iNextTabBackgroundLayout.iThirdTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iThirdTab.iRight.iTl.iX; + + TInt fourthTabHorizontalDistanceRight = + iExtension->iNextTabBackgroundLayout.iFourthTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iFourthTab.iRight.iTl.iX; + + TInt usedStepSizeForFirstTabLeft = defaultStepSize; + TInt usedStepSizeForSecondTabLeft = defaultStepSize; + TInt usedStepSizeForThirdTabLeft = defaultStepSize; + TInt usedStepSizeForFourthTabLeft = defaultStepSize; + + TInt usedStepSizeForFirstTabMiddle = defaultStepSize; + TInt usedStepSizeForSecondTabMiddle = defaultStepSize; + TInt usedStepSizeForThirdTabMiddle = defaultStepSize; + TInt usedStepSizeForFourthTabMiddle = defaultStepSize; + + TInt usedStepSizeForFirstTabRight = defaultStepSize; + TInt usedStepSizeForSecondTabRight = defaultStepSize; + TInt usedStepSizeForThirdTabRight = defaultStepSize; + TInt usedStepSizeForFourthTabRight = defaultStepSize; + + + // If we are close to end, then adjust the step size. Also if we are moving to normal layout + // from narrow, do it with one big step. + if ( Abs( firstTabHorizontalDistanceLeft ) < Abs( usedStepSizeForFirstTabLeft ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForFirstTabLeft = Abs( firstTabHorizontalDistanceLeft ); + } + if ( Abs( firstTabHorizontalDistanceMiddle ) < Abs( usedStepSizeForFirstTabMiddle ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForFirstTabMiddle = Abs( firstTabHorizontalDistanceMiddle ); + } + if ( Abs( firstTabHorizontalDistanceRight ) < Abs( usedStepSizeForFirstTabRight ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForFirstTabRight = Abs( firstTabHorizontalDistanceRight ); + } + + if ( Abs( secondTabHorizontalDistanceLeft ) < Abs( usedStepSizeForSecondTabLeft ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForSecondTabLeft = Abs( secondTabHorizontalDistanceLeft ); + } + if ( Abs( secondTabHorizontalDistanceMiddle ) < Abs( usedStepSizeForSecondTabMiddle ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForSecondTabMiddle = Abs( secondTabHorizontalDistanceMiddle ); + } + if ( Abs( secondTabHorizontalDistanceRight ) < Abs( usedStepSizeForSecondTabRight ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForSecondTabRight = Abs( secondTabHorizontalDistanceRight ); + } + + if ( Abs( thirdTabHorizontalDistanceLeft ) < Abs( usedStepSizeForThirdTabLeft ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForThirdTabLeft = Abs(thirdTabHorizontalDistanceLeft); + } + if ( Abs( thirdTabHorizontalDistanceMiddle ) < Abs( usedStepSizeForThirdTabMiddle ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForThirdTabMiddle = Abs(thirdTabHorizontalDistanceMiddle); + } + if ( Abs( thirdTabHorizontalDistanceRight ) < Abs( usedStepSizeForThirdTabRight) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForThirdTabRight = Abs(thirdTabHorizontalDistanceRight); + } + + if ( Abs( fourthTabHorizontalDistanceLeft ) < Abs( usedStepSizeForFourthTabLeft ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForFourthTabLeft = Abs(fourthTabHorizontalDistanceLeft); + } + if ( Abs( fourthTabHorizontalDistanceMiddle ) < Abs( usedStepSizeForFourthTabMiddle ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForFourthTabMiddle = Abs(fourthTabHorizontalDistanceMiddle); + } + if ( Abs( fourthTabHorizontalDistanceRight ) < Abs( usedStepSizeForFourthTabRight ) || + !NarrowTabLayoutNext() ) + { + usedStepSizeForFourthTabRight = Abs(fourthTabHorizontalDistanceRight); + } + + + // First tab + if ( firstTabHorizontalDistanceLeft < 0 ) + { + usedStepSizeForFirstTabLeft = -usedStepSizeForFirstTabLeft; + } + + if ( firstTabHorizontalDistanceMiddle < 0 ) + { + usedStepSizeForFirstTabMiddle = -usedStepSizeForFirstTabMiddle; + } + + if ( firstTabHorizontalDistanceRight < 0 ) + { + usedStepSizeForFirstTabRight = -usedStepSizeForFirstTabRight; + } + + iExtension->iTabBackgroundLayout.iFirstTab.iLeft.Move( usedStepSizeForFirstTabLeft, 0 ); + iExtension->iTabBackgroundLayout.iFirstTab.iRight.Move( usedStepSizeForFirstTabRight, 0 ); + + iExtension->iTabBackgroundLayout.iFirstTab.iMiddle.iTl.iX = + iExtension->iTabBackgroundLayout.iFirstTab.iLeft.iBr.iX; + + iExtension->iTabBackgroundLayout.iFirstTab.iMiddle.iBr.iX = + iExtension->iTabBackgroundLayout.iFirstTab.iRight.iTl.iX; + + if ( ( iExtension->iNextTabBackgroundLayout.iFirstTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iLeft.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iFirstTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iMiddle.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iFirstTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iFirstTab.iRight.iTl.iX == 0 ) ) + { + firstDone = ETrue; + } + + // Second tab + if ( secondTabHorizontalDistanceLeft < 0 ) + { + usedStepSizeForSecondTabLeft = -usedStepSizeForSecondTabLeft; + } + if ( secondTabHorizontalDistanceMiddle < 0 ) + { + usedStepSizeForSecondTabMiddle = -usedStepSizeForSecondTabMiddle; + } + if ( secondTabHorizontalDistanceRight < 0 ) + { + usedStepSizeForSecondTabRight = -usedStepSizeForSecondTabRight; + } + + iExtension->iTabBackgroundLayout.iSecondTab.iLeft.Move(usedStepSizeForSecondTabLeft,0); + iExtension->iTabBackgroundLayout.iSecondTab.iRight.Move(usedStepSizeForSecondTabRight,0); + + iExtension->iTabBackgroundLayout.iSecondTab.iMiddle.iTl.iX = + iExtension->iTabBackgroundLayout.iSecondTab.iLeft.iBr.iX; + + iExtension->iTabBackgroundLayout.iSecondTab.iMiddle.iBr.iX = + iExtension->iTabBackgroundLayout.iSecondTab.iRight.iTl.iX; + + if ( ( iExtension->iNextTabBackgroundLayout.iSecondTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iSecondTab.iLeft.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iSecondTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iSecondTab.iMiddle.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iSecondTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iSecondTab.iRight.iTl.iX == 0 ) ) + { + secondDone = ETrue; + } + + // Third tab + if ( thirdTabHorizontalDistanceLeft < 0 ) + { + usedStepSizeForThirdTabLeft = -usedStepSizeForThirdTabLeft; + } + if ( thirdTabHorizontalDistanceMiddle < 0 ) + { + usedStepSizeForThirdTabMiddle = -usedStepSizeForThirdTabMiddle; + } + if ( thirdTabHorizontalDistanceRight < 0 ) + { + usedStepSizeForThirdTabRight = -usedStepSizeForThirdTabRight; + } + + iExtension->iTabBackgroundLayout.iThirdTab.iLeft.Move(usedStepSizeForThirdTabLeft,0); + iExtension->iTabBackgroundLayout.iThirdTab.iRight.Move(usedStepSizeForThirdTabRight,0); + + iExtension->iTabBackgroundLayout.iThirdTab.iMiddle.iTl.iX = + iExtension->iTabBackgroundLayout.iThirdTab.iLeft.iBr.iX; + + iExtension->iTabBackgroundLayout.iThirdTab.iMiddle.iBr.iX = + iExtension->iTabBackgroundLayout.iThirdTab.iRight.iTl.iX; + + if ( ( iExtension->iNextTabBackgroundLayout.iThirdTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iThirdTab.iLeft.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iThirdTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iThirdTab.iMiddle.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iThirdTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iThirdTab.iRight.iTl.iX == 0 ) ) + { + thirdDone = ETrue; + } + + // Fourth tab + if ( fourthTabHorizontalDistanceLeft < 0 ) + { + usedStepSizeForFourthTabLeft = -usedStepSizeForFourthTabLeft; + } + if ( fourthTabHorizontalDistanceMiddle < 0 ) + { + usedStepSizeForFourthTabMiddle = -usedStepSizeForFourthTabMiddle; + } + if ( fourthTabHorizontalDistanceRight < 0 ) + { + usedStepSizeForFourthTabRight = -usedStepSizeForFourthTabRight; + } + + iExtension->iTabBackgroundLayout.iFourthTab.iLeft.Move( + usedStepSizeForFourthTabLeft, 0 ); + iExtension->iTabBackgroundLayout.iFourthTab.iRight.Move( + usedStepSizeForFourthTabRight, 0 ); + iExtension->iTabBackgroundLayout.iFourthTab.iMiddle.iTl.iX = + iExtension->iTabBackgroundLayout.iFourthTab.iLeft.iBr.iX; + iExtension->iTabBackgroundLayout.iFourthTab.iMiddle.iBr.iX = + iExtension->iTabBackgroundLayout.iFourthTab.iRight.iTl.iX; + + if ( ( iExtension->iNextTabBackgroundLayout.iFourthTab.iLeft.iTl.iX - + iExtension->iTabBackgroundLayout.iFourthTab.iLeft.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iFourthTab.iMiddle.iTl.iX - + iExtension->iTabBackgroundLayout.iFourthTab.iMiddle.iTl.iX == 0 ) && + ( iExtension->iNextTabBackgroundLayout.iFourthTab.iRight.iTl.iX - + iExtension->iTabBackgroundLayout.iFourthTab.iRight.iTl.iX == 0 ) ) + { + fourthDone = ETrue; + } + } + + // Then lets adjust the tab content to right places. + if ( NarrowTabLayoutNext() ) + { + TBool refreshTabs = iExtension->iNarrowTabLayout; + iExtension->iNarrowTabLayout = ETrue; + if ( refreshTabs ) + { + SizeChanged(); + } + } + else + { + TBool refreshTabs = !iExtension->iNarrowTabLayout; + iExtension->iNarrowTabLayout = EFalse; + if ( refreshTabs ) + { + SizeChanged(); + } + } + + // Check if we are done with the animation + if ( firstDone && secondDone && thirdDone && fourthDone || + ( iExtension->iTabAnimationType == CAknTabGroupExtension::ETabCycleAnimation && + iExtension->iTabCycleAnimationDistanceLeft <= 0 ) ) + { + CancelTabAnimationEventTimer(); // done + SizeChanged(); + } + + // Finally draw the tabs to their new places. Note that drawing must draw + // tabs little differently in this animated case. See Draw() method. + TRAP_IGNORE( InitTabAnimationL() ); + + DrawDeferred(); + } + + +// --------------------------------------------------------------------------- +// Sets the narrow/normal layout state of the tab group. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SetNarrowTabLayoutL( TBool aNarrow, TBool aUseAnimation ) + { + if ( iExtension->iTabCycleAnimationOngoing ) + { + // Narrow tab layout is not currently supported in touch layouts + // and this may should not be called during tab cycle animation. + return; + } + + if ( !aUseAnimation ) + { + // Switch the layout directly without using the animation. + iExtension->iNarrowTabLayout = aNarrow; + iExtension->iTabAnimationType = + CAknTabGroupExtension::ENoAnimation; + } + else + { + iExtension->iTabAnimationType = + CAknTabGroupExtension::ELayoutSwitchAnimation; + } + + iExtension->iNarrowTabLayoutNext = aNarrow; + + iExtension->iTabSvgGraphics->SetTabGroupBackgroundParent( + ParentRect( iExtension->iNaviArrowsUsed ) ); + + // Calculate new destination positions for animated tabs. + TInt positionActive = iActiveTab - iFirstShownTab; + if ( aNarrow ) + { + iExtension->iNextTabBackgroundLayout.iUse = EFalse; + iExtension->iTabSvgGraphics->DrawTabGroupNarrowBackgroundL( + CAknTabGroupGraphics::ENoDraw, + iLongTabs, + iNumberOfTabsShown, + positionActive + 1, + NULL, + iExtension->iNextTabBackgroundLayout ); + iExtension->iNextTabBackgroundLayout.iUse = ETrue; + + if ( !aUseAnimation ) + { + iExtension->iTabBackgroundLayout.iUse = EFalse; + iExtension->iTabSvgGraphics->DrawTabGroupNarrowBackgroundL( + CAknTabGroupGraphics::ENoDraw, + iLongTabs, + iNumberOfTabsShown, + positionActive + 1, + NULL, + iExtension->iTabBackgroundLayout ); + iExtension->iTabBackgroundLayout.iUse = ETrue; + } + } + else + { + iExtension->iNextTabBackgroundLayout.iUse = EFalse; + iExtension->iTabSvgGraphics->DrawTabGroupBackgroundL( + CAknTabGroupGraphics::ENoDraw, + iLongTabs, + iNumberOfTabsShown, + positionActive + 1, + NULL, + iExtension->iNextTabBackgroundLayout, + CAknTabGroupGraphics::ENone ); + iExtension->iNextTabBackgroundLayout.iUse = ETrue; + + iExtension->iTabBackgroundLayout.iUse = EFalse; + iExtension->iTabSvgGraphics->DrawTabGroupBackgroundL( + CAknTabGroupGraphics::ENoDraw, + iLongTabs, + iNumberOfTabsShown, + positionActive + 1, + NULL, + iExtension->iTabBackgroundLayout, + CAknTabGroupGraphics::ENone ); + iExtension->iTabBackgroundLayout.iUse = ETrue; + } + + InitTabAnimationL(); + + if ( AknStatuspaneUtils::FlatLayoutActive() ) + { + InitTabAnimationEventTimer(); + } + else + { + CancelTabAnimationEventTimer(); + } + } + + +// --------------------------------------------------------------------------- +// Sets the tab group internal state of the navi arrow visibility. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SetNaviArrowsVisible( TBool aVisible ) + { + if ( iExtension ) + { + iExtension->iNaviArrowsUsed = aVisible; + } + } + + +TBool CAknTabGroup::NarrowTabLayoutNext() + { + return iExtension && iExtension->iNarrowTabLayoutNext; + } + +TBool CAknTabGroup::NarrowTabLayout() + { + return iExtension && iExtension->iNarrowTabLayout; + } + + +// --------------------------------------------------------------------------- +// Sets the layout of the navi decorator to match the current +// tab group layout. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SetDecoratorLayout( TBool aNarrow ) + { + CEikStatusPaneBase* statusPane = CEikStatusPaneBase::Current(); + CAknNavigationControlContainer* naviPane = NULL; + CAknNavigationDecorator* decorator = NULL; + + if ( statusPane ) + { + CCoeControl* control = NULL; + TRAPD( err, control = statusPane->ControlL( + TUid::Uid( EEikStatusPaneUidNavi ) ) ); + + if ( !err && control ) + { + // Control cannot be casted directly because someone may have + // swapped the control. Use this workaround instead. + control->MopGetObject( naviPane ); + if ( naviPane ) + { + decorator = naviPane->Top(); + if ( decorator && decorator->DecoratedControl() != this ) + { + decorator = NULL; + } + } + } + } + + // Check first that application has not forced any layout mode. + if ( aNarrow ) + { + if ( decorator && + decorator->NaviControlLayoutMode() == + CAknNavigationDecorator::ENaviControlLayoutModeAutomatic ) + { + decorator->SetNaviControlLayoutStyle( + CAknNavigationDecorator::ENaviControlLayoutNarrow ); + } + } + else + { + if ( decorator && + decorator->NaviControlLayoutMode() == + CAknNavigationDecorator::ENaviControlLayoutModeAutomatic ) + { + decorator->SetNaviControlLayoutStyle( + CAknNavigationDecorator::ENaviControlLayoutNormal ); + } + } + + // Only use tab arrows in non-touch layouts and in the one tab layout. + TBool naviArrowsShouldBeVisible( iTabFixedWidth == KTabWidthWithOneTab || + !AknLayoutUtils::PenEnabled() ); + if ( decorator && + !COMPARE_BOOLS( decorator->ScrollButtonVisible(), naviArrowsShouldBeVisible ) ) + { + decorator->MakeScrollButtonVisible( naviArrowsShouldBeVisible ); + } + else + { + if ( iExtension ) + { + // Ensure that the value here is correct if navi decorator + // already has it correct. + iExtension->iNaviArrowsUsed = naviArrowsShouldBeVisible; + } + } + + // After this method call decorator will set this class size right by + // calling us back at CAknTabGroup::SetNarrowTabLayoutL(). + // If decorator does not exist we call ourself SetNarrowTabLayout. + if ( !decorator ) + { + TRAP_IGNORE( SetNarrowTabLayoutL( aNarrow ) ); + } + } + + +// --------------------------------------------------------------------------- +// Creates if necessary and draws the tab group background double buffer. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::InitTabAnimationL() + { + TRect rect( ParentRect( iExtension->iNaviArrowsUsed ) ); + + TSize size( rect.iBr.iX, rect.iBr.iY ); + + if ( size.iHeight <= 0 || size.iWidth <= 0 ) + { + size = rect.Size(); + } + + TInt positionActive = iActiveTab - iFirstShownTab; + + TBool penEnabled( AknLayoutUtils::PenEnabled() ); + + if ( penEnabled && iTabFixedWidth == KTabWidthWithThreeTabs ) + { + // It's ensured here that the focused tab background graphic is drawn + // behind the middle tab in touch layouts when using three tab + // layout, if the currently active tab is not the leftmost or + // rightmost tab. + if ( iActiveTab != RightMostTabIndex() && + iActiveTab != LeftMostTabIndex() ) + { + positionActive = 1; + } + } + + if ( !iExtension->iNarrowTabLayout ) + { + TInt tabCount = TabCount(); + iExtension->iTabsHidden = CAknTabGroupGraphics::ENone; + TBool animationOngoing( iExtension->iTabCycleAnimationOngoing ); + TBool firstAnimationUpdate( animationOngoing + && iExtension->iAmountOfDoneAnimationEvents == 0 ); + + if ( tabCount > iNumberOfTabsShown && penEnabled ) + { + iExtension->iTabsHidden = CAknTabGroupGraphics::ETwoOnBothSides; + if ( animationOngoing && + ( ( iFirstShownTab == 0 && + iExtension->iTabCycleAnimationDirection == ELeft ) || + ( iFirstShownTab == tabCount - ( iNumberOfTabsShown ) && + iExtension->iTabCycleAnimationDirection == ERight ) ) ) + { + iExtension->iTabsHidden = CAknTabGroupGraphics::EOnBothSides; + } + else if ( iActiveTab < iNumberOfTabsShown && + ( ( iFirstShownTab == 0 && + !animationOngoing ) || + firstAnimationUpdate && + iExtension->iTabCycleAnimationDirection == ERight ) ) + { + iExtension->iTabsHidden = CAknTabGroupGraphics::EOnRightSide; + } + else if ( iActiveTab >= tabCount - ( iNumberOfTabsShown ) && + ( ( !animationOngoing && + iFirstShownTab == tabCount - ( iNumberOfTabsShown ) ) || + firstAnimationUpdate && + iExtension->iTabCycleAnimationDirection == ELeft ) ) + { + iExtension->iTabsHidden = CAknTabGroupGraphics::EOnLeftSide; + } + } + + if (firstAnimationUpdate) + { + iExtension->iNextTabBackgroundLayout.iUse = EFalse; + } + else + { + iExtension->iNextTabBackgroundLayout.iUse = ETrue; + } + + } + + iExtension->iTabAnimationDoubleBufferNarrowTabLayout + = iExtension->iNarrowTabLayout; + iExtension->iTabAnimationDoubleBufferNumberOfTabsShown + = iNumberOfTabsShown; + iExtension->iTabAnimationDoubleBufferpositionActive = positionActive; + iExtension->iTabAnimationDoubleBufferLongTabs = iLongTabs; + + iExtension->iTabBackgroundLayout.iUse = ETrue; + } + + +// --------------------------------------------------------------------------- +// Gets the tab group's parent rectangle. +// --------------------------------------------------------------------------- +// +TRect CAknTabGroup::ParentRect( TBool aArrowsUsed ) + { + TBool scaled( ETrue ); + + if ( !AknLayoutUtils::PenEnabled() ) + { + CEikStatusPaneBase* statusPane = CEikStatusPaneBase::Current(); + + if ( statusPane ) + { + // In portrait mode the tab group needs to be adjacent + // the bottom of the navi pane. + TInt layoutResId = statusPane->CurrentLayoutResId(); + if ( layoutResId == R_AVKON_STATUS_PANE_LAYOUT_USUAL_EXT || + layoutResId == R_AVKON_STATUS_PANE_LAYOUT_EMPTY ) + { + scaled = EFalse; + } + } + } + + TRect parentRect( + CAknNavigationDecorator::DecoratedTabControlRect( scaled, + aArrowsUsed ) ); + + return parentRect; + } + + +// --------------------------------------------------------------------------- +// Starts the tab group cycle animation. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::StartCycleAnimationL( TDirection aDirection, + TInt aNewTab ) + { + TInt tabCount( TabCount() ); + + // First check if the animation should be used. + // The cycle animation is currently used only in following situation: + // 1) The three tab layout is active. + // 2) Touch layout is used. + // 3) Cycling the focus changes the first shown tab of the tab group. + // + if ( iTabFixedWidth == KTabWidthWithThreeTabs && // 1 + AknLayoutUtils::PenEnabled() && // 2 + tabCount > iNumberOfTabsShown && + ( ( iActiveTab > 0 && iActiveTab < tabCount - 2 && // 3 + aDirection == ERight ) || + ( iActiveTab > 1 && iActiveTab < tabCount - 1 && // 3 + aDirection == ELeft ) || + ( iActiveTab == 0 && // 3 + aNewTab == ( iNumberOfTabsShown - 1 ) ) || + ( iActiveTab == tabCount - 1 && // 3 + aNewTab == tabCount - iNumberOfTabsShown ) ) ) + { + iExtension->iTabAnimationType = + CAknTabGroupExtension::ETabCycleAnimation; + + iExtension->iTabCycleAnimationOngoing = ETrue; + iExtension->iTabCycleAnimationDirection = aDirection; + + iExtension->iTabSvgGraphics->SetTabGroupBackgroundParent( + ParentRect( iExtension->iNaviArrowsUsed ) ); + + iExtension->iNextTabBackgroundLayout.iUse = EFalse; + + InitTabAnimationEventTimer(); + } + } + + +// --------------------------------------------------------------------------- +// Switches the current tab layout to one that is usable in the current +// layout. +// --------------------------------------------------------------------------- +// +void CAknTabGroup::SwitchTabLayoutL() + { + TBool penEnabled( AknLayoutUtils::PenEnabled() ); + + if ( penEnabled && ( iTabFixedWidth == KTabWidthWithTwoLongTabs || + iTabFixedWidth == KTabWidthWithThreeLongTabs || + iTabFixedWidth == KTabWidthWithFourTabs ) ) + { + // If the current tab width is not supported in touch + // layout then switch it to a corresponding one. + SetTabFixedWidthL( iTabFixedWidth ); + } + else if ( iExtension && iTabFixedWidth != iExtension->iRequestedTabWidth ) + { + // Else try to set the requested width if it's supported in + // the new layout. + SetTabFixedWidthL( iExtension->iRequestedTabWidth ); + } + else + { + // Nothing to do. + return; + } + + // Set the correct focus if tab width is changed in layout + // switch. + if ( iActiveTab >= 0 ) + { + if ( penEnabled && iTabFixedWidth == KTabWidthWithThreeTabs ) + { + if ( iActiveTab != RightMostTabIndex() && + iActiveTab != LeftMostTabIndex() ) + { + iFirstShownTab = iActiveTab - 1; + } + else if ( iActiveTab < iFirstShownTab ) + { + iFirstShownTab = iActiveTab; + } + else if ( iActiveTab >= ( iFirstShownTab + iNumberOfTabsShown ) ) + { + iFirstShownTab = iActiveTab - iNumberOfTabsShown + 1; + } + } + else + { + if ( iActiveTab < iFirstShownTab ) + { + iFirstShownTab = iActiveTab; + } + + if ( iActiveTab >= ( iFirstShownTab + iNumberOfTabsShown ) ) + { + iFirstShownTab = iActiveTab - iNumberOfTabsShown + 1; + } + } + SizeChanged(); + } + + CancelTabAnimationEventTimer(); + } + + // End of File