/* AbiSource Program Utilities
 * Copyright (C) 1998 AbiSource, Inc.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */
 
/*
	In versions previous to Windows Vista we use owner-draw menus. 
	In Vista we use SetMenuItemBitmaps that is more powerful that previous Windows editions
*/

#include <wchar.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "ut_types.h"
#include "ut_stack.h"
#include "ut_string.h"
#include "ut_string_class.h"
#include "ut_debugmsg.h"
#include "ut_Language.h"
#include "xap_Types.h"
#include "ev_Win32Menu.h"
#include "xap_Win32App.h"
#include "ev_Menu_Layouts.h"
#include "ev_Menu_Actions.h"
#include "ev_Menu_Labels.h"
#include "ev_EditEventMapper.h"
#include "xap_Frame.h"
#include "ap_Win32Resources.rc2"
#include "ap_Menu_Id.h"
#include "xap_App.h"
#include "xap_Win32App.h"
#include "xap_Win32Toolbar_Icons.h"
#include "ap_Win32App.h"
#include "ut_Win32OS.h"
#include "ut_Win32LocaleString.h"

#define SPACE_ICONTEXT	4	// Pixels between the icon and the text
#define BITMAP_WITDH	16
#define BITMAP_HEIGHT	16


/*
	This table assigns an icon to every menu entry
*/
static const EV_Menu_Bitmap s_bitmaps[] = 
{	  

	
    // File
	{AP_MENU_ID_FILE_CLOSE,  "Menu_AbiWord_Close"},
	{AP_MENU_ID_FILE_EXIT,		"Menu_AbiWord_Exit"},	
	{AP_MENU_ID_FILE_EXPORT, "Menu_AbiWord_Export"},
	{AP_MENU_ID_FILE_IMPORT, "Menu_AbiWord_Import"},
	{AP_MENU_ID_FILE_NEW,	 "Menu_AbiWord_New"},
	{AP_MENU_ID_FILE_OPEN,	 "Menu_AbiWord_Open"},
	{AP_MENU_ID_FILE_PRINT,		"Menu_AbiWord_Print"}, 
	{AP_MENU_ID_FILE_SAVE,		"Menu_AbiWord_Save"}, 
	{AP_MENU_ID_FILE_SAVEAS,	"Menu_AbiWord_SaveAs"}, 
	{AP_MENU_ID_FILE_REVERT, "Menu_AbiWord_Revert"},
	{AP_MENU_ID_FILE_PROPERTIES, "Menu_AbiWord_Properties"},
	{AP_MENU_ID_FILE_PAGESETUP, "Menu_AbiWord_Print_Setup"},
    
	// Edit
	{AP_MENU_ID_EDIT_PASTE, "Menu_AbiWord_Paste"},				
	{AP_MENU_ID_EDIT_CUT, "Menu_AbiWord_Cut"},				
	{AP_MENU_ID_EDIT_COPY, "Menu_AbiWord_Copy"},				
	{AP_MENU_ID_EDIT_UNDO, "Menu_AbiWord_Undo"},				
	{AP_MENU_ID_EDIT_REDO, "Menu_AbiWord_Redo"},				
	{AP_MENU_ID_EDIT_PASTE_SPECIAL, "Menu_AbiWord_Paste"},
	{AP_MENU_ID_EDIT_CLEAR, "Menu_AbiWord_Clear"},
	{AP_MENU_ID_EDIT_FIND, "Menu_AbiWord_Search"},
	{AP_MENU_ID_EDIT_REPLACE, "Menu_AbiWord_Replace"},
	{AP_MENU_ID_EDIT_GOTO, "Menu_AbiWord_Goto"},

	// Insert
	{AP_MENU_ID_INSERT_SYMBOL,	"Menu_AbiWord_Insert_Symbol"},
	{AP_MENU_ID_INSERT_GRAPHIC, "Menu_AbiWord_Img"},
	{AP_MENU_ID_INSERT_HYPERLINK,	"Menu_AbiWord_Hyperlink"},	

	// Format
	{AP_MENU_ID_FMT_FONT, "Menu_AbiWord_Font"},
	{AP_MENU_ID_TABLE_INSERT_TABLE, "Menu_AbiWord_Insert_Table"},
	{AP_MENU_ID_TOOLS_SPELL, "Menu_AbiWord_Spellcheck"},			
	{AP_MENU_ID_TOOLS_OPTIONS, "Menu_AbiWord_Preferences"},
	{AP_MENU_ID_TOOLS_SCRIPTS, "Menu_AbiWord_Execute"},
	{AP_MENU_ID_TOOLS_LANGUAGE, "Menu_AbiWord_Book"},
	{AP_MENU_ID_FMT_LANGUAGE, "Menu_AbiWord_Book"},


	// Table
	{AP_MENU_ID_TABLE_INSERT_TABLE, "Menu_AbiWord_Insert_Table"},
	{AP_MENU_ID_TABLE_DELETE_TABLE, "Menu_AbiWord_Delete_Table"},
	{AP_MENU_ID_TABLE_INSERTTABLE, "Menu_AbiWord_Insert_Table"},
	{AP_MENU_ID_TABLE_DELETETABLE, "Menu_AbiWord_Delete_Table"},
	{AP_MENU_ID_TABLE_MERGE_CELLS, "Menu_AbiWord_Merge_Cells"},
	{AP_MENU_ID_TABLE_SPLIT_CELLS, "Menu_AbiWord_Split_Cells"},
	{AP_MENU_ID_TABLE_INSERTCOLUMN, "Menu_AbiWord_Add_Column"},
	{AP_MENU_ID_TABLE_INSERTROW, "Menu_AbiWord_Add_Row"},
	{AP_MENU_ID_TABLE_DELETECOLUMN, "Menu_AbiWord_Delete_Column"},
	{AP_MENU_ID_TABLE_DELETEROW, "Menu_AbiWord_Delete_Row"},
	{AP_MENU_ID_TABLE_DELETE_COLUMNS, "Menu_AbiWord_Delete_Column"},
	{AP_MENU_ID_TABLE_DELETE_ROWS, "Menu_AbiWord_Delete_Row"},
	

	// Help
	{AP_MENU_ID_HELP_SEARCH, "Menu_AbiWord_Search"},
	{AP_MENU_ID_HELP_ABOUT, "Menu_AbiWord_About"},
	{AP_MENU_ID_HELP_CREDITS, "Menu_AbiWord_Credits"},
	
	{0, NULL}

		
};



/*

*/
static const wchar_t * _ev_GetLabelName(XAP_Win32App * pWin32App,
									 XAP_Frame * /*pFrame*/, 
									 const EV_EditEventMapper * pEEM,
									 const EV_Menu_Action * pAction,
									 EV_Menu_Label * pLabel) 
{
	const wchar_t * szLabelName;
	const char * szLabelName_utf8;
	
	if (pAction->hasDynamicLabel())
		szLabelName_utf8 = pAction->getDynamicLabel(pLabel);
	else
		szLabelName_utf8 = pLabel->getMenuLabel();

	if (!szLabelName_utf8 || !*szLabelName_utf8)
		return NULL;

	UT_Win32LocaleString str;
	str.fromUTF8 (szLabelName_utf8);
	szLabelName = str.c_str();

	const char * szShortcut_ascii = NULL;
	const wchar_t * szShortcut = NULL;
	UT_Win32LocaleString shortcut;
	
    int len = 0;

	if (pEEM)
	{
		// see if this has an associated keybinding
		const char * szMethodName = pAction->getMethodName();

		if (szMethodName)
		{
			const EV_EditMethodContainer * pEMC = pWin32App->getEditMethodContainer();
			UT_return_val_if_fail(pEMC, NULL);

			EV_EditMethod * pEM = pEMC->findEditMethodByName(szMethodName);
			UT_ASSERT(pEM);					// make sure it's bound to something

			szShortcut_ascii = pEEM->getShortcutFor(pEM);
			if (szShortcut_ascii && *szShortcut_ascii)
				len = strlen(szShortcut_ascii) + 1;	// extra char is for the tab
		}
	}

    if (szShortcut && *szShortcut) {
		shortcut.fromASCII (szShortcut_ascii);
	}
	
	if (pAction->raisesDialog())
		len += 4;

	if (!len)
	{
		static wchar_t buf[128];
		wcscpy(buf,szLabelName);
		return buf;
	}

	static wchar_t buf[128];
    int l = G_N_ELEMENTS(buf);
	memset(buf,0,l);
	wcscpy(buf,szLabelName);           //strncpy

	// append "..." to menu item if it raises a dialog
	if (pAction->raisesDialog())
		wcscat(buf, L"...");                  //todo

	// append shortcut mnemonic, if any
	if (shortcut.length())
	{
		wcscat(buf, L"\t");              //todo
		wcscat(buf, shortcut.c_str());
	}
										  
	return buf;
}



/*****************************************************************/

EV_Win32Menu::EV_Win32Menu(XAP_Win32App * pWin32App,
						   const EV_EditEventMapper * pEEM,
						   const char * szMenuLayoutName,
						   const char * szMenuLabelSetName)
:	EV_Menu(pWin32App, pWin32App->getEditMethodContainer(), szMenuLayoutName, szMenuLabelSetName),
	m_pWin32App(pWin32App),
	m_pEEM(pEEM),
	m_myMenu(NULL),
	m_iDIR(0)
{
		    
	NONCLIENTMETRICSA ncm;
	ncm.cbSize = sizeof (NONCLIENTMETRICSA);
	m_bTrack = false;

    SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0);
	m_hFont = CreateFontIndirectA(&ncm.lfMenuFont);	

	m_nBitmapCX = BITMAP_WITDH + 2;
	m_nBitmapCY = BITMAP_HEIGHT + 2;

	UT_return_if_fail( m_pMenuLabelSet );
	
	UT_Language l;
	if(l.getDirFromCode(m_pMenuLabelSet->getLanguage()) == UTLANG_RTL)
		m_iDIR = DT_RTLREADING;
}

void	EV_Win32Menu::destroy()
{		

	UT_VECTOR_PURGEALL(EV_Menu_Item*,m_vecItems);

	if (m_myMenu)
	{
		DestroyMenu(m_myMenu);
		m_myMenu = 0;
	}

	if (m_hFont)
		DeleteObject(m_hFont);
	
}

EV_Win32Menu::~EV_Win32Menu()
{	
	// we let the derived classes handle destruction of m_myMenu if appropriate.
	// TODO: this is never colld
	
	for (std::vector<HBITMAP>::const_iterator i = m_vechBitmaps.begin(); 
		 i != m_vechBitmaps.end(); i++)
	{	    
	    DeleteObject (*i);
	}
		
}

bool EV_Win32Menu::onCommand(AV_View * pView,
							 HWND /*hWnd*/, WPARAM wParam)         
{
	// TODO do we need the hWnd parameter....

	// map the windows WM_COMMAND command-id into one of our XAP_Menu_Id.
	// we don't need to range check it, getAction() will puke if it's
	// out of range.
	
	XAP_Menu_Id id = MenuIdFromWmCommand(LOWORD(wParam));

	// user selected something from the menu.
	// invoke the appropriate function.
	// return true iff handled.

	const EV_Menu_ActionSet * pMenuActionSet = m_pWin32App->getMenuActionSet();
	UT_return_val_if_fail(pMenuActionSet, false);

	const EV_Menu_Action * pAction = pMenuActionSet->getAction(id);
	if (!pAction)
		return false;

	const char * szMethodName = pAction->getMethodName();
	UT_return_val_if_fail(szMethodName, false);
	
	const EV_EditMethodContainer * pEMC = m_pWin32App->getEditMethodContainer();
	UT_return_val_if_fail(pEMC, false);

	EV_EditMethod * pEM = pEMC->findEditMethodByName(szMethodName);
	UT_ASSERT(pEM);						// make sure it's bound to something

	UT_String script_name(pAction->getScriptName());
	invokeMenuMethod(pView, pEM, script_name);
	return true;
}

/*

	Create a Win32 menu from the info provided.

*/
bool EV_Win32Menu::synthesizeMenu(XAP_Frame * pFrame, HMENU menuRoot)
{	
	bool bResult;
	
	const EV_Menu_ActionSet * pMenuActionSet = m_pWin32App->getMenuActionSet();
	UT_ASSERT(pMenuActionSet);
	
	const UT_uint32 nrLabelItemsInLayout = m_pMenuLayout->getLayoutItemCount();
	UT_ASSERT(nrLabelItemsInLayout > 0);

	// we keep a stack of the submenus so that we can properly
	// parent the menu items and deal with nested pull-rights.
	
	UT_Stack stack;
	stack.push(menuRoot);
	//UT_DEBUGMSG(("Menu::synthesize [menuRoot 0x%08lx]\n",menuRoot));
	
	for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
	{
		
		EV_Menu_LayoutItem * pLayoutItem = m_pMenuLayout->getLayoutItem(k);
		UT_continue_if_fail(pLayoutItem);

		XAP_Menu_Id id = pLayoutItem->getMenuId();
		const EV_Menu_Action * pAction = pMenuActionSet->getAction(id);
		UT_ASSERT(pAction);
		EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(id);
		UT_ASSERT(pLabel);

		// get the name for the menu item

		const wchar_t * szLabelName = _ev_GetLabelName(m_pWin32App,pFrame,m_pEEM,pAction,pLabel);
		
		switch (pLayoutItem->getMenuLayoutFlags())
		{
		case EV_MLF_BeginSubMenu:
			UT_ASSERT(szLabelName && *szLabelName);
			// Fall Thru Intended

		case EV_MLF_Normal:
			{
				UT_DEBUGMSG(("menu::synthesize [name %s]\n",szLabelName));

				HMENU m;
				bResult = stack.viewTop((void **)&m);
				UT_ASSERT(bResult);

				// set standard flags on the item, we'll update the
				// state on an onInitMenu().
				// map our XAP_Menu_Id into a windows WM_COMMAND id.
				
				UINT flags = MF_STRING | MF_ENABLED | MF_UNCHECKED;
				UINT u = WmCommandFromMenuId(id);

				/*
					This a menu bar
				*/
				if (pLayoutItem->getMenuLayoutFlags() == EV_MLF_BeginSubMenu)
				{
					HMENU sub = CreateMenu();	// TODO NOTE: Leaking handle!
					UT_ASSERT(sub);

					UT_DEBUGMSG(("menu::synthesize [name %s][subMenu 0x%08lx] %u\n",szLabelName,u, stack.getDepth()));

					flags |= MF_POPUP;
					stack.push(sub);
					u = (size_t) sub;					
					
					if (szLabelName && *szLabelName)					
					{
						EV_Menu_Item*	item = new EV_Menu_Item;
						item->id = id;					
						item->pMenu= this;							
						
						wcscpy (item->szText, szLabelName);					
						m_vecItems.addItem(item);
							
						if (!m_bTrack && stack.getDepth()==2)
							AppendMenuW(m, flags,u, szLabelName);
						else {
							if (UT_IsWinVista()) {
								AppendMenuW(m, flags|MF_STRING,u, szLabelName);
								_setBitmapforID(m, id, u);
							}
							else
								AppendMenuW(m, flags|MF_OWNERDRAW,u, (const wchar_t*) item);
						}
					}		
						
				}
				else
				{					
					if (szLabelName && *szLabelName)
					{		  
						EV_Menu_Item*	item = new EV_Menu_Item;
						item->id = id;
						item->pMenu= this;						
						wcscpy (item->szText, szLabelName);
						m_vecItems.addItem(item);
						
						if (UT_IsWinVista()) {                                      //todo: code for windows vista : investigate this
							AppendMenuW(m, MF_STRING, u, szLabelName);
							_setBitmapforID (m, id, u);
						}
						else
							AppendMenuW(m, MF_OWNERDRAW, u, (const wchar_t*) item);
					}
				}

				
			}
			break;
	
		case EV_MLF_EndSubMenu:
			{				
				HMENU m = NULL;
				bResult = stack.pop((void **)&m);
				UT_ASSERT(bResult);
				UT_DEBUGMSG(("menu::synthesize [endSubMenu 0x%08lx]\n",m));
			}
			break;
			
		case EV_MLF_Separator:
			{
				HMENU m;
				bResult = stack.viewTop((void **)&m);
				UT_ASSERT(bResult);
				UT_ASSERT(m);

				AppendMenuW(m, MF_SEPARATOR, 0, NULL);
				UT_DEBUGMSG(("menu::synthesize [separator appended to submenu 0x%08lx]\n",m));
			}
			break;

		case EV_MLF_BeginPopupMenu:
		case EV_MLF_EndPopupMenu:
			break;

		default:
			UT_ASSERT_HARMLESS(0);
			break;
		}
	}

#ifdef DEBUG
	HMENU wDbg = NULL;
	bResult = stack.pop((void **)&wDbg);
	UT_ASSERT(bResult);
	UT_ASSERT(wDbg == menuRoot);
#endif

	return true;
}

bool EV_Win32Menu::onInitMenu(XAP_Frame * pFrame, AV_View * pView, HWND /*hWnd*/, HMENU hMenuBar)
{
	// deal with WM_INITMENU.

	if (hMenuBar != m_myMenu)			// these are not different when they
		return false;				// right-click on us on the menu bar.
	
	const EV_Menu_ActionSet * pMenuActionSet = m_pWin32App->getMenuActionSet();
	UT_uint32 nrLabelItemsInLayout = m_pMenuLayout->getLayoutItemCount();
	

	UT_uintptr pos = 0;
	bool bResult;
	UT_Stack stackPos;
	stackPos.push((void*)pos);
	UT_Stack stackMenu;
	stackMenu.push(hMenuBar);

	HMENU mTemp;
	HMENU m = hMenuBar;
	//UT_DEBUGMSG(("menu::onInitMenu: [menubar 0x%08lx]\n",m));

	for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
	{
		EV_Menu_LayoutItem * pLayoutItem = m_pMenuLayout->getLayoutItem(k);
		XAP_Menu_Id id = pLayoutItem->getMenuId();
		const EV_Menu_Action * pAction = pMenuActionSet->getAction(id);
		EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(id);

		UINT cmd = WmCommandFromMenuId(id);

		switch (pLayoutItem->getMenuLayoutFlags())
		{
		case EV_MLF_Normal:
			{
				// see if we need to enable/disable and/or check/uncheck it.
				
				UINT uEnable = MF_BYCOMMAND | MF_ENABLED;
				UINT uCheck = MF_BYCOMMAND | MF_UNCHECKED;
				UINT uBold = 0;
				if (pAction->hasGetStateFunction())
				{
 					EV_Menu_ItemState mis = pAction->getMenuItemState(pView);
					if (mis & EV_MIS_Gray)
						uEnable |= MF_GRAYED;
					if (mis & EV_MIS_Toggled)
						uCheck |= MF_CHECKED;
					if (mis & EV_MIS_Bold)
						uBold = MFS_DEFAULT;
				}

				if (!pAction->hasDynamicLabel())
				{
					// if no dynamic label, all we need to do
					// is enable/disable and/or check/uncheck it.
					pos++;

					// need to check before disabling ...
					CheckMenuItem(hMenuBar,cmd,uCheck);
					EnableMenuItem(hMenuBar,cmd,uEnable);
					break;
				}

				// get the current menu info for this item.
				
				MENUITEMINFOW mif;
				wchar_t bufMIF[128];
				mif.cbSize = sizeof(mif);
				mif.dwTypeData = bufMIF;
				mif.cch = G_N_ELEMENTS(bufMIF)-1;
				mif.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID;
				BOOL bPresent = GetMenuItemInfoW(hMenuBar,cmd,FALSE,&mif);

				// this item has a dynamic label...
				// compute the value for the label.
				// if it is blank, we remove the item from the menu.

				const wchar_t * szLabelName = _ev_GetLabelName(m_pWin32App,pFrame,m_pEEM,pAction,pLabel);

				BOOL bRemoveIt = (!szLabelName || !*szLabelName);

				if (bRemoveIt)			// we don't want it to be there
				{
					if (bPresent)
						RemoveMenu(hMenuBar,cmd,MF_BYCOMMAND);
					
					break;
				}

				// we want the item in the menu.
				pos++;			

				if (bPresent)			// just update the label on the item.
				{					
					// dynamic label has changed
					XAP_Menu_Id id = MenuIdFromWmCommand(cmd);
					EV_Menu_Item*	item;
					for(UT_sint32 i = 0; i< m_vecItems.getItemCount(); i++)
					{
						item = (EV_Menu_Item*)m_vecItems.getNthItem(i);
						if (id==item->id)
						{
							wcscpy (item->szText, szLabelName);					
							//UT_DEBUGMSG(("Menu changing text->%s\n",szLabelName));
							if (UT_IsWinVista()) 
							{
								mif.fState = uCheck | uEnable | uBold;
								mif.fType = MFT_STRING;
								mif.dwTypeData = (LPWSTR)szLabelName;
								SetMenuItemInfoW (hMenuBar,cmd,FALSE,&mif);
							}
							break;
						}
					}
				}
				else	
				{
					EV_Menu_Item*	item = new EV_Menu_Item;
					item->id = id;					
					item->pMenu= this;													
					wcscpy (item->szText, szLabelName);					
					m_vecItems.addItem(item);
					//UT_DEBUGMSG(("Menu adding menu->%s\n",szLabelName));
										
					if (UT_IsWinVista()) {
						AppendMenuW(m, MF_STRING, cmd, szLabelName);
						_setBitmapforID(m, id, cmd);
					}
					else
						AppendMenuW(m, MF_OWNERDRAW,cmd, (const wchar_t*) item);
				}
				
				EV_Menu_ItemState mis = pAction->getMenuItemState(pView);
				
				if (mis & EV_MIS_Gray)
						uEnable |= MF_GRAYED;
						
				if (mis & EV_MIS_Toggled)
						uCheck |= MF_CHECKED;
						
				EnableMenuItem(m,cmd,uEnable);
				CheckMenuItem(m,cmd,uCheck);
				
			}
			break;
	
		case EV_MLF_Separator:
			pos++;
			break;

		case EV_MLF_BeginSubMenu:
			mTemp = m;
			pos++;
			stackMenu.push(mTemp);
			stackPos.push((void*)pos);

			m = GetSubMenu(mTemp, pos-1);
			//UT_DEBUGMSG(("menu::onInitMenu: [menu 0x%08lx] at [pos %d] has [submenu 0x%08lx]\n",mTemp,pos-1,m));
			//UT_ASSERT(m);
			pos = 0;
			break;

		case EV_MLF_EndSubMenu:
			bResult = stackMenu.pop((void **)&mTemp);
			UT_ASSERT(bResult);
			bResult = stackPos.pop((void **)&pos);
			UT_ASSERT(bResult);

			//UT_DEBUGMSG(("menu::onInitMenu: endSubMenu [popping to menu 0x%08lx pos %d] from 0x%08lx\n",mTemp,pos,m));
			m = mTemp;
			break;

		case EV_MLF_BeginPopupMenu:
		case EV_MLF_EndPopupMenu:
			break;
			
		default:
			UT_ASSERT_HARMLESS(0);
			break;
		}
	}

#ifdef DEBUG
	HMENU wDbg = NULL;
	bResult = stackMenu.pop((void **)&wDbg);
	UT_ASSERT(bResult);
	UT_ASSERT(wDbg == hMenuBar);
#endif
		
 	return true;
}

/*
	Caller should DeleteObject the handle returned	
*/
HBITMAP EV_Win32Menu::_loadBitmap(XAP_Menu_Id id, int width, int height, UT_RGBColor color)
{
	
	HBITMAP hBitmap = NULL;
	EV_Menu_Bitmap* pBitmaps = (EV_Menu_Bitmap*)&s_bitmaps;		
							 
	for (; pBitmaps->id;pBitmaps++)
	{							
		if (pBitmaps->id==id)
			break;	
	}

	if (!pBitmaps->id) return hBitmap;

	if (!color.isTransparent())
		XAP_Win32Toolbar_Icons::getBitmapForIcon(GetDesktopWindow(), width, height, &color, pBitmaps->szName, &hBitmap);
	else XAP_Win32Toolbar_Icons::getAlphaBitmapForIcon(GetDesktopWindow(), width, height, pBitmaps->szName, &hBitmap);
	
	return hBitmap; 
}

// Sets the Bitmap in Windows Vista
void EV_Win32Menu::_setBitmapforID (HMENU hMenu, XAP_Menu_Id id, UINT cmd)
{
	UT_RGBColor Color;
	Color.m_bIsTransparent=true;
	HBITMAP hBitmap =  EV_Win32Menu::_loadBitmap(id, BITMAP_WITDH, BITMAP_HEIGHT, Color);
							
	if (hBitmap != NULL) {
		SetMenuItemBitmaps (hMenu, cmd, MF_BYCOMMAND, hBitmap, hBitmap);		
		m_vechBitmaps.push_back (hBitmap);
	}
}

/*
	It tells us which are menu bars
*/
bool EV_Win32Menu::_isAMenuBar(XAP_Menu_Id id, HMENU hMenu)
{
	XAP_Menu_Id ids[] = { AP_MENU_ID_FILE, AP_MENU_ID_EDIT, AP_MENU_ID_VIEW,AP_MENU_ID_INSERT,
		AP_MENU_ID_TOOLS, AP_MENU_ID_WINDOW, AP_MENU_ID_HELP,AP_MENU_ID_TABLE, AP_MENU_ID_FORMAT, NULL};

	for (UT_uint32 i=0; i<(sizeof(ids)/sizeof(XAP_Menu_Id)); i++)
	{
		if (ids[i]==id)
		{		
			
			MENUITEMINFOW menuInfo;	 
			memset (&menuInfo, 0, sizeof(MENUITEMINFOW));
			menuInfo.cbSize = sizeof(MENUITEMINFOW);
			menuInfo.fMask = MIIM_DATA;
			GetMenuItemInfoW(hMenu, 0, TRUE, &menuInfo);		
			EV_Menu_Item*	item = (EV_Menu_Item *) menuInfo.dwItemData;            			           				

			if (item && id==item->id)		
			{
				UT_DEBUGMSG(("EV_Win32Menu::_isAMenuBar->%s, 1\n", item->szText));
				return true;
			}
		}
	}

	UT_DEBUGMSG(("EV_Win32Menu::_isAMenuBar-> 0\n"));
	return false;
}



/*
	Process message WM_MEASUREITEM                          
*/
void EV_Win32Menu::onMeasureItem(HWND hwnd, WPARAM /*wParam*/, LPARAM lParam)
{
	SIZE size;
	LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam; 
	HDC hdc = GetDC(hwnd); 
	
	EV_Menu_Item*	item = (EV_Menu_Item *) lpmis->itemData;            	
	HFONT hfontOld = (HFONT) SelectObject(hdc, m_hFont); 

	// Retrieve the width and height of the item's string 
	GetTextExtentPoint32W(hdc, item->szText, lstrlenW(item->szText), &size); 
		
	if (size.cy < item->pMenu->m_nBitmapCY)
		lpmis->itemHeight = item->pMenu->m_nBitmapCY;
	else
		lpmis->itemHeight = size.cy;

	lpmis->itemWidth =  size.cx + item->pMenu->m_nBitmapCX + SPACE_ICONTEXT;

	SelectObject(hdc, hfontOld); 
	ReleaseDC(hwnd, hdc); 
}

/*
	Process message  WM_MENUCHAR. Process the hotkey messages	
*/
LPARAM EV_Win32Menu::onMenuChar(HWND /*hwnd*/, WPARAM wParam, LPARAM lParam)
{	
	HMENU hMenu = (HMENU) lParam;
	MENUITEMINFOW	menuInfo;
	int nItems = GetMenuItemCount(hMenu);
	wchar_t szBuff[1024];
	
	for (int i=0; i<nItems; i++)
	{					
		memset (&menuInfo, 0, sizeof(MENUITEMINFOW));
		menuInfo.cbSize = sizeof(MENUITEMINFOW);
		menuInfo.fMask = MIIM_DATA;

		GetMenuItemInfoW(hMenu, i, TRUE, &menuInfo);		

		EV_Menu_Item*	item = (EV_Menu_Item *) menuInfo.dwItemData;            			           	

		if (item)
		{
			wcscpy (szBuff, item->szText);
			_wcslwr(szBuff);			

			wchar_t* pHotKeyPos = wcschr (szBuff, L'&');
				
			if (pHotKeyPos)
			{								
				wchar_t n = (wchar_t)wParam & 0x000000ff;

				pHotKeyPos++;

				if (toupper(*pHotKeyPos)==toupper(n))			
					return MAKELRESULT(i, MNC_EXECUTE);														 
				
			}
		}			
	}

	return MNC_IGNORE;
}

/*
	Process message  WM_DRAWITEM
*/
void EV_Win32Menu::onDrawItem(HWND /*hwnd*/, WPARAM /*wParam*/, LPARAM lParam)
{

	LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;  
	EV_Menu_Item*	item = (EV_Menu_Item *) lpdis->itemData;            			           	
    COLORREF crText;    
    COLORREF crBkgnd;   
	DWORD dwColor;
	RECT rect;
	HBITMAP hBitmap;	
	int colorID;
	UT_ASSERT(lpdis->CtlType==ODT_MENU); 	
    UT_Win32LocaleString sTextRight, sTextLeft;					

	/* Rect to draw the text */	
	rect.top =  lpdis->rcItem.top;
	rect.bottom = lpdis->rcItem.bottom;

	if(m_iDIR)
	{
		rect.right = lpdis->rcItem.right - 20;
		rect.left = lpdis->rcItem.left;
	}
	else
	{
		rect.right = lpdis->rcItem.right;
		rect.left = /*m_nBitmapCX*/ 20  + lpdis->rcItem.left;
	}
	
	
	if (lpdis->itemState & ODS_GRAYED) 
		crText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_GRAYTEXT));	
	else
		if (lpdis->itemState & ODS_SELECTED)
			crText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));		
		else
			crText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT));			

	if (lpdis->itemState & ODS_SELECTED)     
		colorID = COLOR_HIGHLIGHT;
	else
		colorID = COLOR_MENU;		
	
	dwColor = GetSysColor(colorID);
	
	UT_RGBColor Color(GetRValue(dwColor),GetGValue(dwColor),GetBValue(dwColor));
	hBitmap =  EV_Win32Menu::_loadBitmap(item->id, BITMAP_WITDH, BITMAP_HEIGHT, Color);

	if (hBitmap)	
	{
		BITMAP bitmap;		
		GetObjectA(hBitmap, sizeof(BITMAP), &bitmap);	
	}	

	/*Draw the background of the item*/
	FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(colorID));

	if(m_iDIR)
		rect.right = rect.right - SPACE_ICONTEXT;
	else
		rect.left = rect.left;
		
	
	// Select the font associated with the item into the 
    // item's device context, and then draw the string.  
    HFONT hfontOld = (HFONT) SelectObject(lpdis->hDC, item->pMenu->m_hFont); 

	
	/* 
		Process tabs
	*/	
	wchar_t* pTabPos = wcschr (item->szText, L'\t');

	if (pTabPos)
	{
		wchar_t szTmp[255];
		wchar_t* pTmp;
		
		wcsncpy (szTmp, item->szText, pTabPos-item->szText);
		pTmp = szTmp; pTmp+=pTabPos-item->szText; *pTmp=NULL;
		sTextLeft.fromLocale (szTmp);
		
		wcscpy (szTmp, pTabPos+1);
		sTextRight.fromLocale (szTmp);
		sTextRight.appendASCII ("  ");
	}
	else
		sTextLeft.fromLocale (item->szText);	
	
	if (lpdis->itemState & ODS_SELECTED) 
		crBkgnd = SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));

	/* Draw text*/
	if(m_iDIR)
	{
		DrawTextW(lpdis->hDC, sTextLeft.c_str(),  sTextLeft.length() , &rect,
				 DT_RIGHT | DT_VCENTER | DT_SINGLELINE | m_iDIR);
		
		if (sTextRight.length())
			DrawTextW(lpdis->hDC, sTextRight.c_str(), sTextRight.length(), &rect,
					 DT_LEFT | DT_VCENTER | DT_SINGLELINE | m_iDIR);
	}
	else
	{
		DrawTextW(lpdis->hDC, sTextLeft.c_str(),  sTextLeft.length() , &rect,
				 DT_LEFT | DT_VCENTER | DT_SINGLELINE | m_iDIR);
		
		if (sTextRight.length())
			DrawTextW(lpdis->hDC, sTextRight.c_str(), sTextRight.length(), &rect,
					 DT_RIGHT | DT_VCENTER | DT_SINGLELINE | m_iDIR);
	}
	
	if (lpdis->itemState & ODS_SELECTED) 
		SetBkColor(lpdis->hDC, crBkgnd); 
	
	/* Draw bitmap*/
	if (hBitmap)
	{	
					  		
		HDC hdcMem = CreateCompatibleDC(lpdis->hDC);
		SelectObject(hdcMem,(void *)hBitmap);				

		if(m_iDIR)
			BitBlt(lpdis->hDC, lpdis->rcItem.right - 20, lpdis->rcItem.top+1, BITMAP_WITDH, BITMAP_HEIGHT, hdcMem, 0, 0, SRCCOPY );
		else
			BitBlt(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, BITMAP_WITDH, BITMAP_HEIGHT, hdcMem, 0, 0, SRCCOPY );
		
		DeleteDC(hdcMem);					
				
	}
	else 
		if (lpdis->itemState & ODS_CHECKED)
		{	
			UINT nWidth = GetSystemMetrics(SM_CXMENUCHECK);
			UINT nHeight = GetSystemMetrics(SM_CYMENUCHECK);
			RECT r;
			HBITMAP bm = CreateBitmap(nWidth, nHeight, 1, 1, NULL );
			HDC hdcMem = CreateCompatibleDC(lpdis->hDC);

			SetBkColor(lpdis->hDC, GetSysColor(colorID));
			SelectObject(hdcMem, bm);
			SetRect(&r, 0, 0, nWidth, nHeight);
			DrawFrameControl(hdcMem, &r, DFC_MENU,DFCS_MENUCHECK);			

			if(m_iDIR)
				BitBlt(lpdis->hDC, lpdis->rcItem.right - 20, lpdis->rcItem.top+2, nWidth, nHeight,
					   hdcMem, 0, 0, SRCCOPY);
			else
				BitBlt(lpdis->hDC, lpdis->rcItem.left+2, lpdis->rcItem.top+2, nWidth, nHeight,
					   hdcMem, 0, 0, SRCCOPY);
				
			DeleteDC(hdcMem);
			DeleteObject(bm);
		}	

    SelectObject(lpdis->hDC, hfontOld); 
    SetTextColor(lpdis->hDC, crText); 	
	if (hBitmap)
		DeleteObject(hBitmap);	
}

								
bool EV_Win32Menu::onMenuSelect(XAP_Frame * pFrame, AV_View * /*pView*/,
								   HWND /*hWnd*/, HMENU hMenu, WPARAM wParam)
{
	UINT nItemID = (UINT)LOWORD(wParam);
	UINT nFlags  = (UINT)HIWORD(wParam);

	if ( (nFlags==0xffff) && (hMenu==0) )
	{
		//UT_DEBUGMSG(("ClearMessage 1\n"));
		pFrame->setStatusMessage(NULL);
		return true;
	}

	if ( (nItemID==0) || (nFlags & (MF_SEPARATOR|MF_POPUP)) )
	{
		//UT_DEBUGMSG(("ClearMessage 2\n"));
		pFrame->setStatusMessage(NULL);
		return true;
	}

	if (nFlags & (MF_SYSMENU))
	{
		//UT_DEBUGMSG(("SysMenu [%x]\n",nItemID));
		pFrame->setStatusMessage(NULL);
		return true;
	}
	
	XAP_Menu_Id id = MenuIdFromWmCommand(nItemID);
	EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(id);
	if (!pLabel)
	{
		//UT_DEBUGMSG(("ClearMessage 3 [%d %d]\n",nItemID,id));
		pFrame->setStatusMessage(NULL);
		return true;
	}

	const char * szMsg = pLabel->getMenuStatusMessage();
	if (!szMsg || !*szMsg)
		szMsg = "TODO This menu item doesn't have a StatusMessage defined.";
	
	pFrame->setStatusMessage(szMsg);
	return true;
}



/*****************************************************************/
/*****************************************************************/

EV_Win32MenuBar::EV_Win32MenuBar(XAP_Win32App * pWin32App,
								 const EV_EditEventMapper * pEEM,
								 const char * szMenuLayoutName,
								 const char * szMenuLabelSetName)
	: EV_Win32Menu(pWin32App,pEEM,szMenuLayoutName,szMenuLabelSetName)
{
}

EV_Win32MenuBar::~EV_Win32MenuBar(void)
{
	destroy();
	// TODO should we destroy m_myMenu if set ??
}

bool EV_Win32MenuBar::synthesizeMenuBar(XAP_Frame * pFrame)
{
	m_myMenu = CreateMenu();

	bool bRet = synthesizeMenu(pFrame, m_myMenu);

	// when dealing with RTL interface language, we need to tell do some tricks here to
	// make the menubar to layout RTL
	// see http://www.microsoft.com/middleeast/msdn/faq.aspx
	MENUITEMINFOW mii;

	wchar_t buff[81];
	memset(buff, 0, 80 * sizeof (wchar_t));
	buff[80] = 0;
	
	mii.cbSize = sizeof(mii);
	mii.dwTypeData = buff;
	mii.fType = MF_STRING;
    mii.cch = 80* sizeof (wchar_t);
	mii.fState = MFS_DEFAULT;
	mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
	
	if(m_iDIR && GetMenuItemInfoW(m_myMenu, 0, 1, &mii))
	{
		mii.fType |= MFT_RIGHTORDER;
		SetMenuItemInfoW(m_myMenu, 0, 1, &mii);
	}
	
	return bRet;
}

/*****************************************************************/
/*****************************************************************/

EV_Win32MenuPopup::EV_Win32MenuPopup(XAP_Win32App * pWin32App,
									 const char * szMenuLayoutName,
									 const char * szMenuLabelSetName)
	: EV_Win32Menu(pWin32App,NULL,szMenuLayoutName,szMenuLabelSetName)
{
}

EV_Win32MenuPopup::~EV_Win32MenuPopup(void)
{
	destroy();
	
	if (m_myMenu)
		DestroyMenu(m_myMenu);
}

bool EV_Win32MenuPopup::synthesizeMenuPopup(XAP_Frame * pFrame)
{
	m_myMenu = CreatePopupMenu();

	bool bRet = synthesizeMenu(pFrame, m_myMenu);

	// when dealing with RTL interface language, we need to tell do some tricks here to
	// make the menubar to layout RTL
	// see http://www.microsoft.com/middleeast/msdn/faq.aspx
	MENUITEMINFOW mii;
	wchar_t buff[81];
	memset(buff, 80 * sizeof (wchar_t), L' ');
	buff[80* sizeof (wchar_t)] = 0;
	
	mii.cbSize = sizeof(mii);
	mii.dwTypeData = buff;
	mii.fType = MF_STRING;
	mii.cch = 80* sizeof (wchar_t);
	mii.fState = MFS_DEFAULT;
	mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
	
	if(m_iDIR && GetMenuItemInfoW(m_myMenu, 0, 1, &mii))
	{
		mii.fType |= MFT_RIGHTORDER;
		SetMenuItemInfoW(m_myMenu, 0, 1, &mii);
	}
	
	return bRet;
	
}