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);
}