/*
* Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Implementation of EIKON Menu Pane class (options menu).
*
*/
// INCLUDE FILES
#include <eikmenup.h>
#include <eikmenub.h>
#include <eikmobs.h>
#include <eikon.hrh>
#include <eikpanic.h>
#include <coemain.h>
#include <basched.h>
#include <barsread.h>
#include <eikhkeyt.h>
#include <eikbutb.h>
#include <eikenv.h>
#include <eikcoctl.rsg>
#include <gulcolor.h>
#include <gulutil.h>
#include <eikappui.h>
#include <eiksbfrm.h>
#include <eikscrlb.h>
#include <gulicon.h>
#include <aknborders.h> // AKNLAF
#include <aknenv.h>
#include <AknUtils.h>
#include <aknpopuplayout.h>
#include <bidi.h> // Bidirectional support
#include <bidivisual.h>
#include <aknconsts.h>
#include <avkon.mbg>
#include <AknsDrawUtils.h>
#include <AknsFrameBackgroundControlContext.h>
#include <AknBidiTextUtils.h>
#include <skinlayout.cdl.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <AknLayoutFont.h>
#include <AknsUtils.h>
#include <AknIconUtils.h>
#include <aknappui.h>
#include <layoutmetadata.cdl.h>
#include <AknStatuspaneUtils.h>
#include <aknCharMap.h>
#include <gfxtranseffect/gfxtranseffect.h> //For transition effects
#include <akntranseffect.h> //For transition effects
#include <akntransitionutils.h> // SetAllParents method
#include <featmgr.h>
#include <avkondomainpskeys.h>
#include <e32property.h>
#include <touchfeedback.h>
#include <AknTasHook.h>
#include <aknphysics.h>
#include <aknphysicsobserveriface.h>
#include <AknPriv.hrh>
#include "aknitemactionmenudata.h"
#include "akntrace.h"
// CONSTANTS
const TInt KItemGranularity = 4;
const TInt KAlternativeSubmenuWidths = 5; // five alternative widths for submenus depending on max text width
const TInt KNoSelectedRadioButtonItem = -1;
// Delay before opening sub menu when dragging, 0.3s
const TInt KCascadeMenuOpenDelay = 300000;
class CRedirectionListener;
// -----------------------------------------------------------------------------
// TaskSwapCallBack
// -----------------------------------------------------------------------------
//
TInt TaskSwapCallBack( TAny* )
{
CEikonEnv::Static()->DisplayTaskList();
return EFalse;
}
// =============================================================================
// Extension class declaration & definition
// =============================================================================
/*
* CEikMenuPaneExtension
*
* Structure containing extra local private data members.
* Created to preserve BC. The CEikMenuPane class contains a pointer to this structure
* CEikmenuPane is responsible for data members of this class.
*
* Extension now contains menu/submenu highlight animation functionality.
*/
NONSHARABLE_CLASS( CEikMenuPaneExtension ):
public CBase,
public MCoeControlObserver,
public MAknPhysicsObserver
{
public:
CEikMenuPaneExtension();
~CEikMenuPaneExtension();
void ConstructL( CEikMenuPane* aControl );
void MenuClosed();
void ConstructMenuSctRowL( TDes& aSpecialChars, TInt aResourceId );
void ConstructMenuSctRowFromDialogL( TDes& aSpecialChars, TInt aResourceId );
void StartCascadeMenuTimerL();
void StopCascadeMenuTimer();
static TInt CascadeMenuTimerCallBack( TAny* aThis );
TBool IsCascadeMenuTimerActive();
void StartHighlightTimerL();
void ResetPressedHighlight();
static TInt HighlightTimerCallBack( TAny* aThis );
TBool HighlightTimerActive() const;
void ChangePosition( TPointerEvent& aPointerEvent );
void CalculateParentEvent( const TPointerEvent& aPointerEvent,
TPointerEvent& aParentEvent );
void HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType);
public:
void ImmediateFeedback( TTouchLogicalFeedback aType,
TTouchFeedbackType aFbType );
public:
void StartCascadeMenuAppearTransition();
/**
* Prepares cascade menu for item specific commands.
*/
void PrepareCascadeForItemCommandsL();
/**
* Returns ETrue if this menu pane belongs to a CS menu.
*
* @return ETrue if this menu pane belongs to a CS menu.
*/
TBool ContextSensitiveMenu() const;
/**
* Returns ETrue if item is item specific command and the command is not
* dimmed.
*
* @param aItem Menu pane item.
* @return ETrue if item is item specific command.
*/
static TBool ItemSpecificCommand( CEikMenuPaneItem& aItem );
/**
* Enables or disables highlight
*
* @param aEnabled ETrue to enable highlight, EFalse to disable.
* @param aPointerEnabled ETrue if highlight was enabled due
* to a pointer event.
*/
void EnableHighlight( TBool aEnabled, TBool aPointerEnabled = EFalse );
/**
* Is highlight enabled
*
* @return ETrue if highlight is enabled
*/
TBool HighlightEnabled();
/**
* Sets the default highlight to options menu
*
*/
void SetDefaultHighlight();
public: // Data
CFbsBitmap* iCascadeBitmap;
CFbsBitmap* iCascadeBitmapMask;
CAknsFrameBackgroundControlContext* iBgContext;
TInt iSubMenuWidthIndex; // index for submenu layout which depends on the text length
CFbsBitmap* iCheckMarkBitmap; // bitmap to be drawn if the item has check box set on
CFbsBitmap* iCheckMarkBitmapMask; // mask for the above bitmap
CFbsBitmap* iRadioButtonBitmap; // bitmap to be drawn if the item has radio button set on
CFbsBitmap* iRadioButtonBitmapMask; // mask for the above bitmap
TBool iHasRadioGroup; // is ETrue if submenu contains radio button group.
TInt iSelectedRadioButtonItem; // index of the radio button item which is currently selected (one must be selected)
CEikMenuPane* iControl;
CAknCharMap* iSct; // Menu SCT row, created only when needed.
TBool iSctHighlighted; // No "normal" menu item can be highlighted if ETrue
// Pen event related flag indicating whether the (sub)menu pane has
// already consumed EButton1Down or not. If false,
// EButton1Up will do nothing.
TBool iItemsReadyForPenSelection;
TBool iSpecialCharPointed;
// transition demarcation rectangle for cascaded submenu
// needs to be mutable since we need to get information from Draw methods
// (that are declared const)
mutable TRect iCascadeDRect;
TBool iShowCascadeTransition;
// For later deletion of cascade menu, this allows the transition system
// to correctly handle the aborted transitions
CEikMenuPane* iCascadeMenuObject;
TBool iDraggedOutside;
TPointerEvent iLastPointerEvent;
TInt iItemsThatFitInView;
TRect iScrollBarRect;
TRect iSctRect;
CIdle* iTaskSwapIdle;
CRedirectionListener* iRedirectionListener;
RWindow* iMenuPaneWindow; // Not own, used by SCT
TBool iLaunchCascadeMenu;
TBool isUpdateScrollDirectly;
TBool iPressedDown; // ETrue if pointer is down, otherwise.
CEikCba* iCba; // Embedded cba
TRect iMenuPaneRect; // Menu area of options menu
TBool iDownOnMenuArea; // Down event received inside menu area
TBool iDownOnCbaArea; // Down event received inside embedded CBA area
/**
* Menu pane extension flags definition.
*/
enum TCEikMenuPaneExtensionFlags
{
ESingleClickEnabled,
EHideItemSpecificCommands,
EContextSensitive,
ESkipScrollbarUpdate,
EHighlightEnabled,
EHideViewSpecificCommands,
EHideMarkAndUnmark,
EHideItemActionCommands
};
/**
* Menu pane extension flags.
*/
TBitFlags iFlags;
/**
* Cached rectangle occupied by menu items (excluding scrollbar's area).
*/
TRect iItemAreaRect;
/**
* Cached rectangle occupied by menu items and scrollbar.
*/
TRect iMenuAreaRect;
/**
* Index of the item were highlight was previously drawn to.
* Can be KErrNotFound.
*/
TInt iHighlightedItem;
/**
* Scrollbar's desired visibility. This is calculated in conjunction with
* menu pane's size and used later on when calculating scrollbar's layout.
*/
CEikScrollBarFrame::TScrollBarVisibility iScrollbarVisibility;
private: // Data
CPeriodic* iTimer; // timer to launch submenu, own
CPeriodic* iHighlightTimer; // Timer to adjust pressed down highlight
TInt iVerticalOffset; // Panning offset
public: // MAknPhysicsObserver
virtual void ViewPositionChanged( const TPoint& aNewPosition,
TBool aDrawNow = ETrue,
TUint aFlags = 0 );
virtual void PhysicEmulationEnded();
virtual TPoint ViewPosition() const;
public:
void InitPhysicsL();
void DoOffset( TInt aOffset );
void RestoreOffset( TInt aKeyCode );
void SetOffset( TInt aOffset );
inline TInt Offset() const { return iVerticalOffset; };
CAknPhysics *iPhysics;
TPoint iViewPosition; // Current view position
TInt iListTopIndex;
TInt iListBottomIndex;
TInt iViewHeight;
TBool iFlickActive;
TBool iPanningActive;
TBool iKeyEventActive;
// For dragging
TPoint iStartPoint;
TTime iStartTime;
TPoint iPrevPoint;
// For highlight
TInt iButtonDownItem; // Item on which down event came
TInt iNextHighlightItem; // Item waiting for highlight timer
// When doing a full redraw drawitem should not
// draw the background because draw has already
// drawn it.
TBool iFullRedraw;
MTouchFeedback* iFeedback;
// The top item index is stored to this member and used for controlling
// tactile feedback when panning/flicking (feedback is only given when
// new item comes into view, i.e. when the top item index changes)
TInt iLastFeedbackTopItemIndex;
};
//
// CEikMenuPane::CMenuScroller
//
class CEikMenuPane::CMenuScroller : public CBase, public MEikScrollBarObserver
{
private:
friend class CEikMenuPaneExtension;
public:
static CMenuScroller* NewL( CEikMenuPane& aMenu );
~CMenuScroller();
inline TInt TopItemIndex() const;
inline void SetTopItemIndex( TInt aIndex );
inline CIdle* Idle() const;
public: // from MEikScrollBarObserver
void HandleScrollEventL( CEikScrollBar* aScrollBar, TEikScrollEvent aEventType );
private:
CMenuScroller( CEikMenuPane& aMenu );
void ConstructL();
private:
CEikMenuPane& iMenuPane;
TInt iTopItemIndex;
CIdle* iIdle;
};
// -----------------------------------------------------------------------------
// CEikMenuPane::CMenuScroller::NewL
// -----------------------------------------------------------------------------
//
CEikMenuPane::CMenuScroller* CEikMenuPane::CMenuScroller::NewL( CEikMenuPane& aMenuPane )
{ // static
CMenuScroller* self = new(ELeave)CMenuScroller( aMenuPane );
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CMenuScroller::~CMenuScroller
// -----------------------------------------------------------------------------
//
CEikMenuPane::CMenuScroller::~CMenuScroller()
{
delete iIdle;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CMenuScroller::CMenuScroller
// -----------------------------------------------------------------------------
//
CEikMenuPane::CMenuScroller::CMenuScroller( CEikMenuPane& aMenuPane )
: iMenuPane( aMenuPane ), iTopItemIndex( 0 )
{}
// -----------------------------------------------------------------------------
// CEikMenuPane::CMenuScroller::ConstructL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CMenuScroller::ConstructL()
{
iIdle = CIdle::NewL( CActive::EPriorityIdle );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CMenuScroller::HandleScrollEventL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CMenuScroller::HandleScrollEventL( CEikScrollBar* aScrollBar,
TEikScrollEvent aEventType )
{
iMenuPane.HandleScrollEventL( aScrollBar, aEventType );
}
inline TInt CEikMenuPane::CMenuScroller::TopItemIndex() const
{ return iTopItemIndex; }
inline void CEikMenuPane::CMenuScroller::SetTopItemIndex(TInt aIndex)
{
iTopItemIndex=aIndex;
}
inline CIdle* CEikMenuPane::CMenuScroller::Idle() const
{ return iIdle; }
void CEikMenuPaneExtension::InitPhysicsL()
{
_AKNTRACE_FUNC_ENTER;
iVerticalOffset = 0;
iListTopIndex = 0;
iLastFeedbackTopItemIndex = 0;
iPressedDown = EFalse;
iFlickActive = EFalse;
TRect rect( iMenuPaneRect );
TInt itemHeight = iControl->iItemHeight;
TInt itemsInRect = rect.Height() / itemHeight;
TInt totalItemHeight = iControl->TotalItemHeight();
iViewHeight = itemsInRect * itemHeight;
TSize totalSize( rect.Width(), totalItemHeight );
TSize viewSize( rect.Width(), iViewHeight );
// Using main menu width also for submenu(s), this
// enables consistent scroll physics between main
// menu and submenus
if ( iControl->iOwner )
{
CEikMenuPane* menu = iControl->iOwner;
// Go through sub menu hierarchy. There might be
// multiple submenus, although default case is
// only one submenu.
while ( menu->iOwner )
{
CEikMenuPane* prevMenu( menu );
menu = menu->iOwner;
// This prevents infinite loop if iOwner is equal to menu.
if ( menu == prevMenu )
{
break;
}
}
totalSize = TSize( menu->Rect().Width(), totalItemHeight );
viewSize = TSize( menu->Rect().Width(), iViewHeight );
}
iPhysics->InitPhysicsL( totalSize, viewSize, EFalse );
iViewPosition = TPoint( rect.Width() / 2, iListTopIndex + iViewHeight / 2 );
_AKNTRACE( "totalSize(%d, %d)", totalSize.iWidth, totalSize.iHeight );
_AKNTRACE( "viewSize(%d, %d)", viewSize.iWidth, viewSize.iHeight );
_AKNTRACE( "iViewPosition(%d, %d)", iViewPosition.iX, iViewPosition.iY );
_AKNTRACE_FUNC_EXIT;
}
// ---------------------------------------------------------------------------
// Physics emulation has moved the view.
// ---------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ViewPositionChanged( const TPoint& aNewPosition,
TBool aDrawNow,
TUint /*aFlags*/ )
{
_AKNTRACE_FUNC_ENTER;
TInt delta = iViewPosition.iY - aNewPosition.iY;
if ( !iControl->iItemArray || delta == 0 )
{
return;
}
iListTopIndex = aNewPosition.iY - iViewHeight / 2;
iListBottomIndex = aNewPosition.iY + iViewHeight - iViewHeight / 2;
DoOffset( delta );
iViewPosition = aNewPosition;
_AKNTRACE( "iListTopIndex = %d", iListTopIndex );
_AKNTRACE( "iListBottomIndex = %d", iListBottomIndex );
_AKNTRACE( "delta = %d", delta );
_AKNTRACE( "iViewPosition(%d,%d)", iViewPosition.iX, iViewPosition.iY );
//here checking the delta whether it is changed.
//if it is changed,the view must be drawn using the below code.
if ( delta != 0 )
{
aDrawNow = ETrue;
}
if ( aDrawNow )
{
if ( iFlags.IsClear( ESkipScrollbarUpdate ) )
{
TRAP_IGNORE( iControl->DoUpdateScrollBarL() );
}
// Redraw only item area if scrollbar is invisible, otherwise include
// also scrollbar's area in order to avoid drawdeferred.
TRect drawRect( iItemAreaRect );
if ( iScrollbarVisibility == CEikScrollBarFrame::EOn )
{
drawRect = iMenuAreaRect;
}
iControl->DrawNow( drawRect );
}
_AKNTRACE_FUNC_EXIT;
}
void CEikMenuPaneExtension::DoOffset( TInt aOffset )
{
_AKNTRACE_FUNC_ENTER;
TInt itemsInRect = iControl->NumberOfItemsThatFitInView();
TInt bottomListPosition = 0;
if(iControl->iItemArray->Count() > itemsInRect)
{
bottomListPosition = (iControl->iItemArray->Count() - itemsInRect) * iControl->iItemHeight;
}
TInt itemIndex = iListTopIndex;
if ( iListTopIndex <= 0 )
{
itemIndex = 0;
}
else if ( iListTopIndex >= bottomListPosition )
{
itemIndex = bottomListPosition;
}
// Calculate new top item index
TInt newTopItemIndex = itemIndex / iControl->iItemHeight;
// Calculate panning offset
SetOffset( newTopItemIndex * iControl->iItemHeight - iListTopIndex );
_AKNTRACE( " iVerticalOffset = %d", iVerticalOffset );
if ( newTopItemIndex >= 0 && newTopItemIndex < iControl->iItemArray->Count() )
{
_AKNTRACE( "%s", "iControl->iScroller->SetTopItemIndex(newTopItemIndex);" );
iControl->iScroller->SetTopItemIndex(newTopItemIndex);
}
// calculate new top item index and offset
TInt menuTopItemIndex = iListTopIndex/iControl->iItemHeight;
TInt listBottomLimit = iControl->iItemArray->Count()* iControl->iItemHeight;
if ( menuTopItemIndex > iControl->iItemArray->Count() )
{
menuTopItemIndex = iControl->iItemArray->Count() - 1;
}
if ( menuTopItemIndex != iLastFeedbackTopItemIndex )
{
iLastFeedbackTopItemIndex = menuTopItemIndex;
// If the top list item index has changed, that means that there's
// a new list item in view and thus feedback needs to be given
// in case there's flicking or panning ongoing and not doing
// bounce action
if ( iFlickActive || iPanningActive )
{
if ( ( aOffset>0 && iListTopIndex <= listBottomLimit && iListTopIndex >= -iViewHeight ) ||
( aOffset<0 && iListBottomIndex >= 0 && iListBottomIndex <= listBottomLimit+iViewHeight ) )
{
if ( iPhysics )
{
switch(iPhysics->OngoingPhysicsAction())
{
case CAknPhysics::EAknPhysicsActionBouncing:
case CAknPhysics::EAknPhysicsActionDragging:
case CAknPhysics::EAknPhysicsActionFlicking:
ImmediateFeedback( ETouchFeedbackSensitiveList,
ETouchFeedbackVibra );
break;
default:
break;
}
}
}
}
}
_AKNTRACE_FUNC_EXIT;
}
void CEikMenuPaneExtension::RestoreOffset( TInt aKeyCode )
{
if ( aKeyCode == 0 )
{
return;
}
_AKNTRACE_FUNC_ENTER;
TPoint oldViewPos = iViewPosition;
TInt itemsInRect = iControl->NumberOfItemsThatFitInView();
TInt topItem = iControl->iScroller->TopItemIndex();
TInt bottomItem = topItem + itemsInRect;
TInt highLightItem = iControl->iSelectedItem;
// There is partially visible items in menu. Offset is restored here if highlight
// is moved to partially visible item by using hw keys (up/down)
if ( ( highLightItem == topItem + 1 || highLightItem == topItem )
&& aKeyCode == EKeyUpArrow )
{
iViewPosition.iY += iVerticalOffset;
}
//ENothingSelected is for sct row.
else if ( ( highLightItem == bottomItem - 1
|| highLightItem == bottomItem
|| highLightItem == CEikMenuPane::ENothingSelected
) && aKeyCode == EKeyDownArrow )
{
iViewPosition.iY += iControl->iItemHeight + iVerticalOffset;
}
// Submenu can be opened with left or right key depending on layout
// or with selection keys
else if ( ( !AknLayoutUtils::LayoutMirrored() && aKeyCode == EKeyRightArrow ) ||
( AknLayoutUtils::LayoutMirrored() && aKeyCode == EKeyLeftArrow ) ||
aKeyCode == EKeyEnter || aKeyCode == EKeyOK || aKeyCode == EAknSoftkeyOk ||
aKeyCode == EAknSoftkeySelect || aKeyCode == EAknSoftkeyOk )
{
if ( highLightItem != CEikMenuPane::ENothingSelected )
{
const CEikMenuPaneItem* item = (*iControl->iItemArray)[highLightItem];
// Check if item has submenu
if ( item->iData.iCascadeId )
{
// Submenu is going to be opened from partial item, we need
// to bring it fully visible
if ( highLightItem == topItem )
{
iViewPosition.iY += iVerticalOffset;
}
else if ( highLightItem == bottomItem )
{
iViewPosition.iY += iControl->iItemHeight + iVerticalOffset;
}
}
}
}
// Avoid redraw if position not changed
if ( oldViewPos != iViewPosition )
{
// Report view position change to scroll physics
// when sub menu is opened with hw keys.
_AKNTRACE( "[%s]", " ViewPositionChanged( iViewPosition )" );
ViewPositionChanged( iViewPosition );
}
_AKNTRACE_FUNC_EXIT;
}
void CEikMenuPaneExtension::SetOffset( TInt aOffset )
{
iVerticalOffset = aOffset;
_AKNTRACE( "iVerticalOffset = %d", iVerticalOffset );
}
void CEikMenuPaneExtension::PhysicEmulationEnded()
{
_AKNTRACE_FUNC_ENTER;
iFlickActive = EFalse;
_AKNTRACE_FUNC_EXIT;
}
TPoint CEikMenuPaneExtension::ViewPosition() const
{
_AKNTRACE( "iViewPosition(%d,%d)", iViewPosition.iX, iViewPosition.iY );
return iViewPosition;
}
//
// =============================================================================
// Helper class that monitor redirection changes declaration & definition
// =============================================================================
/*
* CRedirectionListener
*
* Delays opening of submenus during appear transitions
*/
NONSHARABLE_CLASS( CRedirectionListener ) : public CBase,
public MAknTransitionUtilsObserver
{
public:
CRedirectionListener( CEikMenuPaneExtension& aOwner );
~CRedirectionListener();
void AppearTransitionStarting();
void Closing();
void LaunchCascadeMenu();
private:
TInt AknTransitionCallback( TInt aEvent, TInt aState,
const TDesC8* /*aParams*/ );
private: // Data
TBool iObserving;
TBool iTransitionUpcoming;
TBool iAppearTransitionRunning;
TBool iLaunchWhenUnredirected;
CEikMenuPaneExtension& iOwner;
};
// -----------------------------------------------------------------------------
// CRedirectionListener::CRedirectionListener
// -----------------------------------------------------------------------------
//
CRedirectionListener::CRedirectionListener( CEikMenuPaneExtension& aOwner ) :
iOwner( aOwner )
{
}
// -----------------------------------------------------------------------------
// CRedirectionListener::~CRedirectionListener
// -----------------------------------------------------------------------------
//
CRedirectionListener::~CRedirectionListener()
{
Closing();
}
// -----------------------------------------------------------------------------
// CRedirectionListener::AppearTransitionStarting
// -----------------------------------------------------------------------------
//
void CRedirectionListener::AppearTransitionStarting()
{
TInt err = KErrNone;
iAppearTransitionRunning = EFalse;
if ( !iObserving )
{
err = CAknTransitionUtils::AddObserver( this,
CAknTransitionUtils::EEventWsBufferRedirection );
}
// Only set this value if observing
if ( err == KErrNone )
{
iObserving = ETrue;
iTransitionUpcoming = ETrue;
}
}
// -----------------------------------------------------------------------------
// CRedirectionListener::Closing
// -----------------------------------------------------------------------------
//
void CRedirectionListener::Closing()
{
if ( iObserving )
{
CAknTransitionUtils::RemoveObserver( this,
CAknTransitionUtils::EEventWsBufferRedirection );
iObserving = EFalse;
}
iTransitionUpcoming = EFalse;
iLaunchWhenUnredirected = EFalse;
}
// -----------------------------------------------------------------------------
// CRedirectionListener::LaunchCascadeMenuL
// -----------------------------------------------------------------------------
//
void CRedirectionListener::LaunchCascadeMenu()
{
if ( iTransitionUpcoming && iObserving )
{
// Get current redirection status
TInt redirected;
TInt err = RProperty::Get( KPSUidAvkonDomain,
KAknTfxServerRedirectionStatus,
redirected );
if ( err == KErrNone && redirected )
{
// Transition has started
iAppearTransitionRunning = ETrue;
}
}
if ( iAppearTransitionRunning )
{
// Lauch submenu when unredireted if currently in transition
iLaunchWhenUnredirected = ETrue;
}
else
{
// Launch submenu imediately if not currently in transition
iOwner.StartCascadeMenuAppearTransition();
iLaunchWhenUnredirected = EFalse;
}
}
// -----------------------------------------------------------------------------
// CRedirectionListener::AknTransitionCallback
// -----------------------------------------------------------------------------
//
TInt CRedirectionListener::AknTransitionCallback( TInt aEvent, TInt aState,
const TDesC8* /*aParams*/ )
{
if ( aEvent == CAknTransitionUtils::EEventWsBufferRedirection )
{
if ( aState)
{
// Redirected (transition started)
// Don't display submenu until unredirected
iAppearTransitionRunning = iTransitionUpcoming;
}
else
{
// Unredirected (transition finished)
iAppearTransitionRunning = EFalse;
if ( iLaunchWhenUnredirected )
{
// Launch submenu waiting to be opened
iOwner.StartCascadeMenuAppearTransition();
iLaunchWhenUnredirected = EFalse;
}
}
iTransitionUpcoming = EFalse;
}
return 0;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::StartCascadeMenuAppearTransition
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::StartCascadeMenuAppearTransition()
{
CEikMenuPane* cascadeMenuPane = iControl->iCascadeMenuPane;
if ( cascadeMenuPane )
{
cascadeMenuPane->SetParent( iControl );
GfxTransEffect::Begin( cascadeMenuPane, KGfxControlAppearAction );
cascadeMenuPane->StartDisplayingMenuPane( iControl->iHotKeyTable,
iControl->Position(),
NULL,
0,
EPopupTargetBottomLeft );
GfxTransEffect::SetDemarcation( cascadeMenuPane, iCascadeDRect );
GfxTransEffect::End( cascadeMenuPane );
// Transfer focus to cascade menu (highlight animations adapt to focus
// change)
cascadeMenuPane->SetFocus( ETrue, EDrawNow );
iControl->SetFocus( EFalse, EDrawNow );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::CEikMenuPaneExtension
// High CActive priority is well argumented because running the active object
// will result in animation deletion -> results in freeing resources.
// -----------------------------------------------------------------------------
//
CEikMenuPaneExtension::CEikMenuPaneExtension() :
// Initialise data members to zero
iCascadeBitmap( NULL ),
iCascadeBitmapMask( NULL ),
iBgContext( NULL ),
iSubMenuWidthIndex( 1 ),
iCheckMarkBitmap( NULL ),
iCheckMarkBitmapMask( NULL ),
iRadioButtonBitmap( NULL ),
iRadioButtonBitmapMask( NULL ),
iHasRadioGroup( EFalse ),
iSelectedRadioButtonItem( KNoSelectedRadioButtonItem ),
iControl( NULL ),
iSct( NULL ),
iSctHighlighted( EFalse ),
iSpecialCharPointed( EFalse )
,iVerticalOffset( 0 )
,iPhysics( NULL )
,iListTopIndex( 0 )
,iViewHeight( 0 )
,iFlickActive( EFalse )
,iPanningActive( EFalse )
,iFeedback( MTouchFeedback::Instance() )
,iLastFeedbackTopItemIndex( 0 )
{
iItemsReadyForPenSelection = !AknLayoutUtils::PenEnabled();
iNextHighlightItem = KErrNotFound;
iHighlightedItem = KErrNotFound;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::~CEikMenuPaneExtension
// Destructor for extension class
// -----------------------------------------------------------------------------
//
CEikMenuPaneExtension::~CEikMenuPaneExtension()
{
_AKNTRACE_FUNC_ENTER;
delete iCascadeBitmap;
iCascadeBitmap = NULL;
delete iCascadeBitmapMask;
iCascadeBitmapMask = NULL;
delete iBgContext;
iBgContext = NULL;
delete iCheckMarkBitmap;
iCheckMarkBitmap = NULL;
delete iCheckMarkBitmapMask;
iCheckMarkBitmapMask = NULL;
delete iRadioButtonBitmap;
iRadioButtonBitmap = NULL;
delete iRadioButtonBitmapMask;
iRadioButtonBitmapMask = NULL;
iControl = NULL;
delete iSct;
iSct = NULL;
delete iCascadeMenuObject;
iCascadeMenuObject = NULL;
delete iTimer;
iTimer = NULL;
delete iHighlightTimer;
iHighlightTimer = NULL;
if ( iTaskSwapIdle )
{
if ( iTaskSwapIdle->IsActive() )
{
iTaskSwapIdle->Cancel();
TaskSwapCallBack( NULL );
}
delete iTaskSwapIdle;
}
delete iRedirectionListener;
delete iPhysics;
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ConstructL
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ConstructL( CEikMenuPane* aControl )
{
ASSERT( aControl );
iControl = aControl;
iDraggedOutside = EFalse;
iLaunchCascadeMenu = EFalse;
iButtonDownItem = KErrNotFound;
iTaskSwapIdle = CIdle::NewL( CActive::EPriorityHigh );
if ( aControl->iOwner == NULL && GfxTransEffect::IsRegistered( aControl ) )
{
// Delays submenu opening during appear transitions
iRedirectionListener = new ( ELeave ) CRedirectionListener( *this );
}
if ( static_cast<CAknAppUi*>(
iControl->ControlEnv()->AppUi() )->IsSingleClickCompatible() )
{
iFlags.Set( ESingleClickEnabled );
}
if ( !iPhysics )
{
iPhysics = CAknPhysics::NewL( *this, iControl );
}
iBgContext = CAknsFrameBackgroundControlContext::NewL(
KAknsIIDQsnFrPopup, TRect( 0, 0, 1, 1 ), TRect( 0, 0, 1, 1 ), EFalse );
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::StartCascadeMenuTimerL
// Starts the timer for the sub menu launch. Timer is constructed when used for
// the first time
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::StartCascadeMenuTimerL()
{
_AKNTRACE_FUNC_ENTER;
if ( !iTimer )
{
iTimer = CPeriodic::NewL( CActive::EPriorityStandard );
}
else if ( iTimer->IsActive() )
{
iTimer->Cancel();
}
iTimer->Start( KCascadeMenuOpenDelay,
KCascadeMenuOpenDelay,
TCallBack ( CascadeMenuTimerCallBack, this ) );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::StopCascadeMenuTimer
// Stops the timer for the sub menu launch
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::StopCascadeMenuTimer()
{
_AKNTRACE_FUNC_ENTER;
if ( iTimer && iTimer->IsActive() )
{
iTimer->Cancel();
}
iLaunchCascadeMenu = EFalse;
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::CascadeMenuTimerCallBack
// Callback function of the timer for the sub menu launch
// -----------------------------------------------------------------------------
//
TInt CEikMenuPaneExtension::CascadeMenuTimerCallBack( TAny* aThis )
{
_AKNTRACE_FUNC_ENTER;
CEikMenuPaneExtension* self =
reinterpret_cast <CEikMenuPaneExtension*> ( aThis );
self->iLaunchCascadeMenu = ETrue;
_AKNTRACE_FUNC_EXIT;
return KErrNone;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::IsCascadeMenuTimerActive
// Returns ETrue if timer is active
// -----------------------------------------------------------------------------
//
TBool CEikMenuPaneExtension::IsCascadeMenuTimerActive()
{
if ( !iTimer )
{
return EFalse;
}
return iTimer->IsActive();
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::StartHighlightTimerL
// Starts the timer for the pressed down highlight activation.
// Timer is constructed when used for the first time
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::StartHighlightTimerL()
{
_AKNTRACE_FUNC_ENTER;
if ( !iHighlightTimer )
{
iHighlightTimer = CPeriodic::NewL( CActive::EPriorityStandard );
if ( !iHighlightTimer )
{
return;
}
}
else if ( iHighlightTimer->IsActive() )
{
iHighlightTimer->Cancel();
}
TInt timeout ( 0 );
if ( iPhysics )
{
timeout = iPhysics->HighlightTimeout() * 1000;
}
iPressedDown = EFalse;
iHighlightTimer->Start( timeout,timeout,
TCallBack ( HighlightTimerCallBack, this ) );
_AKNTRACE_FUNC_EXIT;
}
// ---------------------------------------------------------------------------
// CEikMenuPaneExtension::ResetPressedHighlight
// Stops the timer for the pressed down highlight activation and resets the
// pressed highlight
// ---------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ResetPressedHighlight()
{
_AKNTRACE_FUNC_ENTER;
if ( HighlightTimerActive() )
{
iHighlightTimer->Cancel();
}
// if status changed repaint needed
if ( iPressedDown )
{
iPressedDown = EFalse;
iControl->RepaintHighlight();
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::HighlightTimerCallBack
// Callback function of the timer for pressed down highlight
// -----------------------------------------------------------------------------
//
TInt CEikMenuPaneExtension::HighlightTimerCallBack( TAny* aThis )
{
_AKNTRACE_FUNC_ENTER;
CEikMenuPaneExtension* self =
reinterpret_cast <CEikMenuPaneExtension*> ( aThis );
self->iPressedDown = ETrue;
if ( self->iControl->SelectedItem() == self->iNextHighlightItem )
{
self->iControl->RepaintHighlight();
}
else
{
if ( self->iNextHighlightItem != KErrNotFound )
{
self->iControl->MoveHighlightTo( self->iNextHighlightItem );
}
}
self->iNextHighlightItem = KErrNotFound;
if ( self->HighlightTimerActive() )
{
self->iHighlightTimer->Cancel();
}
_AKNTRACE_FUNC_EXIT;
return KErrNone;
}
// ---------------------------------------------------------------------------
// Checks if the highlight timer is running.
// ---------------------------------------------------------------------------
//
TBool CEikMenuPaneExtension::HighlightTimerActive() const
{
return ( iHighlightTimer && iHighlightTimer->IsActive() );
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ChangePosition
// Position of aPointerEvent should be modified when point in beside scrollbar.
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ChangePosition( TPointerEvent& aPointerEvent )
{
if ( !iControl->iSBFrame )
{
return;
}
TRect scrollBarRect( iControl->iSBFrame->VerticalScrollBar()->Rect() );
TPoint scrollerTl( scrollBarRect.iTl );
TPoint scrollerBr( scrollBarRect.iBr );
TRect gapRect;
// For layout that left to right
if ( !AknLayoutUtils::LayoutMirrored() )
{
TPoint rectTl( scrollerBr.iX, iControl->Rect().iTl.iY );
gapRect.SetRect( rectTl, iControl->Rect().iBr );
}
// For layout that right to left
else
{
TPoint rectBr( scrollerTl.iX, iControl->Rect().iBr.iY );
gapRect.SetRect( iControl->Rect().iTl, rectBr );
}
if ( gapRect.Contains( aPointerEvent.iPosition ) )
{
if ( !AknLayoutUtils::LayoutMirrored() )
{
aPointerEvent.iPosition.iX = scrollerBr.iX - 1;
}
else
{
aPointerEvent.iPosition.iX = scrollerTl.iX;
}
//Modify y coordinate of point in top left/right corner of options menu
if ( aPointerEvent.iPosition.iY < scrollerTl.iY )
{
aPointerEvent.iPosition.iY = scrollerTl.iY;
}
//Modify y coordinate of point in bottom left/right corner of options menu
if ( aPointerEvent.iPosition.iY > scrollerBr.iY )
{
aPointerEvent.iPosition.iY = scrollerBr.iY - 1;
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::CalculateParentEvent
// Calculate parent event for sub menu.
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::CalculateParentEvent( const TPointerEvent& aPointerEvent,
TPointerEvent& aParentEvent )
{
aParentEvent.iModifiers = aPointerEvent.iModifiers;
TPoint subPos = iControl->Position();
TPoint ownerPos = iControl->iOwner->Position();
aParentEvent.iPosition.SetXY (
aPointerEvent.iPosition.iX + subPos.iX - ownerPos.iX,
aPointerEvent.iPosition.iY + subPos.iY - ownerPos.iY);
aParentEvent.iType = aPointerEvent.iType;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::MenuClosed
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::MenuClosed()
{
_AKNTRACE_FUNC_ENTER;
delete iSct;
iSct = NULL;
iSctHighlighted = EFalse;
if ( iCba )
{
iCba = NULL;
}
if ( iRedirectionListener )
{
iRedirectionListener->Closing();
}
iFlags.Clear( EHideItemSpecificCommands );
iFlags.Clear( EHideItemActionCommands );
iFlags.Clear( EContextSensitive );
iFlags.Clear( EHighlightEnabled );
iFlags.Clear( EHideViewSpecificCommands );
iFlags.Clear( EHideMarkAndUnmark );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ConstructMenuSctRowL
// Creates a special characters row to be used in edit menu.
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ConstructMenuSctRowL( TDes& aSpecialChars, TInt aResourceId )
{
_AKNTRACE_FUNC_ENTER;
TBool renew = EFalse;
if (iSct)
{
delete iSct;
iSct = NULL;
renew = ETrue;
}
iSct = new(ELeave) CAknCharMap();
iSct->ConstructMenuSctRowL(aResourceId);
iSct->SetBuffer( aSpecialChars );
if ( renew && iMenuPaneWindow && iControl )
{
iSct->SetContainerWindowL( *iControl );
iSct->SetGloballyCapturing( ETrue );
iSct->SetPointerCapture( ETrue );
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ConstructMenuSctRowFromDialogL
// Creates a special characters row to be used in edit menu.
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ConstructMenuSctRowFromDialogL( TDes& aSpecialChars, TInt aResourceId )
{
TBool renew = EFalse;
if (iSct)
{
delete iSct;
iSct = NULL;
renew = ETrue;
}
iSct = new(ELeave) CAknCharMap();
iSct->ConstructMenuSctRowFromDialogL(aResourceId);
iSct->SetBuffer( aSpecialChars );
if ( renew && iMenuPaneWindow && iControl)
{
iSct->SetContainerWindowL( *iControl );
iSct->SetGloballyCapturing( ETrue );
iSct->SetPointerCapture( ETrue );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::HandleControlEventL
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::HandleControlEventL(CCoeControl* /*aControl*/,TCoeEvent aEventType)
{
_AKNTRACE_FUNC_ENTER;
if ( aEventType == EEventStateChanged )
{
// Something has been selected from CharMap
iSpecialCharPointed = ETrue;
}
_AKNTRACE( "aEventType = %d", aEventType );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ImmediateFeedback
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::ImmediateFeedback(
TTouchLogicalFeedback aType,
TTouchFeedbackType aFbType = TTouchFeedbackType( ETouchFeedbackAudio |
ETouchFeedbackVibra ))
{
if( iFeedback && AknLayoutUtils::PenEnabled() )
{
iFeedback->InstantFeedback( iControl, aType, aFbType, TPointerEvent() );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::PrepareCascadeForItemCommandsL
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::PrepareCascadeForItemCommandsL()
{
if ( iFlags.IsSet( ESingleClickEnabled )
&& iControl->iOwner
&& iControl->iOwner->iExtension )
{
const TBitFlags& ownerFlags( iControl->iOwner->iExtension->iFlags );
if ( ownerFlags.IsSet( EContextSensitive ) )
{
iFlags.Set( EContextSensitive );
}
else
{
if ( ownerFlags.IsSet( EHideItemSpecificCommands ) )
{
iControl->SetItemCommandsStateL( ETrue );
}
if ( ownerFlags.IsSet( EHideItemActionCommands ) )
{
iControl->SetItemActionsStateL( ETrue );
}
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ContextSensitiveMenu
// -----------------------------------------------------------------------------
//
TBool CEikMenuPaneExtension::ContextSensitiveMenu() const
{
TBool isContextSensitive( EFalse );
if ( !iControl->iOwner )
{
CEikMenuBar* menuBar = static_cast<CEikMenuBar*>( iControl->Parent() );
if ( menuBar && menuBar->GetMenuType() == CEikMenuBar::EMenuContext )
{
isContextSensitive = ETrue;
}
}
return isContextSensitive;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::ItemSpecificCommand
// -----------------------------------------------------------------------------
//
TBool CEikMenuPaneExtension::ItemSpecificCommand( CEikMenuPaneItem& aItem )
{
TBool itemSpecific( EFalse );
if ( ( aItem.iData.iFlags & EEikMenuItemSpecific
|| aItem.iData.iFlags & EEikMenuItemSpecificListQuery )
&& !( aItem.iData.iFlags & EEikMenuItemDimmed ) )
{
itemSpecific = ETrue;
}
return itemSpecific;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::EnableHighlight
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::EnableHighlight(
TBool aEnabled, TBool aPointerEnabled )
{
TBool wasEnabled( iFlags.IsSet( EHighlightEnabled ) );
if ( aEnabled )
{
iFlags.Set( EHighlightEnabled );
}
else
{
iFlags.Clear( EHighlightEnabled );
}
if ( !aPointerEnabled
&& iCba
&& ( ( wasEnabled && !aEnabled ) || ( !wasEnabled && aEnabled ) ) )
{
iCba->MakeCommandVisible( EAknSoftkeySelect, aEnabled );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::HighlightEnabled
// -----------------------------------------------------------------------------
//
TBool CEikMenuPaneExtension::HighlightEnabled()
{
return iFlags.IsSet( EHighlightEnabled );
}
// -----------------------------------------------------------------------------
// CEikMenuPaneExtension::SetDefaultHighlight
// -----------------------------------------------------------------------------
//
void CEikMenuPaneExtension::SetDefaultHighlight()
{
TInt item( CEikMenuPane::ENothingSelected );
if ( iSct )
{
iSctHighlighted = ETrue;
}
else
{
item = iControl->iScroller->TopItemIndex();
// Partial item
if ( Offset() != 0 )
{
item++;
}
// Task swapper
TInt taskSwapper;
if ( iControl->MenuItemExists( EAknCmdTaskSwapper, taskSwapper ) )
{
if ( item == taskSwapper )
{
item++;
}
}
}
iControl->SetSelectedItem( item );
EnableHighlight( ETrue );
if ( iControl->IsVisible() )
{
iControl->RepaintHighlight();
}
}
// =============================================================================
// Implementation of CEikMenuPane
// =============================================================================
//
// CItemArray
//
// -----------------------------------------------------------------------------
// CEikMenuPane::CItemArray::~CItemArray
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPane::CItemArray::~CItemArray()
{
ResetAndDestroy();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CItemArray::CItemArray
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPane::CItemArray::CItemArray()
: CArrayPtrFlat<CEikMenuPaneItem>( KItemGranularity )
{
__DECLARE_NAME(_S( "CEikMenuPane::CItemArray") );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CItemArray::AddItemL
// Adds the menu pane item aMenuItem to the end of the array owned by the menu pane
// and transfers ownership.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::CItemArray::AddItemL( CEikMenuPaneItem* aMenuItem )
{
CleanupStack::PushL( aMenuItem );
AppendL( aMenuItem );
CleanupStack::Pop();
}
//
// CExtendedItemData
//
CExtendedItemData::~CExtendedItemData()
{
delete iIcon;
delete iScaleableText;
}
//
// CEikMenuPaneItem
//
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::CEikMenuPaneItem
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPaneItem::CEikMenuPaneItem()
{
CreateExtendedDataBlock();
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::~CEikMenuPaneItem
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPaneItem::~CEikMenuPaneItem()
{
delete iExtendedData;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::SetIcon
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::SetIcon( CGulIcon* aIcon )
{
if ( iExtendedData )
{
if( iExtendedData->iIcon )
{
delete iExtendedData->iIcon;
}
iExtendedData->iIcon = aIcon;
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::DrawItemIcon
// Draws the icon for the item to the graphics context aGc, in the rectangle aRect allocating a square area with
// sides of size of aBitmapSpaceRequired to contain the icon. Draws the icon in a dimmed style if aDimmed is
// ETrue.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::DrawItemIcon( CWindowGc& aGc,
TRect aRect,
TBool /*aDimmed*/,
TInt /*aBitmapSpaceRequired*/ ) const
{
_AKNTRACE_FUNC_ENTER;
if (iExtendedData && iExtendedData->iIcon)
{
aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
TRect rect( aRect );
AknIconUtils::SetSize(iExtendedData->iIcon->Bitmap(), rect.Size());
TInt rectWidth = rect.Width();
TInt rectHeight = rect.Height();
TInt iconWidth = iExtendedData->iIcon->Bitmap()->SizeInPixels().iWidth;
TInt iconHeight = iExtendedData->iIcon->Bitmap()->SizeInPixels().iHeight;
// If aspect ratio of the image and rect do not match the image
// is centered.
if ( rectWidth > iconWidth )
{
rect.iTl.iX += TInt( ( rectWidth - iconWidth ) / 2 );
}
if ( rectHeight > iconHeight )
{
rect.iTl.iY += TInt( ( rectHeight - iconHeight ) / 2 );
}
_AKNTRACE( "rectWidth = %d", rectWidth );
_AKNTRACE( "rectHeight = %d", rectHeight );
_AKNTRACE( "iconWidth = %d", iconWidth );
_AKNTRACE( "iconHeight = %d", iconHeight );
_AKNTRACE( "rect.iTl.iX = %d", rect.iTl.iX );
_AKNTRACE( "rect.iTl.iY = %d", rect.iTl.iY );
aGc.BitBltMasked( rect.iTl, iExtendedData->iIcon->Bitmap(),
TRect(0, 0, rect.Width(), rect.Height()),
iExtendedData->iIcon->Mask(), ETrue);
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::CreateIconL
// Constructs a new icon for the item, taking ownership of the picture bitmap
// aBitmap and the mask bitmap aMask unless bitmaps have been set to be owned externally.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::CreateIconL( CFbsBitmap* aBitmap, CFbsBitmap* aMask )
{
if ( iExtendedData )
{
if( iExtendedData->iIcon )
{
delete iExtendedData->iIcon;
}
iExtendedData->iIcon = CGulIcon::NewL( aBitmap, aMask );
}
}
/**
*
*/
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::IconBitmap
// Returns a pointer to the picture bitmap of the item icon.
// Does not normally imply transfer of ownership.
// -----------------------------------------------------------------------------
//
EXPORT_C CFbsBitmap* CEikMenuPaneItem::IconBitmap() const
{
if ( iExtendedData )
{
return iExtendedData->iIcon ? iExtendedData->iIcon->Bitmap() : NULL;
}
return NULL;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::IconMask
// Returns a pointer to the mask bitmap of the item icon.
// Does not normally imply transfer of ownership.
// -----------------------------------------------------------------------------
//
EXPORT_C CFbsBitmap* CEikMenuPaneItem::IconMask() const
{
if ( iExtendedData )
{
return iExtendedData->iIcon ? iExtendedData->iIcon->Mask() : NULL;
}
return NULL;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::SetBitmapsOwnedExternally
// Sets the item icon to be owned externally if aOwnedExternally is ETrue.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::SetBitmapsOwnedExternally( TBool aOwnedExternally )
{
if ( iExtendedData )
{
if( iExtendedData->iIcon )
{
iExtendedData->iIcon->SetBitmapsOwnedExternally( aOwnedExternally );
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::SetIconBitmapL
// Sets the picture bitmap for the title icon to aBitmap.
// Transfers ownership unless the bitmaps are owned externally.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::SetIconBitmapL( CFbsBitmap* aBitmap )
{
if ( iExtendedData )
{
if( !iExtendedData->iIcon )
{
iExtendedData->iIcon = CGulIcon::NewL();
}
iExtendedData->iIcon->SetBitmap( aBitmap );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::SetIconMaskL
// Sets the mask bitmap for the title icon to aMask.
// Transfers ownership unless the bitmaps are owned externally.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::SetIconMaskL( CFbsBitmap* aMask )
{
if ( iExtendedData )
{
if( !iExtendedData->iIcon )
{
iExtendedData->iIcon = CGulIcon::NewL();
}
iExtendedData->iIcon->SetMask( aMask );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::ScaleableText
// Returns scaleable text. If there isn't scaleable text available
// then this method returns iData.iText.
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC CEikMenuPaneItem::ScaleableText() const
{
if ( ( iExtendedData ) && ( iExtendedData->iScaleableText ) )
{
return iExtendedData->iScaleableText->Des();
}
return iData.iText;
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::SetScaleableTextL
// Sets scaleable text. iData.iText is set to first text version.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPaneItem::SetScaleableTextL( const TDesC& aText )
{
if ( iExtendedData )
{
if ( iExtendedData->iScaleableText )
{
delete iExtendedData->iScaleableText;
iExtendedData->iScaleableText = NULL;
}
iData.iText = GetNominalText( aText );
if ( IsScaleableText( aText ) )
{
iExtendedData->iScaleableText = HBufC::NewL( aText.Length() );
iExtendedData->iScaleableText->Des().Copy( aText );
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPaneItem::GetNominalText
// -----------------------------------------------------------------------------
//
TPtrC CEikMenuPaneItem::GetNominalText( const TDesC& aText )
{
TInt limit = aText.Length();
TInt border = aText.Locate( TChar( KScaleableTextSeparator ) );
if ( border != KErrNotFound )
{
limit = border;
}
limit = ( limit > CEikMenuPaneItem::SData::ENominalTextLength ? CEikMenuPaneItem::SData::ENominalTextLength : limit );
return aText.Left( limit);
}
//
// class CEikMenuPane
//
// -----------------------------------------------------------------------------
// CEikMenuPane::~CEikMenuPane
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPane::~CEikMenuPane()
{
_AKNTRACE_FUNC_ENTER;
AKNTASHOOK_REMOVE();
if ( iIsDeleted )
{
*iIsDeleted = ETrue;
iIsDeleted = NULL;
}
CloseCascadeMenu();
if ( !ItemArrayOwnedExternally() )
{
delete iItemArray;
iItemArray = NULL;
}
else
{
ResetItemArray();
}
if ( iLaunchingButton )
{
TPointerEvent event;
event.iType = TPointerEvent::EButton1Up;
event.iModifiers = 0;
event.iPosition = iLaunchingButton->Position();
TRAP_IGNORE( iLaunchingButton->HandlePointerEventL( event ) );
iLaunchingButton = NULL; // not owned
}
delete iScroller;
iScroller = NULL;
delete iSBFrame;
iSBFrame = NULL;
iMenuObserver = NULL; // not owned
iEditMenuObserver = NULL; // not owned
iOwner = NULL; // not owned
delete iExtension;
iExtension = NULL;
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CEikMenuPane
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPane::CEikMenuPane( MEikMenuObserver* aMenuObserver )
: iMenuObserver( aMenuObserver )
{
_AKNTRACE_FUNC_ENTER;
__ASSERT_DEBUG( iMenuObserver,Panic( EEikPanicNullPointer ) );
__DECLARE_NAME(_S("CEikMenuPane"));
iBorder = TGulBorder( AknBorderId::EAknBorderMenuSubmenuPopup ); // AKNLAF
iAllowPointerUpEvents = EFalse;
iNumberOfDragEvents = 0;
MakeVisible( EFalse );
AKNTASHOOK_ADD( this, "CEikMenuPane" );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ConstructL
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::ConstructL( CEikMenuPane* aOwner, MEikMenuObserver* aEditMenuObserver )
{
_AKNTRACE_FUNC_ENTER;
iOwner = aOwner;
iEditMenuObserver = aEditMenuObserver;
CheckCreateScrollerL();
CheckCreateExtensionL();
CreateWindowL( iCoeEnv->RootWin() );
EnableWindowTransparency();
SetAllowStrayPointers();
EnableDragEvents();
iItemHeight = CalculateItemHeight();
if ( iExtension->iSct )
{
RWindow* window = (RWindow*)this->DrawableWindow();
iExtension->iMenuPaneWindow = window;
iExtension->iSct->SetContainerWindowL( *this );
// This is effectively the same as CCoeControl::EnableDragEvents()
// which is protected.
window->PointerFilter( EPointerFilterDrag, 0 );
iExtension->iSct->SetGloballyCapturing( ETrue );
iExtension->iSct->SetPointerCapture( ETrue );
iExtension->iSct->SetObserver(iExtension);
}
if ( iOwner ) // submenu
{
SetPointerCapture( ETrue );
}
LoadCascadeBitmapL();
LoadCheckMarkBitmapL();
LoadRadioButtonBitmapL();
// Window may not be created if OOM earlier during construction
RWindow* window = &Window();
if( window == NULL )
User::Leave( KErrNoMemory );
Window().SetOrdinalPosition( 0 );
Window().SetPointerGrab( ETrue );
SetGloballyCapturing( ETrue );
iExtension->iPhysics->UpdateViewWindowControl();
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ConstructFromResourceL
// Constructs the menu pane using the resource reader aReader, filling the menu item array with the
// list of menu items provided by the resource file.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::ConstructFromResourceL( TResourceReader& aReader )
{
if ( iItemArray && !ItemArrayOwnedExternally() )
{
delete iItemArray;
iItemArray = NULL;
}
CreateItemArrayL();
iItemHeight = CalculateItemHeight();
CheckCreateScrollerL();
CheckCreateExtensionL();
const TInt count=aReader.ReadInt16();
for ( TInt ii=0; ii<count; ++ii )
{
CEikMenuPaneItem* item = new(ELeave) CEikMenuPaneItem();
CleanupStack::PushL( item );
item->iData.iCommandId = aReader.ReadInt32();
item->iData.iCascadeId = aReader.ReadInt32();
item->iData.iFlags = aReader.ReadInt32();
TPtrC txtptr = aReader.ReadTPtrC();
item->SetScaleableTextL( txtptr );
TPtrC extratxtptr = aReader.ReadTPtrC();
item->iData.iExtraText = extratxtptr;
CreateIconFromResourceL( aReader, *item );
CleanupStack::Pop(); // pop first, since additem pushes again
iItemArray->AddItemL( item );
aReader.ReadInt32(); // extension link
if ( item->iData.iFlags&( EEikMenuItemRadioStart|EEikMenuItemRadioMiddle|EEikMenuItemRadioEnd ) )
{
iExtension->iHasRadioGroup = ETrue;
if ( item->iData.iFlags&EEikMenuItemSymbolOn )
{
iExtension->iSelectedRadioButtonItem = ii;
}
}
}
aReader.ReadInt32(); // extension link
}
// -----------------------------------------------------------------------------
// CEikMenuPane::AddMenuItemsL
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::AddMenuItemsL( TInt aResourceId, TInt aPreviousId, TBool /*aAddSeperator*/ )
{
if ( !iItemArray )
{
CreateItemArrayL();
}
// Read from resource and add items after the item with 'aPreviousId'
TResourceReader reader;
iEikonEnv->CreateResourceReaderLC( reader, aResourceId );
TInt position = iItemArray->Count();
if ( aPreviousId )
{
ItemAndPos( aPreviousId, position );
position++;
}
// 'Active Applications' menu item is forced to be first
// item in the options menu.
if (aResourceId == R_AVKON_MENUPANE_TASK_SWAPPER)
{
position = 0;
}
const TInt count = reader.ReadInt16();
for (TInt ii = 0; ii < count; ++ii)
{
CEikMenuPaneItem* item = new(ELeave) CEikMenuPaneItem();
CleanupStack::PushL( item );
item->iData.iCommandId = reader.ReadInt32();
item->iData.iCascadeId = reader.ReadInt32();
item->iData.iFlags = reader.ReadInt32();
TPtrC txtptr = reader.ReadTPtrC();
item->SetScaleableTextL( txtptr );
TPtrC extratxtptr = reader.ReadTPtrC();
item->iData.iExtraText = extratxtptr;
CreateIconFromResourceL( reader, *item );
iItemArray->InsertL( position++, item );
reader.ReadInt32(); // extension link
CleanupStack::Pop();
if ( item->iData.iFlags&(EEikMenuItemRadioStart|EEikMenuItemRadioMiddle|EEikMenuItemRadioEnd) )
{
iExtension->iHasRadioGroup = ETrue;
if ( item->iData.iFlags&EEikMenuItemSymbolOn )
{
iExtension->iSelectedRadioButtonItem = ii; // so if there are several on, we have only the last of them to be activated
}
}
}
CleanupStack::PopAndDestroy();// reader
}
// -----------------------------------------------------------------------------
// CEikMenuPane::FilterDimmedItems
// -----------------------------------------------------------------------------
//
void CEikMenuPane::FilterDimmedItems()
{
TInt pos = iItemArray->Count() - 1;
while ( pos >= 0 )
{
CEikMenuPaneItem* item = (*iItemArray)[pos];
if ( item->iData.iFlags&EEikMenuItemDimmed )
{
DeleteMenuItem( item->iData.iCommandId );
}
pos--;
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetScrollBarOnLeft
// Sets the scroll bar to occupy the left side of the menu pane if aOnLeft is ETrue
//
// @since ER5U
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetScrollBarOnLeft(TBool aOnLeft)
{
if ( aOnLeft )
{
iFlags |= EEikMenuItemScrollBarLeft;
}
else
{
iFlags &= (~EEikMenuItemScrollBarLeft);
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetArrowHeadScrollBar
// Sets the menu pane to use an arrow head scroll bar if aArrowHead is ETrue.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetArrowHeadScrollBar( TBool /*aArrowHead*/ )
{
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ResetItemArray
// Resets the menu's array of items and destroys its elements.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
void CEikMenuPane::ResetItemArray()
{
if ( !iItemArray )
{
return;
}
iItemArray->ResetAndDestroy();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CreateItemArrayL
// Creates a new item array to be owned by the menu pane.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CreateItemArrayL()
{
iItemArray = new(ELeave) CItemArray;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CreateIconFromResourceL
// Creates an icon for the menu item aItem using the resource reader aReader.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CreateIconFromResourceL( TResourceReader& aReader, CEikMenuPaneItem& aItem ) const
{
TPtrC bitmapFile = aReader.ReadTPtrC();
TInt bitmapId = aReader.ReadInt16();
TInt bitmapMaskId = aReader.ReadInt16();
if ( bitmapId != -1 )
{
CFbsBitmap* bitmap = NULL;
CFbsBitmap* bitmapMask = NULL;
if ( bitmapId == EMbmAvkonQgn_indi_app_open_add )
{
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::CreateIconLC(skin,
KAknsIIDQgnIndiAppOpen,
bitmap, bitmapMask,
bitmapFile,
bitmapId, bitmapMaskId);
}
else
{
AknIconUtils::CreateIconLC(bitmap, bitmapMask,
bitmapFile,
bitmapId, bitmapMaskId);
}
aItem.CreateIconL(bitmap, bitmapMask);
CleanupStack::Pop(2); // bitmap, bitmapMask.
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::Reset
// Destroys the menu pane's item array and scroll bar frame.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::Reset()
{
delete iItemArray;
iItemArray = NULL;
delete iSBFrame;
iSBFrame = NULL;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CloseCascadeMenu
// Closes and destroys any current cascade menu and takes focus back.
// Does nothing if no cascade menu exists.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::CloseCascadeMenu()
{
CloseCascadeMenu( EFalse );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::TryLaunchCascadeMenuL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::TryLaunchCascadeMenuL(const CEikMenuPaneItem& aItem)
{
_AKNTRACE_FUNC_ENTER;
iExtension->iShowCascadeTransition = EFalse;
iExtension->iButtonDownItem = KErrNotFound;
if ( aItem.iData.iFlags&EEikMenuItemDimmed )
{
iMenuObserver->HandleAttemptDimmedSelectionL( aItem.iData.iCommandId );
return;
}
LaunchCascadeMenuL( aItem.iData.iCascadeId );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::LaunchCascadeMenuL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::LaunchCascadeMenuL( TInt aCascadeMenuId )
{
_AKNTRACE_FUNC_ENTER;
#ifdef THIS_IS_CORRECT_CODE_BUT_DISABLED_BECAUSE_OF_TEST_APPS
// Series 60 does not have cascade options menus from another cascade menus..
if ( iOwner ) return;
#endif // THIS_IS_CORRECT_CODE_BUT_DISABLED_BECAUSE_OF_TEST_APPS
TInt err( KErrNone );
TRAP( err, iCascadeMenuPane = new(ELeave) CEikMenuPane( iMenuObserver ));
iCascadeMenuPane->SetMopParent( this );
iCascadeMenuPane->SetObserver( Observer() );
// delete object here so that new cascade menu pane does not get the same
// address -> messes up transition registration..
if( iExtension->iCascadeMenuObject )
{
GfxTransEffect::Deregister( iExtension->iCascadeMenuObject );
}
delete iExtension->iCascadeMenuObject;
iExtension->iCascadeMenuObject = NULL;
User::LeaveIfError( err );
// register cascade options menu
GfxTransEffect::Register( iCascadeMenuPane, KGfxOptionsMenuCascadeControlUid, EFalse );
TRAP( err, DoLaunchCascadeMenuL( aCascadeMenuId ) );
if ( err )
{
CloseCascadeMenu();
User::Leave( err );
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::DoLaunchCascadeMenuL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::DoLaunchCascadeMenuL( TInt aCascadeMenuId )
{
_AKNTRACE_FUNC_ENTER;
if ( !iItemArray || iItemArray->Count() == 0 )
{
return;
}
iCascadeMenuPane->ConstructL( this, iEditMenuObserver );
iCascadeMenuPane->SetSelectedItem( 0 );
// Stop menu pane physics when launching cascade menu
iExtension->iPhysics->StopPhysics();
iExtension->iPhysics->ResetFriction();
iMenuObserver->RestoreMenuL(iCascadeMenuPane,aCascadeMenuId,MEikMenuObserver::EMenuPane);
MEikMenuObserver* fepMenuObserver = CAknEnv::Static()->FepMenuObserver();
if (fepMenuObserver)
{
fepMenuObserver->DynInitMenuPaneL( aCascadeMenuId, iCascadeMenuPane );
}
if (iEditMenuObserver)
{
iEditMenuObserver->DynInitMenuPaneL( aCascadeMenuId, iCascadeMenuPane );
}
if ( iExtension->iFlags.IsSet( CEikMenuPaneExtension::EHideMarkAndUnmark ) )
{
TInt pos;
if ( iCascadeMenuPane->MenuItemExists( EAknCmdMark, pos ) )
{
iCascadeMenuPane->SetItemDimmed( EAknCmdMark, ETrue );
}
if ( iCascadeMenuPane->MenuItemExists( EAknCmdUnmark, pos ) )
{
iCascadeMenuPane->SetItemDimmed( EAknCmdUnmark, ETrue );
}
}
iCascadeMenuPane->iExtension->PrepareCascadeForItemCommandsL();
iCascadeMenuPane->iExtension->EnableHighlight( EFalse );
iCascadeMenuPane->FilterDimmedItems();
// cascade menu launch animation
if ( iExtension->iRedirectionListener )
{
iExtension->iRedirectionListener->LaunchCascadeMenu();
}
else
{
iExtension->StartCascadeMenuAppearTransition();
}
TTouchLogicalFeedback fbLogicalType = ETouchFeedbackPopUp;
if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) )
{
fbLogicalType = ETouchFeedbackSubMenuOpened;
}
iExtension->ImmediateFeedback( fbLogicalType,
ETouchFeedbackVibra );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CalculateSizeAndPosition
// Calculates and returns the menu pane's size.
// Also sets the rectangle of the menu pane.
// -----------------------------------------------------------------------------
//
TRect CEikMenuPane::CalculateSizeAndPosition()
{
_AKNTRACE_FUNC_ENTER;
TRect retVal;
TInt numItemsInPane = 0;
if ( iItemArray )
{// Min size is for 1 item even if menu is empty
numItemsInPane = iItemArray->Count();
}
if ( iExtension && iExtension->iSct )
{
numItemsInPane++;
}
TInt maxItemsInView = NumberOfItemsThatFitInView();
if (iExtension && iExtension->iSct)
{
maxItemsInView++;
}
numItemsInPane = Min( Max( 1, numItemsInPane ), maxItemsInView);
TRect windowRect;
AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EPopupParent, windowRect );
retVal = CalculateSizeAndPositionScalable( windowRect, numItemsInPane );
_AKNTRACE_FUNC_EXIT;
return retVal;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::StartDisplayingMenuPane
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::StartDisplayingMenuPane( const CEikHotKeyTable* /*aHotKeyTable*/,
const TPoint& /*aTargetPos*/,
const CEikMenuPaneTitle* /*aMenuPaneTitle*/,
TInt /*aMinTitleWidth*/,
TPopupTargetPosType /*aTargetType*/ )
{
_AKNTRACE_FUNC_ENTER;
if ( iExtension->iRedirectionListener )
{
iExtension->iRedirectionListener->AppearTransitionStarting();
}
CreateScrollBarFrame();
iExtension->iPressedDown = EFalse;
iExtension->SetOffset( 0 );
const TSize screenSize( iEikonEnv->EikAppUi()->ApplicationRect().Size() );
CEikCba *cba = 0;
MopGetObject(cba);
if ( cba )
{
cba->SetSkinBackgroundId( KAknsIIDQsnBgAreaControlPopup );
}
iScroller->SetTopItemIndex(0); // to avoid broken values of topitemindex
// set highlight visible if menu was opened via HW keys
if ( iCoeEnv->LastEvent().Type() == EEventKey
&& iCoeEnv->LastEvent().Key()
&& iCoeEnv->LastEvent().Key()->iCode == EKeyCBA1 )
{
SetDefaultHighlight();
}
SetRect( CalculateSizeAndPosition() );
// We need to set the background context when calling create for the
// first time. Otherwise iExtension->iBgContext would have tiny
// rectangles and grabbing the highlight background would produce
// white.
UpdateBackgroundContext( Rect() );
// Initialize physics engine
TRAP_IGNORE ( iExtension->InitPhysicsL() );
MakeVisible(ETrue);
SetFocus(ETrue);
Window().SetPointerGrab( ETrue );
if ( iExtension->iSct )
{
iExtension->iSctHighlighted = ETrue;
iSelectedItem = ENothingSelected;
// If SCT row existing, set the default focus on SCT row not the top
}
if (iSelectedItem != ENothingSelected)
{
ScrollToMakeItemVisible(iSelectedItem);
}
PrepareHighlightFrame();
SetCascadedIconSize();
TRAP_IGNORE( ActivateL());
if (iMenuPaneTitle)
{
CONST_CAST(CEikMenuPaneTitle*,iMenuPaneTitle)->MakeVisible(ETrue);
TRAP_IGNORE( CONST_CAST(CEikMenuPaneTitle*,iMenuPaneTitle)->ActivateL());
iMenuPaneTitle->DrawNow();
}
TRAP_IGNORE( DoUpdateScrollBarL() );
// No highlight - hide softkey
if ( iExtension && iExtension->iCba )
{
iExtension->iCba->MakeCommandVisible( EAknSoftkeySelect,
iExtension->iFlags.IsSet(
CEikMenuPaneExtension::EHighlightEnabled ) );
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::UpdateBackgroundContext
// -----------------------------------------------------------------------------
//
void CEikMenuPane::UpdateBackgroundContext( const TRect& aWindowRect )
{
_AKNTRACE_FUNC_ENTER;
TAknLayoutRect topLeft;
TAknLayoutRect bottomRight;
TAknsItemID frameIID;
TAknsItemID frameCenterIID;
if( iOwner ) //for sub menu
{
topLeft.LayoutRect( aWindowRect, SkinLayout::Submenu_skin_placing_Line_2() );
bottomRight.LayoutRect( aWindowRect, SkinLayout::Submenu_skin_placing_Line_5() );
frameIID = KAknsIIDQsnFrPopupSub;
frameCenterIID = KAknsIIDQsnFrPopupCenterSubmenu;
}
else
{
topLeft.LayoutRect( aWindowRect, SkinLayout::Popup_windows_skin_placing__frame_general__Line_2() );
bottomRight.LayoutRect( aWindowRect, SkinLayout::Popup_windows_skin_placing__frame_general__Line_5() );
frameIID = KAknsIIDQsnFrPopup;
frameCenterIID = KAknsIIDQsnFrPopupCenterMenu;
}
TRect outerRect( topLeft.Rect().iTl, bottomRight.Rect().iBr );
TRect innerRect( topLeft.Rect().iBr, bottomRight.Rect().iTl );
if( iExtension )
{
iExtension->iBgContext->SetFrame( frameIID );
iExtension->iBgContext->SetCenter( frameCenterIID );
iExtension->iBgContext->SetFrameRects( outerRect, innerRect );
}
_AKNTRACE( " outerRect.iTl.iX = %d", outerRect.iTl.iX );
_AKNTRACE( " outerRect.iTl.iY = %d", outerRect.iTl.iY );
_AKNTRACE( " outerRect.iBr.iX = %d", outerRect.iBr.iX );
_AKNTRACE( " outerRect.iBr.iY = %d", outerRect.iBr.iY );
_AKNTRACE( " innerRect.iTl.iX = %d", innerRect.iTl.iX );
_AKNTRACE( " innerRect.iTl.iY = %d", innerRect.iTl.iY );
_AKNTRACE( " innerRect.iBr.iX = %d", innerRect.iBr.iX );
_AKNTRACE( " innerRect.iBr.iY = %d", innerRect.iBr.iY );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::RepaintHighlight
// -----------------------------------------------------------------------------
//
void CEikMenuPane::RepaintHighlight() const
{
if ( !iExtension->iSctHighlighted )
{
DrawItem( SelectedItem(), EDrawHighlight );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MoveHighlightTo
// Moves the menu pane highlight to the new selected menu item aNewSelectedItem.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::MoveHighlightTo(TInt aNewSelectedItem)
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "aNewSelectedItem = %d", aNewSelectedItem );
_AKNTRACE( "iSelectedItem = %d", iSelectedItem );
if ( aNewSelectedItem == iSelectedItem )
{
return;
}
iExtension->StopCascadeMenuTimer();
TInt previousTopItem = iScroller->TopItemIndex();
TInt previousSelectedItem = iSelectedItem;
_AKNTRACE( "previousTopItem = %d", previousTopItem );
_AKNTRACE( "previousSelectedItem = %d", previousSelectedItem );
SetSelectedItem( aNewSelectedItem );
if ( aNewSelectedItem >= 0 )
{
ScrollToMakeItemVisible( aNewSelectedItem );
}
else
{
ScrollToMakeItemVisible( 0 );
}
ActivateGc();
CWindowGc& gc = SystemGc();
PrepareGcForDrawingItems( gc );
TInt topItem = iScroller->TopItemIndex();
TInt bottomItem = topItem + NumberOfItemsThatFitInView();
if( bottomItem > NumberOfItemsInPane() )
{
bottomItem = NumberOfItemsInPane();
}
_AKNTRACE( "topItem = %d", topItem );
_AKNTRACE( "bottomItem = %d", bottomItem );
// When the SCT row will be highlight, remove highlight from
// bottom's and top's item.
if (iExtension->iSctHighlighted)
{
DrawItem( gc, topItem, ERemoveHighlight );
DrawItem( gc, (bottomItem-1), ERemoveHighlight );
}
PrepareHighlightFrame();
if ( previousTopItem == topItem && aNewSelectedItem >= 0 )
{
// then only previuosly and currently selected items should be redrawn
if ( iExtension->iHighlightedItem != KErrNotFound )
{
DrawItem( gc, previousSelectedItem, ERemoveHighlight );
}
if ( !iExtension->iSctHighlighted )
{
DrawItem( gc, aNewSelectedItem, EDrawHighlight );
}
}
DeactivateGc();
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::PrepareGcForDrawingItems
// -----------------------------------------------------------------------------
//
void CEikMenuPane::PrepareGcForDrawingItems(CGraphicsContext& aGc) const
{
// BIDI
/*
* get the fonts from the LAF!
* Do we need to get them here? - nope - moved to DrawItem()
*/
aGc.SetPenColor( iEikonEnv->ControlColor( EColorMenuPaneText, *this) );
aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );
aGc.SetBrushColor( iEikonEnv->ControlColor( EColorMenuPaneBackground,*this ) );
}
// ---------------------------------------------------------------------------
// CEikMenuPane::DrawItem
// ---------------------------------------------------------------------------
//
void CEikMenuPane::DrawItem( TInt aItem, THighlightType aHighlight ) const
{
ActivateGc();
CWindowGc& gc = SystemGc();
PrepareGcForDrawingItems( gc );
DrawItem( gc, aItem, aHighlight );
DeactivateGc();
}
// ---------------------------------------------------------------------------
// CEikMenuPane::DrawItem
// ---------------------------------------------------------------------------
//
void CEikMenuPane::DrawItem(CWindowGc& aGc,TInt aItem,THighlightType aHighlight) const
// BIDI - no hotkey text. No pre-adornments
{
if ( !iItemArray || iItemArray->Count() == 0 || aItem == ENothingSelected )
{
return;
}
TInt numItemsInArray = iItemArray->Count();
__ASSERT_DEBUG( aItem < numItemsInArray, Panic( EEikPanicNoSuchMenuItem ) );
if ( aItem >= numItemsInArray )
{
return;
}
CEikMenuPaneItem* item = (*iItemArray)[aItem];
// Max visible number of items in menu / submenu
TInt maxNumberOfItems = NumberOfItemsThatFitInView();
TInt topIndex = iScroller->TopItemIndex();
// true if a cascade symbol must be drawn (main menu only)
TBool cascade = ( item->iData.iCascadeId != 0 );
// Specifies whether the text should be moved to give some space for icon.
TBool hasIcon = MenuHasIcon();
if ( iExtension->iSct )
{
++maxNumberOfItems;
++numItemsInArray;
}
// number of items in the whole menu
TInt numItems = Min( Max( 1, numItemsInArray ), maxNumberOfItems );
TInt index = aItem - topIndex;
if ( iExtension->iSct )
{
// Sct row exists -> the rest of the menu items are pushed down
// in visual representation.
++index;
}
TInt itemLeftInBottom = maxNumberOfItems -(numItemsInArray - topIndex);
if ( (itemLeftInBottom > 0) && (topIndex > 0) )
{
index += itemLeftInBottom;
}
TBool drawSeparator = !( ( index + topIndex ) == numItemsInArray - 1 );
TBool drawPartialItem = EFalse;
if ( index == maxNumberOfItems )
{
// We have partial items to draw because of panning so there
// is one more item to draw than normally.
drawPartialItem = ETrue;
// There is no layout data for the extra item, so we used the one
// above it.
--index;
}
// If in Menu Sct, skip the first row of the recent used characters
if ( index < 0 || index >= maxNumberOfItems || (iExtension->iSct && index==0))
{
return; // only interested in drawing visible items
}
TAknTextLineLayout menuTextLayout;
TAknLayoutRect singleMenuPaneRect;
if ( !iOwner ) // main menu
{
singleMenuPaneRect.LayoutRect( iExtension->iItemAreaRect,
AknLayoutScalable_Avkon::list_single_pane_cp2( index ).LayoutLine() );
menuTextLayout =
AknLayoutScalable_Avkon::list_single_pane_t1_cp2( cascade ? 1 : 0 ).LayoutLine();
}
else // submenu
{
singleMenuPaneRect.LayoutRect( iExtension->iItemAreaRect,
AknLayoutScalable_Avkon::list_single_popup_submenu_pane( index ).LayoutLine() );
if ( hasIcon )
{
menuTextLayout =
TAknTextLineLayout(
AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1( 1 ).LayoutLine() );
}
else
{
menuTextLayout =
TAknTextLineLayout(
AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1( 0 ).LayoutLine() );
}
}
TRect itemRect( singleMenuPaneRect.Rect() );
// Move the rect with our panning offset.
itemRect.iTl.iY += iExtension->Offset();
itemRect.iBr.iY += iExtension->Offset();
if( drawPartialItem )
{
// For the extra item, also move it one full item height
itemRect.iTl.iY += iItemHeight;
itemRect.iBr.iY += iItemHeight;
}
TBool drawingInitiated = ETrue;
RWindow& window = Window();
if ( &window && window.GetDrawRect() == TRect::EUninitialized )
{
drawingInitiated = EFalse;
}
if ( !drawingInitiated && !iExtension->iFullRedraw )
{
TRect drawRect( itemRect );
drawRect.Intersection( iExtension->iItemAreaRect );
window.Invalidate( drawRect );
window.BeginRedraw( drawRect );
}
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
MAknsControlContext* cc = NULL;
if( iExtension )
{
cc = iExtension->iBgContext;
}
TBool background( ETrue );
aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );
aGc.SetBrushColor( singleMenuPaneRect.Color() );
// there can be partial items, so clip drawing on menu pane's item area
aGc.SetClippingRect( iExtension->iItemAreaRect );
if (!iExtension->iFullRedraw)
{
background = AknsDrawUtils::Background(
skin, cc, this, aGc, itemRect,
KAknsDrawParamNoClearUnderImage );
}
if ( !background )
{
aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );
aGc.SetPenStyle( CGraphicsContext::ENullPen );
aGc.SetPenColor( singleMenuPaneRect.Color() );
aGc.SetBrushColor( singleMenuPaneRect.Color() );
aGc.DrawRect( itemRect );
}
if ( !iExtension->HighlightEnabled() )
{
aHighlight = ENoHighlight;
}
switch ( aHighlight )
{
case EDrawHighlight :
{
if ( !iExtension->iSctHighlighted )
{
iExtension->iHighlightedItem = aItem;
// Because of transparency, background must be drawn here as well
// (as frame may be see-through)
aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );
aGc.SetBrushColor( singleMenuPaneRect.Color() );
AknsDrawUtils::Background(
skin, cc, this, aGc, itemRect,
KAknsDrawParamNoClearUnderImage );
TAknLayoutRect highlightTopLeft;
TAknLayoutRect highlightBottomRight;
highlightTopLeft.LayoutRect(itemRect,
SkinLayout::List_highlight_skin_placing__popup_windows__Line_2() );
highlightBottomRight.LayoutRect(itemRect,
SkinLayout::List_highlight_skin_placing__popup_windows__Line_5() );
TRect outerRect( highlightTopLeft.Rect().iTl, highlightBottomRight.Rect().iBr );
TRect innerRect( highlightTopLeft.Rect().iBr, highlightBottomRight.Rect().iTl );
TBool drawOk = AknsDrawUtils::DrawFrame( skin,
aGc,
outerRect,
innerRect,
KAknsIIDQsnFrList,
KAknsIIDDefault );
// skinned highlight drawing has failed
if ( !drawOk )
{
TAknLayoutRect shadowRect;
TAknLayoutRect highlightRect;
shadowRect.LayoutRect( itemRect,
AKN_LAYOUT_WINDOW_Highlight_graphics__various__Line_1( itemRect ) );
highlightRect.LayoutRect( itemRect,
AKN_LAYOUT_WINDOW_Highlight_graphics__various__Line_2( itemRect ) );
aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );
shadowRect.DrawRect( aGc );
highlightRect.DrawRect( aGc );
}
}
break;
}
case ERemoveHighlight:
case ENoHighlight:
if ( iExtension->iHighlightedItem == aItem )
{
iExtension->iHighlightedItem = KErrNotFound;
}
default:
break;
}
// Cascade
if ( cascade )
{
TAknWindowLineLayout elementCascade( AknLayoutScalable_Avkon::list_single_pane_cp2_g3().LayoutLine());
TAknLayoutRect cascadeRect;
cascadeRect.LayoutRect( itemRect, elementCascade );
aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
CAknsMaskedBitmapItemData* itemData = static_cast<CAknsMaskedBitmapItemData*>(
skin->GetCachedItemData( KAknsIIDQgnIndiSubmenu, EAknsITMaskedBitmap ) );
if( itemData )
{
AknIconUtils::SetSize( itemData->Bitmap(),cascadeRect.Rect().Size() );
aGc.BitBltMasked( cascadeRect.Rect().iTl, itemData->Bitmap(),
cascadeRect.Rect().Size(), itemData->Mask(), ETrue );
}
else
{
if ( iExtension->iCascadeBitmap && iExtension->iCascadeBitmapMask )
{
AknIconUtils::SetSize( iExtension->iCascadeBitmap,cascadeRect.Rect().Size() );
aGc.BitBltMasked( cascadeRect.Rect().iTl, iExtension->iCascadeBitmap,
cascadeRect.Rect().Size(), iExtension->iCascadeBitmapMask, ETrue );
}
}
}
else
{
TAknLayoutRect activeApplicationsIconRect;
activeApplicationsIconRect.LayoutRect( itemRect,
AknLayoutScalable_Avkon::list_single_pane_g1_cp2(0).LayoutLine() );
item->DrawItemIcon( aGc, activeApplicationsIconRect.Rect(), EFalse, 0);
}
if ( hasIcon )
{
TAknLayoutRect iconLayoutRect;
iconLayoutRect.LayoutRect( itemRect,
AknLayoutScalable_Avkon::list_single_popup_submenu_pane_g1().LayoutLine() );
TRect iconRect = iconLayoutRect.Rect();
// radio button group
if ( iExtension->iHasRadioGroup )
{
if( IsItemMemberOfRadioButtonGroup(aItem) )
{
if ( iExtension->iSelectedRadioButtonItem == KNoSelectedRadioButtonItem &&
item->iData.iFlags&EEikMenuItemRadioStart )
{
// just to be sure that some radio button is set on
iExtension->iSelectedRadioButtonItem = aItem;
}
if ( aItem == iExtension->iSelectedRadioButtonItem )
{
// draw radio button
aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
CAknsMaskedBitmapItemData* itemData = static_cast<CAknsMaskedBitmapItemData*>(
skin->GetCachedItemData( KAknsIIDQgnIndiRadiobuttOn, EAknsITMaskedBitmap ) );
CFbsBitmap* radioButtonBmp = iExtension->iRadioButtonBitmap;
CFbsBitmap* radioButtonMask = iExtension->iRadioButtonBitmapMask;
if( itemData )
{
radioButtonBmp = itemData->Bitmap();
radioButtonMask = itemData->Mask();
}
if( radioButtonBmp && radioButtonMask )
{
AknIconUtils::SetSize( radioButtonBmp, iconRect.Size() );
aGc.BitBltMasked( iconRect.iTl, radioButtonBmp,
iconRect.Size(), radioButtonMask, ETrue );
}
}
}
}
else if ( item->iData.iFlags&EEikMenuItemSymbolOn )
// draw check mark
{
aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
CAknsMaskedBitmapItemData* itemData = static_cast<CAknsMaskedBitmapItemData*>(
skin->GetCachedItemData( KAknsIIDQgnIndiMarkedAdd, EAknsITMaskedBitmap ) );
CFbsBitmap* checkMarkBmp = iExtension->iCheckMarkBitmap;
CFbsBitmap* checkMarkMask = iExtension->iCheckMarkBitmapMask;
if( itemData )
{
checkMarkBmp = itemData->Bitmap();
checkMarkMask = itemData->Mask();
}
if( checkMarkBmp && checkMarkMask )
{
AknIconUtils::SetSize( checkMarkBmp, iconRect.Size() );
aGc.BitBltMasked( iconRect.iTl, checkMarkBmp,
iconRect.Size(), checkMarkMask, ETrue );
}
}
}
// Text
TAknLayoutText textRect;
textRect.LayoutText( itemRect, menuTextLayout );
TRgb textColor = textRect.Color();
if ( aHighlight == EDrawHighlight ) // highlighted text
{
AknsUtils::GetCachedColor( skin, textColor, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG10 );
}
else if ( !iOwner ) // menu
{
AknsUtils::GetCachedColor( skin, textColor, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG19 );
}
else // submenu
{
AknsUtils::GetCachedColor( skin, textColor, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG20 );
}
//when OOM, the background is White, if the font's color is white, hardcode it to black
if( !background && aHighlight != EDrawHighlight )
{
const TInt KRate = 95; // 95% similar rate
const TInt KFullColor = 255;
TInt redcolor = textColor.Red();
TInt bluecolor = textColor.Blue();
TInt greencolor = textColor.Green();
// test if the color is too similar to white color
if ( redcolor > KFullColor * KRate / 100 ||
bluecolor > KFullColor * KRate / 100 ||
greencolor > KFullColor * KRate / 100 )
{
textColor = KRgbBlack;
}
}
aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
aGc.SetPenColor( textColor );
const CFont* font = textRect.Font();
//TBuf<CEikMenuPaneItem::SData::ENominalTextLength + KAknBidiExtraSpacePerLine> visualText; // buffer for visually ordered text
TBuf<255 + KAknBidiExtraSpacePerLine> visualText; // buffer for visually ordered text
TInt clipWidth = textRect.TextRect().Width();
AknBidiTextUtils::ConvertToVisualAndClip(
item->ScaleableText(),
visualText,
*font,
clipWidth,
clipWidth );
textRect.DrawText( aGc, visualText, EFalse, textColor );
// calculate demarcation rectangle for cascaded menu item
if (iCascadeMenuPane)
{
TPoint position( PositionRelativeToScreen() );
TRect cascRect( textRect.TextRect() );
cascRect.Move( position );
iExtension->iCascadeDRect.SetRect( cascRect.iTl, cascRect.iBr );
}
TAknLayoutRect highlightRect;
highlightRect.LayoutRect( itemRect,
AKN_LAYOUT_WINDOW_Highlight_graphics__various__Line_2( itemRect ) );
// store the calculated y-position to the menu item,
// so that it can be used in HandlePointerEventL()
item->iPos = highlightRect.Rect().iTl.iY;
// don't draw separator line for the last item
if ( drawSeparator )
{
AknListUtils::DrawSeparator( aGc, itemRect, textColor, skin );
}
if ( !drawingInitiated && !iExtension->iFullRedraw )
{
Window().EndRedraw();
}
aGc.CancelClippingRect();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::Draw
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::Draw( const TRect& aRect ) const
{
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
MAknsControlContext* cc = NULL;
if( iExtension )
{
cc = iExtension->iBgContext;
}
CWindowGc& gc = SystemGc();
PrepareGcForDrawingItems( gc );
TInt count=0;
if( iItemArray )
{
count=iItemArray->Count();
}
// Give the topmost menu item's rect to SCT if needed.
if ( iExtension->iSct )
{
iExtension->iSct->SetMenuSctRect( ItemRect( 0 ) );
TRegionFix<4> region;
region.AddRect( aRect );
region.SubRect( iExtension->iSct->Rect() );
gc.SetClippingRegion( region );
}
// The added flag removes the white bg for transparency
TBool frameDrawn = AknsDrawUtils::Background(
skin, cc, this, gc, aRect, KAknsDrawParamNoClearUnderImage );
if ( aRect.Intersects( iExtension->iItemAreaRect ) )
{
iExtension->iFullRedraw = ETrue;
for ( TInt ii=0;ii<count;++ii )
{
if(!iExtension->iSctHighlighted && ii == iSelectedItem )
DrawItem( gc, ii, EDrawHighlight);
else
DrawItem( gc, ii, ENoHighlight);
}
iExtension->iFullRedraw = EFalse;
}
if ( iExtension->iSct )
{
gc.CancelClippingRegion();
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ReportSelectionMadeL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::ReportSelectionMadeL( TBool aAbortTransition )
{
_AKNTRACE_FUNC_ENTER;
if( aAbortTransition )
{
GfxTransEffect::Abort();
}
if ( !iItemArray || iItemArray->Count() == 0 )
{
return;
}
if ( iCascadeMenuPane )
{
SetFocus( EFalse, EDrawNow );
iCascadeMenuPane->SetFocus( ETrue, EDrawNow );
return;
}
// means the cascade created on the down event is getting the up event
if ( iSelectedItem == ENothingSelected && !iExtension->iSctHighlighted)
{
return;
}
CEikMenuPaneItem* item = NULL;
// the sct highlight does not have index so do not try to get item with the index
if(iSelectedItem != ENothingSelected)
item = (*iItemArray)[iSelectedItem];
if ( item && item->iData.iFlags&EEikMenuItemDimmed )
{
iMenuObserver->HandleAttemptDimmedSelectionL( item->iData.iCommandId );
}
else
{
TInt commandId = 0;
if ( iExtension->iSctHighlighted )
{
commandId = EAknCmdEditMenuSctSelected;
}
else if (item && !item->iData.iCascadeId)
{
commandId = item->iData.iCommandId;
}
if ( commandId == EAknCmdTaskSwapper )
{
if ( !iExtension->iTaskSwapIdle->IsActive() )
{
iExtension->iTaskSwapIdle->Start( TCallBack( TaskSwapCallBack ) );
}
}
if ( !commandId ) return; // Nothing to process
if ( iEditMenuObserver )
iEditMenuObserver->ProcessCommandL( commandId );
// have to save pointer now because in case if we are in a submenu
// 'this' might be destroyed by calling iMenuObserver->ProcessCommandL(
// commandId ), so need to avoid crash
CEikMenuPane* menu = iOwner ? iOwner : this;
MCoeControlObserver* observer = menu->Observer();
if ( commandId >= EAknCmdMarkingModeEnter
&& commandId <= EAknCmdMarkingModeUnmarkAll )
{
CEikMenuBar* menuBar = static_cast<CEikMenuBar*>( Parent() );
if ( menuBar && menuBar->MenuPane() == this )
{
static_cast<MEikCommandObserver*>(
menuBar)->ProcessCommandL( commandId );
}
ReportCanceled();
}
else if ( commandId != EAknCmdTaskSwapper )
{
_AKNTRACE( "commandId = %d", commandId );
TBool isDeleted = EFalse;
iIsDeleted = &isDeleted;
CleanupStack::PushL( TCleanupItem( CleanLocalRef, this ) );
iMenuObserver->ProcessCommandL( commandId );
CleanupStack::Pop();
if ( !isDeleted )
{
CEikMenuBar* menuBar = static_cast<CEikMenuBar*>( Parent() );
if ( menuBar && menuBar->MenuPane() == this )
{
static_cast<MEikCommandObserver*>(
menuBar)->ProcessCommandL( commandId );
}
}
iIsDeleted = NULL;
}
else
{
ReportCanceled();
return;
}
// very important for the context sensitive menu because it will
// be closed only after this call.
if ( this && observer )
{
observer->HandleControlEventL( menu,
MCoeControlObserver::EEventRequestExit );
}
MEikMenuObserver* fepMenuObserver = CAknEnv::Static()->FepMenuObserver();
if ( fepMenuObserver )
{
fepMenuObserver->ProcessCommandL( commandId );
}
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::FocusChanged
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::FocusChanged( TDrawNow aDrawNow )
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "aDrawNow = %d", aDrawNow );
if ( !iItemArray || iItemArray->Count() == 0 )
{
return;
}
if ( aDrawNow && iExtension->HighlightEnabled() )
{
// if focused or if current item is a cascade draw highlight (only draw if item is selected)
if ( iSelectedItem != ENothingSelected )
{
const CEikMenuPaneItem* item = (*iItemArray)[iSelectedItem];
THighlightType highlight = ERemoveHighlight;
if ( !iExtension->iSctHighlighted &&
( item->iData.iCascadeId || IsFocused() ) )
{
PrepareHighlightFrame();
highlight = EDrawHighlight;
}
DrawItem( iSelectedItem, highlight);
}
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::IsHotKeyL
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::IsHotKeyL( const TInt modifiers, const TInt code )
{
if ( iHotKeyTable )
{
const TInt command = iHotKeyTable->CommandIdFromHotKey( code,modifiers );
if ( command )
{
if ( iMenuObserver->CheckHotKeyNotDimmedL( command) )
{
// have to save pointer now because in case if we are in a submenu
// 'this' might be destroyed by calling iMenuObserver->ProcessCommandL(
// commandId ), so need to avoid crash
CEikMenuPane* menu = iOwner ? iOwner : this;
MCoeControlObserver* observer = menu->Observer();
iMenuObserver->ProcessCommandL( command );
// very important for the context sensitive menu because it will
// be closed only after this call.
if ( this && observer )
{
observer->HandleControlEventL( menu,
MCoeControlObserver::EEventRequestExit );
}
}
else
{
iMenuObserver->HandleAttemptDimmedSelectionL( command );
}
return ETrue;
}
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::OfferKeyEventL
// -----------------------------------------------------------------------------
//
EXPORT_C TKeyResponse CEikMenuPane::OfferKeyEventL( const TKeyEvent& aKeyEvent, TEventCode aType )
{ // if were on the control stack then consume all keys
return OfferKeyEventL( aKeyEvent, aType, ETrue );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::OfferKeyEventL
// -----------------------------------------------------------------------------
//
EXPORT_C TKeyResponse CEikMenuPane::OfferKeyEventL( const TKeyEvent& aKeyEvent, TEventCode aType, TBool aConsumeAllKeys )
{
_AKNTRACE_FUNC_ENTER;
// Key event handling for scroll physics
// Don't react to shift keys
if ( aKeyEvent.iScanCode == EStdKeyLeftShift ||
aKeyEvent.iScanCode == EStdKeyRightShift )
{
if ( aConsumeAllKeys )
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 1" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
}
else
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 2" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasNotConsumed;
}
}
// Disable key events when panning
if ( iExtension->iPanningActive ||
iExtension->iPhysics->OngoingPhysicsAction()
== CAknPhysics::EAknPhysicsActionBouncing )
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 3" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
}
if ( iExtension->iFlickActive )
{
// Stop physics engine when key down event occurs.
iExtension->iPhysics->StopPhysics();
iExtension->iPhysics->ResetFriction();
iExtension->iFlickActive = EFalse;
iExtension->iKeyEventActive = ETrue;
_AKNTRACE( "[%s]", "OfferKeyEventL return 4" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
}
else if ( iExtension->iKeyEventActive && aType != EEventKeyDown )
{
// Consume following events until next key down.
_AKNTRACE( "[%s]", "OfferKeyEventL return 5" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
}
else
{
// Next key down after stopping flick, it is ok to continue.
iExtension->iKeyEventActive = EFalse;
}
// Restore possible panning offset
if (iExtension->Offset() != 0 )
{
iExtension->RestoreOffset( aKeyEvent.iCode );
}
CheckCreateScrollerL();
const TInt modifiers = ( aKeyEvent.iModifiers )&( EModifierCtrl|EModifierShift|EModifierPureKeycode );
const TInt code = aKeyEvent.iCode;
TKeyResponse keyResponse = EKeyWasNotConsumed;
if ( iCascadeMenuPane )
{
keyResponse = iCascadeMenuPane->OfferKeyEventL( aKeyEvent, aType, EFalse );
if ( keyResponse == EKeyWasNotConsumed &&
( code==EKeyEscape || (!AknLayoutUtils::LayoutMirrored() && code==EKeyLeftArrow) || ( AknLayoutUtils::LayoutMirrored() && code==EKeyRightArrow) ) )
{
// show transition only when "canceling" the cascade menu
// choosing an item from cascade does not execute effect
iExtension->iShowCascadeTransition = ETrue;
CloseCascadeMenu();
//Fixed for TSW errors DLAN-7SFH86.
IgnoreEventsUntilNextPointerUp();
keyResponse = EKeyWasConsumed;
}
_AKNTRACE( "[%s]", "OfferKeyEventL return 6" );
_AKNTRACE_FUNC_EXIT;
return keyResponse;
}
// with single click first key event enables highlight
if ( !iExtension->HighlightEnabled() )
{
if ( code == EKeyUpArrow || code == EKeyDownArrow ||
code == EKeyEnter || code == EKeyOK )
{
iExtension->SetDefaultHighlight();
return EKeyWasConsumed;
}
}
// if popup menu displaying, needs to check for hotkeys itself.
if ( IsHotKeyL( modifiers, code ) )
return EKeyWasConsumed;
TInt count = 0;
if( iItemArray )
count = iItemArray->Count();
if ( count == 0 )
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 8" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasNotConsumed;
}
const TInt max = count-1;
TInt newHighlight = iSelectedItem;
TBool loopScrolling = ETrue;
TInt itemAfterLastItem = loopScrolling ? 0 : max;
TInt itemAfterFirstItem = loopScrolling ? max : 0;
// Scroll highlighted item so that it becomes visible,
// if it is not visible before (scrolling with scroll bar
// can cause highlighted item to go out of screen)
TInt topItem = iScroller->TopItemIndex();
TInt bottomItem = topItem + NumberOfItemsThatFitInView();
if ( iExtension->Offset() < 0 )
{
// Extra bottom item when panning
bottomItem++;
}
if( bottomItem > NumberOfItemsInPane() )
{
bottomItem = NumberOfItemsInPane();
}
_AKNTRACE( "topItem = %d,bottomItem = %d", topItem,bottomItem );
if ( aType != EEventKeyDown && iSelectedItem != ENothingSelected &&
!(iExtension->iSctHighlighted && topItem == 0) &&
(iSelectedItem < topItem || iSelectedItem > bottomItem - 1) )
{
_AKNTRACE( "[%s]", "ScrollToMakeItemVisible(iSelectedItem);" );
ScrollToMakeItemVisible(iSelectedItem);
ActivateGc();
CWindowGc& gc = SystemGc();
PrepareGcForDrawingItems( gc );
// draw all items that are needed.
for( TInt i = 0; i < count; i++ )
{
if( i == iSelectedItem && !iExtension->iSctHighlighted)
{
DrawItem( gc, i, EDrawHighlight );
}
else
{
DrawItem( gc, i, ERemoveHighlight );
}
}
DeactivateGc();
_AKNTRACE( "[%s]", "OfferKeyEventL return 9" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
}
if ( iSelectedItem != ENothingSelected || iExtension->iSctHighlighted )
{
switch ( code )
{
case EKeySpace:
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeySpace)" );
iEikonEnv->InfoMsg( R_EIK_TBUF_PRESS_SPACE_MENP );
_AKNTRACE( "[%s]", "OfferKeyEventL return 10" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
// AKNLAF start
// loop scrolling always used in options menus
case EKeyDownArrow:
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyDownArrow)" );
if ( iExtension->iSctHighlighted && iExtension->iSct )
{
iExtension->iSctHighlighted = EFalse;
MoveHighlightTo( ++newHighlight );
iExtension->iSct->HighlightSctRow( iExtension->iSctHighlighted );
}
else
{
if ( iSelectedItem == max && iExtension->iSct)
{
// If SCT exists, it gets the highlight
// if moving from the bottom item
iExtension->iSctHighlighted = ETrue;
MoveHighlightTo( ENothingSelected );
iExtension->iSct->HighlightSctRow( iExtension->iSctHighlighted );
}
else
{
MoveHighlightTo( ++newHighlight>max? itemAfterLastItem: newHighlight );
}
}
keyResponse = EKeyWasConsumed;
break;
case EKeyUpArrow:
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyUpArrow)" );
if ( iExtension->iSct &&
iSelectedItem == 0 && !iExtension->iSctHighlighted )
{
iExtension->iSctHighlighted = ETrue;
MoveHighlightTo( ENothingSelected );
iExtension->iSct->HighlightSctRow( iExtension->iSctHighlighted );
}
else if ( iExtension->iSctHighlighted && iExtension->iSct )
{
iExtension->iSctHighlighted = EFalse;
MoveHighlightTo( itemAfterFirstItem );
iExtension->iSct->HighlightSctRow( iExtension->iSctHighlighted );
}
else
{
MoveHighlightTo( --newHighlight<0?
itemAfterFirstItem: newHighlight );
}
keyResponse = EKeyWasConsumed;
break;
// AKNLAF end
case EKeyRightArrow :
case EKeyLeftArrow :
{
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyRightArrow or EKeyLeftArrow)" );
if( count == 0 ) // Implies empty or undefined item array
{
if ( aConsumeAllKeys )
return EKeyWasConsumed;
return EKeyWasNotConsumed;
}
if ( iExtension->iSctHighlighted && iExtension->iSct )
{
return iExtension->iSct->OfferKeyEventL( aKeyEvent, aType );
}
const CEikMenuPaneItem* item = (*iItemArray)[iSelectedItem];
if ( item->iData.iCascadeId && iExtension->HighlightEnabled() )
{
if ( ( !AknLayoutUtils::LayoutMirrored() && code == EKeyRightArrow ) ||
( AknLayoutUtils::LayoutMirrored() && code == EKeyLeftArrow ) )
{
TryLaunchCascadeMenuL( *item );
if ( iCascadeMenuPane )
{
iCascadeMenuPane->iExtension->SetDefaultHighlight();
}
keyResponse = EKeyWasConsumed;
break;
} // else fall through
} // else fall through
}
case EKeyHome:
case EKeyEnd:
{
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyHome or EKeyEnd)" );
// only popup menu panes should consume these keys. ???
if ( aConsumeAllKeys )
return EKeyWasConsumed;
return EKeyWasNotConsumed;
}
case EKeyEnter:
case EKeyOK:
case EAknSoftkeySelect:
case EAknSoftkeyOk:
{
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyEnter,EKeyOK,EAknSoftkeySelect,EAknSoftkeyOk)" );
if ( iExtension->iSctHighlighted && iExtension->iSct )
{
keyResponse = iExtension->iSct->OfferKeyEventL( aKeyEvent, aType );
if ( keyResponse == EKeyWasConsumed )
{
ReportSelectionMadeL();
break;
}
}
if ( modifiers&( EModifierShift|EModifierCtrl|EModifierFunc ) )
return EKeyWasConsumed;
if ( aKeyEvent.iRepeats )
return EKeyWasConsumed;
if ( count == 0 ) // Do the same as modifiers (implies empty or undefined item array)
return EKeyWasConsumed;
CEikMenuPaneItem* item = (*iItemArray)[iSelectedItem];
if ( item->iData.iCascadeId )
{
TryLaunchCascadeMenuL( *item );
if ( iCascadeMenuPane )
{
iCascadeMenuPane->iExtension->SetDefaultHighlight();
}
}
else
ReportSelectionMadeL();
return EKeyWasConsumed;
}
case '4':// These are for menu sct.
case '5':
case '6':
{
_AKNTRACE( "[%s]", "OfferKeyEventL('4','5','6')" );
if ( iExtension->iSctHighlighted && iExtension->iSct )
{
return iExtension->iSct->OfferKeyEventL( aKeyEvent, aType );
}
else
{
return EKeyWasNotConsumed;
}
}
default:
break;
}
}
switch ( code )
{
case EKeyMenu:
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyMenu)" );
iMenuObserver->HandleSideBarMenuL( 0, TPoint( 0, 0 ), modifiers, iHotKeyTable );
return EKeyWasConsumed;
case EKeyEscape:
_AKNTRACE( "[%s]", "OfferKeyEventL(EKeyEscape)" );
if ( iOwner )
return EKeyWasNotConsumed; // owner will destroy the cascade
ReportCanceled();
return EKeyWasConsumed;
default:
break;
}
if ( MoveToItemL( code, modifiers) )
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 11" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed; // must return here because in the case of a cascade it will have been deleted by now.
}
if ( aConsumeAllKeys )
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 12" );
_AKNTRACE_FUNC_EXIT;
return EKeyWasConsumed;
}
else
{
_AKNTRACE( "[%s]", "OfferKeyEventL return 13" );
_AKNTRACE_FUNC_EXIT;
return keyResponse;
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::NavigateToNextItem
// New for AVKON
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::NavigateToNextItem()
{
if ( iCascadeMenuPane )
iCascadeMenuPane->NavigateToNextItem();
else
{
const TInt max = NumberOfItemsInPane() - 1;
TInt newHighlight = SelectedItem();
MoveHighlightTo( ( ++newHighlight > max ) ? 0 : newHighlight);
}
}
// ---------------------------------------------------------------------------
// Activates the currently highlighted item.
// ---------------------------------------------------------------------------
//
void CEikMenuPane::ActivateCurrentItemL()
{
if ( !iExtension->HighlightEnabled() )
{
iExtension->SetDefaultHighlight();
return;
}
_AKNTRACE_FUNC_ENTER;
if ( iExtension->iPanningActive ||
iExtension->iPhysics->OngoingPhysicsAction()
== CAknPhysics::EAknPhysicsActionBouncing )
{
// Don't allow the item activation in kinetic scrolling enabled
// menus if menu is being dragged or bounce effect is in action.
// In this case the event is discarded.
_AKNTRACE( "[%s]" "ActivateCurrentItemL return 1" );
_AKNTRACE_FUNC_EXIT;
return;
}
TInt count( NumberOfItemsInPane() );
// Scroll highlighted item so that it becomes visible
// if it is not visible before (scrolling with scroll bar
// can cause highlighted item to go out of screen).
TInt topItem( iScroller->TopItemIndex() );
TInt bottomItem( topItem + NumberOfItemsThatFitInView() );
if ( bottomItem > count )
{
bottomItem = count;
}
if ( iExtension->Offset() < 0 &&
( iSelectedItem == topItem || iSelectedItem == bottomItem ) )
{
// Restoring offset with "simulated" ok key event.
iExtension->RestoreOffset( EKeyOK );
}
else if ( iSelectedItem < topItem ||
iSelectedItem > bottomItem - 1 )
{
if ( count > iSelectedItem )
{
if ( iExtension->iSctHighlighted && iExtension->iSct )
{
TKeyEvent key;
key.iCode = EKeyOK;
key.iModifiers = 0;
TKeyResponse keyResponse( EKeyWasNotConsumed );
TEventCode type( EEventNull );
keyResponse = iExtension->iSct->OfferKeyEventL( key,
type );
if ( keyResponse == EKeyWasConsumed )
{
ReportSelectionMadeL();
}
_AKNTRACE( "[%s]" "ActivateCurrentItemL return 2" );
_AKNTRACE_FUNC_EXIT;
return;
}
}
iExtension->isUpdateScrollDirectly = ETrue;
ScrollToMakeItemVisible( iSelectedItem );
iExtension->isUpdateScrollDirectly = EFalse;
ActivateGc();
CWindowGc& gc = SystemGc();
PrepareGcForDrawingItems( gc );
// Draw all items that are needed.
for ( TInt i = 0; i < count; i++ )
{
if ( i == iSelectedItem && !iExtension->iSctHighlighted )
{
DrawItem( gc, i, EDrawHighlight );
}
else
{
DrawItem( gc, i, ERemoveHighlight );
}
}
DeactivateGc();
_AKNTRACE( "[%s]" "ActivateCurrentItemL return 3" );
_AKNTRACE_FUNC_EXIT;
return;
}
if ( iCascadeMenuPane )
{
iCascadeMenuPane->ActivateCurrentItemL();
}
else
{
if ( count > iSelectedItem )
{
if ( iExtension->iSctHighlighted && iExtension->iSct )
{
TKeyEvent key;
key.iCode = EKeyOK;
key.iModifiers = 0;
TKeyResponse keyResponse( EKeyWasNotConsumed );
TEventCode type( EEventNull );
keyResponse = iExtension->iSct->OfferKeyEventL(
key, type );
if ( keyResponse == EKeyWasConsumed )
{
ReportSelectionMadeL();
}
}
else
{
CEikMenuPaneItem* item = (*iItemArray)[iSelectedItem];
if ( item->iData.iCascadeId )
{
TryLaunchCascadeMenuL(*item);
}
else
{
ReportSelectionMadeL();
}
}
}
}
_AKNTRACE( "[%s]" "ActivateCurrentItemL return 4" );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CancelActiveMenuPane
// New for AVKON
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::CancelActiveMenuPane()
{
// If it is possible to close a cascade, return ETrue
if ( iCascadeMenuPane )
{
iCascadeMenuPane->CancelActiveMenuPane();
CloseCascadeMenu( ETrue );
return ETrue;
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MoveToItemL
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::MoveToItemL(TInt /*aCode*/, TInt /*aMods*/)
{
return EFalse;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ReportCanceled
// -----------------------------------------------------------------------------
//
void CEikMenuPane::ReportCanceled()
{
// let menubar handle the cancel case so transition can be shown
// use "fake" pointer event
CEikMenuBar* menubar = static_cast<CEikMenuBar*>( Parent() );
if( menubar->MenuPane() == this )
{
TPointerEvent ptrEvent;
ptrEvent.iType = TPointerEvent::EButton1Up;
TRAP_IGNORE( menubar->HandlePointerEventL( ptrEvent ) );
}
else
{
MCoeControlObserver* observer = iOwner ? iOwner->Observer() : Observer();
if ( observer )
{
// context sensitive menu
TRAP_IGNORE( observer->HandleControlEventL( iOwner ? iOwner : this,
MCoeControlObserver::EEventRequestCancel ) );
}
else
{
// application menu
TRAP_IGNORE( iMenuObserver->ProcessCommandL( EEikCmdCanceled ) );
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ExtensionInterface
// -----------------------------------------------------------------------------
//
EXPORT_C void* CEikMenuPane::ExtensionInterface( TUid /*aInterface*/ )
{
return NULL;
}
// ----------------------------------------------------------------------------
// CEikMenuPane::HandlePointerEventL
//
// Handles pointer events.
// ----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::HandlePointerEventL( const TPointerEvent& aPointerEvent )
{
_AKNTRACE_FUNC_ENTER;
if ( iOwner && !IsVisible() )
{
_AKNTRACE( "[%s]", "HandlePointerEventL return 1" );
_AKNTRACE_FUNC_EXIT;
return;
}
TBool noSelection = EFalse;
// get pointer grabber1
CCoeControl* grabberBefore = GrabbingComponent();
TPointerEvent pointerEvent = aPointerEvent;
iExtension->ChangePosition( pointerEvent );
iExtension->iLastPointerEvent = pointerEvent;
// Send pointerevent to childs - not to scroll bar if a sub menu is open
TRect sbRect;
if ( iSBFrame->VerticalScrollBar() &&
iSBFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn )
{
sbRect = iSBFrame->VerticalScrollBar()->Rect();
}
if ( ! ( iCascadeMenuPane && sbRect.Contains(
pointerEvent.iPosition ) ) )
{
_AKNTRACE( "[%s]", "CAknControl::HandlePointerEventL( pointerEvent );" );
CAknControl::HandlePointerEventL( pointerEvent );
}
else
{
if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
{
if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) )
{
iExtension->ImmediateFeedback( ETouchFeedbackSubMenuClosed );
}
else
{
iExtension->ImmediateFeedback( ETouchFeedbackPopUp );
}
iExtension->iShowCascadeTransition = ETrue;
CloseCascadeMenu();
// Submenu of submenu was closed
if ( iCascadeMenuPane )
{
iCascadeMenuPane->iExtension->EnableHighlight( EFalse );
iCascadeMenuPane->RepaintHighlight();
iExtension->iDownOnMenuArea = EFalse;
}
else
{
iExtension->EnableHighlight( EFalse );
RepaintHighlight();
}
IgnoreEventsUntilNextPointerUp();
_AKNTRACE( "[%s]", "HandlePointerEventL return 2" );
_AKNTRACE_FUNC_EXIT;
return;
}
}
// get pointer grabber
CCoeControl* grabberAfter = GrabbingComponent();
// if grabberBefore or grabberAfter, then some child is handling pointerevent.
if ( (grabberBefore || grabberAfter )
&& ( !iExtension->iSct || iExtension->iScrollBarRect.Contains( pointerEvent.iPosition ) ) )
{
_AKNTRACE( "[%s]", "HandlePointerEventL return 3" );
_AKNTRACE_FUNC_EXIT;
return;
}
// Forward pointer events to embedded CBA if sub menu open
if ( iExtension->iCba && iCascadeMenuPane )
{
TBool sendToCBA = EFalse;
// if embedded CBA is grabbing the pointer we send the events to it
if( iExtension->iDownOnCbaArea )
{
if( aPointerEvent.iType == TPointerEvent::EButton1Up )
{
iExtension->iDownOnCbaArea = EFalse;
}
sendToCBA = ETrue;
}
else
{
TPoint pos (
aPointerEvent.iPosition + PositionRelativeToScreen() );
TRect cbaRect ( iExtension->iCba->PositionRelativeToScreen(),
iExtension->iCba->Size() );
if ( cbaRect.Contains( pos ) &&
aPointerEvent.iType == TPointerEvent::EButton1Down )
{
sendToCBA = ETrue;
iExtension->iDownOnCbaArea = ETrue;
}
}
iCascadeMenuPane->iExtension->iDownOnCbaArea
= iExtension->iDownOnCbaArea;
if ( sendToCBA )
{
// scale the pointer event coordinates relative to CBA
TPointerEvent event = aPointerEvent;
TPoint position( aPointerEvent.iPosition +
PositionRelativeToScreen() );
event.iPosition = (position -
iExtension->iCba->PositionRelativeToScreen());
// send the event to CBA
iExtension->iCba->HandlePointerEventL(event);
_AKNTRACE( "[%s]", "HandlePointerEventL return 4" );
_AKNTRACE_FUNC_EXIT;
return;
}
}
// Submenu of a submenu to forward events to cba
else if ( iCascadeMenuPane )
{
iCascadeMenuPane->iExtension->iDownOnCbaArea
= iExtension->iDownOnCbaArea;
}
// In sub menu and pointer down has come to cba area
if ( iOwner && iOwner->iExtension->iDownOnCbaArea )
{
TPointerEvent parentEvent;
iExtension->CalculateParentEvent(aPointerEvent, parentEvent);
_AKNTRACE( "[%s]", "HandlePointerEventL return 5" );
_AKNTRACE_FUNC_EXIT;
return iOwner->HandlePointerEventL( parentEvent );
}
// Rect whic contains only area of menu items.
const TRect innerRect = iBorder.InnerRect( Rect() );
TRect menuSctRect;
// Get the option item's rect in Menu SCT
if ( iExtension->iSct )
{
menuSctRect = iExtension->iItemAreaRect;
}
TRect cascadeMenuRect(0,0,0,0);
// Y coordinate for pointer event
const TInt yPos = aPointerEvent.iPosition.iY;
// Get top and botton item indexes.
TInt topItem = iScroller->TopItemIndex();
TInt bottomItem = topItem + NumberOfItemsThatFitInView();
if( iExtension->Offset() < 0 )
{
// Panning has happened so we have one extra item.
++bottomItem;
}
if( bottomItem > NumberOfItemsInPane() )
{
bottomItem = NumberOfItemsInPane();
}
// if submenu, then move it's rect coordinates to relative to parent.
if ( iCascadeMenuPane )
{
TPoint subPos = iCascadeMenuPane->Position();
cascadeMenuRect = TRect(subPos-Position(), iCascadeMenuPane->Size());
}
// Pointerevent in case we need to pass event from submenu to parent
TPointerEvent parentEvent;
// Stop timers if dragged outside
if ( iExtension && iExtension->iDraggedOutside )
{
iExtension->StopCascadeMenuTimer();
iExtension->ResetPressedHighlight();
}
switch (aPointerEvent.iType )
{
case TPointerEvent::EButton1Up:
{
_AKNTRACE( "[%s]", "TPointerEvent::EButton1Up" );
if ( !innerRect.Contains( aPointerEvent.iPosition ) )
{
TBool highlightWasEnabled = iExtension->HighlightEnabled();
// remove highlight in case highlight is outside of menu pane
iExtension->EnableHighlight( EFalse );
if ( iOwner )
{
RepaintHighlight();
}
else if ( highlightWasEnabled && !iCascadeMenuPane )
{
DrawItem( SelectedItem(), ENoHighlight );
}
}
if ( iOwner &&
!innerRect.Contains( aPointerEvent.iPosition ) &&
!iExtension->iDownOnMenuArea )
{
iExtension->CalculateParentEvent( aPointerEvent, parentEvent);
_AKNTRACE( "[%s]", "HandlePointerEventL return 6" );
_AKNTRACE_FUNC_EXIT;
return iOwner->HandlePointerEventL( parentEvent );
}
iExtension->iPanningActive = EFalse;
if ( !(iExtension->iSct && iExtension->iSct->Rect().Contains( iExtension->iStartPoint ) )
&& iExtension->iDownOnMenuArea )
{
TPoint drag = iExtension->iStartPoint - aPointerEvent.iPosition;
if ( iExtension->iPhysics->StartPhysics(
drag, iExtension->iStartTime ) )
{
iExtension->iFlickActive = ETrue;
iExtension->ResetPressedHighlight();
}
}
iExtension->iDownOnMenuArea = EFalse;
if ( iExtension->HighlightTimerActive() &&
!iExtension->iPressedDown )
{
// Complete the timer here if it's still running
// when up event is received.
iExtension->ResetPressedHighlight();
CEikMenuPaneExtension::HighlightTimerCallBack( iExtension );
}
// in submenu and pointer lifted outside of x -limits : handle in parent
if ( iOwner && iOwner->IsFocused() && (aPointerEvent.iPosition.iX < innerRect.iTl.iX ||
aPointerEvent.iPosition.iX > innerRect.iBr.iX ))
{
iExtension->CalculateParentEvent( aPointerEvent, parentEvent);
_AKNTRACE( "[%s]", "HandlePointerEventL return 7" );
_AKNTRACE_FUNC_EXIT;
return iOwner->HandlePointerEventL( parentEvent );
}
// if button up inside menu and over selected item, then do selection.
if (Extension()->iItemsReadyForPenSelection &&
innerRect.Contains( aPointerEvent.iPosition ) )
{
if(iExtension->iSct && iExtension->iSct->Rect().Contains(aPointerEvent.iPosition) && iExtension->iSpecialCharPointed)
{
TKeyEvent key;
key.iCode=EKeyOK;
key.iModifiers=0;
iExtension->iSct->OfferKeyEventL(key, EEventKey);
iExtension->iSpecialCharPointed = EFalse;
Extension()->iItemsReadyForPenSelection = EFalse;
ReportSelectionMadeL();
_AKNTRACE( "[%s]", "HandlePointerEventL return 8" );
_AKNTRACE_FUNC_EXIT;
return;
}
else if(iSelectedItem != ENothingSelected ) // beware out of indexing
{
if ( iItemArray->Count() == 0 )
{
_AKNTRACE( "[%s]", "HandlePointerEventL return 9" );
_AKNTRACE_FUNC_EXIT;
return;
}
TInt threshold = 0;
threshold = iExtension->iPhysics->DragThreshold();
CEikMenuPaneItem* item = (*iItemArray)[iSelectedItem];
if((yPos < item->iPos + iItemHeight + threshold ) &&
( yPos > item->iPos - threshold ) )
{
// if new item has submenu, show it
if ( item->iData.iCascadeId
&& iSelectedItem == iExtension->iButtonDownItem )
{
// close previous submenu if open
if ( iCascadeMenuPane )
{
CloseCascadeMenu();
}
iExtension->StopCascadeMenuTimer();
iExtension->ResetPressedHighlight();
// Up happened on partial item, it must be moved to be
// fully visible before opening (possible) cascade menu.
if( iSelectedItem == topItem ||
iSelectedItem == bottomItem - 1)
{
// Restoring physics offset with "simulated" ok key event
iExtension->RestoreOffset( EKeyOK );
}
MoveHighlightTo(iSelectedItem);
TryLaunchCascadeMenuL( *item );
}
else if ( iExtension->iButtonDownItem == iSelectedItem )
{
iExtension->ImmediateFeedback( ETouchFeedbackList,
ETouchFeedbackVibra );
if( !IsCascadeMenuPane() )
{
// EFalse = don't stop transition if opening the cascade menu
// just report selection
if ( ( !iExtension->iSct || ( iExtension->iSct && menuSctRect.Contains( aPointerEvent.iPosition ) ) )
&& !iCascadeMenuPane && iExtension->iPressedDown )
{
Extension()->iItemsReadyForPenSelection = EFalse;
iExtension->ResetPressedHighlight();
ReportSelectionMadeL( EFalse );
_AKNTRACE( "[%s]", "HandlePointerEventL return 10" );
_AKNTRACE_FUNC_EXIT;
return;
}
}
else
{
if ( !iExtension->iSct || ( iExtension->iSct && menuSctRect.Contains(aPointerEvent.iPosition) )
&& iExtension->iPressedDown )
{
Extension()->iItemsReadyForPenSelection = EFalse;
iExtension->ResetPressedHighlight();
ReportSelectionMadeL();
_AKNTRACE( "[%s]", "HandlePointerEventL return 11" );
_AKNTRACE_FUNC_EXIT;
return;
}
}
}
}
}
}
iExtension->ResetPressedHighlight();
iExtension->iButtonDownItem = KErrNotFound;
if ( iExtension->iNextHighlightItem != KErrNotFound )
{
MoveHighlightTo( iExtension->iNextHighlightItem );
iExtension->iNextHighlightItem = KErrNotFound;
}
}
break;
case TPointerEvent::EButton1Down:
{
_AKNTRACE( "[%s]", "TPointerEvent::EButton1Down" );
iExtension->iNextHighlightItem = KErrNotFound;
// Start drag
if( innerRect.Contains( aPointerEvent.iPosition ) )
{
if ( iExtension->iFlickActive )
{
noSelection = ETrue;
//when touch down during the flicking, play a basic list feedback
iExtension->ImmediateFeedback( ETouchFeedbackList );
}
// stop physics for drag
iExtension->iPhysics->StopPhysics();
iExtension->iPhysics->ResetFriction();
iExtension->iStartPoint = aPointerEvent.iPosition;
iExtension->iPrevPoint = iExtension->iStartPoint;
iExtension->iStartTime.HomeTime();
}
if ( !noSelection )
{
Extension()->iItemsReadyForPenSelection = ETrue;
}
if ( innerRect.Contains( aPointerEvent.iPosition ) )
{
iExtension->iDownOnMenuArea = ETrue;
if ( !noSelection )
{
iExtension->EnableHighlight( ETrue, ETrue );
}
if ( iCascadeMenuPane )
{
// if submenu, and clicked outside of it
if ( !cascadeMenuRect.Contains( aPointerEvent.iPosition ) )
{
if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) )
{
iExtension->ImmediateFeedback( ETouchFeedbackSubMenuClosed );
}
else
{
iExtension->ImmediateFeedback( ETouchFeedbackPopUp );
}
//Just close sub menu
iExtension->iShowCascadeTransition = ETrue;
CloseCascadeMenu();
// Submenu of submenu was closed
if ( iCascadeMenuPane )
{
iCascadeMenuPane->iExtension->EnableHighlight( EFalse );
iCascadeMenuPane->RepaintHighlight();
iExtension->iDownOnMenuArea = EFalse;
}
else
{
iExtension->EnableHighlight( EFalse );
RepaintHighlight();
}
IgnoreEventsUntilNextPointerUp();
break;
}
}
else
{
// menu sct
if(iExtension->iSct&& !iExtension->iSctHighlighted && iExtension->iSct->Rect().Contains(aPointerEvent.iPosition))
{
iExtension->iSctHighlighted = ETrue;
iExtension->iSct->HighlightSctRow( iExtension->iSctHighlighted );
MoveHighlightTo( ENothingSelected ); // from other highlight to sct
}
// Act in the rect of option items
else if (!iExtension->iSct || (iExtension->iSct && menuSctRect.Contains(aPointerEvent.iPosition)))
{
// Scroll only through visible items
for ( TInt ii = topItem; ii < bottomItem; ++ii )
{
CEikMenuPaneItem* item = (*iItemArray)[ii];
// if this item is clicked
if ((yPos < item->iPos + iItemHeight) &&
(yPos > item->iPos))
{
if(iExtension->iSctHighlighted && iExtension->iSct && menuSctRect.Contains(aPointerEvent.iPosition))
{
// from sct to normal menu item
iExtension->iSctHighlighted = EFalse;
iExtension->iSct->HighlightSctRow( iExtension->iSctHighlighted );
}
iExtension->iPressedDown = ETrue;
// Start timer for pressed highlight
if ( !noSelection )
{
iExtension->ImmediateFeedback( ETouchFeedbackList );
iExtension->StartHighlightTimerL();
}
iExtension->iNextHighlightItem = ii;
iExtension->iButtonDownItem = ii;
// down even on already highlighted item => list feedback
if ( iExtension->iButtonDownItem == iSelectedItem )
{
iExtension->ImmediateFeedback( ETouchFeedbackList );
}
if ( noSelection )
{
iExtension->iButtonDownItem = KErrNotFound;
}
// if new item has submenu, show it
if ( item->iData.iCascadeId )
{
if ( !iExtension->IsCascadeMenuTimerActive() )
{
iExtension->StartCascadeMenuTimerL();
}
}
// item found, then break looping
break;
}
}
}
}
}
else
{
// Clicked out side submenu, parent handles this
iExtension->iDownOnMenuArea = EFalse;
if ( iOwner )
{
iExtension->CalculateParentEvent(aPointerEvent, parentEvent);
_AKNTRACE( "[%s]", "HandlePointerEventL return 12" );
_AKNTRACE_FUNC_EXIT;
return iOwner->HandlePointerEventL( parentEvent );
}
else
{
// For finger usability, extend to the right.
TRect innerToRightRect;
if ( AknLayoutUtils::LayoutMirrored() )
{
innerToRightRect = TRect( Rect().iTl, innerRect.iBr );
}
else
{
innerToRightRect = TRect( innerRect.iTl, Rect().iBr );
}
// Keep opened
if ( innerToRightRect.Contains( aPointerEvent.iPosition ) )
{
break;
}
// clicked outside, then close menu case by case
if ( iCascadeMenuPane )
{
if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) )
{
iExtension->ImmediateFeedback( ETouchFeedbackSubMenuClosed );
}
else
{
iExtension->ImmediateFeedback( ETouchFeedbackPopUp );
}
iExtension->iShowCascadeTransition = ETrue;
CloseCascadeMenu(); //Just close sub menu.
// Submenu of submenu was closed
if ( iCascadeMenuPane )
{
iCascadeMenuPane->iExtension->EnableHighlight( EFalse );
iCascadeMenuPane->RepaintHighlight();
}
else
{
iExtension->EnableHighlight( EFalse );
RepaintHighlight();
}
IgnoreEventsUntilNextPointerUp();
}
else
{
_AKNTRACE( "[%s]", "HandlePointerEventL return 12.5" );
_AKNTRACE_FUNC_EXIT;
return;
}
}
}
}
break;
case TPointerEvent::EButtonRepeat:
case TPointerEvent::EDrag:
{
_AKNTRACE( "[%s]", "TPointerEvent::EDrag" );
// In submenu and drag outside and down didn't come to menu
if ( iOwner &&
!iExtension->iDownOnMenuArea &&
!innerRect.Contains( aPointerEvent.iPosition ) )
{
iExtension->CalculateParentEvent( aPointerEvent, parentEvent);
_AKNTRACE( "[%s]", "HandlePointerEventL return 13" );
_AKNTRACE_FUNC_EXIT;
return iOwner->HandlePointerEventL( parentEvent );
}
if ( ( iExtension->iSct )
&& ( iExtension->iSct->Rect().Contains( iExtension->iStartPoint ) ) )
{
break;
}
TPoint drag = iExtension->iStartPoint -
aPointerEvent.iPosition;
TInt threshold = drag.iY;
if( Abs( threshold ) > iExtension->iPhysics->DragThreshold()
&& iExtension->iDownOnMenuArea )
{
iExtension->EnableHighlight( EFalse );
iExtension->iButtonDownItem = KErrNotFound;
iExtension->ResetPressedHighlight();
iExtension->iNextHighlightItem = KErrNotFound;
iExtension->iPanningActive = ETrue;
}
if ( iExtension->iPanningActive && iExtension->iDownOnMenuArea )
{
TPoint delta(
0, iExtension->iPrevPoint.iY - aPointerEvent.iPosition.iY );
iExtension->iPhysics->RegisterPanningPosition( delta );
}
iExtension->iPrevPoint = aPointerEvent.iPosition;
// in submenu and pointer dragged outside of x -limits : handle in parent
if ( iOwner && ((aPointerEvent.iPosition.iX < innerRect.iTl.iX ) ||
( aPointerEvent.iPosition.iX > innerRect.iBr.iX )))
{
iExtension->CalculateParentEvent(aPointerEvent, parentEvent);
iExtension->iButtonDownItem = KErrNotFound;
iExtension->ResetPressedHighlight();
}
// act in Menu Sct or Option Menu repectively
if (( iExtension->iSct && menuSctRect.Contains(aPointerEvent.iPosition)) ||
( !iExtension->iSct && innerRect.Contains(aPointerEvent.iPosition)) &&
iExtension->iDownOnMenuArea )
{
iExtension->iDraggedOutside = EFalse;
// Scroll only through visible items
for ( TInt ii = topItem; ii < bottomItem; ++ii )
{
CEikMenuPaneItem* item = (*iItemArray)[ii];
// if item is searched item.
if ( (yPos < item->iPos + iItemHeight) && (yPos
> item->iPos) )
{
if ( iCascadeMenuPane )
{
// if submenu open and touched item is not the one which opened submenu, then close submenu
if ( (ii != iSelectedItem)
&& !cascadeMenuRect.Contains(
aPointerEvent.iPosition ) )
{
if ( CAknTransitionUtils::TransitionsEnabled(
AknTransEffect::EComponentTransitionsOff ) )
{
iExtension->ImmediateFeedback(
ETouchFeedbackSubMenuClosed );
}
else
{
iExtension->ImmediateFeedback(
ETouchFeedbackPopUp );
}
iExtension->iShowCascadeTransition = ETrue;
CloseCascadeMenu();
}
}
// item found, break
break;
}
}
}
}
break;
default:
break;
}
_AKNTRACE( "[%s]", "HandlePointerEventL return 16" );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::InputCapabilities
// Returns the input capabilites of the menu pane which accepts all text.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
EXPORT_C TCoeInputCapabilities CEikMenuPane::InputCapabilities() const
{
return TCoeInputCapabilities( TCoeInputCapabilities::EAllText ); // Max length parameter removed for release15
}
// -----------------------------------------------------------------------------
// CEikMenuPane::AddMenuItemL
// Adds a new menu item to the menu pane by creating a new menu item, setting its data to aMenuItem
// and appending it to the pane's menu item array. Updates the menu's scroll bar to take acount of the
// new item.
// SData is a structure so all fields in it should be set to avoid any unexpected behaviour.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::AddMenuItemL( const CEikMenuPaneItem::SData& aMenuItem )
// For use by Menu extensions
{
if ( !iItemArray )
CreateItemArrayL();
CEikMenuPaneItem* item = new(ELeave) CEikMenuPaneItem();
item->iData = aMenuItem;
iItemArray->AddItemL( item );
UpdateScrollBar();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::AddMenuItemL
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::AddMenuItemL(const CEikMenuPaneItem::SData& aMenuItem, TInt aPreviousId)
{
if ( !iItemArray )
CreateItemArrayL();
CEikMenuPaneItem* item = new(ELeave) CEikMenuPaneItem();
item->iData=aMenuItem;
TInt position = 0;
ItemAndPos( aPreviousId, position );
iItemArray->InsertL( position + 1, item);
UpdateScrollBar();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::DeleteMenuItem
// Deletes the menu item identified by aCommandId from the pane's item array.
// Updates the menu's scroll bar to take acount of the change.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::DeleteMenuItem( TInt aCommandId )
{
TInt count=0;
if( iItemArray )
count=iItemArray->Count();
for ( TInt ii = 0; ii < count; ++ii )
{
CEikMenuPaneItem* item=(*iItemArray)[ii];
if ( item->iData.iCommandId == aCommandId )
{
iItemArray->Delete( ii );
delete item;
UpdateScrollBar();
return;
}
}
Panic( EEikPanicNoSuchMenuItem );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::DeleteBetweenMenuItems
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::DeleteBetweenMenuItems( TInt aStartIndex, TInt aEndIndex )
{
__ASSERT_DEBUG( aStartIndex <= aEndIndex, Panic( EEikPanicNoSuchMenuItem ) );
TInt items(0);
if( iItemArray )
items=iItemArray->Count();
if ( aEndIndex >= items )
Panic( EEikPanicNoSuchMenuItem );
TInt count = aEndIndex - aStartIndex + 1;
for ( TInt ii = 0; ii < count; ii++ )
{
CEikMenuPaneItem* item = (*iItemArray)[aStartIndex];
iItemArray->Delete( aStartIndex );
delete item;
}
UpdateScrollBar();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ItemData
// Returns a reference to the data in the menu item identified by aCommandId.
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPaneItem::SData& CEikMenuPane::ItemData( TInt aCommandId )
{
TInt pos;
CEikMenuPaneItem* item=ItemAndPos( aCommandId, pos );
return item->iData;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ItemAndPos
// Returns a pointer to the menu item identified by aCommandId and gets the position of the item in aPos.
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPaneItem* CEikMenuPane::ItemAndPos( TInt aCommandId, TInt& aPos )
{
TInt count(0);
if( iItemArray )
count = iItemArray->Count();
aPos = 0;
CEikMenuPaneItem* item;
FOREVER
{
if ( aPos == count )
Panic( EEikPanicNoSuchMenuItem );
item = (*iItemArray)[aPos];
if ( item->iData.iCommandId == aCommandId )
break;
++aPos;
}
return item;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemTextL
// Sets the text of the menu item identified by aCommandId by reading it from the resource with id aRid.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemTextL(TInt aCommandId,TInt aRid)
{
TBuf<80> tmp;
iCoeEnv->ReadResource( tmp, aRid );
SetItemTextL( aCommandId, tmp);
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemTextL
// Sets the text of the menu item identified by aCommandId to the descriptor aDes.
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemTextL( TInt aCommandId, const TDesC& aDes )
{
TInt pos;
CEikMenuPaneItem* newItem=ItemAndPos( aCommandId, pos );
newItem->iData.iText.Copy( aDes );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemDimmed
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemDimmed( TInt aCommandId, TBool aDimmed )
{
CEikMenuPaneItem::SData& itemData = ItemData(aCommandId);
if ( aDimmed )
itemData.iFlags |= EEikMenuItemDimmed;
else
itemData.iFlags &= ( ~EEikMenuItemDimmed );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemButtonState
// Sets the item to be indicated or not. It should be used to change the state of radio
// buttons or check box items.
// It has real effect only starting from v3.0.
// @param aButtonState should be EEikMenuItemSymbolOn or EEikMenuItemSymbolIndeterminate
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemButtonState( TInt aCommandId,TInt aButtonState )
{
TInt pos(0);
CEikMenuPaneItem* item = ItemAndPos( aCommandId, pos );
if ( IsItemMemberOfRadioButtonGroup( pos ) )
{
if( aButtonState&EEikMenuItemSymbolOn )
{
iExtension->iSelectedRadioButtonItem = pos;
}
else if( iExtension->iSelectedRadioButtonItem == pos )
{
iExtension->iSelectedRadioButtonItem = KNoSelectedRadioButtonItem;
}
}
item->iData.iFlags&=( ~(EEikMenuItemSymbolOn|EEikMenuItemSymbolIndeterminate) ); // clears the flags
if ( aButtonState&EEikMenuItemSymbolOn )
{
item->iData.iFlags |= EEikMenuItemSymbolOn;
}
else if ( aButtonState&EEikMenuItemSymbolIndeterminate )
{
item->iData.iFlags |= EEikMenuItemSymbolIndeterminate;
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetSelectedItem
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetSelectedItem( TInt aSelectedItem )
{
iSelectedItem = (aSelectedItem >= NumberOfItemsInPane() ) ? 0 : aSelectedItem;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SelectedItem
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CEikMenuPane::SelectedItem() const
{
return iSelectedItem;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemArray
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemArray( CItemArray* aItemArray )
{
if ( !ItemArrayOwnedExternally() )
delete iItemArray;
iItemArray = aItemArray;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemArrayOwnedExternally
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemArrayOwnedExternally( TBool aOwnedExternally )
{
iArrayOwnedExternally=aOwnedExternally;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetLaunchingButton
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetLaunchingButton( CEikButtonBase* aButton )
{
iLaunchingButton = aButton;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::NumberOfItemsInPane
// Returns the number of menu items.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CEikMenuPane::NumberOfItemsInPane() const
{
return( iItemArray ? iItemArray->Count() : 0);
}
// -----------------------------------------------------------------------------
// CEikMenuPane::Close
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::Close()
{
if( iExtension )
{
iExtension->iPressedDown = EFalse;
iExtension->ResetPressedHighlight();
}
if ( OwnsWindow() )
CloseWindow();
if( iExtension )
iExtension->MenuClosed();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::Reserved_1
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::Reserved_1()
{}
// -----------------------------------------------------------------------------
// CEikMenuPane::Reserved_2
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::Reserved_2()
{}
//----------------------------------------------------------------------------
// CEikMenuPane::HandleScrollEventL()
//
// Handles scroll events by calculating new top and botton item indexes
// and then drawing all items that fit to screen
//----------------------------------------------------------------------------
//
void CEikMenuPane::HandleScrollEventL( CEikScrollBar* aScrollBar, TEikScrollEvent aEventType )
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "[%s]", "Stop physics engine");
iExtension->iPhysics->StopPhysics();
iExtension->iPhysics->ResetFriction();
// flag for do we need to update or even calculate scrolling
TBool update = ETrue;
// if submenu is opened, close it because scrolling in submenu is not possible.
// and in this case it also means tapping outside of submenu.
if (iCascadeMenuPane)
{
_AKNTRACE( "[%s]", "CloseCascadeMenu");
CloseCascadeMenu();
update = EFalse;
}
// how many items fit to view
const TInt itemsThatFitToView = NumberOfItemsThatFitInView();
// How many items there are in this menu.
TInt countOfItems = 0;
if( iItemArray )
{
countOfItems = iItemArray->Count();
}
// if scrolling is impossible because (there is not enough items to be scrolled)
if ( countOfItems < itemsThatFitToView )
{
update = EFalse;
}
// Get top and botton item indexes.
TInt topItem = iScroller->TopItemIndex();
TInt bottomItem = topItem + itemsThatFitToView;
_AKNTRACE( "topItem = %d", topItem);
_AKNTRACE( "bottomItem = %d", bottomItem);
if( bottomItem > NumberOfItemsInPane() )
{
bottomItem = NumberOfItemsInPane();
}
// Items that becomes topmost and downmost items
TInt newTopItem = 0;
// if update is not wanted, do nothing.
if ( update )
{
switch (aEventType)
{
case EEikScrollUp:
{
_AKNTRACE( "[%s]", "EEikScrollUp");
_AKNTRACE( "topItem = %d", topItem);
// if topItem is not upmost
if ( topItem > 0)
{
// move menu to one step up.
newTopItem = topItem - 1;
}
else
{
newTopItem = countOfItems - itemsThatFitToView;
}
_AKNTRACE( "newTopItem = %d", newTopItem);
}
break;
case EEikScrollDown:
{
_AKNTRACE( "[%s]", "EEikScrollDown");
_AKNTRACE( "bottomItem = %d", bottomItem);
// if last item is not visible
if ( bottomItem < countOfItems)
{
// move menu to show one step down.
newTopItem = topItem + 1;
}
else
{
newTopItem = 0;
}
_AKNTRACE( "newTopItem = %d", newTopItem);
}
break;
case EEikScrollPageUp:
{
_AKNTRACE( "[%s]", "EEikScrollPageUp");
_AKNTRACE( "topItem = %d", topItem);
// if topItem is not upmost
if ( topItem > 0)
{
// move menu to show one site up or then upmost.
newTopItem = (topItem > itemsThatFitToView) ? (topItem - itemsThatFitToView) : 0;
}
else
{
update = EFalse;
}
_AKNTRACE( "newTopItem = %d", newTopItem);
_AKNTRACE( "update = %d", update);
}
break;
case EEikScrollPageDown:
{
_AKNTRACE( "[%s]", "EEikScrollPageDown");
_AKNTRACE( "bottomItem = %d", bottomItem);
update = ETrue;
_AKNTRACE( "update = %d", update);
}
break;
case EEikScrollThumbDragVert:
{
_AKNTRACE( "[%s]", "EEikScrollThumbDragVert");
// new thumb position
TInt thumb = aScrollBar->ThumbPosition();
_AKNTRACE( "thumb = %d", thumb);
update = ETrue;
_AKNTRACE( "update = %d", update);
}
break;
default:
update = EFalse;
break;
}
// if topItem changed, then draw menu again.
if ( newTopItem != topItem || update )
{
iExtension->iListTopIndex = aScrollBar->ThumbPosition();
TPoint newPosition( iExtension->iViewPosition.iX,
iExtension->iListTopIndex + iExtension->iViewHeight / 2 );
iExtension->iFlags.Set( CEikMenuPaneExtension::ESkipScrollbarUpdate );
iExtension->ViewPositionChanged( newPosition );
iExtension->iFlags.Clear( CEikMenuPaneExtension::ESkipScrollbarUpdate );
}
}
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CreateScrollBarFrame
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CreateScrollBarFrame()
{
if (!CheckCreateScroller())
return;
TRAPD( err,( iSBFrame = new(ELeave) CEikScrollBarFrame( this, iScroller, ETrue, ETrue ) ) );
if ( !err )
{
CEikScrollBarFrame::TScrollBarVisibility visibility = CEikScrollBarFrame::EOn;
if ( iItemArray->Count() <= NumberOfItemsThatFitInView() )
{
// all items fit, no need to show the scrollbar
visibility = CEikScrollBarFrame::EOff;
}
TRAP_IGNORE( iSBFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, visibility ) );
TRAP_IGNORE( iSBFrame->CreateDoubleSpanScrollBarsL( EFalse, EFalse, ETrue, EFalse ) );
iSBFrame->DrawBackground( EFalse, EFalse );
UpdateScrollBar();
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::UpdateScrollBar
// -----------------------------------------------------------------------------
//
void CEikMenuPane::UpdateScrollBar()
{
if ( !CheckCreateScroller() || !IsVisible() )
return;
CIdle* idle = iScroller->Idle();
if ( idle && !idle->IsActive() )
idle->Start( TCallBack( CEikMenuPane::UpdateScrollBarCallBackL, this ) );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::UpdateScrollBarCallBackL
// -----------------------------------------------------------------------------
//
TInt CEikMenuPane::UpdateScrollBarCallBackL( TAny* aObj )
{ // static
REINTERPRET_CAST(CEikMenuPane*,aObj)->DoUpdateScrollBarL();
return 0;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::DoUpdateScrollBarL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::DoUpdateScrollBarL()
{
if (!iSBFrame)
return;
_AKNTRACE_FUNC_ENTER;
TEikScrollBarModel hSbarModel;
TEikScrollBarModel vSbarModel;
TRect clientRect( iExtension->iMenuPaneRect.Size() );
// Panning uses pixel resolution scrollbar
vSbarModel.iThumbPosition = iExtension->iListTopIndex;
vSbarModel.iScrollSpan = TotalItemHeight();
vSbarModel.iThumbSpan = iExtension->iViewHeight;
// Double span scroll bar uses different model, just convert to it here.
TAknDoubleSpanScrollBarModel hDsSbarModel( hSbarModel );
TAknDoubleSpanScrollBarModel vDsSbarModel( vSbarModel );
TRect scrollBarInclusiveRect( clientRect );
TRect scrollBarClientRect( scrollBarInclusiveRect );
TEikScrollBarFrameLayout layout;
layout.SetClientMargin( 0 );
layout.SetInclusiveMargin( 0 );
layout.iTilingMode = TEikScrollBarFrameLayout::EClientRectConstant;
CEikScrollBarFrame::TScrollBarVisibility visibility =
iSBFrame->ScrollBarVisibility( CEikScrollBar::EVertical );
// scrollbar is shown only if needed
if ( iExtension->iScrollbarVisibility == CEikScrollBarFrame::EOn
&& visibility == CEikScrollBarFrame::EOff )
{
iSBFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff,
CEikScrollBarFrame::EOn );
iExtension->iScrollBarRect = iSBFrame->VerticalScrollBar()->Rect();
}
else if ( iExtension->iScrollbarVisibility == CEikScrollBarFrame::EOff
&& visibility == CEikScrollBarFrame::EOn )
{
iSBFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff,
CEikScrollBarFrame::EOff );
iExtension->iScrollBarRect = TRect::EUninitialized;
}
TAknLayoutRect scrollLayoutRect;
scrollLayoutRect.LayoutRect( clientRect,
AknLayoutScalable_Avkon::listscroll_popup_sub_pane().LayoutLine() );
scrollBarInclusiveRect = scrollLayoutRect.Rect();
scrollBarClientRect = scrollBarInclusiveRect;
AknLayoutUtils::LayoutVerticalScrollBar( iSBFrame, scrollBarClientRect,
AknLayoutScalable_Avkon::scroll_pane_cp4().LayoutLine());
iSBFrame->TileL( &hDsSbarModel, &vDsSbarModel, scrollBarClientRect, scrollBarInclusiveRect, layout );
iSBFrame->SetVFocusPosToThumbPos( vDsSbarModel.FocusPosition() );
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::UpdateScrollBarThumbs
// -----------------------------------------------------------------------------
//
void CEikMenuPane::UpdateScrollBarThumbs()
{
if ( iSBFrame )
{
iSBFrame->SetVFocusPosToThumbPos( iExtension->iListTopIndex );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ScrollToMakeItemVisible
// -----------------------------------------------------------------------------
//
void CEikMenuPane::ScrollToMakeItemVisible(TInt aItemIndex)
{
_AKNTRACE_FUNC_ENTER;
if( !iItemArray || iItemArray->Count() == 0 )
return;
if ( !CheckCreateScroller() )
return;
if(iExtension->iSctHighlighted && aItemIndex == ENothingSelected)
aItemIndex = 0;
else if(aItemIndex == ENothingSelected)
return;
TInt maxItems = NumberOfItemsThatFitInView();
if ( iExtension->Offset() < 0 )
{
maxItems++;
}
//
// S60 menus are fixed size pitch and known size so scrolling can be based on index
//
TInt amountToScroll = 0;
if ( aItemIndex < iScroller->TopItemIndex() )
{ // +ve scroll
amountToScroll = iItemHeight * ( iScroller->TopItemIndex() - aItemIndex );
}
else if ( aItemIndex >= ( iScroller->TopItemIndex() + maxItems ) )
{
amountToScroll = iItemHeight * ( ( iScroller->TopItemIndex() +
maxItems ) - aItemIndex - 1 );
}
if ( amountToScroll )
{
_AKNTRACE( "amountToScroll = %d", amountToScroll );
Scroll(amountToScroll);
if ( !iExtension->isUpdateScrollDirectly )
{
UpdateScrollBar();
}
else
{
TRAP_IGNORE( DoUpdateScrollBarL() );
}
}
_AKNTRACE_FUNC_EXIT;
return;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::Scroll
// -----------------------------------------------------------------------------
//
void CEikMenuPane::Scroll( TInt aAmount )
{
_AKNTRACE_FUNC_ENTER;
if ( !CheckCreateScroller() )
return;
TInt count=0;
if( iItemArray )
count = iItemArray->Count();
// convert aAmount to a multiple of iItemHeight.
TInt integer = aAmount / iItemHeight;
TReal real = TReal( TReal( aAmount ) / TReal( iItemHeight ) );
if ( real > TReal( integer ) ) // make more positive
aAmount = ( integer + 1 ) * iItemHeight;
if ( real < TReal( integer ) ) // make more negative
aAmount = ( integer - 1 ) * iItemHeight;
// convert amount back into indices for S60
TInt newTop = iScroller->TopItemIndex() - ( aAmount / iItemHeight ); // don't think there should be a divide by 0 here.
newTop = Max( 0, newTop );
newTop = Min( newTop, count - NumberOfItemsThatFitInView() );
iScroller->SetTopItemIndex( newTop );
_AKNTRACE( "newTop = %d", newTop );
iExtension->iListTopIndex = iScroller->TopItemIndex() * iItemHeight;
TPoint newPosition( iExtension->iViewPosition );
newPosition.iY = iExtension->iListTopIndex + iExtension->iViewHeight / 2;
iExtension->SetOffset( 0 );
iExtension->ViewPositionChanged( newPosition );
_AKNTRACE( "iExtension->iListTopIndex = %d", iExtension->iListTopIndex );
_AKNTRACE( "iExtension->iViewPosition.iY = %d", iExtension->iViewPosition.iY );
_AKNTRACE( "[%s]", "iExtension->SetOffset( 0 )" );
_AKNTRACE_FUNC_EXIT;
return;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ViewRect
// -----------------------------------------------------------------------------
//
TRect CEikMenuPane::ViewRect() const
{
return Rect();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::NumberOfItemsThatFitInView
// -----------------------------------------------------------------------------
//
TInt CEikMenuPane::NumberOfItemsThatFitInView() const
{
TInt subst = 0;
if ( iExtension->iSct )
{
subst = 1;
}
iExtension->iItemsThatFitInView = iOwner ? AknLayoutScalable_Avkon::
list_single_popup_submenu_pane_ParamLimits().LastRow() + 1 :
AknLayoutScalable_Avkon::
list_single_pane_cp2_ParamLimits().LastRow() + 1 - subst;
if ( Layout_Meta_Data::IsLandscapeOrientation()
&& iExtension->iItemsThatFitInView == 6 )
{
iExtension->iItemsThatFitInView --;
}
return iExtension->iItemsThatFitInView;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::TotalItemHeight
// -----------------------------------------------------------------------------
//
TInt CEikMenuPane::TotalItemHeight() const
{
TInt height(0);
TInt count(0);
if( iItemArray )
count = iItemArray->Count();
for (TInt ii = 0; ii < count; ++ii )
{
height += iItemHeight;
}
if ( iExtension->iSct )
{
height += iItemHeight;
}
return height;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CheckCreateScroller
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::CheckCreateScroller()
{
TInt err = KErrNone;
if ( !iScroller )
{
TRAP( err,( iScroller = CMenuScroller::NewL( *this ) ) );
}
return err == KErrNone;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CheckCreateScrollerL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CheckCreateScrollerL()
{
if ( !iScroller )
iScroller = CMenuScroller::NewL( *this );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ItemArrayOwnedExternally
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::ItemArrayOwnedExternally() const
{
return iArrayOwnedExternally;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::GetColorUseListL
// Gets the list of logical colors employed in the drawing of the control,
// paired with an explanation of how they are used. Appends the list into aColorUseList.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::GetColorUseListL( CArrayFix<TCoeColorUse>& aColorUseList ) const
{
CEikBorderedControl::GetColorUseListL( aColorUseList );
TInt commonAttributes = TCoeColorUse::ENormal|TCoeColorUse::ENeutral;
TCoeColorUse colorUse;
colorUse.SetLogicalColor( EColorMenuPaneText );
colorUse.SetUse( TCoeColorUse::EFore|TCoeColorUse::EActive|TCoeColorUse::ESurrounds|commonAttributes );
aColorUseList.AppendL( colorUse );
colorUse.SetLogicalColor( EColorMenuPaneBackground );
colorUse.SetUse( TCoeColorUse::EBack|TCoeColorUse::EActive|TCoeColorUse::ESurrounds|commonAttributes);
aColorUseList.AppendL( colorUse );
colorUse.SetLogicalColor( EColorMenuPaneTextHighlight );
colorUse.SetUse( TCoeColorUse::EFore|TCoeColorUse::EActive|TCoeColorUse::EHighlights|commonAttributes );
aColorUseList.AppendL(colorUse);
colorUse.SetLogicalColor( EColorMenuPaneHighlight );
colorUse.SetUse(TCoeColorUse::EBack|TCoeColorUse::EActive|TCoeColorUse::EHighlights|commonAttributes );
aColorUseList.AppendL( colorUse );
colorUse.SetLogicalColor( EColorMenuPaneDimmedTextHighlight );
colorUse.SetUse( TCoeColorUse::EBack|TCoeColorUse::EDimmed|TCoeColorUse::EHighlights|commonAttributes );
aColorUseList.AppendL( colorUse );
colorUse.SetLogicalColor( EColorMenuPaneDimmedHighlight );
colorUse.SetUse( TCoeColorUse::EFore|TCoeColorUse::EDimmed|TCoeColorUse::EHighlights|commonAttributes );
aColorUseList.AppendL( colorUse );
colorUse.SetLogicalColor( EColorMenuPaneDimmedText );
colorUse.SetUse( TCoeColorUse::EBack|TCoeColorUse::EDimmed|TCoeColorUse::ESurrounds|commonAttributes);
aColorUseList.AppendL( colorUse );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::HandleResourceChange
// Handles a change to the control's resources of type aType
// which are shared across the environment, e.g. colors or fonts.
//
// @since ER5U
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::HandleResourceChange( TInt aType )
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "aType= %d", aType );
if ( aType == KEikDynamicLayoutVariantSwitch )
{
if ( IsActivated() )
{
TInt maxItems = NumberOfItemsThatFitInView();
TInt topIndex = iScroller->TopItemIndex();
TInt count = iItemArray->Count();
if ( count <= maxItems )
{
iScroller->SetTopItemIndex( 0 );
topIndex = iScroller->TopItemIndex();
}
//In portrait mode.
if ( !Layout_Meta_Data::IsLandscapeOrientation() )
{
if( ( count > maxItems ) && ( count - topIndex < maxItems ) )
{
TInt maxItemGaps = maxItems - (count - topIndex);
iScroller->SetTopItemIndex( topIndex - maxItemGaps );
topIndex = iScroller->TopItemIndex();
}
}
TInt index = iSelectedItem - topIndex;
if ( index >= maxItems )
{
topIndex = topIndex + (index + 1 - maxItems);
iScroller->SetTopItemIndex( topIndex );
}
TRect rect( CalculateSizeAndPosition() );
SetExtent( rect.iTl, rect.Size() );
//Initialize physics engine
if ( iExtension->iPhysics )
{
TRAP_IGNORE ( iExtension->InitPhysicsL() );
iExtension->iListTopIndex = iScroller->TopItemIndex() * iItemHeight;
iExtension->iViewPosition.iY =
iExtension->iListTopIndex + iExtension->iViewHeight / 2;
}
TRAP_IGNORE( DoUpdateScrollBarL() );
UpdateBackgroundContext( Rect() );
PrepareHighlightFrame();
SetCascadedIconSize();
DrawDeferred();
if ( iCascadeMenuPane )
{
iCascadeMenuPane->HandleResourceChange( aType );
}
}
}
else if( aType == KEikMessageUnfadeWindows
|| aType == KEikMessageWindowsFadeChange
|| aType == KEikMessageFadeAllWindows )
{
//Fix for ELYG-7DR5UF
if ( IsActivated() )
{
CEikScrollBar *verScrollBar = iSBFrame->VerticalScrollBar();
if ( verScrollBar != NULL
&& iSBFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn )
{
//iLastPointerEvent:Menu pane save the last pointer event in this
// variable every time in HandlePointerEvent().
if ( verScrollBar->Rect().Contains( iExtension->iLastPointerEvent.iPosition ) &&
( iExtension->iLastPointerEvent.iType == TPointerEvent::EButton1Down
|| iExtension->iLastPointerEvent.iType == TPointerEvent::EDrag ) )
{
TPointerEvent pointerEvent = iExtension->iLastPointerEvent;
pointerEvent.iType = TPointerEvent::EButton1Up;
// Sending a up event to scroll bar for dehighlighting
// the scroll bar.
TRAP_IGNORE ( verScrollBar->HandlePointerEventL(pointerEvent) );
iSBFrame->DrawScrollBarsDeferred();
ClaimPointerGrab( EFalse );
}
}
// Fixed for TSW error ELLI-7UG89S
if ( iExtension && iExtension->iPressedDown )
{
iExtension->iPressedDown = EFalse;
DrawNow();
}
if ( iCascadeMenuPane )
{
iCascadeMenuPane->HandleResourceChange( aType );
}
}
}
else if ( aType == KAknMessageFocusLost )
{
if ( iCascadeMenuPane )
{
iCascadeMenuPane->HandleResourceChange( aType );
}
else if ( iExtension && iExtension->HighlightEnabled() )
{
iExtension->EnableHighlight( EFalse, EFalse );
DrawItem( iSelectedItem, ENoHighlight );
}
}
else
{
CCoeControl::HandleResourceChange( aType );
if ( aType == KAknsMessageSkinChange )
{
// fixed for TSW error ECGO-7NZCPR.
SetCascadedIconSize();
DrawDeferred();
}
}
// Note: Animation is skin dependent, but it exists only when the menu is
// displayed (additionally, inactive menupane simply won't receive skin
// change event).
_AKNTRACE_FUNC_EXIT;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::InsertMenuItemL
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::InsertMenuItemL(const CEikMenuPaneItem::SData& aMenuItem, TInt aPosition)
{
if ( !iItemArray )
CreateItemArrayL();
CEikMenuPaneItem* item = new(ELeave) CEikMenuPaneItem();
item->iData = aMenuItem;
iItemArray->InsertL( aPosition, item );
UpdateScrollBar();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MenuItemExists
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CEikMenuPane::MenuItemExists( TInt aCommandId, TInt& aPosition )
{
TInt count(0);
if( iItemArray )
count = iItemArray->Count();
aPosition = 0;
CEikMenuPaneItem* item;
FOREVER
{
if ( aPosition == count )
return EFalse;
item =(*iItemArray)[aPosition];
if ( item->iData.iCommandId == aCommandId )
break;
++aPosition;
}
return ETrue;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::IsCascadeMenuPane
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CEikMenuPane::IsCascadeMenuPane() const
{
return iOwner != NULL;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CascadeMenuPane
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPane* CEikMenuPane::CascadeMenuPane()
{
return iCascadeMenuPane;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ItemDataByIndexL
// Gets a reference to the data in the specified menu item.
// -----------------------------------------------------------------------------
//
EXPORT_C CEikMenuPaneItem::SData& CEikMenuPane::ItemDataByIndexL(TInt aItemIndex)
{
__ASSERT_ALWAYS( iItemArray, Panic( EEikPanicInvalidIndex ) );
if ( aItemIndex < 0 || aItemIndex >= iItemArray->Count() )
{
User::Leave( KErrArgument );
}
CEikMenuPaneItem* item = (*iItemArray)[aItemIndex];
return item->iData;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::LoadCascadeBitmapL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::LoadCascadeBitmapL()
{
if ( iExtension )
{
if ( iExtension->iCascadeBitmap )
{
delete iExtension->iCascadeBitmap;
iExtension->iCascadeBitmap = NULL;
}
if ( iExtension->iCascadeBitmapMask )
{
delete iExtension->iCascadeBitmapMask;
iExtension->iCascadeBitmapMask = NULL;
}
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::CreateIconL( skin, KAknsIIDQgnIndiSubmenu, iExtension->iCascadeBitmap,
iExtension->iCascadeBitmapMask, KAvkonBitmapFile,
EMbmAvkonQgn_indi_submenu, EMbmAvkonQgn_indi_submenu_mask );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::LoadCheckMarkBitmapL
// Creates the bitmap and the mask for check mark icon
// -----------------------------------------------------------------------------
//
void CEikMenuPane::LoadCheckMarkBitmapL()
{
if ( iExtension )
{
if ( iExtension->iCheckMarkBitmap )
{
delete iExtension->iCheckMarkBitmap;
iExtension->iCheckMarkBitmap = NULL;
}
if ( iExtension->iCheckMarkBitmapMask )
{
delete iExtension->iCheckMarkBitmapMask;
iExtension->iCheckMarkBitmapMask = NULL;
}
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::CreateIconL( skin, KAknsIIDQgnPropSubMarked, iExtension->iCheckMarkBitmap,
iExtension->iCheckMarkBitmapMask, KAvkonBitmapFile,
EMbmAvkonQgn_prop_sub_marked, EMbmAvkonQgn_prop_sub_marked_mask );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MenuHasCheckBoxOn
// @return ETrue if at least one of the items has a check box to be on
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::MenuHasCheckBoxOn() const
{
for (TInt i = 0; i < iItemArray->Count(); i++)
{
CEikMenuPaneItem* item=(*iItemArray)[i];
if ( item->iData.iFlags&EEikMenuItemCheckBox && item->iData.iFlags&EEikMenuItemSymbolOn )
return ETrue;
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::LoadRadioButtonBitmapL
// Loads the bitmap and the mask for radio button icon
// -----------------------------------------------------------------------------
//
void CEikMenuPane::LoadRadioButtonBitmapL()
{
if ( iExtension )
{
if ( iExtension->iRadioButtonBitmap )
{
delete iExtension->iRadioButtonBitmap;
iExtension->iRadioButtonBitmap = NULL;
}
if ( iExtension->iRadioButtonBitmapMask )
{
delete iExtension->iRadioButtonBitmapMask;
iExtension->iRadioButtonBitmapMask = NULL;
}
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::CreateIconL( skin, KAknsIIDQgnPropSubCurrent, iExtension->iRadioButtonBitmap,
iExtension->iRadioButtonBitmapMask, KAvkonBitmapFile,
EMbmAvkonQgn_prop_sub_current, EMbmAvkonQgn_prop_sub_current_mask );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::IsItemMemberOfRadioButtonGroup
// @return ETrue if the item in submenu is the member of the radio button group
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::IsItemMemberOfRadioButtonGroup(TInt aItem) const
{
if ( !( Extension()->iHasRadioGroup ) )
{
return EFalse;
}
if (aItem < 0 || aItem >= iItemArray->Count())
{
return EFalse;
}
CEikMenuPaneItem* item = (*iItemArray)[aItem];
if ( item->iData.iFlags&( EEikMenuItemRadioStart|EEikMenuItemRadioMiddle|EEikMenuItemRadioEnd ) )
{
return ETrue;
}
for ( TInt i = aItem; i >= 0; i-- )
{
// try to find the beginning of radio button group, otherwise this item is before radio button group
CEikMenuPaneItem* previuosItem = (*iItemArray)[i];
if (previuosItem->iData.iFlags&EEikMenuItemRadioStart)
{
return ETrue;
}
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MenuHasIcon
// @return ETrue if at least one of the menu items has some icon to be drawn before the text.
// It is needed for DrawItem() function to move the text of all items right or left depending on the layout.
// If the menu doesn't contain any icons then text is positioned as in normal situation.
// -----------------------------------------------------------------------------
//
TBool CEikMenuPane::MenuHasIcon() const
{
TBool retValue = EFalse;
// only submenus might contain radio button or check box
if ( iOwner && iExtension )
{
retValue = ( (iExtension->iHasRadioGroup) || MenuHasCheckBoxOn() );
}
return retValue;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CalculateSizeAndPositionScalable
// Calculate size and position of a menu if scalable layouts are available.
// Also sets the rectangular for the menu pane
// -----------------------------------------------------------------------------
//
TRect CEikMenuPane::CalculateSizeAndPositionScalable( const TRect& aWindowRect, TInt aNumItemsInPane )
{
__ASSERT_ALWAYS( iExtension, Panic( EEikPanicNullPointer ) );
_AKNTRACE_FUNC_ENTER;
TRect retVal;
// it can be only in submenu in case when scalable layout is available
TBool hasIcon = MenuHasIcon();
// scrollbar is shown only if needed
if ( iItemArray->Count() > NumberOfItemsThatFitInView() )
{
iExtension->iScrollbarVisibility = CEikScrollBarFrame::EOn;
}
else
{
iExtension->iScrollbarVisibility = CEikScrollBarFrame::EOff;
}
TRect parentMenuRect;
AknLayoutUtils::TAknCbaLocation cbaPosition = AknLayoutUtils::CbaLocation();
if ( !iOwner )
{
_AKNTRACE( "[%s]", "the laylout of mainmenu" );
TAknLayoutRect parentMenuLayoutRect; // popup_menu_window
// This is a parent menu pane
// Number of items and cba position tells the right layout for menu pane.
// Constants (33, 20, 7) and calculations are based on to the variants of the layout data.
switch ( cbaPosition )
{
case AknLayoutUtils::EAknCbaLocationLeft:
{
_AKNTRACE( "[%s]", "AknLayoutUtils::EAknCbaLocationLeft" );
switch ( aNumItemsInPane )
{
case 7:
case 8:
{
parentMenuLayoutRect.LayoutRect( aWindowRect,
AknLayoutScalable_Avkon::popup_menu_window(37 + aNumItemsInPane).LayoutLine());
break;
}
default:
parentMenuLayoutRect.LayoutRect( aWindowRect,
AknLayoutScalable_Avkon::popup_menu_window(33 - aNumItemsInPane).LayoutLine());
break;
}
break;
}
case AknLayoutUtils::EAknCbaLocationRight:
{
_AKNTRACE( "[%s]", "AknLayoutUtils::EAknCbaLocationRight" );
TRect windowRect;
AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EPopupParent, windowRect );
switch ( aNumItemsInPane )
{
case 7:
case 8:
{
parentMenuLayoutRect.LayoutRect( windowRect,
AknLayoutScalable_Avkon::popup_menu_window(35 + aNumItemsInPane).LayoutLine());
break;
}
default:
parentMenuLayoutRect.LayoutRect( windowRect,
AknLayoutScalable_Avkon::popup_menu_window(20 - aNumItemsInPane).LayoutLine());
break;
}
break;
}
case AknLayoutUtils::EAknCbaLocationBottom:
{
_AKNTRACE( "[%s]", "AknLayoutUtils::EAknCbaLocationBottom" );
switch ( aNumItemsInPane )
{
case 7:
case 8:
{
parentMenuLayoutRect.LayoutRect( aWindowRect,
AknLayoutScalable_Avkon::popup_menu_window(33 + aNumItemsInPane).LayoutLine());
break;
}
default:
parentMenuLayoutRect.LayoutRect( aWindowRect,
AknLayoutScalable_Avkon::popup_menu_window(7 + aNumItemsInPane).LayoutLine());
break;
}
break;
}
default:
break;
}
parentMenuRect = parentMenuLayoutRect.Rect();
}
else
{
_AKNTRACE( "[%s]", "the layout of submenu" );
// submenu
parentMenuRect = TRect( iOwner->Position(), iOwner->Size() );
}
_AKNTRACE( "parentMenuRect.iTl.iX = %d", parentMenuRect.iTl.iX );
_AKNTRACE( "parentMenuRect.iTl.iY = %d", parentMenuRect.iTl.iY );
_AKNTRACE( "parentMenuRect.Width() = %d", parentMenuRect.Width() );
_AKNTRACE( "parentMenuRect.Height( = %d", parentMenuRect.Height() );
if ( !iOwner ) // main menu
{
// Embedded cba
TRect screen;
AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );
TAknLayoutRect cbaRect;
cbaRect.LayoutRect( screen,
AknLayoutScalable_Avkon::popup_sk_window( 0 ).LayoutLine() );
// Add space for embedded cba
TRect menuRect ( parentMenuRect );
parentMenuRect.iBr.iY += ( cbaRect.Rect().Height() );
// CEikMenuPane rect contains empty space. We want the popup content
// to be in correct place - so we calculate correct position for
// background and move control rect to match new background top left
// position.
TPoint backgroundRectPos(
AknPopupUtils::Position( parentMenuRect.Size(), ETrue ) );
retVal = parentMenuRect;
retVal.Move( backgroundRectPos - parentMenuRect.iTl );
// Set embedded cba rect
if ( iExtension->iCba )
{
// There is hidden extra touch space for scroll bar in landscape
TInt xOffset = parentMenuRect.iTl.iX - parentMenuRect.iTl.iX ;
iExtension->iCba->SetRect( TRect(
xOffset,
menuRect.Height(),
parentMenuRect.Width() + xOffset,
menuRect.Height() + cbaRect.Rect().Height() ) );
}
iExtension->iMenuPaneRect = TRect( retVal.iTl,
TSize ( menuRect.Size() ) );
TInt variety = 4;
// reserve area for scrollbar only if it's shown
if ( iExtension->iScrollbarVisibility == CEikScrollBarFrame::EOn )
{
variety = 0;
}
TAknLayoutRect layoutRect;
layoutRect.LayoutRect( TRect( iExtension->iMenuPaneRect.Size() ),
AknLayoutScalable_Avkon::listscroll_popup_sub_pane( 0 ) );
iExtension->iMenuAreaRect = layoutRect.Rect();
layoutRect.LayoutRect( iExtension->iMenuAreaRect,
AknLayoutScalable_Avkon::list_menu_pane( variety ) );
iExtension->iItemAreaRect = layoutRect.Rect();
_AKNTRACE( "[%s]", "the layout of main menu return" );
_AKNTRACE_FUNC_EXIT;
return retVal;
}
// This is a cascaded sub menu
// Get a rectangle for the Parent Menu (iOwner)
TInt parentCount = iOwner->iItemArray->Count(); // There must be at least one parent item for a submenu to have popped up.
iExtension->iSubMenuWidthIndex = KAlternativeSubmenuWidths - 1;
TAknLayoutRect parentListScrollLayoutRect; // listscroll_menu_pane
TAknTextLineLayout subMenuText; // layout for the text when item is not indicated
TAknTextLineLayout subMenuIconText; // layout for the text when item is indicated
TAknWindowLineLayout parentListScrollPaneLayout(
AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() );
parentListScrollLayoutRect.LayoutRect( parentMenuRect, parentListScrollPaneLayout );
subMenuText = AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1(0).LayoutLine();
subMenuIconText = AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1(1).LayoutLine();
// Choose correct submenu width
// Find the narrowest layout that will accommodate the text
// Need the font.
const CFont* font = AknLayoutUtils::FontFromId( subMenuIconText.FontId() );
// find the longest piece of text
TInt textWidth = 0;
TInt maxTextWidth = 0;
TInt ii = 0;
TInt count = (NULL != iItemArray) ? iItemArray->Count() : 0;
for (ii = 0; ii < count; ++ii)
{
CEikMenuPaneItem* item = (*iItemArray)[ii];
textWidth = font->TextWidthInPixels( item->iData.iText );
maxTextWidth = Max( maxTextWidth, textWidth );
}
// find the suitable item width, so that the text would be visible
TInt submenuVariety = 1;
if ( iExtension->iScrollbarVisibility == CEikScrollBarFrame::EOn )
{
submenuVariety = 0;
}
for ( ii = 6; ii < KAlternativeSubmenuWidths + 6; ++ii )
{
TAknWindowLineLayout submenuLayout( AknLayoutScalable_Avkon::popup_submenu_window( ii ).LayoutLine() );
TAknLayoutRect submenuRect;
submenuRect.LayoutRect( parentListScrollLayoutRect.Rect(), submenuLayout );
TAknWindowLineLayout listScrollPaneLayout( AknLayoutScalable_Avkon::listscroll_popup_sub_pane().LayoutLine() );
TAknLayoutRect listScrollPaneRect;
listScrollPaneRect.LayoutRect( submenuRect.Rect(), listScrollPaneLayout );
TAknWindowLineLayout listSubmenuPaneLayout( AknLayoutScalable_Avkon::list_submenu_pane( submenuVariety ).LayoutLine() );
TAknLayoutRect listSubmenuPaneRect;
listSubmenuPaneRect.LayoutRect( listScrollPaneRect.Rect(), listSubmenuPaneLayout );
TAknLayoutText textIconLayout;
textIconLayout.LayoutText( listSubmenuPaneRect.Rect(), subMenuIconText);
TAknLayoutText textLayout;
textLayout.LayoutText( listSubmenuPaneRect.Rect(), subMenuText);
TInt width = textLayout.TextRect().Width();
TInt maxWidth( maxTextWidth );
if ( hasIcon )
{
// this is needed to calculate right index, because they are for the case when there is no indication
TInt difference = textIconLayout.TextRect().iTl.iX - textLayout.TextRect().iTl.iX;
maxWidth = maxTextWidth + difference;
width = textIconLayout.TextRect().Width();
}
if ( width >= maxWidth)
{
iExtension->iSubMenuWidthIndex = ii - 6; // finally we found one
break;
}
}
// Position of submenu depends upon parent size and position of selected item. Position is 1 at bottom up to six at top
TInt parentPos = iOwner->iScroller->TopItemIndex() - iOwner->SelectedItem() +
Min( parentCount, iOwner->NumberOfItemsThatFitInView() );
TRect parentSelectedItemRect( iOwner->HighlightRect() );
parentSelectedItemRect.Move( iOwner->Position() );
TAknLayoutRect submenuWindowRect;
// To prevent a panic in layout code, count has to be at least 1 even if
// submenu is empty. Otherwise the index is out of bounds.
if ( count == 0 )
{
count++;
}
TInt maxItems = NumberOfItemsThatFitInView();
submenuWindowRect.LayoutRect( parentMenuRect,
AknLayoutScalable_Avkon::popup_submenu_window( Min( count, maxItems ) - 1 ).LayoutLine() );
// if submenu is higher than main menu, we should not allow it to cover softkeys in landscape
// the same should be done if position of the menu was set from outside.
if ( ( Layout_Meta_Data::IsLandscapeOrientation()
&& cbaPosition != AknLayoutUtils::EAknCbaLocationBottom &&
( submenuWindowRect.Rect().Height() > parentMenuRect.Height() ) ) )
{
// submenu should stay inside main menu by width,
TRect bufRect( aWindowRect );
bufRect.iTl.iX = parentMenuRect.iTl.iX;
bufRect.iBr.iX = parentMenuRect.iBr.iX;
submenuWindowRect.LayoutRect( bufRect,
AknLayoutScalable_Avkon::popup_submenu_window( Min( count, maxItems ) - 1 ).LayoutLine() );
}
TAknLayoutRect widthSubmenuRect;
widthSubmenuRect.LayoutRect( parentMenuRect,
AknLayoutScalable_Avkon::popup_submenu_window( iExtension->iSubMenuWidthIndex + 6 ).LayoutLine() );
TAknWindowLineLayout listScrollPaneLayout( AknLayoutScalable_Avkon::listscroll_popup_sub_pane().LayoutLine() );
TAknLayoutRect listScrollPaneRect;
listScrollPaneRect.LayoutRect( submenuWindowRect.Rect(), listScrollPaneLayout );
enum { EFloating, EBottom } subMenuPos;
if ( ( Layout_Meta_Data::IsLandscapeOrientation()
&& cbaPosition != AknLayoutUtils::EAknCbaLocationBottom ) )
{
if ( ( parentSelectedItemRect.iTl.iY + submenuWindowRect.Rect().Height() ) >
aWindowRect.iBr.iY )
{
subMenuPos = EBottom;
}
else
{
subMenuPos = EFloating;
}
}
else
{
if ( iOwner->iExtension->Offset() < 0 &&
((parentPos == 1 && count == 1) ||
(parentPos == 2 && count <= 2) ||
(parentPos == 3 && count <= 3) ||
(parentPos == 4 && count <= 4) ||
(parentPos == 5 && count <= 5) ) )
{
// The menu has partial items because of panning and that has an effect on submenu positioning.
subMenuPos = EFloating;
}
else if (parentPos == 1 ||
(parentPos ==2 && count >= 2) ||
(parentPos == 3 && count >= 4) ||
(parentPos == 4 && count >= 5) ||
(parentPos == 5 && count >= 6) )
{
subMenuPos = EBottom;
}
else
{
subMenuPos = EFloating;
}
}
if ( subMenuPos == EBottom )
{
TInt widthOffset = widthSubmenuRect.Rect().Width() - submenuWindowRect.Rect().Width();
if ( !AknLayoutUtils::LayoutMirrored() )
{
retVal = TRect( TPoint( submenuWindowRect.Rect().iTl.iX - widthOffset, submenuWindowRect.Rect().iTl.iY ),
TSize( submenuWindowRect.Rect().Width() + widthOffset, submenuWindowRect.Rect().Height() ) );
}
else
{
retVal = TRect( submenuWindowRect.Rect().iTl,
TSize( submenuWindowRect.Rect().Width() + widthOffset, submenuWindowRect.Rect().Height() ) );
}
}
else // floating
{
TInt yPos = parentSelectedItemRect.iTl.iY -
( listScrollPaneRect.Rect().iTl.iY - submenuWindowRect.Rect().iTl.iY );
// When a submenu is floating, make sure that the possible panning offset of the
// parent menu is taken into account.
yPos += iOwner->iExtension->Offset();
TInt widthOffset = widthSubmenuRect.Rect().Width() - submenuWindowRect.Rect().Width();
if ( !AknLayoutUtils::LayoutMirrored() )
{
retVal = TRect( TPoint( submenuWindowRect.Rect().iTl.iX - widthOffset, yPos ),
TSize( submenuWindowRect.Rect().Width() + widthOffset, submenuWindowRect.Rect().Height() ) );
}
else
{
retVal = TRect( TPoint( submenuWindowRect.Rect().iTl.iX, yPos ),
TSize( submenuWindowRect.Rect().Width() + widthOffset, submenuWindowRect.Rect().Height() ) );
}
}
// move submenu if it overlaps with embedded cba
if ( iOwner && iOwner->iExtension->iCba )
{
if ( retVal.iBr.iY > iOwner->iExtension->iMenuPaneRect.iBr.iY )
{
TInt offset = retVal.iBr.iY -
iOwner->iExtension->iMenuPaneRect.iBr.iY;
retVal.Move( 0, -offset );
}
}
if ( retVal.iTl.iY < 0 )
{
retVal.Move( 0, -retVal.iTl.iY );
}
iExtension->iMenuPaneRect = retVal;
TAknLayoutRect layoutRect;
layoutRect.LayoutRect( TRect( iExtension->iMenuPaneRect.Size() ),
AknLayoutScalable_Avkon::listscroll_popup_sub_pane( 0 ) );
iExtension->iMenuAreaRect = layoutRect.Rect();
layoutRect.LayoutRect( iExtension->iMenuAreaRect,
AknLayoutScalable_Avkon::list_submenu_pane( submenuVariety ) );
iExtension->iItemAreaRect = layoutRect.Rect();
_AKNTRACE( "[%s]", "the layout of sub menu return" );
_AKNTRACE_FUNC_EXIT;
return retVal;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::HighlightRect
// -----------------------------------------------------------------------------
//
TRect CEikMenuPane::HighlightRect() const
{
TInt index = iSelectedItem - iScroller->TopItemIndex();
// If menu is closed and the selected item index is outside the visible
// item range this method is called with new iSelectedItem and old
// TopItemIndex. Which results in negative index. This "fix" prevents from
// crashing the menu.
if( index < 0 )
index = 0;
// When physics is enabled highlight can be moved to partially visible
// item which is at the bottom of menu. This causes layout panic and to
// avoid that we reduce index by one.
if ( index == NumberOfItemsThatFitInView() )
{
index--;
}
return ItemRect( index );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::PrepareHighlightFrame
// helps to avoid flickering on drawing
// -----------------------------------------------------------------------------
//
void CEikMenuPane::PrepareHighlightFrame() const
{
TRect highlightRect( HighlightRect() );
TAknLayoutRect highlightTopLeft;
TAknLayoutRect highlightBottomRight;
highlightTopLeft.LayoutRect( highlightRect,
SkinLayout::List_highlight_skin_placing__popup_windows__Line_2() );
highlightBottomRight.LayoutRect( highlightRect,
SkinLayout::List_highlight_skin_placing__popup_windows__Line_5() );
TRect outerRect = TRect( highlightTopLeft.Rect().iTl, highlightBottomRight.Rect().iBr );
TRect innerRect = TRect( highlightTopLeft.Rect().iBr, highlightBottomRight.Rect().iTl );
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsDrawUtils::PrepareFrame( skin, outerRect, innerRect,
KAknsIIDQsnFrList, KAknsIIDDefault );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetCascadedIconSize
// Calls SetSize for cascaded icon. Doing this in construction phase makes
// Draw() method faster.
// -----------------------------------------------------------------------------
//
void CEikMenuPane::SetCascadedIconSize() const
{
TAknWindowLineLayout elementCascade( AknLayoutScalable_Avkon::list_single_pane_cp2_g3().LayoutLine());
TAknLayoutRect cascadeRect;
cascadeRect.LayoutRect( HighlightRect(), elementCascade );
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
CAknsMaskedBitmapItemData* itemData = static_cast<CAknsMaskedBitmapItemData*>(
skin->GetCachedItemData( KAknsIIDQgnIndiSubmenu, EAknsITMaskedBitmap ) );
if( itemData )
{
AknIconUtils::SetSize( itemData->Bitmap(), cascadeRect.Rect().Size() );
}
else
{
if (iExtension->iCascadeBitmap)
{
AknIconUtils::SetSize( iExtension->iCascadeBitmap, cascadeRect.Rect().Size() );
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::EnableMarqueeL
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::EnableMarqueeL( const TBool /*aEnable*/ )
{
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MopSupplyObject
// -----------------------------------------------------------------------------
//
EXPORT_C TTypeUid::Ptr CEikMenuPane::MopSupplyObject( TTypeUid aId )
{
if( aId.iUid == MAknsControlContext::ETypeId && iExtension && iExtension->iBgContext )
{
// Supply background skin context for scroll bars.
return MAknsControlContext::SupplyMopObject( aId, iExtension->iBgContext);
}
return CCoeControl::MopSupplyObject( aId );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CountComponentControls
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CEikMenuPane::CountComponentControls() const
{
TInt count = 0;
if ( iSBFrame && iSBFrame->VerticalScrollBar() )
{
count = 1;
}
if ( iExtension->iSct )
{
count++;
}
if ( iExtension->iCba )
{
count++;
}
return count;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ComponentControl
// -----------------------------------------------------------------------------
//
EXPORT_C CCoeControl* CEikMenuPane::ComponentControl( TInt aIndex ) const
{
switch ( aIndex)
{
case 0:
{
if ( iSBFrame && iSBFrame->VerticalScrollBar() )
{
return iSBFrame->VerticalScrollBar();
}
}
case 1:
{
if ( iExtension->iSct )
{
return iExtension->iSct;
}
else if ( iExtension->iCba )
{
return iExtension->iCba;
}
}
case 2:
{
if ( iExtension->iCba )
{
return iExtension->iCba;
}
}
default:
{
return NULL;
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::Extension
// Asserts that extension object has been created.
// -----------------------------------------------------------------------------
//
CEikMenuPaneExtension* CEikMenuPane::Extension() const
{
__ASSERT_ALWAYS( iExtension, Panic( EEikPanicNullPointer ) );
return iExtension;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CheckCreateExtensionL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CheckCreateExtensionL()
{
if ( !iExtension )
{
iExtension = new (ELeave) CEikMenuPaneExtension;
iExtension->ConstructL( this );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ItemRect
// -----------------------------------------------------------------------------
//
TRect CEikMenuPane::ItemRect( TInt aItemIndex ) const
{
// this method is valid for the main menu only
TInt lastRow = AknLayoutScalable_Avkon::list_single_pane_cp2_ParamLimits().LastRow();
aItemIndex = Min( aItemIndex, lastRow );
TAknLayoutRect layoutRect;
layoutRect.LayoutRect( iExtension->iItemAreaRect,
AknLayoutScalable_Avkon::list_single_pane_cp2( aItemIndex ) );
return layoutRect.Rect();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CalculateItemHeight
// -----------------------------------------------------------------------------
//
TInt CEikMenuPane::CalculateItemHeight() const
{
TAknWindowLineLayout menuLineLayout;
if ( iOwner ) // submenu
{
menuLineLayout =
AknLayoutScalable_Avkon::list_single_popup_submenu_pane( 0 ).LayoutLine();
}
else
{
menuLineLayout =
AknLayoutScalable_Avkon::list_single_pane_cp2( 0 ).LayoutLine();
}
TAknLayoutRect menuLayoutRect;
menuLayoutRect.LayoutRect( Rect(), menuLineLayout );
return menuLayoutRect.Rect().Height();
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ConstructMenuSctRowL
// Creates an sct row for editing menu.
// @param aSpecialChars Buffer that holds selected characters
// @since 3.1
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::ConstructMenuSctRowL( TDes& aSpecialChars )
{
CheckCreateScrollerL();
CheckCreateExtensionL();
TInt resourceId = R_AVKON_MENU_SCT_ROW_DEFAULT_CONTENTS;
if (FeatureManager::FeatureSupported(KFeatureIdChinese))
{
resourceId = R_AVKON_MENU_SCT_ROW_DEFAULT_CONTENTS_CHINESE;
}
iExtension->ConstructMenuSctRowL( aSpecialChars, resourceId );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ConstructMenuSctRowL
// Creates an sct row for editing menu.
// @param aSpecialChars Buffer that holds selected characters
// @since 3.1
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::ConstructMenuSctRowL( TDes& aSpecialChars, TInt aResourceId )
{
CheckCreateScrollerL();
CheckCreateExtensionL();
iExtension->ConstructMenuSctRowL( aSpecialChars, aResourceId );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ConstructMenuSctRowFromDialogL
// Creates an sct row for editing menu.
// @param aSpecialChars Buffer that holds selected characters
// @since 3.1
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::ConstructMenuSctRowFromDialogL( TDes& aSpecialChars, TInt aResourceId )
{
CheckCreateScrollerL();
CheckCreateExtensionL();
iExtension->ConstructMenuSctRowFromDialogL( aSpecialChars, aResourceId );
}
// -----------------------------------------------------------------------------
// CEikMenuPane::ConstructMenuSctRowFromDialogL
// Creates an sct row for editing menu.
// @param aSpecialChars Buffer that holds selected characters
// @since 3.1
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::ConstructMenuSctRowFromDialogL( TInt aCharCase, TDes& aSpecialChars, TInt aResourceId )
{
ConstructMenuSctRowFromDialogL( aSpecialChars, aResourceId);
iExtension->iSct->SetCharacterCaseL(aCharCase);
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemSpecific
// -----------------------------------------------------------------------------
//
EXPORT_C void CEikMenuPane::SetItemSpecific(
TInt aCommandId, TBool aItemSpecific )
{
if ( !iExtension )
{
TRAPD( err, CheckCreateExtensionL() );
if ( err )
{
return;
}
}
if ( iExtension->iFlags.IsSet(
CEikMenuPaneExtension::ESingleClickEnabled ) )
{
CEikMenuPaneItem::SData& itemData = ItemData( aCommandId );
if ( aItemSpecific )
{
// item specific command cannot be item action command
itemData.iFlags &= ( ~EEikMenuItemAction );
itemData.iFlags |= EEikMenuItemSpecific;
}
else
{
// clear both item specific flags
itemData.iFlags &= ( ~EEikMenuItemSpecific );
itemData.iFlags &= ( ~EEikMenuItemSpecificListQuery );
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::MenuItemCommandId
// Returns the command id of the specified menu item.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CEikMenuPane::MenuItemCommandId( const TInt aIndex ) const
{
if ( !iItemArray || aIndex >= iItemArray->Count() || aIndex < 0 )
{
Panic( EEikPanicInvalidIndex );
}
CEikMenuPaneItem* item = (*iItemArray)[aIndex];
if ( !item )
{
Panic( EEikPanicNullPointer );
}
return item->iData.iCommandId;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetEmbeddedCba
// -----------------------------------------------------------------------------
//
void CEikMenuPane::SetEmbeddedCba( CEikCba* aCba )
{
if ( iExtension )
{
iExtension->iCba = aCba;
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CloseCascadeMenu
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CloseCascadeMenu( TBool aMainMenuClosing )
{
if ( iCascadeMenuPane == NULL )
{
return;
}
if( iCascadeMenuPane->iCascadeMenuPane)
{
return iCascadeMenuPane->CloseCascadeMenu();
}
// This CloseCascadeMenu method is called from CEikMenuPane destructor.
// CEikMenuPane may be destroyed in AppUi's destructor.
// Thus, skin instance may not be valid any more when this function is called
// and all drawing should be avoided in such situation.
TBool okToDraw = EFalse;
//iExtension->StartCascadeMenuDisappearTransition();
if ( iCascadeMenuPane->IsVisible() )
{
okToDraw = AknsUtils::SkinInstance() != NULL;
// Stop ongoing comp. transitions, this is mostly for fast clicking
// cases to make sure that no "scrap" is left behind.
GfxTransEffect::NotifyExternalState( ENotifyGlobalAbort );
// cascade menu "cancel" animation. This does not apply
// when something is chosen from the menu
if ( iExtension->iShowCascadeTransition && okToDraw )
{
iCascadeMenuPane->SetParent( this );
GfxTransEffect::Begin( iCascadeMenuPane, KGfxControlDisappearAction );
GfxTransEffect::SetDemarcation( iCascadeMenuPane, iExtension->iCascadeDRect );
iCascadeMenuPane->MakeVisible( EFalse );
GfxTransEffect::End( iCascadeMenuPane );
}
}
// deregister right away since cascade menu is deleted
GfxTransEffect::Deregister( iCascadeMenuPane );
iExtension->iShowCascadeTransition = EFalse;
//For transitions, keep the cascade menu object alive a little
// longer so that the transition system does not ever refer to
// deleted object
iExtension->iCascadeMenuObject = iCascadeMenuPane;
iCascadeMenuPane->MakeVisible( EFalse );
iCascadeMenuPane = NULL;
if ( !aMainMenuClosing )
{
// Submenu is closed.Parent menu pane will grab window.
// ClaimPointerGrab invokes pointer up event.
ClaimPointerGrab(ETrue);
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::NewItemCommandMenuL
// -----------------------------------------------------------------------------
//
CEikMenuPane* CEikMenuPane::NewItemCommandMenuL( MEikMenuObserver* aObserver )
{
CEikMenuPane* menuPane = new ( ELeave ) CEikMenuPane( aObserver );
CleanupStack::PushL( menuPane );
menuPane->iExtension = new ( ELeave ) CEikMenuPaneExtension();
menuPane->iExtension->iFlags.Set(
CEikMenuPaneExtension::ESingleClickEnabled );
menuPane->CreateItemArrayL();
CleanupStack::Pop( menuPane );
return menuPane;
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemCommandsStateL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::SetItemCommandsStateL( TBool aDimmed )
{
if ( iExtension && iExtension->iFlags.IsSet(
CEikMenuPaneExtension::ESingleClickEnabled ) )
{
if ( aDimmed )
{
iExtension->iFlags.Set(
CEikMenuPaneExtension::EHideItemSpecificCommands );
}
else
{
iExtension->iFlags.Set(
CEikMenuPaneExtension::EHideViewSpecificCommands );
}
for ( TInt i = 0; i < iItemArray->Count(); ++i )
{
CEikMenuPaneItem* item = iItemArray->At( i );
TBool itemSpecificItem(
item->iData.iFlags & EEikMenuItemAction
|| item->iData.iFlags & EEikMenuItemSpecific
|| item->iData.iFlags & EEikMenuItemSpecificListQuery );
// Dim item specific items
if ( aDimmed && itemSpecificItem )
{
item->iData.iFlags |= EEikMenuItemDimmed;
}
// Dim items not item specific
else if ( !aDimmed
&& ( !itemSpecificItem
|| item->iData.iFlags & EEikMenuItemAction ) )
{
item->iData.iFlags |= EEikMenuItemDimmed;
if ( item->iData.iCascadeId )
{
// i is not updated in AddCascadeMenuItemsToMenuL so going
// through added items again here. Then it goes through
// also submenus of submenus.
AddCascadeMenuItemsToMenuL(
item->iData.iCascadeId, ETrue, EFalse, NULL, i );
}
}
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetItemActionsStateL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::SetItemActionsStateL( TBool aDimmed )
{
if ( iExtension && iExtension->iFlags.IsSet(
CEikMenuPaneExtension::ESingleClickEnabled ) )
{
if ( aDimmed )
{
iExtension->iFlags.Set(
CEikMenuPaneExtension::EHideItemActionCommands );
}
for ( TInt i = 0; i < iItemArray->Count(); ++i )
{
CEikMenuPaneItem* item = iItemArray->At( i );
TBool itemActionItem(
item->iData.iFlags & EEikMenuItemAction );
// Dim item specific items
if ( aDimmed && itemActionItem )
{
item->iData.iFlags |= EEikMenuItemDimmed;
}
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::AddMenuItemsToItemActionMenuL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::AddMenuItemsToItemActionMenuL(
CAknItemActionMenuData& aMenuData )
{
TInt menuItemCount( iItemArray->Count() );
for ( TInt i = 0; i < menuItemCount; ++i )
{
CEikMenuPaneItem* item = iItemArray->At( i );
// Add menu item if menu item is not dimmed and
// 1) menu item belongs to cascade menu
// 2) menu item is item specific command
// 3) menu item is item specific list query
if ( CEikMenuPaneExtension::ItemSpecificCommand( *item ) )
{
// If menu item is not list query and it has cascade menu
// add cascade menu items to menu data directly
if ( !( item->iData.iFlags & EEikMenuItemSpecificListQuery )
&& item->iData.iCascadeId )
{
AddCascadeMenuItemsToMenuL(
item->iData.iCascadeId, EFalse, ETrue, &aMenuData );
}
// If menu item is list query or it does not have cascade menu
else
{
aMenuData.AddMenuItemToDataArrayL(
item->iData.iCommandId,
item->iData.iCascadeId,
item->iData.iText );
}
}
// If item is not item specific, add its item specific cascade menu
// items if the item itself isn't dimmed.
else if ( item->iData.iCascadeId &&
!( item->iData.iFlags & EEikMenuItemDimmed ) )
{
AddCascadeMenuItemsToMenuL(
item->iData.iCascadeId, ETrue, ETrue, &aMenuData );
}
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::AddCascadeMenuItemsToMenuL
// -----------------------------------------------------------------------------
//
void CEikMenuPane::AddCascadeMenuItemsToMenuL(
TInt aCascadeId,
TBool aItemSpecific,
TBool aAddToItemActionMenu,
CAknItemActionMenuData* aMenuData,
TInt aItemIndex )
{
if ( aCascadeId && iCoeEnv->IsResourceAvailableL( aCascadeId ) )
{
CEikMenuPane* cascadeMenu =
CEikMenuPane::NewItemCommandMenuL( iMenuObserver );
CleanupStack::PushL( cascadeMenu );
cascadeMenu->AddMenuItemsL( aCascadeId, 0 );
iMenuObserver->DynInitMenuPaneL( aCascadeId, cascadeMenu );
TInt menuItemCount( cascadeMenu->iItemArray->Count() );
for ( TInt i = 0; i < menuItemCount; ++i )
{
CEikMenuPaneItem* item = cascadeMenu->iItemArray->At( i );
if ( ( aItemSpecific
&& CEikMenuPaneExtension::ItemSpecificCommand( *item ) )
|| ( !aItemSpecific
&& !( item->iData.iFlags & EEikMenuItemDimmed ) ) )
{
if ( aAddToItemActionMenu )
{
aMenuData->AddMenuItemToDataArrayL(
item->iData.iCommandId,
item->iData.iCascadeId,
item->iData.iText );
}
else
{
InsertMenuItemL( item->iData, ++aItemIndex );
}
}
}
CleanupStack::PopAndDestroy( cascadeMenu );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::SetDefaultHighlight
// -----------------------------------------------------------------------------
//
void CEikMenuPane::SetDefaultHighlight()
{
if ( iExtension )
{
iExtension->SetDefaultHighlight();
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::HideMarkAndUnmark
// -----------------------------------------------------------------------------
//
void CEikMenuPane::HideMarkAndUnmark( TBool aHide )
{
if ( aHide )
{
iExtension->iFlags.Set( CEikMenuPaneExtension::EHideMarkAndUnmark );
}
else
{
iExtension->iFlags.Clear( CEikMenuPaneExtension::EHideMarkAndUnmark );
}
}
// -----------------------------------------------------------------------------
// CEikMenuPane::CleanLocalRef
// -----------------------------------------------------------------------------
//
void CEikMenuPane::CleanLocalRef( TAny* any )
{
static_cast<CEikMenuPane*>( any )->iIsDeleted = NULL;
}
// end of file