www.pudn.com > DiskInfo.tgz > Flatbutton.cpp


///////////////////////////////////////////////////////////////////////////// 
// Copyright (C) 1998 by Yuheng Zhao 
// All rights reserved 
// 
// Distribute freely, except: don't remove my name from the source or 
// documentation (don't take credit for my work), mark your changes (don't 
// get me blamed for your possible bugs), don't alter or remove this 
// notice. 
// No warrantee of any kind, express or implied, is included with this 
// software; use at your own risk, responsibility for damages (if any) to 
// anyone resulting from the use of this software rests entirely with the 
// user. 
// 
// If you have any questions, I can be reached as follows: 
//    yuheng@ministars.com 
// 
///////////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "flatbutton.h" 
 
///////////////////////////////////////////////////////////////////////////// 
// CFlatButton 
 
CFlatButton::CFlatButton() 
{ 
	dwFlags = FBS_BORDER|FBS_FOCUS|FBS_ROLLOVER; 
 
	m_bMouseIn = FALSE; 
	m_bChecked = FALSE; 
	m_bClickAgain = FALSE; 
} 
 
CFlatButton::~CFlatButton() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(CFlatButton, CButton) 
	//{{AFX_MSG_MAP(CFlatButton) 
	ON_WM_MOUSEMOVE() 
	ON_WM_KILLFOCUS() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONDBLCLK() 
	//}}AFX_MSG_MAP 
	ON_WM_TIMER() 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFlatButton message handlers 
void CFlatButton::OnMouseMove(UINT nFlags, CPoint point)  
{ 
	// If the mouse enter the button with the left button pressed 
	// then do nothing 
	//if (nFlags & MK_LBUTTON && m_bMouseIn == FALSE) return; 
 
	CWnd* pWnd = GetActiveWindow(); 
	CWnd* pParent = GetOwner(); 
 
	CRect rect; 
	GetClientRect(&rect); 
	 
	if (!rect.PtInRect(point)) 
	{ 
		if (m_bMouseIn == TRUE) 
		{ 
			m_bMouseIn = FALSE; 
 
			if (nFlags & MK_LBUTTON || (dwFlags&FBS_ROLLOVER)) 
				Invalidate(); 
		} 
	}else if (m_bMouseIn == FALSE && ((pWnd != NULL) && (pParent != NULL))) 
	{ 
		m_bMouseIn = TRUE; 
		KillTimer(14); 
		SetTimer(14, 10, NULL); 
 
		if (nFlags & MK_LBUTTON || (dwFlags&FBS_ROLLOVER)) 
			InvalidateRect(NULL, FALSE); 
	} 
 
	CButton::OnMouseMove(nFlags, point); 
} 
 
void CFlatButton::OnKillFocus(CWnd* pNewWnd)  
{ 
	CButton::OnKillFocus(pNewWnd); 
	 
	if (m_bMouseIn == TRUE) 
	{ 
	    m_bMouseIn = FALSE; 
	    InvalidateRect(NULL, FALSE); 
	    UpdateWindow(); 
	}	 
} 
 
#define _FBS_SPACE_ 4 
#define _FBS_ARROWWIDTH_ 11 
void CFlatButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
{ 
	CDC* pDC   = CDC::FromHandle(lpDrawItemStruct->hDC); 
	CRect rcClient = lpDrawItemStruct->rcItem; 
	UINT state = lpDrawItemStruct->itemState; 
 
	COLORREF colorFace = GetSysColor(COLOR_BTNFACE); 
	COLORREF colorShadow = GetSysColor(COLOR_3DSHADOW); 
	COLORREF colorLight = GetSysColor(COLOR_3DHILIGHT); 
	 
	CDC memDC; 
	memDC.CreateCompatibleDC( pDC ); 
 
	// Select a compatible bitmap into the memory DC 
	CBitmap bitmap; 
	bitmap.CreateCompatibleBitmap( pDC, rcClient.Width(), rcClient.Height() ); 
	CBitmap* pOldBitmap = memDC.SelectObject( &bitmap ); 
 
	if (m_bChecked && (!m_bMouseIn || dwFlags & FBS_MENU_BUTTON || !(dwFlags&FBS_ROLLOVER))) 
	{ 
		CBrush *pBrush = CDC::GetHalftoneBrush(); 
		memDC.SetTextColor(colorLight); 
		memDC.SetBkColor(colorFace); 
		memDC.FillRect(rcClient, pBrush); 
		//dc.SetTextColor(RGB(0,0,0)); 
		//dc.SetBkColor(clrRect); 
	}else 
		memDC.FillSolidRect(rcClient, colorFace); 
 
	int nIconOffset = 0; 
	CString strText; 
	GetWindowText(strText); 
 
	bool bHasText = !strText.IsEmpty(); 
	CSize szText; 
 
	if (bHasText) 
	{ 
		CFont *pFont = GetFont(); 
 
		CFont* pOldFont = memDC.SelectObject (pFont); 
		szText = memDC.GetTextExtent(strText); 
		memDC.SelectObject (pOldFont); 
	} 
 
	if (dwFlags & FBS_HAS_ICON) 
	{ 
		ASSERT(m_hIcon!=0); 
		CRect rcIcon(rcClient); 
 
		int nOffset = 0; 
 
		if (!bHasText) 
			nOffset = ((rcIcon.Width() - m_nIconWidth)/2); 
		else 
			nOffset = ((rcIcon.Width() - m_nIconWidth - szText.cx)/3); 
			 
		rcIcon.left += nOffset; 
 
		rcIcon.top += ((rcIcon.Height() - m_nIconHeight)/2); 
 
		if (state & ODS_SELECTED) 
			rcIcon.OffsetRect(1, 1); 
 
		/*::DrawIconEx(memDC.GetSafeHdc(), rcIcon.left, rcIcon.top, 
			m_hIcon, m_nIconHeight, m_nIconWidth, 0, NULL, 
			DI_NORMAL);*/ 
		memDC.DrawState(rcIcon.TopLeft(),  
						CSize(m_nIconWidth,m_nIconHeight),  
				        m_hIcon,  
				        ((state & ODS_DISABLED)? DSS_DISABLED : DSS_NORMAL),  
						(CBrush*)NULL); 
 
		//memDC.DrawIcon(rcIcon.TopLeft(), m_hIcon); 
 
		nIconOffset = nOffset*2+m_nIconWidth; 
	} 
	 
	if ( bHasText) 
	{ 
		CFont *pFont = GetFont(); 
 
		CFont* pOldFont = memDC.SelectObject (pFont); 
		int iOldMode = memDC.GetBkMode(); 
		memDC.SetBkMode( TRANSPARENT ); 
		COLORREF crOldText ; 
		crOldText = memDC.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); 
 
		//CSize szText = memDC.GetTextExtent(strText); 
		CPoint ptText; 
 
		if (dwFlags & FBS_ARROW_UP || dwFlags & FBS_ARROW_DOWN) 
		{ 
			int nTotalWidth = szText.cx + _FBS_SPACE_ + _FBS_ARROWWIDTH_; 
 
			if (nIconOffset) // If has icon 
				ptText.x = nIconOffset; 
			else // Centrum 
				ptText.x = (rcClient.Width()-nTotalWidth)/2; 
			ptText.y = (rcClient.Height()-szText.cy)/2; 
			 
			// Draw Arrows if nessesary 
			CPoint pt; 
			pt.x = ptText.x + szText.cx  + _FBS_SPACE_; 
			pt.y = (rcClient.Height() - _FBS_ARROWWIDTH_/2) / 2; 
			 
			if (state & ODS_SELECTED) 
				pt.Offset(1,1); 
			 
			memDC.SelectStockObject(BLACK_PEN); 
			memDC.SelectStockObject(BLACK_BRUSH); 
			DrawArrow(&memDC, pt, _FBS_ARROWWIDTH_, dwFlags); 
		}else 
		{ 
			if (nIconOffset) // If has icon 
				ptText.x = nIconOffset; 
			else // Centrum 
				ptText.x = (rcClient.Width()-szText.cx)/2; 
			ptText.y = (rcClient.Height()-szText.cy)/2; 
		} 
 
		if (state & ODS_SELECTED) 
			ptText.Offset(1,1); 
		 
		if (state & ODS_DISABLED) 
			memDC.DrawState(ptText, szText, strText, DSS_DISABLED,  
				TRUE, 0, (HBRUSH)NULL); 
		else 
			memDC.DrawText(strText, CRect(ptText,szText), DT_CENTER|DT_VCENTER); 
 
		memDC.SetBkMode( iOldMode ); 
		memDC.SetTextColor( crOldText ); 
		memDC.SelectObject (pOldFont); 
	} 
 
	if (state & ODS_SELECTED ) 
		memDC.DrawEdge(rcClient, BDR_SUNKENOUTER, BF_RECT); 
	else if (m_bChecked) 
	{ 
		if (!(dwFlags&FBS_CHECKED_NOBORDER)) 
			memDC.DrawEdge(rcClient, BDR_SUNKENOUTER, BF_RECT); 
	}else if ((!m_bMouseIn) || !(dwFlags&FBS_ROLLOVER)) 
	{ 
		if (dwFlags & FBS_BORDER) 
			memDC.DrawEdge(rcClient, BDR_RAISEDINNER, BF_RECT); 
			//memDC.Draw3dRect(rcClient, colorLight, colorShadow); 
	}else 
	{ 
		if (dwFlags & FBS_BORDER) 
			memDC.DrawEdge(rcClient, EDGE_RAISED, BF_RECT); 
		else 
			memDC.Draw3dRect(rcClient, colorLight, colorShadow); 
	} 
 
	pDC->BitBlt( 0, 0, rcClient.Width(), rcClient.Height(), &memDC,  
				0, 0, SRCCOPY ); 
 
	if (state & ODS_FOCUS && dwFlags & FBS_FOCUS) 
	{ 
		CRect r(rcClient); 
		r.DeflateRect(3,3); 
 
		pDC->DrawFocusRect(r); 
		//memDC.DrawEdge(r, EDGE_RAISED, BF_RECT); 
		//::DrawFocusRect(memDC.m_hDC, r); 
	} 
 
	memDC.SelectObject( pOldBitmap); 
} 
 
void CFlatButton::PreSubclassWindow()  
{ 
	SetButtonStyle(GetButtonStyle() | BS_OWNERDRAW); 
 
	CButton::PreSubclassWindow(); 
} 
 
void CFlatButton::OnTimer(UINT nIDEvent) 
{ 
	if (m_bMouseIn == FALSE) 
	{ 
		KillTimer(14); 
		return; 
	} 
 
	CRect rect; 
	GetClientRect(&rect); 
 
	CPoint point; 
	GetCursorPos(&point); 
	ScreenToClient(&point); 
	 
	if (!rect.PtInRect(point) && m_bMouseIn == TRUE) 
	{ 
		KillTimer(14); 
 
		m_bMouseIn = FALSE; 
 
		if (dwFlags&FBS_ROLLOVER) 
			Invalidate(); 
	} 
} 
 
void CFlatButton::ModifyFlag(const DWORD & dwRemove, const DWORD & dwAdd, const UINT bRedraw) 
{ 
	if (dwRemove)	dwFlags &= ~(dwRemove); 
	if (dwAdd)		dwFlags |= dwAdd; 
 
	if (bRedraw)  
		InvalidateRect(NULL); 
} 
 
void CFlatButton::DrawArrow(CDC* pDC, const CPoint& ptTopLeft, int nWidth, DWORD dwType) 
{ 
	POINT ptArray[3]; 
 
	if (((dwType & FBS_ARROW_DOWN) && !m_bChecked) || ((dwType & FBS_ARROW_UP) && m_bChecked)) 
	{ 
		ptArray[0] = ptTopLeft; 
		ptArray[1].x = ptTopLeft.x + nWidth - nWidth%2; 
		ptArray[1].y = ptTopLeft.y; 
		ptArray[2].x = ptTopLeft.x + nWidth / 2; 
		ptArray[2].y = ptTopLeft.y + nWidth / 2; 
 
		pDC->Polygon(ptArray, 3); 
	}else if (((dwType & FBS_ARROW_UP) && !m_bChecked) || ((dwType & FBS_ARROW_DOWN) && m_bChecked)) 
	{ 
		ptArray[0].x = ptTopLeft.x; 
		ptArray[0].y = ptTopLeft.y + nWidth / 2; 
		ptArray[1].x = ptTopLeft.x + nWidth - nWidth%2; 
		ptArray[1].y = ptTopLeft.y + nWidth / 2; 
		ptArray[2].x = ptTopLeft.x + nWidth / 2; 
		ptArray[2].y = ptTopLeft.y; 
 
		pDC->Polygon(ptArray, 3); 
	} 
	 
} 
 
void CFlatButton::SetCheck(BOOL b) 
{ 
	m_bChecked = b; 
	InvalidateRect(NULL); 
} 
 
BOOL CFlatButton::GetCheck() 
{ 
	return m_bChecked; 
} 
 
void CFlatButton::SetIcon(HICON hIcon, BYTE cx, BYTE cy) 
{ 
	m_hIcon = hIcon; 
	m_nIconWidth = cx; 
	m_nIconHeight = cy; 
} 
 
void CFlatButton::DoMenu() 
{ 
	if (dwFlags & FBS_MENU_BUTTON) 
	{ 
		if (m_bClickAgain) 
		{ 
			m_bClickAgain = FALSE; 
			return; 
		} 
 
		ASSERT(m_pMenu!=NULL); 
 
		SetCheck(TRUE); 
 
		CRect rect; 
		GetWindowRect(&rect);	 
		CPoint pt; 
		pt = rect.TopLeft(); 
		DWORD dwMenu = TPM_LEFTALIGN; 
		if (dwFlags & FBS_MENU_ALIGN_RIGHT) 
			pt.x += rect.Width(); 
		if (!(dwFlags & FBS_MENU_ALIGN_TOP))		 
			pt.y += rect.Height(); 
 
		if (dwFlags & FBS_MENU_ALIGN_RIGHT && !(dwFlags & FBS_MENU_ALIGN_TOP)) 
			dwMenu = TPM_RIGHTALIGN; 
		else if (!(dwFlags & FBS_MENU_ALIGN_RIGHT) && (dwFlags & FBS_MENU_ALIGN_TOP)) 
			dwMenu = TPM_RIGHTALIGN; 
 
		GetOwner()->SendMessage(WM_FB_NOTIFY, FB_NOTIFY_INITMENU, (LPARAM)m_pMenu); 
 
		int n = m_pMenu->TrackPopupMenu(dwMenu|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, GetOwner()); 
		 
		SetCheck(FALSE); 
 
		if (n>0) 
		{ 
			GetOwner()->SendMessage(WM_COMMAND, n, NULL); 
		}else 
		{ 
			CPoint pt; 
			GetCursorPos(&pt); 
			if (rect.PtInRect(pt)) 
				m_bClickAgain = TRUE; 
			else 
				m_bClickAgain = FALSE; 
		}		 
	} 
} 
 
void CFlatButton::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	CButton::OnLButtonDown(nFlags, point); 
 
	DoMenu(); 
} 
 
LRESULT CFlatButton::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
{ 
	if (message == WM_LBUTTONDBLCLK && !(dwFlags & FBS_MENU_BUTTON)) 
	{ 
		message = WM_LBUTTONDOWN; 
	} 
 
	return CButton::DefWindowProc(message, wParam, lParam); 
} 
 
void CFlatButton::OnLButtonDblClk(UINT nFlags, CPoint point)  
{ 
	CButton::OnLButtonDblClk(nFlags, point); 
	DoMenu(); 
} 
 
BOOL CFlatButton::PreTranslateMessage(MSG* pMsg)  
{ 
	if (m_ToolTip.GetSafeHwnd()!=NULL) 
		m_ToolTip.RelayEvent(pMsg); 
	 
	return CButton::PreTranslateMessage(pMsg); 
} 
 
void CFlatButton::SetTooltipText(int nId, BOOL bActivate) 
{ 
	CString str; 
	str.LoadString(nId); 
	 
	if (!str.IsEmpty())  
		SetTooltipText(str, bActivate); 
} 
 
void CFlatButton::SetTooltipText(LPCTSTR strTooltip, BOOL bActivate) 
{ 
	if (!m_ToolTip.GetSafeHwnd()) 
		m_ToolTip.Create(this); 
 
	if (!m_ToolTip.GetToolCount()) 
	{ 
		CRect rc;  
		GetClientRect(rc); 
		m_ToolTip.AddTool(this, strTooltip, rc, GetDlgCtrlID()); 
	} 
 
	m_ToolTip.UpdateTipText(strTooltip, this, GetDlgCtrlID()); 
	m_ToolTip.Activate(bActivate); 
} 
 
void CFlatButton::EnableTooltip(BOOL bEnable) 
{ 
	if (!m_ToolTip.GetSafeHwnd()) 
		return; 
 
	if (!m_ToolTip.GetToolCount())  
		return; 
 
	m_ToolTip.Activate(bEnable); 
}