// CustMenu.cpp: implementation of the CMenuXP class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MenuXP.h"
#include "KeyHelper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// constants used for drawing
const CXGAP = 0; // num pixels between button and text
const CXTEXTMARGIN = 2; // num pixels after hilite to start text
const CXBUTTONMARGIN = 2; // num pixels wider button is than bitmap
const CYBUTTONMARGIN = 2; // ditto for height
// DrawText flags
const DT_MYSTANDARD = DT_SINGLELINE|DT_LEFT|DT_VCENTER;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CMenuXP, CMenu)
CMenuXP::CMenuXP()
{
//initialize menu font with the default
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
VERIFY(m_fontMenu.CreateFontIndirect(&info.lfMenuFont));
//initialize colors with system default
m_clrBackGround = ::GetSysColor(COLOR_MENU);
m_clrSelectedBar = ::GetSysColor(COLOR_HIGHLIGHT);
m_clrSelectedText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
m_clrText = ::GetSysColor(COLOR_MENUTEXT);
m_clrDisabledText = ::GetSysColor(COLOR_GRAYTEXT);
m_clrIconArea = m_clrBackGround;
//initialize sidebar colors
m_clrSideBarStart = RGB(0, 0, 192);
m_clrSideBarEnd = RGB(0, 0, 0);
m_clrSideBarStart = RGB(130, 170, 255);
m_clrSideBarEnd = RGB(6, 8, 60);
//the default sytle is office style
m_Style = STYLE_OFFICE;
m_bBreak = false;
m_bBreakBar = false;
m_hBitmap = NULL;
}
CMenuXP::~CMenuXP()
{
m_fontMenu.DeleteObject();
Clear();
}
void CMenuXP::MeasureItem( LPMEASUREITEMSTRUCT lpms )
{
if (lpms->CtlType != ODT_MENU)
return;
CMenuXPItem *pItem = (CMenuXPItem *)lpms->itemData;
TRACE("pItem: 0x%x",(DWORD)pItem); //This line prevent boundschecker from issue a resource leak
if (!pItem)
return;
if (pItem->m_bSideBar)
{
lpms->itemWidth = pItem->m_nSize;
lpms->itemHeight = 0;
}
else if (pItem->m_bSeparator)
{
// separator: use half system height and zero width
lpms->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK)>>1;
lpms->itemWidth = 0;
}
else
{
//calculate the size needed to draw the text: use DrawText with DT_CALCRECT
CWindowDC dc(NULL); // screen DC--I won't actually draw on it
CRect rcText(0,0,0,0);
CFont* pOldFont = dc.SelectObject(&m_fontMenu);
dc.DrawText(pItem->m_strText, rcText, DT_MYSTANDARD|DT_CALCRECT);
dc.SelectObject(pOldFont);
// the height of the item should be the maximun of the text and the button
lpms->itemHeight = max(rcText.Height(), pItem->m_nSize + (CYBUTTONMARGIN<<1));
if (pItem->m_bButtonOnly)
{ //for button only style, we set the item's width to be the same as its height
lpms->itemWidth = lpms->itemHeight;
}
else
{
// width is width of text plus a bunch of stuff
int cx = rcText.Width(); // text width
cx += CXTEXTMARGIN<<1; // L/R margin for readability
cx += CXGAP; // space between button and menu text
cx += (pItem->m_nSize + CYBUTTONMARGIN * 2) <<1; // button width (L=button; R=empty margin)
lpms->itemWidth = cx; // done deal
}
}
// whatever value I return in lpms->itemWidth, Windows will add the
// width of a menu checkmark, so I must subtract to defeat Windows. Argh.
//
lpms->itemWidth -= GetSystemMetrics(SM_CXMENUCHECK)-1;
TRACE("MeasureItem: ID(%d), Width(%d), Height(%d)\n",
lpms->itemID,
lpms->itemWidth, lpms->itemHeight);
}
// 自绘制菜单项
void CMenuXP::DrawItem( LPDRAWITEMSTRUCT lpds )
{
ASSERT(lpds);
// 若不是菜单项,返回
if (lpds->CtlType != ODT_MENU) return;
// 得到菜单项绘制所需数据
CMenuXPItem * pItem = (CMenuXPItem *)lpds->itemData;
if (!pItem)
return;
ASSERT(lpds->itemAction != ODA_FOCUS);
ASSERT(lpds->hDC);
CDC dc;
dc.Attach(lpds->hDC);
//取得绘制区域
CRect rcItem = lpds->rcItem;
TRACE("DrawItem: ID(%d), Widht(%d), Height(%d)\n",
lpds->itemID, rcItem.Width(), rcItem.Height());
if (pItem->m_bSideBar)
{
CRect rcClipBox;
dc.GetClipBox(rcClipBox);
// 绘制菜单标题栏
CRect rc = rcItem;
rc.top = rcClipBox.top;
rc.bottom = rcClipBox.bottom;
DrawSideBar(&dc, rc, pItem->m_hIcon, pItem->m_strText);
}
else if (pItem->m_bSeparator)
{
// 绘制菜单背景
DrawBackGround(&dc, rcItem, FALSE, FALSE);
CRect rc = rcItem; // 复制区域
rc.top += rc.Height()>>1; // 垂直居中
dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // 绘制分割线
// 在菜单项的图标区中填充背景颜色
if (m_Style == STYLE_XP)
{
CRect rcArea(rcItem.TopLeft(),
CSize(pItem->m_nSize + (CYBUTTONMARGIN<<1),
pItem->m_nSize + (CYBUTTONMARGIN<<1)));
DrawIconArea(&dc, rcArea, FALSE, FALSE, FALSE);
}
}
else
{
BOOL bDisabled = lpds->itemState & ODS_GRAYED;
BOOL bSelected = lpds->itemState & ODS_SELECTED;
BOOL bChecked = lpds->itemState & ODS_CHECKED;
// 绘制菜单背景
DrawBackGround(&dc, rcItem, bSelected, bDisabled);
// 绘制菜单项中的图标
if (m_Style == STYLE_XP)
{
CRect rcArea(rcItem.TopLeft(), CSize(rcItem.Height(), rcItem.Height()));
DrawIconArea(&dc, rcArea, bSelected, bDisabled, bChecked);
}
// 绘制菜单项中的按钮
CRect rcButton(rcItem.TopLeft(), CSize(rcItem.Height(), rcItem.Height()));
if (pItem->m_bButtonOnly)
rcButton = rcItem;
if (pItem->m_hIcon || bChecked)
{
DrawButton(&dc, rcButton, bSelected, bDisabled, bChecked);
}
// 绘制菜单项中图标
if (pItem->m_hIcon)
{
CRect rcIcon = rcButton;
rcIcon.DeflateRect(2, 2);
DrawIcon(&dc, rcIcon, pItem->m_hIcon, bSelected, bDisabled, bChecked);
}
else if (bChecked)
{
// 绘制Check Mark
CRect rcCheck = rcButton;
rcCheck.DeflateRect(2, 2);
DrawCheckMark(&dc, rcCheck, bSelected);
}
// 绘制菜单项文本
if (!pItem->m_bButtonOnly)
{
CRect rcText = rcItem; // 复制区域
rcText.left += rcButton.Width() + CXGAP + CXTEXTMARGIN; // 左空白区宽
rcText.right -= pItem->m_nSize; // 右空白区宽
DrawText(&dc, rcText, pItem->m_strText, bSelected, bDisabled, lpds->itemState&ODS_DEFAULT ? 1 : 0);
}
}
dc.Detach();
}
//draw background
void CMenuXP::DrawBackGround(CDC *pDC, CRect rect, BOOL bSelected, BOOL bDisabled)
{
if (m_hBitmap && (!bSelected || bDisabled))
{
pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &m_memDC,
0, rect.top, SRCCOPY);
}
else if (bSelected)
{
FillRect(pDC, rect, bDisabled? ((m_Style==STYLE_XP)?m_clrBackGround:m_clrSelectedBar) : m_clrSelectedBar);
}
else
{
FillRect(pDC, rect, m_clrBackGround);
}
//in XP mode, draw a line rectangle around
if (m_Style == STYLE_XP && bSelected && !bDisabled)
{
CGdiObject *pOldBrush = pDC->SelectStockObject(HOLLOW_BRUSH);
CGdiObject *pOldPen = pDC->SelectStockObject(BLACK_PEN);
pDC->Rectangle(rect);
pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
}
}
//draw the icon button, the icon is not included
void CMenuXP::DrawButton(CDC *pDC, CRect rect, BOOL bSelected, BOOL bDisabled, BOOL bChecked)
{
if (m_Style == STYLE_OFFICE)
{
// normal: fill BG depending on state
FillRect(pDC, rect, (bChecked && !bSelected) ? m_clrBackGround+RGB(2, 2, 2) : m_clrBackGround);
// draw pushed-in or popped-out edge
if (!bDisabled && (bSelected || bChecked) )
{
pDC->DrawEdge(rect, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER,
BF_RECT);
}
}
else if (m_Style == STYLE_XP && !bSelected)
{
if (bChecked && !bDisabled)
{
DrawBackGround(pDC, rect, TRUE, FALSE);
}
}
}
//draw the icon area, the icon is not included, only in XP style
void CMenuXP::Dr
评论0