📄 menuext.cpp
字号:
#include "stdafx.h"
#include "MenuExt.h"
#include <afxpriv.h> //makes A2W and other spiffy AFX macros work
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define GAP 1
#ifndef OBM_CHECK
#define OBM_CHECK 32760 // from winuser.h
#endif
#if _MFC_VER <0x400
#error This code does not work on Versions of MFC prior to 4.0
#endif
static CPINFO CPInfo;
enum Win32Type{ Win32s, Windoze95, WinNT3, WinNT4orHigher };
Win32Type IsShellType()
{
Win32Type ShellType;
DWORD winVer;
OSVERSIONINFO *osvi;
winVer = GetVersion(); //获得版本信息
if(winVer < 0x80000000) //NT
{
ShellType = WinNT3;
osvi = new OSVERSIONINFO;
if(osvi != NULL)
{
memset(osvi,0,sizeof(OSVERSIONINFO));
osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(osvi);
if(osvi->dwMajorVersion >= 4L)
ShellType=WinNT4orHigher; //NT4或以上
delete osvi;
}
}
else if(LOBYTE(LOWORD(winVer)) < 4)
ShellType = Win32s; //Win32s
else
ShellType = Windoze95; //Windoze95
return ShellType;
}
static Win32Type g_Shell = IsShellType();
void CMenuExtData::SetAnsiString(LPCSTR szAnsiString)
{
USES_CONVERSION;
SetWideString(A2W(szAnsiString));
}
CString CMenuExtData::GetString()
{
CString strText;
if (m_szMenuText)
{
#ifdef UNICODE
strText = m_szMenuText;
#else
USES_CONVERSION;
strText=W2A(m_szMenuText);
#endif
}
return strText;
}
CTypedPtrArray<CPtrArray, HMENU> CMenuExt::m_AllSubMenus;
CMenuExt::CMenuExt()
{
m_bDynIcons = FALSE; // O.S. - no dynamic icons by default
disable_old_style = FALSE;
m_iconX = 16; //缺省的小图标为16*16
m_iconY = 15;
m_selectcheck = -1;
m_unselectcheck = -1;
checkmaps = NULL;
checkmapsshare = FALSE;
// 设置位图背景颜色
m_bitmapBackground = RGB(192,192,192);
m_bitmapBackgroundFlag = FALSE;
GetCPInfo(CP_ACP,&CPInfo);
}
CMenuExt::~CMenuExt()
{
DestroyMenu();
}
BOOL CMenuExt::IsNewShell()
{
return (Windoze95 == g_Shell || WinNT4orHigher == g_Shell);
}
CMenuExtData::~CMenuExtData()
{
if(bitmap) delete(bitmap);
delete[] m_szMenuText;
}
void CMenuExtData::SetWideString(const wchar_t *szWideString)
{
delete[] m_szMenuText;
if (szWideString)
{
// 根据实际的字符串长度来拷贝
m_szMenuText = new wchar_t[sizeof(wchar_t) * (wcslen(szWideString)+1)];
if (m_szMenuText)
wcscpy(m_szMenuText,szWideString);
}
else
m_szMenuText=NULL;
}
BOOL CMenuExt::IsMenu(CMenu *submenu)
{
int nSubMenus = m_AllSubMenus.GetUpperBound();
for(int i=0;i<=nSubMenus;++i)
{
// 在所有的菜单列表中搜索菜单项
if(submenu->m_hMenu == m_AllSubMenus[i]) return TRUE;
}
return FALSE;
}
BOOL CMenuExt::IsMenu(HMENU submenu)
{
int nSubMenus = m_AllSubMenus.GetUpperBound();
for(int i=0;i<=nSubMenus;++i)
{
// 在所有的菜单列表中搜索菜单项
if(submenu == m_AllSubMenus[i]) return TRUE;
}
return FALSE;
}
BOOL CMenuExt::DestroyMenu()
{
int numAllSubMenus = m_AllSubMenus.GetUpperBound();
for(int i=numAllSubMenus;i>=0;i--)
{
if(m_AllSubMenus[i] == this->m_hMenu) m_AllSubMenus.RemoveAt(i);
}
int numSubMenus = m_SubMenus.GetUpperBound();
for(int j=numSubMenus;j>=0;j--)
{
numAllSubMenus = m_AllSubMenus.GetUpperBound();
for(i=numAllSubMenus;i>=0;i--)
{
if(m_AllSubMenus[i] == m_SubMenus[j])m_AllSubMenus.RemoveAt(i);
}
delete((CMenuExt *)FromHandle(m_SubMenus[j]));
}
m_SubMenus.RemoveAll();
int numItems = m_MenuList.GetUpperBound();
for(j=0;j<=numItems;j++) delete(m_MenuList[j]);
m_MenuList.RemoveAll();
if(checkmaps && !checkmapsshare)
{
delete checkmaps;
checkmaps = NULL;
}
return CMenu::DestroyMenu();
}
///////////////////////////////////////////////////////////////////////////
//
// CMenuExt message handlers
void CMenuExt::DrawItem (LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CRect rect;
UINT state = ((CMenuExtData*)(lpDIS->itemData))->nFlags;
if(state & MF_SEPARATOR)
{
rect.CopyRect(&lpDIS->rcItem);
rect.top+=rect.Height()>>1;
pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
}
else
{
CRect rect2;
BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
BOOL checkflag=FALSE;
COLORREF crText = GetSysColor(COLOR_MENUTEXT);
COLORREF m_clrBack=GetSysColor(COLOR_MENU);
CBrush m_brBackground,m_brSelect;
CPen m_penBack;
int x0,y0,dy;
int nIconNormal=-1,xoffset=-1;
CImageList *bitmap=NULL;
CFont m_fontMenu;
LOGFONT m_lf;
m_penBack.CreatePen (PS_SOLID,0,GetSysColor(COLOR_MENU));
m_brBackground.CreateSolidBrush(GetSysColor(COLOR_MENU));
m_brSelect.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
NONCLIENTMETRICS nm;
nm.cbSize = sizeof (NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0);
m_lf = nm.lfMenuFont;
m_fontMenu.CreateFontIndirect (&m_lf);
rect.CopyRect(&lpDIS->rcItem);
rect2=rect;
// 画up/down/focused/disabled状态
UINT action = lpDIS->itemAction;
UINT state = lpDIS->itemState;
CString strText;
LOGFONT lf;
lf = m_lf;
CFont dispFont;
CFont *pFont=NULL;
if(lpDIS->itemData != NULL)
{
nIconNormal = (((CMenuExtData*)(lpDIS->itemData))->menuIconNormal);
xoffset = (((CMenuExtData*)(lpDIS->itemData))->xoffset);
bitmap = (((CMenuExtData*)(lpDIS->itemData))->bitmap);
strText = ((CMenuExtData*) (lpDIS->itemData))->GetString();
if(state&ODS_CHECKED && nIconNormal<0)
{
if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
else if(m_unselectcheck>0) checkflag=TRUE;
}
else if(nIconNormal != -1)
{
standardflag=TRUE;
if(state&ODS_SELECTED && !(state&ODS_GRAYED)) selectedflag = TRUE;
else if(state&ODS_GRAYED) disableflag = TRUE;
}
}
else
{
strText.Empty();
}
if(state&ODS_SELECTED) //画出下边缘
{
CPen *pOldPen = pDC->SelectObject (&m_penBack);
// You need only Text highlight and thats what you get
if(checkflag||standardflag||selectedflag||disableflag||state&ODS_CHECKED)
rect2.SetRect(rect.left+m_iconX+4+GAP,rect.top,rect.right,rect.bottom);
pDC->FillRect (rect2,&m_brSelect);
pDC->SelectObject (pOldPen);
if((HFONT)dispFont != NULL)dispFont.DeleteObject();
dispFont.CreateFontIndirect(&lf);
crText = GetSysColor(COLOR_HIGHLIGHTTEXT);
}
else
{
CPen *pOldPen = pDC->SelectObject (&m_penBack);
pDC->FillRect (rect,&m_brBackground);
pDC->SelectObject (pOldPen);
//画出上边缘
pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
if((HFONT)dispFont != NULL) dispFont.DeleteObject();
dispFont.CreateFontIndirect (&lf); //正常
}
// draw the text if there is any
//We have to paint the text only if the image is nonexistant
dy = (rect.Height()-4-m_iconY)/2;
dy = dy<0 ? 0 : dy;
if(checkflag||standardflag||selectedflag||disableflag)
{
rect2.SetRect(rect.left+1,rect.top+1+dy,rect.left+m_iconX+3,
rect.top+m_iconY+3+dy);
pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
if(checkflag && checkmaps){
pDC->FillRect (rect2,&m_brBackground);
rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
rect.top+m_iconY+4+dy);
pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
CPoint ptImage(rect.left+2,rect.top+2+dy);
if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
}
else if(disableflag)
{
if(!selectedflag)
{
CBitmap bitmapstandard;
GetBitmapFromImageList(pDC,bitmap,xoffset,bitmapstandard);
rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
rect.top+m_iconY+4+dy);
pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
if(disable_old_style)
DitherBlt(lpDIS->hDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
(HBITMAP)(bitmapstandard),0,0);
else
DitherBlt2(pDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
bitmapstandard,0,0);
bitmapstandard.DeleteObject();
}
}
else if(selectedflag)
{
pDC->FillRect (rect2,&m_brBackground);
rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
rect.top+m_iconY+4+dy);
if (IsNewShell())
{
if(state&ODS_CHECKED)
pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
GetSysColor(COLOR_3DHILIGHT));
else
pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DHILIGHT),
GetSysColor(COLOR_3DSHADOW));
}
CPoint ptImage(rect.left+2,rect.top+2+dy);
if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
}
else
{
if(state&ODS_CHECKED)
{
CBrush brush;
COLORREF col =GetSysColor(COLOR_3DLIGHT);
brush.CreateSolidBrush(col);
pDC->FillRect(rect2,&brush);
brush.DeleteObject();
rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
rect.top+m_iconY+4+dy);
if (IsNewShell())
pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
GetSysColor(COLOR_3DHILIGHT));
}
else
{
pDC->FillRect (rect2,&m_brBackground);
rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
rect.top+m_iconY+4+dy);
pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
}
CPoint ptImage(rect.left+2,rect.top+2+dy);
if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
}
}
if(nIconNormal<0 && state&ODS_CHECKED && !checkflag)
{
rect2.SetRect(rect.left+1,rect.top+2+dy,rect.left+m_iconX+1,
rect.top+m_iconY+2+dy);
CMenuItemInfo info;
info.fMask = MIIM_CHECKMARKS;
::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
MF_BYCOMMAND, &info);
if(state&ODS_CHECKED || info.hbmpUnchecked)
{
Draw3DCheckmark(pDC, rect2, state&ODS_SELECTED,
state&ODS_CHECKED ? info.hbmpChecked :
info.hbmpUnchecked);
}
}
//This is needed always so that we can have the space for check marks
x0=rect.left;y0=rect.top;
rect.left = rect.left + m_iconX + 8 + GAP;
if(!strText.IsEmpty())
{
CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);
// 查找tab
CString leftStr,rightStr;
leftStr.Empty();rightStr.Empty();
int tablocr=strText.ReverseFind(_T('\t'));
if(tablocr!=-1)
{
rightStr=strText.Mid(tablocr+1);
leftStr=strText.Left(strText.Find(_T('\t')));
rectt.right-=m_iconX;
}
else leftStr=strText;
int iOldMode = pDC->GetBkMode();
pDC->SetBkMode( TRANSPARENT);
// 显示文本
UINT nFormat = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
if(!(lpDIS->itemState & ODS_GRAYED))
{
pDC->SetTextColor(crText);
pDC->DrawText (leftStr,rectt,nFormat);
if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
}
else
{
// disabled文本
if(!(state & ODS_SELECTED))
{
RECT offset = *rectt;
offset.left+=1;
offset.right+=1;
offset.top+=1;
offset.bottom+=1;
pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));
pDC->DrawText(leftStr,&offset, nFormat);
if(tablocr!=-1) pDC->DrawText (rightStr,&offset,nFormatr);
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
pDC->DrawText(leftStr,rectt, nFormat);
if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
}
else
{
// 标准的Grey文本
pDC->SetTextColor(m_clrBack);
pDC->DrawText(leftStr,rectt, nFormat);
if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
}
}
pFont = pDC->SelectObject(&dispFont);
pDC->SetBkMode(iOldMode);
pDC->SelectObject(pFont);
}
m_penBack.DeleteObject();
m_brBackground.DeleteObject();
m_fontMenu.DeleteObject();
m_brSelect.DeleteObject();
dispFont.DeleteObject ();
}
}
BOOL CMenuExt::GetBitmapFromImageList(CDC* pDC,CImageList *imglist,int nIndex,CBitmap &bmp)
{
CDC dc;
dc.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC,m_iconX,m_iconY);
CBitmap* pOldBmp = dc.SelectObject(&bmp);
CBrush brush ;
brush.CreateSolidBrush(GetSysColor(COLOR_MENU));
HICON hIcon = imglist->ExtractIcon(nIndex);
::DrawIconEx(dc.GetSafeHdc(),0,0,hIcon,m_iconX,m_iconY,0,(HBRUSH)brush,DI_NORMAL);
dc.SelectObject(pOldBmp);
dc.DeleteDC();
DestroyIcon(hIcon);
return TRUE;
}
/*
当框架窗口想要知道自定义菜单项的尺寸时被调用.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -