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