/* 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.
 */

#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 "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"

#define SPACE_ICONTEXT	4	// Pixels between the icon and the text


/*
	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_PICTURE, "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 char * _ev_GetLabelName(XAP_Win32App * pWin32App,
									 XAP_Frame * pFrame, 
									 const EV_EditEventMapper * pEEM,
									 const EV_Menu_Action * pAction,
									 EV_Menu_Label * pLabel)
{
	const char * szLabelName;
	
	if (pAction->hasDynamicLabel())
		szLabelName = pAction->getDynamicLabel(pLabel);
	else
		szLabelName = pLabel->getMenuLabel();

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

	UT_String str = AP_Win32App::s_fromUTF8ToWinLocale(szLabelName);
	szLabelName = str.c_str();

	
	const char * szShortcut = NULL;
	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_ASSERT(pEMC);

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

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

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

	static char buf[128];
	memset(buf,0,NrElements(buf));
	strncpy(buf,szLabelName,NrElements(buf)-len);

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

	// append shortcut mnemonic, if any
	if (szShortcut && *szShortcut)
	{
		strcat(buf, "\t");
		strcat(buf, szShortcut);
	}
										  
	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)
{
		    
	NONCLIENTMETRICSA ncm;
	ncm.cbSize = sizeof (NONCLIENTMETRICSA);
	m_bTrack = false;

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

	m_nBitmapCX = m_nBitmapCY = 24;	// Default value overwritten later

	UT_RGBColor color;
	HBITMAP hBitmap = EV_Win32Menu::_loadBitmap(s_bitmaps[0].id, m_nBitmapCX, m_nBitmapCY, color);
	
	if (hBitmap)	/* Default size for bitmaps*/
	{
		BITMAP bitmap;
		
		if (GetObjectA(hBitmap, sizeof(BITMAP), &bitmap))
		{
			m_nBitmapCX = bitmap.bmWidth+2;
			m_nBitmapCY = bitmap.bmHeight+2;
		}

		DeleteObject(hBitmap);
	}						
	
}

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
		
}

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_ASSERT(pMenuActionSet);

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

	const char * szMethodName = pAction->getMethodName();
	UT_ASSERT(szMethodName);
	if (!szMethodName)
		return false;
	
	const EV_EditMethodContainer * pEMC = m_pWin32App->getEditMethodContainer();
	UT_ASSERT(pEMC);

	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;
	UT_uint32 tmp = 0;
	
	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_ASSERT(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 char * 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 = (UINT) sub;					
					
					if (szLabelName && *szLabelName)					
					{
						EV_Menu_Item*	item = new EV_Menu_Item;
						item->id = id;					
						item->pMenu= this;							
						
						strcpy (item->szText, szLabelName);					
						m_vecItems.addItem(item);
							
						if (!m_bTrack && stack.getDepth()==2)
							AppendMenu(m, flags,u, szLabelName);																	
						else
							AppendMenu(m, flags|MF_OWNERDRAW,u, (const char*) item);
					}		
						
				}
				else
				{					
					if (szLabelName && *szLabelName)
					{		  
						EV_Menu_Item*	item = new EV_Menu_Item;
						item->id = id;
						item->pMenu= this;						
						strcpy (item->szText, szLabelName);																						
						m_vecItems.addItem(item);
						
						AppendMenu(m, MF_OWNERDRAW , u, (const char*) item);// TODO: Parameter four, right cast												
					}
				}

				
			}
			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);

				AppendMenu(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(0);
			break;
		}
	}

#ifdef UT_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_uint32 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.
				
				MENUITEMINFO mif;
				char bufMIF[128];
				mif.cbSize = sizeof(mif);
				mif.dwTypeData = bufMIF;
				mif.cch = NrElements(bufMIF)-1;
				mif.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID;
				BOOL bPresent = GetMenuItemInfo(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 char * 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_uint32 i = 0; i< m_vecItems.getItemCount(); i++)
					{
						item = (EV_Menu_Item*)m_vecItems.getNthItem(i);
						if (id==item->id)
						{
							strcpy (item->szText, szLabelName);					
							//UT_DEBUGMSG(("Menu changing text->%s\n",szLabelName));
							break;
						}
					}
				}
				else	
				{
					EV_Menu_Item*	item = new EV_Menu_Item;
					item->id = id;					
					item->pMenu= this;													
					strcpy (item->szText, szLabelName);					
					m_vecItems.addItem(item);
					//UT_DEBUGMSG(("Menu adding menu->%s\n",szLabelName));
					AppendMenu(m, MF_OWNERDRAW,cmd, (const char*) 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(0);
			break;
		}
	}

#ifdef UT_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 x, int y, 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;	

	AP_Win32Toolbar_Icons::getBitmapForIcon(GetDesktopWindow(), x,y, &color, pBitmaps->szName,	&hBitmap);					
	
	return 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 (int i=0; i<(sizeof(ids)/sizeof(XAP_Menu_Id)); i++)
	{
		if (ids[i]==id)
		{		
			
			MENUITEMINFO menuInfo;	 
			memset (&menuInfo, 0, sizeof(MENUITEMINFO));
			menuInfo.cbSize = sizeof(MENUITEMINFO);
			menuInfo.fMask = MIIM_DATA;
			GetMenuItemInfo(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 
	GetTextExtentPoint32(hdc, item->szText, lstrlen(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;
	MENUITEMINFO	menuInfo;
	int nItems = GetMenuItemCount(hMenu);
	char szBuff[1024];
	
	for (int i=0; i<nItems; i++)
	{					
		memset (&menuInfo, 0, sizeof(MENUITEMINFO));
		menuInfo.cbSize = sizeof(MENUITEMINFO);
		menuInfo.fMask = MIIM_DATA;

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

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

		if (item)
		{
			strcpy (szBuff, item->szText);
			strlwr(szBuff);			

			char* pHotKeyPos = strchr (szBuff, '&');
				
			if (pHotKeyPos)
			{								
				char n = (char)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;
	int x = 255, y=255;									
	RECT rect;
	UT_String sTextRight, sTextLeft;
	HBITMAP hBitmap;	
	int colorID;
	UT_ASSERT(lpdis->CtlType==ODT_MENU); 						

	/* Rect to draw the text */	
	rect.top =  lpdis->rcItem.top;
	rect.right = lpdis->rcItem.right;
	rect.bottom = lpdis->rcItem.bottom;
	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,  x, y, Color);			

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

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

	rect.left = rect.left + SPACE_ICONTEXT;  
	
	// 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
	*/	
	char* pTabPos = strchr (item->szText, '\t');

	if (pTabPos)
	{
		char szTmp[255];
		char* pTmp;
		int nLen = strlen(item->szText);
		
		strncpy (szTmp, item->szText, pTabPos-item->szText);
		pTmp = szTmp; pTmp+=pTabPos-item->szText; *pTmp=NULL;
		sTextLeft = szTmp;
		
		strcpy (szTmp, pTabPos+1);
		sTextRight = szTmp;
		sTextRight +="  ";
	}
	else
		sTextLeft = item->szText;		
	
	if (lpdis->itemState & ODS_SELECTED) 
		crBkgnd = SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));

	/* Draw text*/
	DrawText(lpdis->hDC, sTextLeft.c_str(),  sTextLeft.length() , &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

	if (sTextRight.length())
		DrawText(lpdis->hDC, sTextRight.c_str(), sTextRight.length(), &rect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);

	if (lpdis->itemState & ODS_SELECTED) 
		SetBkColor(lpdis->hDC, crBkgnd); 
	
	/* Draw bitmap*/
	if (hBitmap)
	{	
					  		
		HDC hdcMem = CreateCompatibleDC(lpdis->hDC);
		SelectObject(hdcMem,(void *)hBitmap);				
		BitBlt(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, 16, 16, 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);			
        
			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.";
	
	UT_String str = AP_Win32App::s_fromUTF8ToWinLocale(szMsg);
	pFrame->setStatusMessage(str.c_str());
	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();

	return (synthesizeMenu(pFrame, m_myMenu));
}

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

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();

	return synthesizeMenu(pFrame, m_myMenu);
}