Release 940614
[wine] / controls / button.c
1 /* File: button.c -- Button type widgets
2  *
3  * Copyright (C) 1993 Johannes Ruscheinski
4  * Copyright (C) 1993 David Metcalfe
5  */
6
7 static char Copyright1[] = "Copyright Johannes Ruscheinski, 1993";
8 static char Copyright2[] = "Copyright David Metcalfe, 1993";
9
10 #include <windows.h>
11 #include "win.h"
12 #include "user.h"
13 #include "syscolor.h"
14
15 LONG ButtonWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam);
16
17 static BOOL pressed;
18
19 #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \
20         SendMessage(GetParent(hWndCntrl), WM_COMMAND, \
21                 GetDlgCtrlID(hWndCntrl), MAKELPARAM(hWndCntrl, wNotifyCode));
22 #define DIM(array)      ((sizeof array)/(sizeof array[0]))
23
24 static LONG PB_Paint(HWND hWnd);
25 static LONG PB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam);
26 static LONG PB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam);
27 static LONG PB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam);
28 static LONG PB_KillFocus(HWND hwnd);
29 static void DrawRaisedPushButton(HDC hDC, HWND hButton, RECT rc);
30 static void DrawPressedPushButton(HDC hDC, HWND hButton, RECT rc);
31 static LONG CB_Paint(HWND hWnd);
32 static LONG CB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam);
33 static LONG CB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam);
34 static LONG CB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam);
35 static LONG CB_KillFocus(HWND hWnd);
36 static LONG CB_SetCheck(HWND hWnd, WORD wParam);
37 static LONG CB_GetCheck(HWND hWnd);
38 static LONG RB_Paint(HWND hWnd);
39 static LONG RB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam);
40 static LONG RB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam);
41 static LONG RB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam);
42 static LONG RB_KillFocus(HWND hWnd);
43 static LONG RB_SetCheck(HWND hWnd, WORD wParam);
44 static LONG RB_GetCheck(HWND hWnd);
45 static LONG GB_Paint(HWND hWnd);
46 static LONG UB_Paint(HWND hWnd);
47 static LONG UB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam);
48 static LONG UB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam);
49 static LONG UB_KillFocus(HWND hWnd);
50 static LONG OB_Paint(HWND hWnd);
51 static LONG OB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam);
52 static LONG OB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam);
53 static LONG OB_KillFocus(HWND hWnd);
54
55 typedef struct
56 {
57     LONG (*paintfn)();
58     LONG (*lButtonDownfn)();
59     LONG (*lButtonUpfn)();
60     LONG (*lButtonDblClkfn)();
61     LONG (*killFocusfn)();
62     LONG (*setCheckfn)();
63     LONG (*getCheckfn)();
64 } BTNFN;
65
66 #define MAX_BTN_TYPE  12
67
68 static BTNFN btnfn[MAX_BTN_TYPE] =
69 {
70     { 
71         (LONG(*)())PB_Paint,                       /* BS_PUSHBUTTON */
72         (LONG(*)())PB_LButtonDown,
73         (LONG(*)())PB_LButtonUp,
74         (LONG(*)())PB_LButtonDblClk,
75         (LONG(*)())PB_KillFocus,
76         (LONG(*)())NULL,
77         (LONG(*)())NULL
78     },
79     { 
80         (LONG(*)())PB_Paint,                       /* BS_DEFPUSHBUTTON */
81         (LONG(*)())PB_LButtonDown,
82         (LONG(*)())PB_LButtonUp,
83         (LONG(*)())PB_LButtonDblClk,
84         (LONG(*)())PB_KillFocus,
85         (LONG(*)())NULL,
86         (LONG(*)())NULL
87     },
88     {
89         (LONG(*)())CB_Paint,                       /* BS_CHECKBOX */
90         (LONG(*)())CB_LButtonDown,
91         (LONG(*)())CB_LButtonUp,
92         (LONG(*)())CB_LButtonDblClk,
93         (LONG(*)())CB_KillFocus,
94         (LONG(*)())CB_SetCheck,
95         (LONG(*)())CB_GetCheck
96     },
97     {
98         (LONG(*)())CB_Paint,                       /* BS_AUTOCHECKBOX */
99         (LONG(*)())CB_LButtonDown,
100         (LONG(*)())CB_LButtonUp,
101         (LONG(*)())CB_LButtonDblClk,
102         (LONG(*)())CB_KillFocus,
103         (LONG(*)())CB_SetCheck,
104         (LONG(*)())CB_GetCheck
105     },
106     {
107         (LONG(*)())RB_Paint,                       /* BS_RADIOBUTTON */
108         (LONG(*)())RB_LButtonDown,
109         (LONG(*)())RB_LButtonUp,
110         (LONG(*)())RB_LButtonDblClk,
111         (LONG(*)())RB_KillFocus,
112         (LONG(*)())RB_SetCheck,
113         (LONG(*)())RB_GetCheck
114     },
115     {
116         (LONG(*)())CB_Paint,                       /* BS_3STATE */
117         (LONG(*)())CB_LButtonDown,
118         (LONG(*)())CB_LButtonUp,
119         (LONG(*)())CB_LButtonDblClk,
120         (LONG(*)())CB_KillFocus,
121         (LONG(*)())CB_SetCheck,
122         (LONG(*)())CB_GetCheck
123     },
124     {
125         (LONG(*)())CB_Paint,                       /* BS_AUTO3STATE */
126         (LONG(*)())CB_LButtonDown,
127         (LONG(*)())CB_LButtonUp,
128         (LONG(*)())CB_LButtonDblClk,
129         (LONG(*)())CB_KillFocus,
130         (LONG(*)())CB_SetCheck,
131         (LONG(*)())CB_GetCheck
132     },
133     {
134         (LONG(*)())GB_Paint,                       /* BS_GROUPBOX */
135         (LONG(*)())NULL,
136         (LONG(*)())NULL,
137         (LONG(*)())NULL,
138         (LONG(*)())NULL,
139         (LONG(*)())NULL,
140         (LONG(*)())NULL
141     },
142     {
143         (LONG(*)())UB_Paint,                       /* BS_USERBUTTON */
144         (LONG(*)())UB_LButtonDown,
145         (LONG(*)())UB_LButtonUp,
146         (LONG(*)())NULL,
147         (LONG(*)())UB_KillFocus,
148         (LONG(*)())NULL,
149         (LONG(*)())NULL
150     },
151     {
152         (LONG(*)())RB_Paint,                       /* BS_AUTORADIOBUTTON */
153         (LONG(*)())RB_LButtonDown,
154         (LONG(*)())RB_LButtonUp,
155         (LONG(*)())RB_LButtonDblClk,
156         (LONG(*)())RB_KillFocus,
157         (LONG(*)())RB_SetCheck,
158         (LONG(*)())RB_GetCheck
159     },
160     {
161         (LONG(*)())NULL,                           /* Not defined */
162         (LONG(*)())NULL,
163         (LONG(*)())NULL,
164         (LONG(*)())NULL,
165         (LONG(*)())NULL,
166         (LONG(*)())NULL,
167         (LONG(*)())NULL
168     },
169     { 
170         (LONG(*)())OB_Paint,                       /* BS_OWNERDRAW */
171         (LONG(*)())OB_LButtonDown,
172         (LONG(*)())OB_LButtonUp,
173         (LONG(*)())NULL,
174         (LONG(*)())OB_KillFocus,
175         (LONG(*)())NULL,
176         (LONG(*)())NULL
177     },
178 };
179
180
181 LONG ButtonWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam)
182 {
183         LONG lResult = 0;
184         HDC hDC;
185         RECT rc;
186
187         WND *wndPtr = WIN_FindWndPtr(hWnd);
188         LONG style = wndPtr->dwStyle & 0x0000000F;
189
190         switch (uMsg) {
191 /*      case WM_GETDLGCODE:
192                 lResult = DLGC_BUTTON;
193                 break;
194 */
195         case WM_ENABLE:
196                 InvalidateRect(hWnd, NULL, FALSE);
197                 break;
198
199         case WM_CREATE:
200                 if (style < 0L || style >= (LONG)DIM(btnfn))
201                     lResult = -1L;
202                 else
203                 {
204                     (WORD)(*(wndPtr->wExtra)) = 0;
205                     pressed = FALSE;
206                     lResult = 0L;
207                 }
208                 break;
209
210         case WM_PAINT:
211                 if (btnfn[style].paintfn)
212                     (btnfn[style].paintfn)(hWnd);
213                 break;
214
215         case WM_LBUTTONDOWN:
216                 if (btnfn[style].lButtonDownfn)
217                     (btnfn[style].lButtonDownfn)(hWnd, wParam, lParam);
218                 break;
219
220         case WM_LBUTTONUP:
221                 if (btnfn[style].lButtonUpfn)
222                     (btnfn[style].lButtonUpfn)(hWnd, wParam, lParam);
223                 break;
224
225         case WM_LBUTTONDBLCLK:
226                 if (btnfn[style].lButtonDblClkfn)
227                     (btnfn[style].lButtonDblClkfn)(hWnd, wParam, lParam);
228                 break;
229
230         case WM_SETFOCUS:
231                 break;
232
233         case WM_KILLFOCUS:
234                 if (btnfn[style].killFocusfn)
235                     (btnfn[style].killFocusfn)(hWnd);
236                 break;
237
238         case WM_SYSCOLORCHANGE:
239                 InvalidateRect(hWnd, NULL, TRUE);
240                 break;
241
242         case BM_SETCHECK:
243                 if (btnfn[style].setCheckfn)
244                     (btnfn[style].setCheckfn)(hWnd, wParam);
245                 break;
246
247         case BM_GETCHECK:
248                 if (btnfn[style].getCheckfn)
249                     return (btnfn[style].getCheckfn)(hWnd);
250                 break;
251
252         default:
253                 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
254                 break;
255         }
256
257         GlobalUnlock(hWnd);
258         return lResult;
259 }
260
261
262 /**********************************************************************
263  *       Push Button Functions
264  */
265
266 static LONG PB_Paint(HWND hWnd)
267 {
268     PAINTSTRUCT ps;
269     RECT rc;
270     HDC hDC;
271
272     hDC = BeginPaint(hWnd, &ps);
273     GetClientRect(hWnd, &rc);
274     if (pressed)
275         DrawPressedPushButton(hDC, hWnd, rc);
276     else
277         DrawRaisedPushButton(hDC, hWnd, rc);
278     EndPaint(hWnd, &ps);
279 }
280
281 static LONG PB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
282 {
283     SetFocus(hWnd);
284     SetCapture(hWnd);
285     pressed = TRUE;
286     InvalidateRect(hWnd, NULL, FALSE);
287     UpdateWindow(hWnd);
288 }
289
290 static LONG PB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
291 {
292     RECT rc;
293
294     pressed = FALSE;
295     ReleaseCapture();
296     GetClientRect(hWnd, &rc);
297     if (PtInRect(&rc, MAKEPOINT(lParam)))
298         NOTIFY_PARENT(hWnd, BN_CLICKED);
299     InvalidateRect(hWnd, NULL, FALSE);
300     UpdateWindow(hWnd);
301 }
302
303 static LONG PB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam)
304 {
305     RECT rc;
306
307     GetClientRect(hWnd, &rc);
308     if (PtInRect(&rc, MAKEPOINT(lParam)))
309         NOTIFY_PARENT(hWnd, BN_DOUBLECLICKED);
310 }
311
312 static LONG PB_KillFocus(HWND hWnd)
313 {
314     pressed = FALSE;
315     InvalidateRect(hWnd, NULL, FALSE);
316     UpdateWindow(hWnd);
317 }
318
319 static void DrawRaisedPushButton(HDC hDC, HWND hButton, RECT rc)
320 {
321         HPEN hOldPen;
322         HBRUSH hOldBrush;
323         HRGN rgn1, rgn2, rgn;
324         int len;
325         static char text[50+1];
326         POINT points[6];
327         DWORD dwTextSize;
328         int delta;
329         TEXTMETRIC tm;
330
331         hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
332         hOldBrush = (HBRUSH)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
333         SetBkMode(hDC, TRANSPARENT);
334
335         rgn = CreateRectRgn(0, 0,  0,  0);
336         rgn1 = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
337
338         SendMessage(GetParent(hButton), WM_CTLCOLOR, (WORD)hDC,
339                     MAKELPARAM(hButton, CTLCOLOR_BTN));
340         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
341
342         /* draw button label, if any: */
343         len = GetWindowText(hButton, text, sizeof text);
344         if (len >= 1) {
345                 rc.left--;      rc.bottom--;
346                 DrawText(hDC, text, len, &rc,
347                          DT_SINGLELINE | DT_CENTER| DT_VCENTER);
348         }
349
350         /* draw button highlight */
351         points[0].x = rc.left+2;
352         points[0].y = rc.bottom;
353         points[1].x = rc.left+4;
354         points[1].y = rc.bottom-2;
355         points[2].x = rc.left+4;
356         points[2].y = rc.top+3;
357         points[3].x = rc.right-3;
358         points[3].y = rc.top+3;
359         points[4].x = rc.right-1;
360         points[4].y = rc.top+1;
361         points[5].x = rc.left+2;
362         points[5].y = rc.top+1;
363         rgn2 = CreatePolygonRgn(points, DIM(points), ALTERNATE);
364         CombineRgn(rgn, rgn1, rgn2, RGN_AND);
365         FillRgn(hDC, rgn2, sysColorObjects.hbrushBtnHighlight);
366
367         /* draw button shadow: */
368         points[0].x = rc.left+2;
369         points[0].y = rc.bottom;
370         points[1].x = rc.left+4;
371         points[1].y = rc.bottom-2;
372         points[2].x = rc.right-3;
373         points[2].y = rc.bottom-2;
374         points[3].x = rc.right-3;
375         points[3].y = rc.top+3;
376         points[4].x = rc.right-1;
377         points[4].y = rc.top;
378         points[5].x = rc.right-1;
379         points[5].y = rc.bottom;
380         rgn2 = CreatePolygonRgn(points, DIM(points), ALTERNATE);
381         CombineRgn(rgn, rgn1, rgn2, RGN_AND);
382         FillRgn(hDC, rgn2, sysColorObjects.hbrushBtnShadow);
383
384         /* do we have the focus? */
385         if (len >= 1 && GetFocus() == hButton) {
386                 dwTextSize = GetTextExtent(hDC, text, len);
387                 delta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) >> 1;
388                 rc.left += delta;       rc.right -= delta;
389                 GetTextMetrics(hDC, &tm);
390                 delta = ((rc.bottom - rc.top) - tm.tmHeight - 1) >> 1;
391                 rc.top += delta;        rc.bottom -= delta;
392                 DrawFocusRect(hDC, &rc);
393         }
394
395         SelectObject(hDC, (HANDLE)hOldPen);
396         SelectObject(hDC, (HANDLE)hOldBrush);
397         DeleteObject((HANDLE)rgn1);
398         DeleteObject((HANDLE)rgn2);
399         DeleteObject((HANDLE)rgn);
400 }
401
402
403 static void DrawPressedPushButton(HDC hDC, HWND hButton, RECT rc)
404 {
405         HPEN hOldPen;
406         HBRUSH hOldBrush;
407         int len;
408         static char text[50+1];
409         DWORD dwTextSize;
410         int delta;
411         TEXTMETRIC tm;
412
413         hOldBrush = (HBRUSH)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
414         hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
415         SetBkMode(hDC, TRANSPARENT);
416
417         /* give parent a chance to alter parameters: */
418         SendMessage(GetParent(hButton), WM_CTLCOLOR, (WORD)hDC,
419                     MAKELPARAM(hButton, CTLCOLOR_BTN));
420         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
421
422         /* draw button shadow: */
423         SelectObject(hDC, sysColorObjects.hbrushBtnShadow );
424         PatBlt(hDC, rc.left+1, rc.top+1, 1, rc.bottom-rc.top-2, PATCOPY );
425         PatBlt(hDC, rc.left+1, rc.top+1, rc.right-rc.left-2, 1, PATCOPY );
426
427         /* draw button label, if any: */
428         len = GetWindowText(hButton, text, sizeof text);
429         if (len >= 1) {
430                 rc.top++;       rc.left++;
431                 DrawText(hDC, text, len, &rc,
432                          DT_SINGLELINE | DT_CENTER| DT_VCENTER);
433         }
434
435         /* do we have the focus? */
436         if (len >= 1 && GetFocus() == hButton) {
437                 dwTextSize = GetTextExtent(hDC, text, len);
438                 delta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) >> 1;
439                 rc.left += delta;       rc.right -= delta;
440                 GetTextMetrics(hDC, &tm);
441                 delta = ((rc.bottom - rc.top) - tm.tmHeight - 1) >> 1;
442                 rc.top += delta;        rc.bottom -= delta;
443                 DrawFocusRect(hDC, &rc);
444         }
445
446         SelectObject(hDC, (HANDLE)hOldPen);
447         SelectObject(hDC, (HANDLE)hOldBrush);
448 }
449
450
451 /**********************************************************************
452  *       Check Box Functions
453  */
454
455 static LONG CB_Paint(HWND hWnd)
456 {
457     PAINTSTRUCT ps;
458     RECT rc, rc3;
459     HDC hDC;
460     HPEN hOldPen;
461     HBRUSH hBrush, hGrayBrush;
462     int textlen, delta;
463     char *text;
464     HANDLE hText;
465     TEXTMETRIC tm;
466     SIZE size;
467     WND *wndPtr = WIN_FindWndPtr(hWnd);
468
469     hDC = BeginPaint(hWnd, &ps);
470     GetClientRect(hWnd, &rc);
471
472     hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowText);
473     hGrayBrush = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
474
475     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
476                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
477     FillRect(hDC, &rc, hBrush);
478
479     textlen = GetWindowTextLength(hWnd);
480     hText = USER_HEAP_ALLOC(0, textlen+1);
481     text = USER_HEAP_ADDR(hText);
482     GetWindowText(hWnd, text, textlen+1);
483     GetTextMetrics(hDC, &tm);
484
485     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
486     Rectangle(hDC, 0, rc.top + delta, tm.tmHeight, tm.tmHeight + delta);
487     if (pressed)
488         Rectangle(hDC, 1, rc.top + delta + 1, tm.tmHeight - 1, 
489                                               tm.tmHeight + delta - 1);
490
491     switch ((WORD)(*(wndPtr->wExtra)))
492     {
493     case 1:
494         MoveTo(hDC, 0, rc.top + delta);
495         LineTo(hDC, tm.tmHeight - 1, tm.tmHeight + delta - 1);
496         MoveTo(hDC, 0, tm.tmHeight + delta - 1);
497         LineTo(hDC, tm.tmHeight - 1, rc.top + delta);
498         break;
499
500     case 2:
501         rc3.left = 1;
502         rc3.top = rc.top + delta + 1;
503         rc3.right = tm.tmHeight - 1;
504         rc3.bottom = tm.tmHeight + delta - 1;
505         FillRect(hDC, &rc3, hGrayBrush);
506         break;
507     }
508
509     rc.left = tm.tmHeight + tm.tmAveCharWidth / 2;
510     DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
511
512     /* do we have the focus? */
513     if (GetFocus() == hWnd)
514     {
515         GetTextExtentPoint(hDC, text, textlen, &size);
516         rc.top += delta - 1;
517         rc.bottom -= delta + 1;
518         rc.left--;
519         rc.right = rc.left + size.cx + 2;
520         DrawFocusRect(hDC, &rc);
521     }
522
523     SelectObject(hDC, hOldPen);
524     USER_HEAP_FREE(hText);
525     GlobalUnlock(hWnd);
526     EndPaint(hWnd, &ps);
527 }
528
529 static LONG CB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
530 {
531     RECT rc;
532     HDC hDC;
533     TEXTMETRIC tm;
534     int delta;
535
536     hDC = GetDC(hWnd);
537     GetTextMetrics(hDC, &tm);
538     ReleaseDC(hWnd, hDC);
539     GetClientRect(hWnd, &rc);
540     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
541     rc.top += delta;
542     rc.bottom = tm.tmHeight + delta;
543     if (PtInRect(&rc, MAKEPOINT(lParam)))
544     {
545         SetFocus(hWnd);
546         SetCapture(hWnd);
547         pressed = TRUE;
548         InvalidateRect(hWnd, NULL, FALSE);
549         UpdateWindow(hWnd);
550     }
551 }
552
553 static LONG CB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
554 {
555     RECT rc;
556     HDC hDC;
557     TEXTMETRIC tm;
558     int delta;
559     WND *wndPtr = WIN_FindWndPtr(hWnd);
560     LONG style;
561
562     pressed = FALSE;
563     ReleaseCapture();
564     hDC = GetDC(hWnd);
565     GetTextMetrics(hDC, &tm);
566     ReleaseDC(hWnd, hDC);
567     GetClientRect(hWnd, &rc);
568     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
569     rc.top += delta;
570     rc.bottom = tm.tmHeight + delta;
571
572     if (PtInRect(&rc, MAKEPOINT(lParam)))
573     {
574         style = wndPtr->dwStyle & 0x0000000F;
575         if (style == BS_AUTOCHECKBOX)
576         {
577             switch ((WORD)(*(wndPtr->wExtra)))
578             {
579             case 0:
580                 (WORD)(*(wndPtr->wExtra)) = 1;
581                 break;
582
583             case 1:
584                 (WORD)(*(wndPtr->wExtra)) = 0;
585                 break;
586             }
587         }
588         else if (style == BS_AUTO3STATE)
589         {
590             switch ((WORD)(*(wndPtr->wExtra)))
591             {
592             case 0:
593                 (WORD)(*(wndPtr->wExtra)) = 1;
594                 break;
595
596             case 1:
597                 (WORD)(*(wndPtr->wExtra)) = 2;
598                 break;
599
600             case 2:
601                 (WORD)(*(wndPtr->wExtra)) = 0;
602                 break;
603             }
604         }
605         NOTIFY_PARENT(hWnd, BN_CLICKED);
606     }
607     GlobalUnlock(hWnd);
608     InvalidateRect(hWnd, NULL, FALSE);
609     UpdateWindow(hWnd);
610 }
611
612 static LONG CB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam)
613 {
614     RECT rc;
615     HDC hDC;
616     TEXTMETRIC tm;
617     int delta;
618
619     hDC = GetDC(hWnd);
620     GetTextMetrics(hDC, &tm);
621     ReleaseDC(hWnd, hDC);
622     GetClientRect(hWnd, &rc);
623     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
624     rc.top += delta;
625     rc.bottom = tm.tmHeight + delta;
626     if (PtInRect(&rc, MAKEPOINT(lParam)))
627         NOTIFY_PARENT(hWnd, BN_DOUBLECLICKED);
628 }
629
630 static LONG CB_KillFocus(HWND hWnd)
631 {
632     pressed = FALSE;
633     InvalidateRect(hWnd, NULL, FALSE);
634     UpdateWindow(hWnd);
635 }
636
637 static LONG CB_SetCheck(HWND hWnd, WORD wParam)
638 {
639     WND *wndPtr = WIN_FindWndPtr(hWnd);
640
641     if ((WORD)(*(wndPtr->wExtra)) != wParam)
642     {
643         (WORD)(*(wndPtr->wExtra)) = wParam;
644         InvalidateRect(hWnd, NULL, FALSE);
645         UpdateWindow(hWnd);
646     }
647     GlobalUnlock(hWnd);
648 }
649
650 static LONG CB_GetCheck(HWND hWnd)
651 {
652     WORD wResult;
653     WND *wndPtr = WIN_FindWndPtr(hWnd);
654
655     wResult = (WORD)(*(wndPtr->wExtra));
656     GlobalUnlock(hWnd);
657     return (LONG)wResult;
658 }
659
660
661 /**********************************************************************
662  *       Radio Button Functions
663  */
664
665 static LONG RB_Paint(HWND hWnd)
666 {
667     PAINTSTRUCT ps;
668     RECT rc;
669     HDC hDC;
670     HPEN hOldPen;
671     HBRUSH hBrush, hOldBrush;
672     int textlen, delta;
673     char *text;
674     HANDLE hText;
675     TEXTMETRIC tm;
676     SIZE size;
677     WND *wndPtr = WIN_FindWndPtr(hWnd);
678
679     hDC = BeginPaint(hWnd, &ps);
680     GetClientRect(hWnd, &rc);
681
682     hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowText);
683
684     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
685                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
686     FillRect(hDC, &rc, hBrush);
687
688     textlen = GetWindowTextLength(hWnd);
689     hText = USER_HEAP_ALLOC(0, textlen+1);
690     text = USER_HEAP_ADDR(hText);
691     GetWindowText(hWnd, text, textlen+1);
692     GetTextMetrics(hDC, &tm);
693
694     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
695     Ellipse(hDC, 0, rc.top + delta, tm.tmHeight, tm.tmHeight + delta);
696     if (pressed)
697         Ellipse(hDC, 1, rc.top + delta + 1, tm.tmHeight - 1, 
698                                               tm.tmHeight + delta - 1);
699
700     if ((WORD)(*(wndPtr->wExtra)) == 1)
701     {
702         hBrush = CreateSolidBrush( GetNearestColor(hDC, GetSysColor(COLOR_WINDOWTEXT)));
703         hOldBrush = (HBRUSH)SelectObject(hDC, (HANDLE)hBrush);
704         Ellipse(hDC, 3, rc.top + delta + 3, tm.tmHeight - 3,
705                                             tm.tmHeight + delta -3); 
706         SelectObject(hDC, (HANDLE)hOldBrush);
707         DeleteObject((HANDLE)hBrush);
708     }
709
710     rc.left = tm.tmHeight + tm.tmAveCharWidth / 2;
711     DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
712
713     /* do we have the focus? */
714     if (GetFocus() == hWnd)
715     {
716         GetTextExtentPoint(hDC, text, textlen, &size);
717         rc.top += delta - 1;
718         rc.bottom -= delta + 1;
719         rc.left--;
720         rc.right = rc.left + size.cx + 2;
721         DrawFocusRect(hDC, &rc);
722     }
723
724     SelectObject(hDC, hOldPen );
725     USER_HEAP_FREE(hText);
726     GlobalUnlock(hWnd);
727     EndPaint(hWnd, &ps);
728 }
729
730 static LONG RB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
731 {
732     RECT rc;
733     HDC hDC;
734     TEXTMETRIC tm;
735     int delta;
736
737     hDC = GetDC(hWnd);
738     GetTextMetrics(hDC, &tm);
739     ReleaseDC(hWnd, hDC);
740     GetClientRect(hWnd, &rc);
741     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
742     rc.top += delta;
743     rc.bottom = tm.tmHeight + delta;
744     if (PtInRect(&rc, MAKEPOINT(lParam)))
745     {
746         SetFocus(hWnd);
747         SetCapture(hWnd);
748         pressed = TRUE;
749         InvalidateRect(hWnd, NULL, FALSE);
750         UpdateWindow(hWnd);
751     }
752 }
753
754 static LONG RB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
755 {
756     RECT rc;
757     HDC hDC;
758     TEXTMETRIC tm;
759     int delta;
760     WND *wndPtr = WIN_FindWndPtr(hWnd);
761     LONG style;
762
763     pressed = FALSE;
764     ReleaseCapture();
765     hDC = GetDC(hWnd);
766     GetTextMetrics(hDC, &tm);
767     ReleaseDC(hWnd, hDC);
768     GetClientRect(hWnd, &rc);
769     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
770     rc.top += delta;
771     rc.bottom = tm.tmHeight + delta;
772
773     if (PtInRect(&rc, MAKEPOINT(lParam)))
774     {
775         style = wndPtr->dwStyle & 0x0000000F;
776         if (style == BS_AUTORADIOBUTTON)
777             (WORD)(*(wndPtr->wExtra)) = 1;
778         NOTIFY_PARENT(hWnd, BN_CLICKED);
779     }
780     GlobalUnlock(hWnd);
781     InvalidateRect(hWnd, NULL, FALSE);
782     UpdateWindow(hWnd);
783 }
784
785 static LONG RB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam)
786 {
787     RECT rc;
788     HDC hDC;
789     TEXTMETRIC tm;
790     int delta;
791
792     hDC = GetDC(hWnd);
793     GetTextMetrics(hDC, &tm);
794     ReleaseDC(hWnd, hDC);
795     GetClientRect(hWnd, &rc);
796     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
797     rc.top += delta;
798     rc.bottom = tm.tmHeight + delta;
799     if (PtInRect(&rc, MAKEPOINT(lParam)))
800         NOTIFY_PARENT(hWnd, BN_DOUBLECLICKED);
801 }
802
803 static LONG RB_KillFocus(HWND hWnd)
804 {
805     pressed = FALSE;
806     InvalidateRect(hWnd, NULL, FALSE);
807     UpdateWindow(hWnd);
808 }
809
810 static LONG RB_SetCheck(HWND hWnd, WORD wParam)
811 {
812     WND *wndPtr = WIN_FindWndPtr(hWnd);
813
814     if ((WORD)(*(wndPtr->wExtra)) != wParam)
815     {
816         (WORD)(*(wndPtr->wExtra)) = wParam;
817         InvalidateRect(hWnd, NULL, FALSE);
818         UpdateWindow(hWnd);
819     }
820     GlobalUnlock(hWnd);
821 }
822
823 static LONG RB_GetCheck(HWND hWnd)
824 {
825     WORD wResult;
826     WND *wndPtr = WIN_FindWndPtr(hWnd);
827
828     wResult = (WORD)(*(wndPtr->wExtra));
829     GlobalUnlock(hWnd);
830     return (LONG)wResult;
831 }
832
833
834 /**********************************************************************
835  *       Group Box Functions
836  */
837
838 static LONG GB_Paint(HWND hWnd)
839 {
840     PAINTSTRUCT ps;
841     RECT rc;
842     HDC hDC;
843     HPEN hOldPen;
844     HBRUSH hBrush;
845     int textlen;
846     char *text;
847     HANDLE hText;
848     SIZE size;
849
850     hDC = BeginPaint(hWnd, &ps);
851     GetClientRect(hWnd, &rc);
852
853     hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowText);
854
855     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
856                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
857     FillRect(hDC, &rc, hBrush);
858
859     textlen = GetWindowTextLength(hWnd);
860     hText = USER_HEAP_ALLOC(0, textlen+1);
861     text = USER_HEAP_ADDR(hText);
862     GetWindowText(hWnd, text, textlen+1);
863     GetTextExtentPoint(hDC, text, textlen, &size);
864
865     rc.top = 5;
866     Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
867     rc.left = 10;
868     rc.top = 0;
869     rc.right = rc.left + size.cx + 1;
870     rc.bottom = size.cy;
871     DrawText(hDC, text, textlen, &rc, DT_SINGLELINE);
872
873     SelectObject(hDC, hOldPen );
874     USER_HEAP_FREE(hText);
875     EndPaint(hWnd, &ps);
876 }
877
878
879 /**********************************************************************
880  *       User Button Functions
881  */
882
883 static LONG UB_Paint(HWND hWnd)
884 {
885     PAINTSTRUCT ps;
886     HDC hDC;
887     RECT rc;
888     HBRUSH hBrush;
889
890     hDC = BeginPaint(hWnd, &ps);
891     GetClientRect(hWnd, &rc);
892
893     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
894                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
895     FillRect(hDC, &rc, hBrush);
896
897     NOTIFY_PARENT(hWnd, BN_PAINT);
898
899     /* do we have the focus? */
900     if (GetFocus() == hWnd)
901         DrawFocusRect(hDC, &rc);
902
903     EndPaint(hWnd, &ps);
904 }
905
906 static LONG UB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
907 {
908     RECT rc;
909
910     SetFocus(hWnd);
911     SetCapture(hWnd);
912     GetClientRect(hWnd, &rc);
913     if (PtInRect(&rc, MAKEPOINT(lParam)))
914         NOTIFY_PARENT(hWnd, BN_HILITE);
915     InvalidateRect(hWnd, NULL, FALSE);
916     UpdateWindow(hWnd);
917 }
918
919 static LONG UB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
920 {
921     RECT rc;
922
923     ReleaseCapture();
924     GetClientRect(hWnd, &rc);
925     if (PtInRect(&rc, MAKEPOINT(lParam)))
926     {
927         NOTIFY_PARENT(hWnd, BN_CLICKED);
928         NOTIFY_PARENT(hWnd, BN_UNHILITE);
929     }
930     InvalidateRect(hWnd, NULL, FALSE);
931     UpdateWindow(hWnd);
932 }
933
934 static LONG UB_KillFocus(HWND hWnd)
935 {
936     InvalidateRect(hWnd, NULL, FALSE);
937     UpdateWindow(hWnd);
938 }
939
940
941 /**********************************************************************
942  *       Ownerdrawn Button Functions
943  */
944
945 static LONG OB_Paint(HWND hWnd)
946 {
947     PAINTSTRUCT ps;
948     HDC         hDC;
949     RECT        rc;
950     HANDLE      hDis;
951     LPDRAWITEMSTRUCT lpdis;
952     WND *wndPtr = WIN_FindWndPtr(hWnd);
953     hDC = BeginPaint(hWnd, &ps);
954     GetClientRect(hWnd, &rc);
955     hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT));
956     lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
957     lpdis->hDC = hDC;
958     lpdis->itemID = 0;
959     CopyRect(&lpdis->rcItem, &rc);
960     lpdis->CtlID = wndPtr->wIDmenu;
961     lpdis->CtlType = ODT_BUTTON;
962     lpdis->itemAction = ODA_DRAWENTIRE;
963 /*    printf("ownerdrawn button WM_DRAWITEM CtrlID=%X\n", lpdis->CtlID);*/
964     SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis); 
965     USER_HEAP_FREE(hDis);
966     EndPaint(hWnd, &ps);
967 }
968
969 static LONG OB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
970 {
971     HDC         hDC;
972     RECT        rc;
973     HANDLE      hDis;
974     LPDRAWITEMSTRUCT lpdis;
975     WND *wndPtr = WIN_FindWndPtr(hWnd);
976     SetFocus(hWnd);
977     SetCapture(hWnd);
978     hDC = GetDC(hWnd);
979     GetClientRect(hWnd, &rc);
980     if (PtInRect(&rc, MAKEPOINT(lParam)))
981         NOTIFY_PARENT(hWnd, BN_CLICKED);
982     GetClientRect(hWnd, &rc);
983     hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT));
984     lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
985     lpdis->hDC = hDC;
986     lpdis->itemID = 0;
987     CopyRect(&lpdis->rcItem, &rc);
988     lpdis->CtlID = wndPtr->wIDmenu;
989     lpdis->CtlType = ODT_BUTTON;
990     lpdis->itemAction = ODA_SELECT;
991     SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis); 
992     USER_HEAP_FREE(hDis);
993     ReleaseDC(hWnd, hDC);
994 }
995
996 static LONG OB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
997 {
998     HDC         hDC;
999     RECT        rc;
1000     HANDLE      hDis;
1001     LPDRAWITEMSTRUCT lpdis;
1002     WND *wndPtr = WIN_FindWndPtr(hWnd);
1003     ReleaseCapture();
1004     hDC = GetDC(hWnd);
1005     GetClientRect(hWnd, &rc);
1006     if (PtInRect(&rc, MAKEPOINT(lParam)))
1007         NOTIFY_PARENT(hWnd, BN_CLICKED);
1008     GetClientRect(hWnd, &rc);
1009     hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT));
1010     lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
1011     lpdis->hDC = hDC;
1012     lpdis->itemID = 0;
1013     CopyRect(&lpdis->rcItem, &rc);
1014     lpdis->CtlID = wndPtr->wIDmenu;
1015     lpdis->CtlType = ODT_BUTTON;
1016     lpdis->itemAction = ODA_SELECT;
1017     SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis); 
1018     USER_HEAP_FREE(hDis);
1019     ReleaseDC(hWnd, hDC);
1020 }
1021
1022 static LONG OB_KillFocus(HWND hWnd)
1023 {
1024     InvalidateRect(hWnd, NULL, FALSE);
1025     UpdateWindow(hWnd);
1026 }
1027