diff -r 5315654608de -r 08c6ee43b396 taskswitcher/teleportui/hgteleportapp/src/hgteleportfastswaparea.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/taskswitcher/teleportui/hgteleportapp/src/hgteleportfastswaparea.cpp Mon Jan 18 20:10:36 2010 +0200 @@ -0,0 +1,1642 @@ +/* + * ============================================================================ + * Name : hgteleportfastswaparea.cpp + * Part of : Hg Teleport + * Description : Teleport Fast Swap area UI + * Version : %version: sa1spcx1#74 % + * + * Copyright © 2008 Nokia. All rights reserved. + * This material, including documentation and any related computer + * programs, is protected by copyright controlled by Nokia. All + * rights are reserved. Copying, including reproducing, storing, + * adapting or translating, any or all of this material requires the + * prior written consent of Nokia. This material also contains + * confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * ============================================================================ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hgteleportfastswaparea.h" +#include "hgteleportapplogging.h" +#include "hgfswclient.h" +#include "hgteleportappui.h" +#include "hgteleportdatachangeobserver.h" +#include "hgteleporteventcontroler.h" + +/** command ids for the fsw popup */ +enum TPopupCommands + { + EFswCmdClose = 10000, + EFswCmdCloseAll + }; + +/** Number of closable applications, to show "close all" option. */ +const TInt KHgMaxClosableApps = 2; + +/** Interval until which no change in the fsw content is rendered + after starting the closing of an application. */ +const TInt KRefreshDelayAfterClose = 2; // seconds + +/** Uid of Active Idle application. + Used when movind Ai to specified position.*/ +const TUid KAiUid = TUid::Uid( 0x102750F0 ); + +/** Position of Ai in fsw grid.*/ +const TInt KAiPosition = 0; + +/** Default grid item to highlight.*/ +const TInt KItemToHighlight = 3; + +const TInt KAppKeyTypeShort = 1; +const TInt KAppKeyTypeLong = 2; + +const TInt KLayoutItemCount = 3; + +const TInt KRedrawTime = 250000; // 0.25 sec +const TInt KHighlighActivationTime = 100000; // 100 ms +const TInt KUpdateGridTime = 1000000; // 1 s + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::NewL +// ----------------------------------------------------------------------------- +// +CHgTeleportFastSwapArea* CHgTeleportFastSwapArea::NewL( const TRect& aRect, + CCoeControl& aParent, CHgTeleportDeviceState& aDeviceState, + CHgTeleportEventControler& aEventHandler ) + { + CHgTeleportFastSwapArea* self = CHgTeleportFastSwapArea::NewLC(aRect, + aParent, aDeviceState, aEventHandler); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::NewLC +// ----------------------------------------------------------------------------- +// +CHgTeleportFastSwapArea* CHgTeleportFastSwapArea::NewLC( const TRect& aRect, + CCoeControl& aParent, CHgTeleportDeviceState& aDeviceState, + CHgTeleportEventControler& aEventHandler) + { + CHgTeleportFastSwapArea* self = new (ELeave) CHgTeleportFastSwapArea( + aParent, aDeviceState, aEventHandler); + CleanupStack::PushL( self ); + self->ConstructL( aRect ); + return self; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CHgTeleportFastSwapArea +// ----------------------------------------------------------------------------- +// +CHgTeleportFastSwapArea::CHgTeleportFastSwapArea(CCoeControl& aParent, + CHgTeleportDeviceState& aDeviceState, + CHgTeleportEventControler& aEventHandler) : + iParent(aParent), iDeviceState(aDeviceState), iEvtHandler(aEventHandler), + iPreviousNoOfItems(0) + { + // no implementation required + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::~CHgTeleportFastSwapArea +// ----------------------------------------------------------------------------- +// +CHgTeleportFastSwapArea::~CHgTeleportFastSwapArea() + { + iArray.ResetAndDestroy(); + delete iGrid; + delete iFSClient; + delete iPopup; + delete iConfirmCloseQuery; + delete iHighlightTimer; + delete iRedrawTimer; + delete iUpdateGridTimer; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ConstructL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::ConstructL( const TRect& aRect ) + { + SetContainerWindowL( iParent ); + + SetRect( aRect ); + + // setup ganes grid + ReCreateGridL(); + + // create stylus popup instance + PreCreatePopupL(); + + // connect to fsw server + iFSClient = CHgFswClient::NewL(); + + iEvtHandler.ReInitPhysicsL(GridWorldSize(), ViewSize(), ETrue); + + // add self to device state observer + iDeviceState.AddObserverL( *this, EDeviceType ); + + iHighlightTimer = new (ELeave) CHgTeleportFastSwapTimer( *this ); + iHighlightTimer->ConstructL(); + + iRedrawTimer = new (ELeave) CHgTeleportFastSwapTimer( *this ); + iRedrawTimer->ConstructL(); + + iUpdateGridTimer = new (ELeave) CHgTeleportFastSwapTimer( *this ); + iUpdateGridTimer->ConstructL(); + + ActivateL(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ReCreateGridL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::ReCreateGridL() + { + MCoeControlObserver* obs = NULL; + TBool wasHighlight = iDeviceState.DeviceType() == + CHgTeleportDeviceState::EHybrid ? ETrue : EFalse; + if ( iGrid ) + { + obs = iGrid->Observer(); + iDeviceState.RemoveObserver(*iGrid); + wasHighlight = iGrid->IsHighlightVisible(); + delete iGrid; + iGrid = NULL; + } + + iGrid = new( ELeave ) CHgTeleportFastSwapGrid; + iGrid->ConstructL( this ); + iDeviceState.AddObserverL(*iGrid, MHgDeviceStateObserver::ESkin); + + AknListBoxLayouts::SetupStandardGrid( *iGrid ); + + RArray rects; + CleanupClosePushL(rects); + rects.ReserveL(KLayoutItemCount); + GetFastSwapAreaRects(rects); + TAknLayoutRect gridAppPane = rects[0]; + TAknLayoutRect gridItem = rects[1]; + TAknLayoutRect gridImage = rects[2]; + CleanupStack::PopAndDestroy(&rects); + + TInt variety = Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0; + iGrid->SetRect(gridAppPane.Rect()); + iGrid->SetVisibleViewRect(gridAppPane.Rect()); + TAknLayoutScalableParameterLimits gridParams = + AknLayoutScalable_Apps::cell_tport_appsw_pane_ParamLimits( variety ); + TPoint empty( ELayoutEmpty, ELayoutEmpty ); + +#ifndef TASKSWITCHER_USE_CUSTOM_LAYOUT + AknListBoxLayouts::SetupFormGfxCell( *iGrid, iGrid->ItemDrawer(), 0, + AknLayoutScalable_Apps::cell_tport_appsw_pane_g1( variety ).LayoutLine(), + empty, empty ); +#else + TRect imageRect; + TRect textRect; + TInt leftMargin = ( KFswItemWidth - KFswImageSize ) / 2; + TInt topMargin = ( KFswItemHeight - KFswImageSize - KFswTextHeight ) / 3; + textRect.iTl = TPoint( leftMargin, topMargin ); + textRect.iBr = TPoint( leftMargin + KFswImageSize, topMargin + KFswTextHeight ); + imageRect.iTl = TPoint( leftMargin, topMargin * 2 + KFswTextHeight ); + imageRect.iBr = TPoint( leftMargin + KFswImageSize, topMargin * 2 + KFswTextHeight + KFswImageSize ); + + AknListBoxLayouts::SetupFormGfxCell( *iGrid, iGrid->ItemDrawer(), 0 /*Column index*/, + imageRect.iTl.iX /*Left pos*/, imageRect.iTl.iY /*Top pos*/, + 0 /*unused*/, 0 /*unused*/, + imageRect.Width() /*Icon width*/, + imageRect.Height() /*Icon height*/, + imageRect.iTl /*Start pos*/, + imageRect.iBr /*End pos*/ ); +#endif + + // Setup text layout + TRgb textColor; + AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, + KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG9 ); + + TAknLayoutText textLayout; + textLayout.LayoutText( + Rect(), + AknLayoutScalable_Apps::cell_tport_appsw_pane_t1( variety ).LayoutLine() ); + + // Because textLayout.BaselineOffset() does not work (missing lib entry), + // we need to calculate offset ourselves +#ifndef TASKSWITCHER_USE_CUSTOM_LAYOUT + TInt baselineOffset = textLayout.TextRect().iBr.iY - textLayout.TextRect().iTl.iY; + AknListBoxLayouts::SetupFormTextCell( *iGrid, iGrid->ItemDrawer(), 1 /*Column index*/, + textLayout.Font() /*Font type*/, + textColor.Color16() /*color*/, + textLayout.TextRect().iTl.iX /*Left margin*/, 0 /*unused*/, + baselineOffset /*Baseline*/, 0 /*Text width*/, + textLayout.Align() /*Text alignment*/, + TPoint(0,0) /*Start pos*/, + TPoint(0,0) /*End pos*/); +#else + TInt baselineOffset = textRect.iBr.iY - textRect.iTl.iY; + AknListBoxLayouts::SetupFormTextCell( *iGrid, iGrid->ItemDrawer(), 1 /*Column index*/, + textLayout.Font() /*Font type*/, + textColor.Color16() /*color*/, + textRect.iTl.iX /*Left margin*/, 0 /*unused*/, + baselineOffset /*Baseline*/, 0 /*Text width*/, + CGraphicsContext::ECenter /*Text alignment*/, + TPoint(0,0) /*Start pos*/, + TPoint(0,0) /*End pos*/); +#endif + + // Setup grid observers + if ( obs ) + { + iGrid->SetObserver( obs ); + } + iGrid->SetListBoxObserver(this); + iGrid->SetFastSwapGridObserver(this); + iGrid->SetContainerWindowL(*this); + +#ifndef TASKSWITCHER_USE_CUSTOM_LAYOUT + iMaxItemsOnScreen = Rect().Width() / gridItem.Rect().Width(); + iGridItemWidth = gridItem.Rect().Width(); +#else + iMaxItemsOnScreen = Rect().Width() / KFswItemWidth; + iGridItemWidth = KFswItemWidth; +#endif + + iGrid->ItemDrawer()->ColumnData()->SetDrawBackground(EFalse); + + // Update state + HandleDeviceStateChanged( EDeviceType ); + if( wasHighlight ) + { + iGrid->ShowHighlight(); + } + else + { + iGrid->HideHighlight(); + } + + // Make sure that there is an ActivateL call even when we are not + // called from ConstructL. (in order to have the grid's parent ptr set properly) + ActivateL(); + } + + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::GetFastSwapAreaRects +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::GetFastSwapAreaRects( RArray& aRects ) + { + TAknLayoutRect gridAppPane; + TAknLayoutRect gridItem; + TAknLayoutRect gridImage; + + TInt variety = Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0; + + gridAppPane.LayoutRect( Rect(), + AknLayoutScalable_Apps::tport_appsw_pane( variety ) ); + aRects.Append(gridAppPane); + + gridItem.LayoutRect( gridAppPane.Rect(), + AknLayoutScalable_Apps::cell_tport_appsw_pane( variety, 0, 0 ) ); + aRects.Append(gridItem); + + gridImage.LayoutRect( gridItem.Rect(), + AknLayoutScalable_Apps::cell_tport_appsw_pane_g1( variety ) ); + aRects.Append(gridImage); + } + + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::Setup +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::Setup( MCoeControlObserver& aControlObserver ) + { + iGrid->SetObserver( &aControlObserver ); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SizeChanged +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::SizeChanged() + { + HGLOG_CONTEXT( CHgTeleportFastSwapArea::SizeChanged, HGLOG_LOCAL ); + HGLOG_IN(); + + if ( iGrid ) + { + // Grid needs to be recreated to proper reinitilize + // data with new layout values + TInt selIdx = SelectedIndex(); + TRAPD(err, + ReCreateGridL(); + iEvtHandler.ReInitPhysicsL(GridWorldSize(), ViewSize(), ETrue);); + if ( err != KErrNone ) + { + HGLOG1( HGLOG_INFO, "ReCreateGridL leaves with %d", err ); + } + HandleFswContentChanged(); + iGrid->SetCurrentDataIndex(selIdx); + UpdateGrid(ETrue, EFalse); + DrawDeferred(); + } + HGLOG_OUT(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::Draw +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::Draw( const TRect& /*aRect*/ ) const + { + CWindowGc& gc = SystemGc(); + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + MAknsControlContext* cc = AknsDrawUtils::ControlContext( this ); + AknsDrawUtils::Background( skin, + cc, + this, + gc, + Rect() ); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SwitchToApp +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::SwitchToApp( TInt aIndex ) + { + if ( aIndex >= 0 && aIndex < iArray.Count() ) + { + TInt wgId = iArray[aIndex]->WgId(); + // Move other app to foreground and then move ourselves to background. + // Order is important and cannot be reversed. + iFSClient->SwitchToApp( wgId ); + // We do not want to come back to teleport if the activated app is closed. + // Therefore teleport must be moved to background. + CHgTeleportAppUi* appui = + static_cast( iEikonEnv->AppUi() ); + appui->MoveAppToBackground( AknTransEffect::EApplicationStartRect ); + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::TryCloseAppL +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::TryCloseAppL( TInt aIndex, + TBool aSuppressRendering ) + { + HGLOG_CONTEXT( TryCloseAppL, HGLOG_LOCAL ); + HGLOG2_IN( "%d %d", aIndex, aSuppressRendering ); + + if ( aIndex >= 0 && aIndex < iArray.Count() && CanClose( aIndex ) ) + { + TInt wgId = iArray[aIndex]->WgId(); + iFSClient->CloseApp( wgId ); + // The fsw content will change sooner or later + // but the updated content (without the closed app) will not + // come very fast. It looks better to the user if the item + // in the grid is removed right here, right now. + // If the app does not close for some reason then this is + // not fully correct but the app will then reappear on the next + // content-changed notification anyway. + delete iArray[aIndex]; + iArray.Remove( aIndex ); + NotifyChange(); + if ( !aSuppressRendering ) + { + RenderContentL(); + } + // Update item selection on the screen if last item was deleted + TInt newItemCount = GridItemCount(); + if ( aIndex == newItemCount ) + { + newItemCount--; + iGrid->SetCurrentDataIndex(newItemCount); + } + iTimeOfLastClose.HomeTime(); + } + + HGLOG_OUT(); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::TryCloseAppWithQueryL +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::TryCloseAppWithQueryL( TInt aIndex ) + { + if ( aIndex >= 0 && aIndex < iArray.Count() + && CanClose( aIndex ) + && ConfirmCloseL( aIndex ) ) + { + TryCloseAppL( aIndex ); + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::TryCloseAllL +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::TryCloseAllL() + { + // note the direction of the loop, this is needed because + // TryCloseAppL may modify the array + TBool changed = EFalse; + for ( TInt i = iArray.Count() - 1; i >= 0; --i ) + { + if ( CanClose( i ) ) + { + TryCloseAppL( i, ETrue ); + changed = ETrue; + } + } + if ( changed ) + { + RenderContentL(); + RestoreSelectedIndex(); + iGrid->DrawNow(); + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CanClose +// -------------------------------------------------------------------------- +// +TBool CHgTeleportFastSwapArea::CanClose( TInt aIndex ) const + { + CHgFswEntry* e = iArray[aIndex]; + return !e->AlwaysShown() && !e->SystemApp(); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CanCloseOthers +// -------------------------------------------------------------------------- +// +TBool CHgTeleportFastSwapArea::CanCloseAll( TInt aSelectedItem ) const + { + TInt count( 0 ); + + // Count number of closable applications and if number exceeds 2 finish + // counting, because it is already enough to show the option. + for ( TInt i = iArray.Count(); --i >= 0 && count < KHgMaxClosableApps; ) + { + if ( CanClose( i ) ) + { + count++; + } + } + return ( count >= KHgMaxClosableApps ) || + ( count && !CanClose( aSelectedItem ) ); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleFswContentChanged +// From MHgFswObserver +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleFswContentChanged() + { + HGLOG_CONTEXT( HandleFswContentChanged, HGLOG_LOCAL ); + HGLOG_IN(); + + TRAPD( err, HandleFswContentChangedL() ); + if ( err != KErrNone ) + { + HGLOG1( HGLOG_INFO, "leave occured: %d", err ); + } + + HGLOG_OUT(); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleFswContentChangedL +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleFswContentChangedL() + { + HGLOG_CONTEXT( HandleFswContentChangedL, HGLOG_LOCAL ); + HGLOG_IN(); + + // If there was an app close operation started during the last + // few seconds then stop, to prevent flickering. + TTime now; + now.HomeTime(); + TTimeIntervalSeconds iv; + if ( now.SecondsFrom( iTimeOfLastClose, iv ) == KErrNone + && iv.Int() <= KRefreshDelayAfterClose ) + { + HGLOG1_OUT( "difference since last close is only %d sec, stop", iv.Int() ); + return; + } + + // get current content from fastswap server + iFSClient->GetContentL( iArray ); + SwapApplicationOrder( iArray ); + +#ifdef _DEBUG + for ( TInt i = 0, ie = iArray.Count(); i != ie; ++i ) + { + CHgFswEntry* e = iArray[i]; + const TDesC& name( e->AppName() ); + HGLOG4( HGLOG_INFO, "[%d]: %d %d %S", i, e->WgId(), e->AppUid(), &name ); + } +#endif + + // draw + RenderContentL(); + + // notify observer, if present + NotifyChange(); + + HGLOG_OUT(); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::RenderContentL +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::RenderContentL() + { + HGLOG_CONTEXT( RenderContentL, HGLOG_LOCAL ); + HGLOG_IN(); + + _LIT(KSeparator, "\t"); + + CArrayPtr* iconArray = new ( ELeave ) CAknIconArray( iArray.Count() ); + CleanupStack::PushL( iconArray ); + CDesCArrayFlat* textArray = new ( ELeave ) CDesCArrayFlat( iArray.Count() ); + CleanupStack::PushL( textArray ); + RArray closeItemArray; + CleanupClosePushL(closeItemArray); + + TInt variety = Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0; + RArray rects; + CleanupClosePushL(rects); + rects.ReserveL(KLayoutItemCount); + GetFastSwapAreaRects(rects); + TAknLayoutRect gridItem = rects[1]; + CleanupStack::PopAndDestroy(&rects); + if ( AknLayoutUtils::LayoutMirrored() ) + { +#ifndef TASKSWITCHER_USE_CUSTOM_LAYOUT + iGrid->SetLayoutL( EFalse, EFalse, ETrue, iArray.Count(), 1, gridItem.Rect().Size() ); +#else + TSize itemSize( KFswItemWidth, KFswItemHeight ); + iGrid->SetLayoutL( EFalse, EFalse, ETrue, iArray.Count(), 1, itemSize ); +#endif + } + else + { +#ifndef TASKSWITCHER_USE_CUSTOM_LAYOUT + iGrid->SetLayoutL( EFalse, ETrue, ETrue, iArray.Count(), 1, gridItem.Rect().Size() ); +#else + TSize itemSize( KFswItemWidth, KFswItemHeight ); + iGrid->SetLayoutL( EFalse, ETrue, ETrue, iArray.Count(), 1, itemSize ); +#endif + } + + for ( TInt i = 0, ie = iArray.Count(); i != ie; ++i ) + { + const TDesC& appName( iArray[i]->AppName() ); + const TInt formatLen = 3 + 2; + RBuf formAppName; + CleanupClosePushL(formAppName); + formAppName.CreateL(appName.Length() + formatLen); + formAppName.AppendNum(i); + formAppName.Append(KSeparator); + formAppName.Append(appName); + textArray->AppendL(formAppName); + CleanupStack::PopAndDestroy(&formAppName); + TSize sz = PreferredImageSize(); + + // take the screenshot or appicon+mask and make a copy and scale + CFbsBitmap* bitmap = 0; + TInt h = iArray[i]->ScreenshotHandle(); + HGLOG2( HGLOG_INFO, "'%S' screenshot handle %d", &appName, h ); + TInt maskh = 0; + CFbsBitmap* mask = 0; + if ( !h ) + { + h = iArray[i]->AppIconBitmapHandle(); + maskh = iArray[i]->AppIconMaskHandle(); + HGLOG1( HGLOG_INFO, "using appicon, handle = %d", h ); + } + __ASSERT_DEBUG( h, User::Invariant() ); + bitmap = CopyBitmapL( h, sz ); + CleanupStack::PushL( bitmap ); + if ( maskh ) + { + mask = CopyBitmapL( maskh, sz ); + } + CleanupStack::PushL( mask ); + + CGulIcon* icon = CGulIcon::NewL( bitmap, mask ); + CleanupStack::PushL(icon); + iconArray->AppendL(icon); + CleanupStack::Pop( 3, bitmap ); // mask, bitmap, icon + + // Check if item can be closed + if ( CanClose(i) && AknLayoutUtils::PenEnabled() ) + { + closeItemArray.AppendL(i); + } + } + // Setup grid + iGrid->Model()->SetItemTextArray(textArray); + CArrayPtr* oldIconArray = + iGrid->ItemDrawer()->FormattedCellData()->IconArray(); + if(oldIconArray) + { + delete oldIconArray; + oldIconArray = NULL; + } + iGrid->ItemDrawer()->FormattedCellData()->SetIconArrayL(iconArray); + iGrid->SetCloseItemsL(closeItemArray); + + // Cleanup + CleanupStack::PopAndDestroy(&closeItemArray); + CleanupStack::Pop(textArray); + CleanupStack::Pop(iconArray); + + iGrid->ScrollBarFrame()->SetScrollBarVisibilityL( + CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOff); + + // refresh the items in the grid + if(iPreviousNoOfItems < iArray.Count()) + { + iGrid->HandleItemAdditionL(); + } + else if(iPreviousNoOfItems > iArray.Count()) + { + iGrid->HandleItemRemovalL(); + } + iPreviousNoOfItems = iArray.Count(); + iEvtHandler.ReInitPhysicsL( GridWorldSize(), ViewSize(), ETrue ); + UpdateGrid( ETrue ); + + HGLOG_OUT(); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CopyBitmapL +// Copy and scale. +// -------------------------------------------------------------------------- +// +CFbsBitmap* CHgTeleportFastSwapArea::CopyBitmapL( TInt aFbsHandle, TSize aSize ) + { + CFbsBitmap* ret = new (ELeave) CFbsBitmap(); + CleanupStack::PushL( ret ); + + CFbsBitmap* bmp = new (ELeave) CFbsBitmap(); + CleanupStack::PushL( bmp ); + User::LeaveIfError( bmp->Duplicate( aFbsHandle ) ); + + // do not always use aSize, preserving the aspect ratio is quite + // important when showing app icons instead of screenshots + TSize sz = CalculateSizePreserveRatio( aSize, bmp->SizeInPixels() ); + + User::LeaveIfError( ret->Create( sz, bmp->DisplayMode() ) ); + + AknIconUtils::ScaleBitmapL( sz, ret, bmp ); + + CleanupStack::PopAndDestroy( bmp ); + CleanupStack::Pop( ret ); + + return ret; + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CountComponentControls +// -------------------------------------------------------------------------- +// +TInt CHgTeleportFastSwapArea::CountComponentControls() const + { + return 1; + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ComponentControl +// -------------------------------------------------------------------------- +// +CCoeControl* CHgTeleportFastSwapArea::ComponentControl( TInt aIndex ) const + { + if ( aIndex == 0 ) + { + return iGrid; + } + return NULL; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleSwitchToBackgroundEvent +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleSwitchToBackgroundEvent() + { + // stop listening for changes in fsw content + iFSClient->CancelSubscribe(); + // get rid of the close confirmation query if shown + delete iConfirmCloseQuery; // this will cause ExecuteLD to return with 0 + iConfirmCloseQuery = 0; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleSwitchToForegroundEvent +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleSwitchToForegroundEvent() + { + HGLOG_CONTEXT( CHgTeleportFastSwapArea::HandleSwitchToForegroundEvent, HGLOG_LOCAL ); + HGLOG_IN(); + + // get the current task list + HandleFswContentChanged(); + // and then start listening for changes + iFSClient->Subscribe( *this ); + + if ( iDeviceState.DeviceType() == CHgTeleportDeviceState::EFullTouch ) + { + iGrid->HideHighlight(); + } + else + { + iGrid->ShowHighlight(); + } + + RestoreSelectedIndex(); + UpdateGrid(ETrue, EFalse); + + iRedrawTimer->Cancel(); + iRedrawTimer->After(KRedrawTime); + + // give feedback + LaunchPopupFeedback(); + + HGLOG_OUT(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::FocusChanged +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::FocusChanged( TDrawNow /*aDrawNow*/ ) + { + if ( IsFocused() ) + { + // if in non-touch mode then select (highlight) some item + if ( !AknLayoutUtils::PenEnabled() + && SelectedIndex() == KErrNotFound + && GridItemCount() ) + { + RestoreSelectedIndex(); + } + } + else + { + // store the currently selected index if there is one + SaveSelectedIndex(); + } + iGrid->DrawDeferred(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::OfferKeyEventL +// ----------------------------------------------------------------------------- +// +TKeyResponse CHgTeleportFastSwapArea::OfferKeyEventL( + const TKeyEvent& aKeyEvent, + TEventCode aType ) + { + iKeyEvent = ETrue; + // handle the 'clear' key + if ( aType == EEventKey && aKeyEvent.iCode == EKeyBackspace ) + { + TInt idx = SelectedIndex(); + if ( idx >= 0 ) + { + TryCloseAppWithQueryL( idx ); + } + return EKeyWasConsumed; + } + + //do not forward the event until item is higlighted + if( aKeyEvent.iScanCode == EStdKeyLeftArrow || + aKeyEvent.iScanCode == EStdKeyRightArrow ) + { + if ( !iGrid->IsHighlightVisible() ) + { + if ( aType == EEventKey ) + { + ShowHighlight(); + iConsumeEvent = ETrue; + } + return EKeyWasConsumed; + } + else if(iConsumeEvent) + { + if (aType == EEventKeyUp) + { + return EKeyWasConsumed; + } + iConsumeEvent = EFalse; + } + } + + // pass the event to grid + // do not pass down and up arrow key events + if ( aKeyEvent.iScanCode != EStdKeyUpArrow && + aKeyEvent.iScanCode != EStdKeyDownArrow ) + { + TBool animate(ETrue); + TBool redraw(EFalse); + TInt prevItem = SelectedIndex(); + TKeyResponse response = iGrid->OfferKeyEventL( aKeyEvent, aType ); + if ( prevItem != SelectedIndex() && // item changed + ( ( prevItem == 0 && + SelectedIndex() == GridItemCount() - 1 && + GridItemCount() > iMaxItemsOnScreen + 1 ) || // loop from first to last item + ( prevItem == GridItemCount() - 1 && + SelectedIndex() == 0 && + GridItemCount() > iMaxItemsOnScreen + 1) // loop from last to first item + ) // loop + ) + { + // Loop occured + animate = EFalse; + } + if ( prevItem != SelectedIndex() ) + { + redraw = ETrue; + iGrid->ShowHighlight(); + } + UpdateGrid( redraw, animate ); + return response; + } + + return EKeyWasNotConsumed; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandlePointerEventL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandlePointerEventL( const TPointerEvent& aPointerEvent ) + { + iKeyEvent = EFalse; + if(aPointerEvent.iType == TPointerEvent::EButton1Down) + { + iTapEvent = aPointerEvent; + } + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ConfirmCloseL +// ----------------------------------------------------------------------------- +// +TBool CHgTeleportFastSwapArea::ConfirmCloseL( TInt aIndex ) + { + HBufC* msg = StringLoader::LoadLC( R_TELEPORT_FSW_CONFIRM_CLOSE, + iArray[aIndex]->AppName() ); + iConfirmCloseQuery = CAknQueryDialog::NewL( + CAknQueryDialog::EConfirmationTone ); + iConfirmCloseQuery->SetPromptL( *msg ); + CleanupStack::PopAndDestroy( msg ); + TBool ok = iConfirmCloseQuery->ExecuteLD( + R_HG_TELEPORT_FSW_CONFIRM_CLOSE_QUERY ); + iConfirmCloseQuery = 0; + return ok; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SelectedIndex +// ----------------------------------------------------------------------------- +// +TInt CHgTeleportFastSwapArea::SelectedIndex() const + { + return iGrid->CurrentDataIndex(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SaveSelectedIndex +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::SaveSelectedIndex() + { + iSavedSelectedIndex = SelectedIndex(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::RestoreSelectedIndex +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::RestoreSelectedIndex() + { + iSavedSelectedIndex = KErrNotFound; + if ( GridItemCount() ) + { + // highlight second recent item (that has index 2) if possible + TInt highlightItem = 0; + TInt count = GridItemCount(); + while( highlightItem < count + && highlightItem < KItemToHighlight ) + { + ++highlightItem; + } + iSavedSelectedIndex = highlightItem - 1;//count from 0 + iGrid->SetCurrentItemIndex( iSavedSelectedIndex ); + TBool forceRedraw(ETrue); + UpdateGrid(forceRedraw); + } + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ProcessCommandL +// Handle fsw popup commands +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::ProcessCommandL( TInt aCommandId ) + { + switch ( aCommandId ) + { + case EFswCmdClose: + TryCloseAppL( iAppIndexForPopup ); + break; + + case EFswCmdCloseAll: + TryCloseAllL(); + break; + + case KErrCancel: + // popup dismisses automatically when tapping outside or when switching to other app + break; + } + iTapEvent.iType = TPointerEvent::EButton1Up; + iGrid->HandlePointerEventL(iTapEvent); + } + + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleCloseEventL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleCloseEventL(TInt aItemIdx) + { + if ( !iLongTap ) + { + TryCloseAppWithQueryL( aItemIdx ); + } + // Simulate long tap to prevent item activation + iLongTap = ETrue; + iTapEvent.iType = TPointerEvent::EButton1Up; + iGrid->HandlePointerEventL(iTapEvent); + } + + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleDeviceStateChanged +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleDeviceStateChanged( TChangeType aChangeType ) + { + if ( aChangeType == EDeviceType ) + { + CHgTeleportDeviceState::TDeviceType state = iDeviceState.DeviceType(); + switch ( state ) + { + case CHgTeleportDeviceState::EHybrid: + { + iGrid->SetGridBehaviour( CHgTeleportFastSwapGrid::EHybrid ); + } + break; + case CHgTeleportDeviceState::EFullTouch: + { + iGrid->SetGridBehaviour( CHgTeleportFastSwapGrid::ETouchOnly ); + } + break; + default: + break; + } + } + } + + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::TimerCompletedL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::TimerCompletedL( CHgTeleportFastSwapTimer* aSource ) + { + if(aSource == iHighlightTimer) + { + iTapEvent.iType = TPointerEvent::EButton1Up; + iGrid->HandlePointerEventL(iTapEvent); + } + else if(aSource == iRedrawTimer) + { + DrawNow(); + } + else if( aSource == iUpdateGridTimer ) + { + UpdateGrid(ETrue, ETrue); + } + } + + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::PreCreatePopupL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::PreCreatePopupL() + { + if ( !iPopup ) + { + iPopup = CAknStylusPopUpMenu::NewL( this, Rect().iTl ); + HBufC* text = StringLoader::LoadLC( R_TELEPORT_FSW_CLOSE ); + iPopup->AddMenuItemL( *text, EFswCmdClose ); + CleanupStack::PopAndDestroy( text ); + text = StringLoader::LoadLC( R_TELEPORT_FSW_CLOSE_ALL ); + iPopup->AddMenuItemL( *text, EFswCmdCloseAll ); + CleanupStack::PopAndDestroy( text ); + } + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ShowPopupL +// ----------------------------------------------------------------------------- +// +TBool CHgTeleportFastSwapArea::ShowPopupL( TInt aIndex, const TPoint& aPoint ) + { + TBool showPopUp(EFalse); + TBool showPopupItem; + // hide 'close' if app cannot be closed + showPopupItem = CanClose( aIndex ); + iPopup->SetItemDimmed( EFswCmdClose, !showPopupItem ); + showPopUp = showPopUp || showPopupItem; + // hide 'close all' if there are no applications to close. + showPopupItem = CanCloseAll( aIndex ); + iPopup->SetItemDimmed( EFswCmdCloseAll, !showPopupItem ); + showPopUp = showPopUp || showPopupItem; + + if(showPopUp) + { + // give feedback + LaunchPopupFeedback(); + // save index for later use & show popup + iAppIndexForPopup = aIndex; + iPopup->SetPosition( aPoint, CAknStylusPopUpMenu::EPositionTypeLeftBottom ); + iPopup->ShowMenu(); + } + return showPopUp; + } + + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::Count +// ----------------------------------------------------------------------------- +// +TInt CHgTeleportFastSwapArea::Count() const + { + return iArray.Count(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SetDataChangeObserver +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::SetDataChangeObserver( + MHgTeleportDataChangeObserver* aDcObserver ) + { + iDcObserver = aDcObserver; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::NotifyChange +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::NotifyChange() + { + if ( iDcObserver ) + { + iDcObserver->DataChanged( this, Count() ); + } + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SwapApplicationOrder +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::SwapApplicationOrder( + RPointerArray& aArray ) + { + for ( TInt i = 0; i < aArray.Count(); ++i ) + { + if( aArray[i]->AppUid() == KAiUid ) + { + CHgFswEntry* homescreenEntry(0); + homescreenEntry = aArray[i]; + aArray.Remove(i); + aArray.Insert(homescreenEntry, KAiPosition); + break; + } + } + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::PreferredImageSize +// ----------------------------------------------------------------------------- +// +TSize CHgTeleportFastSwapArea::PreferredImageSize() + { +#ifndef TASKSWITCHER_USE_CUSTOM_LAYOUT + TAknLayoutRect gridImage; + TRAP_IGNORE( + RArray rects; + CleanupClosePushL(rects); + rects.ReserveL(KLayoutItemCount); + GetFastSwapAreaRects(rects); + gridImage = rects[2]; + CleanupStack::PopAndDestroy(&rects); + ); + return gridImage.Rect().Size(); +#else + return TSize( KFswImageSize, KFswImageSize ); +#endif + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::GridItemCount +// ----------------------------------------------------------------------------- +// +TInt CHgTeleportFastSwapArea::GridItemCount() + { + return iGrid->Model()->ItemTextArray()->MdcaCount(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleListBoxEventL +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleListBoxEventL(CEikListBox* aListBox, TListBoxEvent aEventType) + { + if ( aListBox == iGrid ) + { + switch ( aEventType ) + { + case EEventEnterKeyPressed: + case EEventItemClicked: + { + if (!iLongTap) + { + SwitchToApp(SelectedIndex()); + } + } + break; + case EEventPenDownOnItem: + { + iGrid->HideHighlight(); + iGrid->ShowHighlight(); + if (!iLongTap ) + { + iHighlightTimer->Cancel(); + iHighlightTimer->After(KHighlighActivationTime); + } + } + break; + default: + break; + } + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CalculateSizePreserveRatio +// -------------------------------------------------------------------------- +// +TSize CHgTeleportFastSwapArea::CalculateSizePreserveRatio( + const TSize& aTargetAreaSize, + const TSize& aSourceSize ) + { + TSize sz; + if ( aSourceSize.iWidth > aSourceSize.iHeight ) + { + sz.iWidth = aTargetAreaSize.iWidth; + TReal ratio = aSourceSize.iWidth / (TReal) aSourceSize.iHeight; + sz.iHeight = sz.iWidth / ratio; + } + else + { + sz.iHeight = aTargetAreaSize.iHeight; + TReal ratio = aSourceSize.iHeight / (TReal) aSourceSize.iWidth; + sz.iWidth = sz.iHeight / ratio; + } + return sz; + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::SelectNextItem +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::SelectNextItem() + { + iKeyEvent = ETrue; + TBool forceRedraw(ETrue); + TBool animate(ETrue); + TInt selectedItem = SelectedIndex(); + selectedItem++; + if ( selectedItem == GridItemCount() ) + { + // Last item is selected, move to first one + selectedItem = 0; + animate = EFalse; + } + iGrid->SetCurrentItemIndex(selectedItem); + UpdateGrid(forceRedraw, animate); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ShowHiglight +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::ShowHighlight() + { + iGrid->ShowHighlight(); + UpdateGrid(ETrue, EFalse); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::CenterItem +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::CenterItem(TInt aRedrawDelay) + { + if( iMaxItemsOnScreen < GridItemCount() ) + { + TInt visibleItem = ViewToVisibleItem( ViewPos() ); + if(iKeyEvent) + { + visibleItem = SelectedIndex(); + } + iGrid->SetCurrentDataIndex( visibleItem ); + } + + iUpdateGridTimer->Cancel(); + iUpdateGridTimer->After(aRedrawDelay); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::GridWorldSize +// -------------------------------------------------------------------------- +// +TSize CHgTeleportFastSwapArea::GridWorldSize() + { + return TSize( GridItemCount() * iGridItemWidth, Rect().Height() ); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::UpdateGrid +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::UpdateGrid( TBool aForceRedraw, TBool aAnimate ) + { + TPoint targetPoint = ItemViewPosition( SelectedIndex() ); + if ( aForceRedraw || targetPoint.iX != ViewPos().iX ) + { + if ( aAnimate ) + { + iEvtHandler.Animate( targetPoint ); + } + else + { + MoveOffset(targetPoint); + iEvtHandler.StopAnimation(); + } + if ( aForceRedraw ) + { + iGrid->DrawNow(); + } + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::HandleAppKey +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::HandleAppKey(TInt aType) + { + if( aType == KAppKeyTypeShort ) + { + if(iGrid->IsHighlightVisible()) + { + SelectNextItem(); + } + else + { + ShowHighlight(); + } + } + else if( aType == KAppKeyTypeLong ) + { + SwitchToApp( SelectedIndex() ); + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::MoveOffset +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::MoveOffset(const TPoint& aPoint) + { + HGLOG_CONTEXT( CHgTeleportFastSwapArea::MoveOffset, HGLOG_LOCAL ); + HGLOG2_IN("Old position x: %d, y:%d", ViewPos().iX, ViewPos().iY); + HGLOG2_IN("New position x: %d, y:%d", aPoint.iX, aPoint.iY); + HGLOG_OUT(); + + TInt currentXPos = aPoint.iX; + currentXPos -= Rect().Width() / 2; + TRect gridViewRect = Rect(); + gridViewRect.iTl.iX = -currentXPos; + // Take edge offset into account + gridViewRect.iTl.iX += Rect().iTl.iX; + if(GridItemCount() <= iMaxItemsOnScreen) + { + // Center view + gridViewRect.iTl.iX += ( Rect().Width() - GridItemCount() * iGridItemWidth ) / 2; + } + iGrid->SetRect( gridViewRect ); + DrawNow(); + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::Tap +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::TapL(const TPoint& aPoint) + { + iLongTap = EFalse; + if(iGrid->Rect().Contains(aPoint)) + { + //provide tap pointer event to grid + iGrid->HandlePointerEventL(iTapEvent); + } + else + { + //move task switcher to background + iEikonEnv->EikAppUi()->HandleCommandL(EAknSoftkeyExit); + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::LongTap +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::LongTapL(const TPoint& aPoint) + { + iLongTap = ETrue; + TInt index(KErrNotFound); + if( iGrid->GridView()->XYPosToItemIndex(aPoint,index) ) + { + if ( AknLayoutUtils::LayoutMirrored() ) + { + // Calculate logical item index + index = GridItemCount() - 1 - index; + } + SaveSelectedIndex(); + iGrid->HandlePointerEventL(iTapEvent); + if ( !ShowPopupL(index, aPoint) ) + { + TapL(aPoint); + } + } + else + { + TapL(aPoint); + } + } + +// -------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::Drag +// -------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::Drag( + const MAknTouchGestureFwDragEvent& /*aEvent*/) + { + iGrid->HideHighlight(); + CenterItem( KUpdateGridTime ); + DrawNow(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ViewSize +// ----------------------------------------------------------------------------- +// +TSize CHgTeleportFastSwapArea::ViewSize() + { + return TSize(Rect().Width(), Rect().Height()); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::Stop +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::Stop() + { + CenterItem( KUpdateGridTime ); + DrawNow(); + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ViewSize +// ----------------------------------------------------------------------------- +// +TPoint CHgTeleportFastSwapArea::ViewPos() const + { + TPoint retVal; + retVal.iY = iGrid->Rect().iTl.iY + Rect().Height() / 2; + retVal.iX = - (iGrid->Rect().iTl.iX - Rect().iTl.iX) + Rect().Width() / 2 ; + TInt gridItemCount = iGrid->Model()->ItemTextArray()->MdcaCount(); + if( gridItemCount <= iMaxItemsOnScreen) + { + // View centered + retVal.iX += ( Rect().Width() - gridItemCount * iGridItemWidth ) / 2; + } + return retVal; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ItemPosition +// ----------------------------------------------------------------------------- +// +TPoint CHgTeleportFastSwapArea::ItemViewPosition( TInt aItemIdx ) + { + TPoint retVal = Rect().iTl; + if ( aItemIdx == 0 ) + { + // First item + if( AknLayoutUtils::LayoutMirrored() ) + { + if ( GridItemCount() > iMaxItemsOnScreen ) + { + retVal.iX = GridWorldSize().iWidth - Rect().Width(); + } + else + { + retVal.iX = 0; + } + } + else // normal layout + { + retVal.iX = 0; + } + } + else if ( aItemIdx == GridItemCount() - 1 ) + { + // Last item selected + if( AknLayoutUtils::LayoutMirrored() ) + { + retVal.iX = 0; + } + else // normal layout + { + if ( GridItemCount() > iMaxItemsOnScreen ) + { + retVal.iX = GridWorldSize().iWidth - Rect().Width(); + } + else + { + retVal.iX = 0; + } + } + } + else + { + // Middle item + TInt screenMiddleItemOffset = ( Rect().Width() - iGridItemWidth ) / 2; + if( AknLayoutUtils::LayoutMirrored() ) + { + retVal.iX = iGridItemWidth * ( GridItemCount() - 1 - aItemIdx ) - screenMiddleItemOffset; + } + else // normal layout + { + retVal.iX = iGridItemWidth * aItemIdx - screenMiddleItemOffset; + } + if ( retVal.iX < 0 ) + { + retVal.iX = 0; + } + else if ( retVal.iX + Rect().Width() > GridWorldSize().iWidth ) + { + retVal.iX = GridWorldSize().iWidth - Rect().Width(); + } + } + + // Return middle of the view rectangle + retVal.iX += Rect().Width() / 2; + + return retVal; + } + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::ViewToVisibleItem +// ----------------------------------------------------------------------------- +// +TInt CHgTeleportFastSwapArea::ViewToVisibleItem( const TPoint aViewPos ) + { + TInt retVal(0); + TPoint absViewPos = aViewPos; + absViewPos.iX -= Rect().Width() / 2; + if ( absViewPos.iX < 0 ) + { + if ( AknLayoutUtils::LayoutMirrored() ) + { + // View crossed left border of grid world rect, last item selected + retVal = GridItemCount() - 1; + } + else // normal layout + { + // View crossed left border of grid world rect, first item selected + retVal = 0; + } + } + else if ( absViewPos.iX + Rect().Width() > GridWorldSize().iWidth ) + { + if ( AknLayoutUtils::LayoutMirrored() ) + { + // View crossed right border of grid world rect, first item selected + retVal = 0; + } + else // normal layout + { + // View crossed right border of grid world rect, last item selected + retVal = GridItemCount() - 1; + } + } + else + { + TInt offsetCheck = GridWorldSize().iWidth; + // View inside of grid world rect + for ( TInt i = 0 ; i < GridItemCount(); i++ ) + { + TInt offset = aViewPos.iX - ItemViewPosition( i ).iX; + if ( Abs( offset ) <= offsetCheck ) + { + offsetCheck = Abs( offset ); + retVal = i; + } + else + { + break; + } + } + } + return retVal; + } + + +// ----------------------------------------------------------------------------- +// CHgTeleportFastSwapArea::LaunchPopupFeedback +// ----------------------------------------------------------------------------- +// +void CHgTeleportFastSwapArea::LaunchPopupFeedback() + { + if ( AknLayoutUtils::PenEnabled() ) + { + MTouchFeedback* feedback = MTouchFeedback::Instance(); + if ( feedback ) + { + TTouchLogicalFeedback fbLogicalType = ETouchFeedbackPopUp; + if ( CAknTransitionUtils::TransitionsEnabled( + AknTransEffect::EComponentTransitionsOff ) ) + { + fbLogicalType = ETouchFeedbackIncreasingPopUp; + } + feedback->InstantFeedback( this, + fbLogicalType, + ETouchFeedbackVibra, + TPointerEvent() ); + } + } + } + +// End of file