Colored Buttons

Environment: VC6

This is a class based on Bob Ryan's CColorButton code of 1998/08/06.

The main modifications were to make the default view of a button to be exactly the same as a normal non-owner drawn button. To this end, the default colors are set in the constructor by interrogating the current Windows settings through the GetSysColor function. The colors may be set at any time by calling SetColour or SetColor (whatever your preference) with two or three parameters. The first is the text color. The second is the background color. The optional third is the color that will be used as the background for a disabled button. The button may be set to the Windows default by calling ResetColour() or ResetColor(). The small demo app. shows all of the permutations.
class CClrButton : public CButton
{
// Construction
public:
  CClrButton();

// Attributes
public:

// Operations
public:
  // UK version
  void SetColour( COLORREF text_colour, 
                  COLORREF background_colour);

  // US version
  void SetColor( COLORREF text_colour, 
                 COLORREF background_colour)
  {
    SetColour( text_colour, 
               background_colour);		
  };

  // UK version
  void SetColour(COLORREF text_colour, 
                 COLORREF background_colour, 
                 COLORREF disabled_background_colour);

  // US version
  void SetColor(COLORREF text_colour, 
                COLORREF background_colour, 
                COLORREF disabled_background_colour)
  {
    SetColour( text_colour, 
               background_colour, 
               disabled_background_colour);
  };

  // UK version
  void ResetColour();

  // US version
  void ResetColor()
  {
    ResetColour();
  }

  // Overrides
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CClrButton)
  public:
  virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
  //}}AFX_VIRTUAL

// Implementation
public:
  virtual ~CClrButton();

private:
  COLORREF text_colour, background_colour, disabled_background_colour;
  COLORREF light, highlight, shadow, dark_shadow;

  // Generated message map functions
protected:
  //{{AFX_MSG(CClrButton)
  // NOTE - the ClassWizard will add and remove member functions here.
  //}}AFX_MSG

  void DrawFrame(CDC *dc, CRect r, int state);
  void DrawFilledRect(CDC *dc, CRect r, COLORREF colour);
  void DrawLine(CDC *dc, long sx, long sy, 
                         long ex, long ey, COLORREF colour);
  void DrawButtonText(CDC *dc, CRect r, 
                      const char *buf, COLORREF text_colour);

  DECLARE_MESSAGE_MAP()
};

const COLORREF CLR_BTN_WHITE	= RGB(255, 255, 255);
const COLORREF CLR_BTN_BLACK	= RGB(0, 0, 0);
const COLORREF CLR_BTN_DGREY	= RGB(128, 128, 128);
const COLORREF CLR_BTN_GREY	= RGB(192, 192, 192);
const COLORREF CLR_BTN_LLGREY	= RGB(223, 223, 223);

const int BUTTON_IN		= 0x01;
const int BUTTON_OUT		= 0x02;
const int BUTTON_BLACK_BORDER	= 0x04;

//////////////////////////////////////////////////////////////////////
// CClrButton

CClrButton::CClrButton()
{
  text_colour         = GetSysColor(COLOR_BTNTEXT);
  background_colour   = GetSysColor(COLOR_BTNFACE); 
  disabled_background_colour = background_colour;
  light               = GetSysColor(COLOR_3DLIGHT);
  highlight           = GetSysColor(COLOR_BTNHIGHLIGHT);
  shadow              = GetSysColor(COLOR_BTNSHADOW);
  dark_shadow         = GetSysColor(COLOR_3DDKSHADOW);
}

CClrButton::~CClrButton()
{
}

void CClrButton::SetColour( COLORREF new_text_colour, 
                            COLORREF new_background_colour)
{
  text_colour                = new_text_colour;
  background_colour          = new_background_colour; 
  disabled_background_colour = GetSysColor(COLOR_BTNFACE); 

  Invalidate(FALSE);
}

void CClrButton::SetColour(COLORREF new_text_colour, 
                           COLORREF new_background_colour, 
                           COLORREF new_disabled_background_colour)
{
  text_colour                = new_text_colour;
  background_colour          = new_background_colour; 
  disabled_background_colour = new_disabled_background_colour; 

  Invalidate(FALSE);
}

void CClrButton::ResetColour()
{
  text_colour                = GetSysColor(COLOR_BTNTEXT);
  background_colour          = GetSysColor(COLOR_BTNFACE); 
  disabled_background_colour = background_colour;
  light                      = GetSysColor(COLOR_3DLIGHT);
  highlight                  = GetSysColor(COLOR_BTNHIGHLIGHT);
  shadow                     = GetSysColor(COLOR_BTNSHADOW);
  dark_shadow                = GetSysColor(COLOR_3DDKSHADOW);

  Invalidate(FALSE);
}

BEGIN_MESSAGE_MAP(CClrButton, CButton)
  //{{AFX_MSG_MAP(CClrButton)
  // NOTE - the ClassWizard will add and remove mapping
  //        macros here.
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////
// CClrButton message handlers

void CClrButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
  CDC   *dc;
  CRect	focus_rect, button_rect, offset_button_rect;
  UINT  state;
	
  dc  = CDC::FromHandle(lpDrawItemStruct->hDC);
  state = lpDrawItemStruct->itemState;

  focus_rect.CopyRect(&lpDrawItemStruct->rcItem); 
  button_rect.CopyRect(&lpDrawItemStruct->rcItem); 

  // Set the focus rectangle to just past the border decoration
  focus_rect.left  += 4;
  focus_rect.right  -= 4;
  focus_rect.top    += 4;
  focus_rect.bottom -= 4;
      
  // Retrieve the button's caption
  const int bufSize = 512;
  TCHAR buffer[bufSize];
  GetWindowText(buffer, bufSize);

  if (state & ODS_DISABLED)
  {
    DrawFilledRect(dc, button_rect, disabled_background_colour);
  }
  else
  {
    DrawFilledRect(dc, button_rect, background_colour);
  }
		
  if (state & ODS_SELECTED)
  { 
     DrawFrame(dc, button_rect, BUTTON_IN);
  }
  else
  {
    if ((state & ODS_DEFAULT) || (state & ODS_FOCUS))
    {
      DrawFrame(dc, button_rect, BUTTON_OUT | BUTTON_BLACK_BORDER);			
    }
    else
    {
      DrawFrame(dc, button_rect, BUTTON_OUT);
    }
  }

  if (state & ODS_DISABLED)
  {
    offset_button_rect = button_rect;
    offset_button_rect.OffsetRect(1, 1);
  
    DrawButtonText(dc, offset_button_rect, buffer, CLR_BTN_WHITE);
    DrawButtonText(dc, button_rect, buffer, CLR_BTN_DGREY);
  }
  else
  {
    DrawButtonText(dc, button_rect, buffer, text_colour);
  }

  if (state & ODS_FOCUS)
  {
    DrawFocusRect(lpDrawItemStruct->hDC, (LPRECT)&focus_rect);
  }
} 

void CClrButton::DrawFrame(CDC *dc, CRect r, int state)
{ 
  COLORREF colour;

  if (state & BUTTON_BLACK_BORDER)
  {
    colour = CLR_BTN_BLACK;

    DrawLine(dc, r.left,  r.top,
                 r.right, r.top, colour);   // Across top
    DrawLine(dc, r.left, r.top,  
                 r.left, r.bottom, colour); // Down left
    DrawLine(dc, r.left, r.bottom - 1, 
                 r.right, r.bottom - 1, colour); // Across bottom
    DrawLine(dc, r.right - 1, r.top,  
                 r.right - 1, r.bottom, colour); // Down right

    r.InflateRect(-1, -1);
  }
	
  if (state & BUTTON_OUT)
  {
    colour = highlight;

    DrawLine(dc, r.left, r.top, 
                 r.right, r.top, colour);    // Across top
    DrawLine(dc, r.left, r.top, 
                 r.left,  r.bottom, colour); // Down left

    colour = dark_shadow;
	
    DrawLine(dc, r.left, r.bottom - 1, 
                 r.right, r.bottom - 1, colour); // Across bottom
    DrawLine(dc, r.right - 1, r.top, 
                 r.right - 1, r.bottom, colour); // Down right
	
    r.InflateRect(-1, -1);

    colour = light;
	
    DrawLine(dc, r.left, r.top, 
                 r.right, r.top, colour);   // Across top
    DrawLine(dc, r.left, r.top, 
                 r.left, r.bottom, colour); // Down left

    colour = shadow;
	
    DrawLine(dc, r.left, r.bottom - 1, 
                 r.right, r.bottom - 1, colour); // Across bottom
    DrawLine(dc, r.right - 1, r.top, 
                 r.right - 1, r.bottom, colour); // Down right
  }

  if (state & BUTTON_IN)
  {
    colour = dark_shadow;

    DrawLine(dc, r.left, r.top, 
                 r.right, r.top, colour);   // Across top
    DrawLine(dc, r.left, r.top, 
                 r.left, r.bottom, colour); // Down left
    DrawLine(dc, r.left, r.bottom - 1, 
                 r.right, r.bottom - 1, colour); // Across bottom
    DrawLine(dc, r.right - 1, r.top, 
                 r.right - 1, r.bottom, colour); // Down right
	
    r.InflateRect(-1, -1);

    colour = shadow;
	
    DrawLine(dc, r.left,  r.top, 
                 r.right, r.top, colour);    // Across top
    DrawLine(dc, r.left,  r.top, 
                 r.left,  r.bottom, colour); // Down left
    DrawLine(dc, r.left,  r.bottom - 1, 
                 r.right, r.bottom - 1, colour); // Across bottom
    DrawLine(dc, r.right - 1, r.top,
                 r.right - 1, r.bottom, colour); // Down right
  }
}

void CClrButton::DrawFilledRect(CDC *dc, CRect r, COLORREF colour)
{ 
  CBrush B;

  B.CreateSolidBrush(colour);
  dc->FillRect(r, &B);
}

void CClrButton::DrawLine( CDC *dc, 
                           long sx, 
                           long sy, 
                           long ex, 
                           long ey, 
                           COLORREF colour)
{ 
  CPen new_pen;
  CPen *old_pen;

  new_pen.CreatePen(PS_SOLID, 1, colour);
  old_pen = dc->SelectObject(&new_pen);
  dc->MoveTo(sx, sy);
  dc->LineTo(ex, ey);
  dc->SelectObject(old_pen);
  new_pen.DeleteObject();
}


void CClrButton::DrawButtonText( CDC *dc, 
                                 CRect r, 
                                 const char *Buf, 
                                 COLORREF text_colour)
{
  COLORREF previous_colour;

  previous_colour = dc->SetTextColor(text_colour);
  dc->SetBkMode(TRANSPARENT);
  dc->DrawText(Buf, strlen(Buf), r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  dc->SetTextColor(previous_colour);
}

Downloads

Download demo project -36Kb
Download source - 13Kb


Comments

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Moving from an on-premises environment to Office 365 does not remove the need to plan for disruptions or reduce the business risk requirements for protecting email services. If anything, some risks increase with a move to the cloud. Read how to ease the transition every business faces if considering or already migrating to cloud email. This white paper discusses: Setting expectations when migrating to Office 365 Understanding the implications of relying solely on Exchange Online security Necessary archiving …

  • Following an IT incident through to resolution is more than just acknowledging an alert and restarting a server. The recent State of On-Call Report found that it takes most companies an average of 10-30 minutes to resolve an incident with an average of 5 people involved. Imagine how much money and time companies are spending to deal with incident resolution. But what if you had a tool that offered solutions baked in? Or a tool that sent alerts to the right person or team every time? These are the kind of …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date