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
14 #include "wine/winuser16.h"
17 static void PaintGrayOnGray( HDC hDC
,HFONT hFont
,RECT
*rc
,
18 LPCWSTR text
, UINT format
);
20 static void PB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
21 static void CB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
22 static void GB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
23 static void UB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
24 static void OB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
);
25 static void BUTTON_CheckAutoRadioButton( WND
*wndPtr
);
26 static void BUTTON_DrawPushButton( WND
*wndPtr
, HDC hDC
, WORD action
, BOOL pushedState
);
28 #define MAX_BTN_TYPE 12
30 static const WORD maxCheckState
[MAX_BTN_TYPE
] =
32 BUTTON_UNCHECKED
, /* BS_PUSHBUTTON */
33 BUTTON_UNCHECKED
, /* BS_DEFPUSHBUTTON */
34 BUTTON_CHECKED
, /* BS_CHECKBOX */
35 BUTTON_CHECKED
, /* BS_AUTOCHECKBOX */
36 BUTTON_CHECKED
, /* BS_RADIOBUTTON */
37 BUTTON_3STATE
, /* BS_3STATE */
38 BUTTON_3STATE
, /* BS_AUTO3STATE */
39 BUTTON_UNCHECKED
, /* BS_GROUPBOX */
40 BUTTON_UNCHECKED
, /* BS_USERBUTTON */
41 BUTTON_CHECKED
, /* BS_AUTORADIOBUTTON */
42 BUTTON_UNCHECKED
, /* Not defined */
43 BUTTON_UNCHECKED
/* BS_OWNERDRAW */
46 typedef void (*pfPaint
)( WND
*wndPtr
, HDC hdc
, WORD action
);
48 static const pfPaint btnPaintFunc
[MAX_BTN_TYPE
] =
50 PB_Paint
, /* BS_PUSHBUTTON */
51 PB_Paint
, /* BS_DEFPUSHBUTTON */
52 CB_Paint
, /* BS_CHECKBOX */
53 CB_Paint
, /* BS_AUTOCHECKBOX */
54 CB_Paint
, /* BS_RADIOBUTTON */
55 CB_Paint
, /* BS_3STATE */
56 CB_Paint
, /* BS_AUTO3STATE */
57 GB_Paint
, /* BS_GROUPBOX */
58 UB_Paint
, /* BS_USERBUTTON */
59 CB_Paint
, /* BS_AUTORADIOBUTTON */
60 NULL
, /* Not defined */
61 OB_Paint
/* BS_OWNERDRAW */
64 #define PAINT_BUTTON(wndPtr,style,action) \
65 if (btnPaintFunc[style]) { \
66 HDC hdc = GetDC( (wndPtr)->hwndSelf ); \
67 (btnPaintFunc[style])(wndPtr,hdc,action); \
68 ReleaseDC( (wndPtr)->hwndSelf, hdc ); }
70 #define BUTTON_SEND_CTLCOLOR(wndPtr,hdc) \
71 SendMessageA( GetParent((wndPtr)->hwndSelf), WM_CTLCOLORBTN, \
72 (hdc), (wndPtr)->hwndSelf )
74 static HBITMAP hbitmapCheckBoxes
= 0;
75 static WORD checkBoxWidth
= 0, checkBoxHeight
= 0;
78 /***********************************************************************
79 * ButtonWndProc_locked
81 * Called with window lock held.
83 static inline LRESULT WINAPI
ButtonWndProc_locked(WND
* wndPtr
, UINT uMsg
,
84 WPARAM wParam
, LPARAM lParam
)
87 HWND hWnd
= wndPtr
->hwndSelf
;
89 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
90 LONG style
= wndPtr
->dwStyle
& 0x0f;
93 pt
.x
= LOWORD(lParam
);
94 pt
.y
= HIWORD(lParam
);
101 case BS_PUSHBUTTON
: return DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
;
102 case BS_DEFPUSHBUTTON
: return DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
;
104 case BS_AUTORADIOBUTTON
: return DLGC_BUTTON
| DLGC_RADIOBUTTON
;
105 default: return DLGC_BUTTON
;
109 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
113 if (!hbitmapCheckBoxes
)
116 hbitmapCheckBoxes
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECKBOXES
));
117 GetObjectA( hbitmapCheckBoxes
, sizeof(bmp
), &bmp
);
118 checkBoxWidth
= bmp
.bmWidth
/ 4;
119 checkBoxHeight
= bmp
.bmHeight
/ 3;
121 if (style
< 0L || style
>= MAX_BTN_TYPE
)
122 return -1; /* abort */
123 infoPtr
->state
= BUTTON_UNCHECKED
;
132 if (btnPaintFunc
[style
])
135 HDC hdc
= wParam
? (HDC
)wParam
: BeginPaint( hWnd
, &ps
);
136 int nOldMode
= SetBkMode( hdc
, OPAQUE
);
137 (btnPaintFunc
[style
])( wndPtr
, hdc
, ODA_DRAWENTIRE
);
138 SetBkMode(hdc
, nOldMode
); /* reset painting mode */
139 if( !wParam
) EndPaint( hWnd
, &ps
);
144 if (wParam
== VK_SPACE
)
146 SendMessageA( hWnd
, BM_SETSTATE
, TRUE
, 0 );
147 infoPtr
->state
|= BUTTON_BTNPRESSED
;
151 case WM_LBUTTONDBLCLK
:
152 if(wndPtr
->dwStyle
& BS_NOTIFY
||
153 style
==BS_RADIOBUTTON
||
154 style
==BS_USERBUTTON
||
155 style
==BS_OWNERDRAW
) {
156 SendMessageA( GetParent(hWnd
), WM_COMMAND
,
157 MAKEWPARAM( wndPtr
->wIDmenu
, BN_DOUBLECLICKED
), hWnd
);
164 SendMessageA( hWnd
, BM_SETSTATE
, TRUE
, 0 );
165 infoPtr
->state
|= BUTTON_BTNPRESSED
;
169 if (wParam
!= VK_SPACE
)
173 if (!(infoPtr
->state
& BUTTON_BTNPRESSED
)) break;
174 infoPtr
->state
&= BUTTON_NSTATES
;
175 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) {
179 SendMessageA( hWnd
, BM_SETSTATE
, FALSE
, 0 );
181 GetClientRect( hWnd
, &rect
);
182 if (uMsg
== WM_KEYUP
|| PtInRect( &rect
, pt
))
186 case BS_AUTOCHECKBOX
:
187 SendMessageA( hWnd
, BM_SETCHECK
,
188 !(infoPtr
->state
& BUTTON_CHECKED
), 0 );
190 case BS_AUTORADIOBUTTON
:
191 SendMessageA( hWnd
, BM_SETCHECK
, TRUE
, 0 );
194 SendMessageA( hWnd
, BM_SETCHECK
,
195 (infoPtr
->state
& BUTTON_3STATE
) ? 0 :
196 ((infoPtr
->state
& 3) + 1), 0 );
199 SendMessageA( GetParent(hWnd
), WM_COMMAND
,
200 MAKEWPARAM( wndPtr
->wIDmenu
, BN_CLICKED
), hWnd
);
204 case WM_CAPTURECHANGED
:
205 if (infoPtr
->state
& BUTTON_BTNPRESSED
) {
206 infoPtr
->state
&= BUTTON_NSTATES
;
207 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
)
208 SendMessageA( hWnd
, BM_SETSTATE
, FALSE
, 0 );
213 if (GetCapture() == hWnd
)
215 GetClientRect( hWnd
, &rect
);
216 SendMessageA( hWnd
, BM_SETSTATE
, PtInRect(&rect
, pt
), 0 );
221 if(style
== BS_GROUPBOX
) return HTTRANSPARENT
;
222 return DefWindowProcA( hWnd
, uMsg
, wParam
, lParam
);
225 DEFWND_SetTextA( wndPtr
, (LPCSTR
)lParam
);
226 if( wndPtr
->dwStyle
& WS_VISIBLE
)
227 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
231 infoPtr
->hFont
= (HFONT16
)wParam
;
232 if (lParam
&& (wndPtr
->dwStyle
& WS_VISIBLE
))
233 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
237 return infoPtr
->hFont
;
240 if ((style
== BS_RADIOBUTTON
|| style
== BS_AUTORADIOBUTTON
) && (GetCapture() != hWnd
) &&
241 !(SendMessageA(hWnd
, BM_GETCHECK
, 0, 0) & BST_CHECKED
))
243 /* The notification is sent when the button (BS_AUTORADIOBUTTON)
244 is unckecked and the focus was not given by a mouse click. */
245 if (style
== BS_AUTORADIOBUTTON
)
246 SendMessageA( hWnd
, BM_SETCHECK
, BUTTON_CHECKED
, 0 );
247 SendMessageA( GetParent(hWnd
), WM_COMMAND
,
248 MAKEWPARAM( wndPtr
->wIDmenu
, BN_CLICKED
), hWnd
);
250 infoPtr
->state
|= BUTTON_HASFOCUS
;
251 PAINT_BUTTON( wndPtr
, style
, ODA_FOCUS
);
255 infoPtr
->state
&= ~BUTTON_HASFOCUS
;
256 PAINT_BUTTON( wndPtr
, style
, ODA_FOCUS
);
257 InvalidateRect( hWnd
, NULL
, TRUE
);
260 case WM_SYSCOLORCHANGE
:
261 InvalidateRect( hWnd
, NULL
, FALSE
);
266 if ((wParam
& 0x0f) >= MAX_BTN_TYPE
) break;
267 wndPtr
->dwStyle
= (wndPtr
->dwStyle
& 0xfffffff0)
268 | (wParam
& 0x0000000f);
269 style
= wndPtr
->dwStyle
& 0x0000000f;
271 /* Only redraw if lParam flag is set.*/
273 PAINT_BUTTON( wndPtr
, style
, ODA_DRAWENTIRE
);
278 SendMessageA( hWnd
, WM_LBUTTONDOWN
, 0, 0 );
279 SendMessageA( hWnd
, WM_LBUTTONUP
, 0, 0 );
283 oldHbitmap
= infoPtr
->hImage
;
284 if ((wndPtr
->dwStyle
& BS_BITMAP
) || (wndPtr
->dwStyle
& BS_ICON
))
286 infoPtr
->hImage
= (HANDLE
) lParam
;
287 InvalidateRect( hWnd
, NULL
, FALSE
);
292 if (wParam
== IMAGE_BITMAP
)
293 return (HBITMAP
)infoPtr
->hImage
;
294 else if (wParam
== IMAGE_ICON
)
295 return (HICON
)infoPtr
->hImage
;
301 return infoPtr
->state
& 3;
305 if (wParam
> maxCheckState
[style
]) wParam
= maxCheckState
[style
];
306 if ((infoPtr
->state
& 3) != wParam
)
308 if ((style
== BS_RADIOBUTTON
) || (style
== BS_AUTORADIOBUTTON
))
311 wndPtr
->dwStyle
|= WS_TABSTOP
;
313 wndPtr
->dwStyle
&= ~WS_TABSTOP
;
315 infoPtr
->state
= (infoPtr
->state
& ~3) | wParam
;
316 PAINT_BUTTON( wndPtr
, style
, ODA_SELECT
);
318 if ((style
== BS_AUTORADIOBUTTON
) && (wParam
== BUTTON_CHECKED
))
319 BUTTON_CheckAutoRadioButton( wndPtr
);
324 return infoPtr
->state
;
330 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) break;
331 infoPtr
->state
|= BUTTON_HIGHLIGHTED
;
335 if (!(infoPtr
->state
& BUTTON_HIGHLIGHTED
)) break;
336 infoPtr
->state
&= ~BUTTON_HIGHLIGHTED
;
338 PAINT_BUTTON( wndPtr
, style
, ODA_SELECT
);
342 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
347 /***********************************************************************
349 * The button window procedure. This is just a wrapper which locks
350 * the passed HWND and calls the real window procedure (with a WND*
351 * pointer pointing to the locked windowstructure).
353 LRESULT WINAPI
ButtonWndProc( HWND hWnd
, UINT uMsg
,
354 WPARAM wParam
, LPARAM lParam
)
357 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
359 res
= ButtonWndProc_locked(wndPtr
,uMsg
,wParam
,lParam
);
361 WIN_ReleaseWndPtr(wndPtr
);
365 /**********************************************************************
366 * Push Button Functions
368 static void PB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
370 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
371 BOOL bHighLighted
= (infoPtr
->state
& BUTTON_HIGHLIGHTED
);
374 * Delegate this to the more generic pushbutton painting
377 BUTTON_DrawPushButton(wndPtr
,
383 /**********************************************************************
384 * This method will actually do the drawing of the pushbutton
385 * depending on it's state and the pushedState parameter.
387 static void BUTTON_DrawPushButton(
396 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
397 int xBorderOffset
, yBorderOffset
;
398 xBorderOffset
= yBorderOffset
= 0;
400 GetClientRect( wndPtr
->hwndSelf
, &rc
);
402 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
403 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
404 BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
405 hOldPen
= (HPEN
)SelectObject(hDC
, GetSysColorPen(COLOR_WINDOWFRAME
));
406 hOldBrush
=(HBRUSH
)SelectObject(hDC
,GetSysColorBrush(COLOR_BTNFACE
));
407 SetBkMode(hDC
, TRANSPARENT
);
409 if ( TWEAK_WineLook
== WIN31_LOOK
)
411 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
413 SetPixel( hDC
, rc
.left
, rc
.top
, GetSysColor(COLOR_WINDOW
) );
414 SetPixel( hDC
, rc
.left
, rc
.bottom
-1, GetSysColor(COLOR_WINDOW
) );
415 SetPixel( hDC
, rc
.right
-1, rc
.top
, GetSysColor(COLOR_WINDOW
) );
416 SetPixel( hDC
, rc
.right
-1, rc
.bottom
-1, GetSysColor(COLOR_WINDOW
));
417 InflateRect( &rc
, -1, -1 );
420 if ((wndPtr
->dwStyle
& 0x000f) == BS_DEFPUSHBUTTON
)
422 Rectangle(hDC
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
423 InflateRect( &rc
, -1, -1 );
426 if (TWEAK_WineLook
== WIN31_LOOK
)
430 /* draw button shadow: */
431 SelectObject(hDC
, GetSysColorBrush(COLOR_BTNSHADOW
));
432 PatBlt(hDC
, rc
.left
, rc
.top
, 1, rc
.bottom
-rc
.top
, PATCOPY
);
433 PatBlt(hDC
, rc
.left
, rc
.top
, rc
.right
-rc
.left
, 1, PATCOPY
);
434 rc
.left
+= 2; /* To position the text down and right */
437 rc
.right
++, rc
.bottom
++;
438 DrawEdge( hDC
, &rc
, EDGE_RAISED
, BF_RECT
);
440 /* To place de bitmap correctly */
441 xBorderOffset
+= GetSystemMetrics(SM_CXEDGE
);
442 yBorderOffset
+= GetSystemMetrics(SM_CYEDGE
);
444 rc
.right
--, rc
.bottom
--;
449 UINT uState
= DFCS_BUTTONPUSH
;
453 if ( (wndPtr
->dwStyle
& 0x000f) == BS_DEFPUSHBUTTON
)
456 uState
|= DFCS_PUSHED
;
459 DrawFrameControl( hDC
, &rc
, DFC_BUTTON
, uState
);
460 InflateRect( &rc
, -2, -2 );
466 rc
.left
+= 2; /* To position the text down and right */
471 /* draw button label, if any:
473 * In win9x we don't show text if there is a bitmap or icon.
474 * I don't know about win31 so I leave it as it was for win31.
475 * Dennis Björklund 12 Jul, 99
477 if ( wndPtr
->text
&& wndPtr
->text
[0]
478 && (TWEAK_WineLook
== WIN31_LOOK
|| !(wndPtr
->dwStyle
& (BS_ICON
|BS_BITMAP
))) )
481 GetObjectA( GetSysColorBrush(COLOR_BTNFACE
), sizeof(lb
), &lb
);
482 if (wndPtr
->dwStyle
& WS_DISABLED
&&
483 GetSysColor(COLOR_GRAYTEXT
)==lb
.lbColor
)
484 /* don't write gray text on gray background */
485 PaintGrayOnGray( hDC
,infoPtr
->hFont
,&rc
,wndPtr
->text
,
486 DT_CENTER
| DT_VCENTER
);
489 SetTextColor( hDC
, (wndPtr
->dwStyle
& WS_DISABLED
) ?
490 GetSysColor(COLOR_GRAYTEXT
) :
491 GetSysColor(COLOR_BTNTEXT
) );
492 DrawTextW( hDC
, wndPtr
->text
, -1, &rc
,
493 DT_SINGLELINE
| DT_CENTER
| DT_VCENTER
);
494 /* do we have the focus?
495 * Win9x draws focus last with a size prop. to the button
497 if (TWEAK_WineLook
== WIN31_LOOK
498 && infoPtr
->state
& BUTTON_HASFOCUS
)
500 RECT r
= { 0, 0, 0, 0 };
503 DrawTextW( hDC
, wndPtr
->text
, -1, &r
,
504 DT_SINGLELINE
| DT_CALCRECT
);
505 xdelta
= ((rc
.right
- rc
.left
) - (r
.right
- r
.left
) - 1) / 2;
506 ydelta
= ((rc
.bottom
- rc
.top
) - (r
.bottom
- r
.top
) - 1) / 2;
507 if (xdelta
< 0) xdelta
= 0;
508 if (ydelta
< 0) ydelta
= 0;
509 InflateRect( &rc
, -xdelta
, -ydelta
);
510 DrawFocusRect( hDC
, &rc
);
514 if ( ((wndPtr
->dwStyle
& BS_ICON
) || (wndPtr
->dwStyle
& BS_BITMAP
) ) &&
515 (infoPtr
->hImage
!= 0) )
517 int yOffset
, xOffset
;
518 int imageWidth
, imageHeight
;
521 * We extract the size of the image from the handle.
523 if (wndPtr
->dwStyle
& BS_ICON
)
528 GetIconInfo((HICON
)infoPtr
->hImage
, &iconInfo
);
529 GetObjectA (iconInfo
.hbmColor
, sizeof(BITMAP
), &bm
);
531 imageWidth
= bm
.bmWidth
;
532 imageHeight
= bm
.bmHeight
;
534 DeleteObject(iconInfo
.hbmColor
);
535 DeleteObject(iconInfo
.hbmMask
);
542 GetObjectA (infoPtr
->hImage
, sizeof(BITMAP
), &bm
);
544 imageWidth
= bm
.bmWidth
;
545 imageHeight
= bm
.bmHeight
;
548 /* Center the bitmap */
549 xOffset
= (((rc
.right
- rc
.left
) - 2*xBorderOffset
) - imageWidth
) / 2;
550 yOffset
= (((rc
.bottom
- rc
.top
) - 2*yBorderOffset
) - imageHeight
) / 2;
552 /* If the image is too big for the button then create a region*/
553 if(xOffset
< 0 || yOffset
< 0)
556 hBitmapRgn
= CreateRectRgn(
557 rc
.left
+ xBorderOffset
, rc
.top
+yBorderOffset
,
558 rc
.right
- xBorderOffset
, rc
.bottom
- yBorderOffset
);
559 SelectClipRgn(hDC
, hBitmapRgn
);
560 DeleteObject(hBitmapRgn
);
563 /* Let minimum 1 space from border */
564 xOffset
++, yOffset
++;
567 * Draw the image now.
569 if (wndPtr
->dwStyle
& BS_ICON
)
572 rc
.left
+ xOffset
, rc
.top
+ yOffset
,
573 (HICON
)infoPtr
->hImage
);
579 hdcMem
= CreateCompatibleDC (hDC
);
580 SelectObject (hdcMem
, (HBITMAP
)infoPtr
->hImage
);
584 imageWidth
, imageHeight
,
585 hdcMem
, 0, 0, SRCCOPY
);
590 if(xOffset
< 0 || yOffset
< 0)
592 SelectClipRgn(hDC
, 0);
596 if (TWEAK_WineLook
!= WIN31_LOOK
597 && infoPtr
->state
& BUTTON_HASFOCUS
)
599 InflateRect( &focus_rect
, -1, -1 );
600 DrawFocusRect( hDC
, &focus_rect
);
604 SelectObject( hDC
, hOldPen
);
605 SelectObject( hDC
, hOldBrush
);
609 /**********************************************************************
610 * PB_Paint & CB_Paint sub function [internal]
611 * Paint text using a raster brush to avoid gray text on gray
612 * background. 'format' can be a combination of DT_CENTER and
613 * DT_VCENTER to use this function in both PB_PAINT and
614 * CB_PAINT. - Dirk Thierbach
616 * FIXME: This and TEXT_GrayString should be eventually combined,
617 * so calling one common function from PB_Paint, CB_Paint and
618 * TEXT_GrayString will be enough. Also note that this
619 * function ignores the CACHE_GetPattern funcs.
622 void PaintGrayOnGray(HDC hDC
, HFONT hFont
, RECT
*rc
, LPCWSTR text
,
625 /* This is the standard gray on gray pattern:
626 static const WORD Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55};
628 /* This pattern gives better readability with X Fonts.
629 FIXME: Maybe the user should be allowed to decide which he wants. */
630 static const WORD Pattern
[] = {0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF};
632 HBITMAP hbm
= CreateBitmap( 8, 8, 1, 1, Pattern
);
633 HDC hdcMem
= CreateCompatibleDC(hDC
);
639 DrawTextW( hDC
, text
, -1, &rect
, DT_SINGLELINE
| DT_CALCRECT
);
640 /* now text width and height are in rect.right and rect.bottom */
642 rect
.left
= rect
.top
= 0; /* drawing pos in hdcMem */
643 if (format
& DT_CENTER
) rect
.left
=(rc
->right
-rect
.right
)/2;
644 if (format
& DT_VCENTER
) rect
.top
=(rc
->bottom
-rect
.bottom
)/2;
645 hbmMem
= CreateCompatibleBitmap( hDC
,rect
.right
,rect
.bottom
);
646 SelectObject( hdcMem
, hbmMem
);
647 PatBlt( hdcMem
,0,0,rect
.right
,rect
.bottom
,WHITENESS
);
648 /* will be overwritten by DrawText, but just in case */
649 if (hFont
) SelectObject( hdcMem
, hFont
);
650 DrawTextW( hdcMem
, text
, -1, &rc2
, DT_SINGLELINE
);
651 /* After draw: foreground = 0 bits, background = 1 bits */
652 hBr
= SelectObject( hdcMem
, CreatePatternBrush(hbm
) );
654 PatBlt( hdcMem
,0,0,rect
.right
,rect
.bottom
,0xAF0229);
655 /* only keep the foreground bits where pattern is 1 */
656 DeleteObject( SelectObject( hdcMem
,hBr
) );
657 BitBlt(hDC
,rect
.left
,rect
.top
,rect
.right
,rect
.bottom
,hdcMem
,0,0,SRCAND
);
658 /* keep the background of the dest */
660 DeleteObject( hbmMem
);
664 /**********************************************************************
665 * Check Box & Radio Button Functions
668 static void CB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
670 RECT rbox
, rtext
, client
;
673 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
676 * if the button has a bitmap/icon, draw a normal pushbutton
677 * instead of a radion button.
679 if (infoPtr
->hImage
!= 0)
681 BOOL bHighLighted
= ((infoPtr
->state
& BUTTON_HIGHLIGHTED
) ||
682 (infoPtr
->state
& BUTTON_CHECKED
));
684 BUTTON_DrawPushButton(wndPtr
,
692 GetClientRect(wndPtr
->hwndSelf
, &client
);
693 rbox
= rtext
= client
;
695 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
697 /* Something is still not right, checkboxes (and edit controls)
698 * in wsping32 have white backgrounds instead of dark grey.
699 * BUTTON_SEND_CTLCOLOR() is even worse since it returns 0 in this
700 * particular case and the background is not painted at all.
703 hBrush
= GetControlBrush16( wndPtr
->hwndSelf
, hDC
, CTLCOLOR_BTN
);
705 if (wndPtr
->dwStyle
& BS_LEFTTEXT
)
707 /* magic +4 is what CTL3D expects */
709 rtext
.right
-= checkBoxWidth
+ 4;
710 rbox
.left
= rbox
.right
- checkBoxWidth
;
714 rtext
.left
+= checkBoxWidth
+ 4;
715 rbox
.right
= checkBoxWidth
;
718 /* Draw the check-box bitmap */
720 if (wndPtr
->text
) textlen
= lstrlenW( wndPtr
->text
);
721 if (action
== ODA_DRAWENTIRE
|| action
== ODA_SELECT
)
723 if( TWEAK_WineLook
== WIN31_LOOK
)
725 HDC hMemDC
= CreateCompatibleDC( hDC
);
727 delta
= (rbox
.bottom
- rbox
.top
- checkBoxHeight
) / 2;
729 /* Check in case the client area is smaller than the checkbox bitmap */
730 if (delta
< 0) delta
= 0;
732 if (action
== ODA_SELECT
) FillRect( hDC
, &rbox
, hBrush
);
733 else FillRect( hDC
, &client
, hBrush
);
735 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) x
+= 2 * checkBoxWidth
;
736 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
)) x
+= checkBoxWidth
;
737 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
738 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
)) y
+= checkBoxHeight
;
739 else if (infoPtr
->state
& BUTTON_3STATE
) y
+= 2 * checkBoxHeight
;
741 /* The bitmap for the radio button is not aligned with the
742 * left of the window, it is 1 pixel off. */
743 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
744 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
))
747 SelectObject( hMemDC
, hbitmapCheckBoxes
);
748 BitBlt( hDC
, rbox
.left
, rbox
.top
+ delta
, checkBoxWidth
,
749 checkBoxHeight
, hMemDC
, x
, y
, SRCCOPY
);
756 if (((wndPtr
->dwStyle
& 0x0f) == BS_RADIOBUTTON
) ||
757 ((wndPtr
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
)) state
= DFCS_BUTTONRADIO
;
758 else if (infoPtr
->state
& BUTTON_3STATE
) state
= DFCS_BUTTON3STATE
;
759 else state
= DFCS_BUTTONCHECK
;
761 if (infoPtr
->state
& (BUTTON_CHECKED
| BUTTON_3STATE
)) state
|= DFCS_CHECKED
;
763 if (infoPtr
->state
& BUTTON_HIGHLIGHTED
) state
|= DFCS_PUSHED
;
765 if (wndPtr
->dwStyle
& WS_DISABLED
) state
|= DFCS_INACTIVE
;
767 /* rbox must have the correct height */
768 delta
= rbox
.bottom
- rbox
.top
- checkBoxHeight
;
771 int ofs
= (abs(delta
) / 2);
772 rbox
.bottom
-= ofs
+ 1;
773 rbox
.top
= rbox
.bottom
- checkBoxHeight
;
777 int ofs
= (abs(delta
) / 2);
779 rbox
.bottom
= rbox
.top
+ checkBoxHeight
;
782 DrawFrameControl( hDC
, &rbox
, DFC_BUTTON
, state
);
785 if( textlen
&& action
!= ODA_SELECT
)
787 if (wndPtr
->dwStyle
& WS_DISABLED
&&
788 GetSysColor(COLOR_GRAYTEXT
)==GetBkColor(hDC
)) {
789 /* don't write gray text on gray background */
790 PaintGrayOnGray( hDC
, infoPtr
->hFont
, &rtext
, wndPtr
->text
,
793 if (wndPtr
->dwStyle
& WS_DISABLED
)
794 SetTextColor( hDC
, GetSysColor(COLOR_GRAYTEXT
) );
795 DrawTextW( hDC
, wndPtr
->text
, textlen
, &rtext
,
796 DT_SINGLELINE
| DT_VCENTER
);
801 if ((action
== ODA_FOCUS
) ||
802 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
804 /* again, this is what CTL3D expects */
808 DrawTextW( hDC
, wndPtr
->text
, textlen
, &rbox
,
809 DT_SINGLELINE
| DT_CALCRECT
);
810 textlen
= rbox
.bottom
- rbox
.top
;
811 delta
= ((rtext
.bottom
- rtext
.top
) - textlen
)/2;
812 rbox
.bottom
= (rbox
.top
= rtext
.top
+ delta
- 1) + textlen
+ 2;
813 textlen
= rbox
.right
- rbox
.left
;
814 rbox
.right
= (rbox
.left
+= --rtext
.left
) + textlen
+ 2;
815 IntersectRect(&rbox
, &rbox
, &rtext
);
816 DrawFocusRect( hDC
, &rbox
);
821 /**********************************************************************
822 * BUTTON_CheckAutoRadioButton
824 * wndPtr is checked, uncheck every other auto radio button in group
826 static void BUTTON_CheckAutoRadioButton( WND
*wndPtr
)
828 HWND parent
, sibling
, start
;
829 if (!(wndPtr
->dwStyle
& WS_CHILD
)) return;
830 parent
= wndPtr
->parent
->hwndSelf
;
831 /* assure that starting control is not disabled or invisible */
832 start
= sibling
= GetNextDlgGroupItem( parent
, wndPtr
->hwndSelf
, TRUE
);
837 tmpWnd
= WIN_FindWndPtr(sibling
);
838 if ((wndPtr
->hwndSelf
!= sibling
) &&
839 ((tmpWnd
->dwStyle
& 0x0f) == BS_AUTORADIOBUTTON
))
840 SendMessageA( sibling
, BM_SETCHECK
, BUTTON_UNCHECKED
, 0 );
841 sibling
= GetNextDlgGroupItem( parent
, sibling
, FALSE
);
842 WIN_ReleaseWndPtr(tmpWnd
);
843 } while (sibling
!= start
);
847 /**********************************************************************
848 * Group Box Functions
851 static void GB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
854 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
856 if (action
!= ODA_DRAWENTIRE
) return;
858 BUTTON_SEND_CTLCOLOR( wndPtr
, hDC
);
860 GetClientRect( wndPtr
->hwndSelf
, &rc
);
861 if (TWEAK_WineLook
== WIN31_LOOK
) {
862 HPEN hPrevPen
= SelectObject( hDC
,
863 GetSysColorPen(COLOR_WINDOWFRAME
));
864 HBRUSH hPrevBrush
= SelectObject( hDC
,
865 GetStockObject(NULL_BRUSH
) );
867 Rectangle( hDC
, rc
.left
, rc
.top
+ 2, rc
.right
- 1, rc
.bottom
- 1 );
868 SelectObject( hDC
, hPrevBrush
);
869 SelectObject( hDC
, hPrevPen
);
875 SelectObject (hDC
, infoPtr
->hFont
);
876 GetTextMetricsA (hDC
, &tm
);
877 rcFrame
.top
+= (tm
.tmHeight
/ 2) - 1;
878 DrawEdge (hDC
, &rcFrame
, EDGE_ETCHED
, BF_RECT
);
883 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
884 if (wndPtr
->dwStyle
& WS_DISABLED
)
885 SetTextColor( hDC
, GetSysColor(COLOR_GRAYTEXT
) );
887 DrawTextW( hDC
, wndPtr
->text
, -1, &rc
, DT_SINGLELINE
| DT_NOCLIP
);
892 /**********************************************************************
893 * User Button Functions
896 static void UB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
900 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
902 if (action
== ODA_SELECT
) return;
904 GetClientRect( wndPtr
->hwndSelf
, &rc
);
906 if (infoPtr
->hFont
) SelectObject( hDC
, infoPtr
->hFont
);
907 hBrush
= GetControlBrush16( wndPtr
->hwndSelf
, hDC
, CTLCOLOR_BTN
);
909 FillRect( hDC
, &rc
, hBrush
);
910 if ((action
== ODA_FOCUS
) ||
911 ((action
== ODA_DRAWENTIRE
) && (infoPtr
->state
& BUTTON_HASFOCUS
)))
912 DrawFocusRect( hDC
, &rc
);
916 /**********************************************************************
917 * Ownerdrawn Button Functions
920 static void OB_Paint( WND
*wndPtr
, HDC hDC
, WORD action
)
922 BUTTONINFO
*infoPtr
= (BUTTONINFO
*)wndPtr
->wExtra
;
927 dis
.CtlType
= ODT_BUTTON
;
928 dis
.CtlID
= wndPtr
->wIDmenu
;
930 dis
.itemAction
= action
;
931 dis
.itemState
= ((infoPtr
->state
& BUTTON_HASFOCUS
) ? ODS_FOCUS
: 0) |
932 ((infoPtr
->state
& BUTTON_HIGHLIGHTED
) ? ODS_SELECTED
: 0) |
933 ((wndPtr
->dwStyle
& WS_DISABLED
) ? ODS_DISABLED
: 0);
934 dis
.hwndItem
= wndPtr
->hwndSelf
;
937 GetClientRect( wndPtr
->hwndSelf
, &dis
.rcItem
);
939 clipRegion
= CreateRectRgnIndirect(&dis
.rcItem
);
940 if (GetClipRgn(hDC
, clipRegion
) != 1)
942 DeleteObject(clipRegion
);
943 clipRegion
=(HRGN
)NULL
;
945 clipRect
= dis
.rcItem
;
946 DPtoLP(hDC
, (LPPOINT
) &clipRect
, 2);
947 IntersectClipRect(hDC
, clipRect
.left
, clipRect
.top
, clipRect
.right
, clipRect
.bottom
);
949 SetBkColor( hDC
, GetSysColor( COLOR_BTNFACE
) );
951 SendMessageA( GetParent(wndPtr
->hwndSelf
), WM_DRAWITEM
,
952 wndPtr
->wIDmenu
, (LPARAM
)&dis
);
954 SelectClipRgn(hDC
, clipRegion
);