WTL 界面设计篇(CSkinMenu)

头文件声明(CSkinMenu.h):

#pragma once

#include "SkinManager.h"

#define SKIN_MENU_MAGIC		0x2010		// 皮肤菜单项目信息标识

struct SKIN_MENU_ITEM_INFO					// 皮肤菜单项目信息结构
{
	UINT nMagic;							// 皮肤菜单项目信息标识
	UINT nID;								// 菜单ID
	UINT nState;							// 菜单状态
	UINT nType;								// 类型
	HMENU hSubMenu;							// 子弹菜(即弹出式菜单)句柄
	TCHAR szText[256];						// 菜单项文本
	CImageEx * lpIconImgN;					// 未选中图标
	CImageEx * lpIconImgH;					// 选中图标
};

class CSkinMenu								// 皮肤菜单封装类
{
public:
	CSkinMenu(HMENU hMenu = NULL);
	~CSkinMenu(void);

public:
	BOOL SetBgPic(LPCTSTR lpszLeftBg, LPCTSTR lpszRightBg);	// 设置菜单项背景图片
	BOOL SetSelectedPic(LPCTSTR lpszFileName);		// 设置菜单项选中图片
	BOOL SetSepartorPic(LPCTSTR lpszFileName);		// 设置分隔符图片
	BOOL SetArrowPic(LPCTSTR lpszFileName);			// 设置弹出式菜单箭头图片
	BOOL SetCheckPic(LPCTSTR lpszFileName);			// 设置Check状态图片
	BOOL SetIcon(UINT nItem, BOOL bByPosition, LPCTSTR lpszIconN, LPCTSTR lpszIconH);	// 设置指定菜单项所使用的图标

	void SetTextColor(COLORREF clrText);			// 设置普通菜单文本颜色
	void SetSelTextColor(COLORREF clrSelText);		// 设置选中菜单文本颜色
	void SetGrayedTextColor(COLORREF clrGrayedText);// 设置灰化菜单文本颜色

public:
	BOOL CreateMenu();
	BOOL CreatePopupMenu();
	BOOL LoadMenu(LPCWSTR lpszResourceName);
	BOOL LoadMenu(UINT nIDResource);
	BOOL DestroyMenu();

	void OnInitMenuPopup(HMENU hMenuPopup, UINT nIndex, BOOL bSysMenu);
	void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
	void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);

	CSkinMenu& operator =(HMENU hMenu);

	BOOL Attach(HMENU hMenu);
	HMENU Detach();

	BOOL DeleteMenu(UINT nPosition, UINT nFlags);
	BOOL TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect = 0);
	BOOL TrackPopupMenuEx(UINT fuFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm);

	BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0,
		LPCTSTR lpszNewItem = NULL);
	UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck);
	UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable);
	UINT GetMenuItemCount() const;
	UINT GetMenuItemID(int nPos) const;
	UINT GetMenuState(UINT nID, UINT nFlags);
	int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags);
	CSkinMenu GetSubMenu(int nPos) const;
	BOOL InsertMenu(UINT nPosition, UINT nFlags, 
		UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL);
	BOOL ModifyMenu(UINT nPosition, UINT nFlags, 
		UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL);
	BOOL RemoveMenu(UINT nPosition, UINT nFlags);
	BOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags);

	BOOL IsMenu();

private:
	SKIN_MENU_ITEM_INFO * GetMenuItemInfo(UINT nItem, BOOL bByPosition);	// 获取指定菜单项信息数据函数
	BOOL SetMenuItemInfo(UINT nItem, BOOL bByPosition, SKIN_MENU_ITEM_INFO * lpItemInfo);	// 设置指定菜单顶信息数据函数

	BOOL EnableOwnerDraw(HMENU hMenu, BOOL bEnable);			// 使能菜单自绘风格

	SIZE GetTextExtent(LPCTSTR lpszText);						// 获取指定文字的宽高度

	void DrawBg(HDC hDC, CRect& rect);							// 绘制菜单项背景
	void DrawSepartor(HDC hDC, CRect& rect);					// 绘制分隔符
	void DrawSelRect(HDC hDC, CRect& rect);						// 填充选中区域
	void DrawIcon(HDC hDC, CRect& rect, CImageEx * lpIconImg);	// 绘制菜单图标
	void DrawCheckState(HDC hDC, CRect& rect);					// 绘制Check状态
	void DrawText(HDC hDC, CRect& rect, BOOL bGrayed,			// 绘制菜单文本
		BOOL bSelected, BOOL bIsSubMenu, LPCTSTR lpText);	
	void DrawArrow(HDC hDC, CRect& rect);						// 绘制弹出式菜单箭头

public:
	HMENU m_hMenu;							// 菜单句柄

private:
	CImageEx * m_lpBgImgL, * m_lpBgImgR;	// 菜单项背景图片
	CImageEx * m_lpSelectedImg;				// 菜单项选中图片
	CImageEx * m_lpSepartorImg;				// 分隔符图片
	CImageEx * m_lpArrowImg;				// 弹出式菜单箭头图片
	CImageEx * m_lpCheckImg;				// Check状态图片

	COLORREF m_clrText;						// 普通菜单文本颜色
	COLORREF m_clrSelText;					// 选中菜单文本颜色
	COLORREF m_clrGrayedText;				// 灰化菜单文本颜色

	HFONT m_hFont;							// 菜单字体
	int m_nLMargin;							// 左边栏宽度
};

源码定义(CSkinMenu.cpp):

#include "StdAfx.h"
#include "SkinMenu.h"

CSkinMenu::CSkinMenu(HMENU hMenu/* = NULL*/)
{
	m_hMenu = hMenu;

	m_lpBgImgL = m_lpBgImgR = NULL;
	m_lpSelectedImg = NULL;
	m_lpSepartorImg = NULL;
	m_lpArrowImg = NULL;
	m_lpCheckImg = NULL;

	m_clrText = RGB(0, 0 , 0);
	m_clrSelText = RGB(255, 255, 255);
	m_clrGrayedText = RGB(131, 136, 140);

	m_nLMargin = 28;

	NONCLIENTMETRICS ncm = {0};
	ncm.cbSize = sizeof(ncm);

	::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID)&ncm, FALSE);

	m_hFont = ::CreateFontIndirect(&ncm.lfMenuFont);
}

CSkinMenu::~CSkinMenu(void)
{
	if (m_hFont != NULL)
	{
		::DeleteObject(m_hFont);
		m_hFont = NULL;
	}
}

BOOL CSkinMenu::SetBgPic(LPCTSTR lpszLeftBg, LPCTSTR lpszRightBg)
{
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgL);
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgR);

	m_lpBgImgL = CSkinManager::GetInstance()->GetImage(lpszLeftBg);
	m_lpBgImgR = CSkinManager::GetInstance()->GetImage(lpszRightBg);

	if (NULL == m_lpBgImgL || NULL == m_lpBgImgR)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::SetSelectedPic(LPCTSTR lpszFileName)
{
	CSkinManager::GetInstance()->ReleaseImage(m_lpSelectedImg);

	m_lpSelectedImg = CSkinManager::GetInstance()->GetImage(lpszFileName);

	if (NULL == m_lpSelectedImg)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::SetSepartorPic(LPCTSTR lpszFileName)
{
	CSkinManager::GetInstance()->ReleaseImage(m_lpSepartorImg);

	m_lpSepartorImg = CSkinManager::GetInstance()->GetImage(lpszFileName);

	if (NULL == m_lpSepartorImg)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::SetArrowPic(LPCTSTR lpszFileName)
{
	CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImg);

	m_lpArrowImg = CSkinManager::GetInstance()->GetImage(lpszFileName);

	if (NULL == m_lpArrowImg)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::SetCheckPic(LPCTSTR lpszFileName)
{
	CSkinManager::GetInstance()->ReleaseImage(m_lpCheckImg);

	m_lpCheckImg = CSkinManager::GetInstance()->GetImage(lpszFileName);

	if (NULL == m_lpCheckImg)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::SetIcon(UINT nItem, BOOL bByPosition, LPCTSTR lpszIconN, LPCTSTR lpszIconH)
{
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;

	lpSkinMenuItemInfo = GetMenuItemInfo(nItem, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgN);
		CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgH);
		
		lpSkinMenuItemInfo->lpIconImgN = CSkinManager::GetInstance()->GetImage(lpszIconN);
		lpSkinMenuItemInfo->lpIconImgH = CSkinManager::GetInstance()->GetImage(lpszIconH);

		if (lpSkinMenuItemInfo->lpIconImgN != NULL && lpSkinMenuItemInfo->lpIconImgH != NULL)
			return TRUE;
	}

	return FALSE;
}

// 设置普通菜单文本颜色
void CSkinMenu::SetTextColor(COLORREF clrText)
{
	m_clrText = clrText;
}

// 设置选中菜单文本颜色
void CSkinMenu::SetSelTextColor(COLORREF clrSelText)
{
	m_clrSelText = clrSelText;
}

// 设置灰化菜单文本颜色
void CSkinMenu::SetGrayedTextColor(COLORREF clrGrayedText)
{
	m_clrGrayedText = clrGrayedText;
}

BOOL CSkinMenu::CreateMenu()
{
	if (m_hMenu != NULL)
	{
		EnableOwnerDraw(m_hMenu, FALSE);
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	}

	m_hMenu = ::CreateMenu();
	if (!m_hMenu)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::CreatePopupMenu()
{
	if (m_hMenu != NULL)
	{
		EnableOwnerDraw(m_hMenu, FALSE);
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	}

	m_hMenu = ::CreatePopupMenu();
	if (!m_hMenu)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinMenu::LoadMenu(LPCWSTR lpszResourceName)
{
	HMENU hMenu;
	BOOL bRet;

	if (m_hMenu != NULL)
	{
		EnableOwnerDraw(m_hMenu, FALSE);
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	}

	hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), lpszResourceName);
	if (!hMenu)
		return FALSE;

	bRet = EnableOwnerDraw(hMenu, TRUE);
	if (!bRet)
	{
		return FALSE;
	}
	else
	{
		m_hMenu = hMenu;
		return TRUE;
	}
}

BOOL CSkinMenu::LoadMenu(UINT nIDResource)
{
	return LoadMenu(MAKEINTRESOURCE(nIDResource));
}

BOOL CSkinMenu::DestroyMenu()
{
	if (m_hMenu != NULL)
	{
		EnableOwnerDraw(m_hMenu, FALSE);
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	}

	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgL);
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgR);
	CSkinManager::GetInstance()->ReleaseImage(m_lpSelectedImg);
	CSkinManager::GetInstance()->ReleaseImage(m_lpSepartorImg);
	CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImg);
	CSkinManager::GetInstance()->ReleaseImage(m_lpCheckImg);
	
	return TRUE;
}

void CSkinMenu::OnInitMenuPopup(HMENU hMenuPopup, UINT nIndex, BOOL bSysMenu)
{
	EnableOwnerDraw(hMenuPopup, TRUE);
}

void CSkinMenu::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	LPMEASUREITEMSTRUCT lpms;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	RECT rcText = {0};
	SIZE sz;

	lpms = lpMeasureItemStruct;
	if (!lpms || lpms->CtlType != ODT_MENU)
		return;

	lpSkinMenuItemInfo = (SKIN_MENU_ITEM_INFO *)lpms->itemData;
	if (NULL == lpSkinMenuItemInfo || lpSkinMenuItemInfo->nMagic != SKIN_MENU_MAGIC)
		return;

	if (lpSkinMenuItemInfo->nType & MFT_SEPARATOR)		// 分隔符
	{
		lpms->itemWidth = 0;
		if (m_lpSepartorImg != NULL && !m_lpSepartorImg->IsNull())
			lpms->itemHeight = m_lpSepartorImg->GetHeight();
		else
			lpms->itemHeight = 3;
	}
	else
	{
		sz = GetTextExtent(lpSkinMenuItemInfo->szText);

		lpms->itemWidth = m_nLMargin + 8 + sz.cx + 8;	// 左边栏宽度+菜单文本左边8像素+菜单文本宽度+菜单文本右边8像素
		lpms->itemHeight = 5 + sz.cy + 5;				// 菜单文本上边5像素+菜单文本高度+菜单文本下边5像素

		if (lpSkinMenuItemInfo->hSubMenu != NULL)		// 如果是子菜单
		{
			if (m_lpArrowImg != NULL && !m_lpArrowImg->IsNull())
				lpms->itemWidth += m_lpArrowImg->GetWidth() + 8;	// 原来的宽度 + 箭头图标宽度 + 箭头图标右边8像素
			else
				lpms->itemWidth += 5 + 8;
		}
	}
}

void CSkinMenu::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	LPDRAWITEMSTRUCT lpds;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	HDC hDC;
	CRect rcItem;
	BOOL bGrayed, bDisabled, bSelected, bChecked;
	BOOL bIsSeparator;
	CImageEx * lpIconImgN, * lpIconImgH;
	HDC hMemDC;
	HBITMAP hMemBmp, hOldBmp;

	lpds = lpDrawItemStruct;
	if (NULL == lpds || lpds->CtlType != ODT_MENU)
		return;

	lpSkinMenuItemInfo = (SKIN_MENU_ITEM_INFO *)lpds->itemData;
	if (NULL == lpSkinMenuItemInfo || lpSkinMenuItemInfo->nMagic != SKIN_MENU_MAGIC)
		return;

	hDC = lpds->hDC;
	rcItem = lpds->rcItem;

	bGrayed = lpds->itemState & ODS_GRAYED;
	bDisabled = lpds->itemState & ODS_DISABLED;
	bSelected = lpds->itemState & ODS_SELECTED;
	//bChecked  = lpds->itemState & ODS_CHECKED;
	bChecked  = lpSkinMenuItemInfo->nState & ODS_CHECKED;

	bIsSeparator = lpSkinMenuItemInfo->nType & MFT_SEPARATOR;

	lpIconImgN = lpSkinMenuItemInfo->lpIconImgN;
	lpIconImgH = lpSkinMenuItemInfo->lpIconImgH;

	rcItem.OffsetRect(-rcItem.left, -rcItem.top);

	hMemDC = ::CreateCompatibleDC(hDC);
	hMemBmp = ::CreateCompatibleBitmap(hDC, rcItem.Width(), rcItem.Height());
	hOldBmp = (HBITMAP)::SelectObject(hMemDC, hMemBmp);

	DrawBg(hMemDC, rcItem);					// 绘制背景

	if (bIsSeparator)						// 绘制分隔符
	{
		DrawSepartor(hMemDC, rcItem);
	}
	else
	{
		if (bSelected && !bGrayed)
			DrawSelRect(hMemDC, rcItem);	// 绘制选中区域

		if (bChecked)						// 绘制Check状态
		{
			DrawCheckState(hMemDC, rcItem);
		}
		else
		{
			if (bSelected)
				DrawIcon(hMemDC, rcItem, lpIconImgH);	// 绘制选中图标
			else
				DrawIcon(hMemDC, rcItem, lpIconImgN);	// 绘制非选中图标
		}

		DrawText(hMemDC, rcItem, bGrayed, bSelected, 
			(BOOL)lpSkinMenuItemInfo->hSubMenu, lpSkinMenuItemInfo->szText);	// 绘制菜单文本

		if (lpSkinMenuItemInfo->hSubMenu != NULL)	// 绘制子菜单的右三角箭头
			DrawArrow(hMemDC, rcItem);
	}

	rcItem = lpds->rcItem;

	::BitBlt(hDC, rcItem.left, rcItem.top, rcItem.Width(), rcItem.Height(), hMemDC, 0, 0, SRCCOPY);

	if (lpSkinMenuItemInfo->hSubMenu != NULL)	// 不让系统绘制弹出式菜单箭头
		::ExcludeClipRect(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);

	::SelectObject(hMemDC, hOldBmp);
	::DeleteObject(hMemBmp);
	::DeleteDC(hMemDC);
}

CSkinMenu& CSkinMenu::operator =(HMENU hMenu)
{
	Attach(hMenu);
	return *this;
}

BOOL CSkinMenu::Attach(HMENU hMenu)
{
	BOOL bRet;

	if (m_hMenu != NULL)
	{
		EnableOwnerDraw(m_hMenu, FALSE);
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	}

	bRet = EnableOwnerDraw(hMenu, TRUE);
	if (!bRet)
	{
		return FALSE;
	}
	else
	{
		m_hMenu = hMenu;
		return TRUE;
	}
}

HMENU CSkinMenu::Detach()
{
	HMENU hMenu = m_hMenu;

	if (m_hMenu != NULL)
	{
		EnableOwnerDraw(m_hMenu, FALSE);
		m_hMenu = NULL;
	}

	return hMenu;
}

BOOL CSkinMenu::DeleteMenu(UINT nPosition, UINT nFlags)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;

	bByPosition = nFlags & MF_BYPOSITION;
	lpSkinMenuItemInfo = GetMenuItemInfo(nPosition, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		if (lpSkinMenuItemInfo->hSubMenu != NULL)
		{
			CSkinMenu SubMenu(lpSkinMenuItemInfo->hSubMenu);
			SubMenu.DeleteMenu(nPosition, nFlags);
		}

		CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgN);
		CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgH);
		
		delete lpSkinMenuItemInfo;

		SetMenuItemInfo(nPosition, nFlags, NULL);
	}

	return ::DeleteMenu(m_hMenu, nPosition, nFlags);
}

BOOL CSkinMenu::TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect/* = 0*/)
{
	return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect);
}

BOOL CSkinMenu::TrackPopupMenuEx(UINT fuFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm)
{
	return ::TrackPopupMenuEx(m_hMenu, fuFlags, x, y, hWnd, lptpm);
}

BOOL CSkinMenu::AppendMenu(UINT nFlags, UINT_PTR nIDNewItem/* = 0*/, 
						   LPCTSTR lpszNewItem/* = NULL*/)
{
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	int nCount;
	BOOL bRet;

	nFlags |= MF_OWNERDRAW;
	bRet = ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem);
	if (bRet)
	{
		lpSkinMenuItemInfo = new SKIN_MENU_ITEM_INFO;
		if (lpSkinMenuItemInfo != NULL)
		{
			memset(lpSkinMenuItemInfo, 0, sizeof(SKIN_MENU_ITEM_INFO));

			lpSkinMenuItemInfo->nMagic = SKIN_MENU_MAGIC;

			if (nFlags & MF_POPUP)				// 弹出菜单
			{
				lpSkinMenuItemInfo->hSubMenu = (HMENU)nIDNewItem;
				if (lpszNewItem != NULL && _tcslen(lpszNewItem) > 0)
				{
					_tcsncpy(lpSkinMenuItemInfo->szText, lpszNewItem, 
						sizeof(lpSkinMenuItemInfo->szText) / sizeof(TCHAR));
				}
				bRet = EnableOwnerDraw(lpSkinMenuItemInfo->hSubMenu, TRUE);
			}
			else
			{
				if (nFlags & MF_SEPARATOR)		// 分隔符
				{
					lpSkinMenuItemInfo->nID = 0;
					lpSkinMenuItemInfo->nType = MFT_SEPARATOR;
				}
				else							// 菜单项
				{
					lpSkinMenuItemInfo->nID = nIDNewItem;
					if (lpszNewItem != NULL && _tcslen(lpszNewItem) > 0)
					{
						_tcsncpy(lpSkinMenuItemInfo->szText, lpszNewItem, 
							sizeof(lpSkinMenuItemInfo->szText) / sizeof(TCHAR));
					}
				}
			}

			nCount = ::GetMenuItemCount(m_hMenu);
			bRet = SetMenuItemInfo(nCount - 1, TRUE, lpSkinMenuItemInfo);
		}
	}

	return bRet;
}

UINT CSkinMenu::CheckMenuItem(UINT nIDCheckItem, UINT nCheck)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	UINT nRet = MF_UNCHECKED;

	bByPosition = nCheck & MF_BYPOSITION ? TRUE : FALSE;
	lpSkinMenuItemInfo = GetMenuItemInfo(nIDCheckItem, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		if (nCheck & MF_CHECKED)
		{
			lpSkinMenuItemInfo->nState |= MF_CHECKED;
			nRet = MF_CHECKED;
		}
		else
		{
			lpSkinMenuItemInfo->nState &= ~MF_CHECKED;
			nRet = MF_UNCHECKED;
		}
	}

	return nRet;
	//return ::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck);
}

UINT CSkinMenu::EnableMenuItem(UINT nIDEnableItem, UINT nEnable)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;

	bByPosition = nEnable & MF_BYPOSITION ? TRUE : FALSE;
	lpSkinMenuItemInfo = GetMenuItemInfo(nIDEnableItem, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		if (nEnable & MF_DISABLED)
		{
			lpSkinMenuItemInfo->nState |= MF_DISABLED;
			lpSkinMenuItemInfo->nState &= ~MF_ENABLED;
		}
		else if (nEnable & MF_GRAYED)
		{
			lpSkinMenuItemInfo->nState |= MF_GRAYED;
			lpSkinMenuItemInfo->nState &= ~MF_ENABLED;
		}
		else
		{
			lpSkinMenuItemInfo->nState |= MF_ENABLED;
			lpSkinMenuItemInfo->nState &= ~MF_DISABLED;
			lpSkinMenuItemInfo->nState &= ~MF_GRAYED;
		}
	}

	return ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable);
}

UINT CSkinMenu::GetMenuItemCount() const
{
	return ::GetMenuItemCount(m_hMenu);
}

UINT CSkinMenu::GetMenuItemID(int nPos) const
{
	return ::GetMenuItemID(m_hMenu, nPos);
}

UINT CSkinMenu::GetMenuState(UINT nID, UINT nFlags)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	UINT nRet = 0;

	bByPosition = nFlags & MF_BYPOSITION ? TRUE : FALSE;
	lpSkinMenuItemInfo = GetMenuItemInfo(nID, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		nRet = lpSkinMenuItemInfo->nState;
	}

	return nRet;
}

int CSkinMenu::GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	int nRet = 0;

	bByPosition = nFlags & MF_BYPOSITION ? TRUE : FALSE;
	lpSkinMenuItemInfo = GetMenuItemInfo(nIDItem, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		_tcsncpy(lpString, lpSkinMenuItemInfo->szText, nMaxCount);
		nRet = _tcslen(lpString);
	}

	return nRet;
	//return ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags);
}

CSkinMenu CSkinMenu::GetSubMenu(int nPos) const
{
	return CSkinMenu(::GetSubMenu(m_hMenu, nPos));
}

BOOL CSkinMenu::InsertMenu(UINT nPosition, UINT nFlags, 
						   UINT_PTR nIDNewItem/* = 0*/, LPCTSTR lpszNewItem/* = NULL*/)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	BOOL bRet;

	bByPosition = nFlags & MF_BYPOSITION ? TRUE : FALSE;

	nFlags |= MF_OWNERDRAW;
	bRet = ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem);
	if (bRet)
	{
		lpSkinMenuItemInfo = new SKIN_MENU_ITEM_INFO;
		if (lpSkinMenuItemInfo != NULL)
		{
			memset(lpSkinMenuItemInfo, 0, sizeof(SKIN_MENU_ITEM_INFO));

			lpSkinMenuItemInfo->nMagic = SKIN_MENU_MAGIC;
			if (nFlags & MF_POPUP)				// 弹出菜单
			{
				lpSkinMenuItemInfo->hSubMenu = (HMENU)nIDNewItem;
				if (lpszNewItem != NULL && _tcslen(lpszNewItem) > 0)
				{
					_tcsncpy(lpSkinMenuItemInfo->szText, lpszNewItem, 
						sizeof(lpSkinMenuItemInfo->szText) / sizeof(TCHAR));
				}

				bRet = EnableOwnerDraw(lpSkinMenuItemInfo->hSubMenu, TRUE);
			}
			else
			{
				if (nFlags & MF_SEPARATOR)		// 分隔符
				{
					lpSkinMenuItemInfo->nID = 0;
					lpSkinMenuItemInfo->nType = MFT_SEPARATOR;
				}
				else if (nFlags & MF_STRING)	// 菜单项
				{
					lpSkinMenuItemInfo->nID = nIDNewItem;
					if (lpszNewItem != NULL && _tcslen(lpszNewItem) > 0)
					{
						_tcsncpy(lpSkinMenuItemInfo->szText, lpszNewItem, 
							sizeof(lpSkinMenuItemInfo->szText) / sizeof(TCHAR));
					}
				}
			}

			bRet = SetMenuItemInfo(nPosition, bByPosition, lpSkinMenuItemInfo);
		}
	}

	return bRet;
}

BOOL CSkinMenu::ModifyMenu(UINT nPosition, UINT nFlags, 
						   UINT_PTR nIDNewItem/* = 0*/, LPCTSTR lpszNewItem/* = NULL*/)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	BOOL bRet;

	bByPosition = nFlags & MF_BYPOSITION ? TRUE : FALSE;
	lpSkinMenuItemInfo = GetMenuItemInfo(nPosition, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		//SetMenuItemInfo(nPosition, bByPosition, NULL);

		nFlags |= MF_OWNERDRAW;
		bRet = ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem);
		if (bRet)
		{
			if (nFlags & MF_SEPARATOR)		// 分隔符
			{
				lpSkinMenuItemInfo->nID = 0;
				lpSkinMenuItemInfo->nType = MFT_SEPARATOR;
			}
			else							// 菜单项
			{
				lpSkinMenuItemInfo->nID = nIDNewItem;
				if (lpszNewItem != NULL && _tcslen(lpszNewItem) > 0)
				{
					_tcsncpy(lpSkinMenuItemInfo->szText, lpszNewItem, 
						sizeof(lpSkinMenuItemInfo->szText) / sizeof(TCHAR));
				}
			}

			bRet = SetMenuItemInfo(nPosition, bByPosition, lpSkinMenuItemInfo);
		}
	}

	return bRet;
}

BOOL CSkinMenu::RemoveMenu(UINT nPosition, UINT nFlags)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	MENUITEMINFO stMenuItemInfo = {0};
	WCHAR cText[256] = {0};

	bByPosition = nFlags & MF_BYPOSITION ? TRUE : FALSE;
	lpSkinMenuItemInfo = GetMenuItemInfo(nPosition, bByPosition);
	if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
	{
		if (lpSkinMenuItemInfo->hSubMenu != NULL)
		{
			CSkinMenu SubMenu(lpSkinMenuItemInfo->hSubMenu);
			SubMenu.RemoveMenu(nPosition, nFlags);
		}

		CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgN);
		CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgH);
		
		delete lpSkinMenuItemInfo;

		SetMenuItemInfo(nPosition, bByPosition, NULL);
	}

	return ::RemoveMenu(m_hMenu, nPosition, nFlags);
}

BOOL CSkinMenu::CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags)
{
	BOOL bByPosition;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;

	bByPosition = nFlags & MF_BYPOSITION ? TRUE : FALSE;
	for (UINT i = nIDFirst; i <= nIDLast; i++)
	{
		lpSkinMenuItemInfo = GetMenuItemInfo(i, bByPosition);
		if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
		{
			if (i == nIDItem)
				lpSkinMenuItemInfo->nState |= MF_CHECKED;
			else
				lpSkinMenuItemInfo->nState &= ~MF_CHECKED;
		}
	}

	return ::CheckMenuRadioItem(m_hMenu, nIDFirst, nIDLast, nIDItem, nFlags);
}

BOOL CSkinMenu::IsMenu()
{
	return ::IsMenu(m_hMenu);
}

SKIN_MENU_ITEM_INFO * CSkinMenu::GetMenuItemInfo(UINT nItem, BOOL bByPosition)
{
	MENUITEMINFO stMenuItemInfo = {0};
	BOOL bRet;

	stMenuItemInfo.cbSize = sizeof(MENUITEMINFO);
	stMenuItemInfo.fMask = MIIM_DATA;
	bRet = ::GetMenuItemInfo(m_hMenu, nItem, bByPosition, &stMenuItemInfo);
	if (bRet)
		return (SKIN_MENU_ITEM_INFO *)stMenuItemInfo.dwItemData;
	else
		return NULL;
}

BOOL CSkinMenu::SetMenuItemInfo(UINT nItem, BOOL bByPosition, SKIN_MENU_ITEM_INFO * lpItemInfo)
{
	MENUITEMINFO stMenuItemInfo = {0};

	stMenuItemInfo.cbSize = sizeof(MENUITEMINFO);
	stMenuItemInfo.fMask = MIIM_DATA;
	stMenuItemInfo.dwItemData = (DWORD)lpItemInfo;

	return ::SetMenuItemInfo(m_hMenu, nItem, bByPosition, &stMenuItemInfo);
}

BOOL CSkinMenu::EnableOwnerDraw(HMENU hMenu, BOOL bEnable)
{
	MENUITEMINFO stMenuItemInfo;
	SKIN_MENU_ITEM_INFO * lpSkinMenuItemInfo;
	TCHAR szText[256] = {0};
	int nMenuItemCount;
	BOOL bRet;

	nMenuItemCount = ::GetMenuItemCount(hMenu);
	for (int i = 0; i < nMenuItemCount; i++)
	{
		memset(&stMenuItemInfo, 0, sizeof(stMenuItemInfo));
		stMenuItemInfo.cbSize = sizeof(MENUITEMINFO);
		stMenuItemInfo.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_ID | MIIM_TYPE | MIIM_STATE;
		stMenuItemInfo.dwTypeData = szText;
		stMenuItemInfo.cch = sizeof(szText) / sizeof(TCHAR);
		bRet = ::GetMenuItemInfo(hMenu, i, TRUE, &stMenuItemInfo);

		if (bEnable)
		{
			if (stMenuItemInfo.hSubMenu != NULL)
				EnableOwnerDraw(stMenuItemInfo.hSubMenu, bEnable);

			if (!(stMenuItemInfo.fType & MFT_OWNERDRAW))	// 未起用菜单自绘
			{
				lpSkinMenuItemInfo = (SKIN_MENU_ITEM_INFO *)stMenuItemInfo.dwItemData;
				if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
				{
					CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgN);
					CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgH);
					
					lpSkinMenuItemInfo->nMagic = NULL;

					delete lpSkinMenuItemInfo;
				}

				lpSkinMenuItemInfo = new SKIN_MENU_ITEM_INFO;
				if (lpSkinMenuItemInfo != NULL)
				{
					lpSkinMenuItemInfo->nMagic = SKIN_MENU_MAGIC;
					lpSkinMenuItemInfo->nID = stMenuItemInfo.wID;
					lpSkinMenuItemInfo->nState = stMenuItemInfo.fState;
					lpSkinMenuItemInfo->nType = stMenuItemInfo.fType;
					if (stMenuItemInfo.dwTypeData != NULL && _tcslen(stMenuItemInfo.dwTypeData) > 0)
					{
						_tcsncpy(lpSkinMenuItemInfo->szText, stMenuItemInfo.dwTypeData, 
							sizeof(lpSkinMenuItemInfo->szText) / sizeof(TCHAR));
					}
					lpSkinMenuItemInfo->hSubMenu = stMenuItemInfo.hSubMenu;
					lpSkinMenuItemInfo->lpIconImgN = NULL;
					lpSkinMenuItemInfo->lpIconImgH = NULL;

					stMenuItemInfo.fMask = MIIM_TYPE | MIIM_DATA;
					stMenuItemInfo.fType |= MFT_OWNERDRAW;
					stMenuItemInfo.dwItemData = (DWORD)lpSkinMenuItemInfo;
					bRet = ::SetMenuItemInfo(hMenu, i, TRUE, &stMenuItemInfo);
				}
			}
		}
		else
		{
			if (stMenuItemInfo.hSubMenu != NULL)
				EnableOwnerDraw(stMenuItemInfo.hSubMenu, bEnable);

			lpSkinMenuItemInfo = (SKIN_MENU_ITEM_INFO *)stMenuItemInfo.dwItemData;
			if (lpSkinMenuItemInfo != NULL && SKIN_MENU_MAGIC == lpSkinMenuItemInfo->nMagic)
			{
				CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgN);
				CSkinManager::GetInstance()->ReleaseImage(lpSkinMenuItemInfo->lpIconImgH);
				
				delete lpSkinMenuItemInfo;

				stMenuItemInfo.fMask = MIIM_DATA;
				stMenuItemInfo.dwItemData = NULL;
				bRet = ::SetMenuItemInfo(hMenu, i, TRUE, &stMenuItemInfo);
			}
		}
	}

	return TRUE;
}

SIZE CSkinMenu::GetTextExtent(LPCTSTR lpszText)
{
	HDC hDC;
	RECT rcText = {0};
	SIZE sz = {0};
	HFONT hOldFont;

	if (NULL == lpszText || _tcslen(lpszText) <= 0)
		return sz;

	hDC = ::GetDC(NULL);
	hOldFont = (HFONT)::SelectObject(hDC, m_hFont);
	::DrawText(hDC, lpszText, _tcslen(lpszText), &rcText, DT_SINGLELINE | DT_CALCRECT);
	::SelectObject(hDC, hOldFont);
	::ReleaseDC(NULL, hDC);

	sz.cx = rcText.right - rcText.left;
	sz.cy = rcText.bottom - rcText.top;

	return sz;
}

// 绘制菜单顶背景
void CSkinMenu::DrawBg(HDC hDC, CRect& rect)
{
	if (m_lpBgImgL != NULL && !m_lpBgImgL->IsNull())
	{
		CRect rcLeft(rect);
		rcLeft.right = rcLeft.left + m_nLMargin;
		m_lpBgImgL->Draw(hDC, rcLeft);
	}

	if (m_lpBgImgR != NULL && !m_lpBgImgR->IsNull())
	{
		CRect rcRight(rect);
		rcRight.left += m_nLMargin;
		m_lpBgImgR->Draw(hDC, rcRight);
	}
}

// 绘制分隔符
void CSkinMenu::DrawSepartor(HDC hDC, CRect& rect)
{
	if (m_lpSepartorImg != NULL && !m_lpSepartorImg->IsNull())
	{
		CRect rcSepartor(rect);
		rcSepartor.left += m_nLMargin;
		m_lpSepartorImg->Draw(hDC, rcSepartor);
	}
}

// 填充选中区域
void CSkinMenu::DrawSelRect(HDC hDC, CRect& rect)
{
	if (m_lpSelectedImg != NULL && !m_lpSelectedImg->IsNull())
		m_lpSelectedImg->Draw(hDC, rect);
}

// 绘制菜单图标
void CSkinMenu::DrawIcon(HDC hDC, CRect& rect, CImageEx * lpIconImg)
{
	if (lpIconImg != NULL && !lpIconImg->IsNull())
	{
		int cxIcon = lpIconImg->GetWidth();
		int cyIcon = lpIconImg->GetHeight();

		CRect rcLeft(rect);
		rcLeft.right = rcLeft.left + m_nLMargin;

		int x = (rcLeft.Width() - cxIcon + 1) / 2;
		int y = (rcLeft.Height() - cyIcon + 1) / 2;

		CRect rcIcon(x, y, x+cxIcon, y+cyIcon);
		lpIconImg->Draw(hDC, rcIcon);
	}
}

// 绘制Check状态
void CSkinMenu::DrawCheckState(HDC hDC, CRect& rect)
{
	DrawIcon(hDC, rect, m_lpCheckImg);
}

// 绘制菜单文本
void CSkinMenu::DrawText(HDC hDC, CRect& rect, BOOL bGrayed, 
						 BOOL bSelected, BOOL bIsSubMenu, LPCTSTR lpText)
{
	int nMode;
	COLORREF clrColor;

	CRect rcText(rect);
	rcText.left = m_nLMargin + 8;
	rcText.right -= 8;

	if (bIsSubMenu)
	{
		if (m_lpArrowImg != NULL && !m_lpArrowImg->IsNull())
			rcText.right = rcText.right - m_lpArrowImg->GetWidth() - 8;
		else
			rcText.right = rcText.right - 5 - 8;
	}

	nMode = ::SetBkMode(hDC, TRANSPARENT);

	if (bGrayed)
	{
		clrColor = m_clrGrayedText;
	}
	else
	{
		if (bSelected)
			clrColor = m_clrSelText;
		else
			clrColor = m_clrText;
	}

	::SetTextColor(hDC, clrColor);
	HFONT hOldFont = (HFONT)::SelectObject(hDC, m_hFont);
	::DrawText(hDC, lpText, _tcslen(lpText), &rcText, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
	::SelectObject(hDC, hOldFont);

	::SetBkMode(hDC, nMode);
}

// 绘制弹出式菜单箭头
void CSkinMenu::DrawArrow(HDC hDC, CRect& rect)
{
	if (m_lpArrowImg != NULL && !m_lpArrowImg->IsNull())
	{
		int cxArrow = m_lpArrowImg->GetWidth();
		int cyArrow = m_lpArrowImg->GetHeight();

		int x = rect.right - 8 - cxArrow;
		int y = (rect.Height() - cyArrow + 1) / 2;

		CRect rcArrow(x, y, x+cxArrow, y+cyArrow);

		m_lpArrowImg->Draw(hDC, rcArrow);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值