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 #include "stackframe.h"
15 extern void DEFWND_SetText( HWND hwnd
, LPSTR text
); /* windows/defwnd.c */
17 static void PB_Paint( HWND hWnd
, HDC hDC
, WORD action
);
18 static void CB_Paint( HWND hWnd
, HDC hDC
, WORD action
);
19 static void GB_Paint( HWND hWnd
, HDC hDC
, WORD action
);
20 static void UB_Paint( HWND hWnd
, HDC hDC
, WORD action
);
21 static void OB_Paint( HWND hWnd
, HDC hDC
, WORD action
);
22 static void BUTTON_CheckAutoRadioButton(HWND hWnd
);
25 #define MAX_BTN_TYPE 12
27 static WORD maxCheckState
[MAX_BTN_TYPE
] =
29 BUTTON_UNCHECKED
, /* BS_PUSHBUTTON */
30 BUTTON_UNCHECKED
, /* BS_DEFPUSHBUTTON */
31 BUTTON_CHECKED
, /* BS_CHECKBOX */
32 BUTTON_CHECKED
, /* BS_AUTOCHECKBOX */
33 BUTTON_CHECKED
, /* BS_RADIOBUTTON */
34 BUTTON_3STATE
, /* BS_3STATE */
35 BUTTON_3STATE
, /* BS_AUTO3STATE */
36 BUTTON_UNCHECKED
, /* BS_GROUPBOX */
37 BUTTON_UNCHECKED
, /* BS_USERBUTTON */
38 BUTTON_CHECKED
, /* BS_AUTORADIOBUTTON */
39 BUTTON_UNCHECKED
, /* Not defined */
40 BUTTON_UNCHECKED
/* BS_OWNERDRAW */
43 typedef void (*pfPaint
)(HWND
,HDC
,WORD
);
45 static pfPaint btnPaintFunc
[MAX_BTN_TYPE
] =
47 PB_Paint
, /* BS_PUSHBUTTON */
48 PB_Paint
, /* BS_DEFPUSHBUTTON */
49 CB_Paint
, /* BS_CHECKBOX */
50 CB_Paint
, /* BS_AUTOCHECKBOX */
51 CB_Paint
, /* BS_RADIOBUTTON */
52 CB_Paint
, /* BS_3STATE */
53 CB_Paint
, /* BS_AUTO3STATE */
54 GB_Paint
, /* BS_GROUPBOX */
55 UB_Paint
, /* BS_USERBUTTON */
56 CB_Paint
, /* BS_AUTORADIOBUTTON */
57 NULL
, /* Not defined */
58 OB_Paint
/* BS_OWNERDRAW */
61 #define PAINT_BUTTON(hwnd,style,action) \
62 if (btnPaintFunc[style]) { \
63 HDC hdc = GetDC( hwnd ); \
64 (btnPaintFunc[style])(hwnd,hdc,action); \
65 ReleaseDC( hwnd, hdc ); }
67 static HBITMAP hbitmapCheckBoxes
= 0;
68 static WORD checkBoxWidth
= 0, checkBoxHeight
= 0;
71 LONG
ButtonWndProc(HWND hWnd
, WORD uMsg
, WORD wParam
, LONG lParam
)
75 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
76 LONG style
= wndPtr
->dwStyle
& 0x0000000F;
77 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
84 return DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
;
85 case BS_DEFPUSHBUTTON
:
86 return DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
;
88 case BS_AUTORADIOBUTTON
:
89 return DLGC_BUTTON
| DLGC_RADIOBUTTON
;
95 PAINT_BUTTON( hWnd
, style
, ODA_DRAWENTIRE
);
99 if (!hbitmapCheckBoxes
)
102 hbitmapCheckBoxes
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECKBOXES
) );
103 GetObject( hbitmapCheckBoxes
, sizeof(bmp
), (LPSTR
)&bmp
);
104 checkBoxWidth
= bmp
.bmWidth
/ 4;
105 checkBoxHeight
= bmp
.bmHeight
/ 3;
108 if (style
< 0L || style
>= MAX_BTN_TYPE
)
112 infoPtr
->state
= BUTTON_UNCHECKED
;
122 if (btnPaintFunc
[style
])
125 HDC hdc
= BeginPaint( hWnd
, &ps
);
126 (btnPaintFunc
[style
])( hWnd
, hdc
, ODA_DRAWENTIRE
);
127 ReleaseDC( hWnd
, hdc
);
132 SendMessage( hWnd
, BM_SETSTATE
, TRUE
, 0 );
139 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) break;
140 SendMessage( hWnd
, BM_SETSTATE
, FALSE
, 0 );
141 GetClientRect( hWnd
, &rect
);
142 if (PtInRect( &rect
, MAKEPOINT(lParam
) ))
146 case BS_AUTOCHECKBOX
:
147 SendMessage( hWnd
, BM_SETCHECK
,
148 !(infoPtr
->state
& BUTTON_CHECKED
), 0 );
150 case BS_AUTORADIOBUTTON
:
151 SendMessage( hWnd
, BM_SETCHECK
, TRUE
, 0 );
154 SendMessage( hWnd
, BM_SETCHECK
,
155 (infoPtr
->state
& BUTTON_3STATE
) ? 0 :
156 ((infoPtr
->state
& 3) + 1), 0 );
159 SendMessage( GetParent(hWnd
), WM_COMMAND
,
160 wndPtr
->wIDmenu
, MAKELPARAM(hWnd
,BN_CLICKED
));
165 if (GetCapture() == hWnd
)
167 GetClientRect( hWnd
, &rect
);
168 if (PtInRect( &rect
, MAKEPOINT(lParam
)) )
169 SendMessage( hWnd
, BM_SETSTATE
, TRUE
, 0 );
170 else SendMessage( hWnd
, BM_SETSTATE
, FALSE
, 0 );
175 if(style
== BS_GROUPBOX
) return HTTRANSPARENT
;
176 lResult
= DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
180 DEFWND_SetText( hWnd
, (LPSTR
)PTR_SEG_TO_LIN(lParam
) );
181 PAINT_BUTTON( hWnd
, style
, ODA_DRAWENTIRE
);
185 infoPtr
->hFont
= wParam
;
187 PAINT_BUTTON( hWnd
, style
, ODA_DRAWENTIRE
);
191 return infoPtr
->hFont
;
194 infoPtr
->state
|= BUTTON_HASFOCUS
;
195 PAINT_BUTTON( hWnd
, style
, ODA_FOCUS
);
199 infoPtr
->state
&= ~BUTTON_HASFOCUS
;
200 PAINT_BUTTON( hWnd
, style
, ODA_FOCUS
);
203 case WM_SYSCOLORCHANGE
:
204 InvalidateRect(hWnd
, NULL
, FALSE
);
208 if ((wParam
& 0x0f) >= MAX_BTN_TYPE
) break;
209 wndPtr
->dwStyle
= (wndPtr
->dwStyle
& 0xfffffff0)
210 | (wParam
& 0x0000000f);
211 style
= wndPtr
->dwStyle
& 0x0000000f;
212 PAINT_BUTTON( hWnd
, style
, ODA_DRAWENTIRE
);
216 lResult
= infoPtr
->state
& 3;
220 if (wParam
> maxCheckState
[style
])
221 wParam
= maxCheckState
[style
];
222 if ((infoPtr
->state
& 3) != wParam
)
224 infoPtr
->state
= (infoPtr
->state
& ~3) | wParam
;
225 PAINT_BUTTON( hWnd
, style
, ODA_SELECT
);
227 if(style
== BS_AUTORADIOBUTTON
&& wParam
==BUTTON_CHECKED
)
228 BUTTON_CheckAutoRadioButton(hWnd
);
232 lResult
= infoPtr
->state
;
236 if (!wParam
!= !(infoPtr
->state
& BUTTON_HIGHLIGHTED
))
238 if (wParam
) infoPtr
->state
|= BUTTON_HIGHLIGHTED
;
239 else infoPtr
->state
&= ~BUTTON_HIGHLIGHTED
;
240 PAINT_BUTTON( hWnd
, style
, ODA_SELECT
);
245 lResult
= DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
253 /**********************************************************************
254 * Push Button Functions
257 static void PB_Paint( HWND hButton
, HDC hDC
, WORD action
)
266 WND
*wndPtr
= WIN_FindWndPtr( hButton
);
267 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
269 GetClientRect(hButton
, &rc
);
271 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
272 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
273 SendMessage( GetParent(hButton
), WM_CTLCOLOR
, (WORD
)hDC
,
274 MAKELPARAM(hButton
, CTLCOLOR_BTN
) );
275 hOldPen
= (HPEN
)SelectObject(hDC
, sysColorObjects
.hpenWindowFrame
);
276 hOldBrush
= (HBRUSH
)SelectObject(hDC
, sysColorObjects
.hbrushBtnFace
);
277 SetBkMode(hDC
, TRANSPARENT
);
278 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
279 if (action
== ODA_DRAWENTIRE
)
281 SetPixel( hDC
, rc
.left
, rc
.top
, GetSysColor(COLOR_WINDOW
) );
282 SetPixel( hDC
, rc
.left
, rc
.bottom
-1, GetSysColor(COLOR_WINDOW
) );
283 SetPixel( hDC
, rc
.right
-1, rc
.top
, GetSysColor(COLOR_WINDOW
) );
284 SetPixel( hDC
, rc
.right
-1, rc
.bottom
-1, GetSysColor(COLOR_WINDOW
) );
286 InflateRect( &rc
, -1, -1 );
288 if ((wndPtr
->dwStyle
& 0x000f) == BS_DEFPUSHBUTTON
)
290 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
291 InflateRect( &rc
, -1, -1 );
294 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
)
296 /* draw button shadow: */
297 SelectObject(hDC
, sysColorObjects
.hbrushBtnShadow
);
298 PatBlt(hDC
, rc
.left
, rc
.top
, 1, rc
.bottom
-rc
.top
, PATCOPY
);
299 PatBlt(hDC
, rc
.left
, rc
.top
, rc
.right
-rc
.left
, 1, PATCOPY
);
300 rc
.left
+= 2; /* To position the text down and right */
303 else GRAPH_DrawReliefRect( hDC
, &rc
, 2, 2, FALSE
);
305 /* draw button label, if any: */
306 text
= USER_HEAP_LIN_ADDR( wndPtr
->hText
);
309 SetTextColor( hDC
, (wndPtr
->dwStyle
& WS_DISABLED
) ?
310 GetSysColor(COLOR_GRAYTEXT
) : GetSysColor(COLOR_BTNTEXT
));
311 DrawText(hDC
, text
, -1, &rc
,
312 DT_SINGLELINE
| DT_CENTER
| DT_VCENTER
);
313 /* do we have the focus? */
314 if (infoPtr
->state
& BUTTON_HASFOCUS
)
316 short xdelta
, ydelta
;
317 dwTextSize
= GetTextExtent( hDC
, text
, strlen(text
) );
318 GetTextMetrics( hDC
, &tm
);
319 xdelta
= ((rc
.right
- rc
.left
) - LOWORD(dwTextSize
) - 1) / 2;
320 ydelta
= ((rc
.bottom
- rc
.top
) - tm
.tmHeight
- 1) / 2;
321 if (xdelta
< 0) xdelta
= 0;
322 if (ydelta
< 0) ydelta
= 0;
323 InflateRect( &rc
, -xdelta
, -ydelta
);
324 DrawFocusRect( hDC
, &rc
);
328 SelectObject(hDC
, (HANDLE
)hOldPen
);
329 SelectObject(hDC
, (HANDLE
)hOldBrush
);
333 /**********************************************************************
334 * Check Box & Radio Button Functions
337 static void CB_Paint( HWND hWnd
, HDC hDC
, WORD action
)
341 int textlen
, delta
, x
, y
;
345 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
346 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
348 GetClientRect(hWnd
, &rc
);
350 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
351 hBrush
= SendMessage(GetParent(hWnd
), WM_CTLCOLOR
, (WORD
)hDC
,
352 MAKELPARAM(hWnd
, CTLCOLOR_BTN
));
353 if (action
== ODA_DRAWENTIRE
) FillRect(hDC
, &rc
, hBrush
);
355 GetTextMetrics(hDC
, &tm
);
356 delta
= (rc
.bottom
- rc
.top
- tm
.tmHeight
) >> 1;
357 text
= USER_HEAP_LIN_ADDR( wndPtr
->hText
);
358 textlen
= strlen( text
);
360 /* Draw the check-box bitmap */
362 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) x
+= 2 * checkBoxWidth
;
363 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
)) x
+= checkBoxWidth
;
364 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
365 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
)) y
+= checkBoxHeight
;
366 else if (infoPtr
->state
& BUTTON_3STATE
) y
+= 2 * checkBoxHeight
;
367 GRAPH_DrawBitmap( hDC
, hbitmapCheckBoxes
, rc
.left
, rc
.top
+ delta
,
368 x
, y
, checkBoxWidth
, checkBoxHeight
);
369 rc
.left
+= checkBoxWidth
+ tm
.tmAveCharWidth
/ 2;
371 if (action
== ODA_DRAWENTIRE
)
373 if (wndPtr
->dwStyle
& WS_DISABLED
)
374 SetTextColor( hDC
, GetSysColor(COLOR_GRAYTEXT
) );
375 DrawText(hDC
, text
, textlen
, &rc
, DT_SINGLELINE
| DT_VCENTER
);
378 if ((action
== ODA_FOCUS
) ||
379 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
381 GetTextExtentPoint(hDC
, text
, textlen
, &size
);
385 rc
.bottom
-= delta
+ 1;
388 rc
.right
= min( rc
.left
+ size
.cx
+ 2, rc
.right
);
389 DrawFocusRect(hDC
, &rc
);
394 /**********************************************************************
395 * BUTTON_CheckAutoRadioButton
397 * hWnd is checked, uncheck everything else in group
399 static void BUTTON_CheckAutoRadioButton(HWND hWnd
)
401 HWND parent
= GetParent(hWnd
);
403 for(sibling
= GetNextDlgGroupItem(parent
,hWnd
,FALSE
);
405 sibling
= GetNextDlgGroupItem(parent
,sibling
,FALSE
))
406 SendMessage(sibling
,BM_SETCHECK
,BUTTON_UNCHECKED
,0);
410 /**********************************************************************
411 * Group Box Functions
414 static void GB_Paint( HWND hWnd
, HDC hDC
, WORD action
)
419 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
420 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
422 if (action
!= ODA_DRAWENTIRE
) return;
424 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
425 SendMessage( GetParent(hWnd
), WM_CTLCOLOR
, (WORD
)hDC
,
426 MAKELPARAM(hWnd
, CTLCOLOR_BTN
));
427 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
429 GetClientRect(hWnd
, &rc
);
431 MoveTo( hDC
, rc
.left
, rc
.top
+2 );
432 LineTo( hDC
, rc
.right
-1, rc
.top
+2 );
433 LineTo( hDC
, rc
.right
-1, rc
.bottom
-1 );
434 LineTo( hDC
, rc
.left
, rc
.bottom
-1 );
435 LineTo( hDC
, rc
.left
, rc
.top
+2 );
437 text
= USER_HEAP_LIN_ADDR( wndPtr
->hText
);
438 GetTextExtentPoint(hDC
, text
, strlen(text
), &size
);
440 rc
.right
= rc
.left
+ size
.cx
+ 1;
442 if (wndPtr
->dwStyle
& WS_DISABLED
)
443 SetTextColor( hDC
, GetSysColor(COLOR_GRAYTEXT
) );
444 DrawText(hDC
, text
, -1, &rc
, DT_SINGLELINE
);
448 /**********************************************************************
449 * User Button Functions
452 static void UB_Paint( HWND hWnd
, HDC hDC
, WORD action
)
456 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
457 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
459 if (action
== ODA_SELECT
) return;
461 GetClientRect(hWnd
, &rc
);
463 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
464 hBrush
= SendMessage(GetParent(hWnd
), WM_CTLCOLOR
, (WORD
)hDC
,
465 MAKELPARAM(hWnd
, CTLCOLOR_BTN
));
466 FillRect(hDC
, &rc
, hBrush
);
468 if ((action
== ODA_FOCUS
) ||
469 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
470 DrawFocusRect(hDC
, &rc
);
474 /**********************************************************************
475 * Ownerdrawn Button Functions
478 static void OB_Paint( HWND hWnd
, HDC hDC
, WORD action
)
481 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
482 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
484 dis
.CtlType
= ODT_BUTTON
;
485 dis
.CtlID
= wndPtr
->wIDmenu
;
487 dis
.itemAction
= action
;
488 dis
.itemState
= (infoPtr
->state
& BUTTON_HASFOCUS
) ? ODS_FOCUS
: 0 |
489 (infoPtr
->state
& BUTTON_HIGHLIGHTED
) ? ODS_SELECTED
: 0 |
490 (wndPtr
->dwStyle
& WS_DISABLED
) ? ODS_DISABLED
: 0;
493 GetClientRect( hWnd
, &dis
.rcItem
);
495 SendMessage(GetParent(hWnd
), WM_DRAWITEM
, 1, MAKE_SEGPTR(&dis
) );