Release 941017
[wine/gsoc-2012-control.git] / controls / button.c
blobd20baffd8724d985236bba30953ffa00b543f954
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 static char Copyright1[] = "Copyright Johannes Ruscheinski, 1993";
9 static char Copyright2[] = "Copyright David Metcalfe, 1993";
10 static char Copyright3[] = "Copyright Alexandre Julliard, 1994";
12 #include "button.h"
13 #include "win.h"
14 #include "user.h"
15 #include "syscolor.h"
18 extern BOOL GRAPH_DrawBitmap( HDC hdc, HBITMAP hbitmap, int xdest, int ydest,
19 int xsrc, int ysrc, int width, int height,
20 int rop ); /* windows/graphics.c */
21 extern void GRAPH_DrawReliefRect( HDC hdc, RECT *rect, int thickness,
22 BOOL pressed ); /* windows/graphics.c */
24 extern void DEFWND_SetText( HWND hwnd, LPSTR text ); /* windows/defwnd.c */
26 static void PB_Paint( HWND hWnd, HDC hDC, WORD action );
27 static void CB_Paint( HWND hWnd, HDC hDC, WORD action );
28 static void GB_Paint( HWND hWnd, HDC hDC, WORD action );
29 static void UB_Paint( HWND hWnd, HDC hDC, WORD action );
30 static void OB_Paint( HWND hWnd, HDC hDC, WORD action );
33 #define MAX_BTN_TYPE 12
35 static WORD maxCheckState[MAX_BTN_TYPE] =
37 BUTTON_UNCHECKED, /* BS_PUSHBUTTON */
38 BUTTON_UNCHECKED, /* BS_DEFPUSHBUTTON */
39 BUTTON_CHECKED, /* BS_CHECKBOX */
40 BUTTON_CHECKED, /* BS_AUTOCHECKBOX */
41 BUTTON_CHECKED, /* BS_RADIOBUTTON */
42 BUTTON_3STATE, /* BS_3STATE */
43 BUTTON_3STATE, /* BS_AUTO3STATE */
44 BUTTON_UNCHECKED, /* BS_GROUPBOX */
45 BUTTON_UNCHECKED, /* BS_USERBUTTON */
46 BUTTON_CHECKED, /* BS_AUTORADIOBUTTON */
47 BUTTON_UNCHECKED, /* Not defined */
48 BUTTON_UNCHECKED /* BS_OWNERDRAW */
51 typedef void (*pfPaint)(HWND,HDC,WORD);
53 static pfPaint btnPaintFunc[MAX_BTN_TYPE] =
55 PB_Paint, /* BS_PUSHBUTTON */
56 PB_Paint, /* BS_DEFPUSHBUTTON */
57 CB_Paint, /* BS_CHECKBOX */
58 CB_Paint, /* BS_AUTOCHECKBOX */
59 CB_Paint, /* BS_RADIOBUTTON */
60 CB_Paint, /* BS_3STATE */
61 CB_Paint, /* BS_AUTO3STATE */
62 GB_Paint, /* BS_GROUPBOX */
63 UB_Paint, /* BS_USERBUTTON */
64 CB_Paint, /* BS_AUTORADIOBUTTON */
65 NULL, /* Not defined */
66 OB_Paint /* BS_OWNERDRAW */
69 #define PAINT_BUTTON(hwnd,style,action) \
70 if (btnPaintFunc[style]) { \
71 HDC hdc = GetDC( hwnd ); \
72 (btnPaintFunc[style])(hwnd,hdc,action); \
73 ReleaseDC( hwnd, hdc ); }
75 static HBITMAP hbitmapCheckBoxes = 0;
76 static WORD checkBoxWidth = 0, checkBoxHeight = 0;
79 LONG ButtonWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam)
81 RECT rect;
82 LONG lResult = 0;
83 WND *wndPtr = WIN_FindWndPtr(hWnd);
84 LONG style = wndPtr->dwStyle & 0x0000000F;
85 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
87 switch (uMsg) {
88 case WM_GETDLGCODE:
89 switch(style)
91 case BS_PUSHBUTTON:
92 return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
93 case BS_DEFPUSHBUTTON:
94 return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
95 case BS_RADIOBUTTON:
96 case BS_AUTORADIOBUTTON:
97 return DLGC_BUTTON | DLGC_RADIOBUTTON;
98 default:
99 return DLGC_BUTTON;
102 case WM_ENABLE:
103 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
104 break;
106 case WM_CREATE:
107 if (!hbitmapCheckBoxes)
109 BITMAP bmp;
110 hbitmapCheckBoxes = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECKBOXES) );
111 GetObject( hbitmapCheckBoxes, sizeof(bmp), (LPSTR)&bmp );
112 checkBoxWidth = bmp.bmWidth / 4;
113 checkBoxHeight = bmp.bmHeight / 3;
116 if (style < 0L || style >= MAX_BTN_TYPE)
117 lResult = -1L;
118 else
120 infoPtr->state = BUTTON_UNCHECKED;
121 infoPtr->hFont = 0;
122 lResult = 0L;
124 break;
126 case WM_ERASEBKGND:
127 break;
129 case WM_PAINT:
130 if (btnPaintFunc[style])
132 PAINTSTRUCT ps;
133 HDC hdc = BeginPaint( hWnd, &ps );
134 (btnPaintFunc[style])( hWnd, hdc, ODA_DRAWENTIRE );
135 ReleaseDC( hWnd, hdc );
137 break;
139 case WM_LBUTTONDOWN:
140 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
141 SetFocus( hWnd );
142 SetCapture( hWnd );
143 break;
145 case WM_LBUTTONUP:
146 ReleaseCapture();
147 SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
148 GetClientRect( hWnd, &rect );
149 if (PtInRect( &rect, MAKEPOINT(lParam) ))
151 switch(style)
153 case BS_AUTOCHECKBOX:
154 SendMessage( hWnd, BM_SETCHECK,
155 !(infoPtr->state & BUTTON_CHECKED), 0 );
156 break;
157 case BS_AUTORADIOBUTTON:
158 SendMessage( hWnd, BM_SETCHECK, TRUE, 0 );
159 break;
160 case BS_AUTO3STATE:
161 SendMessage( hWnd, BM_SETCHECK,
162 (infoPtr->state & BUTTON_3STATE) ? 0 :
163 ((infoPtr->state & 3) + 1), 0 );
164 break;
166 SendMessage( GetParent(hWnd), WM_COMMAND,
167 wndPtr->wIDmenu, MAKELPARAM(hWnd,BN_CLICKED));
169 break;
171 case WM_MOUSEMOVE:
172 if (GetCapture() == hWnd)
174 GetClientRect( hWnd, &rect );
175 if (PtInRect( &rect, MAKEPOINT(lParam)) )
176 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
177 else SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
179 break;
181 case WM_SETTEXT:
182 DEFWND_SetText( hWnd, (LPSTR)lParam );
183 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
184 return 0;
186 case WM_SETFONT:
187 infoPtr->hFont = wParam;
188 if (lParam)
189 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
190 break;
192 case WM_GETFONT:
193 return infoPtr->hFont;
195 case WM_SETFOCUS:
196 infoPtr->state |= BUTTON_HASFOCUS;
197 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
198 break;
200 case WM_KILLFOCUS:
201 infoPtr->state &= ~BUTTON_HASFOCUS;
202 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
203 break;
205 case WM_SYSCOLORCHANGE:
206 InvalidateRect(hWnd, NULL, FALSE);
207 break;
209 case BM_SETSTYLE:
210 if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
211 wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
212 | (wParam & 0x0000000f);
213 style = wndPtr->dwStyle & 0x0000000f;
214 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
215 break;
217 case BM_GETCHECK:
218 lResult = infoPtr->state & 3;
219 break;
221 case BM_SETCHECK:
222 if (wParam > maxCheckState[style])
223 wParam = maxCheckState[style];
224 if ((infoPtr->state & 3) != wParam)
226 infoPtr->state = (infoPtr->state & ~3) | wParam;
227 PAINT_BUTTON( hWnd, style, ODA_SELECT );
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, FALSE );
305 /* draw button label, if any: */
306 text = USER_HEAP_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 dwTextSize = GetTextExtent(hDC, text, strlen(text) );
317 delta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) >> 1;
318 rc.left += delta;
319 rc.right -= delta;
320 GetTextMetrics(hDC, &tm);
321 delta = ((rc.bottom - rc.top) - tm.tmHeight - 1) >> 1;
322 rc.top += delta; rc.bottom -= delta;
323 DrawFocusRect(hDC, &rc);
327 SelectObject(hDC, (HANDLE)hOldPen);
328 SelectObject(hDC, (HANDLE)hOldBrush);
332 /**********************************************************************
333 * Check Box & Radion Button Functions
336 static void CB_Paint( HWND hWnd, HDC hDC, WORD action )
338 RECT rc;
339 HBRUSH hBrush;
340 int textlen, delta, x, y;
341 char *text;
342 TEXTMETRIC tm;
343 SIZE size;
344 WND *wndPtr = WIN_FindWndPtr(hWnd);
345 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
347 GetClientRect(hWnd, &rc);
349 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
350 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
351 MAKELPARAM(hWnd, CTLCOLOR_BTN));
352 if (action == ODA_DRAWENTIRE) FillRect(hDC, &rc, hBrush);
354 GetTextMetrics(hDC, &tm);
355 delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
356 text = USER_HEAP_ADDR( wndPtr->hText );
357 textlen = strlen( text );
359 /* Draw the check-box bitmap */
360 x = y = 0;
361 if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
362 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
363 if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
364 ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
365 else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
366 GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rc.left, rc.top + delta,
367 x, y, checkBoxWidth, checkBoxHeight, SRCCOPY );
368 rc.left += checkBoxWidth + tm.tmAveCharWidth / 2;
370 if (action == ODA_DRAWENTIRE)
372 if (wndPtr->dwStyle & WS_DISABLED)
373 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
374 DrawText(hDC, text, textlen, &rc, DT_SINGLELINE | DT_VCENTER);
377 if ((action == ODA_FOCUS) ||
378 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
380 GetTextExtentPoint(hDC, text, textlen, &size);
381 rc.top += delta - 1;
382 rc.bottom -= delta + 1;
383 rc.left--;
384 rc.right = rc.left + size.cx + 2;
385 DrawFocusRect(hDC, &rc);
390 /**********************************************************************
391 * Group Box Functions
394 static void GB_Paint( HWND hWnd, HDC hDC, WORD action )
396 RECT rc;
397 char *text;
398 SIZE size;
399 WND *wndPtr = WIN_FindWndPtr( hWnd );
400 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
402 if (action != ODA_DRAWENTIRE) return;
404 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
405 SendMessage( GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
406 MAKELPARAM(hWnd, CTLCOLOR_BTN));
407 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
409 GetClientRect(hWnd, &rc);
411 MoveTo( hDC, rc.left, rc.top+2 );
412 LineTo( hDC, rc.right-1, rc.top+2 );
413 LineTo( hDC, rc.right-1, rc.bottom-1 );
414 LineTo( hDC, rc.left, rc.bottom-1 );
415 LineTo( hDC, rc.left, rc.top+2 );
417 text = USER_HEAP_ADDR( wndPtr->hText );
418 GetTextExtentPoint(hDC, text, strlen(text), &size);
419 rc.left += 10;
420 rc.right = rc.left + size.cx + 1;
421 rc.bottom = size.cy;
422 if (wndPtr->dwStyle & WS_DISABLED)
423 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
424 DrawText(hDC, text, -1, &rc, DT_SINGLELINE );
428 /**********************************************************************
429 * User Button Functions
432 static void UB_Paint( HWND hWnd, HDC hDC, WORD action )
434 RECT rc;
435 HBRUSH hBrush;
436 WND *wndPtr = WIN_FindWndPtr( hWnd );
437 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
439 if (action == ODA_SELECT) return;
441 GetClientRect(hWnd, &rc);
443 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
444 hBrush = SendMessage(GetParent(hWnd), WM_CTLCOLOR, (WORD)hDC,
445 MAKELPARAM(hWnd, CTLCOLOR_BTN));
446 FillRect(hDC, &rc, hBrush);
448 if ((action == ODA_FOCUS) ||
449 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
450 DrawFocusRect(hDC, &rc);
454 /**********************************************************************
455 * Ownerdrawn Button Functions
458 static void OB_Paint( HWND hWnd, HDC hDC, WORD action )
460 HANDLE hDis;
461 LPDRAWITEMSTRUCT lpdis;
462 WND *wndPtr = WIN_FindWndPtr( hWnd );
463 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
465 if (!(hDis = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(DRAWITEMSTRUCT))))
466 return;
467 lpdis = (LPDRAWITEMSTRUCT)USER_HEAP_ADDR(hDis);
468 lpdis->CtlType = ODT_BUTTON;
469 lpdis->CtlID = wndPtr->wIDmenu;
470 lpdis->itemID = 0;
471 lpdis->itemAction = action;
472 lpdis->itemState = (infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0 |
473 (infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0 |
474 (wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0;
475 lpdis->hwndItem = hWnd;
476 lpdis->hDC = hDC;
477 GetClientRect( hWnd, &lpdis->rcItem );
478 lpdis->itemData = 0;
479 SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, (LPARAM)lpdis);
480 USER_HEAP_FREE(hDis);