www.pudn.com > 200308141526117224仿MSN(网易泡泡)界面.rar > CNPopupMenu.cpp


// GfxPopupMenu.cpp: implementation of the CNPopupMenu class. 
// 
// Modified a lot by Zhang Yong 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
 
#include "CNPopupMenu.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CNPopupMenu::CNPopupMenu() 
{ 
	crMenuText = GetSysColor(COLOR_MENUTEXT); 
	crMenuTextSel = GetSysColor(COLOR_HIGHLIGHTTEXT); 
 
	cr3dFace = GetSysColor(COLOR_3DFACE); 
	crMenu = GetSysColor(COLOR_MENU); 
	crHighlight = GetSysColor(COLOR_HIGHLIGHT); 
	cr3dHilight = GetSysColor(COLOR_3DHILIGHT); 
	cr3dShadow = GetSysColor(COLOR_3DSHADOW); 
	crGrayText = GetSysColor(COLOR_GRAYTEXT); 
 
	m_clrBtnFace = GetSysColor(COLOR_BTNFACE); 
	m_clrBtnHilight = GetSysColor(COLOR_BTNHILIGHT); 
	m_clrBtnShadow = GetSysColor(COLOR_BTNSHADOW); 
 
	iSpawnItem = 0; 
	pSpawnItem = NULL; 
 
	iImageItem = 0; 
	pImageItem = NULL; 
 
	hMenuFont = NULL; 
/*	COLORMAP cMap[3] = {  
		{ RGB(128,128,128), cr3dShadow },  
		{ RGB(192,192,192), cr3dFace },  
		{ RGB(255,255,255), cr3dHilight } 
	}; 
	CBitmap bmp; 
	bmp.LoadMappedBitmap(IDB_MENUCHK, 0, cMap, 3); 
	ilOther.Create(19, 19, ILC_COLOR4|ILC_MASK, 1, 0); 
	ilOther.Add(&bmp, cr3dFace); 
	bmp.DeleteObject(); 
*/ 
	NONCLIENTMETRICS ncm; 
	memset(&ncm, 0, sizeof(ncm)); 
	ncm.cbSize = sizeof(ncm); 
 
	::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0); 
 
	hGuiFont = ::CreateFontIndirect(&ncm.lfMenuFont); 
 
	// David 08/04/98 - start - bold font handling 
	hMenuBoldFont = NULL; 
	CreateBoldFont(); 
	// David 08/04/98 - end - bold font handling 
 
	ilList.Create(16, 16, ILC_MASK | ILC_COLOR8, 5, 15); 
	szImage = CSize(16, 16); 
 
	// @@ 
	vertDrawn = FALSE; 
} 
 
CNPopupMenu::~CNPopupMenu() 
{ 
	if (iSpawnItem > 0) 
	{ 
		for (int t = 0; t < iSpawnItem; t++) 
			if (pSpawnItem[t]) delete pSpawnItem[t]; 
 
		GlobalFree((HGLOBAL) pSpawnItem); 
	} 
	if (iImageItem > 0) 
	{ 
		GlobalFree((HGLOBAL) pImageItem); 
	} 
	if (hMenuFont) ::DeleteObject((HGDIOBJ)hMenuFont); 
	if (hMenuBoldFont) ::DeleteObject((HGDIOBJ)hMenuBoldFont); 
} 
 
void CNPopupMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{ 
//	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); 
//	CRect rcItem(lpDrawItemStruct->rcItem); 
//	pDC->FillSolidRect(rcItem, RGB(255,0,0)); 
	if (lpDrawItemStruct->CtlType == ODT_MENU) 
	{ 
		UINT id = lpDrawItemStruct->itemID; 
		UINT state = lpDrawItemStruct->itemState; 
		bool bEnab = !(state & ODS_DISABLED); 
		bool bSelect = (state & ODS_SELECTED) ? true : false; 
		bool bChecked = (state & ODS_CHECKED) ? true : false; 
		// David 08/04/98 - start - bold font handling 
		bool bBold = (state & ODS_DEFAULT) ? true : false; 
		// David 08/04/98 - end - bold font handling 
 
		SpawnItem * pItem = (SpawnItem *) lpDrawItemStruct->itemData; 
		if (pItem) 
		{ 
			CDC * pDC = CDC::FromHandle(lpDrawItemStruct->hDC); 
			CFont * pft; 
			// David 08/04/98 - start - bold font handling 
			if (!bBold) pft = CFont::FromHandle((HFONT) hMenuFont ? hMenuFont : hGuiFont); 
			else pft = CFont::FromHandle((HFONT) hMenuBoldFont ? hMenuBoldFont : hGuiFont); 
			// David 08/04/98 - end - bold font handling 
			CFont * of = pDC->SelectObject(pft); 
 
			CRect rc(lpDrawItemStruct->rcItem); 
 
			// @@ 
			if (bmVert.m_hObject) { 
				BITMAP bm; 
				bmVert.GetBitmap(&bm); 
				if ((lpDrawItemStruct->itemAction & ODA_DRAWENTIRE) && !vertDrawn) { 
					vertDrawn = TRUE; 
 
					CDC dcMem; 
					dcMem.CreateCompatibleDC(pDC); 
					CBitmap *bmOld = dcMem.SelectObject(&bmVert); 
					pDC->SelectClipRgn(NULL); 
					CRect rcWhole; 
					pDC->GetClipBox(rcWhole); 
					pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMem, 
						0, bm.bmHeight - rcWhole.Height(), SRCCOPY); 
				} 
				rc.left += bm.bmWidth; 
			} 
 
			CRect rcImage(rc), rcText(rc); 
			rcImage.right = rcImage.left + rc.Height(); 
			rcImage.bottom = rc.bottom; 
 
			if (pItem->iCmd == -3) // is a separator 
			{ 
				CPen pnDk(PS_SOLID,1,cr3dShadow); 
				CPen pnLt(PS_SOLID,1,cr3dHilight); 
				CPen * opn = pDC->SelectObject(&pnDk); 
				pDC->MoveTo(rc.left + 2, rc.top + 2); 
				pDC->LineTo(rc.right - 2, rc.top + 2); 
				pDC->SelectObject(&pnLt); 
				pDC->MoveTo(rc.left + 2, rc.top + 3); 
				pDC->LineTo(rc.right - 2, rc.top + 3); 
				pDC->SelectObject(opn); 
			} 
/*			else if (pItem->iCmd == -4) // is a title item 
			{ 
				CString cs(pItem->cText), cs1; 
				CRect rcBdr(rcText); 
 
				if (bSelect && bEnab) 
				{ 
					rcText.top ++; 
					rcText.left += 2; 
				} 
				pDC->FillSolidRect(rcText, crMenu); 
				pDC->DrawText(cs, rcText, DT_VCENTER|DT_CENTER|DT_SINGLELINE); 
				if (bSelect && bEnab) pDC->Draw3dRect(rcBdr,cr3dShadow,cr3dHilight); 
			}*/ 
			else 
			{ 
				rcText.left = rcImage.right + 1; 
 
				int obk = pDC->SetBkMode(TRANSPARENT); 
				 
				COLORREF ocr; 
				if (bSelect) 
				{ 
					if (pItem->iImageIdx >= 0 || (state & ODS_CHECKED)) 
						//pDC->FillSolidRect(rcText, crHighlight); 
						pDC->Draw3dRect(rcText, cr3dShadow, cr3dHilight);	// @@ 
					else 
						//pDC->FillSolidRect(rc, crHighlight); 
						pDC->Draw3dRect(rc, cr3dShadow, cr3dHilight);		// @@ 
 
					//ocr = pDC->SetTextColor(crMenuTextSel); 
					ocr = pDC->SetTextColor(crHighlight);	// @@ 
				} 
				else 
				{ 
					if (pItem->iImageIdx >= 0 || (state & ODS_CHECKED)) 
						pDC->FillSolidRect(rcText, crMenu); 
					else 
						pDC->FillSolidRect(rc/*rcText*/, crMenu); 
					ocr = pDC->SetTextColor(crMenuText); 
				} 
 
				if (pItem->iImageIdx >= 0) 
				{ 
					int ay = (rcImage.Height() - szImage.cy) / 2; 
					int ax = (rcImage.Width()  - szImage.cx) / 2; 
 
					if (bSelect && bEnab) 
						pDC->Draw3dRect(rcImage,cr3dHilight,cr3dShadow); 
					else 
					{ 
						pDC->Draw3dRect(rcImage,crMenu,crMenu); 
					} 
 
 
					if (bEnab) 
					{ 
						ilList.Draw(pDC, pItem->iImageIdx, CPoint(rcImage.left + ax, rcImage.top +ay), ILD_NORMAL); 
					} 
					else 
					{ 
						HICON hIcon = ilList.ExtractIcon( pItem->iImageIdx ); 
						pDC->DrawState( CPoint(rcImage.left + ax, rcImage.top + ay ), szImage, (HICON)hIcon, DST_ICON | DSS_DISABLED, (CBrush *)NULL ); 
						DestroyIcon(hIcon);		// @@ 
					} 
				} 
				else 
				{ 
					if (bChecked) 
					{ 
						int ay = (rcImage.Height() - szImage.cy) / 2; 
						int ax = (rcImage.Width()  - szImage.cx) / 2; 
 
						ilOther.Draw(pDC, 0, CPoint(rcImage.left + ax, rcImage.top + ay - 2), ILD_NORMAL); 
					} 
				} 
 
				CString cs(pItem->cText), cs1; 
				if (cs.Compare("dummy") == 0) 
					pItem = pItem; 
 
				CSize sz; 
				sz = pDC->GetTextExtent(cs); 
				int ay1 = (rcText.Height() - sz.cy) / 2; 
				rcText.top += ay1; 
				rcText.left += 2; 
				rcText.right -= 15; 
 
				int tf = cs.Find('\t'); 
				if (tf >= 0) 
				{ 
					cs1 = cs.Right(cs.GetLength() - tf - 1); 
					cs = cs.Left(tf); 
					if (!bEnab) 
					{ 
						if (!bSelect) 
						{ 
							CRect rcText1(rcText); 
							rcText1.InflateRect(-1,-1); 
							pDC->SetTextColor(cr3dHilight); 
							pDC->DrawText(cs, rcText1, DT_VCENTER|DT_LEFT); 
							pDC->DrawText(cs1, rcText1, DT_VCENTER|DT_RIGHT); 
							pDC->SetTextColor(crGrayText); 
							pDC->DrawText(cs, rcText, DT_VCENTER|DT_LEFT); 
							pDC->DrawText(cs1, rcText, DT_VCENTER|DT_RIGHT); 
						} 
						else 
						{ 
							pDC->SetTextColor(crMenu); 
							pDC->DrawText(cs, rcText, DT_VCENTER|DT_LEFT); 
							pDC->DrawText(cs1, rcText, DT_VCENTER|DT_RIGHT); 
						} 
					} 
					else 
					{ 
						pDC->DrawText(cs, rcText, DT_VCENTER|DT_LEFT); 
						pDC->DrawText(cs1, rcText, DT_VCENTER|DT_RIGHT); 
					} 
				} 
				else  
				{ 
					if (!bEnab) 
					{ 
//						if (!bSelect)	// @@ 
						{ 
							CRect rcText1(rcText); 
							rcText1.InflateRect(-1,-1); 
							pDC->SetTextColor(cr3dHilight); 
							pDC->DrawText(cs, rcText1, DT_VCENTER|DT_LEFT|DT_EXPANDTABS); 
							pDC->SetTextColor(crGrayText); 
							pDC->DrawText(cs, rcText, DT_VCENTER|DT_LEFT|DT_EXPANDTABS); 
						} 
/*						else 
						{ 
							pDC->SetTextColor(crMenu); 
							pDC->DrawText(cs, rcText, DT_VCENTER|DT_LEFT|DT_EXPANDTABS); 
						}*/ 
					} 
					else 
						pDC->DrawText(cs, rcText, DT_VCENTER|DT_LEFT|DT_EXPANDTABS); 
				} 
				pDC->SetTextColor(ocr); 
				pDC->SetBkMode(obk); 
			} 
 
			pDC->SelectObject(of); 
		} 
	} 
} 
 
void CNPopupMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{ 
//	lpMeasureItemStruct->itemWidth = 200; 
//	lpMeasureItemStruct->itemHeight = 25; 
	bool res = false; 
	if (lpMeasureItemStruct->CtlType == ODT_MENU) 
	{ 
		UINT id = lpMeasureItemStruct->itemID; 
 
		SpawnItem * pItem = (SpawnItem *) lpMeasureItemStruct->itemData; 
		if (pItem) 
		{ 
			if (pItem->iCmd == -3) // is a separator 
			{ 
				lpMeasureItemStruct->itemWidth  = 10; 
				lpMeasureItemStruct->itemHeight = 6; 
			} 
			else 
			{ 
				CString cs(pItem->cText); 
				if (!cs.IsEmpty()) 
				{ 
					CClientDC dc(AfxGetMainWnd()); 
					CFont * pft = CFont::FromHandle(hMenuFont ? hMenuFont : hGuiFont); 
					CFont * of = dc.SelectObject(pft); 
					CSize osz = dc.GetOutputTabbedTextExtent(cs,0,NULL); 
					// @@ 
					/*if (pItem->iCmd == -4) 
					{ 
						CRect rci(0,0,0,0); 
						dc.DrawText(cs, rci, DT_CALCRECT|DT_TOP|DT_VCENTER|DT_SINGLELINE); 
						lpMeasureItemStruct->itemHeight = rci.Height(); 
						lpMeasureItemStruct->itemWidth = rci.Width(); 
					} 
					else*/ 
					{ 
						lpMeasureItemStruct->itemHeight = szImage.cy + 5; 
						if (osz.cy > (int) lpMeasureItemStruct->itemHeight) lpMeasureItemStruct->itemHeight = (int) osz.cy; 
						lpMeasureItemStruct->itemWidth  = osz.cx + 2 + 15; 
						lpMeasureItemStruct->itemWidth += lpMeasureItemStruct->itemHeight > (UINT) szImage.cx ? (UINT) lpMeasureItemStruct->itemHeight : (UINT) szImage.cx; 
					} 
					dc.SelectObject(of); 
				} 
				else 
				{ 
					lpMeasureItemStruct->itemHeight = szImage.cy + 5; 
					lpMeasureItemStruct->itemWidth  = 100; 
				} 
			} 
			if (bmVert.m_hObject) { 
				BITMAP bm; 
				bmVert.GetBitmap(&bm); 
				lpMeasureItemStruct->itemWidth += bm.bmWidth; 
			} 
		} 
	} 
} 
 
bool CNPopupMenu::CreateBoldFont() 
{ 
	if (hMenuBoldFont)  
		::DeleteObject((HGDIOBJ)hMenuBoldFont); 
 
	LOGFONT lgFont; 
	::GetObject (hMenuFont ? hMenuFont : hGuiFont, sizeof (lgFont), &lgFont); 
	lgFont.lfWeight = FW_BOLD; 
 
	hMenuBoldFont = CreateFontIndirect (&lgFont); 
	return !!hMenuBoldFont; 
} 
 
bool CNPopupMenu::AddToolBarResource(unsigned int resId) 
{ 
	// David 08/04/98 - start - put CMenuSpawn in DLL 
	HINSTANCE hInst = AfxFindResourceHandle (MAKEINTRESOURCE(resId), RT_TOOLBAR); 
	if (!hInst) 
		return false; 
	// David 08/04/98 - end - put CMenuSpawn in DLL 
 
	HRSRC hRsrc = ::FindResource(/*AfxGetResourceHandle()*/hInst, MAKEINTRESOURCE(resId), RT_TOOLBAR); 
	if (hRsrc == NULL) return false; 
 
	HGLOBAL hGlb = ::LoadResource(/*AfxGetResourceHandle()*/hInst, hRsrc); 
	if (hGlb == NULL) return false; 
 
 
	ToolBarData* pTBData = (ToolBarData*) ::LockResource(hGlb); 
	if (pTBData == NULL) return false; 
	 
	ASSERT(pTBData->wVersion == 1); 
 
	CBitmap bmp; 
	bmp.LoadBitmap(resId); 
	int nBmpItems = ilList.Add(&bmp, RGB(192,192,192)); 
	bmp.DeleteObject(); 
 
	WORD* pItem = (WORD*)(pTBData+1); 
	 
	for(int i=0; iwItemCount; i++, pItem++) 
	{ 
		if(*pItem != ID_SEPARATOR) 
			AddImageItem(nBmpItems++, (WORD) *pItem); 
	} 
// ** it seem that Windows doesn't free these resource (from Heitor Tome) 
    ::UnlockResource(hGlb); 
    ::FreeResource(hGlb); 
// ** 
	return true; 
} 
 
bool CNPopupMenu::LoadToolBarResource(unsigned int resId) 
{ 
	//David 08/04/98 - start - put CMenuSpawn in DLL 
	HINSTANCE hInst = AfxFindResourceHandle (MAKEINTRESOURCE(resId), RT_TOOLBAR); 
	if (!hInst) 
		return false; 
	//David 08/04/98 - end - put CMenuSpawn in DLL 
 
	HRSRC hRsrc = ::FindResource(/*AfxGetResourceHandle()*/hInst, MAKEINTRESOURCE(resId), RT_TOOLBAR); 
	if (hRsrc == NULL) return false; 
 
	HGLOBAL hGlb = ::LoadResource(/*AfxGetResourceHandle()*/hInst, hRsrc); 
	if (hGlb == NULL) return false; 
 
	ToolBarData* pTBData = (ToolBarData*) ::LockResource(hGlb); 
	if (pTBData == NULL) return false; 
	 
	ASSERT(pTBData->wVersion == 1); 
 
	szImage.cx = (int) pTBData->wWidth; 
	szImage.cy = (int) pTBData->wHeight; 
 
	if (ilList.Create(szImage.cx, szImage.cy, ILC_COLOR4|ILC_MASK, pTBData->wItemCount, 0) == false) 
		return false; 
 
	ilList.SetBkColor(cr3dFace); 
 
	CBitmap bmp; 
	bmp.LoadBitmap(resId); 
	ilList.Add(&bmp, RGB(192,192,192)); 
	bmp.DeleteObject(); 
 
	WORD* pItem = (WORD*)(pTBData+1); 
	int nBmpItems = 0; 
	for(int i=0; iwItemCount; i++, pItem++) 
	{ 
		if(*pItem != ID_SEPARATOR) 
			AddImageItem(nBmpItems++, (WORD) *pItem); 
	} 
// ** it seem that Windows doesn't free these resource (from Heitor Tome) 
    ::UnlockResource(hGlb); 
    ::FreeResource(hGlb); 
// ** 
	return true; 
} 
 
void CNPopupMenu::AddImageItem(const int idx, WORD cmd) 
{ 
	if (iImageItem == 0) 
		pImageItem = (ImageItem *) GlobalAlloc(GPTR, sizeof(ImageItem)); 
	else 
		pImageItem = (ImageItem *) GlobalReAlloc((HGLOBAL) pImageItem, sizeof(ImageItem) * (iImageItem + 1), GMEM_MOVEABLE|GMEM_ZEROINIT); 
	 
	ASSERT(pImageItem); 
	pImageItem[iImageItem].iCmd = (int) cmd; 
	pImageItem[iImageItem].iImageIdx = idx; 
	iImageItem ++; 
} 
 
void CNPopupMenu::RemapMenu(CMenu * pMenu) 
{ 
	static int iRecurse = 0; 
	iRecurse ++; 
 
	ASSERT(pMenu); 
	int nItem = pMenu->GetMenuItemCount(); 
	while ((--nItem)>=0) 
	{ 
		UINT itemId = pMenu->GetMenuItemID(nItem); 
		if (itemId == (UINT) -1) 
		{ 
			CMenu *pops = pMenu->GetSubMenu(nItem); 
			if (pops) 
				RemapMenu(pops); 
			if (iRecurse > 0) 
			{ 
				CString cs; 
				pMenu->GetMenuString(nItem, cs, MF_BYPOSITION); 
				if (cs != "") 
				{ 
					SpawnItem * sp = AddSpawnItem(cs, (iRecurse == 1) ? -4 : -2); 
					pMenu->ModifyMenu(nItem,MF_BYPOSITION|MF_OWNERDRAW, (UINT) -1, (LPCTSTR)sp); 
				} 
			} 
		} 
		else 
		{ 
			if (itemId != 0) 
			{ 
				UINT oldState = pMenu->GetMenuState(nItem,MF_BYPOSITION); 
				if (!(oldState&MF_OWNERDRAW) && !(oldState&MF_BITMAP)) 
				{ 
					ASSERT(oldState != (UINT)-1); 
					CString cs; 
					pMenu->GetMenuString(nItem, cs, MF_BYPOSITION); 
					SpawnItem * sp = AddSpawnItem(cs, itemId); 
					pMenu->ModifyMenu(nItem,MF_BYPOSITION|MF_OWNERDRAW|oldState, (LPARAM)itemId, (LPCTSTR)sp); 
				} 
			} 
			else 
			{ 
				UINT oldState = pMenu->GetMenuState(nItem,MF_BYPOSITION); 
				if (!(oldState&MF_OWNERDRAW) && !(oldState&MF_BITMAP)) 
				{ 
					ASSERT(oldState != (UINT)-1); 
					SpawnItem * sp = AddSpawnItem("--", -3); 
					pMenu->ModifyMenu(nItem,MF_BYPOSITION|MF_OWNERDRAW|oldState, (LPARAM)itemId, (LPCTSTR)sp); 
				} 
			} 
		} 
	} 
	iRecurse --; 
} 
 
CNPopupMenu::SpawnItem * CNPopupMenu::AddSpawnItem(const char * txt, const int cmd) 
{ 
	if (iSpawnItem == 0) 
		pSpawnItem = (SpawnItem **) GlobalAlloc(GPTR, sizeof(SpawnItem)); 
	else 
		pSpawnItem = (SpawnItem **) GlobalReAlloc((HGLOBAL) pSpawnItem, sizeof(SpawnItem) * (iSpawnItem + 1), GMEM_MOVEABLE|GMEM_ZEROINIT); 
 
	ASSERT(pSpawnItem); 
 
	SpawnItem * p = new SpawnItem; 
	ASSERT(p); 
	pSpawnItem[iSpawnItem] = p; 
	lstrcpy(p->cText, txt); 
	p->iCmd = cmd; 
 
	if (cmd >= 0) p->iImageIdx = FindImageItem(cmd); 
	else p->iImageIdx = cmd; 
 
	iSpawnItem ++; 
	return p; 
} 
 
int CNPopupMenu::FindImageItem(const int cmd) 
{ 
	for (int t = 0; t < iImageItem; t++) 
		if (pImageItem[t].iCmd == cmd) return pImageItem[t].iImageIdx; 
 
	return -1; 
} 
 
void CNPopupMenu::EnableMenuItems(CMenu * pMenu, CWnd * pParent) 
{ 
	ASSERT(pMenu); 
	ASSERT(pParent); 
 
	int nItem = pMenu->GetMenuItemCount(); 
	CCmdUI state; 
	state.m_pMenu = pMenu; 
	state.m_nIndex = nItem-1; 
	state.m_nIndexMax = nItem; 
 
	while ((--nItem)>=0) 
	{ 
		UINT itemId = pMenu->GetMenuItemID(nItem); 
		if (itemId == (UINT) -1) 
		{ 
			CMenu *pops = pMenu->GetSubMenu(nItem); 
			if (pops) EnableMenuItems(pops, pParent); 
		} 
		else 
		{ 
			if (itemId != 0) 
			{ 
				state.m_nID = itemId; 
				pParent->OnCmdMsg(itemId, CN_UPDATE_COMMAND_UI, &state, NULL); 
				state.DoUpdate(pParent, true); 
			} 
		} 
		state.m_nIndex = nItem-1; 
	} 
} 
 
void CNPopupMenu::modifyMenu(UINT itemId, UINT bitmap, BOOL byCmd) 
{ 
	int index; 
	if (!imageHash.Lookup(bitmap, index)) { 
		CBitmap bm; 
		bm.LoadBitmap(bitmap); 
		index = ilList.Add(&bm, RGB(192, 192, 192)); 
		imageHash.SetAt(bitmap, index); 
	} 
	modifyMenuInternal(itemId, index, byCmd); 
} 
 
void CNPopupMenu::modifyMenu(UINT itemId, HICON icon) 
{ 
	int index; 
	if (!bitmapHash.Lookup(icon, index)) { 
		index = ilList.Add(icon); 
		bitmapHash.SetAt(icon, index); 
	} 
	modifyMenuInternal(itemId, index, TRUE); 
} 
	 
void CNPopupMenu::modifyMenuInternal(UINT itemId, int imageIndex, BOOL byCmd) 
{ 
	if (byCmd) { 
		UINT oldState = GetMenuState(itemId,MF_BYCOMMAND); 
		if (!(oldState&MF_OWNERDRAW) && !(oldState&MF_BITMAP)) 
		{ 
			ASSERT(oldState != (UINT)-1); 
			CString cs; 
			GetMenuString(itemId, cs, MF_BYCOMMAND); 
			SpawnItem * sp = AddSpawnItem(cs, itemId); 
			sp->iImageIdx = imageIndex; 
			ModifyMenu(itemId,MF_BYCOMMAND|MF_OWNERDRAW|oldState, (LPARAM)itemId, (LPCTSTR)sp); 
		} 
	} else { 
		UINT nItem = itemId; 
		itemId = GetMenuItemID(nItem); 
 
		if (itemId == (UINT) -1) 
		{ 
			CString cs; 
			GetMenuString(nItem, cs, MF_BYPOSITION); 
			if (cs != "") 
			{ 
				SpawnItem * sp = AddSpawnItem(cs, -4); 
				sp->iImageIdx = imageIndex; 
				ModifyMenu(nItem,MF_BYPOSITION|MF_OWNERDRAW, (UINT) -1, (LPCTSTR)sp); 
			} 
		} 
		else 
		{ 
			if (itemId != 0) 
			{ 
				UINT oldState = GetMenuState(nItem,MF_BYPOSITION); 
				if (!(oldState&MF_OWNERDRAW) && !(oldState&MF_BITMAP)) 
				{ 
					ASSERT(oldState != (UINT)-1); 
					CString cs; 
					GetMenuString(nItem, cs, MF_BYPOSITION); 
					SpawnItem * sp = AddSpawnItem(cs, itemId); 
					sp->iImageIdx = imageIndex; 
					ModifyMenu(nItem,MF_BYPOSITION|MF_OWNERDRAW|oldState, (LPARAM)itemId, (LPCTSTR)sp); 
				} 
			} 
			else 
			{ 
				UINT oldState = GetMenuState(nItem,MF_BYPOSITION); 
				if (!(oldState&MF_OWNERDRAW) && !(oldState&MF_BITMAP)) 
				{ 
					ASSERT(oldState != (UINT)-1); 
					SpawnItem * sp = AddSpawnItem("--", -3); 
					ModifyMenu(nItem,MF_BYPOSITION|MF_OWNERDRAW|oldState, (LPARAM)itemId, (LPCTSTR)sp); 
				} 
			} 
		} 
	} 
} 
 
void CNPopupMenu::appendMenu(UINT id, UINT bitmap, LPCTSTR str) 
{ 
	AppendMenu(MF_BYCOMMAND, id, str); 
	modifyMenu(id, bitmap); 
} 
 
void CNPopupMenu::appendMenu(UINT id, UINT bitmap, UINT strID) 
{ 
	CString str; 
	str.LoadString(strID); 
	appendMenu(id, bitmap, str); 
} 
 
void CNPopupMenu::setVertBitmap(UINT bitmap) 
{ 
	for (int i = GetMenuItemCount() - 1; i >= 0; i--) { 
		if (GetMenuItemID(i) == 0) { 
			SpawnItem * sp = AddSpawnItem("--", -3); 
			ModifyMenu(i, MF_BYPOSITION | MF_OWNERDRAW | MF_SEPARATOR, 0, (LPCTSTR) sp); 
		} 
	} 
	 
	bmVert.LoadBitmap(bitmap); 
}