65.2.1 Modifying the ChooseColor Common Dialog Box

In order to modify the ChooseColor common-dialog box, it was first necessary to modify the dialog resource template that is stored in the file color.dlg. The modifications included changing the coordinates of the custom-colors box and custom-colors pushbutton (so that they were drawn outside of the dialog window) and adding three new controls. Two of these new controls are listboxes which the user can use to select a line-style and a join-style. The third control is an edit box in which the user can specify a line width (ranging from 1 to 99). The following excerpt from the application's resource file shows part of the the modified dialog template:

DLGINCLUDE RCDATA DISCARDABLE

BEGIN

"colordlg.h\0"

END

CHOOSECOLOR DIALOG 2, 0, 298, 184

STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU

CAPTION "Standard Pen"

FONT 8, "Helv"

BEGIN

LTEXT "Pen Color:", -1, 4, 4, 140, 9

CONTROL "", COLOR_BOX1, "Static", SS_SIMPLE | WS_GROUP |

WS_TABSTOP, 4, 14, 140, 86

LTEXT "&Custom Colors:", -1, 4, 806, 140, 9

CONTROL "", COLOR_CUSTOM1, "Static", SS_SIMPLE | WS_GROUP |

WS_TABSTOP, 4, 816, 140, 28

PUSHBUTTON "&Define Custom Colors...", COLOR_MIX, 4, 850, 140, 14,

WS_GROUP

DEFPUSHBUTTON "OK", IDOK, 4, 166, 44, 14, WS_GROUP

PUSHBUTTON "Cancel", IDCANCEL, 52, 166, 44, 14, WS_GROUP

PUSHBUTTON "&Help", 1038, 100, 166, 44, 14, WS_GROUP

CONTROL "", COLOR_RAINBOW, "Static", SS_BLACKFRAME, 152, 4, 118,

116

CONTROL "", COLOR_LUMSCROLL, "Static", SS_SIMPLE, 280, 4, 8, 116

CONTROL "", COLOR_CURRENT, "Static", SS_BLACKFRAME, 152, 124, 40,

26

RTEXT "Color|", -1, 152, 151, 20, 9

LTEXT "S&olid", -1, 172, 151, 20, 9

PUSHBUTTON "&o", COLOR_SOLID, 300, 200, 4, 14, WS_GROUP

RTEXT "&Hue:", COLOR_HUEACCEL, 194, 126, 20, 9

EDITTEXT COLOR_HUE, 216, 124, 18, 12, WS_GROUP

RTEXT "&Sat:", COLOR_SATACCEL, 194, 140, 20, 9

EDITTEXT COLOR_SAT, 216, 138, 18, 12, WS_GROUP

RTEXT "&Lum:", COLOR_LUMACCEL, 194, 154, 20, 9

EDITTEXT COLOR_LUM, 216, 152, 18, 12, WS_GROUP

RTEXT "&Red:", COLOR_REDACCEL, 243, 126, 24, 9

EDITTEXT COLOR_RED, 269, 124, 18, 12, WS_GROUP

RTEXT "&Green:", COLOR_GREENACCEL, 243, 140, 24, 9

EDITTEXT COLOR_GREEN, 269, 138, 18, 12, WS_GROUP

RTEXT "Bl&ue:", COLOR_BLUEACCEL, 243, 154, 24, 9

EDITTEXT COLOR_BLUE, 269, 152, 18, 12, WS_GROUP

PUSHBUTTON "&Add to Custom Colors", COLOR_ADD, 152, 166, 142, 14,

WS_GROUP

LISTBOX 101, 3, 113, 80, 52, LBS_SORT | WS_VSCROLL | WS_TABSTOP

LTEXT "Pen Style", 102, 3, 102, 57, 10

LTEXT "Pen Width", 103, 93, 103, 37, 8

EDITTEXT 104, 94, 113, 32, 12, ES_AUTOHSCROLL

LTEXT "Join Style", 105, 93, 129, 40, 8

LISTBOX 106, 94, 138, 48, 24, LBS_SORT | WS_VSCROLL | WS_TABSTOP

END

In addition to modifying the template, it was necessary to provide a callback function which initialized the new controls in the dialog and processed the corresponding input. The following excerpt from the application's source file shows the callback function:

UINT FAR PASCAL SetPenAttr(HWND hdlg, UINT msg, UINT wParan, LONG lParam)

{

static HWND hwndLineStyles;

static HWND hwndJoinStyles;

static HWND hwndWidth;

int index;

switch(msg){

case WM_INITDIALOG:

/* Initialize each custom control with the required data. */

hwndLineStyles = GetDlgItem(hdlg, 101);

/* Use the PenStyle constants as indices. */

SendMessage(hwndLineStyles, LB_ADDSTRING, 0, (LONG)"DASH");

SendMessage(hwndLineStyles, LB_ADDSTRING, 0, (LONG)"DASHDOT");

SendMessage(hwndLineStyles, LB_ADDSTRING, 0, (LONG)"DOT");

SendMessage(hwndLineStyles, LB_ADDSTRING, 0, (LONG)"INSIDEFRAME");

SendMessage(hwndLineStyles, LB_ADDSTRING, 0, (LONG)"NULL");

SendMessage(hwndLineStyles, LB_ADDSTRING, 0, (LONG)"SOLID");

hwndJoinStyles = GetDlgItem(hdlg, 106);

/* Use the JoinStyle constants as indices. */

SendMessage(hwndJoinStyles, LB_ADDSTRING, PS_JOIN_BEVEL, (LONG)"BEVEL");

SendMessage(hwndJoinStyles, LB_ADDSTRING, PS_JOIN_MITER, (LONG)"MITER");

SendMessage(hwndJoinStyles, LB_ADDSTRING, PS_JOIN_ROUND, (LONG)"ROUND");

hwndWidth = GetDlgItem(hdlg, 104);

SetWindowText(hwndWidth, (LPTSTR)"1");

return TRUE;

case WM_COMMAND:

/* Retrieve the requested line style. */

index = SendMessage(hwndLineStyles, LB_GETCURSEL, 0, 0L);

if (index == 0)

dwPenStyle = PS_DASH;

else if (index == 1)

dwPenStyle = PS_DASHDOT;

else if (index == 2)

dwPenStyle = PS_DOT;

else if (index == 3)

dwPenStyle = PS_INSIDEFRAME;

else if (index == 4)

dwPenStyle = PS_NULL;

else if (index == 5)

dwPenStyle = PS_SOLID;

/* Retrieve the requested join style. */

index = SendMessage(hwndJoinStyles, LB_GETCURSEL, 0, 0L);

if (index == 0)

dwJoinStyle = PS_JOIN_BEVEL;

else if (index == 1)

dwJoinStyle = PS_JOIN_MITER;

else if (index == 2)

dwJoinStyle = PS_JOIN_ROUND;

/* Retrieve the requested width. */

GetDlgItemText(hdlg, 104, chWidth, 3);

iCount = GetStrLngth(chWidth);

dwWidth = RetrieveWidth(chWidth, iCount);

return FALSE;

}

return FALSE;

}

Finally, it was necessary to register the callback function with the common dialog procedure by initializing the appropriate members of a CHOOSECOLOR data structure which was passed to the ChooseColor function. The following excerpt from the application's source file shows how this was done:

/* Set all structure fields to zero. */

memset(&cc, 0, sizeof(CHOOSECOLOR));

/* Initialize the necessary CHOOSECOLOR members. */

cc.lStructSize = sizeof(CHOOSECOLOR);

cc.hwndOwner = hWnd;

cc.hInstance = hInst;

cc.rgbResult = clr;

cc.lpCustColors = aclrCust;

cc.Flags = CC_ENABLEHOOK | CC_ENABLETEMPLATE;

cc.lpfnHook = (LPCCHOOKPROC)SetPenAttr;

cc.lpTemplateName = "CHOOSECOLOR";

After the ChooseColor function executes, the rgbResult member contains the user's requested color, the dwPenStyle variable identifies the user's requested pen style, the dwJoinStyle variable identifies the user's requested join style, and the dwWidth variable specifies the requested line width. These values were passed to the ExtCreatePen function and used to create a geometric pen which was then selected into a device context and used for various line drawing operations:

if (ChooseColor(&cc)){

hdc = GetDC(hWnd);

/* Initialize the pen's "brush". */

logbrush.lbStyle = BS_SOLID;

logbrush.lbColor = cc.rgbResult;

logbrush.lbHatch = NULL;

/* Create a pen and select it into the dc. */

hpenOld = SelectObject(hdc,

ExtCreatePen(PS_GEOMETRIC | dwPenStyle

| dwJoinStyle,

dwWidth, &logbrush, (DWORD)NULL,

(LPDWORD)NULL));

/* Perform drawing operations. */

MoveToEx(hdc, 100, 100, NULL);

LineTo(hdc, 100, 200);

LineTo(hdc, 200, 200);

LineTo(hdc, 200, 100);

LineTo(hdc, 100, 100);

ReleaseDC(hWnd, hdc);

}