⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cbmpmenu.cpp

📁 一个功能挺多的
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	font.CreateFontIndirect ( &lf );
	
	CFont * OldFont = dc.SelectObject ( &font );
	
	COLORREF OldColor = dc.SetTextColor(m_ColorText);
	
	dc.SetBkMode(TRANSPARENT);
		
	rect2.left = 2;
	dc.DrawText ( GetTitle(), &rect2, DT_BOTTOM | DT_LEFT | DT_SINGLELINE );
	
	// restore old text color
	dc.SetTextColor( OldColor);
	// restore old font
	dc.SelectObject(OldFont);
	
	// clean up
	font.DeleteObject();
*/

	//Fill the blank space with whiteness
	dc.FillSolidRect(&rect, GetSysColor(COLOR_BTNHIGHLIGHT));

	//draw the vertical bitmap if required
	if(m_hBitmap)
	{
		CDC memDC;
		memDC.CreateCompatibleDC(&dc);
		HBITMAP hOldBmp = (HBITMAP)SelectObject(memDC.GetSafeHdc(), m_hBitmap);
		
		BITMAP bitmap;
		GetObject(m_hBitmap, sizeof(bitmap), &bitmap);
		
		//draw the bitmap
		if(m_bStretchBmp)
			dc.StretchBlt(0, 0, m_nTBOffSet, rect.Height(), &memDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, 
				SRCCOPY);
		else
		{
			//draw using pattern brush
			HBRUSH hPatternBr = CreatePatternBrush(m_hBitmap);
			RECT rect1={0, 0, m_nTBOffSet, rect.Height()};
			FillRect(dc.GetSafeHdc(), &rect1, hPatternBr);
			DeleteObject(hPatternBr);
		}

		//restore objects
		memDC.SelectObject(hOldBmp);
		memDC.DeleteDC();
	}
}

//Used to place the menu window
void CBmpMenu::PositionMenuWindow(CPoint pt, CRect* pItemRect, CRect menuRect)
{
	CRect deskRect;

	GetDesktopWindow()->GetWindowRect(&deskRect);

	//Check if this is a submenu...then we need to check either right top or right bottom point of menuRect
	if(pItemRect)
	{
		if(PositionSubMenu(CPoint(pItemRect->right, pItemRect->top), menuRect, TRUE, TRUE) == FALSE)
		{
			if(PositionSubMenu(CPoint(pItemRect->right, pItemRect->bottom), menuRect, TRUE, FALSE) == FALSE)
			{
				if(PositionSubMenu(CPoint(pItemRect->left, pItemRect->top), menuRect, FALSE, TRUE) == FALSE)
				{
					PositionSubMenu(CPoint(pItemRect->left, pItemRect->bottom), menuRect, FALSE, FALSE);
				}	
			}	
		}
		return;
	}

	//we need to check which position is best for showing menu
	//check for left top alignment with pt
	if((pt.x+menuRect.Width() < deskRect.right) &&
		(pt.y+menuRect.Height() < deskRect.bottom))
	{
		MoveWindow(pt.x, pt.y, menuRect.Width(), menuRect.Height());	
	}
	else //right top
	if((pt.x-menuRect.Width() > deskRect.left) && 
		(pt.y+menuRect.Height() < deskRect.bottom))
	{
		MoveWindow(pt.x-menuRect.Width(), pt.y, menuRect.Width(), menuRect.Height());
	}
	else
	//check for left bottom alignment with pt
	if((pt.x+menuRect.Width() < deskRect.right) && 
		(pt.y-menuRect.Height() > deskRect.top))
	{
		MoveWindow(pt.x, pt.y-menuRect.Height(), menuRect.Width(), menuRect.Height());
	}
	else
	//check for right bottom alignment with pt
	if((pt.x-menuRect.Width() > deskRect.left) && 
		(pt.y-menuRect.Height() > deskRect.top))
	{
		MoveWindow(pt.x-menuRect.Width(), pt.y-menuRect.Height(), menuRect.Width(), menuRect.Height());
	}
	else //left top is default
		MoveWindow(pt.x, pt.y, menuRect.Width(), menuRect.Height());
}

BOOL
CBmpMenu::PositionSubMenu(CPoint pt, CRect menuRect, BOOL bRtAlign, BOOL bDnAlign)
{
	CRect deskRect;

	GetDesktopWindow()->GetWindowRect(&deskRect);

	if(bRtAlign && bDnAlign)
	{
		if((pt.x+menuRect.Width() < deskRect.right) &&
			(pt.y+menuRect.Height() < deskRect.bottom))
		{
			MoveWindow(pt.x, pt.y, menuRect.Width(), menuRect.Height());	
		}
		else
		{
			return FALSE;
		}
	}

	if(bRtAlign && ! bDnAlign)
	{
		if((pt.x+menuRect.Width() < deskRect.right) && 
			(pt.y-menuRect.Height() > deskRect.top))
		{
			MoveWindow(pt.x, pt.y-menuRect.Height(), menuRect.Width(), menuRect.Height());
		}
		else
		{
			return FALSE;
		}
	}

	if(!bRtAlign && bDnAlign)
	{
		if((pt.x-menuRect.Width() > deskRect.left) && 
			(pt.y+menuRect.Height() < deskRect.bottom))
		{
			MoveWindow(pt.x-menuRect.Width(), pt.y, menuRect.Width(), menuRect.Height());
		}
		else
		{
			return FALSE;
		}
	}

	if(!bRtAlign && !bDnAlign)
	{
		if((pt.x-menuRect.Width() > deskRect.left) && 
			(pt.y-menuRect.Height() > deskRect.top))
		{
			MoveWindow(pt.x-menuRect.Width(), pt.y-menuRect.Height(), menuRect.Width(), menuRect.Height());
		}
		else
		{
			return FALSE;
		}
	}
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// MenuToolBar

MenuToolBar::MenuToolBar()
{
	m_nLastLBDownIndex = -1;
	m_nLastHoverIndex  = -1;
	m_oHoverPt.x = -1;
	m_oHoverPt.y = -1;
	m_nSelectedItem = -1;
}

MenuToolBar::~MenuToolBar()
{
	m_oMenuFont.DeleteObject();
}


BEGIN_MESSAGE_MAP(MenuToolBar, CToolBar)
	//{{AFX_MSG_MAP(MenuToolBar)
	ON_WM_CREATE()
	ON_WM_LBUTTONDOWN()
	ON_WM_KEYDOWN()
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW , OnCustomDrawNotify)
	ON_WM_MOUSEMOVE()
	ON_WM_CHAR()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_LBUTTONDOWNAFTER, OnPostLbuttonMsg)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// MenuToolBar message handlers

void MenuToolBar::OnCustomDrawNotify(LPARAM lParam, LRESULT* pResult )
{
	LPNMTBCUSTOMDRAW lpNMCustomDraw = (LPNMTBCUSTOMDRAW) lParam;

	if(!lParam)
		return;

	if(lpNMCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
	{
		*pResult = CDRF_NOTIFYITEMDRAW ;	//we need CDDS_ITEMPREPAINT notifications
		return;
	}

	if(lpNMCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
	{
		MENUITEMINFO menuInfo = *(MENUITEMINFO*)(lpNMCustomDraw->nmcd.lItemlParam);
		CRect rcItem = lpNMCustomDraw->nmcd.rc;
		CDC dc;
		CFont* pOldFont;
		dc.Attach(lpNMCustomDraw->nmcd.hdc);

		//Check if this is a hot item
		if(lpNMCustomDraw->nmcd.uItemState & CDIS_HOT)
		{
			lpNMCustomDraw->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
			lpNMCustomDraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHT);

			//check if last hot item was same as this hot item. If not then we need to send notification
			//to owner window
			if(m_nSelectedItem != (int)lpNMCustomDraw->nmcd.dwItemSpec)
			{
				int ndx = lpNMCustomDraw->nmcd.dwItemSpec;

				//for submenus we need to send index of this item rather than Command Id
				if(menuInfo.hSubMenu)
				{
					ndx = CommandToIndex(lpNMCustomDraw->nmcd.dwItemSpec);
					menuInfo.fState = MF_POPUP;
				}

				//Send WM_MENUSELECT notification message to owner window
				((CBmpMenu*)GetParent())->m_pOwnerWnd->SendMessage(WM_MENUSELECT, 
									MAKEWPARAM(ndx, menuInfo.fState), 
									(LPARAM)((CBmpMenu*)GetParent())->m_hMenu);

			}
			//store th hot item index
			m_nSelectedItem = lpNMCustomDraw->nmcd.dwItemSpec;
		}
		else
		{
			lpNMCustomDraw->clrText = GetSysColor(COLOR_MENUTEXT);
			lpNMCustomDraw->clrHighlightHotTrack = GetSysColor(COLOR_MENU);
		}
		
		if(menuInfo.fState & MF_GRAYED)
		{
			lpNMCustomDraw->clrText = GetSysColor(COLOR_GRAYTEXT);
			//this is required for checkmark color
			dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT));
		}
		else
			dc.SetTextColor(GetSysColor(COLOR_MENUTEXT));

		//leave a one pixel gap
		rcItem.left++;

		//draw the background rectangle first
		dc.FillSolidRect(rcItem, lpNMCustomDraw->clrHighlightHotTrack);

		//Select menu font
		pOldFont = dc.SelectObject(&m_oMenuFont);

		//check if we need to draw the checkmark for this menu item
		if(menuInfo.fState & MF_CHECKED)
		{
			CRect CheckRect = rcItem;
			CheckRect.right = CheckRect.left + CheckRect.Height();
			//draw the checkmarked image
			Draw3DCheckmark(dc, CheckRect, lpNMCustomDraw->nmcd.uItemState & CDIS_HOT, 
				menuInfo.hbmpChecked, TRUE, menuInfo.fState & MF_GRAYED);
		}
		else
		{
			//if unchecked bmp is provided
			if(menuInfo.hbmpUnchecked)
			{
				CRect CheckRect = rcItem;
				CheckRect.right = CheckRect.left + CheckRect.Height();
				//draw the UnCheckmarked image
				Draw3DCheckmark(dc, CheckRect, lpNMCustomDraw->nmcd.uItemState & CDIS_HOT, 
					menuInfo.hbmpUnchecked, FALSE, menuInfo.fState & MF_GRAYED);
			}
		}

		//draw the background rectangle for this button and then draw menu text
		dc.SetTextColor(lpNMCustomDraw->clrText);
		dc.SetBkMode(TRANSPARENT);

		//calculate text rectangle. The width of Checkmark has to be added
		rcItem.left += rcItem.Height() + 2;

		//Check if the item is disabled or grayed. Then we need to draw embossed text
		if((menuInfo.fState & MF_GRAYED) && !(lpNMCustomDraw->nmcd.uItemState & CDIS_HOT))
		{
			rcItem.OffsetRect(1,1);
			dc.SetTextColor(GetSysColor(COLOR_3DHILIGHT));
			dc.DrawText(menuInfo.dwTypeData, rcItem, DT_SINGLELINE|DT_LEFT|DT_VCENTER);
			dc.SetTextColor(lpNMCustomDraw->clrText);
			rcItem.OffsetRect(-1,-1);
		}

		//draw the text
		dc.DrawText(menuInfo.dwTypeData, rcItem, DT_SINGLELINE|DT_LEFT|DT_VCENTER);
		dc.SelectObject(pOldFont);

		//draw the popup arrow mark
		if(menuInfo.hSubMenu)
		{
			rcItem.left = rcItem.right-GetSystemMetrics(SM_CXMENUCHECK)*3/4;
			rcItem.right = rcItem.left + GetSystemMetrics(SM_CXMENUCHECK);
			CRect arrowRect = rcItem;
			arrowRect.top += (rcItem.Height()-GetSystemMetrics(SM_CXMENUCHECK))/2;
			arrowRect.bottom = arrowRect.top + GetSystemMetrics(SM_CXMENUCHECK);

			arrowRect.right -= GetSystemMetrics(SM_CXMENUCHECK)*3/10;
			arrowRect.left += GetSystemMetrics(SM_CXMENUCHECK)*3/10;
			arrowRect.top += GetSystemMetrics(SM_CXMENUCHECK)*3/10;
			arrowRect.bottom -= GetSystemMetrics(SM_CXMENUCHECK)*3/10;

			POINT points[3];
			points[0].x = arrowRect.left;
			points[0].y = arrowRect.top;
			points[1].x = arrowRect.left+arrowRect.Width()/2;
			points[1].y = arrowRect.top+arrowRect.Height()/2;
			points[2].x = points[0].x;
			points[2].y = points[1].y + arrowRect.Height()/2;

			CPen oPen(PS_SOLID, 1, lpNMCustomDraw->clrText), *pOldPen;
			pOldPen=dc.SelectObject(&oPen);
			
			dc.MoveTo(points[0]);
			dc.LineTo(points[1]);
			dc.LineTo(points[2]);
			dc.LineTo(points[0]);

			dc.SelectObject(pOldPen);

			CBrush oBrush(lpNMCustomDraw->clrText), *pOldBrush;
			pOldBrush = dc.SelectObject(&oBrush);
			dc.FloodFill(points[0].x +1, points[0].y +2, lpNMCustomDraw->clrText);
			dc.SelectObject(pOldBrush);
		}

		//detach DC
		dc.Detach();
		*pResult = CDRF_SKIPDEFAULT;
	}
	else
		*pResult = 0;

}

//////////////////
// Draw 3D checkmark
BOOL MenuToolBar::Draw3DCheckmark(CDC& dc, CRect rc,
	BOOL bSelected, HBITMAP hbmCheck, BOOL bDrawSunkenBdr, BOOL bGrayImage)
{
	// get checkmark bitmap if none, use Windows standard
	HBITMAP hbm = hbmCheck;

	if (!hbmCheck) {
		CBitmap bm;
		bm.LoadOEMBitmap(OBM_CHECK);
		hbm = (HBITMAP)bm.Detach();
		if(!hbm)
			return FALSE;
	}
	
	// center bitmap in caller's rectangle
	BITMAP bm;
	::GetObject(hbm, 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;

	//draw background rectangle first
	if(hbmCheck && bDrawSunkenBdr)
		dc.FillSolidRect(rc, GetSysColor(COLOR_MENU));

	// select checkmark into memory DC
	CDC memdc;
	memdc.CreateCompatibleDC(&dc);

	//change the background colors of bitmap
	if(hbmCheck)
	{
		hbm = GetSysColorBitmap(dc.GetSafeHdc(), hbm, bGrayImage, bSelected);
	}

	HBITMAP hOldBM = (HBITMAP)::SelectObject(memdc, hbm);

	// set BG color based on selected state
	COLORREF colorOld = dc.SetBkColor(GetSysColor((bSelected && !bGrayImage)?COLOR_HIGHLIGHT:COLOR_MENU));
	dc.BitBlt(rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
		&memdc, p.x, p.y, SRCCOPY);
	dc.SetBkColor(colorOld);

	::SelectObject(memdc, hOldBM); //restore

	//Delete hbm object..it is either created by GetSysColorBitmap function or LoadOEMBitmap
	DeleteObject(hbm);			
	memdc.DeleteDC();

	//Check if we need to draw sunken border
	if(bDrawSunkenBdr)
	{
		dc.DrawEdge(rc, BDR_SUNKENOUTER, BF_RECT);

		//draw background
		CBrush brush;
		CBitmap bmp;
		WORD      Bits[8] = { 0x0055, 0x00aa, 0x0055, 0x00aa,
							 0x0055, 0x00aa, 0x0055, 0x00aa };
		bmp.CreateBitmap( 8, 8, 1, 1, &Bits );
		//hatched background
		brush.CreatePatternBrush(&bmp);

		//if item is selected, then we draw plain background
		CBrush brush1(GetSysColor(COLOR_MENU));

		CBrush* oldBr = dc.SelectObject(bSelected ? &brush1 : &brush);

		//the text color is used by pattern brush
		dc.SetTextColor(GetSysColor(COLOR_3DHIGHLIGHT));
		dc.SetBkColor(GetSysColor(COLOR_MENU));

		if(!hbmCheck)
			dc.ExtFloodFill(rc.left+1, rc.top+1, GetSysColor(bSelected?COLOR_HIGHLIGHT:COLOR_MENU), FLOODFILLSURFACE);
		else
			dc.ExtFloodFill(rc.left+1, rc.top+1, GetSysColor(COLOR_MENU), FLOODFILLSURFACE);

		//cleanup
		dc.SelectObject(oldBr);
		brush.DeleteObject();
		brush1.DeleteObject();
		bmp.DeleteObject();
	}

	return TRUE;
}

int MenuToolBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	lpCreateStruct->style &= ~WS_VISIBLE;
	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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -