Release 940420
[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     rc.right = tm.tmHeight;
544     if (PtInRect(&rc, MAKEPOINT(lParam)))
545     {
546         SetFocus(hWnd);
547         SetCapture(hWnd);
548         pressed = TRUE;
549         InvalidateRect(hWnd, NULL, FALSE);
550         UpdateWindow(hWnd);
551     }
552 }
553
554 static LONG CB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
555 {
556     RECT rc;
557     HDC hDC;
558     TEXTMETRIC tm;
559     int delta;
560     WND *wndPtr = WIN_FindWndPtr(hWnd);
561     LONG style;
562
563     pressed = FALSE;
564     ReleaseCapture();
565     hDC = GetDC(hWnd);
566     GetTextMetrics(hDC, &tm);
567     ReleaseDC(hWnd, hDC);
568     GetClientRect(hWnd, &rc);
569     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
570     rc.top += delta;
571     rc.bottom = tm.tmHeight + delta;
572     rc.right = tm.tmHeight;
573
574     if (PtInRect(&rc, MAKEPOINT(lParam)))
575     {
576         style = wndPtr->dwStyle & 0x0000000F;
577         if (style == BS_AUTOCHECKBOX)
578         {
579             switch ((WORD)(*(wndPtr->wExtra)))
580             {
581             case 0:
582                 (WORD)(*(wndPtr->wExtra)) = 1;
583                 break;
584
585             case 1:
586                 (WORD)(*(wndPtr->wExtra)) = 0;
587                 break;
588             }
589         }
590         else if (style == BS_AUTO3STATE)
591         {
592             switch ((WORD)(*(wndPtr->wExtra)))
593             {
594             case 0:
595                 (WORD)(*(wndPtr->wExtra)) = 1;
596                 break;
597
598             case 1:
599                 (WORD)(*(wndPtr->wExtra)) = 2;
600                 break;
601
602             case 2:
603                 (WORD)(*(wndPtr->wExtra)) = 0;
604                 break;
605             }
606         }
607         NOTIFY_PARENT(hWnd, BN_CLICKED);
608     }
609     GlobalUnlock(hWnd);
610     InvalidateRect(hWnd, NULL, FALSE);
611     UpdateWindow(hWnd);
612 }
613
614 static LONG CB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam)
615 {
616     RECT rc;
617     HDC hDC;
618     TEXTMETRIC tm;
619     int delta;
620
621     hDC = GetDC(hWnd);
622     GetTextMetrics(hDC, &tm);
623     ReleaseDC(hWnd, hDC);
624     GetClientRect(hWnd, &rc);
625     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
626     rc.top += delta;
627     rc.bottom = tm.tmHeight + delta;
628     rc.right = tm.tmHeight;
629     if (PtInRect(&rc, MAKEPOINT(lParam)))
630         NOTIFY_PARENT(hWnd, BN_DOUBLECLICKED);
631 }
632
633 static LONG CB_KillFocus(HWND hWnd)
634 {
635     pressed = FALSE;
636     InvalidateRect(hWnd, NULL, FALSE);
637     UpdateWindow(hWnd);
638 }
639
640 static LONG CB_SetCheck(HWND hWnd, WORD wParam)
641 {
642     WND *wndPtr = WIN_FindWndPtr(hWnd);
643
644     if ((WORD)(*(wndPtr->wExtra)) != wParam)
645     {
646         (WORD)(*(wndPtr->wExtra)) = wParam;
647         InvalidateRect(hWnd, NULL, FALSE);
648         UpdateWindow(hWnd);
649     }
650     GlobalUnlock(hWnd);
651 }
652
653 static LONG CB_GetCheck(HWND hWnd)
654 {
655     WORD wResult;
656     WND *wndPtr = WIN_FindWndPtr(hWnd);
657
658     wResult = (WORD)(*(wndPtr->wExtra));
659     GlobalUnlock(hWnd);
660     return (LONG)wResult;
661 }
662
663
664 /**********************************************************************
665  *       Radio Button Functions
666  */
667
668 static LONG RB_Paint(HWND hWnd)
669 {
670     PAINTSTRUCT ps;
671     RECT rc;
672     HDC hDC;
673     HPEN hOldPen;
674     HBRUSH hBrush, hOldBrush;
675     int textlen, delta;
676     char *text;
677     HANDLE hText;
678     TEXTMETRIC tm;
679     SIZE size;
680     WND *wndPtr = WIN_FindWndPtr(hWnd);
681
682     hDC = BeginPaint(hWnd, &ps);
683     GetClientRect(hWnd, &rc);
684
685     hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowText);
686
687     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
688                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
689     FillRect(hDC, &rc, hBrush);
690
691     textlen = GetWindowTextLength(hWnd);
692     hText = USER_HEAP_ALLOC(0, textlen+1);
693     text = USER_HEAP_ADDR(hText);
694     GetWindowText(hWnd, text, textlen+1);
695     GetTextMetrics(hDC, &tm);
696
697     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
698     Ellipse(hDC, 0, rc.top + delta, tm.tmHeight, tm.tmHeight + delta);
699     if (pressed)
700         Ellipse(hDC, 1, rc.top + delta + 1, tm.tmHeight - 1, 
701                                               tm.tmHeight + delta - 1);
702
703     if ((WORD)(*(wndPtr->wExtra)) == 1)
704     {
705         hBrush = CreateSolidBrush( GetNearestColor(hDC, GetSysColor(COLOR_WINDOWTEXT)));
706         hOldBrush = (HBRUSH)SelectObject(hDC, (HANDLE)hBrush);
707         Ellipse(hDC, 3, rc.top + delta + 3, tm.tmHeight - 3,
708                                             tm.tmHeight + delta -3); 
709         SelectObject(hDC, (HANDLE)hOldBrush);
710         DeleteObject((HANDLE)hBrush);
711     }
712
713     rc.left = tm.tmHeight + tm.tmAveCharWidth / 2;
714     DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
715
716     /* do we have the focus? */
717     if (GetFocus() == hWnd)
718     {
719         GetTextExtentPoint(hDC, text, textlen, &size);
720         rc.top += delta - 1;
721         rc.bottom -= delta + 1;
722         rc.left--;
723         rc.right = rc.left + size.cx + 2;
724         DrawFocusRect(hDC, &rc);
725     }
726
727     SelectObject(hDC, hOldPen );
728     USER_HEAP_FREE(hText);
729     GlobalUnlock(hWnd);
730     EndPaint(hWnd, &ps);
731 }
732
733 static LONG RB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
734 {
735     RECT rc;
736     HDC hDC;
737     TEXTMETRIC tm;
738     int delta;
739
740     hDC = GetDC(hWnd);
741     GetTextMetrics(hDC, &tm);
742     ReleaseDC(hWnd, hDC);
743     GetClientRect(hWnd, &rc);
744     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
745     rc.top += delta;
746     rc.bottom = tm.tmHeight + delta;
747     rc.right = tm.tmHeight;
748     if (PtInRect(&rc, MAKEPOINT(lParam)))
749     {
750         SetFocus(hWnd);
751         SetCapture(hWnd);
752         pressed = TRUE;
753         InvalidateRect(hWnd, NULL, FALSE);
754         UpdateWindow(hWnd);
755     }
756 }
757
758 static LONG RB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
759 {
760     RECT rc;
761     HDC hDC;
762     TEXTMETRIC tm;
763     int delta;
764     WND *wndPtr = WIN_FindWndPtr(hWnd);
765     LONG style;
766
767     pressed = FALSE;
768     ReleaseCapture();
769     hDC = GetDC(hWnd);
770     GetTextMetrics(hDC, &tm);
771     ReleaseDC(hWnd, hDC);
772     GetClientRect(hWnd, &rc);
773     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
774     rc.top += delta;
775     rc.bottom = tm.tmHeight + delta;
776     rc.right = tm.tmHeight;
777
778     if (PtInRect(&rc, MAKEPOINT(lParam)))
779     {
780         style = wndPtr->dwStyle & 0x0000000F;
781         if (style == BS_AUTORADIOBUTTON)
782             (WORD)(*(wndPtr->wExtra)) = 1;
783         NOTIFY_PARENT(hWnd, BN_CLICKED);
784     }
785     GlobalUnlock(hWnd);
786     InvalidateRect(hWnd, NULL, FALSE);
787     UpdateWindow(hWnd);
788 }
789
790 static LONG RB_LButtonDblClk(HWND hWnd, WORD wParam, LONG lParam)
791 {
792     RECT rc;
793     HDC hDC;
794     TEXTMETRIC tm;
795     int delta;
796
797     hDC = GetDC(hWnd);
798     GetTextMetrics(hDC, &tm);
799     ReleaseDC(hWnd, hDC);
800     GetClientRect(hWnd, &rc);
801     delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
802     rc.top += delta;
803     rc.bottom = tm.tmHeight + delta;
804     rc.right = tm.tmHeight;
805     if (PtInRect(&rc, MAKEPOINT(lParam)))
806         NOTIFY_PARENT(hWnd, BN_DOUBLECLICKED);
807 }
808
809 static LONG RB_KillFocus(HWND hWnd)
810 {
811     pressed = FALSE;
812     InvalidateRect(hWnd, NULL, FALSE);
813     UpdateWindow(hWnd);
814 }
815
816 static LONG RB_SetCheck(HWND hWnd, WORD wParam)
817 {
818     WND *wndPtr = WIN_FindWndPtr(hWnd);
819
820     if ((WORD)(*(wndPtr->wExtra)) != wParam)
821     {
822         (WORD)(*(wndPtr->wExtra)) = wParam;
823         InvalidateRect(hWnd, NULL, FALSE);
824         UpdateWindow(hWnd);
825     }
826     GlobalUnlock(hWnd);
827 }
828
829 static LONG RB_GetCheck(HWND hWnd)
830 {
831     WORD wResult;
832     WND *wndPtr = WIN_FindWndPtr(hWnd);
833
834     wResult = (WORD)(*(wndPtr->wExtra));
835     GlobalUnlock(hWnd);
836     return (LONG)wResult;
837 }
838
839
840 /**********************************************************************
841  *       Group Box Functions
842  */
843
844 static LONG GB_Paint(HWND hWnd)
845 {
846     PAINTSTRUCT ps;
847     RECT rc;
848     HDC hDC;
849     HPEN hOldPen;
850     HBRUSH hBrush;
851     int textlen;
852     char *text;
853     HANDLE hText;
854     SIZE size;
855
856     hDC = BeginPaint(hWnd, &ps);
857     GetClientRect(hWnd, &rc);
858
859     hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowText);
860
861     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
862                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
863     FillRect(hDC, &rc, hBrush);
864
865     textlen = GetWindowTextLength(hWnd);
866     hText = USER_HEAP_ALLOC(0, textlen+1);
867     text = USER_HEAP_ADDR(hText);
868     GetWindowText(hWnd, text, textlen+1);
869     GetTextExtentPoint(hDC, text, textlen, &size);
870
871     rc.top = 5;
872     Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
873     rc.left = 10;
874     rc.top = 0;
875     rc.right = rc.left + size.cx + 1;
876     rc.bottom = size.cy;
877     DrawText(hDC, text, textlen, &rc, DT_SINGLELINE);
878
879     SelectObject(hDC, hOldPen );
880     USER_HEAP_FREE(hText);
881     EndPaint(hWnd, &ps);
882 }
883
884
885 /**********************************************************************
886  *       User Button Functions
887  */
888
889 static LONG UB_Paint(HWND hWnd)
890 {
891     PAINTSTRUCT ps;
892     HDC hDC;
893     RECT rc;
894     HBRUSH hBrush;
895
896     hDC = BeginPaint(hWnd, &ps);
897     GetClientRect(hWnd, &rc);
898
899     hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
900                          MAKELPARAM(hWnd, CTLCOLOR_BTN));
901     FillRect(hDC, &rc, hBrush);
902
903     NOTIFY_PARENT(hWnd, BN_PAINT);
904
905     /* do we have the focus? */
906     if (GetFocus() == hWnd)
907         DrawFocusRect(hDC, &rc);
908
909     EndPaint(hWnd, &ps);
910 }
911
912 static LONG UB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
913 {
914     RECT rc;
915
916     SetFocus(hWnd);
917     SetCapture(hWnd);
918     GetClientRect(hWnd, &rc);
919     if (PtInRect(&rc, MAKEPOINT(lParam)))
920         NOTIFY_PARENT(hWnd, BN_HILITE);
921     InvalidateRect(hWnd, NULL, FALSE);
922     UpdateWindow(hWnd);
923 }
924
925 static LONG UB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
926 {
927     RECT rc;
928
929     ReleaseCapture();
930     GetClientRect(hWnd, &rc);
931     if (PtInRect(&rc, MAKEPOINT(lParam)))
932     {
933         NOTIFY_PARENT(hWnd, BN_CLICKED);
934         NOTIFY_PARENT(hWnd, BN_UNHILITE);
935     }
936     InvalidateRect(hWnd, NULL, FALSE);
937     UpdateWindow(hWnd);
938 }
939
940 static LONG UB_KillFocus(HWND hWnd)
941 {
942     InvalidateRect(hWnd, NULL, FALSE);
943     UpdateWindow(hWnd);
944 }
945
946
947 /**********************************************************************
948  *       Ownerdrawn Button Functions
949  */
950
951 static LONG OB_Paint(HWND hWnd)
952 {
953     PAINTSTRUCT ps;
954     HDC         hDC;
955     RECT        rc;
956     HANDLE      hDis;
957     LPDRAWITEMSTRUCT lpdis;
958     WND *wndPtr = WIN_FindWndPtr(hWnd);
959     hDC = BeginPaint(hWnd, &ps);
960     GetClientRect(hWnd, &rc);
961     hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT));
962     lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
963     lpdis->hDC = hDC;
964     lpdis->itemID = 0;
965     CopyRect(&lpdis->rcItem, &rc);
966     lpdis->CtlID = wndPtr->wIDmenu;
967     lpdis->CtlType = ODT_BUTTON;
968     lpdis->itemAction = ODA_DRAWENTIRE;
969 /*    printf("ownerdrawn button WM_DRAWITEM CtrlID=%X\n", lpdis->CtlID);*/
970     SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis); 
971     USER_HEAP_FREE(hDis);
972     EndPaint(hWnd, &ps);
973 }
974
975 static LONG OB_LButtonDown(HWND hWnd, WORD wParam, LONG lParam)
976 {
977     HDC         hDC;
978     RECT        rc;
979     HANDLE      hDis;
980     LPDRAWITEMSTRUCT lpdis;
981     WND *wndPtr = WIN_FindWndPtr(hWnd);
982     SetFocus(hWnd);
983     SetCapture(hWnd);
984     hDC = GetDC(hWnd);
985     GetClientRect(hWnd, &rc);
986     if (PtInRect(&rc, MAKEPOINT(lParam)))
987         NOTIFY_PARENT(hWnd, BN_CLICKED);
988     GetClientRect(hWnd, &rc);
989     hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT));
990     lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
991     lpdis->hDC = hDC;
992     lpdis->itemID = 0;
993     CopyRect(&lpdis->rcItem, &rc);
994     lpdis->CtlID = wndPtr->wIDmenu;
995     lpdis->CtlType = ODT_BUTTON;
996     lpdis->itemAction = ODA_SELECT;
997     SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis); 
998     USER_HEAP_FREE(hDis);
999     ReleaseDC(hWnd, hDC);
1000 }
1001
1002 static LONG OB_LButtonUp(HWND hWnd, WORD wParam, LONG lParam)
1003 {
1004     HDC         hDC;
1005     RECT        rc;
1006     HANDLE      hDis;
1007     LPDRAWITEMSTRUCT lpdis;
1008     WND *wndPtr = WIN_FindWndPtr(hWnd);
1009     ReleaseCapture();
1010     hDC = GetDC(hWnd);
1011     GetClientRect(hWnd, &rc);
1012     if (PtInRect(&rc, MAKEPOINT(lParam)))
1013         NOTIFY_PARENT(hWnd, BN_CLICKED);
1014     GetClientRect(hWnd, &rc);
1015     hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT));
1016     lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
1017     lpdis->hDC = hDC;
1018     lpdis->itemID = 0;
1019     CopyRect(&lpdis->rcItem, &rc);
1020     lpdis->CtlID = wndPtr->wIDmenu;
1021     lpdis->CtlType = ODT_BUTTON;
1022     lpdis->itemAction = ODA_SELECT;
1023     SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis); 
1024     USER_HEAP_FREE(hDis);
1025     ReleaseDC(hWnd, hDC);
1026 }
1027
1028 static LONG OB_KillFocus(HWND hWnd)
1029 {
1030     InvalidateRect(hWnd, NULL, FALSE);
1031     UpdateWindow(hWnd);
1032 }
1033