gusucode.com > VC++模仿QQ界面风格源码程序 > VC++模仿QQ界面风格/GfxPopupMenu.cpp
// GfxPopupMenu.cpp: implementation of the CGfxPopupMenu class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "GfxPopupMenu.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CGfxPopupMenu::CGfxPopupMenu() { 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; szImage = CSize(20,20); 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 } CGfxPopupMenu::~CGfxPopupMenu() { 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 CGfxPopupMenu::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); 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); else pDC->FillSolidRect(rc, crHighlight); ocr = pDC->SetTextColor(crMenuTextSel); } 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 ); } } 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; 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 CGfxPopupMenu::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; } } } } } bool CGfxPopupMenu::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 CGfxPopupMenu::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; i<pTBData->wItemCount; 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 CGfxPopupMenu::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; i<pTBData->wItemCount; 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 CGfxPopupMenu::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 CGfxPopupMenu::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 --; } CGfxPopupMenu::SpawnItem * CGfxPopupMenu::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 CGfxPopupMenu::FindImageItem(const int cmd) { for (int t = 0; t < iImageItem; t++) if (pImageItem[t].iCmd == cmd) return pImageItem[t].iImageIdx; return -1; } void CGfxPopupMenu::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; } }