📄 coolmenu.cpp
字号:
info.fMask |= MIIM_TYPE; // change item type
ASSERT(pmd); // sanity check
sItemName = pmd->text; // save name before deleting pmd
} else // otherwise:
sItemName = info.dwTypeData; // use name from MENUITEMINFO
if (pmd) {
// NOTE: pmd (item data) could still be left hanging around even
// if MFT_OWNERDRAW is not set, in case mentioned above where app
// calls pCmdUI->SetText to set text of item and MFC sets the type
// to MFT_STRING.
//
info.dwItemData = NULL; // item data is NULL
info.fMask |= MIIM_DATA; // change it
safe_delete(pmd); // and item data too
}
// possibly add accelerator name
if (m_pAccel && m_bAutoAccel && AppendAccelName(sItemName, info.wID))
info.fMask |= MIIM_TYPE; // change item type (string)
if (info.fMask & MIIM_TYPE) {
// if setting name, copy name from CString to buffer and set cch
strncpy(itemname, sItemName, sizeof(itemname));
info.dwTypeData = itemname;
info.cch = sItemName.GetLength();
}
}
// if after all the above, there is anything to change, change it
if (info.fMask) {
CMTRACE(_T("Converting '%s' to %s\n"), itemname,
(info.fType & MFT_OWNERDRAW) ? _T("OWNERDRAW") : _T("STRING"));
SetMenuItemInfo(*pMenu, i, TRUE, &info);
}
}
}
//////////////////
// User typed a char into menu. Look for item with & preceeding the char typed.
//
LRESULT CCoolMenuManager::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu)
{
ASSERT_VALID(pMenu);
UINT iCurrentItem = (UINT)-1; // guaranteed higher than any command ID
CUIntArray arItemsMatched; // items that match the character typed
UINT nItem = pMenu->GetMenuItemCount();
for (UINT i=0; i< nItem; i++) {
// get menu info
CMenuItemInfo info;
info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
::GetMenuItemInfo(*pMenu, i, TRUE, &info);
CMyItemData* pmd = (CMyItemData*)info.dwItemData;
if ((info.fType & MFT_OWNERDRAW) && pmd && pmd->IsMyItemData()) {
CString& text = pmd->text;
int iAmpersand = text.Find(_T('&'));
if (iAmpersand >=0 && toupper(nChar)==toupper(text[iAmpersand+1]))
arItemsMatched.Add(i);
}
if (info.fState & MFS_HILITE)
iCurrentItem = i; // note index of current item
}
// arItemsMatched now contains indexes of items that match the char typed.
//
// * if none: beep
// * if one: execute it
// * if more than one: hilite next
//
UINT nFound = arItemsMatched.GetSize();
if (nFound == 0)
return 0;
else if (nFound==1)
return MAKELONG(arItemsMatched[0], MNC_EXECUTE);
// more than one found--return 1st one past current selected item;
UINT iSelect = 0;
for (i=0; i < nFound; i++) {
if (arItemsMatched[i] > iCurrentItem) {
iSelect = i;
break;
}
}
return MAKELONG(arItemsMatched[iSelect], MNC_SELECT);
}
//////////////////
// Handle WM_MENUSELECT: check for menu closed
//
void CCoolMenuManager::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
{
if (hSysMenu==NULL && nFlags==0xFFFF) {
// Windows has closed the menu: restore all menus to original state
while (!m_menuList.IsEmpty()) {
ConvertMenu(CMenu::FromHandle((HMENU)m_menuList.RemoveHead()),
0, FALSE, FALSE);
}
}
}
// fix for virtual key names - Seain Conover (1999/01/09)
CString CCoolMenuManager::GetVirtualKeyName( const CString strVirtKey ) const
{
CString strResult;
if ( strVirtKey == _T("Num 7")) { strResult = _T("Home"); }
else if ( strVirtKey == _T("Num 1")) { strResult = _T("End"); }
else if ( strVirtKey == _T("Num 9")) { strResult = _T("PgUp"); }
else if ( strVirtKey == _T("Num 3")) { strResult = _T("PgDn"); }
else if ( strVirtKey == _T("Num 0")) { strResult = _T("Ins"); }
else if ( strVirtKey == _T("Num Del")) { strResult = _T("Del"); }
else
{
strResult = strVirtKey;
}
return strResult;
}
//////////////////
// Append the name of accelerator for given command ID to menu string.
// sItemName is menu item name, which will have the accelerator appended.
// For example, might call with sItemName = "File &Open" and return with
// sItemName = "File &Open\tCtrl-O". Returns BOOL = whether string changed.
//
BOOL CCoolMenuManager::AppendAccelName(CString& sItemName, UINT nID)
{
/* int iTabPos = sItemName.Find(_T('\t'));
if (iTabPos > 0)
sItemName = sItemName.Left(iTabPos);
*/
BOOL bFound = FALSE;/*
for (ACCEL* pa = GetAccel(nID); pa; pa -= pa->cmd) {
sItemName += bFound ? _T(", ") : _T("\t");
if (pa->fVirt & FALT) sItemName += _T("Alt+");
if (pa->fVirt & FCONTROL) sItemName += _T("Ctrl+");
if (pa->fVirt & FSHIFT) sItemName += _T("Shift+");
if (pa->fVirt & FVIRTKEY) {
TCHAR keyname[64];
UINT vkey = MapVirtualKey(pa->key, 0)<<16;
GetKeyNameText(vkey, keyname, sizeof(keyname));
// Seain Conover (1999/01/09)
sItemName += GetVirtualKeyName( keyname );
} else
sItemName += (char)pa->key;
bFound = TRUE;
if (pa->cmd == 0)
break;
}*/
return bFound;
}
//////////////////
// This function fixes MFC's diseased dot bitmap used for
// "radio-style" menu items (CCmdUI->SetRadio), which is completely
// wrong if the menu font is large.
//
void CCoolMenuManager::FixMFCDotBitmap()
{
HBITMAP hbmDot = GetMFCDotBitmap();
if (hbmDot) {
// Draw a centered dot of appropriate size
BITMAP bm;
::GetObject(hbmDot, sizeof(bm), &bm);
CRect rcDot(0,0, bm.bmWidth, bm.bmHeight);
rcDot.DeflateRect((bm.bmWidth>>1)-2, (bm.bmHeight>>1)-2);
CWindowDC dcScreen(NULL);
CDC memdc;
memdc.CreateCompatibleDC(&dcScreen);
int nSave = memdc.SaveDC();
memdc.SelectStockObject(BLACK_PEN);
memdc.SelectStockObject(BLACK_BRUSH);
memdc.SelectObject((HGDIOBJ)hbmDot);
memdc.PatBlt(0, 0, bm.bmWidth, bm.bmHeight, WHITENESS);
memdc.Ellipse(&rcDot);
memdc.RestoreDC(nSave);
}
}
//////////////////
// This function gets MFC's dot bitmap.
//
HBITMAP CCoolMenuManager::GetMFCDotBitmap()
{
// The bitmap is stored in afxData.hbmMenuDot, but afxData is MFC-private,
// so the only way to get it is create a menu, set the radio check,
// and then see what bitmap MFC set in the menu item.
CMenu menu;
VERIFY(menu.CreateMenu());
VERIFY(menu.AppendMenu(MFT_STRING, 0, (LPCTSTR)NULL));
CCmdUI cui;
cui.m_pMenu = &menu;
cui.m_nIndex = 0;
cui.m_nIndexMax = 1;
cui.SetRadio(TRUE);
CMenuItemInfo info;
info.fMask = MIIM_CHECKMARKS;
GetMenuItemInfo(menu, 0, MF_BYPOSITION, &info);
HBITMAP hbmDot = info.hbmpChecked;
menu.DestroyMenu();
return hbmDot;
}
// Peter Tewkesbury
BOOL CCoolMenuManager::AddSingleBitmap(UINT nBitmapID, UINT n, UINT *nID)
{
// load bitmap
HBITMAP hbmBitmap = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(nBitmapID), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
ASSERT(hbmBitmap);
if (!hbmBitmap) {
TRACE(_T("*** Can't load bitmap %d!\n"), nBitmapID);
return FALSE;
}
// Assign Bitmap to CBitmap
CBitmap bmBitmap;
bmBitmap.Attach(hbmBitmap); // destructor will detach & destroy
// OK, I have the bitmap - Check that Bitmaps are correct size.
if (m_szBitmap.cx==0)
{
// First toolbar: initialized bitmap/button sizes and create image list.
CSize sz(16,15);
m_szBitmap = sz;
m_szButton = sz + CSize(CXBUTTONMARGIN<<1, CYBUTTONMARGIN<<1);
VERIFY(m_ilButtons.Create(sz.cx, sz.cy, ILC_MASK, 0, 10));
}
// Add Bitmap to ImageList
int iNextImage = m_ilButtons.GetImageCount();
m_ilButtons.Add(&bmBitmap, GetSysColor(COLOR_3DFACE));
// Add ID to Map.
for(UINT i=0;i<n;i++)
{
if (nID[i] > 0)
{
if (GetButtonIndex(nID[i]) >= 0)
{
TRACE(_T("*** Duplicate button ID %d ignored\n"), nID[i]);
}
else m_mapIDtoImage.SetAt(nID[i], (void*)iNextImage++);
}
}
// All Done.
return TRUE;
}
////////////////////////////////////////////////////////////////
// Helper functions
//////////////////
// Load a bitmap, converting the standard colors.
// Calls AfxLoadSysColorBitmap to do the work.
//
// RGB(0x00, 0x00, 0x00) (black) --> COLOR_BTNTEXT
// RGB(0x80, 0x80, 0x80) (dark gray) --> COLOR_3DSHADOW
// RGB(0xC0, 0xC0, 0xC0) (gray) --> COLOR_3DFACE
// RGB(0xFF, 0xFF, 0xFF) (white) --> COLOR_3DHILIGHT
//
HBITMAP PLLoadSysColorBitmap(LPCTSTR lpResName, BOOL bMono)
{
HINSTANCE hInst = AfxFindResourceHandle(lpResName, RT_BITMAP);
HRSRC hRsrc = ::FindResource(hInst, lpResName, RT_BITMAP);
if (hRsrc == NULL)
return NULL;
return AfxLoadSysColorBitmap(hInst, hRsrc, bMono);
}
//////////////////
// Shorthand to fill a rectangle with a solid color.
//
void PLFillRect(CDC& dc, const CRect& rc, COLORREF color)
{
CBrush brush(color);
CBrush* pOldBrush = dc.SelectObject(&brush);
dc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
dc.SelectObject(pOldBrush);
}
// This is the magic ROP code used to generate the embossed look for
// a disabled button. It's listed in Appendix F of the Win32 Programmer's
// Reference as PSDPxax (!) which is a cryptic reverse-polish notation for
//
// ((Destination XOR Pattern) AND Source) XOR Pattern
//
// which I leave to you to figure out. In the case where I apply it,
// Source is a monochrome bitmap which I want to draw in such a way that
// the black pixels get transformed to the brush color and the white pixels
// draw transparently--i.e. leave the Destination alone.
//
// black ==> Pattern (brush)
// white ==> Destintation (ie, transparent)
//
// 0xb8074a is the ROP code that does this. For more info, see Charles
// Petzold, _Programming Windows_, 2nd Edition, p 622-624.
//
#define TRANSPARENTROP 0xb8074a
//////////////////
// Draw an image with the embossed (disabled) look.
//
// dc device context to draw in
// il image list containing image
// i index of image to draw
// p point in dc to draw image at
// bColor do color embossing. Default is B/W.
//
void PLDrawEmbossed(CDC& dc, CImageList& il, int i,
CPoint p, BOOL bColor)
{
IMAGEINFO info;
VERIFY(il.GetImageInfo(0, &info));
CRect rc = info.rcImage;
int cx = rc.Width();
int cy = rc.Height();
// create memory dc
CDC memdc;
memdc.CreateCompatibleDC(&dc);
// create mono or color bitmap
CBitmap bm;
if (bColor)
bm.CreateCompatibleBitmap(&dc, cx, cy);
else
bm.CreateBitmap(cx, cy, 1, 1, NULL);
// draw image into memory DC--fill BG white first
CBitmap* pOldBitmap = memdc.SelectObject(&bm);
memdc.PatBlt(0, 0, cx, cy, WHITENESS);
il.Draw(&memdc, i, CPoint(0,0), ILD_TRANSPARENT);
// This seems to be required. Why, I don't know. ???
COLORREF colorOldBG = dc.SetBkColor(RGB(255,255,255)); // white
// Draw using hilite offset by (1,1), then shadow
CBrush brShadow(GetSysColor(COLOR_3DSHADOW));
CBrush brHilite(GetSysColor(COLOR_3DHIGHLIGHT));
CBrush* pOldBrush = dc.SelectObject(&brHilite);
dc.BitBlt(p.x+1, p.y+1, cx, cy, &memdc, 0, 0, TRANSPARENTROP);
dc.SelectObject(&brShadow);
dc.BitBlt(p.x, p.y, cx, cy, &memdc, 0, 0, TRANSPARENTROP);
dc.SelectObject(pOldBrush);
dc.SetBkColor(colorOldBG); // restore
memdc.SelectObject(pOldBitmap); // ...
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -