Click here to Skip to main content
15,892,746 members
Articles / Desktop Programming / MFC

A Better Bitmap Button Class

Rate me:
Please Sign up or sign in to vote.
3.46/5 (14 votes)
14 Oct 2001 398.3K   9.2K   80  
An improvement on the CBitmapButton class.
// ToggleButton.cpp : implementation file
//
// Originally by Joseph M. Newcomer.
// Modified in Aug 01 by Jeff Mallett to display highlight color when pressed.

#include "stdafx.h"
#include "button.h"
#include "ToggleButton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CToggleButton

CToggleButton::CToggleButton()
{
 depressed = FALSE;
}

CToggleButton::~CToggleButton()
{
}


BEGIN_MESSAGE_MAP(CToggleButton, CButton)
	//{{AFX_MSG_MAP(CToggleButton)
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CToggleButton message handlers

/****************************************************************************
*                            CToggleButton::SetVPos
* Inputs:
*       DWORD newstyle: Vertical style, one of BS_TOP, BS_BOTTOM, BS_VCENTER
* Result: DWORD
*       Previous style
* Effect: 
*       Sets the style
****************************************************************************/

DWORD CToggleButton::SetVPos(DWORD newstyle)
   {
    DWORD style = GetStyle();
    DWORD result = style;
    style &= ~ (BS_TOP | BS_BOTTOM | BS_VCENTER);
    style |= newstyle;
    ::SetWindowLong(m_hWnd, GWL_STYLE, (long)style);
    InvalidateRect(NULL);
    return result & (BS_TOP | BS_BOTTOM | BS_VCENTER);
   } // CToggleButton::SetVPos

/****************************************************************************
*                            CToggleButton::SetHPos
* Inputs:
*       DWORD newstyle: Horizontal style, one of BS_LEFT, BS_RIGHT, BS_CENTER
* Result: DWORD
*       Previous style
* Effect: 
*       Sets the style
****************************************************************************/

DWORD CToggleButton::SetHPos(DWORD newstyle)
   {
    DWORD style = GetStyle();
    DWORD result = style;
    style &= ~ (BS_LEFT | BS_RIGHT | BS_CENTER);
    style |= newstyle;
    ::SetWindowLong(m_hWnd, GWL_STYLE, (long)style);
    InvalidateRect(NULL);
    return result & (BS_LEFT | BS_RIGHT | BS_CENTER);
   } // CToggleButton::SetHPos


void CToggleButton::DrawItem(LPDRAWITEMSTRUCT dis) 
{
     CDC * dc = CDC::FromHandle(dis->hDC); // Get a CDC we can use
     CRect r(dis->rcItem);		   // Copy the button rectangle
     int saved = dc->SaveDC();		   // Save the DC for later restoration
     CPoint pt;                            // left point of text
     CSize sz;                             // size of text
     CSize border(::GetSystemMetrics(SM_CXBORDER), ::GetSystemMetrics(SM_CYBORDER));
					   // Dimensions of a border line
					   // We use ::GetSystemMetrics so we work on
					   // hi-res displays
     CPoint baseOffset(border.cx, border.cy); // Offset amount if button-down

     // The three states are
     //  ODS_SELECTED  ODS_DISABLED 
     //       1		n/a		Button is pressed
     //	      0		0		Button is up
     //	      0		1		Button is disabled
     //

     dc->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
     //dc->SetBkMode(TRANSPARENT);
     if(dis->itemState & (ODS_DISABLED | ODS_GRAYED))
	{ /* grayed */
	 dc->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
	} /* grayed */

     DWORD style = GetStyle();
     style &= (BS_LEFT | BS_RIGHT | BS_CENTER);

#define MARGIN 4
     CString s;
     GetWindowText(s);
     sz = dc->GetTextExtent(s);

     UINT flags = (GetStyle() & BS_MULTILINE ? 0 : DT_SINGLELINE);
     switch(style)
	{ /* hstyle */
	 case BS_LEFT:
	    pt.x = MARGIN * border.cx;
	    flags |= DT_LEFT;
	    break;
	 case BS_RIGHT:
	    pt.x = r.Width() - MARGIN * border.cx - sz.cx;
	    flags |= DT_RIGHT;
	    break;
	 case 0:
	 case BS_CENTER:
	    pt.x = (r.Width() - sz.cx) / 2;
	    flags |= DT_CENTER;
	    break;
	} /* hstyle */

     style = GetStyle();
     style &= (BS_TOP | BS_BOTTOM | BS_VCENTER);

     switch(style)
	{ /* vstyle */
	 case BS_TOP:
	    pt.y = 3 * border.cy;
	    flags |= DT_TOP;
	    break;
	 case BS_BOTTOM:
	    pt.y = r.Height() - MARGIN * border.cy - sz.cy;
	    flags |= DT_BOTTOM;
	    break;
	 case 0:
	 case BS_VCENTER:
	    pt.y = (r.Height() - sz.cy) / 2;
	    flags |= DT_VCENTER;
	    break;
	} /* vstyle */

     // Compute the focus rectangle area
     CRect focus(pt.x, pt.y, pt.x + sz.cx, pt.y + sz.cy);

     // For visual effect, if the button is down, shift the text over and
     // down to make it look "pushed".
     CPoint useOffset(0, 0);
     if(depressed)
	{ /* down */
	 useOffset = baseOffset;
	} /* down */

     // Draw the traditional pushbutton edge using DrawEdge
     if(depressed)
	{ /* down */
	 dc->DrawEdge(&dis->rcItem, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_SOFT);
	} /* down */
     else
	{ /* up */
	 dc->DrawEdge(&dis->rcItem, EDGE_RAISED, BF_RECT | BF_MIDDLE | BF_SOFT);
	} /* up */

	// Fill background with highlight color
	if (depressed)
	{
		UINT x = 3 * border.cx; 
		UINT y = 3 * border.cy;
		CRect rect(x, y,
					x + r.Width() - baseOffset.x - 4,
					y + r.Height() - baseOffset.y - 4);
		dc->FillSolidRect( &rect, ::GetSysColor(COLOR_BTNHIGHLIGHT));
		dc->SetBkColor(::GetSysColor(COLOR_BTNHIGHLIGHT));
	}

     // Adjust the focus position and text position by shifting them
     // right-and-down by the desired offset
     focus += useOffset;
     pt += useOffset;

     focus.InflateRect(border.cx, border.cy);

     r.InflateRect(-MARGIN * border.cx, -MARGIN * border.cy);
     r += useOffset;

     dc->DrawText(s, r, flags);

     if(dis->itemState & ODS_FOCUS)
	::DrawFocusRect(dis->hDC, &focus);

     dc->RestoreDC(saved);
}

void CToggleButton::OnLButtonDown(UINT nFlags, CPoint point) 
{
    depressed = !depressed;
    InvalidateRect(NULL);
    CButton::OnLButtonDown(nFlags, point);
}

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.


Written By
Retired
United States United States
PhD, Computer Science, Carnegie Mellon University, 1975
Certificate in Forensic Science and the Law, Duquesne University, 2008

Co-Author, [i]Win32 Programming[/i]

Comments and Discussions