65.9K
CodeProject is changing. Read more.
Home

Round Buttons

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (34 votes)

Nov 27, 1999

CPOL

2 min read

viewsIcon

415405

downloadIcon

16300

A class that turns rectangular buttons into round buttons.

Sample Image

Introduction

I wanted a button that looked exactly like normal buttons, but instead I wanted them circular. This class can be used like any other owner drawn control - simply include the header file, and declare your button controls as CRoundButton instead of CButton

First of all I make sure the buttons are circles (and not ellipses) and store the centre and radius of the button. Next I simply make the button owner drawn and draw it like every other owner drwn button, but instead of being able to use nice routines like Draw3dRect, I had to roll my own circle drawing routine which would draw each pixel with the correct colour dependant on the point on the circle I was drawing.

I will not include the full source in this page - it is available for download here. The owner draw part is simple and follows along the lines of any other owner drawn button. The circle drawing routine is a standard algorithm, with the only modification in calculating the pixel colour. Given two colours crBright and crDark, and an angle relative to the x-axis, the colour for a pixel can be calculated using the following.

COLORREF GetColour(double dAngle, COLORREF crBright, COLORREF crDark)
{
#define Rad2Deg            180.0/3.1415 
#define LIGHT_SOURCE_ANGLE  -2.356    // -2.356 radians = -135 degrees, 
                                      // i.e. From the top left of the screen

    ASSERT(dAngle > -3.1416 && dAngle < 3.1416);
    double dAngleDifference = LIGHT_SOURCE_ANGLE - dAngle;

    if (dAngleDifference < -3.1415) 
        dAngleDifference = 6.293 + dAngleDifference;
    else if (dAngleDifference > 3.1415) 
        dAngleDifference = 6.293 - dAngleDifference;

    double Weight = 0.5*(cos(dAngleDifference)+1.0);

    BYTE Red   = (BYTE) (Weight*GetRValue(crBright) + 
                        (1.0-Weight)*GetRValue(crDark));
    BYTE Green = (BYTE) (Weight*GetGValue(crBright) + 
                        (1.0-Weight)*GetGValue(crDark));
    BYTE Blue  = (BYTE) (Weight*GetBValue(crBright) + 
                        (1.0-Weight)*GetBValue(crDark));

    return RGB(Red, Green, Blue);
}

This is a simple linear interpolation between the two colours based on the cosine of the angle between the light source and the point. Angles are measured from the +ve x-axis (i.e. (1,0) = 0 degrees, (0,1) = 90 degrees ), but remember: positive y points down!

Update

Tom Kalmijn kindly added routines that post-process the button image to smooth out the jagged edges. His method uses a nearest-neighbours algorithm to interpolate missing pixels. It's not particularly fast but it does increase smoothing.