Release 960314
[wine/multimedia.git] / controls / button.c
blob9310643e656fb48784d5df0f96a30d6ac7bc9757
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 "user.h"
10 #include "syscolor.h"
11 #include "graphics.h"
12 #include "button.h"
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 LRESULT ButtonWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
73 RECT rect;
74 POINT pt;
75 LONG lResult = 0;
76 WND *wndPtr = WIN_FindWndPtr(hWnd);
77 LONG style = wndPtr->dwStyle & 0x0000000F;
78 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
80 switch (uMsg) {
81 case WM_GETDLGCODE:
82 switch(style)
84 case BS_PUSHBUTTON:
85 return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
86 case BS_DEFPUSHBUTTON:
87 return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
88 case BS_RADIOBUTTON:
89 case BS_AUTORADIOBUTTON:
90 return DLGC_BUTTON | DLGC_RADIOBUTTON;
91 default:
92 return DLGC_BUTTON;
95 case WM_ENABLE:
96 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
97 break;
99 case WM_CREATE:
100 if (!hbitmapCheckBoxes)
102 BITMAP bmp;
103 hbitmapCheckBoxes = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECKBOXES) );
104 GetObject( hbitmapCheckBoxes, sizeof(bmp), (LPSTR)&bmp );
105 checkBoxWidth = bmp.bmWidth / 4;
106 checkBoxHeight = bmp.bmHeight / 3;
109 if (style < 0L || style >= MAX_BTN_TYPE)
110 lResult = -1L;
111 else
113 infoPtr->state = BUTTON_UNCHECKED;
114 infoPtr->hFont = 0;
115 lResult = 0L;
117 break;
119 case WM_ERASEBKGND:
120 break;
122 case WM_PAINT:
123 if (btnPaintFunc[style])
125 PAINTSTRUCT ps;
126 HDC hdc = BeginPaint( hWnd, &ps );
127 (btnPaintFunc[style])( hWnd, hdc, ODA_DRAWENTIRE );
128 ReleaseDC( hWnd, hdc );
130 break;
132 case WM_LBUTTONDOWN:
133 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
134 SetFocus( hWnd );
135 SetCapture( hWnd );
136 break;
138 case WM_LBUTTONUP:
139 ReleaseCapture();
140 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
141 SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
142 GetClientRect( hWnd, &rect );
143 pt.x = LOWORD(lParam);
144 pt.y = HIWORD(lParam);
145 if (PtInRect( &rect, pt ))
147 switch(style)
149 case BS_AUTOCHECKBOX:
150 SendMessage( hWnd, BM_SETCHECK,
151 !(infoPtr->state & BUTTON_CHECKED), 0 );
152 break;
153 case BS_AUTORADIOBUTTON:
154 SendMessage( hWnd, BM_SETCHECK, TRUE, 0 );
155 break;
156 case BS_AUTO3STATE:
157 SendMessage( hWnd, BM_SETCHECK,
158 (infoPtr->state & BUTTON_3STATE) ? 0 :
159 ((infoPtr->state & 3) + 1), 0 );
160 break;
162 #ifdef WINELIB32
163 SendMessage( GetParent(hWnd), WM_COMMAND,
164 MAKEWPARAM(wndPtr->wIDmenu,BN_CLICKED),
165 (LPARAM) hWnd );
166 #else
167 SendMessage( GetParent(hWnd), WM_COMMAND,
168 wndPtr->wIDmenu, MAKELPARAM(hWnd,BN_CLICKED));
169 #endif
171 break;
173 case WM_MOUSEMOVE:
174 if (GetCapture() == hWnd)
176 GetClientRect( hWnd, &rect );
177 pt.x = LOWORD(lParam);
178 pt.y = HIWORD(lParam);
179 if (PtInRect( &rect, pt) )
180 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
181 else SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
183 break;
185 case WM_NCHITTEST:
186 if(style == BS_GROUPBOX) return HTTRANSPARENT;
187 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
188 break;
190 case WM_SETTEXT:
191 DEFWND_SetText( hWnd, (LPSTR)PTR_SEG_TO_LIN(lParam) );
192 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
193 return 0;
195 case WM_SETFONT:
196 infoPtr->hFont = (HFONT) wParam;
197 if (lParam)
198 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
199 break;
201 case WM_GETFONT:
202 return (LONG) infoPtr->hFont;
204 case WM_SETFOCUS:
205 infoPtr->state |= BUTTON_HASFOCUS;
206 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
207 break;
209 case WM_KILLFOCUS:
210 infoPtr->state &= ~BUTTON_HASFOCUS;
211 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
212 break;
214 case WM_SYSCOLORCHANGE:
215 InvalidateRect(hWnd, NULL, FALSE);
216 break;
218 case BM_SETSTYLE:
219 if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
220 wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
221 | (wParam & 0x0000000f);
222 style = wndPtr->dwStyle & 0x0000000f;
223 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
224 break;
226 case BM_GETCHECK:
227 lResult = infoPtr->state & 3;
228 break;
230 case BM_SETCHECK:
231 if (wParam > maxCheckState[style])
232 wParam = maxCheckState[style];
233 if ((infoPtr->state & 3) != wParam)
235 infoPtr->state = (infoPtr->state & ~3) | wParam;
236 PAINT_BUTTON( hWnd, style, ODA_SELECT );
238 if(style == BS_AUTORADIOBUTTON && wParam==BUTTON_CHECKED)
239 BUTTON_CheckAutoRadioButton(hWnd);
240 break;
242 case BM_GETSTATE:
243 lResult = infoPtr->state;
244 break;
246 case BM_SETSTATE:
247 if (!wParam != !(infoPtr->state & BUTTON_HIGHLIGHTED))
249 if (wParam) infoPtr->state |= BUTTON_HIGHLIGHTED;
250 else infoPtr->state &= ~BUTTON_HIGHLIGHTED;
251 PAINT_BUTTON( hWnd, style, ODA_SELECT );
253 break;
255 default:
256 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
257 break;
260 return lResult;
264 /**********************************************************************
265 * Push Button Functions
268 static void PB_Paint( HWND hButton, HDC hDC, WORD action )
270 RECT rc;
271 HPEN hOldPen;
272 HBRUSH hOldBrush;
273 char *text;
274 DWORD dwTextSize;
275 TEXTMETRIC tm;
276 WND *wndPtr = WIN_FindWndPtr( hButton );
277 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
279 GetClientRect(hButton, &rc);
281 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
282 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
283 #ifdef WINELIB32
284 SendMessage( GetParent(hButton), WM_CTLCOLORBTN,
285 (WPARAM)hDC, (LPARAM)hButton );
286 #else
287 SendMessage( GetParent(hButton), WM_CTLCOLOR, (WORD)hDC,
288 MAKELPARAM(hButton, CTLCOLOR_BTN) );
289 #endif
290 hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
291 hOldBrush = (HBRUSH)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
292 SetBkMode(hDC, TRANSPARENT);
293 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
294 if (action == ODA_DRAWENTIRE)
296 SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
297 SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
298 SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
299 SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
301 InflateRect( &rc, -1, -1 );
303 if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
305 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
306 InflateRect( &rc, -1, -1 );
309 if (infoPtr->state & BUTTON_HIGHLIGHTED)
311 /* draw button shadow: */
312 SelectObject(hDC, sysColorObjects.hbrushBtnShadow );
313 PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
314 PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
315 rc.left += 2; /* To position the text down and right */
316 rc.top += 2;
318 else GRAPH_DrawReliefRect( hDC, &rc, 2, 2, FALSE );
320 /* draw button label, if any: */
321 text = (char*) USER_HEAP_LIN_ADDR( wndPtr->hText );
322 if (text && text[0])
324 SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
325 GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNTEXT));
326 DrawText(hDC, text, -1, &rc,
327 DT_SINGLELINE | DT_CENTER | DT_VCENTER);
328 /* do we have the focus? */
329 if (infoPtr->state & BUTTON_HASFOCUS)
331 short xdelta, ydelta;
332 dwTextSize = GetTextExtent( hDC, text, strlen(text) );
333 GetTextMetrics( hDC, &tm );
334 xdelta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) / 2;
335 ydelta = ((rc.bottom - rc.top) - tm.tmHeight - 1) / 2;
336 if (xdelta < 0) xdelta = 0;
337 if (ydelta < 0) ydelta = 0;
338 InflateRect( &rc, -xdelta, -ydelta );
339 DrawFocusRect( hDC, &rc );
343 SelectObject(hDC, (HANDLE)hOldPen);
344 SelectObject(hDC, (HANDLE)hOldBrush);
348 /**********************************************************************
349 * Check Box & Radio Button Functions
352 static void CB_Paint( HWND hWnd, HDC hDC, WORD action )
354 RECT rc;
355 HBRUSH hBrush;
356 int textlen, delta, x, y;
357 char *text;
358 TEXTMETRIC tm;
359 SIZE size;
360 WND *wndPtr = WIN_FindWndPtr(hWnd);
361 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
363 GetClientRect(hWnd, &rc);
365 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
366 #ifdef WINELIB32 /* JBP: Different in Win32 */
367 hBrush = (HBRUSH) SendMessage(GetParent(hWnd), WM_CTLCOLORBTN, (WPARAM)hDC,
368 (LPARAM)hWnd);
369 #else
370 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
371 MAKELPARAM(hWnd, CTLCOLOR_BTN));
372 #endif
373 if (action == ODA_DRAWENTIRE) FillRect(hDC, &rc, hBrush);
375 GetTextMetrics(hDC, &tm);
376 delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
378 /* Draw the check-box bitmap */
379 x = y = 0;
380 if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
381 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
382 if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
383 ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
384 else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
385 GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rc.left, rc.top + delta,
386 x, y, checkBoxWidth, checkBoxHeight );
387 rc.left += checkBoxWidth + tm.tmAveCharWidth / 2;
389 if (!(text = (char*) USER_HEAP_LIN_ADDR( wndPtr->hText ))) return;
390 textlen = strlen( text );
392 if (action == ODA_DRAWENTIRE)
394 if (wndPtr->dwStyle & WS_DISABLED)
395 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
396 DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
399 if ((action == ODA_FOCUS) ||
400 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
402 GetTextExtentPoint(hDC, text, textlen, &size);
403 if (delta > 1)
405 rc.top += delta - 1;
406 rc.bottom -= delta + 1;
408 rc.left--;
409 rc.right = MIN( rc.left + size.cx + 2, rc.right );
410 DrawFocusRect(hDC, &rc);
415 /**********************************************************************
416 * BUTTON_CheckAutoRadioButton
418 * hWnd is checked, uncheck everything else in group
420 static void BUTTON_CheckAutoRadioButton(HWND hWnd)
422 HWND parent = GetParent(hWnd);
423 HWND sibling;
424 for(sibling = GetNextDlgGroupItem(parent,hWnd,FALSE);
425 sibling != hWnd;
426 sibling = GetNextDlgGroupItem(parent,sibling,FALSE))
427 SendMessage(sibling,BM_SETCHECK,BUTTON_UNCHECKED,0);
431 /**********************************************************************
432 * Group Box Functions
435 static void GB_Paint( HWND hWnd, HDC hDC, WORD action )
437 RECT rc;
438 char *text;
439 SIZE size;
440 WND *wndPtr = WIN_FindWndPtr( hWnd );
441 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
443 if (action != ODA_DRAWENTIRE) return;
445 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
446 #ifdef WINELIB32
447 SendMessage( GetParent(hWnd), WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hWnd );
448 #else
449 SendMessage( GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
450 MAKELPARAM(hWnd, CTLCOLOR_BTN));
451 #endif
452 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
454 GetClientRect(hWnd, &rc);
456 MoveTo( hDC, rc.left, rc.top+2 );
457 LineTo( hDC, rc.right-1, rc.top+2 );
458 LineTo( hDC, rc.right-1, rc.bottom-1 );
459 LineTo( hDC, rc.left, rc.bottom-1 );
460 LineTo( hDC, rc.left, rc.top+2 );
462 if (!(text = (char*) USER_HEAP_LIN_ADDR( wndPtr->hText ))) return;
463 GetTextExtentPoint(hDC, text, strlen(text), &size);
464 rc.left += 10;
465 rc.right = rc.left + size.cx + 1;
466 rc.bottom = size.cy;
467 if (wndPtr->dwStyle & WS_DISABLED)
468 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
469 DrawText(hDC, text, -1, &rc, DT_SINGLELINE );
473 /**********************************************************************
474 * User Button Functions
477 static void UB_Paint( HWND hWnd, HDC hDC, WORD action )
479 RECT rc;
480 HBRUSH hBrush;
481 WND *wndPtr = WIN_FindWndPtr( hWnd );
482 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
484 if (action == ODA_SELECT) return;
486 GetClientRect(hWnd, &rc);
488 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
489 #ifdef WINELIB32
490 hBrush = (HBRUSH) SendMessage(GetParent(hWnd), WM_CTLCOLORBTN, (WPARAM)hDC,
491 (LPARAM)hWnd);
492 #else
493 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
494 MAKELPARAM(hWnd, CTLCOLOR_BTN));
495 #endif
496 FillRect(hDC, &rc, hBrush);
498 if ((action == ODA_FOCUS) ||
499 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
500 DrawFocusRect(hDC, &rc);
504 /**********************************************************************
505 * Ownerdrawn Button Functions
508 static void OB_Paint( HWND hWnd, HDC hDC, WORD action )
510 DRAWITEMSTRUCT dis;
511 WND *wndPtr = WIN_FindWndPtr( hWnd );
512 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
514 dis.CtlType = ODT_BUTTON;
515 dis.CtlID = wndPtr->wIDmenu;
516 dis.itemID = 0;
517 dis.itemAction = action;
518 dis.itemState = (infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0 |
519 (infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0 |
520 (wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0;
521 dis.hwndItem = hWnd;
522 dis.hDC = hDC;
523 GetClientRect( hWnd, &dis.rcItem );
524 dis.itemData = 0;
525 SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM) MAKE_SEGPTR(&dis) );