?? coolmenu.cpp
字號:
CString right;
int iTabPos = left.Find('\t');
if (iTabPos >= 0) {
right = left.Right(left.GetLength() - iTabPos - 1);
left = left.Left(iTabPos);
}
dc.SetTextColor(color);
dc.DrawText(left, &rc, DT_MYSTANDARD);
if (iTabPos > 0)
dc.DrawText(right, &rc, DT_MYSTANDARD|DT_RIGHT);
}
#ifndef OBM_CHECK
#define OBM_CHECK 32760 // from winuser.h
#endif
//////////////////
// Draw 3D checkmark
//
// dc device context to draw in
// rc rectangle to center bitmap in
// bSelected TRUE if button is also selected
// hbmCheck Checkmark bitmap to use, or NULL for default
//
BOOL CCoolMenuManager::Draw3DCheckmark(CDC& dc, const CRect& rc,
BOOL bSelected, HBITMAP hbmCheck)
{
// get checkmark bitmap if none, use Windows standard
if (!hbmCheck) {
CBitmap bm;
VERIFY(bm.LoadOEMBitmap(OBM_CHECK));
hbmCheck = (HBITMAP)bm.Detach();
ASSERT(hbmCheck);
}
// center bitmap in caller's rectangle
BITMAP bm;
::GetObject(hbmCheck, sizeof(bm), &bm);
int cx = bm.bmWidth;
int cy = bm.bmHeight;
CRect rcDest = rc;
CPoint p(0,0);
CSize delta(CPoint((rc.Width() - cx)/2, (rc.Height() - cy)/2));
if (rc.Width() > cx)
rcDest = CRect(rc.TopLeft() + delta, CSize(cx, cy));
else
p -= delta;
// select checkmark into memory DC
CDC memdc;
memdc.CreateCompatibleDC(&dc);
HBITMAP hOldBM = (HBITMAP)::SelectObject(memdc, hbmCheck);
// set BG color based on selected state
COLORREF colorOld =
dc.SetBkColor(GetSysColor(bSelected ? COLOR_MENU : COLOR_3DLIGHT));
dc.BitBlt(rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
&memdc, p.x, p.y, SRCCOPY);
dc.SetBkColor(colorOld);
::SelectObject(memdc, hOldBM); // restore
// draw pushed-in hilight.
if (rc.Width() > cx) // if room:
rcDest.InflateRect(1,1); // inflate checkmark by one pixel all around
dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
return TRUE;
}
//////////////////
// Handle WM_INITMENUPOPUP on behalf of frame.
//
void CCoolMenuManager::OnInitMenuPopup(CMenu* pMenu,
UINT nIndex, BOOL bSysMenu)
{
if (m_bAutoAccel) {
// check for new accels. If ASSERT bombs, you forgot
//to call Install.
ASSERT_VALID(m_pFrame);
HACCEL hAccel = m_pFrame->GetDefaultAccelerator();
if (hAccel != m_hAccel)
LoadAccel(hAccel);
}
// Wang Jun
if (!bSysMenu) { //Check if Click system menu
ConvertMenu(pMenu, nIndex, bSysMenu, m_bShowButtons);
}
}
//////////////////
// Set the accelerator table used to generate automatic key
// names in menus. Delete previous table if any.
//
void CCoolMenuManager::LoadAccel(HACCEL hAccel)
{
DestroyAccel();
int nAccel;
if (hAccel && (nAccel = CopyAcceleratorTable(hAccel, NULL, 0)) > 0) {
m_pAccel = new ACCEL [nAccel];
ASSERT(m_pAccel);
CopyAcceleratorTable(hAccel, m_pAccel, nAccel);
// Now I have the accelerators. Look over list, linking each command
// ID with its ACCEL structure--i.e., m_mapIDtoAccel[nID] = ACCEL for
// that ID. If more than one ACCEL for a given command (command has more
// than one shortcut), fix up so ACCEL.cmd is offset of prev ACCEL
//
for (int i=0; i<nAccel; i++) {
ACCEL& ac = m_pAccel[i];
ACCEL* pAccel = GetAccel(ac.cmd);
m_mapIDtoAccel.SetAt(ac.cmd, &ac);
ac.cmd = pAccel ? &ac - pAccel : 0; // ac.cmd = offset of prev, or 0
}
}
}
//////////////////
// This rather gnarly function is used both to convert the menu from strings to
// owner-draw and vice versa. In either case, it also appends automagic
// accelerator key names to the menu items, if m_bAutoAccel is TRUE.
//
void CCoolMenuManager::ConvertMenu(CMenu* pMenu,
UINT nIndex, BOOL bSysMenu, BOOL bShowButtons)
{
ASSERT_VALID(pMenu);
CString sItemName;
UINT nItem = pMenu->GetMenuItemCount();
for (UINT i = 0; i < nItem; i++) { // loop over each item in menu
// get menu item info
char itemname[256];
CMenuItemInfo info;
info.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_ID | MIIM_TYPE;
info.dwTypeData = itemname;
info.cch = sizeof(itemname);
::GetMenuItemInfo(*pMenu, i, TRUE, &info);
CMyItemData* pmd = (CMyItemData*)info.dwItemData;
if (pmd && !pmd->IsMyItemData()) {
CMTRACE(_T("CCoolMenuManager: ignoring foreign owner-draw item\n"));
continue; // owner-draw menu item isn't mine--leave it alone
}
if (bSysMenu && info.wID >= 0xF000) {
CMTRACE(_T("CCoolMenuManager: ignoring sys menu item\n"));
continue; // don't do for system menu commands
}
// now that I have the info, I will modify it
info.fMask = 0; // assume nothing to change
if (bShowButtons) {
// I'm showing buttons: convert to owner-draw
if (!(info.fType & MFT_OWNERDRAW)) {
// If not already owner-draw, make it so. NOTE: If app calls
// pCmdUI->SetText to change the text of a menu item, MFC will
// turn the item to MFT_STRING. So I must set it back to
// MFT_OWNERDRAW again. In this case, the menu item data (pmd)
// will still be there.
//
info.fType |= MFT_OWNERDRAW;
info.fMask |= MIIM_TYPE;
if (!pmd) { // if no item data:
pmd = new CMyItemData; // create one
ASSERT(pmd); // (I hope)
pmd->fType = info.fType; // handy when drawing
pmd->iButton = GetButtonIndex(info.wID);
info.dwItemData = (DWORD)pmd; // set in menu item data
info.fMask |= MIIM_DATA; // set item data
}
pmd->text = info.dwTypeData; // copy menu item string
}
// now add the menu to list of "converted" menus
HMENU hmenu = pMenu->GetSafeHmenu();
ASSERT(hmenu);
if (!m_menuList.Find(hmenu))
m_menuList.AddHead(hmenu);
// append accelerators to menu item name
if (m_pAccel && m_bAutoAccel)
AppendAccelName(pmd->text, info.wID);
} else {
// no buttons -- I'm converting to strings
if (info.fType & MFT_OWNERDRAW) { // if ownerdraw:
info.fType &= ~MFT_OWNERDRAW; // turn it off
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
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('&');
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);
}
}
}
//////////////////
// 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');
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));
sItemName += 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= PxLib::LoadSysColorBitmap(nBitmapID);
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 PxLib::LoadSysColorBitmap(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 PxLib::FillRect(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);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -