// EIKMENUB.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikmenub.h>
#include <eikmenup.h>
#include <eikmobs.h>
#include <eikhkeyt.h>
#include <eikcmds.hrh>
#include <barsread.h>
#include <eikenv.h>
#include <eikcmobs.h>
#include <eikpanic.h>
#include <coeutils.h>
#include <eikdutil.h>
#include <eikkeys.h>

#include <eikcolor.h>
#include <eikon.rsg>

enum { EEikMenuBarTitleArrayGranularity=10 };
enum { EEikMenuBarPosArrayGranularity=2 };
const TInt KExtraBaselineOffsetForFirstPaneItem=4;


EXPORT_C CEikMenuBar::CTitleArray::~CTitleArray()
	{}

EXPORT_C CEikMenuBar::CTitleArray::CTitleArray()
	: CArrayVarFlat<TTitle>(EEikMenuBarTitleArrayGranularity)
	{
	__DECLARE_NAME(_S("CEikMenuBar::CTitleArray"));
	}

EXPORT_C void CEikMenuBar::CTitleArray::AddTitleL(TTitle& aMenuTitle)
	{
	TInt titleLength=sizeof(TTitle)-(TTitle::SData::ENominalTextLength-aMenuTitle.iData.iText.Length())*sizeof(TText);
	AppendL(aMenuTitle,titleLength);
	}

//
// class CEikMenuBar
//

const TInt KEikMenuBarHBorder=8;
const TInt KEikMenuBarVBorder=2;
const TInt KEikMenuMnenPad=3;
const TInt KEikMaxMenuTitlePadding=10;
const TInt KEikNumOfSideButtons=5;
const TInt KEikSidebarPopupXPos=5;
const TInt KMenuPaneOverlap=1;

const TInt KMenuTitleLeftSpace = 12;
const TInt KMenuTitleRightSpace = 12;
const TInt KMenuTitleLeftSmallSpace = 2;
const TInt KMenuTitleRightSmallSpace = 2;

inline TBool CEikMenuBar::MenuHasItems()
	{
	return iMenuFlags&EMenuHasItems;
	}

inline void CEikMenuBar::SetMenuHasItems()
	{
	iMenuFlags|=EMenuHasItems;
	}

inline TBool CEikMenuBar::MenuHasPane()
	{
	return iMenuFlags&EMenuHasPane;
	}

inline void CEikMenuBar::SetMenuHasPane()
	{
	iMenuFlags|=EMenuHasPane;
	}

inline TBool CEikMenuBar::TitleArrayOwnedExternally()
	{
	return iMenuFlags&ETitleArrayOwnedExternally;
	}

EXPORT_C CEikMenuBar::~CEikMenuBar()
	{
	delete iMenuPaneTitle;
	delete iPastMenuPosArray;
	delete iHotKeyTable;
	delete iMenuPane;
	if (!TitleArrayOwnedExternally())
		delete iTitleArray;
	}

EXPORT_C CEikMenuBar::CEikMenuBar()
	: iSelectedTitle(ENothingSelected)
	{
	__DECLARE_NAME(_S("CEikMenuBar"));
	iBorder=TEikBorder(TEikBorder::EThickDeepRaisedWithOutline);
	}

EXPORT_C void CEikMenuBar::ConstructL(MEikMenuObserver* aMenuObserver,TInt aHotKeyResourceId,TInt aMenuTitleResourceId)
	{
	iMenuObserver=aMenuObserver;
	iMenuHotKeyResourceId=aHotKeyResourceId;
	iMenuTitleResourceId=aMenuTitleResourceId;
	iBaseLine=iEikonEnv->NormalFont()->AscentInPixels()+KExtraBaselineOffsetForFirstPaneItem;
	iPastMenuPosArray=new(ELeave) CArrayFixFlat<SPosition>(EEikMenuBarPosArrayGranularity);
	iTitleArray=new(ELeave) CTitleArray;
	iMenuPaneTitle=new(ELeave) CEikMenuPaneTitle(this);
	iMenuPane=new(ELeave) CEikMenuPane(iMenuObserver);
	MakeVisible(EFalse);

	if (aHotKeyResourceId==NULL)
		return;
	iHotKeyTable=new(ELeave) CEikHotKeyTable;
	iHotKeyTable->ConstructFromResourceL(aHotKeyResourceId);
	}

EXPORT_C void CEikMenuBar::ConstructFromResourceL(TResourceReader& aReader)
	{
	SetMenuHasItems();
	TInt count=aReader.ReadInt16();
	while (count--)
		{
		TTitle title;
		title.iData.iMenuPaneResourceId=aReader.ReadInt32();
		const TPtrC ptr=aReader.ReadTPtrC();
		title.iData.iText=ptr;
		iTitleArray->AddTitleL(title);
		}
	}

EXPORT_C void CEikMenuBar::FindCommandIdInResourceL(TInt aCommandId,TInt& aPaneindex,TInt& aItemindex)
	{
	aPaneindex=-1;
	aItemindex=-1;
	TResourceReader reader;
	CEikMenuPane::TItem item;
	TInt panes=iTitleArray->Count();
	for (TInt pindex=0;pindex<panes;++pindex)
		{
		TTitle& title=(*iTitleArray)[pindex];
		ControlEnv()->CreateResourceReaderLC(reader,title.iData.iMenuPaneResourceId);
		const TInt count=reader.ReadInt16();
		for (TInt iindex=0;iindex<count;++iindex)
			{
			item.iData.iCommandId=reader.ReadInt32();
			item.iData.iCascadeId=reader.ReadInt32();
			item.iData.iFlags=reader.ReadInt32();
			reader.ReadTPtrC();
			reader.ReadTPtrC();
			if (item.iData.iCommandId==aCommandId)
				{
				aItemindex=iindex;
				break;
				}
			}
		if (aItemindex>=0)
			{
			aPaneindex=pindex;
			CleanupStack::PopAndDestroy();
			return;
			}
		CleanupStack::PopAndDestroy();
		}
	}


EXPORT_C void CEikMenuBar::ChangeMenuBarL(TInt aHotKeyResourceId,TInt aMenuTitleResourceId,TBool aDisplayNow)
	{
	SaveCurrentMenuPositionL();
	StopDisplayingMenuBar();
	if (aHotKeyResourceId && aHotKeyResourceId!=iMenuHotKeyResourceId)
		{
		CEikHotKeyTable* hotKeyTable=new(ELeave) CEikHotKeyTable;
		CleanupStack::PushL(hotKeyTable);
		hotKeyTable->ConstructFromResourceL(aHotKeyResourceId);
		CleanupStack::Pop();	// hotKeyTable
		delete iHotKeyTable;
		iHotKeyTable=hotKeyTable;
		iMenuHotKeyResourceId=aHotKeyResourceId;
		}
	iMenuTitleResourceId=aMenuTitleResourceId;
	SetCursorPositionFromArray();
	if (aDisplayNow)
		{
		StartDisplayingMenuBarL();
		if (iCursor.iMenuItemIndex==ENothingSelected)
				iCursor.iMenuItemIndex=0;
		MoveHighlightToL(iCursor.iMenuPaneIndex,iCursor.iMenuItemIndex);
		}
	}

void CEikMenuBar::SaveCurrentMenuPositionL()
//Save position on current menu
//See if current menu is already on past menu array.
//If it is, just change the cursor value, if it is not
//add a new element to the array.
	{
	const TInt count=iPastMenuPosArray?iPastMenuPosArray->Count():0;
	for (TInt ii=0;ii<count;++ii)
		{
		if ((*iPastMenuPosArray)[ii].iMenuId==iMenuTitleResourceId)
			{
			(*iPastMenuPosArray)[ii].iMenuCursorPos=iCursor;
			return;
			}
		}
	SPosition menuPos;
	menuPos.iMenuId=iMenuTitleResourceId;
	menuPos.iMenuCursorPos=iCursor;
	iPastMenuPosArray->AppendL(&menuPos,sizeof(menuPos));
	}

void CEikMenuBar::SetCursorPositionFromArray()
//Set cursor position
//Check position array to see if menu previously displayed and use that last position.
	{
	const TInt count=iPastMenuPosArray?iPastMenuPosArray->Count():0;
	for (TInt ii=0;ii<count;++ii)//Use same count as above cos we wont be interested in menu we have just added to the list
		{
		if ((*iPastMenuPosArray)[ii].iMenuId==iMenuTitleResourceId)
			{
			iCursor=(*iPastMenuPosArray)[ii].iMenuCursorPos;
			return;
			}
		}
	iCursor.iMenuPaneIndex=0;	
	iCursor.iMenuItemIndex=0;
	}

EXPORT_C CEikHotKeyTable* CEikMenuBar::SetHotKeyTable(CEikHotKeyTable* aHotKeyTable)
	{
	CEikHotKeyTable* ret=iHotKeyTable;
	delete iHotKeyTable;
	iHotKeyTable=aHotKeyTable;
	return ret;
	}

EXPORT_C void CEikMenuBar::SetMenuTitleResourceId(TInt aMenuTitleResourceId)
	{
	SetCursorPositionFromArray();  // defaults set here if this menu not previously displayed
	if (iMenuPane)
		iMenuPane->SetSelectedItem(0); 
	iSelectedTitle=ENothingSelected;
	iMenuTitleResourceId=aMenuTitleResourceId;
	}

EXPORT_C void CEikMenuBar::SetMenuTitleArray(CTitleArray* aTitleArray)
	{
	if (!TitleArrayOwnedExternally())
		delete iTitleArray;
	iTitleArray=aTitleArray;
	SetMenuHasItems();
	}

EXPORT_C void CEikMenuBar::SetTitleArrayOwnedExternally(TBool aOwnedExternally)
	{
	if (aOwnedExternally)
		iMenuFlags|=ETitleArrayOwnedExternally;
	else
		iMenuFlags&=~ETitleArrayOwnedExternally;
	}

EXPORT_C TKeyResponse CEikMenuBar::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	const TInt code=aKeyEvent.iCode;
	const TInt modifiers=(aKeyEvent.iModifiers)&(EModifierCtrl|EModifierShift|EModifierPureKeycode);
	
	if (aType==EEventKeyDown || aType==EEventKeyUp)
		return MenuHasItems()? EKeyWasConsumed: EKeyWasNotConsumed;
	const TInt mod=aKeyEvent.iModifiers;
	if (iHotKeyTable && !((mod&EModifierPureKeycode && mod&EModifierCtrl) || mod&EModifierFunc))
		{
		const TInt command=iHotKeyTable->CommandIdFromHotKey(code,modifiers);
		if (command)
			{
			if (iMenuObserver->CheckHotKeyNotDimmedL(command))
				iMenuObserver->ProcessCommandL(command);
			else
				iMenuObserver->HandleAttemptDimmedSelectionL(command);
			return EKeyWasConsumed;
			}
		}
	switch (code)
		{
	case EEikSidebarZoomOutKey:
		iMenuObserver->ProcessCommandL(EEikCmdZoomOut);
		return EKeyWasConsumed;
	case EEikSidebarZoomInKey:
		iMenuObserver->ProcessCommandL(EEikCmdZoomIn);
		return EKeyWasConsumed;
	case EEikSidebarClipKey:
	case EEikSidebarIrdaKey:
		{
		TInt region=1;
		TInt menuId=R_EIK_SIDEBAR_EDIT_MENU;
		if (code==EEikSidebarIrdaKey)
			{
			region=2;
			menuId=R_EIK_SIDEBAR_IRDA_MENU;
			}
		TSize screenSize=iCoeEnv->ScreenDevice()->SizeInPixels();
		TInt sidebarSectorLength=screenSize.iHeight/KEikNumOfSideButtons;
		iMenuObserver->HandleSideBarMenuL(menuId,TPoint(KEikSidebarPopupXPos,region*sidebarSectorLength),modifiers,iHotKeyTable);
		return EKeyWasConsumed;
		}
	case EEikSidebarMenuKey:
	case EKeyMenu:
		if (MenuHasPane())
			{
			iMenuObserver->ProcessCommandL(EEikCmdCanceled);
			return EKeyWasConsumed;
			}
		if (modifiers)
			return EKeyWasNotConsumed;
		if (!iMenuTitleResourceId)
			return EKeyWasNotConsumed;
		TryDisplayMenuBarL();
		if (!MenuHasPane())
			{
				{
				if (iCursor.iMenuItemIndex==ENothingSelected)
						iCursor.iMenuItemIndex=0;
				MoveHighlightToL(iCursor.iMenuPaneIndex,iCursor.iMenuItemIndex);
				}
			return EKeyWasConsumed;
			}
		if (MenuHasPane()&&(code==EKeyMenu || code==EEikSidebarMenuKey))
			{
			// if pane already displaying - alt moves to next pane, shift+alt to previous
			const TInt max=iTitleArray->Count()-1;
			TInt newSelectedTitle;
			if (modifiers&EModifierShift)
				newSelectedTitle= ((iSelectedTitle-1)<0? max : iSelectedTitle-1);
			else 
				newSelectedTitle= ((iSelectedTitle+1)>max? 0 : iSelectedTitle+1);
			MoveHighlightToL(newSelectedTitle);
			return EKeyWasConsumed;
			}
		}
	if (!MenuHasItems())  // menu bar not currently displayed
		return EKeyWasNotConsumed;
	if (!MenuHasPane())
		{
		if (code==EKeyEscape)
			iMenuObserver->ProcessCommandL(EEikCmdCanceled);
		else if (code || aType==EEventKeyUp)
			{
			if (iCursor.iMenuItemIndex==ENothingSelected)
					iCursor.iMenuItemIndex=0;
			MoveHighlightToL(iCursor.iMenuPaneIndex,iCursor.iMenuItemIndex);
			}
		return EKeyWasConsumed;
		}
	TKeyResponse keyResponse=iMenuPane->OfferKeyEventL(aKeyEvent,aType,EFalse);
	if (keyResponse==EKeyWasNotConsumed)
		keyResponse=TryNavigateAlongMenuBarL(code);
	// When displaying, the menu bar must comsume all keys, even those it doesn't use.
	// So use callback here to see if app wants key.
	if (keyResponse==EKeyWasNotConsumed)
		iMenuObserver->OfferKeyToAppL(aKeyEvent, aType);
	return EKeyWasConsumed;
	}

LOCAL_C void CleanupMenu(TAny* aPtr)
	{
	((CEikMenuBar*)aPtr)->StopDisplayingMenuBar();
	}

EXPORT_C TInt CEikMenuBar::SelectedTitle()
	{
	return iCursor.iMenuPaneIndex;		
	}

EXPORT_C TInt CEikMenuBar::SelectedItem()
	{
	return iCursor.iMenuItemIndex;	
	}

EXPORT_C void CEikMenuBar::TryDisplayMenuBarL()
	{
	if (MenuHasItems())
		return; // menu already being displayed
	CleanupStack::PushL(TCleanupItem(CleanupMenu,this));
	StartDisplayingMenuBarL();
	CleanupStack::Pop();
	}

TKeyResponse CEikMenuBar::TryNavigateAlongMenuBarL(TInt aKeyCode)
	{
	TKeyResponse keyresponse=EKeyWasNotConsumed;
	const TInt max=iTitleArray->Count()-1;
	TInt newHighlight=iSelectedTitle;
	switch (aKeyCode)
		{
	case EKeyLeftArrow:
		if (--newHighlight<0)
			newHighlight=max;
		keyresponse=EKeyWasConsumed;
		break;
	case EKeyRightArrow:
		if (++newHighlight>max)
			newHighlight=0;
		keyresponse=EKeyWasConsumed;
		break;
	case EKeyHome:
		newHighlight=0;
		keyresponse=EKeyWasConsumed;
		break;
	case EKeyEnd:
		newHighlight=max;
		keyresponse=EKeyWasConsumed;
		break;
		}
	if (newHighlight==iSelectedTitle) // none of above, now test for digits
		{
		const TChar achar=aKeyCode; 
		
		if (achar.IsDigit())
			{
			TInt digit=achar - '0';
			if (digit==0)
				newHighlight=0;
			else if (digit<=(max+1))
				newHighlight= digit-1;
			else
				newHighlight= max;
			keyresponse=EKeyWasConsumed;
			}
		}
	MoveHighlightToL(newHighlight);
	return keyresponse;
	}

void CEikMenuBar::HideMenuPane()
	{
	if (MenuHasPane())
		{
		iCursor.iMenuPaneIndex=iSelectedTitle; // !! check this can never be -1
		iCursor.iMenuItemIndex=iMenuPane->SelectedItem();
		iMenuPane->CloseCascadeMenu();
		iMenuFlags&=~EMenuHasPane;
		iMenuPane->Reset();
		iMenuPane->MakeVisible(EFalse);
		}
	iSelectedTitle=ENothingSelected;
	}

inline void CEikMenuBar::HideMenuPaneTitle()
	{
	iMenuPaneTitle->MakeVisible(EFalse);
	}

EXPORT_C void CEikMenuBar::MoveHighlightToL(TInt aNewSelectedTitle,TInt aNewSelectedItem)
	{
	if (aNewSelectedTitle==iSelectedTitle)
		return;
	const TInt max=iTitleArray->Count()-1;
	aNewSelectedTitle=(aNewSelectedTitle>max)?max:aNewSelectedTitle;
	
	// OOM during construction can mean that max is -1 
	if(aNewSelectedTitle<0)
		User::Leave(KErrNoMemory);
	//
	
	TBool redrawNeeded = EFalse;
	TRect oldHighlightRect;
	TInt oldSelectedTitle=iSelectedTitle;
	if (MenuHasPane())
		{
		redrawNeeded = ETrue;
		oldHighlightRect=iMenuPaneTitle->Rect();
		}

	HideMenuPane();
	HideMenuPaneTitle();

		
	const TTitle& title=(*iTitleArray)[aNewSelectedTitle];
	iMenuObserver->RestoreMenuL(iMenuPane,title.iData.iMenuPaneResourceId,MEikMenuObserver::EMenuPane);
	SetMenuHasPane();
	iMenuPane->SetSelectedItem(aNewSelectedItem);
	iMenuPane->SetFocus(ETrue);

		TMargins margins=iBorder.Margins();
	TMargins highlightMargins=iMenuPaneTitle->Margins();
	TPoint highlightPos(iPosition.iX+title.iPos-margins.iLeft,iPosition.iY);
	TSize highlightSize(title.iWidth+highlightMargins.iLeft+highlightMargins.iRight,
		iSize.iHeight-KMenuPaneOverlap-margins.iBottom);

	iMenuPaneTitle->SetSelectedTitle(aNewSelectedTitle);
	iSelectedTitle=aNewSelectedTitle;
	iCursor.iMenuPaneIndex=iSelectedTitle;
	iMenuPaneTitle->SetExtentL(highlightPos,highlightSize);
	if (redrawNeeded)
		{// redraw where the old pane title was
		DrawItem(oldSelectedTitle);
		//HandleRedrawEvent(oldHighlightRect);
		}
	TPoint pos(highlightPos.iX,iPosition.iY);
	pos.iY+=iSize.iHeight-margins.iTop-KMenuPaneOverlap;

	const TInt titleWidth=title.iWidth+margins.iLeft+margins.iRight;
	iMenuPane->StartDisplayingMenuPane(iHotKeyTable,pos,iMenuPaneTitle,titleWidth);
	}

EXPORT_C void CEikMenuBar::StopDisplayingMenuBar()
	{
	if (!MenuHasItems())
		return;
	MakeVisible(EFalse);
	iMenuObserver->SetEmphasis(this,EFalse);
	iTitleArray->Reset();
	iMenuFlags&=~EMenuHasItems;
	HideMenuPane();
	iMenuPane->Close();
	HideMenuPaneTitle();
	iMenuPaneTitle->Close();
	if (OwnsWindow())
		CloseWindow();
	}

void CEikMenuBar::StartDisplayingMenuBarL()
	{
	MakeVisible(ETrue);
	iMenuObserver->RestoreMenuL(this,iMenuTitleResourceId,MEikMenuObserver::EMenuBar);
	iMenuPaneTitle->ConstructL();
	iMenuPane->ConstructL(NULL);
	DisplayL();
	}

void CEikMenuBar::DisplayL()
	{
	CreateWindowL();
    SetAllowStrayPointers();
	Window().SetBackgroundColor(iEikonEnv->ControlColor(EEikColorMenubarBackground,*this));
	iEikonEnv->AddWindowShadow(this);
	EnableDragEvents();
	SetPointerCapture();
	CalculateSizeAndPosition();
	TPoint pos(0,iSize.iHeight-iBorder.Margins().iTop-KMenuPaneOverlap);
	iMenuPane->SetPosition(pos);
	iMenuObserver->SetEmphasis(this,ETrue);
	ActivateL();
	DrawNow();
	}

EXPORT_C void CEikMenuBar::Draw(const TRect& aRect) const
	{
	CWindowGc& gc=SystemGc();
	gc.SetPenStyle(CGraphicsContext::ESolidPen);
	iBorder.Draw(gc,Rect());
	gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorMenubarBackground,*this));
	if (Rect().iBr.iY-aRect.iTl.iY<=iBorder.Margins().iBottom+KMenuPaneOverlap)
		{// handle special case of pane being moved
		TRect innerRect=iBorder.InnerRect(Rect());
		innerRect.Intersection(aRect);
		gc.Clear(innerRect);
		return;
		}
	if (Rect().iBr.iX-aRect.iTl.iX<=iBorder.Margins().iRight+1)
		{// handle special case of pane being moved
		TRect innerRect=iBorder.InnerRect(Rect());
		innerRect.Intersection(aRect);
		gc.Clear(innerRect);
		return;
		}
	const TRect innerRect=iBorder.InnerRect(Rect());
	gc.Clear(innerRect);

	gc.SetPenColor(iEikonEnv->ControlColor(EEikColorMenubarText,*this));
	const CFont* font=iEikonEnv->NormalFont();
	gc.UseFont(font);
	const TInt count=iTitleArray->Count();
	TRect textRect=innerRect;
	for (TInt ii=0;ii<count;++ii)
		{
		const TTitle& title=(*iTitleArray)[ii];
		textRect.iTl.iX=title.iPos;
		textRect.iBr.iX=textRect.iTl.iX+title.iWidth;
		gc.DrawText(title.iData.iText,textRect,iBaseLine,CGraphicsContext::ELeft,iMenuTitleLeftSpace);
		}
	}

EXPORT_C void CEikMenuBar::DrawItem(TInt aItem) const
	{
	ActivateGc();

	const TTitle& title=(*iTitleArray)[aItem];

	TRect fillRect=Rect();
	fillRect.iTl.iX=title.iPos-iBorder.Margins().iLeft;
	//+1 for shadow
	fillRect.iBr.iX=title.iPos+title.iWidth+iBorder.Margins().iRight+1;

	Window().BeginRedraw(fillRect);
	CWindowGc& gc=SystemGc();
	iBorder.Draw(gc,Rect());

	gc.SetPenColor(iEikonEnv->ControlColor(EEikColorMenubarText,*this));
	const CFont* font=iEikonEnv->NormalFont();
	gc.UseFont(font);
	gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorMenubarBackground,*this));
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	//iEikonEnv->SetTexturedBrush(gc);
	//TRect textRect=fillRect;
	//textRect.iTl.iY+=iBorder.Margins().iTop;
	//textRect.iBr.iY-=iBorder.Margins().iBottom;	
	const TRect innerRect=iBorder.InnerRect(Rect());
	TRect textRect=innerRect;
	textRect.iTl.iX=title.iPos;
	textRect.iBr.iX=textRect.iTl.iX+title.iWidth;
	//gc.DrawText(title.iData.iText,textRect,iBaseLine,CGraphicsContext::ELeft,iMenuTitleLeftSpace +3);
	gc.DrawText(title.iData.iText,textRect,iBaseLine,CGraphicsContext::ELeft,iMenuTitleLeftSpace);
	Window().EndRedraw();
	DeactivateGc();
	}

void CEikMenuBar::MoveHighlightToCurrentMenuPaneFirstItem()
	{
	if (iMenuPane)
		{	
		iMenuPane->CloseCascadeMenu();
		iMenuPane->MoveHighlightTo(0);
		}
	}

void CEikMenuBar::CalculateSizeAndPosition()
// Calculates and sets total size and position of menu bar
// Calculates and sets relative position of title areas in menu bar
	{
	const CFont* font=iEikonEnv->NormalFont();
	const TInt count=iTitleArray->Count();
	TMargins margins=iBorder.Margins();
	TSize size=TSize(KEikMenuBarHBorder+margins.iLeft,0);
	for (TInt ii=0;ii<count;++ii)
		{
		TTitle& title=(*iTitleArray)[ii];
		title.iPos=size.iWidth;
		title.iWidth=font->TextWidthInPixels(title.iData.iText)+KMenuTitleLeftSpace+KMenuTitleRightSpace;
		size.iWidth+=title.iWidth;
		}
	size.iWidth+=KEikMenuBarHBorder+margins.iRight;
	iMenuTitleLeftSpace = KMenuTitleLeftSpace;

	const TSize screenSize=iCoeEnv->ScreenDevice()->SizeInPixels();
	if (size.iWidth>screenSize.iWidth)
		{// menu too wide, so remove luxury of large gap between items
		size.iWidth=KEikMenuBarHBorder+margins.iLeft;
		for (TInt ii=0;ii<count;++ii)
			{
			TTitle& title=(*iTitleArray)[ii];
			title.iPos=size.iWidth;
			title.iWidth-=KMenuTitleLeftSpace+KMenuTitleRightSpace;
			title.iWidth+=KMenuTitleLeftSmallSpace+KMenuTitleRightSmallSpace;
			size.iWidth+=title.iWidth;
			}
		size.iWidth+=KEikMenuBarHBorder+margins.iRight;
		iMenuTitleLeftSpace = KMenuTitleLeftSmallSpace;
		}
	
	size.iHeight=KEikMenuBarVBorder*2+margins.iTop+margins.iBottom
		+font->HeightInPixels()+KEikMenuMnenPad;
	SetExtentL(TPoint(2,2),size); // won't fail
	}

EXPORT_C void CEikMenuBar::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	const TRect rect=Rect();
	if (!rect.Contains(aPointerEvent.iPosition))
		{
		switch (aPointerEvent.iType)
			{
		case TPointerEvent::EButton1Down:
		case TPointerEvent::EButton1Up:
			iMenuObserver->ProcessCommandL(EEikCmdCanceled); // shouldn't Leave in practiceReportCancelled();
			return;
		case TPointerEvent::EDrag:
			// dragging off a pane sometimes sends the events to the bar; this code redirects the event
			// to the pane so that highlighing can be removed.
			if (iMenuPane)
				{
				TPoint panepos= iMenuPane->Position();
				TRect panerect= TRect(panepos, iMenuPane->Size());
				if (!panerect.Contains(aPointerEvent.iPosition))
					{
					TPointerEvent aPEvent=aPointerEvent;
					aPEvent.iPosition=aPointerEvent.iPosition - panepos;
					iMenuPane->HandlePointerEventL(aPEvent);
					}
				}
			return;
		default:
			return;
			}
		}
	const TInt yPos=aPointerEvent.iPosition.iY;
	if (yPos<2 || yPos>iSize.iHeight-2)
		return;
	const TInt xPos=aPointerEvent.iPosition.iX;
	const TInt count=iTitleArray->Count();
	for (TInt ii=0;ii<count;++ii)
		{
		TTitle& title=(*iTitleArray)[ii];
		if (xPos<title.iPos)
			return;
		if (xPos<title.iPos+title.iWidth)
			{
			MoveHighlightToL(ii);
			return;
			}
		}
	}

EXPORT_C CEikMenuBar::SCursor CEikMenuBar::SetMenuCursor(const SCursor& aCursor)
	{
	SCursor ret=iCursor;
	iCursor=aCursor;
	return ret;
	}

EXPORT_C void CEikMenuBar::Reserved_1()
	{}

EXPORT_C void CEikMenuBar::Reserved_2()
	{}

//
// class CEikMenuPaneTitle
//

EXPORT_C CEikMenuPaneTitle::CEikMenuPaneTitle(CEikMenuBar* aMenuBar)
	: iMenuBar(aMenuBar)
	{
	__DECLARE_NAME(_S("CEikMenuPaneTitle"));
	iBorder=TEikBorder(TEikBorder::EThickDeepRaisedWithOutline);
	}

EXPORT_C void CEikMenuPaneTitle::ConstructL()
	{
	CreateWindowL();
	EnableDragEvents();
    SetAllowStrayPointers();
	iEikonEnv->AddWindowShadow(this);
	Window().SetBackgroundColor(iEikonEnv->ControlColor(EEikColorMenubarTitleBackground,*this));
	}

EXPORT_C void CEikMenuPaneTitle::SetSelectedTitle(TInt aSelectedTitle)
	{
	Window().SetOrdinalPosition(0);
	Window().SetShadowHeight(0);
	iSelectedTitle=aSelectedTitle;
	}

EXPORT_C void CEikMenuPaneTitle::Draw(const TRect& /*aRect*/) const
	{
	CWindowGc& gc=SystemGc();

	const TRect rect(Rect());
	iBorder.Draw(gc,rect);
	const TRect innerRect=iBorder.InnerRect(rect);
	const TMargins margins=iBorder.Margins();

	gc.SetPenStyle(CGraphicsContext::ESolidPen);

	// get rid of the bit of border on the left
	gc.SetPenColor(KRgbWhite);
	gc.DrawLine(TPoint(rect.iTl.iX+2,rect.iBr.iY-4),TPoint(rect.iTl.iX+2,rect.iBr.iY));
	gc.DrawLine(TPoint(rect.iTl.iX+3,rect.iBr.iY-4),TPoint(rect.iTl.iX+3,rect.iBr.iY));
	
	gc.SetPenColor(KRgbGray);
	gc.DrawLine(TPoint(rect.iTl.iX+4,rect.iBr.iY-8),TPoint(rect.iTl.iX+4,rect.iBr.iY));

	// get rid of the bit of border on the right
	gc.SetPenColor(KRgbDarkGray);
	gc.DrawLine(TPoint(rect.iBr.iX-3,rect.iBr.iY-5),TPoint(rect.iBr.iX-3,rect.iBr.iY));
	gc.DrawLine(TPoint(rect.iBr.iX-4,rect.iBr.iY-5),TPoint(rect.iBr.iX-4,rect.iBr.iY));
	gc.DrawLine(TPoint(rect.iBr.iX-5,rect.iBr.iY-5),TPoint(rect.iBr.iX-5,rect.iBr.iY));
	const CFont* font = iEikonEnv->NormalFont();
	gc.UseFont(font);
	gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	gc.SetBrushColor(iEikonEnv->ControlColor(EEikColorMenubarTitleBackground,*this));
	gc.SetPenColor(iEikonEnv->ControlColor(EEikColorMenubarTitleText,*this));
	TRect textRect=innerRect;
	textRect.iBr.iY+=margins.iBottom;

	const CEikMenuBar::TTitle& title=(*(iMenuBar->iTitleArray))[iSelectedTitle];
	gc.DrawText(title.iData.iText,textRect,iMenuBar->iBaseLine,CGraphicsContext::ELeft,iMenuBar->iMenuTitleLeftSpace);		
	}

EXPORT_C void CEikMenuPaneTitle::HandlePointerEventL(const TPointerEvent&)
	{
	iMenuBar->MoveHighlightToCurrentMenuPaneFirstItem();
	}

EXPORT_C TMargins CEikMenuPaneTitle::Margins() const
	{
	return iBorder.Margins();
	}

EXPORT_C void CEikMenuPaneTitle::Close()
	{
	if (OwnsWindow())
		CloseWindow();
	}
