📄 uicoolmenu.cpp
字号:
for (int i = 0; i < nToolbars; i++)
LoadToolbar(arToolbarID[i]);
}
//////////////////
// Get menu font, creating if needed
//
CFont* CCoolMenuManager::GetMenuFont()
{
if (!(HFONT)m_fontMenu) {
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
VERIFY(m_fontMenu.CreateFontIndirect(&info.lfMenuFont));
}
return &m_fontMenu;
}
//////////////////
// Handle WM_MEASUREITEM on behalf of frame: compute menu item size.
//
BOOL CCoolMenuManager::OnMeasureItem(LPMEASUREITEMSTRUCT lpms)
{
ASSERT(lpms);
CMyItemData* pmd = (CMyItemData*)lpms->itemData;
ASSERT(pmd);
if (lpms->CtlType != ODT_MENU || !pmd->IsMyItemData())
return FALSE; // not handled by me
// Addition: Philip Oldaker
// Pass it on to the shell if lpcm has been set
if (pmd->lpcm)
{
IContextMenu2 *lpcm2=NULL;
HRESULT hr = pmd->lpcm->QueryInterface(IID_IContextMenu2,(LPVOID*)&lpcm2);
if (SUCCEEDED(hr))
{
// switch context item data
lpms->itemData = (DWORD)pmd->pContext;
lpcm2->HandleMenuMsg(WM_MEASUREITEM,0,(LPARAM)lpms);
// clean up
lpms->itemData = (DWORD)pmd;
lpcm2->Release();
}
return TRUE;
}
/////////////////////
if (pmd->fType & MFT_SEPARATOR) {
// separator: use half system height and zero width
lpms->itemHeight = GetSystemMetrics(SM_CYMENU)>>1;
lpms->itemWidth = 0;
} else {
// compute size of 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(GetMenuFont());
dc.DrawText(pmd->text, rcText, DT_MYSTANDARD|DT_CALCRECT);
dc.SelectObject(pOldFont);
// height of item is just height of a standard menu item
lpms->itemHeight= max(GetSystemMetrics(SM_CYMENU), rcText.Height());
// 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 += m_szButton.cx<<1; // button width (L=button; R=empty margin)
// whatever value I return in lpms->itemWidth, Windows will add the
// width of a menu checkmark, so I must subtract to defeat Windows. Argh.
//
cx -= GetSystemMetrics(SM_CXMENUCHECK)-1;
lpms->itemWidth = cx; // done deal
CMTRACE(_T("OnMeasureItem for '%s':\tw=%d h=%d\n"), (LPCTSTR)pmd->text,
lpms->itemWidth, lpms->itemHeight);
}
return TRUE; // handled
}
/////////////////
// Handle WM_DRAWITEM on behalf of frame. Note: in all that goes
// below, can't assume rcItem.left=0 because of multi-column menus!
//
BOOL CCoolMenuManager::OnDrawItem(LPDRAWITEMSTRUCT lpds)
{
ASSERT(lpds);
// Omar L Francisco
if (lpds->CtlType != ODT_MENU)
return FALSE;
// Omar L Francisco
CMyItemData* pmd = (CMyItemData*)lpds->itemData;
if (!pmd->IsMyItemData())
return FALSE;
// Addition: Philip Oldaker
// Pass it on to the shell if this has been set
if (pmd->lpcm)
{
IContextMenu2 *lpcm2=NULL;
HRESULT hr = pmd->lpcm->QueryInterface(IID_IContextMenu2,(LPVOID*)&lpcm2);
if (SUCCEEDED(hr))
{
lpds->itemData = (DWORD)pmd->pContext;
lpcm2->HandleMenuMsg(WM_DRAWITEM,0,(LPARAM)lpds);
lpds->itemData = (DWORD)pmd;
lpcm2->Release();
}
return TRUE;
}
////////////////////////////////
ASSERT(lpds->itemAction != ODA_FOCUS);
ASSERT(lpds->hDC);
CDC dc;
dc.Attach(lpds->hDC);
const CRect& rcItem = lpds->rcItem;
if (pmd->fType & MFT_SEPARATOR) {
// draw separator
CRect rc = rcItem; // copy rect
rc.top += rc.Height()>>1; // vertical center
dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line
} else { // not a separator
CMTRACE(_T("OnDrawItem for '%s':\tw=%d h=%d\n"), (LPCTSTR)pmd->text,
rcItem.Width(), rcItem.Height());
BOOL bDisabled = lpds->itemState & ODS_GRAYED;
BOOL bSelected = lpds->itemState & ODS_SELECTED;
BOOL bChecked = lpds->itemState & ODS_CHECKED;
BOOL bHaveButn=FALSE;
// Paint button, or blank if none
CRect rcButn(rcItem.TopLeft(), m_szButton); // button rect
rcButn += CPoint(0, // center vertically
(rcItem.Height() - rcButn.Height())>>1 );
int iButton = pmd->iButton;
if (iButton >= 0 || iButton == USES_ICON)
{
// this item has a button!
bHaveButn = TRUE;
// compute point to start drawing
CSize sz = rcButn.Size() - m_szBitmap;
sz.cx >>= 1;
sz.cy >>= 1;
CPoint p(rcButn.TopLeft() + sz);
// draw disabled or normal
if (!bDisabled) {
// normal: fill BG depending on state
PLFillRect(dc, rcButn, GetSysColor(
(bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU));
// draw pushed-in or popped-out edge
if (bSelected || bChecked) {
CRect rc2 = rcButn;
dc.DrawEdge(rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER,
BF_RECT);
}
// draw the button!
if (iButton != USES_ICON)
{
m_ilButtons.Draw(&dc, iButton, p, ILD_TRANSPARENT);
}
else
{
dc.DrawState(p, CSize(0,0), pmd->hIcon, DSS_NORMAL,
(HBRUSH)NULL);
}
} else if (m_bUseDrawState) {
// use DrawState to draw disabled button: must convert to icon
if (iButton != USES_ICON)
{
HICON hIcon=m_ilButtons.ExtractIcon(iButton);
ASSERT(hIcon);
dc.DrawState(p, CSize(0,0), hIcon, DSS_DISABLED, (HBRUSH)NULL);
DestroyIcon(hIcon);
}
else
{
dc.DrawState(p, CSize(0,0), pmd->hIcon, DSS_DISABLED,
(HBRUSH)NULL);
}
} else
// use DrawEmbossed to draw disabeld button, w/color flag
if (iButton != USES_ICON)
{
PLDrawEmbossed(dc, m_ilButtons, iButton, p,
m_bDrawDisabledButtonsInColor);
}
else
{
int i = m_ilTemp.Add(pmd->hIcon);
PLDrawEmbossed(dc, m_ilTemp, i, p,
m_bDrawDisabledButtonsInColor);
m_ilTemp.Remove(i);
}
} else {
// no button: look for custom checked/unchecked bitmaps
CMenuItemInfo info;
info.fMask = MIIM_CHECKMARKS;
GetMenuItemInfo((HMENU)lpds->hwndItem,
lpds->itemID, MF_BYCOMMAND, &info);
if (bChecked || info.hbmpUnchecked) {
bHaveButn = Draw3DCheckmark(dc, rcButn, bSelected,
bChecked ? info.hbmpChecked : info.hbmpUnchecked);
}
}
// Done with button, now paint text. First do background if needed.
int cxButn = m_szButton.cx; // width of button
COLORREF colorBG = GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);
if (bSelected || lpds->itemAction==ODA_SELECT) {
// selected or selection state changed: paint text background
CRect rcBG = rcItem; // whole rectangle
if (bHaveButn) // if there's a button:
rcBG.left += cxButn + CXGAP; // don't paint over it!
PLFillRect(dc, rcBG, colorBG); // paint it!
}
// compute text rectangle and colors
CRect rcText = rcItem; // start w/whole item
rcText.left += cxButn + CXGAP + CXTEXTMARGIN; // left margin
rcText.right -= cxButn; // right margin
dc.SetBkMode(TRANSPARENT); // paint transparent text
COLORREF colorText = GetSysColor(bDisabled ? COLOR_GRAYTEXT :
bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT);
// Now paint menu item text. No need to select font,
// because windows sets it up before sending WM_DRAWITEM
//
if (bDisabled && (!bSelected || colorText == colorBG)) {
// disabled: draw hilite text shifted southeast 1 pixel for embossed
// look. Don't do it if item is selected, tho--unless text color same
// as menu highlight color. Got it?
//
DrawMenuText(dc, rcText + CPoint(1,1), pmd->text,
GetSysColor(COLOR_3DHILIGHT));
}
DrawMenuText(dc, rcText, pmd->text, colorText); // finally!
}
dc.Detach();
return TRUE; // handled
}
/////////////////
// Helper function to draw justified menu text. If the text contains a TAB,
// draw everything after the tab right-aligned
//
void CCoolMenuManager::DrawMenuText(CDC& dc, CRect rc, CString text,
COLORREF color)
{
CString left = text;
CString right;
int iTabPos = left.Find(_T('\t'));
if (iTabPos >= 0) {
right = left.Right(left.GetLength() - iTabPos - 1);
left = left.Left(iTabPos);
}
dc.SetTextColor(color);
dc.DrawText(left, &rc, DT_MYSTANDARD);
if (iTabPos > 0)
dc.DrawText(right, &rc, DT_MYSTANDARD|DT_RIGHT);
}
#ifndef OBM_CHECK
#define OBM_CHECK 32760 // from winuser.h
#endif
//////////////////
// Draw 3D checkmark
//
// dc device context to draw in
// rc rectangle to center bitmap in
// bSelected TRUE if button is also selected
// hbmCheck Checkmark bitmap to use, or NULL for default
//
BOOL CCoolMenuManager::Draw3DCheckmark(CDC& dc, const CRect& rc,
BOOL bSelected, HBITMAP hbmCheck)
{
// get checkmark bitmap if none, use Windows standard
if (!hbmCheck) {
CBitmap bm;
VERIFY(bm.LoadOEMBitmap(OBM_CHECK));
hbmCheck = (HBITMAP)bm.Detach();
ASSERT(hbmCheck);
}
// center bitmap in caller's rectangle
BITMAP bm;
::GetObject(hbmCheck, sizeof(bm), &bm);
int cx = bm.bmWidth;
int cy = bm.bmHeight;
CRect rcDest = rc;
CPoint p(0,0);
CSize delta(CPoint((rc.Width() - cx)/2, (rc.Height() - cy)/2));
if (rc.Width() > cx)
rcDest = CRect(rc.TopLeft() + delta, CSize(cx, cy));
else
p -= delta;
// select checkmark into memory DC
CDC memdc;
memdc.CreateCompatibleDC(&dc);
HBITMAP hOldBM = (HBITMAP)::SelectObject(memdc, hbmCheck);
// set BG color based on selected state
COLORREF colorOld =
dc.SetBkColor(GetSysColor(bSelected ? COLOR_MENU : COLOR_3DLIGHT));
dc.BitBlt(rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
&memdc, p.x, p.y, SRCCOPY);
dc.SetBkColor(colorOld);
::SelectObject(memdc, hOldBM); // restore
// draw pushed-in hilight.
if (rc.Width() > cx) // if room:
rcDest.InflateRect(1,1); // inflate checkmark by one pixel all around
dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
return TRUE;
}
//////////////////
// Handle WM_INITMENUPOPUP on behalf of frame.
//
void CCoolMenuManager::OnInitMenuPopup(CMenu* pMenu,
UINT nIndex, BOOL bSysMenu)
{
// Addition: Philip Oldaker
/////////////////////////
// Let the shell handle it
if (bSysMenu)
return;
for(UINT i=0;i < pMenu->GetMenuItemCount();i++)
{
CMyItemData* pmd = GetMyItemData(*pMenu,i,TRUE);
if (pmd->IsMyItemData() && pmd->lpcm)
{
IContextMenu2 *lpcm2=NULL;
HRESULT hr = pmd->lpcm->QueryInterface(IID_IContextMenu2,(LPVOID*)&lpcm2);
if (SUCCEEDED(hr))
{
SetMyItemData((CMyItemData*)pmd->pContext,*pMenu,i,TRUE);
lpcm2->HandleMenuMsg(WM_INITMENUPOPUP,(WPARAM)pMenu->GetSafeHmenu(),0);
SetMyItemData(pmd,*pMenu,i,TRUE);
lpcm2->Release();
}
return;
}
}
//////////////////////
if (m_bAutoAccel)
{
// check for new accels. If ASSERT bombs,
// you forgot to call Install.
// ASSERT_VALID(m_pFrame);
// HACCEL hAccel = m_pFrame->GetDefaultAccelerator();
HACCEL hAccel = NULL;
if (hAccel != m_hAccel)
LoadAccel(hAccel);
// 12 Nov 1998 - Wang Jun - Fixes debug assert in system menu.
// Check if click system menu.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -