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
9 #include <stdlib.h> /* for abs() */
15 #include "wine/winuser16.h"
18 static void PB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
19 static void CB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
20 static void GB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
21 static void UB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
22 static void OB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
23 static void BUTTON_CheckAutoRadioButton( WND
*wndPtr
);
24 static void BUTTON_DrawPushButton( WND
*wndPtr
, HDC hDC
, WORD action
, BOOL pushedState
);
26 #define MAX_BTN_TYPE 12
28 static const WORD maxCheckState
[MAX_BTN_TYPE
] =
30 BUTTON_UNCHECKED
, /* BS_PUSHBUTTON */
31 BUTTON_UNCHECKED
, /* BS_DEFPUSHBUTTON */
32 BUTTON_CHECKED
, /* BS_CHECKBOX */
33 BUTTON_CHECKED
, /* BS_AUTOCHECKBOX */
34 BUTTON_CHECKED
, /* BS_RADIOBUTTON */
35 BUTTON_3STATE
, /* BS_3STATE */
36 BUTTON_3STATE
, /* BS_AUTO3STATE */
37 BUTTON_UNCHECKED
, /* BS_GROUPBOX */
38 BUTTON_UNCHECKED
, /* BS_USERBUTTON */
39 BUTTON_CHECKED
, /* BS_AUTORADIOBUTTON */
40 BUTTON_UNCHECKED
, /* Not defined */
41 BUTTON_UNCHECKED
/* BS_OWNERDRAW */
44 typedef void (*pfPaint
)( WND
*wndPtr
, HDC hdc
, WORD action
);
46 static const pfPaint btnPaintFunc
[MAX_BTN_TYPE
] =
48 PB_Paint
, /* BS_PUSHBUTTON */
49 PB_Paint
, /* BS_DEFPUSHBUTTON */
50 CB_Paint
, /* BS_CHECKBOX */
51 CB_Paint
, /* BS_AUTOCHECKBOX */
52 CB_Paint
, /* BS_RADIOBUTTON */
53 CB_Paint
, /* BS_3STATE */
54 CB_Paint
, /* BS_AUTO3STATE */
55 GB_Paint
, /* BS_GROUPBOX */
56 UB_Paint
, /* BS_USERBUTTON */
57 CB_Paint
, /* BS_AUTORADIOBUTTON */
58 NULL
, /* Not defined */
59 OB_Paint
/* BS_OWNERDRAW */
62 #define PAINT_BUTTON(wndPtr,style,action) \
63 if (btnPaintFunc[style]) { \
64 HDC hdc = GetDC( (wndPtr)->hwndSelf ); \
65 (btnPaintFunc[style])(wndPtr,hdc,action); \
66 ReleaseDC( (wndPtr)->hwndSelf, hdc ); }
68 #define BUTTON_SEND_CTLCOLOR(wndPtr,hdc) \
69 SendMessageW( GetParent((wndPtr)->hwndSelf), WM_CTLCOLORBTN, \
70 (hdc), (wndPtr)->hwndSelf )
72 static HBITMAP hbitmapCheckBoxes
= 0;
73 static WORD checkBoxWidth
= 0, checkBoxHeight
= 0;
76 /***********************************************************************
77 * ButtonWndProc_locked
79 * Called with window lock held.
81 static inline LRESULT WINAPI
ButtonWndProc_locked(WND
* wndPtr
, UINT uMsg
,
82 WPARAM wParam
, LPARAM lParam
)
85 HWND hWnd
= wndPtr
->hwndSelf
;
87 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
88 LONG style
= wndPtr
->dwStyle
& 0x0f;
91 pt
.x
= LOWORD(lParam
);
92 pt
.y
= HIWORD(lParam
);
99 case BS_PUSHBUTTON
: return DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
;
100 case BS_DEFPUSHBUTTON
: return DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
;
102 case BS_AUTORADIOBUTTON
: return DLGC_BUTTON
| DLGC_RADIOBUTTON
;
103 default: return DLGC_BUTTON
;
107 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
111 if (!hbitmapCheckBoxes
)
114 hbitmapCheckBoxes
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CHECKBOXES
));
115 GetObjectW( hbitmapCheckBoxes
, sizeof(bmp
), &bmp
);
116 checkBoxWidth
= bmp
.bmWidth
/ 4;
117 checkBoxHeight
= bmp
.bmHeight
/ 3;
119 if (style
< 0L || style
>= MAX_BTN_TYPE
)
120 return -1; /* abort */
121 infoPtr
->state
= BUTTON_UNCHECKED
;
130 if (btnPaintFunc
[style
])
133 HDC hdc
= wParam
? (HDC
)wParam
: BeginPaint( hWnd
, &ps
);
134 int nOldMode
= SetBkMode( hdc
, OPAQUE
);
135 (btnPaintFunc
[style
])( wndPtr
, hdc
, ODA_DRAWENTIRE
);
136 SetBkMode(hdc
, nOldMode
); /* reset painting mode */
137 if( !wParam
) EndPaint( hWnd
, &ps
);
142 if (wParam
== VK_SPACE
)
144 SendMessageW( hWnd
, BM_SETSTATE
, TRUE
, 0 );
145 infoPtr
->state
|= BUTTON_BTNPRESSED
;
149 case WM_LBUTTONDBLCLK
:
150 if(wndPtr
->dwStyle
& BS_NOTIFY
||
151 style
==BS_RADIOBUTTON
||
152 style
==BS_USERBUTTON
||
153 style
==BS_OWNERDRAW
) {
154 SendMessageW( GetParent(hWnd
), WM_COMMAND
,
155 MAKEWPARAM( wndPtr
->wIDmenu
, BN_DOUBLECLICKED
), hWnd
);
162 SendMessageW( hWnd
, BM_SETSTATE
, TRUE
, 0 );
163 infoPtr
->state
|= BUTTON_BTNPRESSED
;
167 if (wParam
!= VK_SPACE
)
171 if (!(infoPtr
->state
& BUTTON_BTNPRESSED
)) break;
172 infoPtr
->state
&= BUTTON_NSTATES
;
173 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) {
177 SendMessageW( hWnd
, BM_SETSTATE
, FALSE
, 0 );
179 GetClientRect( hWnd
, &rect
);
180 if (uMsg
== WM_KEYUP
|| PtInRect( &rect
, pt
))
184 case BS_AUTOCHECKBOX
:
185 SendMessageW( hWnd
, BM_SETCHECK
,
186 !(infoPtr
->state
& BUTTON_CHECKED
), 0 );
188 case BS_AUTORADIOBUTTON
:
189 SendMessageW( hWnd
, BM_SETCHECK
, TRUE
, 0 );
192 SendMessageW( hWnd
, BM_SETCHECK
,
193 (infoPtr
->state
& BUTTON_3STATE
) ? 0 :
194 ((infoPtr
->state
& 3) + 1), 0 );
197 SendMessageW( GetParent(hWnd
), WM_COMMAND
,
198 MAKEWPARAM( wndPtr
->wIDmenu
, BN_CLICKED
), hWnd
);
202 case WM_CAPTURECHANGED
:
203 if (infoPtr
->state
& BUTTON_BTNPRESSED
) {
204 infoPtr
->state
&= BUTTON_NSTATES
;
205 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
)
206 SendMessageW( hWnd
, BM_SETSTATE
, FALSE
, 0 );
211 if (GetCapture() == hWnd
)
213 GetClientRect( hWnd
, &rect
);
214 SendMessageW( hWnd
, BM_SETSTATE
, PtInRect(&rect
, pt
), 0 );
219 if(style
== BS_GROUPBOX
) return HTTRANSPARENT
;
220 return DefWindowProcW( hWnd
, uMsg
, wParam
, lParam
);
223 DEFWND_SetTextW( wndPtr
, (LPCWSTR
)lParam
);
224 if( wndPtr
->dwStyle
& WS_VISIBLE
)
225 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
226 return 1; /* success. FIXME: check text length */
229 infoPtr
->hFont
= (HFONT16
)wParam
;
230 if (lParam
&& (wndPtr
->dwStyle
& WS_VISIBLE
))
231 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
235 return infoPtr
->hFont
;
238 if ((style
== BS_RADIOBUTTON
|| style
== BS_AUTORADIOBUTTON
) && (GetCapture() != hWnd
) &&
239 !(SendMessageW(hWnd
, BM_GETCHECK
, 0, 0) & BST_CHECKED
))
241 /* The notification is sent when the button (BS_AUTORADIOBUTTON)
242 is unchecked and the focus was not given by a mouse click. */
243 if (style
== BS_AUTORADIOBUTTON
)
244 SendMessageW( hWnd
, BM_SETCHECK
, BUTTON_CHECKED
, 0 );
245 SendMessageW( GetParent(hWnd
), WM_COMMAND
,
246 MAKEWPARAM( wndPtr
->wIDmenu
, BN_CLICKED
), hWnd
);
248 infoPtr
->state
|= BUTTON_HASFOCUS
;
249 PAINT_BUTTON( wndPtr
, style
, ODA_FOCUS
);
253 infoPtr
->state
&= ~BUTTON_HASFOCUS
;
254 PAINT_BUTTON( wndPtr
, style
, ODA_FOCUS
);
255 InvalidateRect( hWnd
, NULL
, TRUE
);
258 case WM_SYSCOLORCHANGE
:
259 InvalidateRect( hWnd
, NULL
, FALSE
);
264 if ((wParam
& 0x0f) >= MAX_BTN_TYPE
) break;
265 wndPtr
->dwStyle
= (wndPtr
->dwStyle
& 0xfffffff0)
266 | (wParam
& 0x0000000f);
267 style
= wndPtr
->dwStyle
& 0x0000000f;
269 /* Only redraw if lParam flag is set.*/
271 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
276 SendMessageW( hWnd
, WM_LBUTTONDOWN
, 0, 0 );
277 SendMessageW( hWnd
, WM_LBUTTONUP
, 0, 0 );
281 /* Check that image format confirm button style */
282 if ((wndPtr
->dwStyle
& (BS_BITMAP
|BS_ICON
)) == BS_BITMAP
)
284 if (wParam
!= (WPARAM
) IMAGE_BITMAP
)
287 else if ((wndPtr
->dwStyle
& (BS_BITMAP
|BS_ICON
)) == BS_ICON
)
289 if (wParam
!= (WPARAM
) IMAGE_ICON
)
294 oldHbitmap
= infoPtr
->hImage
;
295 infoPtr
->hImage
= (HANDLE
) lParam
;
296 InvalidateRect( hWnd
, NULL
, FALSE
);
300 if ((wndPtr
->dwStyle
& (BS_BITMAP
|BS_ICON
)) == BS_BITMAP
)
302 if (wParam
!= (WPARAM
) IMAGE_BITMAP
)
305 else if ((wndPtr
->dwStyle
& (BS_BITMAP
|BS_ICON
)) == BS_ICON
)
307 if (wParam
!= (WPARAM
) IMAGE_ICON
)
311 return infoPtr
->hImage
;
315 return infoPtr
->state
& 3;
319 if (wParam
> maxCheckState
[style
]) wParam
= maxCheckState
[style
];
320 if ((infoPtr
->state
& 3) != wParam
)
322 if ((style
== BS_RADIOBUTTON
) || (style
== BS_AUTORADIOBUTTON
))
325 wndPtr
->dwStyle
|= WS_TABSTOP
;
327 wndPtr
->dwStyle
&= ~WS_TABSTOP
;
329 infoPtr
->state
= (infoPtr
->state
& ~3) | wParam
;
330 PAINT_BUTTON( wndPtr
, style
, ODA_SELECT
);
332 if ((style
== BS_AUTORADIOBUTTON
) && (wParam
== BUTTON_CHECKED
))
333 BUTTON_CheckAutoRadioButton( wndPtr
);
338 return infoPtr
->state
;
344 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) break;
345 infoPtr
->state
|= BUTTON_HIGHLIGHTED
;
349 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) break;
350 infoPtr
->state
&= ~BUTTON_HIGHLIGHTED
;
352 PAINT_BUTTON( wndPtr
, style
, ODA_SELECT
);
356 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
361 /***********************************************************************
363 * The button window procedure. This is just a wrapper which locks
364 * the passed HWND and calls the real window procedure (with a WND*
365 * pointer pointing to the locked windowstructure).
367 LRESULT WINAPI
ButtonWndProc( HWND hWnd
, UINT uMsg
,
368 WPARAM wParam
, LPARAM lParam
)
371 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
373 res
= ButtonWndProc_locked(wndPtr
,uMsg
,wParam
,lParam
);
375 WIN_ReleaseWndPtr(wndPtr
);
379 /**********************************************************************
380 * Push Button Functions
382 static void PB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
384 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
385 BOOL bHighLighted
= (infoPtr
->state
& BUTTON_HIGHLIGHTED
);
388 * Delegate this to the more generic pushbutton painting
391 BUTTON_DrawPushButton(wndPtr
,
397 /**********************************************************************
398 * Convert button styles to flags used by DrawText.
399 * TODO: handle WS_EX_RIGHT extended style.
401 static UINT
BUTTON_BStoDT(DWORD style
)
403 UINT dtStyle
= DT_NOCLIP
; /* We use SelectClipRgn to limit output */
405 /* "Convert" pushlike buttons to pushbuttons */
406 if (style
& BS_PUSHLIKE
)
409 if (!(style
& BS_MULTILINE
))
410 dtStyle
|= DT_SINGLELINE
;
412 dtStyle
|= DT_WORDBREAK
;
414 switch (style
& BS_CENTER
)
416 case BS_LEFT
: /* DT_LEFT is 0 */ break;
417 case BS_RIGHT
: dtStyle
|= DT_RIGHT
; break;
418 case BS_CENTER
: dtStyle
|= DT_CENTER
; break;
420 /* Pushbutton's text is centered by default */
421 if ((style
& 0x0F) <= BS_DEFPUSHBUTTON
)
422 dtStyle
|= DT_CENTER
;
423 /* all other flavours have left aligned text */
426 /* DrawText ignores vertical alignment for multiline text,
427 * but we use these flags to align label manualy.
429 if ((style
& 0x0F) != BS_GROUPBOX
)
431 switch (style
& BS_VCENTER
)
433 case BS_TOP
: /* DT_TOP is 0 */ break;
434 case BS_BOTTOM
: dtStyle
|= DT_BOTTOM
; break;
435 case BS_VCENTER
: /* fall through */
436 default: dtStyle
|= DT_VCENTER
; break;
440 /* GroupBox's text is always single line and is top aligned. */
441 dtStyle
|= DT_SINGLELINE
;
446 /**********************************************************************
447 * BUTTON_CalcLabelRect
449 * Calculates label's rectangle depending on button style.
451 * Returns flags to be passed to DrawText.
452 * Calculated rectangle doesn't take into account button state
453 * (pushed, etc.). If there is nothing to draw (no text/image) output
454 * rectangle is empty, and return value is (UINT)-1.
456 static UINT
BUTTON_CalcLabelRect(WND
*wndPtr
, HDC hdc
, RECT
*rc
)
458 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
461 UINT dtStyle
= BUTTON_BStoDT(wndPtr
->dwStyle
);
465 /* Calculate label rectangle according to label type */
466 switch (wndPtr
->dwStyle
& (BS_ICON
|BS_BITMAP
))
469 if (wndPtr
->text
&& wndPtr
->text
[0])
470 DrawTextW(hdc
, wndPtr
->text
, -1, &r
, dtStyle
| DT_CALCRECT
);
476 if (!GetIconInfo((HICON
)infoPtr
->hImage
, &iconInfo
))
479 GetObjectW (iconInfo
.hbmColor
, sizeof(BITMAP
), &bm
);
481 r
.right
= r
.left
+ bm
.bmWidth
;
482 r
.bottom
= r
.top
+ bm
.bmHeight
;
484 DeleteObject(iconInfo
.hbmColor
);
485 DeleteObject(iconInfo
.hbmMask
);
489 if (!GetObjectW (infoPtr
->hImage
, sizeof(BITMAP
), &bm
))
492 r
.right
= r
.left
+ bm
.bmWidth
;
493 r
.bottom
= r
.top
+ bm
.bmHeight
;
500 return (UINT
)(LONG
)-1;
503 /* Position label inside bounding rectangle according to
504 * alignment flags. (calculated rect is always left-top aligned).
505 * If label is aligned to any side - shift label in opposite
506 * direction to leave extra space for focus rectangle.
508 switch (dtStyle
& (DT_CENTER
|DT_RIGHT
))
510 case DT_LEFT
: r
.left
++; r
.right
++; break;
511 case DT_CENTER
: n
= r
.right
- r
.left
;
512 r
.left
= rc
->left
+ ((rc
->right
- rc
->left
) - n
) / 2;
513 r
.right
= r
.left
+ n
; break;
514 case DT_RIGHT
: n
= r
.right
- r
.left
;
515 r
.right
= rc
->right
- 1;
516 r
.left
= r
.right
- n
;
520 switch (dtStyle
& (DT_VCENTER
|DT_BOTTOM
))
522 case DT_TOP
: r
.top
++; r
.bottom
++; break;
523 case DT_VCENTER
: n
= r
.bottom
- r
.top
;
524 r
.top
= rc
->top
+ ((rc
->bottom
- rc
->top
) - n
) / 2;
525 r
.bottom
= r
.top
+ n
; break;
526 case DT_BOTTOM
: n
= r
.bottom
- r
.top
;
527 r
.bottom
= rc
->bottom
- 1;
528 r
.top
= r
.bottom
- n
;
537 /**********************************************************************
538 * BUTTON_DrawTextCallback
540 * Callback function used by DrawStateW function.
542 static BOOL CALLBACK
BUTTON_DrawTextCallback(HDC hdc
, LPARAM lp
, WPARAM wp
, int cx
, int cy
)
550 DrawTextW(hdc
, (LPCWSTR
)lp
, -1, &rc
, (UINT
)wp
);
555 /**********************************************************************
558 * Common function for drawing button label.
560 static void BUTTON_DrawLabel(WND
*wndPtr
, HDC hdc
, UINT dtFlags
, RECT
*rc
)
562 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
563 DRAWSTATEPROC lpOutputProc
= NULL
;
567 UINT flags
= IsWindowEnabled(wndPtr
->hwndSelf
) ? DSS_NORMAL
: DSS_DISABLED
;
569 /* Fixme: To draw disabled label in Win31 look-and-feel, we probably
570 * must use DSS_MONO flag and COLOR_GRAYTEXT brush (or maybe DSS_UNION).
571 * I don't have Win31 on hand to verify that, so I leave it as is.
574 if ((wndPtr
->dwStyle
& BS_PUSHLIKE
) && (infoPtr
->state
& BUTTON_3STATE
))
576 hbr
= GetSysColorBrush(COLOR_GRAYTEXT
);
580 switch (wndPtr
->dwStyle
& (BS_ICON
|BS_BITMAP
))
583 /* DST_COMPLEX -- is 0 */
584 lpOutputProc
= BUTTON_DrawTextCallback
;
585 lp
= (LPARAM
)wndPtr
->text
;
586 wp
= (WPARAM
)dtFlags
;
591 lp
= (LPARAM
)infoPtr
->hImage
;
596 lp
= (LPARAM
)infoPtr
->hImage
;
603 DrawStateW(hdc
, hbr
, lpOutputProc
, lp
, wp
, rc
->left
, rc
->top
,
604 rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, flags
);
607 /**********************************************************************
608 * This method will actually do the drawing of the pushbutton
609 * depending on it's state and the pushedState parameter.
611 static void BUTTON_DrawPushButton(
617 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
618 RECT rc
, focus_rect
, r
;
624 COLORREF oldTxtColor
;
626 GetClientRect( wndPtr
->hwndSelf
, &rc
);
628 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
629 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
630 BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
631 hOldPen
= (HPEN
)SelectObject(hDC
, GetSysColorPen(COLOR_WINDOWFRAME
));
632 hOldBrush
=(HBRUSH
)SelectObject(hDC
,GetSysColorBrush(COLOR_BTNFACE
));
633 oldBkMode
= SetBkMode(hDC
, TRANSPARENT
);
635 if ( TWEAK_WineLook
== WIN31_LOOK
)
637 COLORREF clr_wnd
= GetSysColor(COLOR_WINDOW
);
638 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
640 SetPixel( hDC
, rc
.left
, rc
.top
, clr_wnd
);
641 SetPixel( hDC
, rc
.left
, rc
.bottom
-1, clr_wnd
);
642 SetPixel( hDC
, rc
.right
-1, rc
.top
, clr_wnd
);
643 SetPixel( hDC
, rc
.right
-1, rc
.bottom
-1, clr_wnd
);
644 InflateRect( &rc
, -1, -1 );
647 if ((wndPtr
->dwStyle
& 0x000f) == BS_DEFPUSHBUTTON
)
649 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
650 InflateRect( &rc
, -1, -1 );
653 if (TWEAK_WineLook
== WIN31_LOOK
)
657 /* draw button shadow: */
658 SelectObject(hDC
, GetSysColorBrush(COLOR_BTNSHADOW
));
659 PatBlt(hDC
, rc
.left
, rc
.top
, 1, rc
.bottom
-rc
.top
, PATCOPY
);
660 PatBlt(hDC
, rc
.left
, rc
.top
, rc
.right
-rc
.left
, 1, PATCOPY
);
662 rc
.right
++, rc
.bottom
++;
663 DrawEdge( hDC
, &rc
, EDGE_RAISED
, BF_RECT
);
664 rc
.right
--, rc
.bottom
--;
669 UINT uState
= DFCS_BUTTONPUSH
| DFCS_ADJUSTRECT
;
671 if (wndPtr
->dwStyle
& BS_FLAT
)
673 else if (pushedState
)
675 if ( (wndPtr
->dwStyle
& 0x000f) == BS_DEFPUSHBUTTON
)
678 uState
|= DFCS_PUSHED
;
681 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
))
682 uState
|= DFCS_CHECKED
;
684 DrawFrameControl( hDC
, &rc
, DFC_BUTTON
, uState
);
689 /* draw button label */
691 dtFlags
= BUTTON_CalcLabelRect(wndPtr
, hDC
, &r
);
693 if (dtFlags
== (UINT
)-1L)
697 OffsetRect(&r
, 1, 1);
699 if(TWEAK_WineLook
== WIN31_LOOK
)
702 InflateRect(&focus_rect
, 2, 0);
705 hRgn
= CreateRectRgn(rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
706 SelectClipRgn(hDC
, hRgn
);
708 oldTxtColor
= SetTextColor( hDC
, GetSysColor(COLOR_BTNTEXT
) );
710 BUTTON_DrawLabel(wndPtr
, hDC
, dtFlags
, &r
);
712 SetTextColor( hDC
, oldTxtColor
);
713 SelectClipRgn(hDC
, 0);
716 if (infoPtr
->state
& BUTTON_HASFOCUS
)
718 InflateRect( &focus_rect
, -1, -1 );
719 IntersectRect(&focus_rect
, &focus_rect
, &rc
);
720 DrawFocusRect( hDC
, &focus_rect
);
724 SelectObject( hDC
, hOldPen
);
725 SelectObject( hDC
, hOldBrush
);
726 SetBkMode(hDC
, oldBkMode
);
729 /**********************************************************************
730 * Check Box & Radio Button Functions
733 static void CB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
735 RECT rbox
, rtext
, client
;
738 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
742 if (wndPtr
->dwStyle
& BS_PUSHLIKE
)
744 BOOL bHighLighted
= (infoPtr
->state
& BUTTON_HIGHLIGHTED
);
746 BUTTON_DrawPushButton(wndPtr
,
753 GetClientRect(wndPtr
->hwndSelf
, &client
);
754 rbox
= rtext
= client
;
756 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
758 /* GetControlBrush16 sends WM_CTLCOLORBTN, plus it returns default brush
759 * if parent didn't return valid one. So we kill two hares at once
761 hBrush
= GetControlBrush16( wndPtr
->hwndSelf
, hDC
, CTLCOLOR_BTN
);
763 if (wndPtr
->dwStyle
& BS_LEFTTEXT
)
765 /* magic +4 is what CTL3D expects */
767 rtext
.right
-= checkBoxWidth
+ 4;
768 rbox
.left
= rbox
.right
- checkBoxWidth
;
772 rtext
.left
+= checkBoxWidth
+ 4;
773 rbox
.right
= checkBoxWidth
;
776 /* Draw the check-box bitmap */
777 if (action
== ODA_DRAWENTIRE
|| action
== ODA_SELECT
)
779 if( TWEAK_WineLook
== WIN31_LOOK
)
781 HDC hMemDC
= CreateCompatibleDC( hDC
);
783 delta
= (rbox
.bottom
- rbox
.top
- checkBoxHeight
) / 2;
785 /* Check in case the client area is smaller than the checkbox bitmap */
786 if (delta
< 0) delta
= 0;
788 if (action
== ODA_SELECT
) FillRect( hDC
, &rbox
, hBrush
);
789 else FillRect( hDC
, &client
, hBrush
);
791 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) x
+= 2 * checkBoxWidth
;
792 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
)) x
+= checkBoxWidth
;
793 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
794 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
)) y
+= checkBoxHeight
;
795 else if (infoPtr
->state
& BUTTON_3STATE
) y
+= 2 * checkBoxHeight
;
797 /* The bitmap for the radio button is not aligned with the
798 * left of the window, it is 1 pixel off. */
799 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
800 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
))
803 SelectObject( hMemDC
, hbitmapCheckBoxes
);
804 BitBlt( hDC
, rbox
.left
, rbox
.top
+ delta
, checkBoxWidth
,
805 checkBoxHeight
, hMemDC
, x
, y
, SRCCOPY
);
812 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
813 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
)) state
= DFCS_BUTTONRADIO
;
814 else if (infoPtr
->state
& BUTTON_3STATE
) state
= DFCS_BUTTON3STATE
;
815 else state
= DFCS_BUTTONCHECK
;
817 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
)) state
|= DFCS_CHECKED
;
819 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) state
|= DFCS_PUSHED
;
821 if (wndPtr
->dwStyle
& WS_DISABLED
) state
|= DFCS_INACTIVE
;
823 /* rbox must have the correct height */
824 delta
= rbox
.bottom
- rbox
.top
- checkBoxHeight
;
827 int ofs
= (abs(delta
) / 2);
828 rbox
.bottom
-= ofs
+ 1;
829 rbox
.top
= rbox
.bottom
- checkBoxHeight
;
833 int ofs
= (abs(delta
) / 2);
835 rbox
.bottom
= rbox
.top
+ checkBoxHeight
;
838 DrawFrameControl( hDC
, &rbox
, DFC_BUTTON
, state
);
844 dtFlags
= BUTTON_CalcLabelRect(wndPtr
, hDC
, &rtext
);
846 if (dtFlags
== (UINT
)-1L) /* Noting to draw */
848 hRgn
= CreateRectRgn(client
.left
, client
.top
, client
.right
, client
.bottom
);
849 SelectClipRgn(hDC
, hRgn
);
852 if (action
== ODA_DRAWENTIRE
)
853 BUTTON_DrawLabel(wndPtr
, hDC
, dtFlags
, &rtext
);
856 if ((action
== ODA_FOCUS
) ||
857 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
861 IntersectRect(&rtext
, &rtext
, &client
);
862 DrawFocusRect( hDC
, &rtext
);
864 SelectClipRgn(hDC
, 0);
868 /**********************************************************************
869 * BUTTON_CheckAutoRadioButton
871 * wndPtr is checked, uncheck every other auto radio button in group
873 static void BUTTON_CheckAutoRadioButton( WND
*wndPtr
)
875 HWND parent
, sibling
, start
;
876 if (!(wndPtr
->dwStyle
& WS_CHILD
)) return;
877 parent
= wndPtr
->parent
->hwndSelf
;
878 /* assure that starting control is not disabled or invisible */
879 start
= sibling
= GetNextDlgGroupItem( parent
, wndPtr
->hwndSelf
, TRUE
);
884 tmpWnd
= WIN_FindWndPtr(sibling
);
885 if ((wndPtr
->hwndSelf
!= sibling
) &&
886 ((tmpWnd
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
))
887 SendMessageW( sibling
, BM_SETCHECK
, BUTTON_UNCHECKED
, 0 );
888 sibling
= GetNextDlgGroupItem( parent
, sibling
, FALSE
);
889 WIN_ReleaseWndPtr(tmpWnd
);
890 } while (sibling
!= start
);
894 /**********************************************************************
895 * Group Box Functions
898 static void GB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
901 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
905 if (action
!= ODA_DRAWENTIRE
) return;
908 SelectObject (hDC
, infoPtr
->hFont
);
909 /* GroupBox acts like static control, so it sends CTLCOLORSTATIC */
910 hbr
= GetControlBrush16( wndPtr
->hwndSelf
, hDC
, CTLCOLOR_STATIC
);
913 GetClientRect( wndPtr
->hwndSelf
, &rc
);
914 if (TWEAK_WineLook
== WIN31_LOOK
) {
915 HPEN hPrevPen
= SelectObject( hDC
,
916 GetSysColorPen(COLOR_WINDOWFRAME
));
917 HBRUSH hPrevBrush
= SelectObject( hDC
,
918 GetStockObject(NULL_BRUSH
) );
920 Rectangle( hDC
, rc
.left
, rc
.top
+ 2, rc
.right
- 1, rc
.bottom
- 1 );
921 SelectObject( hDC
, hPrevBrush
);
922 SelectObject( hDC
, hPrevPen
);
927 GetTextMetricsW (hDC
, &tm
);
928 rcFrame
.top
+= (tm
.tmHeight
/ 2) - 1;
929 DrawEdge (hDC
, &rcFrame
, EDGE_ETCHED
, BF_RECT
|
930 ((wndPtr
->dwStyle
& BS_FLAT
) ? BF_FLAT
: 0));
933 InflateRect(&rc
, -7, 1);
934 dtFlags
= BUTTON_CalcLabelRect(wndPtr
, hDC
, &rc
);
936 if (dtFlags
== (UINT
)-1L)
939 /* Because buttons have CS_PARENTDC class style, there is a chance
940 * that label will be drawn out of client rect.
941 * But Windows doesn't clip label's rect, so do I.
944 /* There is 1-pixel marging at the left, right, and bottom */
945 rc
.left
--; rc
.right
++; rc
.bottom
++;
946 FillRect(hDC
, &rc
, hbr
);
947 rc
.left
++; rc
.right
--; rc
.bottom
--;
949 BUTTON_DrawLabel(wndPtr
, hDC
, dtFlags
, &rc
);
953 /**********************************************************************
954 * User Button Functions
957 static void UB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
961 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
963 if (action
== ODA_SELECT
) return;
965 GetClientRect( wndPtr
->hwndSelf
, &rc
);
967 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
968 hBrush
= GetControlBrush16( wndPtr
->hwndSelf
, hDC
, CTLCOLOR_BTN
);
970 FillRect( hDC
, &rc
, hBrush
);
971 if ((action
== ODA_FOCUS
) ||
972 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
973 DrawFocusRect( hDC
, &rc
);
977 /**********************************************************************
978 * Ownerdrawn Button Functions
981 static void OB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
983 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
988 dis
.CtlType
= ODT_BUTTON
;
989 dis
.CtlID
= wndPtr
->wIDmenu
;
991 dis
.itemAction
= action
;
992 dis
.itemState
= ((infoPtr
->state
& BUTTON_HASFOCUS
) ? ODS_FOCUS
: 0) |
993 ((infoPtr
->state
& BUTTON_HIGHLIGHTED
) ? ODS_SELECTED
: 0) |
994 (IsWindowEnabled(wndPtr
->hwndSelf
) ? 0: ODS_DISABLED
);
995 dis
.hwndItem
= wndPtr
->hwndSelf
;
998 GetClientRect( wndPtr
->hwndSelf
, &dis
.rcItem
);
1000 clipRegion
= CreateRectRgnIndirect(&dis
.rcItem
);
1001 if (GetClipRgn(hDC
, clipRegion
) != 1)
1003 DeleteObject(clipRegion
);
1004 clipRegion
=(HRGN
)NULL
;
1006 clipRect
= dis
.rcItem
;
1007 DPtoLP(hDC
, (LPPOINT
) &clipRect
, 2);
1008 IntersectClipRect(hDC
, clipRect
.left
, clipRect
.top
, clipRect
.right
, clipRect
.bottom
);
1010 SetBkColor( hDC
, GetSysColor( COLOR_BTNFACE
) );
1012 SendMessageW( GetParent(wndPtr
->hwndSelf
), WM_DRAWITEM
,
1013 wndPtr
->wIDmenu
, (LPARAM
)&dis
);
1015 SelectClipRgn(hDC
, clipRegion
);