?? cbmpmenu.cpp
字號:
if (CToolBar::OnCreate(lpCreateStruct) == -1)
return -1;
ModifyStyleEx(0, WS_EX_TOOLWINDOW);
GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
NONCLIENTMETRICS nc;
ZeroMemory(&nc, sizeof(nc));
nc.cbSize = sizeof(nc);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &nc, 0);
m_oMenuFont.CreateFontIndirect(&nc.lfMenuFont);
SetFont(&m_oMenuFont);
return 0;
}
void MenuToolBar::OnLButtonDown(UINT nFlags, CPoint point)
{
//Calculate button index and post a user define message to ourselves..so that this function returns immediately
int nBtnIndex = GetToolBarCtrl().HitTest(&point);
TBBUTTON tbb;
GetToolBarCtrl().GetButton(nBtnIndex, &tbb);
//if this button is disabled or grayed down...then we simply return
BOOL bRet = (((MENUITEMINFO*)(tbb.dwData))->fState & MF_GRAYED) ||
(((MENUITEMINFO*)(tbb.dwData))->fState & MF_DISABLED);
if(bRet)
return;
if(nBtnIndex >= 0)
{
if(m_nLastLBDownIndex != nBtnIndex)
{
//If already another popup menu was opened, then we need to close that window
((CBmpMenu*)GetParent())->DestroySubMenus();
PostMessage(WM_LBUTTONDOWNAFTER, nFlags, MAKELPARAM(point.x, point.y));
m_nLastLBDownIndex = nBtnIndex;
}
}
}
void MenuToolBar::OnPostLbuttonMsg(UINT nFlags, LPARAM lp)
{
//claculate the button index
CPoint point(LOWORD(lp), HIWORD(lp));
int nBtnIndex = GetToolBarCtrl().HitTest(&point);
TBBUTTON tbb;
GetToolBarCtrl().GetButton(nBtnIndex, &tbb);
//if the click was on a button corresponding to popup item, then we need to open up popup menu
//and don't pass the message up windows hirarchy.
if(tbb.dwData && ((MENUITEMINFO*)(tbb.dwData))->hSubMenu)
{
((CBmpMenu*)GetParent())->SendMessage(WM_POPUPSUBMENU, lp, (MENU_SELECTFIRSTITEM & nFlags)?MENU_SELECTFIRSTITEM:0);
return;
}
//If this is a valid button and no submenu then send wm_command message to owner and close all menus
((CBmpMenu*)GetParent())->m_pOwnerWnd->PostMessage(WM_COMMAND, MAKEWPARAM(tbb.idCommand, 0), 0);
((CBmpMenu*)GetParent())->DestroyRootMenu();
}
void MenuToolBar::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
int nBtnIndex = GetToolBarCtrl().HitTest(&point);
//skip mouse move message if this button is disabled or grayed or inactive
TBBUTTON tbb;
GetToolBarCtrl().GetButton(nBtnIndex, &tbb);
//if this button is disabled or grayed down...then we simply return
BOOL bRet = (((MENUITEMINFO*)(tbb.dwData))->fState & MF_GRAYED) ||
(((MENUITEMINFO*)(tbb.dwData))->fState & MF_DISABLED);
if(bRet)
return;
//skip WM_MOUSEMOVE message if the last mouse position is same as curent one.
static CPoint pt(0,0);
if(point != pt)
pt = point;
else
return;
if(nBtnIndex >= 0)
{
if(m_nLastHoverIndex != nBtnIndex)
{
m_nLastHoverIndex = nBtnIndex;
m_oHoverPt = point;
//Hovetrack only for submenu items
TRACKMOUSEEVENT tme = {sizeof(tme), TME_HOVER, m_hWnd, 0};
_TrackMouseEvent(&tme);
}
}
CToolBar::OnMouseMove(nFlags, point);
}
LRESULT MenuToolBar::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
//Garb WM_MOUSEHOVER message
if(message == WM_MOUSEHOVER)
{
if(m_nLastHoverIndex >= 0)
{
TBBUTTON tbb;
GetToolBarCtrl().GetButton(m_nLastHoverIndex, &tbb);
if(tbb.dwData)
{
//pass on left mouse down event for submenu items
if(((MENUITEMINFO*)(tbb.dwData))->hSubMenu)
{
SendMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(m_oHoverPt.x, m_oHoverPt.y));
SendMessage(WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(m_oHoverPt.x, m_oHoverPt.y));
}
else //delete any submenus present for this menu
{
((CBmpMenu*)GetParent())->DestroySubMenus();
m_nLastLBDownIndex = -1; //reset after destroying submenus
}
}
}
}
if(message == WM_RESETDATA)
m_nLastLBDownIndex = -1;
return CToolBar::DefWindowProc(message, wParam, lParam);
}
//Grab Key down events
BOOL MenuToolBar::KeyboardFilter(UINT nChar, UINT nRepCnt, UINT nFlags)
{
//On escape key, we close all menu windows
if(nChar==VK_ESCAPE)
{
((CBmpMenu*)GetParent())->DestroyRootMenu();
return TRUE;
}
//On left arrow...we need to close the current submenu and go to parent
if(nChar == VK_LEFT)
{
CWnd *pWnd = GetParent()->GetParent();
if(pWnd && IsWindow(pWnd->m_hWnd) && pWnd->IsKindOf(RUNTIME_CLASS(CBmpMenu)))
{
((CBmpMenu*)pWnd)->DestroySubMenus();
(CBmpMenu*)pWnd->SendMessage(WM_RESETDATA, 0, 0);
}
return TRUE;
}
if((nChar == VK_RIGHT) || (nChar == VK_RETURN))
{
if(m_nSelectedItem != -1)
{
int ndx = CommandToIndex(m_nSelectedItem);
if(ndx >= 0)
{
TBBUTTON tbb;
GetToolBarCtrl().GetButton(ndx, &tbb);
CRect rect;
GetToolBarCtrl().GetItemRect(ndx, &rect);
if(tbb.dwData)
{
//pass on left mouse down event for submenu items..also need to select the first submenu item
if((((MENUITEMINFO*)(tbb.dwData))->hSubMenu) || (nChar == VK_RETURN))
{
m_nLastLBDownIndex = -1;
SendMessage(WM_LBUTTONDOWN, MK_LBUTTON|MENU_SELECTFIRSTITEM, MAKELPARAM(rect.left+1, rect.top+1));
SendMessage(WM_LBUTTONUP, MK_LBUTTON|MENU_SELECTFIRSTITEM, MAKELPARAM(rect.left+1, rect.top+1));
}
}
}
}
return TRUE;
}
//pass on for further processing
OnChar(nChar, nRepCnt, nFlags);
return FALSE;
}
void MenuToolBar::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
if(KeyboardFilter(nChar,nRepCnt,nFlags))
return;
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
// User typed a char into menu. Look for item with & preceeding the char typed.
void MenuToolBar::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
//////////////////
UINT iCurrentItem = (UINT)-1; // guaranteed higher than any command ID
CUIntArray arItemsMatched; // items that match the character typed
UINT nItem = GetToolBarCtrl().GetButtonCount();
for (UINT i=0; i< nItem; i++)
{
// get menu info
TBBUTTON tbb;
GetToolBarCtrl().GetButton(i, &tbb);
if(tbb.dwData)
{
if(((MENUITEMINFO*)(tbb.dwData))->dwTypeData)
{
CString text = ((MENUITEMINFO*)(tbb.dwData))->dwTypeData;
int iAmpersand = text.Find('&');
if (iAmpersand >=0 && toupper(nChar)==toupper(text[iAmpersand+1]))
arItemsMatched.Add(i);
}
if ((UINT)SendMessage(TB_GETHOTITEM, 0, 0) == i)
iCurrentItem = i; // note index of current item
}
}
// arItemsMatched now contains indexes of items that match the char typed.
UINT nFound = arItemsMatched.GetSize();
if (nFound == 0)
{
//notify owner window and take corresponding action
UINT lRet = (((CBmpMenu*)GetParent())->m_pOwnerWnd)->SendMessage(WM_MENUCHAR, MAKEWPARAM(nChar, MF_POPUP),
(LPARAM)((CBmpMenu*)GetParent())->m_hMenu);
switch(HIWORD(lRet))
{
case MNC_CLOSE:
((CBmpMenu*)GetParent())->DestroyRootMenu();
break;
case MNC_SELECT:
//select the menu item
break;
case MNC_EXECUTE:
(((CBmpMenu*)GetParent())->m_pOwnerWnd)->SendMessage(WM_COMMAND, LOWORD(lRet), 0);
break;
}
return;
}
else if (nFound==1)
{
CRect rect;
GetToolBarCtrl().GetItemRect(arItemsMatched[0], &rect);
SendMessage(TB_SETHOTITEM, arItemsMatched[0], 0);
m_nLastLBDownIndex = -1;
SendMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left+1, rect.top+1));
SendMessage(WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(rect.left+1, rect.top+1));
return;
}
// more than one found--return 1st one past current selected item;
UINT iSelect = 0;
for (i=0; i < nFound; i++) {
if (arItemsMatched[i] > iCurrentItem) {
iSelect = i;
break;
}
}
SendMessage(TB_SETHOTITEM, iSelect, 0);
}
HBITMAP
GetSysColorBitmap(HDC hDC, HBITMAP hSourceBitmap, BOOL bMono, BOOL bSelected)
{
struct _COLORMAPTABLE{
COLORREF rgb;
int nSysColor;
};
_COLORMAPTABLE _ColorMap[]=
{
// mapping from color in DIB to system color
{ RGB(0x00, 0x00, 0x00), COLOR_BTNTEXT }, // black
{ RGB(0x80, 0x80, 0x80), COLOR_BTNSHADOW }, // dark gray
{ RGB(0xC0, 0xC0, 0xC0), COLOR_MENU }, // bright gray
{ RGB(0xFF, 0xFF, 0xFF), COLOR_BTNHIGHLIGHT } // white
};
HBITMAP hOldSourceBitmap, hOldDestBitmap, hDestBitmap;
HDC hMemSrc, hMemDest;
int height, width;
int i, j;
BITMAP SrcBitmap;
if(bSelected && !bMono)
_ColorMap[2].nSysColor= COLOR_HIGHLIGHT;
else
_ColorMap[2].nSysColor= COLOR_MENU;
// Step 1: Create a memory DC for the source and destination bitmaps
// compatible with the device used.
hMemSrc = CreateCompatibleDC(hDC);
hMemDest= CreateCompatibleDC(hDC);
// Step 2: Get the height and width of the source bitmap.
GetObject(hSourceBitmap, sizeof(BITMAP), (LPSTR)&SrcBitmap);
width = SrcBitmap.bmWidth;
height = SrcBitmap.bmHeight;
// Step 3: Select the source bitmap into the source DC. Create a
// destination bitmap, and select it into the destination DC.
hOldSourceBitmap = (HBITMAP)SelectObject(hMemSrc, hSourceBitmap);
hDestBitmap = CreateBitmap(height, width, (bMono)?1:SrcBitmap.bmPlanes,
(bMono)?1:SrcBitmap.bmBitsPixel, NULL);
if (hDestBitmap)
{
hOldDestBitmap = (HBITMAP)SelectObject(hMemDest, hDestBitmap);
// Step 4: Copy the pixels from the source to the destination.
for (i = 0; i < width; ++i)
{
for (j = 0; j < height; ++j)
{
//Get the color of source bitmap
COLORREF rgb = GetPixel(hMemSrc, i, j);
SetPixel(hMemDest, i, j, rgb);
if(!bMono)
{
//check if we need to change this color
for(int k=0; k<sizeof(_ColorMap)/sizeof(_ColorMap[0]); k++)
{
if(rgb == _ColorMap[k].rgb)
{
SetPixel(hMemDest, i, j, GetSysColor(_ColorMap[k].nSysColor));
break;
}
}
}
}
}
}
// Step 5: Destroy the DCs.
SelectObject(hMemSrc, hOldSourceBitmap);
SelectObject(hMemDest, hOldDestBitmap);
DeleteDC(hMemDest);
DeleteDC(hMemSrc);
// Step 6: Return the rotated bitmap.
return(hDestBitmap);
}
//新增漸變色條狀菜單顯示
#define NCOLORSHADES 128 // this many shades in gradient
static void PaintRect(CDC* pDC, int x, int y, int w, int h, COLORREF color)
{
CBrush brush(color);
CBrush* pOldBrush = pDC->SelectObject(&brush);
pDC->PatBlt(x, y, w, h, PATCOPY);
pDC->SelectObject(pOldBrush);
brush.DeleteObject();
}
void CBmpMenu::PaintGradiantRect(CDC *pDC, const RECT &rect,COLORREF clrFrom, COLORREF clrTo,
BOOL hori, BOOL ascend)
{
int cxCap = rect.right - rect.left;
int cyCap = rect.bottom - rect.top;
// Get the intensity values for the ending color
int r1 = GetRValue(clrTo); // red
int g1 = GetGValue(clrTo); // green
int b1 = GetBValue(clrTo); // blue
// Get the intensity values for the begining color
int r2 = GetRValue(clrFrom); // red
int g2 = GetGValue(clrFrom); // green
int b2 = GetBValue(clrFrom); // blue
int r, g, b;
if(hori) //paint horizontal rect;
{
int x = cxCap;
int w = x; // width of area to shade
int xDelta= max(w/NCOLORSHADES,1); // width of one shade band
while (x >= xDelta) {
x -= xDelta;
if (r1 > r2)
r = r1 - (r1-r2)*(w-x)/w;
else
r = r1 + (r2-r1)*(w-x)/w;
if (g1 > g2)
g = g1 - (g1-g2)*(w-x)/w;
else
g = g1 + (g2-g1)*(w-x)/w;
if (b1 > b2)
b = b1 - (b1-b2)*(w-x)/w;
else
b = b1 + (b2-b1)*(w-x)/w;
if(ascend) // Paint from left to right;
PaintRect(pDC, rect.left+x, rect.top, xDelta, cyCap, RGB(r, g, b));
else // Paint from right to left;
PaintRect(pDC, rect.right-x-xDelta, rect.top, xDelta, cyCap, RGB(r, g, b));
}
}
else //paint vertical rect;
{
int y = cyCap;
int w = y; // height of area to shade
int yDelta= max(w/NCOLORSHADES,1); // height of one shade band
//while (y >= yDelta) {
while (y > 0) {
y -= yDelta;
if (r1 > r2)
r = r1 - (r1-r2)*(w-y)/w;
else
r = r1 + (r2-r1)*(w-y)/w;
if (g1 > g2)
g = g1 - (g1-g2)*(w-y)/w;
else
g = g1 + (g2-g1)*(w-y)/w;
if (b1 > b2)
b = b1 - (b1-b2)*(w-y)/w;
else
b = b1 + (b2-b1)*(w-y)/w;
if(ascend) // Paint from top to bottom;
PaintRect(pDC, rect.left, rect.top+y, cxCap, yDelta, RGB(r, g, b));
else // Paint from bottom to top;
PaintRect(pDC, rect.left, rect.bottom-y-yDelta, cxCap, yDelta, RGB(r, g, b));
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -