Release 961222
[wine/multimedia.git] / controls / button.c
blobb9bbe052bf6b047c3fc4e15342d5f35dafc260a0
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
6 */
8 #include "win.h"
9 #include "syscolor.h"
10 #include "graphics.h"
11 #include "button.h"
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 /***********************************************************************
72 * ButtonWndProc
74 LRESULT ButtonWndProc(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
76 RECT16 rect;
77 WND *wndPtr = WIN_FindWndPtr(hWnd);
78 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
79 LONG style = wndPtr->dwStyle & 0x0f;
81 switch (uMsg)
83 case WM_GETDLGCODE:
84 switch(style)
86 case BS_PUSHBUTTON: return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
87 case BS_DEFPUSHBUTTON: return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
88 case BS_RADIOBUTTON:
89 case BS_AUTORADIOBUTTON: return DLGC_BUTTON | DLGC_RADIOBUTTON;
90 default: return DLGC_BUTTON;
93 case WM_ENABLE:
94 PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
95 break;
97 case WM_CREATE:
98 if (!hbitmapCheckBoxes)
100 BITMAP16 bmp;
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;
108 infoPtr->hFont = 0;
109 return 0;
111 case WM_ERASEBKGND:
112 break;
114 case WM_PAINT:
115 if (btnPaintFunc[style])
117 PAINTSTRUCT32 ps;
118 HDC32 hdc = BeginPaint32( hWnd, &ps );
119 (btnPaintFunc[style])( wndPtr, hdc, ODA_DRAWENTIRE );
120 EndPaint32( hWnd, &ps );
122 break;
124 case WM_LBUTTONDOWN:
125 SendMessage32A( hWnd, BM_SETSTATE32, TRUE, 0 );
126 SetFocus32( hWnd );
127 SetCapture32( hWnd );
128 break;
130 case WM_LBUTTONUP:
131 ReleaseCapture();
132 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
133 SendMessage32A( hWnd, BM_SETSTATE32, FALSE, 0 );
134 GetClientRect16( hWnd, &rect );
135 if (PtInRect16( &rect, MAKEPOINT16(lParam) ))
137 switch(style)
139 case BS_AUTOCHECKBOX:
140 SendMessage32A( hWnd, BM_SETCHECK32,
141 !(infoPtr->state & BUTTON_CHECKED), 0 );
142 break;
143 case BS_AUTORADIOBUTTON:
144 SendMessage32A( hWnd, BM_SETCHECK32, TRUE, 0 );
145 break;
146 case BS_AUTO3STATE:
147 SendMessage32A( hWnd, BM_SETCHECK32,
148 (infoPtr->state & BUTTON_3STATE) ? 0 :
149 ((infoPtr->state & 3) + 1), 0 );
150 break;
152 SendMessage32A( GetParent32(hWnd), WM_COMMAND,
153 MAKEWPARAM( wndPtr->wIDmenu, BN_CLICKED ), hWnd);
155 break;
157 case WM_MOUSEMOVE:
158 if (GetCapture32() == hWnd)
160 GetClientRect16( hWnd, &rect );
161 SendMessage32A( hWnd, BM_SETSTATE32,
162 PtInRect16( &rect,MAKEPOINT16(lParam) ), 0 );
164 break;
166 case WM_NCHITTEST:
167 if(style == BS_GROUPBOX) return HTTRANSPARENT;
168 return DefWindowProc32A( hWnd, uMsg, wParam, lParam );
170 case WM_SETTEXT:
171 DEFWND_SetText( wndPtr, (LPSTR)lParam );
172 PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
173 return 0;
175 case WM_SETFONT:
176 infoPtr->hFont = (HFONT16)wParam;
177 if (lParam) PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
178 break;
180 case WM_GETFONT:
181 return infoPtr->hFont;
183 case WM_SETFOCUS:
184 infoPtr->state |= BUTTON_HASFOCUS;
185 PAINT_BUTTON( wndPtr, style, ODA_FOCUS );
186 break;
188 case WM_KILLFOCUS:
189 infoPtr->state &= ~BUTTON_HASFOCUS;
190 PAINT_BUTTON( wndPtr, style, ODA_FOCUS );
191 InvalidateRect16( hWnd, NULL, TRUE );
192 break;
194 case WM_SYSCOLORCHANGE:
195 InvalidateRect32( hWnd, NULL, FALSE );
196 break;
198 case BM_SETSTYLE16:
199 case BM_SETSTYLE32:
200 if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
201 wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
202 | (wParam & 0x0000000f);
203 style = wndPtr->dwStyle & 0x0000000f;
204 PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
205 break;
207 case BM_GETCHECK16:
208 case BM_GETCHECK32:
209 return infoPtr->state & 3;
211 case BM_SETCHECK16:
212 case BM_SETCHECK32:
213 if (wParam > maxCheckState[style]) wParam = maxCheckState[style];
214 if ((infoPtr->state & 3) != wParam)
216 infoPtr->state = (infoPtr->state & ~3) | wParam;
217 PAINT_BUTTON( wndPtr, style, ODA_SELECT );
219 if ((style == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED))
220 BUTTON_CheckAutoRadioButton( wndPtr );
221 break;
223 case BM_GETSTATE16:
224 case BM_GETSTATE32:
225 return infoPtr->state;
227 case BM_SETSTATE16:
228 case BM_SETSTATE32:
229 if (wParam)
231 if (infoPtr->state & BUTTON_HIGHLIGHTED) break;
232 infoPtr->state |= BUTTON_HIGHLIGHTED;
234 else
236 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
237 infoPtr->state &= ~BUTTON_HIGHLIGHTED;
239 PAINT_BUTTON( wndPtr, style, ODA_SELECT );
240 break;
242 default:
243 return DefWindowProc32A(hWnd, uMsg, wParam, lParam);
245 return 0;
249 /**********************************************************************
250 * Push Button Functions
253 static void PB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
255 RECT32 rc;
256 HPEN32 hOldPen;
257 HBRUSH32 hOldBrush;
258 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
260 GetClientRect32( wndPtr->hwndSelf, &rc );
262 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
263 if (infoPtr->hFont) SelectObject32( hDC, infoPtr->hFont );
264 BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
265 hOldPen = (HPEN32)SelectObject32(hDC, sysColorObjects.hpenWindowFrame);
266 hOldBrush = (HBRUSH32)SelectObject32(hDC, sysColorObjects.hbrushBtnFace);
267 SetBkMode32(hDC, TRANSPARENT);
268 Rectangle32(hDC, rc.left, rc.top, rc.right, rc.bottom);
269 if (action == ODA_DRAWENTIRE)
271 SetPixel32( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
272 SetPixel32( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
273 SetPixel32( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
274 SetPixel32( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
276 InflateRect32( &rc, -1, -1 );
278 if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
280 Rectangle32(hDC, rc.left, rc.top, rc.right, rc.bottom);
281 InflateRect32( &rc, -1, -1 );
284 if (infoPtr->state & BUTTON_HIGHLIGHTED)
286 /* draw button shadow: */
287 SelectObject32(hDC, sysColorObjects.hbrushBtnShadow );
288 PatBlt32(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
289 PatBlt32(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
290 rc.left += 2; /* To position the text down and right */
291 rc.top += 2;
293 else GRAPH_DrawReliefRect( hDC, &rc, 2, 2, FALSE );
295 /* draw button label, if any: */
296 if (wndPtr->text && wndPtr->text[0])
298 LOGBRUSH16 lb;
299 GetObject16( sysColorObjects.hbrushBtnFace, sizeof(lb), &lb );
300 if (wndPtr->dwStyle & WS_DISABLED &&
301 GetSysColor(COLOR_GRAYTEXT)==lb.lbColor)
302 /* don't write gray text on gray bkg */
303 PB_PaintGrayOnGray(hDC,infoPtr->hFont,&rc,wndPtr->text);
304 else
306 SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
307 GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNTEXT));
308 DrawText32A( hDC, wndPtr->text, -1, &rc,
309 DT_SINGLELINE | DT_CENTER | DT_VCENTER );
310 /* do we have the focus? */
311 if (infoPtr->state & BUTTON_HASFOCUS)
313 RECT32 r = { 0, 0, 0, 0 };
314 INT32 xdelta, ydelta;
316 DrawText32A( hDC, wndPtr->text, -1, &r,
317 DT_SINGLELINE | DT_CALCRECT );
318 xdelta = ((rc.right - rc.left) - (r.right - r.left) - 1) / 2;
319 ydelta = ((rc.bottom - rc.top) - (r.bottom - r.top) - 1) / 2;
320 if (xdelta < 0) xdelta = 0;
321 if (ydelta < 0) ydelta = 0;
322 InflateRect32( &rc, -xdelta, -ydelta );
323 DrawFocusRect32( hDC, &rc );
328 SelectObject32( hDC, hOldPen );
329 SelectObject32( hDC, hOldBrush );
333 /**********************************************************************
334 * Push Button sub function [internal]
335 * using a raster brush to avoid gray text on gray background
338 void PB_PaintGrayOnGray(HDC32 hDC,HFONT32 hFont,RECT32 *rc,char *text)
340 static int Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55};
341 HBITMAP16 hbm = CreateBitmap(8, 8, 1, 1, Pattern);
342 HDC32 hdcMem = CreateCompatibleDC32(hDC);
343 HBITMAP16 hbmMem;
344 HBRUSH16 hBr;
345 RECT32 rect,rc2;
347 rect=*rc;
348 DrawText32A( hDC, text, -1, &rect, DT_SINGLELINE | DT_CALCRECT);
349 rc2=rect;
350 rect.left=(rc->right-rect.right)/2; /* for centering text bitmap */
351 rect.top=(rc->bottom-rect.bottom)/2;
352 hbmMem = CreateCompatibleBitmap( hDC,rect.right,rect.bottom);
353 SelectObject32( hdcMem, hbmMem);
354 hBr = SelectObject32( hdcMem, CreatePatternBrush32(hbm) );
355 DeleteObject32( hbm );
356 PatBlt32( hdcMem,0,0,rect.right,rect.bottom,WHITENESS);
357 if (hFont) SelectObject32( hdcMem, hFont);
358 DrawText32A( hdcMem, text, -1, &rc2, DT_SINGLELINE);
359 PatBlt32( hdcMem,0,0,rect.right,rect.bottom,0xFA0089);
360 DeleteObject32( SelectObject32( hdcMem,hBr) );
361 BitBlt32(hDC,rect.left,rect.top,rect.right,rect.bottom,hdcMem,0,0,0x990000);
362 DeleteDC32( hdcMem);
363 DeleteObject32( hbmMem );
367 /**********************************************************************
368 * Check Box & Radio Button Functions
371 static void CB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
373 RECT16 rbox, rtext, client;
374 HBRUSH16 hBrush;
375 int textlen, delta;
376 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
378 textlen = 0;
379 GetClientRect16(wndPtr->hwndSelf, &client);
380 rbox = rtext = client;
382 if (infoPtr->hFont) SelectObject32( hDC, infoPtr->hFont );
383 hBrush = BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
384 if (wndPtr->dwStyle & BS_LEFTTEXT)
386 /* magic +4 is what CTL3D expects */
388 rtext.right -= checkBoxWidth + 4;
389 rbox.left = rbox.right - checkBoxWidth;
391 else
393 rtext.left += checkBoxWidth + 4;
394 rbox.right = checkBoxWidth;
397 /* Draw the check-box bitmap */
399 if (wndPtr->text) textlen = strlen( wndPtr->text );
400 if (action == ODA_DRAWENTIRE || action == ODA_SELECT)
402 int x = 0, y = 0;
403 delta = (rbox.bottom - rbox.top - checkBoxHeight) >> 1;
405 if (action == ODA_SELECT) FillRect16( hDC, &rbox, hBrush );
406 else FillRect16( hDC, &client, hBrush );
408 if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
409 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
410 if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
411 ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
412 else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
414 GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rbox.left, rbox.top + delta,
415 x, y, checkBoxWidth, checkBoxHeight );
416 if( textlen && action != ODA_SELECT )
418 if (wndPtr->dwStyle & WS_DISABLED)
419 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
420 DrawText16( hDC, wndPtr->text, textlen, &rtext,
421 DT_SINGLELINE | DT_VCENTER );
425 if ((action == ODA_FOCUS) ||
426 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
428 /* again, this is what CTL3D expects */
430 SetRectEmpty16(&rbox);
431 if( textlen )
432 DrawText16( hDC, wndPtr->text, textlen, &rbox,
433 DT_SINGLELINE | DT_CALCRECT );
434 textlen = rbox.bottom - rbox.top;
435 delta = ((rtext.bottom - rtext.top) - textlen)/2;
436 rbox.bottom = (rbox.top = rtext.top + delta - 1) + textlen + 2;
437 textlen = rbox.right - rbox.left;
438 rbox.right = (rbox.left += --rtext.left) + textlen + 2;
439 IntersectRect16(&rbox, &rbox, &rtext);
440 DrawFocusRect16( hDC, &rbox );
445 /**********************************************************************
446 * BUTTON_CheckAutoRadioButton
448 * wndPtr is checked, uncheck every other auto radio button in group
450 static void BUTTON_CheckAutoRadioButton( WND *wndPtr )
452 HWND32 parent, sibling;
453 if (!(wndPtr->dwStyle & WS_CHILD)) return;
454 parent = wndPtr->parent->hwndSelf;
455 for(sibling = GetNextDlgGroupItem32( parent, wndPtr->hwndSelf, FALSE );
456 sibling != wndPtr->hwndSelf && sibling != 0;
457 sibling = GetNextDlgGroupItem32( parent, sibling, FALSE ))
458 if((WIN_FindWndPtr(sibling)->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)
459 SendMessage32A( sibling, BM_SETCHECK32, BUTTON_UNCHECKED, 0 );
463 /**********************************************************************
464 * Group Box Functions
467 static void GB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
469 RECT16 rc;
470 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
472 if (action != ODA_DRAWENTIRE) return;
474 if (infoPtr->hFont) SelectObject32( hDC, infoPtr->hFont );
475 BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
476 SelectObject32( hDC, sysColorObjects.hpenWindowFrame );
478 GetClientRect16( wndPtr->hwndSelf, &rc);
480 MoveTo( hDC, rc.left, rc.top+2 );
481 LineTo32( hDC, rc.right-1, rc.top+2 );
482 LineTo32( hDC, rc.right-1, rc.bottom-1 );
483 LineTo32( hDC, rc.left, rc.bottom-1 );
484 LineTo32( hDC, rc.left, rc.top+2 );
486 if (!wndPtr->text) return;
487 if (wndPtr->dwStyle & WS_DISABLED)
488 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
489 rc.left += 10;
490 DrawText16( hDC, wndPtr->text, -1, &rc, DT_SINGLELINE | DT_NOCLIP );
494 /**********************************************************************
495 * User Button Functions
498 static void UB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
500 RECT16 rc;
501 HBRUSH16 hBrush;
502 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
504 if (action == ODA_SELECT) return;
506 GetClientRect16( wndPtr->hwndSelf, &rc);
508 if (infoPtr->hFont) SelectObject32( hDC, infoPtr->hFont );
509 hBrush = BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
510 FillRect16( hDC, &rc, hBrush );
512 if ((action == ODA_FOCUS) ||
513 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
514 DrawFocusRect16( hDC, &rc );
518 /**********************************************************************
519 * Ownerdrawn Button Functions
522 static void OB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
524 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
525 DRAWITEMSTRUCT32 dis;
527 dis.CtlType = ODT_BUTTON;
528 dis.CtlID = wndPtr->wIDmenu;
529 dis.itemID = 0;
530 dis.itemAction = action;
531 dis.itemState = ((infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) |
532 ((infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) |
533 ((wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0);
534 dis.hwndItem = wndPtr->hwndSelf;
535 dis.hDC = hDC;
536 dis.itemData = 0;
537 GetClientRect32( wndPtr->hwndSelf, &dis.rcItem );
538 SendMessage32A( GetParent32(wndPtr->hwndSelf), WM_DRAWITEM,
539 wndPtr->wIDmenu, (LPARAM)&dis );