1 /* File: button.c -- Button type widgets
3 * Copyright (C) 1993 Johannes Ruscheinski
4 * Copyright (C) 1993 David Metcalfe
5 * Copyright (C) 1994 Alexandre Julliard
13 static void PB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
);
14 static void PB_PaintGrayOnGray(HDC32 hDC
,HFONT32 hFont
,RECT32
*rc
,char *text
);
15 static void CB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
);
16 static void GB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
);
17 static void UB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
);
18 static void OB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
);
19 static void BUTTON_CheckAutoRadioButton( WND
*wndPtr
);
21 #define MAX_BTN_TYPE 12
23 static const WORD maxCheckState
[MAX_BTN_TYPE
] =
25 BUTTON_UNCHECKED
, /* BS_PUSHBUTTON */
26 BUTTON_UNCHECKED
, /* BS_DEFPUSHBUTTON */
27 BUTTON_CHECKED
, /* BS_CHECKBOX */
28 BUTTON_CHECKED
, /* BS_AUTOCHECKBOX */
29 BUTTON_CHECKED
, /* BS_RADIOBUTTON */
30 BUTTON_3STATE
, /* BS_3STATE */
31 BUTTON_3STATE
, /* BS_AUTO3STATE */
32 BUTTON_UNCHECKED
, /* BS_GROUPBOX */
33 BUTTON_UNCHECKED
, /* BS_USERBUTTON */
34 BUTTON_CHECKED
, /* BS_AUTORADIOBUTTON */
35 BUTTON_UNCHECKED
, /* Not defined */
36 BUTTON_UNCHECKED
/* BS_OWNERDRAW */
39 typedef void (*pfPaint
)( WND
*wndPtr
, HDC32 hdc
, WORD action
);
41 static const pfPaint btnPaintFunc
[MAX_BTN_TYPE
] =
43 PB_Paint
, /* BS_PUSHBUTTON */
44 PB_Paint
, /* BS_DEFPUSHBUTTON */
45 CB_Paint
, /* BS_CHECKBOX */
46 CB_Paint
, /* BS_AUTOCHECKBOX */
47 CB_Paint
, /* BS_RADIOBUTTON */
48 CB_Paint
, /* BS_3STATE */
49 CB_Paint
, /* BS_AUTO3STATE */
50 GB_Paint
, /* BS_GROUPBOX */
51 UB_Paint
, /* BS_USERBUTTON */
52 CB_Paint
, /* BS_AUTORADIOBUTTON */
53 NULL
, /* Not defined */
54 OB_Paint
/* BS_OWNERDRAW */
57 #define PAINT_BUTTON(wndPtr,style,action) \
58 if (btnPaintFunc[style]) { \
59 HDC32 hdc = GetDC32( (wndPtr)->hwndSelf ); \
60 (btnPaintFunc[style])(wndPtr,hdc,action); \
61 ReleaseDC32( (wndPtr)->hwndSelf, hdc ); }
63 #define BUTTON_SEND_CTLCOLOR(wndPtr,hdc) \
64 SendMessage32A( GetParent32((wndPtr)->hwndSelf), WM_CTLCOLORBTN, \
65 (hdc), (wndPtr)->hwndSelf )
67 static HBITMAP16 hbitmapCheckBoxes
= 0;
68 static WORD checkBoxWidth
= 0, checkBoxHeight
= 0;
71 /***********************************************************************
74 LRESULT
ButtonWndProc(HWND32 hWnd
, UINT32 uMsg
, WPARAM32 wParam
, LPARAM lParam
)
77 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
78 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
79 LONG style
= wndPtr
->dwStyle
& 0x0f;
86 case BS_PUSHBUTTON
: return DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
;
87 case BS_DEFPUSHBUTTON
: return DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
;
89 case BS_AUTORADIOBUTTON
: return DLGC_BUTTON
| DLGC_RADIOBUTTON
;
90 default: return DLGC_BUTTON
;
94 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
98 if (!hbitmapCheckBoxes
)
101 hbitmapCheckBoxes
= LoadBitmap16(0, MAKEINTRESOURCE(OBM_CHECKBOXES
));
102 GetObject16( hbitmapCheckBoxes
, sizeof(bmp
), &bmp
);
103 checkBoxWidth
= bmp
.bmWidth
/ 4;
104 checkBoxHeight
= bmp
.bmHeight
/ 3;
106 if (style
< 0L || style
>= MAX_BTN_TYPE
) return -1; /* abort */
107 infoPtr
->state
= BUTTON_UNCHECKED
;
115 if (btnPaintFunc
[style
])
118 HDC32 hdc
= BeginPaint32( hWnd
, &ps
);
119 (btnPaintFunc
[style
])( wndPtr
, hdc
, ODA_DRAWENTIRE
);
120 EndPaint32( hWnd
, &ps
);
125 SendMessage32A( hWnd
, BM_SETSTATE32
, TRUE
, 0 );
127 SetCapture32( hWnd
);
132 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) break;
133 SendMessage32A( hWnd
, BM_SETSTATE32
, FALSE
, 0 );
134 GetClientRect16( hWnd
, &rect
);
135 if (PtInRect16( &rect
, MAKEPOINT16(lParam
) ))
139 case BS_AUTOCHECKBOX
:
140 SendMessage32A( hWnd
, BM_SETCHECK32
,
141 !(infoPtr
->state
& BUTTON_CHECKED
), 0 );
143 case BS_AUTORADIOBUTTON
:
144 SendMessage32A( hWnd
, BM_SETCHECK32
, TRUE
, 0 );
147 SendMessage32A( hWnd
, BM_SETCHECK32
,
148 (infoPtr
->state
& BUTTON_3STATE
) ? 0 :
149 ((infoPtr
->state
& 3) + 1), 0 );
152 SendMessage32A( GetParent32(hWnd
), WM_COMMAND
,
153 MAKEWPARAM( wndPtr
->wIDmenu
, BN_CLICKED
), hWnd
);
158 if (GetCapture32() == hWnd
)
160 GetClientRect16( hWnd
, &rect
);
161 SendMessage32A( hWnd
, BM_SETSTATE32
,
162 PtInRect16( &rect
,MAKEPOINT16(lParam
) ), 0 );
167 if(style
== BS_GROUPBOX
) return HTTRANSPARENT
;
168 return DefWindowProc32A( hWnd
, uMsg
, wParam
, lParam
);
171 DEFWND_SetText( wndPtr
, (LPSTR
)lParam
);
172 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
176 infoPtr
->hFont
= (HFONT16
)wParam
;
177 if (lParam
) PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
181 return infoPtr
->hFont
;
184 infoPtr
->state
|= BUTTON_HASFOCUS
;
185 PAINT_BUTTON( wndPtr
, style
, ODA_FOCUS
);
189 infoPtr
->state
&= ~BUTTON_HASFOCUS
;
190 PAINT_BUTTON( wndPtr
, style
, ODA_FOCUS
);
193 case WM_SYSCOLORCHANGE
:
194 InvalidateRect32( hWnd
, NULL
, FALSE
);
199 if ((wParam
& 0x0f) >= MAX_BTN_TYPE
) break;
200 wndPtr
->dwStyle
= (wndPtr
->dwStyle
& 0xfffffff0)
201 | (wParam
& 0x0000000f);
202 style
= wndPtr
->dwStyle
& 0x0000000f;
203 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
208 return infoPtr
->state
& 3;
212 if (wParam
> maxCheckState
[style
]) wParam
= maxCheckState
[style
];
213 if ((infoPtr
->state
& 3) != wParam
)
215 infoPtr
->state
= (infoPtr
->state
& ~3) | wParam
;
216 PAINT_BUTTON( wndPtr
, style
, ODA_SELECT
);
218 if ((style
== BS_AUTORADIOBUTTON
) && (wParam
== BUTTON_CHECKED
))
219 BUTTON_CheckAutoRadioButton( wndPtr
);
224 return infoPtr
->state
;
230 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) break;
231 infoPtr
->state
|= BUTTON_HIGHLIGHTED
;
235 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) break;
236 infoPtr
->state
&= ~BUTTON_HIGHLIGHTED
;
238 PAINT_BUTTON( wndPtr
, style
, ODA_SELECT
);
242 return DefWindowProc32A(hWnd
, uMsg
, wParam
, lParam
);
248 /**********************************************************************
249 * Push Button Functions
252 static void PB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
)
257 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
259 GetClientRect32( wndPtr
->hwndSelf
, &rc
);
261 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
262 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
263 BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
264 hOldPen
= (HPEN16
)SelectObject(hDC
, sysColorObjects
.hpenWindowFrame
);
265 hOldBrush
= (HBRUSH16
)SelectObject(hDC
, sysColorObjects
.hbrushBtnFace
);
266 SetBkMode(hDC
, TRANSPARENT
);
267 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
268 if (action
== ODA_DRAWENTIRE
)
270 SetPixel( hDC
, rc
.left
, rc
.top
, GetSysColor(COLOR_WINDOW
) );
271 SetPixel( hDC
, rc
.left
, rc
.bottom
-1, GetSysColor(COLOR_WINDOW
) );
272 SetPixel( hDC
, rc
.right
-1, rc
.top
, GetSysColor(COLOR_WINDOW
) );
273 SetPixel( hDC
, rc
.right
-1, rc
.bottom
-1, GetSysColor(COLOR_WINDOW
) );
275 InflateRect32( &rc
, -1, -1 );
277 if ((wndPtr
->dwStyle
& 0x000f) == BS_DEFPUSHBUTTON
)
279 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
280 InflateRect32( &rc
, -1, -1 );
283 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
)
285 /* draw button shadow: */
286 SelectObject(hDC
, sysColorObjects
.hbrushBtnShadow
);
287 PatBlt(hDC
, rc
.left
, rc
.top
, 1, rc
.bottom
-rc
.top
, PATCOPY
);
288 PatBlt(hDC
, rc
.left
, rc
.top
, rc
.right
-rc
.left
, 1, PATCOPY
);
289 rc
.left
+= 2; /* To position the text down and right */
292 else GRAPH_DrawReliefRect( hDC
, &rc
, 2, 2, FALSE
);
294 /* draw button label, if any: */
295 if (wndPtr
->text
&& wndPtr
->text
[0])
298 GetObject16( sysColorObjects
.hbrushBtnFace
, sizeof(lb
), &lb
);
299 if (wndPtr
->dwStyle
& WS_DISABLED
&&
300 GetSysColor(COLOR_GRAYTEXT
)==lb
.lbColor
)
301 /* don't write gray text on gray bkg */
302 PB_PaintGrayOnGray(hDC
,infoPtr
->hFont
,&rc
,wndPtr
->text
);
305 SetTextColor( hDC
, (wndPtr
->dwStyle
& WS_DISABLED
) ?
306 GetSysColor(COLOR_GRAYTEXT
) : GetSysColor(COLOR_BTNTEXT
));
307 DrawText32A( hDC
, wndPtr
->text
, -1, &rc
,
308 DT_SINGLELINE
| DT_CENTER
| DT_VCENTER
);
309 /* do we have the focus? */
310 if (infoPtr
->state
& BUTTON_HASFOCUS
)
312 RECT32 r
= { 0, 0, 0, 0 };
313 INT32 xdelta
, ydelta
;
315 DrawText32A( hDC
, wndPtr
->text
, -1, &r
,
316 DT_SINGLELINE
| DT_CALCRECT
);
317 xdelta
= ((rc
.right
- rc
.left
) - (r
.right
- r
.left
) - 1) / 2;
318 ydelta
= ((rc
.bottom
- rc
.top
) - (r
.bottom
- r
.top
) - 1) / 2;
319 if (xdelta
< 0) xdelta
= 0;
320 if (ydelta
< 0) ydelta
= 0;
321 InflateRect32( &rc
, -xdelta
, -ydelta
);
322 DrawFocusRect32( hDC
, &rc
);
327 SelectObject( hDC
, hOldPen
);
328 SelectObject( hDC
, hOldBrush
);
332 /**********************************************************************
333 * Push Button sub function [internal]
334 * using a raster brush to avoid gray text on gray background
337 void PB_PaintGrayOnGray(HDC32 hDC
,HFONT32 hFont
,RECT32
*rc
,char *text
)
339 static int Pattern
[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55};
340 HBITMAP16 hbm
= CreateBitmap(8, 8, 1, 1, Pattern
);
341 HDC32 hdcMem
= CreateCompatibleDC(hDC
);
347 DrawText32A( hDC
, text
, -1, &rect
, DT_SINGLELINE
| DT_CALCRECT
);
349 rect
.left
=(rc
->right
-rect
.right
)/2; /* for centering text bitmap */
350 rect
.top
=(rc
->bottom
-rect
.bottom
)/2;
351 hbmMem
= CreateCompatibleBitmap( hDC
,rect
.right
,rect
.bottom
);
352 SelectObject( hdcMem
, hbmMem
);
353 hBr
= SelectObject( hdcMem
,CreatePatternBrush(hbm
));
355 PatBlt( hdcMem
,0,0,rect
.right
,rect
.bottom
,WHITENESS
);
356 if (hFont
) SelectObject( hdcMem
, hFont
);
357 DrawText32A( hdcMem
, text
, -1, &rc2
, DT_SINGLELINE
);
358 PatBlt( hdcMem
,0,0,rect
.right
,rect
.bottom
,0xFA0089);
359 DeleteObject( SelectObject( hdcMem
,hBr
));
360 BitBlt( hDC
,rect
.left
,rect
.top
,rect
.right
,rect
.bottom
,hdcMem
,0,0,0x990000);
362 DeleteObject( hbmMem
);
366 /**********************************************************************
367 * Check Box & Radio Button Functions
370 static void CB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
)
374 int textlen
, delta
, x
, y
;
376 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
378 GetClientRect16(wndPtr
->hwndSelf
, &rc
);
380 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
381 hBrush
= BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
382 if (action
== ODA_DRAWENTIRE
) FillRect16( hDC
, &rc
, hBrush
);
384 GetTextMetrics16(hDC
, &tm
);
385 delta
= (rc
.bottom
- rc
.top
- tm
.tmHeight
) >> 1;
387 /* Draw the check-box bitmap */
389 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) x
+= 2 * checkBoxWidth
;
390 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
)) x
+= checkBoxWidth
;
391 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
392 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
)) y
+= checkBoxHeight
;
393 else if (infoPtr
->state
& BUTTON_3STATE
) y
+= 2 * checkBoxHeight
;
394 GRAPH_DrawBitmap( hDC
, hbitmapCheckBoxes
, rc
.left
, rc
.top
+ delta
,
395 x
, y
, checkBoxWidth
, checkBoxHeight
);
396 rc
.left
+= checkBoxWidth
+ tm
.tmAveCharWidth
/ 2;
398 if (!wndPtr
->text
) return;
399 textlen
= strlen( wndPtr
->text
);
401 if (action
== ODA_DRAWENTIRE
)
403 if (wndPtr
->dwStyle
& WS_DISABLED
)
404 SetTextColor( hDC
, GetSysColor(COLOR_GRAYTEXT
) );
405 DrawText16( hDC
, wndPtr
->text
, textlen
, &rc
,
406 DT_SINGLELINE
| DT_VCENTER
| DT_NOCLIP
);
409 if ((action
== ODA_FOCUS
) ||
410 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
412 RECT16 rect
= { 0, 0, 0, 0 };
413 DrawText16( hDC
, wndPtr
->text
, textlen
, &rect
,
414 DT_SINGLELINE
| DT_CALCRECT
);
418 rc
.bottom
-= delta
+ 1;
421 rc
.right
= rc
.left
+ rect
.right
+ 2;
422 DrawFocusRect16( hDC
, &rc
);
427 /**********************************************************************
428 * BUTTON_CheckAutoRadioButton
430 * wndPtr is checked, uncheck everything else in group
432 static void BUTTON_CheckAutoRadioButton( WND
*wndPtr
)
434 HWND32 parent
, sibling
;
435 if (!(wndPtr
->dwStyle
& WS_CHILD
)) return;
436 parent
= wndPtr
->parent
->hwndSelf
;
437 for(sibling
= GetNextDlgGroupItem32( parent
, wndPtr
->hwndSelf
, FALSE
);
438 sibling
!= wndPtr
->hwndSelf
;
439 sibling
= GetNextDlgGroupItem32( parent
, sibling
, FALSE
))
440 SendMessage32A( sibling
, BM_SETCHECK32
, BUTTON_UNCHECKED
, 0 );
444 /**********************************************************************
445 * Group Box Functions
448 static void GB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
)
451 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
453 if (action
!= ODA_DRAWENTIRE
) return;
455 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
456 BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
457 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
459 GetClientRect16( wndPtr
->hwndSelf
, &rc
);
461 MoveTo( hDC
, rc
.left
, rc
.top
+2 );
462 LineTo( hDC
, rc
.right
-1, rc
.top
+2 );
463 LineTo( hDC
, rc
.right
-1, rc
.bottom
-1 );
464 LineTo( hDC
, rc
.left
, rc
.bottom
-1 );
465 LineTo( hDC
, rc
.left
, rc
.top
+2 );
467 if (!wndPtr
->text
) return;
468 if (wndPtr
->dwStyle
& WS_DISABLED
)
469 SetTextColor( hDC
, GetSysColor(COLOR_GRAYTEXT
) );
471 DrawText16( hDC
, wndPtr
->text
, -1, &rc
, DT_SINGLELINE
| DT_NOCLIP
);
475 /**********************************************************************
476 * User Button Functions
479 static void UB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
)
483 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
485 if (action
== ODA_SELECT
) return;
487 GetClientRect16( wndPtr
->hwndSelf
, &rc
);
489 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
490 hBrush
= BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
491 FillRect16( hDC
, &rc
, hBrush
);
493 if ((action
== ODA_FOCUS
) ||
494 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
495 DrawFocusRect16( hDC
, &rc
);
499 /**********************************************************************
500 * Ownerdrawn Button Functions
503 static void OB_Paint( WND
*wndPtr
, HDC32 hDC
, WORD action
)
505 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
506 DRAWITEMSTRUCT32 dis
;
508 dis
.CtlType
= ODT_BUTTON
;
509 dis
.CtlID
= wndPtr
->wIDmenu
;
511 dis
.itemAction
= action
;
512 dis
.itemState
= ((infoPtr
->state
& BUTTON_HASFOCUS
) ? ODS_FOCUS
: 0) |
513 ((infoPtr
->state
& BUTTON_HIGHLIGHTED
) ? ODS_SELECTED
: 0) |
514 ((wndPtr
->dwStyle
& WS_DISABLED
) ? ODS_DISABLED
: 0);
515 dis
.hwndItem
= wndPtr
->hwndSelf
;
518 GetClientRect32( wndPtr
->hwndSelf
, &dis
.rcItem
);
519 SendMessage32A( GetParent32(wndPtr
->hwndSelf
), WM_DRAWITEM
,
520 wndPtr
->wIDmenu
, (LPARAM
)&dis
);