diff -r 000000000000 -r 2f259fa3e83a uifw/EikStd/coctlsrc/EIKMENUP.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/EikStd/coctlsrc/EIKMENUP.CPP Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,7899 @@ +/* +* Copyright (c) 2002-2009 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // AKNLAF +#include +#include +#include +#include // Bidirectional support +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include //For transition effects +#include //For transition effects +#include // SetAllParents method +#include +#include +#include +#include + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST +#include // LISTBOX EFFECTS IMPLEMENTATION +#include +#include +#endif // RD_UI_TRANSITION_EFFECTS_LIST + +#include +#include +#include +#include +#include +#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 CActive, + public MCoeForegroundObserver, + public MAknsEffectAnimObserver, + public MCoeControlObserver, + public MAknPhysicsObserver + { +public: + enum TFlag + { + /** + * If set, animation creation is attempted. If not set, animation will + * never be created. + */ + EFlagUseAnimation = 0 + }; + + enum TScreen + { + EQhdHeight = 360, + EQhdWidth = 640 + }; + + CEikMenuPaneExtension(); + ~CEikMenuPaneExtension(); + + void ConstructL( CEikMenuPane* aControl ); + void CreateAnimation(); + void NoAnimIfError( TInt aError ); + void UseNoAnimation(); + void FocusGained(); + void FocusLost(); + + void HandleLayoutSwitch(); + void ChangeHighlightBackground(); + 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 ); + TRect GetBackgroundRect( const TRect& aWindowRect ) const; + static void AdjustPopupLayoutData( TAknWindowLineLayout& aListScrollPaneLayout ); + + const TAknLayoutText GetMenuItemTextLayout(const TRect& aItemRect, TBool cascade); + +public: // Implementation of MCoeForegroundObserver + void HandleGainingForeground(); + void HandleLosingForeground(); + +public: // Implementation of MAknsEffectAnimObserver + void AnimFrameReady( TInt aError, TInt ); + void HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType); + +protected: // CActive overloads + void DoCancel(); + void RunL(); + +private: // New internal methods + void Play(); + TBool DrawHighlightBackground( CFbsBitGc& aGc ); + void PostDeleteAnimation(); + void CreateAnimationL( const TSize& aHighlightSize ); + void DoResizeL( const TSize& aHighlightSize, TBool aAboutToStart ); +public: + void ImmediateFeedback( TTouchLogicalFeedback aType, + TTouchFeedbackType aFbType ); + +public: + void StartCascadeMenuAppearTransition(); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + void CalcItemSize( MAknListBoxTfxInternal* transApi ) const; +#endif + + /** + * Prepares cascade menu for item specific commands. + */ + void PrepareCascadeForItemCommands(); + + /** + * 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 + TBool iHasIcon; + TBool iIsPenEnable; + 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) + CCoeControl* iGrabbingCBAComponent; // component control of CBA which is currently grabbing the pointer + CEikMenuPane* iControl; + CAknsEffectAnim* iAnimation; + /** + * Stored flags are explained in enumeration TFlags. + */ + TBitFlags32 iAnimFlags; + + 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 iTransitionsOn; // Transitions FtMgr flag on + 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; + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + CWindowGc* iGc; +#endif + TInt iItemsThatFitInView; + TRect iScrollBarRect; + TRect iSctRect; + TInt iTotalNumberOfItemsInView; // this value includes partial items + + + CIdle* iTaskSwapIdle; + CRedirectionListener* iRedirectionListener; + TRect iSBRect; + 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, + EHighlightEnabled + }; + + /** + * Menu pane extension flags. + */ + TBitFlags iFlags; + +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; +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( iMenuPane.iExtension ) + { + iTopItemIndex = aIndex; + } +#endif + } + +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; + if ( !iControl->iOwner ) + { + rect = iMenuPaneRect; + } + else + { + rect = iControl->Rect(); + } + + 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; + if ( !iControl->iItemArray ) + { + return; + } + + iListTopIndex = aNewPosition.iY - iViewHeight / 2; + + iListBottomIndex = aNewPosition.iY + iViewHeight - iViewHeight / 2; + + TInt delta = iViewPosition.iY - aNewPosition.iY; + + DoOffset( delta ); + + iViewPosition = aNewPosition; + _AKNTRACE( "iListTopIndex = %d", iListTopIndex ); + _AKNTRACE( "iListBottomIndex = %d", iListBottomIndex ); + _AKNTRACE( "delta = %d", delta ); + _AKNTRACE( "iViewPosition(%d,%d)", iViewPosition.iX, iViewPosition.iY ); + + if ( aDrawNow ) + { + TRAP_IGNORE( iControl->DoUpdateScrollBarL() ); + + if ( iControl->iOwner ) // Submenu + { + iControl->DrawNow(); + } + else + { + iControl->DrawNow( TRect( iMenuPaneRect.Size() ) ); + } + } + _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 ) + { + TTouchFeedbackType feedbackType = ETouchFeedbackVibra; + switch( iPhysics->OngoingPhysicsAction() ) + { + case CAknPhysics::EAknPhysicsActionDragging: + { + feedbackType = static_cast ( ETouchFeedbackVibra | ETouchFeedbackAudio ); + } + case CAknPhysics::EAknPhysicsActionFlicking: + case CAknPhysics::EAknPhysicsActionBouncing: + { + ImmediateFeedback( ETouchFeedbackSensitiveList, + feedbackType ); + 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; +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfx* tfxApi = CAknListLoader::TfxApi( iGc ); + + if ( tfxApi ) + { + tfxApi->EnableEffects( ETrue ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + _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() : + CActive( EPriorityHigh ), + // 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 ), + iGrabbingCBAComponent( NULL ), + iControl( NULL ), + iAnimation( NULL ), + iAnimFlags ( 0 ), + iSct( NULL ), + iSctHighlighted( EFalse ), + iSpecialCharPointed( EFalse ) +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + ,iGc ( NULL ) +#endif // RD_UI_TRANSITION_EFFECTS_LIST + ,iVerticalOffset( 0 ) + ,iPhysics( NULL ) + ,iListTopIndex( 0 ) + ,iViewHeight( 0 ) + ,iFlickActive( EFalse ) + ,iPanningActive( EFalse ) + ,iFeedback( MTouchFeedback::Instance() ) + ,iLastFeedbackTopItemIndex( 0 ) + { + iIsPenEnable = AknLayoutUtils::PenEnabled(); + iItemsReadyForPenSelection = !iIsPenEnable; + iNextHighlightItem = KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::~CEikMenuPaneExtension +// Destructor for extension class +// ----------------------------------------------------------------------------- +// +CEikMenuPaneExtension::~CEikMenuPaneExtension() + { + _AKNTRACE_FUNC_ENTER; +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( CAknListLoader::TfxApiInternal( iGc ) ) + { + delete iGc; + } +#endif + Cancel(); // Cancel possibly pending request + + // Stop receiving foreground events + CCoeEnv* env = CCoeEnv::Static(); + env->RemoveForegroundObserver( *this ); + + 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 iAnimation; + iAnimation = 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; + iAnimFlags.Set( EFlagUseAnimation ); // Animations are created by default + CActiveScheduler::Add( this ); + 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 ); + } +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + iGc = CAknListLoader::CreateTfxGc( *aControl, + iControl->iScroller->iTopItemIndex, + iTotalNumberOfItemsInView ); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + if ( static_cast( + 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::CreateAnimation +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::CreateAnimation() + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + return; +#else + if( !iAnimation && iAnimFlags.IsSet( EFlagUseAnimation ) ) + { + TRect rect = iControl->HighlightRect(); + TRAPD( err, CreateAnimationL( rect.Size() ) ); + if( KErrNone != err ) + { + // Animation has not been drawn -> no need for repaint + UseNoAnimation(); + } + } +#endif //RD_UI_TRANSITION_EFFECTS_LIST + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::NoAnimIfError +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::NoAnimIfError( TInt aError ) + { + if( KErrNone != aError ) + UseNoAnimation(); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::UseNoAnimation +// Falls back to normal highlight rendering. +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::UseNoAnimation() + { + delete iAnimation; + iAnimation = NULL; + + // Do not attempt to create animations in the future + iAnimFlags.Clear( EFlagUseAnimation ); + + // Stop receiving foreground events + CCoeEnv* env = CCoeEnv::Static(); + env->RemoveForegroundObserver( *this ); + } + +// ----------------------------------------------------------------------------- +// 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 ( 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 ( 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 ) + { + iControl->CreateScrollBarFrame(); + } + 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->PositionRelativeToScreen(); + TPoint ownerPos = iControl->iOwner->PositionRelativeToScreen(); + aParentEvent.iPosition.SetXY ( + aPointerEvent.iPosition.iX + subPos.iX - ownerPos.iX, + aPointerEvent.iPosition.iY + subPos.iY - ownerPos.iY); + aParentEvent.iType = aPointerEvent.iType; + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::GetBackgroundRect +// Get background rect for landscape mode of menu pane. +// ----------------------------------------------------------------------------- +// +TRect CEikMenuPaneExtension::GetBackgroundRect( const TRect& aWindowRect ) const + { + return aWindowRect; + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::AdjustPopupLayoutData +// Adjust popup layout data for main menu pane in landscape mode +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::AdjustPopupLayoutData( TAknWindowLineLayout& aListScrollPaneLayout ) + { + TRect screenRect; + AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screenRect ); + AknLayoutUtils::TAknCbaLocation cbaPosition = AknLayoutUtils::CbaLocation(); + + if ( screenRect.Width() == EQhdWidth && screenRect.Height() == EQhdHeight + && cbaPosition == AknLayoutUtils::EAknCbaLocationBottom ) + { + if ( !AknLayoutUtils::LayoutMirrored() ) + { + aListScrollPaneLayout.ir -= 32; + } + else + { + aListScrollPaneLayout.il -= 32; + } + } + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::GetMenuItemTextLayout +// Get Layout of menu item text. +// ----------------------------------------------------------------------------- +// +const TAknLayoutText CEikMenuPaneExtension::GetMenuItemTextLayout(const TRect& aItemRect, TBool cascade) + { + TAknTextLineLayout menuTextLayout; + + if ( !iControl->iOwner ) + { + menuTextLayout = AknLayoutScalable_Avkon::list_single_pane_t1_cp2( cascade ? 3 : 0 ).LayoutLine(); + } + else + { + if ( iHasIcon ) + { + 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() ); + } + } + + TAknLayoutText textRect; + textRect.LayoutText( aItemRect, menuTextLayout ); + return textRect; + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::FocusGained +// The owning control has gained focus -> animation should be continued. +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::FocusGained() + { + Play(); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::FocusLost +// The owning control has lost focus -> no running animation (even if the +// control is partially visible). +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::FocusLost() + { + if( iAnimation ) + { + NoAnimIfError( iAnimation->Pause() ); + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::HandleLayoutSwitch +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::HandleLayoutSwitch() + { + if( iAnimation ) // Animation exists -> try to resize + { + TRect rect( iControl->HighlightRect() ); + + // Resize animation + TBool aboutToStart = ETrue; + if( iAnimation->State() == EAknsAnimStateStopped ) + aboutToStart = EFalse; + + TRAPD( err, DoResizeL( rect.Size(), aboutToStart ) ); + NoAnimIfError( err ); + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::ChangeHighlightBackground +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::ChangeHighlightBackground() + { + // Every time the current list item is changed we need to change the + // animation input layer (animated element is the highlight bacground that + // can differ between highlight positions). + if( iAnimation ) + { + if( iAnimation->State() == EAknsAnimStateStopped ) + { + // Input layers don't exist when stopped or finished. We need to + // resize to create the input layers and to update the output + // layer. + + TRAPD( err, DoResizeL( iAnimation->Size(), EFalse ) ); + NoAnimIfError( err ); + } + else // Either paused, running or finished + { + // Update the highlight background + if( iAnimation->InputRgbGc() ) + DrawHighlightBackground( *iAnimation->InputRgbGc() ); + + // We need to update the output frame (otherwise the highlight + // would drawn with the old output before the next new animation + // frame). + NoAnimIfError( iAnimation->UpdateOutput() ); + } + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::MenuClosed +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::MenuClosed() + { + _AKNTRACE_FUNC_ENTER; + delete iAnimation; + iAnimation = NULL; + + CCoeEnv* env = CCoeEnv::Static(); + env->RemoveForegroundObserver( *this ); + + iAnimFlags.Set( EFlagUseAnimation ); + + delete iSct; + iSct = NULL; + iSctHighlighted = EFalse; +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + iSctRect = TRect::EUninitialized; +#endif + + if ( iCba ) + { + iCba = NULL; + } + + if ( iRedirectionListener ) + { + iRedirectionListener->Closing(); + } + + iFlags.Clear( EHideItemSpecificCommands ); + iFlags.Clear( EContextSensitive ); + iFlags.Clear( EHighlightEnabled ); + _AKNTRACE_FUNC_EXIT; + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::HandleGainingForeground +// The application has gained foreground -> animation should be continued. +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::HandleGainingForeground() + { + // It is safe to start animation in this method because animation is + // deleted when the menu is closed -> it is not possible that menu receives + // foreground event while it is not visible and the animation exists. + + // We need to check if the menu has focus (to prevent running nonfocused + // animation because also the nonfocused menu (menu/submenu) receives + // foreground events) + Play(); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::HandleLosingForeground +// The application lost foreground -> no running animation (even if the +// application is partially visible). +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::HandleLosingForeground() + { + if( iAnimation ) + { + NoAnimIfError( iAnimation->Stop() ); + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::AnimFrameReady +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::AnimFrameReady( TInt aError, TInt ) + { + if( KErrNone != aError ) + { + // Animation has failed to run -> schedule the animation for + // deletion to fall back to normal rendering. + PostDeleteAnimation(); + } + else if( iControl ) // Frame ok + { + if ( iControl->IsVisible() ) + { + iControl->RepaintHighlight(); + } + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::DoCancel +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::DoCancel() + { + // Required method, but not needed + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::RunL +// Postponed animation deletion is done here +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::RunL() + { + UseNoAnimation(); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::Play +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::Play() + { + if( !iAnimation || !iControl->IsFocused() ) + { + return; + } + + // No need to start running/finished animation + if( EAknsAnimStateRunning == iAnimation->State() || + EAknsAnimStateFinished == iAnimation->State() ) + { + return; + } + + CAknAppUi* aui = static_cast(CEikonEnv::Static()->AppUi()); + if( !aui->IsForeground() ) + { + return; + } + + if( EAknsAnimStatePaused == iAnimation->State() ) + { + NoAnimIfError( iAnimation->Continue() ); + } + else if( EAknsAnimStateStopped == iAnimation->State() ) + { + if( iAnimation->NeedsInputLayer() ) + { + TRAPD( err, DoResizeL( iAnimation->Size(), ETrue ) ); + NoAnimIfError( err ); + + if( KErrNone != err ) + return; + } + + NoAnimIfError( iAnimation->Start() ); + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::DrawHighlightBackground +// Draws skinned highlight background to the provided graphics context. +// ----------------------------------------------------------------------------- +// +TBool CEikMenuPaneExtension::DrawHighlightBackground( CFbsBitGc& aGc ) + { + // Draw the background under the current highlight. This simplified + // drawing, we only grab a piece from the list background bitmap. + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + return AknsDrawUtils::DrawBackground( skin, iBgContext, iControl, aGc, TPoint(0,0), + iControl->HighlightRect(), + KAknsDrawParamRGBOnly ); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::PostDeleteAnimation +// Schedules the animation for deletion by activating the extension itself. +// Deletion is postponed because in many error/failure occasions the caller has +// been animation and direct deletion is possibly not safe (because function +// stack would return through the deleted object). +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::PostDeleteAnimation() + { + TRequestStatus* status = &iStatus; + User::RequestComplete( status, KErrNone ); + SetActive(); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::CreateAnimationL +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::CreateAnimationL( const TSize& aHighlightSize ) + { + // Create animation + CCoeEnv* env = CCoeEnv::Static(); + env->AddForegroundObserverL( *this ); + + delete iAnimation; + iAnimation = NULL; + + iAnimation = CAknsEffectAnim::NewL( this ); + TBool ok = iAnimation->ConstructFromSkinL( KAknsIIDQsnAnimList ); + + if( !ok ) // Animation for the ID was not found from the skin + { + User::Leave( KErrNotFound ); + } + + DoResizeL( aHighlightSize, ETrue ); + + Play(); + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::DoResizeL +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::DoResizeL( + const TSize& aHighlightSize, TBool aAboutToStart ) + { + iAnimation->BeginConfigInputLayersL( aHighlightSize, aAboutToStart ); + + if( iAnimation->InputRgbGc() ) + DrawHighlightBackground( *iAnimation->InputRgbGc() ); + + iAnimation->EndConfigInputLayersL(); + } + +// ----------------------------------------------------------------------------- +// 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 ); + if ( AknLayoutUtils::PenEnabled() ) + { + 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 ); + if ( AknLayoutUtils::PenEnabled() ) + { + iSct->SetGloballyCapturing( ETrue ); + iSct->SetPointerCapture( ETrue ); + } + } + } + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::HandleControlEventL +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::HandleControlEventL(CCoeControl* /*aControl*/,TCoeEvent aEventType) + { + _AKNTRACE_FUNC_ENTER; + if ( AknLayoutUtils::PenEnabled() ) + { + 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 ) + { + iFeedback->InstantFeedback( iControl, aType, aFbType, TPointerEvent() ); + } + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::PrepareCascadeForItemCommands +// ----------------------------------------------------------------------------- +// +void CEikMenuPaneExtension::PrepareCascadeForItemCommands() + { + 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->SetItemCommandsDimmed(); + } + } + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPaneExtension::ContextSensitiveMenu +// ----------------------------------------------------------------------------- +// +TBool CEikMenuPaneExtension::ContextSensitiveMenu() const + { + TBool isContextSensitive( EFalse ); + if ( !iControl->iOwner ) + { + CEikMenuBar* menuBar = static_cast( 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( 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(); + 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(); + + iExtension->iTransitionsOn = FeatureManager::FeatureSupported( KFeatureIdUiTransitionEffects ); + + CreateWindowL( iCoeEnv->RootWin() ); + EnableWindowTransparency(); + SetAllowStrayPointers(); + EnableDragEvents(); + + 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(); + } + + TRect windowRect = Rect(); + TAknLayoutRect menuLayoutRect; + menuLayoutRect.LayoutRect( windowRect, menuLineLayout ); + iItemHeight = menuLayoutRect.Rect().Height(); + + if ( iExtension->iSct ) + { + RWindow* window = (RWindow*)this->DrawableWindow(); + iExtension->iMenuPaneWindow = window; + iExtension->iSct->SetContainerWindowL( *this ); + + if ( AknLayoutUtils::PenEnabled() ) + { + // 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(); + + TAknWindowLineLayout menuLineLayout; + if ( iOwner ) // submenu + { + menuLineLayout = AKN_LAYOUT_WINDOW_list_single_popup_submenu_pane( 0, 0 ); + } + else + { + menuLineLayout = AKN_LAYOUT_WINDOW_list_single_popup_menu_pane( 0 ); + } + TRect windowRect = Rect(); + TAknLayoutRect menuLayoutRect; + menuLayoutRect.LayoutRect( windowRect, menuLineLayout ); + iItemHeight = menuLayoutRect.Rect().Height(); + + CheckCreateScrollerL(); + CheckCreateExtensionL(); + + const TInt count=aReader.ReadInt16(); + for ( TInt ii=0; iiiData.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 ); + } + + iCascadeMenuPane->iExtension->PrepareCascadeForItemCommands(); + iCascadeMenuPane->iExtension->EnableHighlight( EFalse ); + iCascadeMenuPane->FilterDimmedItems(); + + // cascade menu launch animation + if ( iExtension->iRedirectionListener ) + { + iExtension->iRedirectionListener->LaunchCascadeMenu(); + } + else + { + iExtension->StartCascadeMenuAppearTransition(); + } + + if( AknLayoutUtils::PenEnabled() ) + { + TTouchLogicalFeedback fbLogicalType = ETouchFeedbackPopUp; + if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) ) + { + fbLogicalType = ETouchFeedbackIncreasingPopUp; + } + 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->iSct ) + { + numItemsInPane++; + } + + TInt maxNumItemsInMenu = AknLayoutScalable_Avkon:: + list_single_pane_cp2_ParamLimits().LastRow() + 1; + TInt maxNumItemsInSubMenu = AknLayoutScalable_Avkon:: + list_single_popup_submenu_pane_ParamLimits().LastRow() + 1; + + 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 ); + iExtension->iHasIcon = MenuHasIcon(); + + if ( iExtension->iTransitionsOn ) + { + CAknTransitionUtils::SetAllParents( this ); + } + + 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(); + } + + TRect rect( CalculateSizeAndPosition() ); + TPoint newPos( rect.iTl ); + TSize menuSize( rect.Size() ); + + SetExtent( newPos, menuSize ); + + // 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() ); + + // The extent has been set. This is the first safe point in code to + // construct animations (because before this highlight related layout code + // will produce invalid results + if( iExtension ) + { + // Creates animation only if it does not exist + iExtension->CreateAnimation(); + } + + // 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; + + TRect backgroundRect( iExtension->GetBackgroundRect( aWindowRect ) ); + + 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( backgroundRect, SkinLayout::Popup_windows_skin_placing__frame_general__Line_2() ); + bottomRight.LayoutRect( backgroundRect, 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 ); + + ActivateGc(); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iExtension->iGc ); + if ( transApi ) + { + iExtension->iGc->Activate( *DrawableWindow() ); + } + CWindowGc& gc = transApi ? *iExtension->iGc : SystemGc(); +#else + CWindowGc& gc = SystemGc(); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + PrepareGcForDrawingItems( gc ); + + // Scrollers top item index must be updated first because setting selected + // item results in animation redraw (which requires knowledge about the + // current top item). + if ( aNewSelectedItem >= 0 ) + { + ScrollToMakeItemVisible( aNewSelectedItem ); + } + else + { + ScrollToMakeItemVisible( 0 ); + } + + 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 ); + } + SetSelectedItem( aNewSelectedItem ); + + PrepareHighlightFrame(); + + if ( previousTopItem == topItem && aNewSelectedItem >= 0 ) + { + // then only previuosly and currently selected items should be redrawn + DrawItem( gc, previousSelectedItem, ERemoveHighlight ); + + if ( !iExtension->iSctHighlighted ) + { + DrawItem( gc, aNewSelectedItem, EDrawHighlight ); + } + } + else + { + TBool skipHighlight = EFalse; + if (iExtension && iExtension->iSct && aNewSelectedItem == 0 && + previousSelectedItem > 1) + { + skipHighlight = ETrue; + } + for( TInt i = topItem; iiGc->Deactivate(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + DeactivateGc(); + + UpdateScrollBarThumbs(); + + // Updating view position here prevents some flickering + iExtension->ViewPositionChanged( iExtension->iViewPosition ); + + _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() + */ +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iExtension->iGc ); + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListNotSpecified ); + } +#endif + + aGc.SetPenColor(iEikonEnv->ControlColor( EColorMenuPaneText, *this) ); +#if defined(MENU_TEXTURED_BACKGROUND) + iEikonEnv->SetTexturedBrush( aGc ); +#else + aGc.SetBrushStyle( CGraphicsContext::ESolidBrush ); + aGc.SetBrushColor( iEikonEnv->ControlColor( EColorMenuPaneBackground,*this ) ); +#endif + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST +/** + * Iterate through the visible items in a menu and calculate minimum + * item margins that dont need drawing. + */ +void CEikMenuPaneExtension::CalcItemSize( MAknListBoxTfxInternal* transApi ) const + { + if ( transApi && iControl->iItemArray && iControl->iItemArray->Count() ) + { + TRect marginRect(TRect::EUninitialized); + const TInt index = 0; + + // Specifies whether the text should be moved to give some space for icon. + TInt hasIcon = iControl->MenuHasIcon() ? 1 : 0; + + TAknWindowLineLayout menuPane( AKN_LAYOUT_WINDOW_list_menu_pane( 0 , 0 ) ); + TAknWindowLineLayout singleMenuPane( + AKN_LAYOUT_WINDOW_list_single_popup_menu_pane( index ) ); + TAknTextLineLayout menuTextLayout( + AKN_LAYOUT_TEXT_List_pane_texts__menu_single__Line_1(0) ); + + TAknLayoutRect menuPaneRect; + TAknLayoutRect singleMenuPaneRect; + TAknLayoutText textRect; + + TBool hasCascade = EFalse; + TBool hasNonCascade = EFalse; + + // number of items in the whole menu + for(TInt i = 0; i < iControl->iItemArray->Count(); i++) + { + CEikMenuPaneItem* item = (*iControl->iItemArray)[i]; + + // true if a cascade symbol must be drawn (main menu only) + TBool cascade = item->iData.iCascadeId != 0; + + if ( cascade ) + { + if ( hasCascade ) + { + if ( hasNonCascade ) + { + break; + } + continue; + } + hasCascade = ETrue; + } + else + { + if ( hasNonCascade ) + { + if ( hasCascade ) + { + break; + } + continue; + } + hasNonCascade = ETrue; + } + + if ( !iControl->iOwner ) + { + TAknWindowLineLayout listScrollPaneLayout( + AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() ); + AdjustPopupLayoutData( listScrollPaneLayout ); + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( iControl->Rect(), listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_menu_pane( 0 ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + + singleMenuPane = AknLayoutScalable_Avkon::list_single_pane_cp2( index ).LayoutLine(); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), singleMenuPane ); + + menuTextLayout = AknLayoutScalable_Avkon::list_single_pane_t1_cp2( cascade ? 3 : 0 ).LayoutLine(); + } + else // Submenu + { + TBool hasDoubleSpanScrollBar = EFalse; + if ( iControl->iOwner && iControl->iSBFrame && + iControl->iSBFrame->VScrollBarVisibility() ) + { + hasDoubleSpanScrollBar = ETrue; + } + TAknWindowLineLayout listScrollPaneLayout( AknLayoutScalable_Avkon::listscroll_popup_sub_pane().LayoutLine() ); + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( iControl->Rect(), listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_submenu_pane( !hasDoubleSpanScrollBar ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + + singleMenuPane = AknLayoutScalable_Avkon::list_single_popup_submenu_pane( index ).LayoutLine(); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), singleMenuPane ); + + menuTextLayout = TAknTextLineLayout( AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1( hasIcon ).LayoutLine() ); + } + + textRect.LayoutText( singleMenuPaneRect.Rect(), menuTextLayout ); + if (marginRect == TRect::EUninitialized) + { + marginRect = textRect.TextRect(); + } + else + { + marginRect.BoundingRect(textRect.TextRect()); + } + + if ( cascade ) + { + TAknWindowLineLayout elementCascade( AknLayoutScalable_Avkon::list_single_pane_cp2_g3().LayoutLine()); + TAknLayoutRect cascadeRect; + cascadeRect.LayoutRect( singleMenuPaneRect.Rect(), elementCascade ); + marginRect.BoundingRect(cascadeRect.Rect()); + } + else + { + TAknLayoutRect activeApplicationsIconRect; + activeApplicationsIconRect.LayoutRect( singleMenuPaneRect.Rect(), + AknLayoutScalable_Avkon::list_single_pane_g1_cp2(0).LayoutLine() ); + marginRect.BoundingRect(activeApplicationsIconRect.Rect()); + } + } + + if ( hasIcon ) + { + TAknLayoutRect iconLayoutRect; + iconLayoutRect.LayoutRect( singleMenuPaneRect.Rect(), + AknLayoutScalable_Avkon::list_single_popup_submenu_pane_g1().LayoutLine() ); + marginRect.BoundingRect(iconLayoutRect.Rect()); + } + + //send margins to tfx + TPoint tl ( marginRect.iTl - menuPaneRect.Rect().iTl ); + transApi->SetPosition( MAknListBoxTfxInternal::EListTLMargin, tl ); + + TPoint br( singleMenuPaneRect.Rect().Size().AsPoint() - marginRect.iBr + menuPaneRect.Rect().iTl ); + transApi->SetPosition( MAknListBoxTfxInternal::EListBRMargin, br ); + } + } +#endif + + +// --------------------------------------------------------------------------- +// CEikMenuPane::DrawItem +// --------------------------------------------------------------------------- +// +void CEikMenuPane::DrawItem( TInt aItem, THighlightType aHighlight ) const + { + ActivateGc(); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = + CAknListLoader::TfxApiInternal( iExtension->iGc ); + + if ( transApi ) + { + iExtension->iGc->Activate( *DrawableWindow() ); + } + + CWindowGc& gc = transApi ? *iExtension->iGc : SystemGc(); +#else + CWindowGc& gc = SystemGc(); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + PrepareGcForDrawingItems( gc ); + DrawItem( gc, aItem, aHighlight ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + iExtension->iGc->Deactivate(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + 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; + } + + // seem to have window owning control in correct place + TRect windowRect = Rect(); + + if ( !iOwner ) + { + windowRect.iBr.iY -= ( iExtension->iCba->Rect().Height() ); + } + + 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 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 + } + + // Collect all of the information from the Layout DLL. Initialise these + // variables with DUMMY data. Then replace it with menu/submenu data. + TAknWindowLineLayout menuPane( AKN_LAYOUT_WINDOW_list_menu_pane( 0 , 0 ) ); + TAknWindowLineLayout singleMenuPane( + AKN_LAYOUT_WINDOW_list_single_popup_menu_pane( index ) ); + TAknTextLineLayout menuTextLayout( + AKN_LAYOUT_TEXT_List_pane_texts__menu_single__Line_1(0) ); + TAknLayoutRect menuPaneRect; + TAknLayoutRect singleMenuPaneRect; + + if ( !iOwner ) + { + TAknWindowLineLayout listScrollPaneLayout( + AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() ); + if ( iExtension ) + { + iExtension->AdjustPopupLayoutData( listScrollPaneLayout ); + } + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( windowRect, listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_menu_pane( 0 ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + + singleMenuPane = AknLayoutScalable_Avkon::list_single_pane_cp2( index ).LayoutLine(); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), singleMenuPane ); + + menuTextLayout = AknLayoutScalable_Avkon::list_single_pane_t1_cp2( cascade ? 3 : 0 ).LayoutLine(); + } + else // Submenu + { + TBool hasDoubleSpanScrollBar = EFalse; + if ( iSBFrame && iSBFrame->VScrollBarVisibility() ) + { + hasDoubleSpanScrollBar = ETrue; + } + + TAknWindowLineLayout listScrollPaneLayout( AknLayoutScalable_Avkon::listscroll_popup_sub_pane().LayoutLine() ); + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( windowRect, listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_submenu_pane( !hasDoubleSpanScrollBar ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + + singleMenuPane = AknLayoutScalable_Avkon::list_single_popup_submenu_pane( index ).LayoutLine(); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), singleMenuPane ); + + menuTextLayout = TAknTextLineLayout( AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1( 0 ).LayoutLine() ); + + if ( hasIcon ) + { + menuTextLayout = TAknTextLineLayout( AknLayoutScalable_Avkon::list_single_popup_submenu_pane_t1( 1 ).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 ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = + CAknListLoader::TfxApiInternal( &aGc ); + drawingInitiated = transApi && !transApi->EffectsDisabled(); +#else + drawingInitiated = EFalse; +#endif + } + + if ( !drawingInitiated ) + { + window.Invalidate( itemRect ); + window.BeginRedraw( itemRect ); + } + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + MAknsControlContext* cc = NULL; + if( iExtension ) + { + cc = iExtension->iBgContext; + } + TBool background( ETrue ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( &aGc ); + if ( transApi && !transApi->EffectsDisabled() ) + { + iExtension->iGc->Activate( *DrawableWindow() ); + } +#endif + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( !transApi || transApi->EffectsDisabled() ) + { +#endif + aGc.SetBrushStyle( CGraphicsContext::ESolidBrush ); + aGc.SetBrushColor( singleMenuPaneRect.Color() ); + + 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 ); + } +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + } +#endif + + if ( !iExtension->HighlightEnabled() ) + { + aHighlight = ENoHighlight; + } + + switch ( aHighlight ) + { + case EDrawHighlight : + { + if ( !iExtension->iSctHighlighted ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + // This will remove the old bitmap + transApi->Invalidate( MAknListBoxTfxInternal::EListHighlight ); + + transApi->BeginRedraw( MAknListBoxTfxInternal::EListHighlight, + itemRect ); + transApi->StartDrawing( MAknListBoxTfxInternal::EListHighlight ); + } +#endif + + // Partial items, so prevent drawing over the edge of menu pane +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( !transApi || ( transApi && transApi->EffectsDisabled() ) ) + { + aGc.SetClippingRect(menuPaneRect.Rect()); + } +#else + aGc.SetClippingRect(menuPaneRect.Rect()); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + TBool drawOk = EFalse; + if( iExtension->iAnimation ) // Draw animated highlight + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi && transApi->VerifyKml() == KErrNone ) + { + Extension()->UseNoAnimation(); + } + else + { +#endif + 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 ); + + drawOk = iExtension->iAnimation->Render( aGc, outerRect ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + } +#endif + } + + if( !drawOk ) + { + // Animated highlight was not available, use normal skinned + // rendering. + + // 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 ); + + drawOk = AknsDrawUtils::DrawFrame( skin, + aGc, + outerRect, + innerRect, + KAknsIIDQsnFrList, + KAknsIIDDefault ); + + } + + // Both animated highlight and normal highlight drawing have + // 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 ); + } + + aGc.CancelClippingRect(); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + transApi->EndRedraw( MAknListBoxTfxInternal::EListHighlight ); + } +#endif + } + break; + } + case ERemoveHighlight: + case ENoHighlight: + default: + break; + } +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->BeginRedraw( MAknListBoxTfxInternal::EListItem, itemRect, aItem ); + transApi->StartDrawing( MAknListBoxTfxInternal::EListItem ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + // Partial items, so prevent drawing over the edge of menu pane +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( !transApi || ( transApi && transApi->EffectsDisabled() ) ) + { + aGc.SetClippingRect(menuPaneRect.Rect()); + } +#else + aGc.SetClippingRect(menuPaneRect.Rect()); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + // 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( + skin->GetCachedItemData( KAknsIIDQgnIndiSubmenu, EAknsITMaskedBitmap ) ); + if( itemData ) + { + aGc.BitBltMasked( cascadeRect.Rect().iTl, itemData->Bitmap(), + cascadeRect.Rect().Size(), itemData->Mask(), ETrue ); + } + else + { + 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( + 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( + 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( iExtension->GetMenuItemTextLayout( itemRect, cascade ) ); + 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 ); + aGc.UseFont( textRect.Font() ); + + const CFont* font = textRect.Font(); + + //TBuf 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 ); + } + + if(iExtension->iIsPenEnable) + { + 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; + aGc.DiscardFont(); + } + + if ( !drawingInitiated ) + { + Window().EndRedraw(); + } + + aGc.CancelClippingRect(); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi && !transApi->EffectsDisabled() ) + { + transApi->StopDrawing(); + transApi->EndRedraw( MAknListBoxTfxInternal::EListItem, aItem ); + iExtension->iGc->Deactivate(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPane::Draw +// ----------------------------------------------------------------------------- +// +#ifdef RD_UI_TRANSITION_EFFECTS_LIST +EXPORT_C void CEikMenuPane::Draw( const TRect& aRect ) const + { + CWindowGc& gc = ( iExtension && iExtension->iGc ) ? + *iExtension->iGc : SystemGc(); + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( &gc ); + + if ( transApi ) + { + iExtension->iGc->Activate( *DrawableWindow() ); + + if ( !transApi->EffectsDisabled() ) + { + if ( iExtension->iScrollBarRect.iTl.iX <= aRect.iTl.iX && + iExtension->iScrollBarRect.iBr.iX >= aRect.iBr.iX ) + { + transApi->BeginRedraw( MAknListBoxTfxInternal::EListUpdateRect, aRect ); + iExtension->iGc->Deactivate(); + return; + } + + iExtension->CalcItemSize( transApi ); + } + } +#else +EXPORT_C void CEikMenuPane::Draw(const TRect& /*aRect*/) const + { +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + TRect windowRect( Rect() ); + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + MAknsControlContext* cc = NULL; + + if( iExtension ) + { + cc = iExtension->iBgContext; + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->SetListType( MAknListBoxTfxInternal::EListBoxTypeMenuPane ); + transApi->BeginRedraw( MAknListBoxTfxInternal::EListView, windowRect ); + } +#else + CWindowGc& gc = SystemGc(); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + PrepareGcForDrawingItems( gc ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListView ); + } +#endif + + if ( !IsCascadeMenuPane() ) + { + CFbsBitmap* cbaExtension = AknsUtils::GetCachedBitmap( skin, KAknsIIDQsnBgSlicePopup ); + if ( cbaExtension ) + { + TAknLayoutRect sliceRect; + sliceRect.LayoutRect( windowRect, SkinLayout::Popup_windows_skin_placing__background_slice__Line_2() ); + AknIconUtils::SetSize( cbaExtension, sliceRect.Rect().Size() ); + gc.BitBlt( TPoint( windowRect.iTl.iX, windowRect.iBr.iY-cbaExtension->SizeInPixels().iHeight ), cbaExtension ); + windowRect.iBr.iY -=2; // two used as margin when rect layouts were done + } + } + + TInt count=0; + if( iItemArray ) + { + count=iItemArray->Count(); + } + + // Give the topmost menu item's rect to SCT if needed. + if ( iExtension->iSct ) + { + TAknLayoutRect listScrollPaneRect; + TAknLayoutRect menuPaneRect; + TAknLayoutRect singleMenuPaneRect; + + TAknWindowLineLayout listScrollPaneLayout( + AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() ); + if ( iExtension ) + { + iExtension->AdjustPopupLayoutData( listScrollPaneLayout ); + } + listScrollPaneRect.LayoutRect( windowRect, listScrollPaneLayout ); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), + AknLayoutScalable_Avkon::list_menu_pane( 0 ).LayoutLine() ); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), + AknLayoutScalable_Avkon::list_single_pane_cp2( 0 ).LayoutLine() ); + // Give the rect of the first menu item to SCT. + iExtension->iSct->SetMenuSctRect( singleMenuPaneRect.Rect() ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if( transApi ) + { + iExtension->iSctRect = singleMenuPaneRect.Rect(); + TAknLayoutRect cellLayRect; + cellLayRect.LayoutRect( iExtension->iSctRect, + AknLayoutScalable_Avkon::cell_graphic_popup_pane( 0, 0, 0 ) ); + iExtension->iSctRect.iTl.iX -= 1; + iExtension->iSctRect.iTl.iY -= 1; + iExtension->iSctRect.iBr.iX += 3; + transApi->ResetNonDrawingRects(); + transApi->AddNonDrawingRect( iExtension->iScrollBarRect ); + transApi->AddNonDrawingRect( iExtension->iSctRect ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + } + + if ( iExtension->iSct ) + { + TRegionFix<4> region; + region.AddRect( Rect() ); + region.SubRect( iExtension->iSct->Rect() ); + gc.SetClippingRegion( region ); + } + + TRect backgroundRect( iOwner ? windowRect : iExtension->GetBackgroundRect( windowRect ) ); + + // The added flag removes the white bg for transparency + TBool frameDrawn = AknsDrawUtils::Background( + skin, cc, this, gc, backgroundRect, KAknsDrawParamNoClearUnderImage ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + iExtension->iFullRedraw = ETrue; + + for ( TInt ii=0;iiiSctHighlighted && ii == iSelectedItem ) + DrawItem( gc, ii, EDrawHighlight); + else + DrawItem( gc, ii, ENoHighlight); + } + + iExtension->iFullRedraw = EFalse; + + if ( iExtension->iSct ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListNotSpecified ); + } +#endif + gc.CancelClippingRegion(); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->EndViewRedraw( aRect ); + iExtension->iGc->Deactivate(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + } + + +// ----------------------------------------------------------------------------- +// 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 != EAknCmdTaskSwapper ) + { + _AKNTRACE( "commandId = %d", commandId ); + iMenuObserver->ProcessCommandL( commandId ); + } + 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( iExtension ) + { + if ( IsFocused() ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + // Focus must be handled here, otherwise it will come to late + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iExtension->iGc ); + + if ( transApi ) + { + transApi->HandleFocusChange( ETrue ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + iExtension->FocusGained(); + } + else // Not focused + { + iExtension->FocusLost(); + } + } + + 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; + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + CWindowGc& gc = iExtension->iGc ? *iExtension->iGc : SystemGc(); + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( &gc ); +#endif //RD_UI_TRANSITION_EFFECTS_LIST + + if(iExtension->iIsPenEnable) + { + _AKNTRACE( "[%s]", "iExtension->iIsPenEnable = TRUE" ); + // 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(); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + iExtension->iGc->Activate( *DrawableWindow() ); + } +#else + CWindowGc& gc = SystemGc(); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + 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 ); + } + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + iExtension->iGc->Deactivate(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + 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)" ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->SetMoveType( + MAknListBoxTfxInternal::EListMoveDown ); + } +#endif //RD_UI_TRANSITION_EFFECTS_LIST + 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)" ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->SetMoveType( + MAknListBoxTfxInternal::EListMoveUp ); + } +#endif //RD_UI_TRANSITION_EFFECTS_LIST + 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() ); + + if ( iExtension->iIsPenEnable ) + { + // 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(); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + + MAknListBoxTfxInternal *transApi = + CAknListLoader::TfxApiInternal( iExtension->iGc ); + if ( transApi ) + { + iExtension->iGc->Activate( *DrawableWindow() ); + } + CWindowGc& gc = transApi ? *iExtension->iGc : SystemGc(); + +#else + + CWindowGc& gc = SystemGc(); + +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + 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 ); + } + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + + if ( transApi ) + { + iExtension->iGc->Deactivate(); + } + +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + 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( Parent() ); + if( menubar->MenuPane() == this ) + { + TPointerEvent ptrEvent; + ptrEvent.iType = TPointerEvent::EButton1Up; + 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 ) + { + if( !AknLayoutUtils::PenEnabled() ) + { + return; + } + + _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( AknLayoutUtils::PenEnabled() ) + { + if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) ) + { + iExtension->ImmediateFeedback( ETouchFeedbackDecreasingPopUp ); + } + else + { + iExtension->ImmediateFeedback( ETouchFeedbackPopUp ); + } + } + iExtension->iShowCascadeTransition = ETrue; + CloseCascadeMenu(); + 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 ) + { + TAknLayoutRect menuPaneRect; + TAknWindowLineLayout menuPane; + + TAknWindowLineLayout listScrollPaneLayout( + AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() ); + if ( iExtension ) + { + iExtension->AdjustPopupLayoutData( listScrollPaneLayout ); + } + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( Rect(), listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_menu_pane( 0 ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + menuSctRect = menuPaneRect.Rect(); + } + 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->PositionRelativeToScreen(); + cascadeMenuRect = TRect(subPos-PositionRelativeToScreen(), 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(); + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( + iExtension->iGc ); + TBool effects = transApi && !transApi->EffectsDisabled(); +#endif + + switch (aPointerEvent.iType ) + { + case TPointerEvent::EButton1Up: + { + _AKNTRACE( "[%s]", "TPointerEvent::EButton1Up" ); + if ( !innerRect.Contains( aPointerEvent.iPosition ) ) + { + // remove highlight in case highlight is outside of menu pane + iExtension->EnableHighlight( EFalse ); + if ( iOwner ) + { + RepaintHighlight(); + } + } + 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->iDownOnMenuArea = EFalse; + + iExtension->iPanningActive = EFalse; + if ( !(iExtension->iSct && iExtension->iSct->Rect().Contains( iExtension->iStartPoint ) ) ) + { + TPoint drag = iExtension->iStartPoint - aPointerEvent.iPosition; + if ( iExtension->iPhysics->StartPhysics( + drag, iExtension->iStartTime ) ) + { + iExtension->iFlickActive = ETrue; + iExtension->ResetPressedHighlight(); + } + } + 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( AknLayoutUtils::PenEnabled() ) + { + if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) ) + { + iExtension->ImmediateFeedback( ETouchFeedbackDecreasingPopUp ); + } + else + { + iExtension->ImmediateFeedback( ETouchFeedbackPopUp ); + } + } + //Just close sub menu + iExtension->iShowCascadeTransition = ETrue; + CloseCascadeMenu(); + 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 ); + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( effects ) + { + transApi->SetMoveType( MAknListBoxTfxInternal::EListTap ); + } +#endif + 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; + } +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( effects ) + { + transApi->Draw( Rect() ); + } +#endif + // 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 + if ( iOwner ) + { + iExtension->CalculateParentEvent(aPointerEvent, parentEvent); + _AKNTRACE( "[%s]", "HandlePointerEventL return 12" ); + _AKNTRACE_FUNC_EXIT; + return iOwner->HandlePointerEventL( parentEvent ); + } + else + { + if ( iExtension->iIsPenEnable ) + { + // 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( AknLayoutUtils::PenEnabled() ) + { + if ( CAknTransitionUtils::TransitionsEnabled( AknTransEffect::EComponentTransitionsOff ) ) + { + iExtension->ImmediateFeedback( ETouchFeedbackDecreasingPopUp ); + } + else + { + iExtension->ImmediateFeedback( ETouchFeedbackPopUp ); + } + } + iExtension->iShowCascadeTransition = ETrue; + CloseCascadeMenu(); //Just close sub menu. + iExtension->EnableHighlight( EFalse ); + RepaintHighlight(); + IgnoreEventsUntilNextPointerUp(); + } + else + { + ReportCanceled(); //Close main menu. + } + } + } + + } + 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->iButtonDownItem = KErrNotFound; + iExtension->ResetPressedHighlight(); + iExtension->iNextHighlightItem = KErrNotFound; + iExtension->iPanningActive = ETrue; + iExtension->EnableHighlight( EFalse ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfx* tfxApi = CAknListLoader::TfxApi( iExtension->iGc ); + + if ( tfxApi ) + { + tfxApi->EnableEffects( EFalse ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + } + + if ( iExtension->iPanningActive ) + { + 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->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 ( AknLayoutUtils::PenEnabled() ) + { + if ( CAknTransitionUtils::TransitionsEnabled( + AknTransEffect::EComponentTransitionsOff ) ) + { + iExtension->ImmediateFeedback( + ETouchFeedbackDecreasingPopUp ); + } + else + { + iExtension->ImmediateFeedback( + ETouchFeedbackPopUp ); + } + } + iExtension->iShowCascadeTransition = ETrue; + CloseCascadeMenu(); + } + } + else + { + TInt oldSelected = iSelectedItem; + // update highlight to new item + if ( oldSelected != ii ) + { + iExtension->iPressedDown = EFalse; +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( effects + && !iExtension->iShowCascadeTransition ) + { + transApi->SetMoveType( + MAknListBoxTfxInternal::EListDrag ); + } +#endif + } + TRect screenRect( TPoint( KMinTInt, KMinTInt ), + TPoint( KMaxTInt, KMaxTInt ) ); + TRect repeatRect( screenRect.iTl.iX, item->iPos, + screenRect.iBr.iX, item->iPos + + iItemHeight ); + } + // 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; + + if( iExtension ) + iExtension->ChangeHighlightBackground(); + } + +// ----------------------------------------------------------------------------- +// 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; + if( !AknLayoutUtils::PenEnabled()) + { + return; + } + + _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 ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( + iExtension->iGc ); + TBool effects = transApi && !transApi->EffectsDisabled(); +#endif + + 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); + // if last item is not visible + if ( bottomItem < countOfItems) + { + // move menu to show one site down or then downmost items. + newTopItem = (bottomItem <= (countOfItems - itemsThatFitToView)) ? (topItem + itemsThatFitToView) : (countOfItems - itemsThatFitToView); + } + else + { + update = EFalse; + } + _AKNTRACE( "newTopItem = %d", newTopItem); + _AKNTRACE( "update = %d", update); + } + break; + + case EEikScrollThumbDragVert: + { + _AKNTRACE( "[%s]", "EEikScrollThumbDragVert"); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + + if ( effects ) + { + MAknListBoxTfx* tfxApi = CAknListLoader::TfxApi( iExtension->iGc ); + + if ( tfxApi ) + { + tfxApi->EnableEffects( EFalse ); + effects = EFalse; + } + } +#endif + // new thumb position + TInt thumb = aScrollBar->ThumbPosition(); + _AKNTRACE( "thumb = %d", thumb); + + // did dragging cause scrolling + if ( thumb != topItem ) + { + newTopItem = thumb; + } + else + { + update = EFalse; + } + _AKNTRACE( "newTopItem = %d", newTopItem); + _AKNTRACE( "update = %d", update); + } + break; + + case EEikScrollThumbReleaseVert: + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfx* tfxApi = CAknListLoader::TfxApi( iExtension->iGc ); + + if ( tfxApi ) + { + tfxApi->EnableEffects( ETrue ); + } +#endif + } + return; + + default: + update = EFalse; + break; + } + + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( effects ) + { + transApi->SetMoveType( newTopItem > topItem ? + MAknListBoxTfxInternal::EListScrollDown : + MAknListBoxTfxInternal::EListScrollUp ); + } +#endif + + + iExtension->iListTopIndex = aScrollBar->ThumbPosition(); + + iExtension->iViewPosition.iY = + iExtension->iListTopIndex + iExtension->iViewHeight / 2; + + iExtension->ViewPositionChanged( iExtension->iViewPosition ); + + } + _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 ( iOwner && ( iItemArray->Count() <= NumberOfItemsThatFitInView() ) ) + { + // submenu with less than 6 items + visibility = CEikScrollBarFrame::EOff; + } + TRAP_IGNORE( iSBFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, visibility /*CEikScrollBarFrame::EAuto*/ ) ); + + TRAP_IGNORE( iSBFrame->CreateDoubleSpanScrollBarsL( EFalse, EFalse, ETrue, EFalse ) ); + iSBFrame->DrawBackground( EFalse, EFalse ); + UpdateScrollBar(); + } + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPane::UpdateScrollBar +// ----------------------------------------------------------------------------- +// +void CEikMenuPane::UpdateScrollBar() + { + if ( !CheckCreateScroller() ) + 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 menuPaneRect; + if ( !iOwner ) + { + menuPaneRect = iExtension->iMenuPaneRect; + } + else + { + menuPaneRect = Rect(); + } + + TRect clientRect( menuPaneRect.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; + + // For main menupane scrollbar is always shown, for submenu only when needed + if ( !iOwner ) + { + iSBFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn ); + } + else + { + TInt maxItems = NumberOfItemsThatFitInView(); + TInt count = iItemArray->Count(); + iSBFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, + (count > maxItems) ? CEikScrollBarFrame::EOn : CEikScrollBarFrame::EOff ); + } + + TAknLayoutRect scrollLayoutRect; + if ( !iOwner ) + { + TAknWindowLineLayout listScrollPaneLayout( + AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() ); + if ( iExtension ) + { + iExtension->AdjustPopupLayoutData( listScrollPaneLayout ); + } + scrollLayoutRect.LayoutRect( clientRect, listScrollPaneLayout ); + scrollBarInclusiveRect = scrollLayoutRect.Rect(); + scrollBarClientRect = scrollBarInclusiveRect; + + AknLayoutUtils::LayoutVerticalScrollBar( iSBFrame, scrollBarClientRect, + AknLayoutScalable_Avkon::scroll_pane_cp25(0).LayoutLine() ); + } + else + { + 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() ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iExtension->iGc ); + if ( iSBFrame->VerticalScrollBar() && + iSBFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn ) + { + iExtension->iScrollBarRect = iSBFrame->VerticalScrollBar()->Rect(); + } + else + { + iExtension->iScrollBarRect = TRect::EUninitialized; + } + if ( transApi ) + { + transApi->ResetNonDrawingRects(); + transApi->AddNonDrawingRect( iExtension->iScrollBarRect ); + transApi->AddNonDrawingRect( iExtension->iSctRect ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + if ( iSBFrame->VerticalScrollBar() && + iSBFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn ) + { + iExtension->iSBRect = iSBFrame->VerticalScrollBar()->Rect(); + } + else + { + iExtension->iSBRect = TRect::EUninitialized; + } + _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 + { + 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 ); + + // Menu moved with keys, update panning/flicking data + iExtension->iListTopIndex = iScroller->TopItemIndex() * iItemHeight; + iExtension->iViewPosition.iY = + iExtension->iListTopIndex + iExtension->iViewHeight / 2; + + iExtension->SetOffset( 0 ); + + _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; + } +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + 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 --; + } + + if ( iExtension->iPhysics && iExtension->Offset() != 0 ) + { + // with kinetic scrolling there can be partial items on the screen + iExtension->iTotalNumberOfItemsInView = iExtension->iItemsThatFitInView + 1; + } + + return iExtension->iItemsThatFitInView; +#else + return iOwner ? AknLayoutScalable_Avkon:: + list_single_popup_submenu_pane_ParamLimits().LastRow() + 1 : + AknLayoutScalable_Avkon:: + list_single_pane_cp2_ParamLimits().LastRow() + 1 - subst; +#endif + } + +// ----------------------------------------------------------------------------- +// 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& 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() ); + + TRAP_IGNORE( DoUpdateScrollBarL() ); + + UpdateBackgroundContext( Rect() ); + PrepareHighlightFrame(); + SetCascadedIconSize(); + + // Background under highlight may have changed -> we need to update + // highlight background to animation + if( iExtension ) + { + iExtension->HandleLayoutSwitch(); + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iExtension->iGc ); + if ( transApi ) + { + transApi->Remove( MAknListBoxTfxInternal:: EListEverything ); + } +#endif + + //Initialize physics engine + if ( iExtension->iPhysics ) + { + TRAP_IGNORE ( iExtension->InitPhysicsL() ); + iExtension->iListTopIndex = iScroller->TopItemIndex() * iItemHeight; + iExtension->iViewPosition.iY = + iExtension->iListTopIndex + iExtension->iViewHeight / 2; + iExtension->ViewPositionChanged( iExtension->iViewPosition ); + } + + 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. + 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 ( 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(); + TBool hasDoubleSpanScrollBar = EFalse; + + if ( iSBFrame && iSBFrame->VScrollBarVisibility() ) + { + _AKNTRACE( "[%s]", "hasDoubleSpanScrollBar = ETrue;" ); + hasDoubleSpanScrollBar = ETrue; + } + + 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 we have landscape layout then main menu should be positioned vertically centered + TRect appRect( iEikonEnv->EikAppUi()->ApplicationRect() ); + + 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. + TRect backgroundRect( iExtension->GetBackgroundRect( parentMenuRect ) ); + TPoint backgroundRectPos( + AknPopupUtils::Position( backgroundRect.Size(), ETrue ) ); + + retVal = parentMenuRect; + retVal.Move( backgroundRectPos - backgroundRect.iTl ); + + // Set embedded cba rect + if ( iExtension->iCba ) + { + // There is hidden extra touch space for scroll bar in landscape + TInt xOffset = backgroundRect.iTl.iX - parentMenuRect.iTl.iX ; + iExtension->iCba->SetRect( TRect( + xOffset, + menuRect.Height(), + backgroundRect.Width() + xOffset, + menuRect.Height() + cbaRect.Rect().Height() ) ); + } + + iExtension->iMenuPaneRect = TRect( retVal.iTl, + TSize ( menuRect.Size() ) ); + + _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 + TAknLayoutRect parentPaneLayoutRect; // list_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() ); + if ( iExtension ) + { + iExtension->AdjustPopupLayoutData( parentListScrollPaneLayout ); + } + parentListScrollLayoutRect.LayoutRect( parentMenuRect, parentListScrollPaneLayout ); + parentPaneLayoutRect.LayoutRect( parentListScrollLayoutRect.Rect(), + AknLayoutScalable_Avkon::list_menu_pane(0).LayoutLine() ); + 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 + 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( !hasDoubleSpanScrollBar ).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() ); + + TInt index = iOwner->SelectedItem() - iOwner->iScroller->TopItemIndex(); + TInt rows = AknLayoutScalable_Avkon::list_single_pane_cp2_ParamLimits().LastRow(); + + // This condition may be true if less items fits to menu view than sub-menu view + // and sub-menu under sub-menu is launched. + if (index > rows) + { + // Change the out-of-boundary index to last legal one. + index = rows; + } + + TAknLayoutRect parentSelectedItemRect; + parentSelectedItemRect.LayoutRect( parentPaneLayoutRect.Rect(), + AknLayoutScalable_Avkon::list_single_pane_cp2( index ).LayoutLine() ); + + 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.Rect().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.Rect().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 ); + } + } + _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; + + // It is possible that this method is called when iItemArray is NULL. In + // that case we fake numItems as 1 to make layout code work. + TInt maxItems = NumberOfItemsThatFitInView(); + TInt numItems = Min( Max( 1, iItemArray->Count() ), maxItems ); + if( !iItemArray ) + numItems = 1; + + // 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 == maxItems ) + { + index--; + } + + TRect windowRect = Rect(); + + TAknWindowLineLayout menuPane( AKN_LAYOUT_WINDOW_list_menu_pane( 0 , 0 ) ); + TAknWindowLineLayout singleMenuPane( AKN_LAYOUT_WINDOW_list_single_popup_menu_pane( index ) ); + TAknLayoutRect menuPaneRect; + TAknLayoutRect singleMenuPaneRect; + + TBool hasDoubleSpanScrollBar = EFalse; + + if ( iSBFrame && iSBFrame->VScrollBarVisibility() ) + { + hasDoubleSpanScrollBar = ETrue; + } + + if ( !iOwner ) + { + TAknWindowLineLayout listScrollPaneLayout( + AknLayoutScalable_Avkon::listscroll_menu_pane(0).LayoutLine() ); + if ( iExtension ) + { + iExtension->AdjustPopupLayoutData( listScrollPaneLayout ); + } + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( windowRect, listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_menu_pane( 0 ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + + singleMenuPane = AknLayoutScalable_Avkon::list_single_pane_cp2( index ).LayoutLine(); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), singleMenuPane ); + } + else // Submenu + { + TAknWindowLineLayout listScrollPaneLayout( AknLayoutScalable_Avkon::listscroll_popup_sub_pane().LayoutLine() ); + TAknLayoutRect listScrollPaneRect; + listScrollPaneRect.LayoutRect( windowRect, listScrollPaneLayout ); + + menuPane = AknLayoutScalable_Avkon::list_submenu_pane( !hasDoubleSpanScrollBar ).LayoutLine(); + menuPaneRect.LayoutRect( listScrollPaneRect.Rect(), menuPane ); + + singleMenuPane = AknLayoutScalable_Avkon::list_single_popup_submenu_pane( index ).LayoutLine(); + singleMenuPaneRect.LayoutRect( menuPaneRect.Rect(), singleMenuPane ); + } + + // Compared to normal DrawItem the highlight rect step is omitted because + // it would shift the highlight towards left. + + return singleMenuPaneRect.Rect(); + } + + +// ----------------------------------------------------------------------------- +// 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( + 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() && + !( iSBFrame->VerticalScrollBar()->OwnsWindow() ) ) + { + 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() && + !( iSBFrame->VerticalScrollBar()->OwnsWindow() ) ) + { + 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; + } + + +void CEikMenuPane::CheckCreateExtensionL() + { + if ( !iExtension ) + { + iExtension = new (ELeave) CEikMenuPaneExtension; + iExtension->ConstructL( this ); + } + } + + +// ----------------------------------------------------------------------------- +// 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->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; +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iExtension->iGc ); + if ( transApi && okToDraw ) + { + iCascadeMenuPane->SetFocus( EFalse, EDrawNow ); + } +#endif + // 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::SetItemCommandsDimmed +// ----------------------------------------------------------------------------- +// +void CEikMenuPane::SetItemCommandsDimmed() + { + if ( iExtension && iExtension->iFlags.IsSet( + CEikMenuPaneExtension::ESingleClickEnabled ) ) + { + iExtension->iFlags.Set( + CEikMenuPaneExtension::EHideItemSpecificCommands ); + for ( TInt i = 0; i < iItemArray->Count(); ++i ) + { + CEikMenuPaneItem* item = iItemArray->At( i ); + if ( item->iData.iFlags & EEikMenuItemAction + || item->iData.iFlags & EEikMenuItemSpecific + || item->iData.iFlags & EEikMenuItemSpecificListQuery ) + { + 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 ) + { + AddCascadeMenuItemsToActionMenuL( + item->iData.iCascadeId, EFalse, 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 ) ) + { + AddCascadeMenuItemsToActionMenuL( + item->iData.iCascadeId, ETrue, aMenuData ); + } + } + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPane::AddCascadeMenuItemsToActionMenuL +// ----------------------------------------------------------------------------- +// +void CEikMenuPane::AddCascadeMenuItemsToActionMenuL( + TInt aCascadeId, + TBool aItemSpecific, + CAknItemActionMenuData& aMenuData ) + { + 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 ) ) ) + { + aMenuData.AddMenuItemToDataArrayL( + item->iData.iCommandId, + item->iData.iCascadeId, + item->iData.iText ); + } + } + CleanupStack::PopAndDestroy( cascadeMenu ); + } + } + + +// ----------------------------------------------------------------------------- +// CEikMenuPane::SetDefaultHighlight +// ----------------------------------------------------------------------------- +// +void CEikMenuPane::SetDefaultHighlight() + { + if ( iExtension ) + { + iExtension->SetDefaultHighlight(); + } + } + +// end of file +