www.pudn.com > SDKSkin.rar > SkinMenuBar.h


 
#ifndef _SKINMENUBAR_ONCE_ 
#define _SKINMENUBAR_ONCE_ 
 
#define IDBUTTON_FIRST      65000 
#define IDBUTTON_SYSMENU    65000 
#define IDBUTTON_LAST       65100 
#define VERIFY(f)          ((void)(f)) 
#define ASSERT(f)          ((void)0) 
#define MENUSPACE			6 
 
const   int   MENUTEXTLEN  = 128; 
 
class SkinMenuBar 
{ 
public: 
	SkinMenuBar() 
	{ 
		Init(); 
	} 
	virtual ~SkinMenuBar() 
	{ 
	} 
 
	bool EqualHwnd(HWND hWnd) 
	{ 
		if(hWnd == m_hWnd) return true; 
		return false; 
	} 
	static SkinMenuBar*	GetSkinMenuBar(HWND hWnd) 
	{ 
		FRMPARAM frm = SkinIni::Instance()->GetFrmParam(); 
		PSKINMBARNODE pNode = SkinResList::skMenuBar; 
		while(pNode) 
		{ 
			if(pNode->data->EqualHwnd(hWnd)) 
			{ 
				pNode->data->CaclMenuRect(); 
				return pNode->data; 
			} 
			pNode = pNode->next; 
		} 
 
		return NULL; 
	} 
 
	static int	CaclMenuBarHei(HWND hWnd) 
	{ 
		SkinMenuBar* pmInfo = SkinMenuBar::GetSkinMenuBar(hWnd); 
		if(pmInfo == NULL) return 0; 
 
		RECT	rcDraw = pmInfo->m_rcBar; 
		RNHDC	hWndDc(hWnd,DC_WIN); 
		HFONT	fOld = (HFONT)SelectObject(hWndDc,SkinCommon::GetMenuFont()); 
		 
		int		iMenuHei = 1; 
		rcDraw.bottom = rcDraw.top + SkinCommon::GetCYMenu(); 
 
		if(pmInfo->m_hMenu != 0) 
		{ 
			UINT nItems = GetMenuItemCount(pmInfo->m_hMenu); 
			UINT nIndex = 0; 
			 
			for(nIndex = 0; nIndexm_hMenu,nIndex); 
				 
				TCHAR strMenu[MENUTEXTLEN] = {0}; 
				SIZE size = {0,0}; 
				int strLen = GetMenuString(pmInfo->m_hMenu,nIndex,strMenu,MENUTEXTLEN,MF_BYPOSITION); 
				::GetTextExtentPoint32(hWndDc,strMenu,_tcslen(strMenu), &size); 
				rcDraw.right = rcDraw.left + size.cx + MENUSPACE; 
				if(rcDraw.right > (pmInfo->m_rcBar.right +MENUSPACE)) 
				{ 
					rcDraw.right = pmInfo->m_rcBar.left; 
					iMenuHei++; 
				} 
				rcDraw.left = rcDraw.right; 
			} 
		} 
		SelectObject(hWndDc,fOld); 
 
		return (iMenuHei * SkinCommon::GetCYMenu()); 
	} 
 
	void DrawSkinMenuBar(HWND hWnd) 
	{ 
		bDraw = true; 
		 
		RNHDC	hWndDc(hWnd,DC_WIN); 
		RECT	rcDraw = m_rcBar; 
		HFONT	fOld = (HFONT)SelectObject(hWndDc,SkinCommon::GetMenuFont()); 
		int		iWndWid = m_rcBar.right-m_rcBar.left; 
 
		// 创建一个内存位图,这样避免闪烁 
		RNHDC memDc(CreateCompatibleDC(hWndDc)); 
		RNHBitmap memBmp(CreateCompatibleBitmap(hWndDc,rcDraw.right-rcDraw.left,rcDraw.bottom-rcDraw.top)); 
		HBITMAP hOldBmp = (HBITMAP)SelectObject(memDc,memBmp); 
 
		rcDraw.right = rcDraw.right - rcDraw.left; 
		rcDraw.bottom = rcDraw.bottom - rcDraw.top; 
		rcDraw.left = rcDraw.top = 0; 
 
		RECT rcMem = rcDraw; 
 
		DrawBKMenu(hWnd,memDc,rcDraw,SKIN_NORMAL); 
		 
		rcDraw.bottom = rcDraw.top + SkinCommon::GetCYMenu(); 
 
		if(m_hMenu != 0) 
		{ 
			UINT nItems = GetMenuItemCount(m_hMenu); 
			UINT nIndex = 0; 
			 
			for(nIndex = 0; nIndex < nItems; nIndex++) 
			{ 
				UINT nID    = GetMenuItemID(m_hMenu,nIndex); 
				 
				switch(nID) 
				{ 
					case -1: 
						nID = IDBUTTON_SYSMENU + 1 + nIndex; 
						break; 
					case 0: 
						//nStyle = TBBS_SEPARATOR; 
						break; 
					default: 
					; 
				} 
				 
				TCHAR strMenu[MENUTEXTLEN] = {0}; 
				SIZE size = {0,0}; 
				int strLen = GetMenuString(m_hMenu,nIndex,strMenu,MENUTEXTLEN,MF_BYPOSITION); 
				::GetTextExtentPoint32(hWndDc,strMenu,_tcslen(strMenu), &size); 
				rcDraw.right = rcDraw.left + size.cx + MENUSPACE; 
				if(rcDraw.right > (iWndWid+MENUSPACE)) 
				{ 
					rcDraw.left = 0; 
					rcDraw.right = size.cx + MENUSPACE; 
					rcDraw.top += SkinCommon::GetCYMenu(); 
					rcDraw.bottom += SkinCommon::GetCYMenu(); 
				} 
				else if(rcDraw.right > iWndWid) 
				{ 
					rcDraw.right = iWndWid; 
				} 
				DrawMenuText(memDc,rcDraw,strMenu,strLen,SKIN_NORMAL); 
 
				rcItems[nIndex] = rcDraw; 
				rcItems[nIndex].left += m_rcBar.left; 
				rcItems[nIndex].right += m_rcBar.left; 
				rcItems[nIndex].top += m_rcBar.top; 
				rcItems[nIndex].bottom += m_rcBar.top; 
 
				rcDraw.left = rcDraw.right; 
			} 
 
			rcItems[nIndex].left = 0; 
			rcItems[nIndex].top = 0; 
			rcItems[nIndex].right = 0; 
			rcItems[nIndex].bottom = 0; 
		} 
 
		SkinDraw::DrawStretch(hWndDc,memDc,m_rcBar,rcMem); 
 
		SelectObject(hWndDc,fOld); 
		SelectObject(memDc,hOldBmp); 
	} 
 
	int FindRectByPoint(POINT &pt) 
	{ 
		int iRet = -1; 
		for(int i=0;i < MENUITEMCOUNT;++i) 
		{ 
			if(IsRectValid(rcItems[i]) == false) 
			{ 
				break; 
			} 
			 
			if(PtInRect(&rcItems[i],pt)) 
			{ 
				iRet = i; 
				break; 
			} 
		} 
 
		return iRet; 
	} 
 
	void MenuMouseOver(HWND hWnd,POINT pt) 
	{ 
		/*POINT pt; 
		::GetCursorPos(&pt);//得到鼠标位置*/ 
		RECT  wndRc; 
		GetWindowRect(m_hWnd,&wndRc); 
		pt.x = pt.x - wndRc.left; 
		pt.y = pt.y - wndRc.top; 
 
		bool bFind = false; 
		 
		for(int i=0;i= 0 && m_nItem != iItem) 
				{ 
					m_nItem = iItem; 
					//DrawMenuState(hWnd,pmInfo,iItem,SKIN_DOWN); 
					ContinueTracking(iItem != 0); 
				} 
				break; 
			} 
			case WM_KEYDOWN: 
			{ 
				UINT nChar = ( UINT )wParam; 
				bool bForward = false;  // by default 
				UINT nItems = GetMenuItemCount(m_hMenu); 
				 
				switch(nChar) 
				{ 
					case VK_LEFT: 
						bForward = m_bPrimaryMenu; 
						break; 
					case VK_RIGHT: 
						bForward = !m_bSubmenuItem; 
						break; 
					case VK_ESCAPE: 
						m_bEscape = m_bPrimaryMenu; 
						break; 
				} 
				 
				// Should we forward this message to the menu bar? 
				if(bForward) 
				{ 
					//OnKeyDown(hWnd,nChar,LOWORD(lParam),HIWORD(lParam)); 
					//pmInfo->m_nItem = (++pmInfo->m_nItem)%nItems; 
					//DrawMenuState(hWnd,pmInfo,iItem,SKIN_DOWN); 
					//ContinueTracking(hWnd,pmInfo,pmInfo->m_nItem != 0); 
					//SendMessage(hWnd,message, wParam, lParam ); 
				} 
				break; 
			} 
		} 
	} 
	 
	static LRESULT CALLBACK MessageProc(int code, WPARAM wParam, LPARAM lParam) 
	{	 
		if(code == MSGF_MENU ) 
		{ 
			MSG* pMsg = ( MSG*)lParam; 
			SkinMenuBar *pmInfo = SkinMenuBar::GetSkinMenuBar(pMsg->hwnd); 
			if(NULL != pmInfo) 
			{ 
				pmInfo->HookMessageProc(pMsg->message, pMsg->wParam, pMsg->lParam ); 
			} 
		} 
		 
		return ::CallNextHookEx(SkinResList::m_hMsgHook,code,wParam,lParam); 
	} 
 
	bool OnKeyDown(HWND hWnd,UINT nChar, UINT nRepCnt, UINT nFlags ) 
	{ 
		return true; 
		//if(bItemTracking == 1) 
		{ 
			switch(nChar ) 
			{ 
            case VK_SPACE: 
				{ 
					if(bItemTracking == 1) 
					{ 
						ExitTrackingMode(hWnd); 
						PostMessage(hWnd,WM_SYSCOMMAND, SC_KEYMENU, 32); 
						return true; 
					} 
				} 
				break; 
            case VK_ESCAPE: 
				{ 
					if(bItemTracking == 1) 
					{ 
						ExitTrackingMode(hWnd); 
						return true; 
					} 
				} 
				break; 
			case VK_CONTROL: 
				{ 
					bool bLButtonDown = ( ::GetKeyState( VK_LBUTTON ) < 0 ); 
					 
					//EnterTrackingMode(hWnd,0); 
					 
					m_nItem = 0; 
					m_bSelectFirst = !bLButtonDown; 
					m_bContinue    = true; 
					//m_bEscape      = false; 
					 
					TrackPopupMenu(hWnd); 
					 
					//ExitTrackingMode(hWnd); 
				} 
				break; 
            default: 
                break; 
			} 
		} 
		 
		return false; 
	} 
 
	void EnterTrackingMode(HWND hWnd,int iItem) 
	{ 
		if(bItemTracking == 0) 
		{ 
			bItemTracking = 1; 
			m_hOldFocusWnd  = 0; 
			 
			// Gain focus 
			if(GetFocus() != hWnd) 
			{ 
				m_hOldFocusWnd = SetFocus(hWnd); 
			} 
			 
			// Capture mouse 
			if(GetCapture() != hWnd) 
			{ 
				SetCapture(hWnd); 
				SendMessage(hWnd,WM_SETCURSOR,(WPARAM)m_hWnd,MAKELPARAM(HTCLIENT,0)); 
			} 
			 
			DrawMenuState(hWnd,iItem,SKIN_DOWN); 
			bDrawText = 1; 
		} 
	} 
 
	void ExitTrackingMode(HWND hWnd) 
	{ 
		if(bItemTracking == 1) 
		{ 
			DrawMenuItem(hWnd,iPrevMenu,SKIN_NORMAL); 
			bDrawText = 0; 
			 
			// Restore focus 
			if((GetFocus() == hWnd) && ::IsWindow(m_hOldFocusWnd)) 
			{ 
				::SetFocus(m_hOldFocusWnd); 
			} 
			 
			// Release capture 
			if(GetCapture() == hWnd) 
			{ 
				VERIFY(ReleaseCapture()); 
			} 
			 
			bItemTracking = 0; 
			m_hOldFocusWnd  = 0; 
		} 
	} 
 
	void ContinueTracking(bool bSelectFirst) 
	{ 
		m_bSelectFirst = bSelectFirst; 
		m_bContinue    = true; 
 
		PostMessage(m_hWnd,WM_CANCELMODE,0,0);   // close currently tracked menu 
	} 
 
	void TrackPopupMenu(HWND hWnd) 
	{ 
		for(int nItem = m_nItem; m_bContinue; nItem = m_nItem ) 
		{ 
			// Get popup menu to be tracked 
			m_hMenuTracking = ::GetSubMenu(m_hMenu,nItem); 
			//(nItem < 0) ? 
			//	::GetSystemMenu( m_hWndMDIChild, false ) : 
            //::GetSubMenu( m_hMenu, nItem); 
			if(m_hMenuTracking == 0) 
			{ 
				break; 
			} 
 
			DrawMenuState(hWnd,nItem,SKIN_DOWN); 
 
			if(m_bSelectFirst) 
			{ 
				PostMessage(hWnd,WM_KEYDOWN,VK_DOWN,1); 
				PostMessage(hWnd,WM_KEYUP,VK_DOWN,1); 
			} 
			 
			RECT rc = rcItems[nItem]; 
			RECT  wndRc; 
			GetWindowRect(hWnd,&wndRc); 
			rc.left += wndRc.left; 
			rc.top += wndRc.top; 
			rc.right += wndRc.left; 
			rc.bottom += wndRc.top; 
			 
			TPMPARAMS tpm; 
			tpm.cbSize    = sizeof( TPMPARAMS ); 
			tpm.rcExclude = rc; 
			 
			m_bPrimaryMenu = false; 
			m_bSubmenuItem = false; 
			m_bContinue    = false; 
			 
			::TrackPopupMenuEx(m_hMenuTracking, 
				TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL, 
				rc.left,rc.bottom,hWnd,&tpm); 
			 
			//tbCtrl.PressButton( GetItemID( nItem ), false ); 
		} 
	} 
 
	void MenuLButtonDown(HWND hWnd,POINT pt) 
	{ 
		RECT  wndRc; 
		GetWindowRect(hWnd,&wndRc); 
		pt.x = pt.x - wndRc.left; 
		pt.y = pt.y - wndRc.top; 
		 
		bool bFind = false; 
		 
		for(int i=0;ibDrawText == 0 || !PtInRect(&pmInfo->prevRect,pt)) 
				{ 
					DrawMenuState(hWnd,i,SKIN_DOWN); 
					bDrawText = 1; 
				} 
 
				bFind = true; 
 
				bool bLButtonDown = ( ::GetKeyState( VK_LBUTTON ) < 0 ); 
 
				EnterTrackingMode(hWnd,i); 
 
				m_nItem = i; 
				m_bSelectFirst = !bLButtonDown; 
				m_bContinue    = true; 
				//m_bEscape      = false; 
				 
				TrackPopupMenu(hWnd); 
 
				ExitTrackingMode(hWnd); 
 
				break; 
			} 
		} 
	} 
 
	static bool AddMenuInfo(HWND hWnd) 
	{ 
		return AddMenuInfo(hWnd,&(SkinResList::skMenuBar)); 
	} 
 
	static bool AddMenuInfo(HWND hWnd,PSKINMBARNODE *pMenuBar) 
	{ 
		if(!IsWindow(hWnd) || GetMenu(hWnd) == NULL) return false;		 
		 
		if(NULL == *pMenuBar) 
		{ 
			*pMenuBar = (PSKINMBARNODE)malloc(sizeof(SKINMBARNODE)); 
			ZeroMemory(*pMenuBar,sizeof(SKINMBARNODE)); 
			(*pMenuBar)->data = new SkinMenuBar(); 
			return AddMenuNode(hWnd,pMenuBar); 
		} 
		 
		PSKINMBARNODE barNode = (PSKINMBARNODE)malloc(sizeof(SKINMBARNODE)); 
		ZeroMemory(barNode,sizeof(SKINMBARNODE)); 
		barNode->data = new SkinMenuBar(); 
		 
		if(AddMenuNode(hWnd,&barNode) < 0) return false; 
 
		PSKINMBARNODE tmNode = (*pMenuBar)->next; 
		barNode->next = tmNode; 
		(*pMenuBar)->next = barNode; 
 
		return true; 
	} 
 
	static void	DeleteMenuInfo(HWND hWnd) 
	{ 
		PSKINMBARNODE pNode = SkinResList::skMenuBar; 
		PSKINMBARNODE pPrev = SkinResList::skMenuBar; 
 
		while(pNode) 
		{ 
			if(pNode->data->EqualHwnd(hWnd)) 
			{ 
				PSKINMBARNODE tmNode = pNode; 
				if(pNode != SkinResList::skMenuBar) 
				{ 
					pPrev->next = pNode->next; 
				} 
				else 
				{ 
					SkinResList::skMenuBar = NULL; 
				} 
				 
				free(tmNode); 
				tmNode = NULL; 
 
				return; 
			} 
 
			pPrev = pNode; 
			pNode = pNode->next; 
		} 
	} 
	static void	DeleteAllMenuInfo() 
	{ 
	} 
 
	static void SetMenuDrawState(HWND hWnd,bool bState) 
	{ 
		SkinMenuBar* pmInfo = SkinMenuBar::GetSkinMenuBar(hWnd); 
		if(pmInfo == NULL) return; 
 
		pmInfo->bDrawText = bState; 
	} 
 
	static void SetRedrawMenu(HWND hWnd,bool bState) 
	{ 
		SkinMenuBar* pmInfo = SkinMenuBar::GetSkinMenuBar(hWnd); 
		if(pmInfo == NULL) return; 
 
		pmInfo->bDraw = bState; 
	} 
	 
	int Init() 
	{ 
		m_hWnd = NULL; 
		m_mHwnd = NULL; 
		m_hOldFocusWnd = NULL; 
		m_hMenu = NULL; 
		m_nItem = -1; 
		m_hMenuTracking = NULL; 
		 
		ZeroMemory(&m_rcBar,sizeof(RECT)); 
		ZeroMemory(&prevRect,sizeof(RECT)); 
		iPrevMenu = -1; 
		//rcItems[MENUITEMCOUNT]; 
		bBarFocused = false;  // bar, popup has the focus 
		bFocused = false;     // item has the focus 
		bTracking = false; 
		bItemTracking = false; 
		bDraw = false; 
		bDrawText = false; 
		m_bSelectFirst = false; 
		m_bContinue = false; 
		m_bPrimaryMenu = false; 
		m_bSubmenuItem = false; 
		m_bItemDropped = false; 
		m_bEscape = false; 
 
		return 0; 
	} 
private: 
	bool IsRectValid(RECT rc) 
	{ 
		if(rc.left == 0  && 
		   rc.right == 0 && 
		   rc.top == 0	 && 
		   rc.bottom == 0) 
		{ 
			return false; 
		} 
		return true; 
	} 
 
	int  DrawMenuText(RNHDC &hDc,RECT rcDraw,TCHAR *strMenu,int strLen,WNDSTATE iState) 
	{ 
		int iMode = SetBkMode(hDc,TRANSPARENT); 
		NONCLIENTMETRICS info; 
		info.cbSize = sizeof( NONCLIENTMETRICS ); 
		VERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(info),&info,0)); 
		 
		HFONT fMenu = CreateFontIndirect(&info.lfMenuFont); 
		HFONT fOld = (HFONT)SelectObject(hDc,fMenu); 
		 
		DrawText(hDc,strMenu,strLen,&rcDraw,DT_SINGLELINE|DT_CENTER|DT_VCENTER); 
		 
		SelectObject(hDc,fOld); 
		SetBkMode(hDc,iMode); 
 
		DeleteObject(fMenu); 
 
		return 0; 
	} 
	int  DrawFaceText(HWND hWnd,RECT rcDraw,TCHAR *strMenu,int strLen,WNDSTATE iState) 
	{ 
		RNHDC hDc(GetWindowDC(hWnd)); 
	 
		DrawBKMenu(hWnd,hDc,rcDraw,iState); 
 
		DrawMenuText(hDc,rcDraw,strMenu,strLen,iState); 
 
		return 0; 
	} 
 
	int DrawMenuItem(HWND hWnd,int iItem,WNDSTATE iState) 
	{ 
		TCHAR strMenu[MENUTEXTLEN] = {0}; 
		int iStrLen = FindMenuText(m_hMenu,iItem,strMenu,MENUTEXTLEN); 
		DrawFaceText(hWnd,rcItems[iItem],strMenu,iStrLen,iState); 
 
		return 0; 
	} 
	 
	int DrawMenuState(HWND hWnd,int iItem,WNDSTATE iState) 
	{ 
		DrawMenuItem(hWnd,iPrevMenu,SKIN_NORMAL); 
 
		prevRect = rcItems[iItem]; 
		iPrevMenu = iItem; 
 
		DrawMenuItem(hWnd,iItem,iState); 
		 
		return 0; 
	} 
	int	CaclMenuRect() 
	{ 
		SKRect rcWnd = SkinRect::GetWndRect(m_hWnd); 
		FRMPARAM frm = SkinIni::Instance()->GetFrmParam(); 
 
		if(m_rcBar.right > 0 && 
		   m_rcBar.right == (rcWnd.Width() - frm.nRightWidth)) 
		{ 
			return 1; 
		} 
 
		m_rcBar.top = frm.nTopHeight; 
		m_rcBar.left = frm.nLeftWidth; 
		 
		m_rcBar.right = rcWnd.Width() - frm.nRightWidth; 
		m_rcBar.bottom = m_rcBar.top + CaclMenuBarHei(m_hWnd);//SkinCommon::GetCYMenu();		 
		 
		return 0; 
	} 
 
	static int	AddMenuNode(HWND hWnd,PSKINMBARNODE *pmInfo) 
	{ 
		if(NULL == *pmInfo || NULL == hWnd) return -1; 
 
		(*pmInfo)->data->m_hWnd = hWnd; 
		(*pmInfo)->data->m_hMenu = GetMenu(hWnd); 
				 
		(*pmInfo)->data->CaclMenuRect(); 
		 
		::SetMenu(hWnd,NULL); 
		 
		return 0; 
	} 
 
	void	DrawBKMenu(HWND hWnd,RNHDC &hMemDc,RECT rcDraw,WNDSTATE iState) 
	{ 
		if(SKIN_HOT == iState) 
		{ 
			Rectangle(hMemDc,rcDraw.left, 
					  rcDraw.top, 
					  rcDraw.right, 
					  rcDraw.bottom); 
			return; 
		} 
 
		if(SKIN_DOWN == iState) 
		{ 
			HBRUSH hb = CreateSolidBrush(RGB(125,125,125)); 
			HBRUSH hOld = (HBRUSH)SelectObject(hMemDc,hb); 
			Rectangle(hMemDc,rcDraw.left, 
					  rcDraw.top, 
					  rcDraw.right, 
					  rcDraw.bottom); 
			SelectObject(hMemDc,hOld); 
			DeleteObject(hb); 
			return; 
		} 
 
		RNHBitmap bmMenu(SkinIni::Instance()->GetMenuBGImg()); 
		if(!bmMenu) 
		{ 
			HBRUSH hb = (HBRUSH)GetClassLong(hWnd,GCL_HBRBACKGROUND); 
			FillRect(hMemDc,&rcDraw,hb); 
		} 
		else 
		{ 
			SkinDraw::Draw(hMemDc,bmMenu,rcDraw); 
		} 
	} 
 
	static int FindMenuText(HMENU &hMenu,int nIndex,TCHAR *strMenu,int mLen) 
	{ 
		UINT nItems = GetMenuItemCount(hMenu); 
		if(nIndex < 0 || nIndex >= nItems) return 0; 
 
		return GetMenuString(hMenu,nIndex,strMenu,mLen,MF_BYPOSITION); 
	} 
 
public: 
	HWND	m_hWnd; 
	HWND	m_mHwnd; 
	HWND	m_hOldFocusWnd; 
	HMENU	m_hMenu; 
	short	m_nItem; 
	HMENU   m_hMenuTracking; 
		 
	RECT	m_rcBar; 
	RECT	prevRect; 
	short	iPrevMenu; 
	RECT	rcItems[MENUITEMCOUNT]; 
	bool	bBarFocused;  // bar, popup has the focus 
	bool	bFocused;     // item has the focus 
	bool	bTracking; 
	bool	bItemTracking; 
	bool	bDraw; 
	bool	bDrawText; 
	bool	m_bSelectFirst; 
	bool	m_bContinue; 
	bool	m_bPrimaryMenu; 
	bool	m_bSubmenuItem; 
	bool	m_bItemDropped; 
	bool	m_bEscape; 
}; 
 
#endif