Release 950109
[wine/multimedia.git] / controls / button.c
blob32b8fed2dadaa0ed4a6dad9159e4604e8e87776a
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
7 static char Copyright1[] = "Copyright Johannes Ruscheinski, 1993";
8 static char Copyright2[] = "Copyright David Metcalfe, 1993";
9 static char Copyright3[] = "Copyright Alexandre Julliard, 1994";
12 #include "win.h"
13 #include "user.h"
14 #include "syscolor.h"
15 #include "graphics.h"
16 #include "button.h"
18 extern void DEFWND_SetText( HWND hwnd, LPSTR text ); /* windows/defwnd.c */
20 static void PB_Paint( HWND hWnd, HDC hDC, WORD action );
21 static void CB_Paint( HWND hWnd, HDC hDC, WORD action );
22 static void GB_Paint( HWND hWnd, HDC hDC, WORD action );
23 static void UB_Paint( HWND hWnd, HDC hDC, WORD action );
24 static void OB_Paint( HWND hWnd, HDC hDC, WORD action );
25 static void BUTTON_CheckAutoRadioButton(HWND hWnd);
28 #define MAX_BTN_TYPE 12
30 static 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)(HWND,HDC,WORD);
48 static 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(hwnd,style,action) \
65 if (btnPaintFunc[style]) { \
66 HDC hdc = GetDC( hwnd ); \
67 (btnPaintFunc[style])(hwnd,hdc,action); \
68 ReleaseDC( hwnd, hdc ); }
70 static HBITMAP hbitmapCheckBoxes = 0;
71 static WORD checkBoxWidth = 0, checkBoxHeight = 0;
74 LONG ButtonWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam)
76 RECT rect;
77 LONG lResult = 0;
78 WND *wndPtr = WIN_FindWndPtr(hWnd);
79 LONG style = wndPtr->dwStyle & 0x0000000F;
80 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
82 switch (uMsg) {
83 case WM_GETDLGCODE:
84 switch(style)
86 case BS_PUSHBUTTON:
87 return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
88 case BS_DEFPUSHBUTTON:
89 return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
90 case BS_RADIOBUTTON:
91 case BS_AUTORADIOBUTTON:
92 return DLGC_BUTTON | DLGC_RADIOBUTTON;
93 default:
94 return DLGC_BUTTON;
97 case WM_ENABLE:
98 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
99 break;
101 case WM_CREATE:
102 if (!hbitmapCheckBoxes)
104 BITMAP bmp;
105 hbitmapCheckBoxes = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECKBOXES) );
106 GetObject( hbitmapCheckBoxes, sizeof(bmp), (LPSTR)&bmp );
107 checkBoxWidth = bmp.bmWidth / 4;
108 checkBoxHeight = bmp.bmHeight / 3;
111 if (style < 0L || style >= MAX_BTN_TYPE)
112 lResult = -1L;
113 else
115 infoPtr->state = BUTTON_UNCHECKED;
116 infoPtr->hFont = 0;
117 lResult = 0L;
119 break;
121 case WM_ERASEBKGND:
122 break;
124 case WM_PAINT:
125 if (btnPaintFunc[style])
127 PAINTSTRUCT ps;
128 HDC hdc = BeginPaint( hWnd, &ps );
129 (btnPaintFunc[style])( hWnd, hdc, ODA_DRAWENTIRE );
130 ReleaseDC( hWnd, hdc );
132 break;
134 case WM_LBUTTONDOWN:
135 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
136 SetFocus( hWnd );
137 SetCapture( hWnd );
138 break;
140 case WM_LBUTTONUP:
141 if (GetCapture() != hWnd) break;
142 ReleaseCapture();
143 SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
144 GetClientRect( hWnd, &rect );
145 if (PtInRect( &rect, MAKEPOINT(lParam) ))
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 SendMessage( GetParent(hWnd), WM_COMMAND,
163 wndPtr->wIDmenu, MAKELPARAM(hWnd,BN_CLICKED));
165 break;
167 case WM_MOUSEMOVE:
168 if (GetCapture() == hWnd)
170 GetClientRect( hWnd, &rect );
171 if (PtInRect( &rect, MAKEPOINT(lParam)) )
172 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
173 else SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
175 break;
177 case WM_NCHITTEST:
178 if(style == BS_GROUPBOX) return HTTRANSPARENT;
179 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
180 break;
182 case WM_SETTEXT:
183 DEFWND_SetText( hWnd, (LPSTR)lParam );
184 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
185 return 0;
187 case WM_SETFONT:
188 infoPtr->hFont = wParam;
189 if (lParam)
190 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
191 break;
193 case WM_GETFONT:
194 return infoPtr->hFont;
196 case WM_SETFOCUS:
197 infoPtr->state |= BUTTON_HASFOCUS;
198 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
199 break;
201 case WM_KILLFOCUS:
202 infoPtr->state &= ~BUTTON_HASFOCUS;
203 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
204 break;
206 case WM_SYSCOLORCHANGE:
207 InvalidateRect(hWnd, NULL, FALSE);
208 break;
210 case BM_SETSTYLE:
211 if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
212 wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
213 | (wParam & 0x0000000f);
214 style = wndPtr->dwStyle & 0x0000000f;
215 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
216 break;
218 case BM_GETCHECK:
219 lResult = infoPtr->state & 3;
220 break;
222 case BM_SETCHECK:
223 if (wParam > maxCheckState[style])
224 wParam = maxCheckState[style];
225 if ((infoPtr->state & 3) != wParam)
227 infoPtr->state = (infoPtr->state & ~3) | wParam;
228 PAINT_BUTTON( hWnd, style, ODA_SELECT );
230 if(style == BS_AUTORADIOBUTTON && wParam==BUTTON_CHECKED)
231 BUTTON_CheckAutoRadioButton(hWnd);
232 break;
234 case BM_GETSTATE:
235 lResult = infoPtr->state;
236 break;
238 case BM_SETSTATE:
239 if (!wParam != !(infoPtr->state & BUTTON_HIGHLIGHTED))
241 if (wParam) infoPtr->state |= BUTTON_HIGHLIGHTED;
242 else infoPtr->state &= ~BUTTON_HIGHLIGHTED;
243 PAINT_BUTTON( hWnd, style, ODA_SELECT );
245 break;
247 default:
248 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
249 break;
252 return lResult;
256 /**********************************************************************
257 * Push Button Functions
260 static void PB_Paint( HWND hButton, HDC hDC, WORD action )
262 RECT rc;
263 HPEN hOldPen;
264 HBRUSH hOldBrush;
265 char *text;
266 DWORD dwTextSize;
267 int delta;
268 TEXTMETRIC tm;
269 WND *wndPtr = WIN_FindWndPtr( hButton );
270 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
272 GetClientRect(hButton, &rc);
274 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
275 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
276 SendMessage( GetParent(hButton), WM_CTLCOLOR, (WORD)hDC,
277 MAKELPARAM(hButton, CTLCOLOR_BTN) );
278 hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
279 hOldBrush = (HBRUSH)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
280 SetBkMode(hDC, TRANSPARENT);
281 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
282 if (action == ODA_DRAWENTIRE)
284 SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
285 SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
286 SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
287 SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
289 InflateRect( &rc, -1, -1 );
291 if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
293 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
294 InflateRect( &rc, -1, -1 );
297 if (infoPtr->state & BUTTON_HIGHLIGHTED)
299 /* draw button shadow: */
300 SelectObject(hDC, sysColorObjects.hbrushBtnShadow );
301 PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
302 PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
303 rc.left += 2; /* To position the text down and right */
304 rc.top += 2;
306 else GRAPH_DrawReliefRect( hDC, &rc, 2, 2, FALSE );
308 /* draw button label, if any: */
309 text = USER_HEAP_ADDR( wndPtr->hText );
310 if (text[0])
312 SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
313 GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNTEXT));
314 DrawText(hDC, text, -1, &rc,
315 DT_SINGLELINE | DT_CENTER | DT_VCENTER);
316 /* do we have the focus? */
317 if (infoPtr->state & BUTTON_HASFOCUS)
319 dwTextSize = GetTextExtent(hDC, text, strlen(text) );
320 delta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) >> 1;
321 rc.left += delta;
322 rc.right -= delta;
323 GetTextMetrics(hDC, &tm);
324 delta = ((rc.bottom - rc.top) - tm.tmHeight - 1) >> 1;
325 rc.top += delta; rc.bottom -= delta;
326 DrawFocusRect(hDC, &rc);
330 SelectObject(hDC, (HANDLE)hOldPen);
331 SelectObject(hDC, (HANDLE)hOldBrush);
335 /**********************************************************************
336 * Check Box & Radio Button Functions
339 static void CB_Paint( HWND hWnd, HDC hDC, WORD action )
341 RECT rc;
342 HBRUSH hBrush;
343 int textlen, delta, x, y;
344 char *text;
345 TEXTMETRIC tm;
346 SIZE size;
347 WND *wndPtr = WIN_FindWndPtr(hWnd);
348 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
350 GetClientRect(hWnd, &rc);
352 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
353 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
354 MAKELPARAM(hWnd, CTLCOLOR_BTN));
355 if (action == ODA_DRAWENTIRE) FillRect(hDC, &rc, hBrush);
357 GetTextMetrics(hDC, &tm);
358 delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
359 text = USER_HEAP_ADDR( wndPtr->hText );
360 textlen = strlen( text );
362 /* Draw the check-box bitmap */
363 x = y = 0;
364 if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
365 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
366 if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
367 ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
368 else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
369 GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rc.left, rc.top + delta,
370 x, y, checkBoxWidth, checkBoxHeight );
371 rc.left += checkBoxWidth + tm.tmAveCharWidth / 2;
373 if (action == ODA_DRAWENTIRE)
375 if (wndPtr->dwStyle & WS_DISABLED)
376 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
377 DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
380 if ((action == ODA_FOCUS) ||
381 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
383 GetTextExtentPoint(hDC, text, textlen, &size);
384 rc.top += delta - 1;
385 rc.bottom -= delta + 1;
386 rc.left--;
387 rc.right = rc.left + size.cx + 2;
388 DrawFocusRect(hDC, &rc);
393 /**********************************************************************
394 * BUTTON_CheckAutoRadioButton
396 * hWnd is checked, uncheck everything else in group
398 static void BUTTON_CheckAutoRadioButton(HWND hWnd)
400 HWND parent = GetParent(hWnd);
401 HWND sibling;
402 for(sibling = GetNextDlgGroupItem(parent,hWnd,FALSE);
403 sibling != hWnd;
404 sibling = GetNextDlgGroupItem(parent,sibling,FALSE))
405 SendMessage(sibling,BM_SETCHECK,BUTTON_UNCHECKED,0);
409 /**********************************************************************
410 * Group Box Functions
413 static void GB_Paint( HWND hWnd, HDC hDC, WORD action )
415 RECT rc;
416 char *text;
417 SIZE size;
418 WND *wndPtr = WIN_FindWndPtr( hWnd );
419 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
421 if (action != ODA_DRAWENTIRE) return;
423 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
424 SendMessage( GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
425 MAKELPARAM(hWnd, CTLCOLOR_BTN));
426 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
428 GetClientRect(hWnd, &rc);
430 MoveTo( hDC, rc.left, rc.top+2 );
431 LineTo( hDC, rc.right-1, rc.top+2 );
432 LineTo( hDC, rc.right-1, rc.bottom-1 );
433 LineTo( hDC, rc.left, rc.bottom-1 );
434 LineTo( hDC, rc.left, rc.top+2 );
436 text = USER_HEAP_ADDR( wndPtr->hText );
437 GetTextExtentPoint(hDC, text, strlen(text), &size);
438 rc.left += 10;
439 rc.right = rc.left + size.cx + 1;
440 rc.bottom = size.cy;
441 if (wndPtr->dwStyle & WS_DISABLED)
442 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
443 DrawText(hDC, text, -1, &rc, DT_SINGLELINE );
447 /**********************************************************************
448 * User Button Functions
451 static void UB_Paint( HWND hWnd, HDC hDC, WORD action )
453 RECT rc;
454 HBRUSH hBrush;
455 WND *wndPtr = WIN_FindWndPtr( hWnd );
456 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
458 if (action == ODA_SELECT) return;
460 GetClientRect(hWnd, &rc);
462 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
463 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
464 MAKELPARAM(hWnd, CTLCOLOR_BTN));
465 FillRect(hDC, &rc, hBrush);
467 if ((action == ODA_FOCUS) ||
468 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
469 DrawFocusRect(hDC, &rc);
473 /**********************************************************************
474 * Ownerdrawn Button Functions
477 static void OB_Paint( HWND hWnd, HDC hDC, WORD action )
479 HANDLE hDis;
480 LPDRAWITEMSTRUCT lpdis;
481 WND *wndPtr = WIN_FindWndPtr( hWnd );
482 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
484 if (!(hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT))))
485 return;
486 lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
487 lpdis->CtlType = ODT_BUTTON;
488 lpdis->CtlID = wndPtr->wIDmenu;
489 lpdis->itemID = 0;
490 lpdis->itemAction = action;
491 lpdis->itemState = (infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0 |
492 (infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0 |
493 (wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0;
494 lpdis->hwndItem = hWnd;
495 lpdis->hDC = hDC;
496 GetClientRect( hWnd, &lpdis->rcItem );
497 lpdis->itemData = 0;
498 SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis);
499 USER_HEAP_FREE(hDis);