Release 950817
[wine/multimedia.git] / controls / button.c
blob9e29e543b2a3a7144bfdee967a801e043119caa8
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 LONG ButtonWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam)
73 RECT rect;
74 LONG lResult = 0;
75 WND *wndPtr = WIN_FindWndPtr(hWnd);
76 LONG style = wndPtr->dwStyle & 0x0000000F;
77 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
79 switch (uMsg) {
80 case WM_GETDLGCODE:
81 switch(style)
83 case BS_PUSHBUTTON:
84 return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
85 case BS_DEFPUSHBUTTON:
86 return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
87 case BS_RADIOBUTTON:
88 case BS_AUTORADIOBUTTON:
89 return DLGC_BUTTON | DLGC_RADIOBUTTON;
90 default:
91 return DLGC_BUTTON;
94 case WM_ENABLE:
95 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
96 break;
98 case WM_CREATE:
99 if (!hbitmapCheckBoxes)
101 BITMAP bmp;
102 hbitmapCheckBoxes = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECKBOXES) );
103 GetObject( hbitmapCheckBoxes, sizeof(bmp), (LPSTR)&bmp );
104 checkBoxWidth = bmp.bmWidth / 4;
105 checkBoxHeight = bmp.bmHeight / 3;
108 if (style < 0L || style >= MAX_BTN_TYPE)
109 lResult = -1L;
110 else
112 infoPtr->state = BUTTON_UNCHECKED;
113 infoPtr->hFont = 0;
114 lResult = 0L;
116 break;
118 case WM_ERASEBKGND:
119 break;
121 case WM_PAINT:
122 if (btnPaintFunc[style])
124 PAINTSTRUCT ps;
125 HDC hdc = BeginPaint( hWnd, &ps );
126 (btnPaintFunc[style])( hWnd, hdc, ODA_DRAWENTIRE );
127 ReleaseDC( hWnd, hdc );
129 break;
131 case WM_LBUTTONDOWN:
132 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
133 SetFocus( hWnd );
134 SetCapture( hWnd );
135 break;
137 case WM_LBUTTONUP:
138 ReleaseCapture();
139 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
140 SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
141 GetClientRect( hWnd, &rect );
142 if (PtInRect( &rect, MAKEPOINT(lParam) ))
144 switch(style)
146 case BS_AUTOCHECKBOX:
147 SendMessage( hWnd, BM_SETCHECK,
148 !(infoPtr->state & BUTTON_CHECKED), 0 );
149 break;
150 case BS_AUTORADIOBUTTON:
151 SendMessage( hWnd, BM_SETCHECK, TRUE, 0 );
152 break;
153 case BS_AUTO3STATE:
154 SendMessage( hWnd, BM_SETCHECK,
155 (infoPtr->state & BUTTON_3STATE) ? 0 :
156 ((infoPtr->state & 3) + 1), 0 );
157 break;
159 SendMessage( GetParent(hWnd), WM_COMMAND,
160 wndPtr->wIDmenu, MAKELPARAM(hWnd,BN_CLICKED));
162 break;
164 case WM_MOUSEMOVE:
165 if (GetCapture() == hWnd)
167 GetClientRect( hWnd, &rect );
168 if (PtInRect( &rect, MAKEPOINT(lParam)) )
169 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
170 else SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
172 break;
174 case WM_NCHITTEST:
175 if(style == BS_GROUPBOX) return HTTRANSPARENT;
176 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
177 break;
179 case WM_SETTEXT:
180 DEFWND_SetText( hWnd, (LPSTR)PTR_SEG_TO_LIN(lParam) );
181 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
182 return 0;
184 case WM_SETFONT:
185 infoPtr->hFont = wParam;
186 if (lParam)
187 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
188 break;
190 case WM_GETFONT:
191 return infoPtr->hFont;
193 case WM_SETFOCUS:
194 infoPtr->state |= BUTTON_HASFOCUS;
195 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
196 break;
198 case WM_KILLFOCUS:
199 infoPtr->state &= ~BUTTON_HASFOCUS;
200 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
201 break;
203 case WM_SYSCOLORCHANGE:
204 InvalidateRect(hWnd, NULL, FALSE);
205 break;
207 case BM_SETSTYLE:
208 if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
209 wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
210 | (wParam & 0x0000000f);
211 style = wndPtr->dwStyle & 0x0000000f;
212 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
213 break;
215 case BM_GETCHECK:
216 lResult = infoPtr->state & 3;
217 break;
219 case BM_SETCHECK:
220 if (wParam > maxCheckState[style])
221 wParam = maxCheckState[style];
222 if ((infoPtr->state & 3) != wParam)
224 infoPtr->state = (infoPtr->state & ~3) | wParam;
225 PAINT_BUTTON( hWnd, style, ODA_SELECT );
227 if(style == BS_AUTORADIOBUTTON && wParam==BUTTON_CHECKED)
228 BUTTON_CheckAutoRadioButton(hWnd);
229 break;
231 case BM_GETSTATE:
232 lResult = infoPtr->state;
233 break;
235 case BM_SETSTATE:
236 if (!wParam != !(infoPtr->state & BUTTON_HIGHLIGHTED))
238 if (wParam) infoPtr->state |= BUTTON_HIGHLIGHTED;
239 else infoPtr->state &= ~BUTTON_HIGHLIGHTED;
240 PAINT_BUTTON( hWnd, style, ODA_SELECT );
242 break;
244 default:
245 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
246 break;
249 return lResult;
253 /**********************************************************************
254 * Push Button Functions
257 static void PB_Paint( HWND hButton, HDC hDC, WORD action )
259 RECT rc;
260 HPEN hOldPen;
261 HBRUSH hOldBrush;
262 char *text;
263 DWORD dwTextSize;
264 int delta;
265 TEXTMETRIC tm;
266 WND *wndPtr = WIN_FindWndPtr( hButton );
267 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
269 GetClientRect(hButton, &rc);
271 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
272 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
273 SendMessage( GetParent(hButton), WM_CTLCOLOR, (WORD)hDC,
274 MAKELPARAM(hButton, CTLCOLOR_BTN) );
275 hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
276 hOldBrush = (HBRUSH)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
277 SetBkMode(hDC, TRANSPARENT);
278 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
279 if (action == ODA_DRAWENTIRE)
281 SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
282 SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
283 SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
284 SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
286 InflateRect( &rc, -1, -1 );
288 if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
290 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
291 InflateRect( &rc, -1, -1 );
294 if (infoPtr->state & BUTTON_HIGHLIGHTED)
296 /* draw button shadow: */
297 SelectObject(hDC, sysColorObjects.hbrushBtnShadow );
298 PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
299 PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
300 rc.left += 2; /* To position the text down and right */
301 rc.top += 2;
303 else GRAPH_DrawReliefRect( hDC, &rc, 2, 2, FALSE );
305 /* draw button label, if any: */
306 text = USER_HEAP_LIN_ADDR( wndPtr->hText );
307 if (text[0])
309 SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
310 GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNTEXT));
311 DrawText(hDC, text, -1, &rc,
312 DT_SINGLELINE | DT_CENTER | DT_VCENTER);
313 /* do we have the focus? */
314 if (infoPtr->state & BUTTON_HASFOCUS)
316 short xdelta, ydelta;
317 dwTextSize = GetTextExtent( hDC, text, strlen(text) );
318 GetTextMetrics( hDC, &tm );
319 xdelta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) / 2;
320 ydelta = ((rc.bottom - rc.top) - tm.tmHeight - 1) / 2;
321 if (xdelta < 0) xdelta = 0;
322 if (ydelta < 0) ydelta = 0;
323 InflateRect( &rc, -xdelta, -ydelta );
324 DrawFocusRect( hDC, &rc );
328 SelectObject(hDC, (HANDLE)hOldPen);
329 SelectObject(hDC, (HANDLE)hOldBrush);
333 /**********************************************************************
334 * Check Box & Radio Button Functions
337 static void CB_Paint( HWND hWnd, HDC hDC, WORD action )
339 RECT rc;
340 HBRUSH hBrush;
341 int textlen, delta, x, y;
342 char *text;
343 TEXTMETRIC tm;
344 SIZE size;
345 WND *wndPtr = WIN_FindWndPtr(hWnd);
346 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
348 GetClientRect(hWnd, &rc);
350 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
351 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
352 MAKELPARAM(hWnd, CTLCOLOR_BTN));
353 if (action == ODA_DRAWENTIRE) FillRect(hDC, &rc, hBrush);
355 GetTextMetrics(hDC, &tm);
356 delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
357 text = USER_HEAP_LIN_ADDR( wndPtr->hText );
358 textlen = strlen( text );
360 /* Draw the check-box bitmap */
361 x = y = 0;
362 if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
363 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
364 if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
365 ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
366 else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
367 GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rc.left, rc.top + delta,
368 x, y, checkBoxWidth, checkBoxHeight );
369 rc.left += checkBoxWidth + tm.tmAveCharWidth / 2;
371 if (action == ODA_DRAWENTIRE)
373 if (wndPtr->dwStyle & WS_DISABLED)
374 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
375 DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
378 if ((action == ODA_FOCUS) ||
379 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
381 GetTextExtentPoint(hDC, text, textlen, &size);
382 if (delta > 1)
384 rc.top += delta - 1;
385 rc.bottom -= delta + 1;
387 rc.left--;
388 rc.right = min( rc.left + size.cx + 2, rc.right );
389 DrawFocusRect(hDC, &rc);
394 /**********************************************************************
395 * BUTTON_CheckAutoRadioButton
397 * hWnd is checked, uncheck everything else in group
399 static void BUTTON_CheckAutoRadioButton(HWND hWnd)
401 HWND parent = GetParent(hWnd);
402 HWND sibling;
403 for(sibling = GetNextDlgGroupItem(parent,hWnd,FALSE);
404 sibling != hWnd;
405 sibling = GetNextDlgGroupItem(parent,sibling,FALSE))
406 SendMessage(sibling,BM_SETCHECK,BUTTON_UNCHECKED,0);
410 /**********************************************************************
411 * Group Box Functions
414 static void GB_Paint( HWND hWnd, HDC hDC, WORD action )
416 RECT rc;
417 char *text;
418 SIZE size;
419 WND *wndPtr = WIN_FindWndPtr( hWnd );
420 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
422 if (action != ODA_DRAWENTIRE) return;
424 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
425 SendMessage( GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
426 MAKELPARAM(hWnd, CTLCOLOR_BTN));
427 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
429 GetClientRect(hWnd, &rc);
431 MoveTo( hDC, rc.left, rc.top+2 );
432 LineTo( hDC, rc.right-1, rc.top+2 );
433 LineTo( hDC, rc.right-1, rc.bottom-1 );
434 LineTo( hDC, rc.left, rc.bottom-1 );
435 LineTo( hDC, rc.left, rc.top+2 );
437 text = USER_HEAP_LIN_ADDR( wndPtr->hText );
438 GetTextExtentPoint(hDC, text, strlen(text), &size);
439 rc.left += 10;
440 rc.right = rc.left + size.cx + 1;
441 rc.bottom = size.cy;
442 if (wndPtr->dwStyle & WS_DISABLED)
443 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
444 DrawText(hDC, text, -1, &rc, DT_SINGLELINE );
448 /**********************************************************************
449 * User Button Functions
452 static void UB_Paint( HWND hWnd, HDC hDC, WORD action )
454 RECT rc;
455 HBRUSH hBrush;
456 WND *wndPtr = WIN_FindWndPtr( hWnd );
457 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
459 if (action == ODA_SELECT) return;
461 GetClientRect(hWnd, &rc);
463 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
464 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
465 MAKELPARAM(hWnd, CTLCOLOR_BTN));
466 FillRect(hDC, &rc, hBrush);
468 if ((action == ODA_FOCUS) ||
469 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
470 DrawFocusRect(hDC, &rc);
474 /**********************************************************************
475 * Ownerdrawn Button Functions
478 static void OB_Paint( HWND hWnd, HDC hDC, WORD action )
480 DRAWITEMSTRUCT dis;
481 WND *wndPtr = WIN_FindWndPtr( hWnd );
482 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
484 dis.CtlType = ODT_BUTTON;
485 dis.CtlID = wndPtr->wIDmenu;
486 dis.itemID = 0;
487 dis.itemAction = action;
488 dis.itemState = (infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0 |
489 (infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0 |
490 (wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0;
491 dis.hwndItem = hWnd;
492 dis.hDC = hDC;
493 GetClientRect( hWnd, &dis.rcItem );
494 dis.itemData = 0;
495 SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, MAKE_SEGPTR(&dis) );