Click here to Skip to main content
15,879,535 members
Articles / Desktop Programming / WTL

Some Mix-in classes that give your ATL/WTL program a better appearance

Rate me:
Please Sign up or sign in to vote.
4.04/5 (11 votes)
18 Apr 2004CPOL6 min read 71.6K   1.5K   18  
This article discusses some MixIn classs for WTL. These MixIn classes provides some features that WTL/ATL framework does not support, such as owner-draw menu, skinned dialog buttons and static text controls.
/****************************************************************************************
* Author : Simon Wang
*	Created time : 2003.09
*	home : http://www.winmsg.com/
*	contact us : inte2000@263.net
****************************************************************************************/
#ifndef __MENUHELP_H__
#define __MENUHELP_H__

template <class T>
class CMenuHelp
{
public:
	CMenuHelp()
	{
		m_hActiveMenu = NULL;
		m_crText = RGB(0,0,0);
		m_crHiText = RGB(0,0,0);
//		m_crBkGnd = RGB(222,222,222);
		m_crBkGnd = RGB(255,255,220);
		m_crHiBkGnd = RGB(255,238,194);
		m_nLeftSpace = 18;
	}

	~CMenuHelp() 
	{
	}
	
	HMENU AttachActiveMenu(HMENU hActiveMenu)
	{
		HMENU hTmp = m_hActiveMenu;
		m_hActiveMenu = hActiveMenu;
		int Count = GetMenuItemCount(m_hActiveMenu);
		for(int i = 0; i < Count; i++)
		{
			MENUITEMINFO mii;
			mii.cbSize = sizeof(MENUITEMINFO);
			mii.fMask = MIIM_FTYPE;
			GetMenuItemInfo(m_hActiveMenu,i,TRUE,&mii);
			mii.fType |= MFT_OWNERDRAW;
			SetMenuItemInfo(m_hActiveMenu,i,TRUE,&mii);
		}
		
		return hTmp;
	}

	HMENU DetachActiveMenu()
	{
		HMENU hTmp = m_hActiveMenu;
		m_hActiveMenu = NULL;
		return hTmp;
	}

	BEGIN_MSG_MAP(CMenuHelp)
		MESSAGE_HANDLER(WM_ENTERMENULOOP, OnEnterMenuLoop)
		MESSAGE_HANDLER(WM_EXITMENULOOP, OnExitMenuLoop)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_INITMENU, OnInitMenu)
//		MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
		MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
		MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
	END_MSG_MAP()

	LRESULT OnEnterMenuLoop(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	LRESULT OnExitMenuLoop(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		DetachActiveMenu();
		return 0;
	}

	LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
//		T*   pT = static_cast<T*>(this);
		HMENU hMenu = (HMENU)wParam;
		int Count = GetMenuItemCount(hMenu);
		ATLTRACE(_T("OnInitMenu : Count = %d,HMenu = %x\n"),Count,hMenu);
		AttachActiveMenu(hMenu);
		return 0;
	}

//@**#---2003-10-29 21:15:48 (NoName)---#**@
//	LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
//	{
//		HMENU hMenu = (HMENU)wParam;
//		return 0;
//	}
	
	LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		UINT uCtrlID = (UINT)wParam;
		LPMEASUREITEMSTRUCT pMI = (LPMEASUREITEMSTRUCT)lParam;
		if(pMI->CtlType == ODT_MENU)//We only want menu
		{
			ATLASSERT(m_hActiveMenu != NULL);

			MENUITEMINFO mii;
			mii.cbSize = sizeof(MENUITEMINFO);
			mii.fMask = MIIM_FTYPE | MIIM_STRING;
			mii.dwTypeData = NULL;
			GetMenuItemInfo(m_hActiveMenu,pMI->itemID,FALSE,&mii);//get the string length

			if(mii.fType & MFT_SEPARATOR)
			{
				pMI->itemWidth = 0;
				pMI->itemHeight = GetSystemMetrics(SM_CYMENU) >> 1;
			}
			else
			{
				int nWidth = 4;//left space : 2; right space 4
				int nHeight = 18;
				TCHAR *pszText = new TCHAR[mii.cch + 1];
				if(pszText != NULL)
				{
					mii.fMask = MIIM_FTYPE | MIIM_STRING;
					mii.dwTypeData = pszText;
					mii.cch += 1;
					GetMenuItemInfo(m_hActiveMenu,pMI->itemID,FALSE,&mii);//get menu text

					//for fix BUG on window 9X,Get bitmap handle sep
					mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_BITMAP;
					mii.cch = 0;
					GetMenuItemInfo(m_hActiveMenu,pMI->itemID,FALSE,&mii);//get menu text
//					if((mii.fState & MFS_CHECKED) == MFS_CHECKED || (mii.fState & MFS_UNCHECKED) == MFS_UNCHECKED)
/*
					if((mii.fState & MFS_CHECKED) == MFS_CHECKED)
					{
						m_nLeftSpace = max(16,m_nLeftSpace);
						nWidth += m_nLeftSpace;
					}
*/
					if(mii.hbmpItem != NULL)
					{
						m_nLeftSpace = max(18,m_nLeftSpace);
						nWidth += m_nLeftSpace;
					}
					else
					{
						m_nLeftSpace = max(10,m_nLeftSpace);
						nWidth += m_nLeftSpace;
					}

					HFONT hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
					HWND hWnd = ::GetDesktopWindow();
					HDC hDC = ::GetDC(hWnd);
					HGDIOBJ of = ::SelectObject(hDC,hFont);
					RECT rect;
					rect.left=rect.top=0;
					SIZE size;
					size.cy = ::DrawText(hDC,pszText,-1,&rect,DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CALCRECT);
					size.cx = rect.right - rect.left + 3;
					::SelectObject(hDC,of);
					::ReleaseDC(hWnd,hDC);  // Release the DC
					// Set width and height:
					nWidth += (size.cx + 1);//GAP;
					int temp = GetSystemMetrics(SM_CYMENU);
					nHeight = temp > 20 ? temp : 20;
				
					delete []pszText;
				}

				pMI->itemWidth = nWidth;
				pMI->itemHeight = nHeight;
			}

			return 1;
		}
		else
			return 0;
	}

	LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		UINT uCtrlID = (UINT)wParam;
		LPDRAWITEMSTRUCT pDI = (LPDRAWITEMSTRUCT)lParam;
		
		if(pDI->CtlType == ODT_MENU)//We only want menu
		{
			ATLASSERT(m_hActiveMenu != NULL);
/*			
			HWND hMenuWnd = WindowFromDC(pDI->hDC);
			HDC hWndDC = GetDC(hMenuWnd);
			RECT rcWnd,rcClient;
			GetWindowRect(hMenuWnd,&rcWnd);
			GetClientRect(hMenuWnd,&rcClient);
			
//			ScreenToClient(hMenuWnd, (LPPOINT)&rcWnd);
//			ScreenToClient(hMenuWnd, ((LPPOINT)&rcWnd)+1);
			rcWnd.right = rcWnd.right - rcWnd.left;
			rcWnd.bottom = rcWnd.bottom - rcWnd.top;
			rcWnd.left = rcWnd.top = 0;

			CDCHandle dc1 = hWndDC;
			dc1.FillSolidRect(&rcWnd,m_crBkGnd);
			ReleaseDC(hMenuWnd,hWndDC);
*/
			CDCHandle dc = pDI->hDC;
			RECT rect = pDI->rcItem;

			MENUITEMINFO mii;
			mii.cbSize = sizeof(MENUITEMINFO);
			mii.fMask = MIIM_FTYPE | MIIM_STRING;
			mii.dwTypeData = NULL;
			GetMenuItemInfo(m_hActiveMenu,pDI->itemID,FALSE,&mii);//get the string length

			if(mii.fType & MFT_SEPARATOR)
			{
				RECT rcLeft = rect;
				rcLeft.right = rcLeft.left + m_nLeftSpace;//bitmap width
				rect.left += m_nLeftSpace;
				dc.FillSolidRect(&rcLeft,RGB(215,241,215));
				dc.FillSolidRect(&rect,m_crBkGnd);

				rect.top += ((rect.bottom - rect.top) >> 1);
				dc.DrawEdge(&rect,EDGE_ETCHED,BF_TOP);			
			}
			else
			{
				TCHAR *pszText = new TCHAR[mii.cch + 1];
				if(pszText != NULL)
				{
					mii.fMask = MIIM_FTYPE | MIIM_STRING;
					mii.dwTypeData = pszText;
					mii.cch += 1;
					GetMenuItemInfo(m_hActiveMenu,pDI->itemID,FALSE,&mii);//get the string length

					mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_BITMAP;
					mii.cch = 0;
					GetMenuItemInfo(m_hActiveMenu,pDI->itemID,FALSE,&mii);//get bitmap handle


					RECT rcText,rcIcon;
					int dy;
					
					HFONT hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
					HFONT of = dc.SelectFont(hFont);
					
					dy = (rect.bottom - rect.top - 4 - 15) / 2;
					dy = (dy < 0) ? 0 : dy;

//					if(mii.hbmpItem != NULL || (mii.fState & MFS_CHECKED) == MFS_CHECKED)
						SetRect(&rcText,rect.left + m_nLeftSpace + 6,rect.top,rect.right,rect.bottom);
//					else
//						SetRect(&rcText,rect.left + 2,rect.top,rect.right,rect.bottom);
					
					rcIcon.left = rect.left + 2;
					rcIcon.right = rcIcon.left + m_nLeftSpace;
					rcIcon.top = rect.top + 2;
					rcIcon.bottom = rcIcon.top + 16;

					if(pDI->itemAction & ODA_DRAWENTIRE)
					{
						RECT rcLeft = rect;
						rcLeft.right = rcLeft.left + m_nLeftSpace;//bitmap width
						rect.left += m_nLeftSpace;
						dc.FillSolidRect(&rcLeft,RGB(215,241,215));
						dc.FillSolidRect(&rect,m_crBkGnd);

						if(mii.hbmpItem != NULL)//have icon
						{
							//draw the bitmap,not support now
						}
						else if((mii.fState & MFS_CHECKED) == MFS_CHECKED)
						{
							//draw the check mark
							HPEN hCheckPen = CreatePen(PS_SOLID, 2, m_crText);
							HPEN hop = dc.SelectPen(hCheckPen);

							dc.MoveTo(rcIcon.left + 2,rcIcon.top + 3);
							dc.LineTo(rcIcon.left + 3,rcIcon.top + 8);
							dc.MoveTo(rcIcon.left + 3,rcIcon.top + 9);
							dc.LineTo(rcIcon.left + 9,rcIcon.top + 3);

							dc.SelectPen(hop);
							DeleteObject(hCheckPen);
						}

						RECT rect2;
						SetRect(&rect2,rcText.left + 4,rcText.top + 1,rcText.right - 2,rcText.bottom - 1);
						COLORREF oclr = dc.SetTextColor(m_crText);
						int mode = dc.SetBkMode(TRANSPARENT);
						dc.DrawText(pszText,-1,&rect2,DT_LEFT|DT_NOCLIP|DT_SINGLELINE|DT_VCENTER);
						dc.SetBkMode(mode);
						dc.SetTextColor(oclr);
					}//if (lpDIS->itemAction & ODA_DRAWENTIRE)

					//Draws the selected item
					if((pDI->itemState & ODS_SELECTED) && (pDI->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
					{
						RECT rect2;
						if(mii.hbmpItem != NULL || (mii.fState & MFS_CHECKED) == MFS_CHECKED)
						{
							SetRect(&rect2,rcIcon.left - 2,rcIcon.top - 2,rcIcon.right + 2,rcIcon.bottom + 2);
							dc.Draw3dRect(&rect2,::GetSysColor(COLOR_3DHILIGHT),::GetSysColor(COLOR_3DDKSHADOW));
							rect2 = rcText;
						}
						else
						{
							SetRect(&rect2,rect.left + 2,rect.top + 1,rect.right - 2,rect.bottom - 1);
						}
						
						//draw hightlight background
//@**#---2004-04-14 20:54:30 (NoName)---#**@
//						RECT rcLeft = rect;
//						rcLeft.right = rcLeft.left + m_nLeftSpace;//bitmap width
//						rect.left += m_nLeftSpace;
//						dc.FillSolidRect(&rcLeft,RGB(215,241,215));
//						dc.FillSolidRect(&rect,m_crBkGnd);
						
						dc.FillSolidRect(&rect2,m_crHiBkGnd);
						HPEN penFrame = CreatePen(PS_SOLID, 1, RGB(0,0,128));
						HPEN hOP = dc.SelectPen(penFrame);
						dc.SelectStockBrush(NULL_BRUSH);
						dc.Rectangle(&rect2);
						dc.SelectPen(hOP);
						DeleteObject(penFrame);
						//draw highlight text
						SetRect(&rect2,rcText.left + 4,rcText.top + 1,rcText.right - 2,rcText.bottom - 1);
						COLORREF oclr = dc.SetTextColor(m_crHiText);
						COLORREF crBgOld = dc.SetBkColor(m_crHiBkGnd);
						dc.DrawText(pszText,-1,&rect2,DT_LEFT|DT_NOCLIP|DT_SINGLELINE|DT_VCENTER);
						dc.SetBkColor(crBgOld);
						dc.SetTextColor(oclr);
					}

					//Draws the deselected item
					if(!(pDI->itemState & ODS_SELECTED) && (pDI->itemAction & ODA_SELECT))
					{
						RECT rect2;
						if(mii.hbmpItem != NULL || (mii.fState & MFS_CHECKED) == MFS_CHECKED)
						{
							SetRect(&rect2,rcIcon.left-2,rcIcon.top-2,rcIcon.right+2,rcIcon.bottom+2);
							dc.Draw3dRect(&rect2,m_crBkGnd,m_crBkGnd);
							rect2 = rcText;
						}
						else
						{
							SetRect(&rect2,rect.left + 2,rect.top + 1,rect.right - 2,rect.bottom - 1);
						}

						//draw background
						RECT rcLeft = rect;
						rcLeft.right = rcLeft.left + m_nLeftSpace;//bitmap width
						rect.left += m_nLeftSpace;
						dc.FillSolidRect(&rcLeft,RGB(215,241,215));
						dc.FillSolidRect(&rect,m_crBkGnd);
//						dc.FillSolidRect(&rect2,m_crBkGnd);
						SetRect(&rect2,rcText.left+4,rcText.top+1,rcText.right-2,rcText.bottom-1);
						//draw Text
						COLORREF oclr = dc.SetTextColor(m_crText);
						COLORREF crBgOld = dc.SetBkColor(m_crBkGnd);
						dc.DrawText(pszText,-1,&rect2,DT_LEFT|DT_NOCLIP|DT_SINGLELINE|DT_VCENTER);
						dc.SetBkColor(crBgOld);
						dc.SetTextColor(oclr);
					}
					
					dc.SelectFont(of);
					
					delete []pszText;
				}
			}

			return 1;
		}
		else
			return 0;
	}


protected:
	HMENU m_hActiveMenu;
	COLORREF m_crText;
	COLORREF m_crHiText;
	COLORREF m_crBkGnd;
	COLORREF m_crHiBkGnd;
	int m_nLeftSpace;
	//CSimpleArray<t_ButtonClass *> m_arButtons;
};


#endif //__MENUHELP_H__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
China China
I had graduated from HuaZhong University of Science & Technology. Now, I'm working in ZTE.

Comments and Discussions