Release 961023
[wine/dcerpc.git] / controls / button.c
blobfcf591b94a53a40b8cef8803cf625496b8095e4e
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 break;
193 case WM_SYSCOLORCHANGE:
194 InvalidateRect32( hWnd, NULL, FALSE );
195 break;
197 case BM_SETSTYLE16:
198 case BM_SETSTYLE32:
199 if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
200 wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
201 | (wParam & 0x0000000f);
202 style = wndPtr->dwStyle & 0x0000000f;
203 PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
204 break;
206 case BM_GETCHECK16:
207 case BM_GETCHECK32:
208 return infoPtr->state & 3;
210 case BM_SETCHECK16:
211 case BM_SETCHECK32:
212 if (wParam > maxCheckState[style]) wParam = maxCheckState[style];
213 if ((infoPtr->state & 3) != wParam)
215 infoPtr->state = (infoPtr->state & ~3) | wParam;
216 PAINT_BUTTON( wndPtr, style, ODA_SELECT );
218 if ((style == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED))
219 BUTTON_CheckAutoRadioButton( wndPtr );
220 break;
222 case BM_GETSTATE16:
223 case BM_GETSTATE32:
224 return infoPtr->state;
226 case BM_SETSTATE16:
227 case BM_SETSTATE32:
228 if (wParam)
230 if (infoPtr->state & BUTTON_HIGHLIGHTED) break;
231 infoPtr->state |= BUTTON_HIGHLIGHTED;
233 else
235 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
236 infoPtr->state &= ~BUTTON_HIGHLIGHTED;
238 PAINT_BUTTON( wndPtr, style, ODA_SELECT );
239 break;
241 default:
242 return DefWindowProc32A(hWnd, uMsg, wParam, lParam);
244 return 0;
248 /**********************************************************************
249 * Push Button Functions
252 static void PB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
254 RECT32 rc;
255 HPEN16 hOldPen;
256 HBRUSH16 hOldBrush;
257 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
259 GetClientRect32( wndPtr->hwndSelf, &rc );
261 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
262 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
263 BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
264 hOldPen = (HPEN16)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
265 hOldBrush = (HBRUSH16)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
266 SetBkMode(hDC, TRANSPARENT);
267 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
268 if (action == ODA_DRAWENTIRE)
270 SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
271 SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
272 SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
273 SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
275 InflateRect32( &rc, -1, -1 );
277 if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
279 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
280 InflateRect32( &rc, -1, -1 );
283 if (infoPtr->state & BUTTON_HIGHLIGHTED)
285 /* draw button shadow: */
286 SelectObject(hDC, sysColorObjects.hbrushBtnShadow );
287 PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
288 PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
289 rc.left += 2; /* To position the text down and right */
290 rc.top += 2;
292 else GRAPH_DrawReliefRect( hDC, &rc, 2, 2, FALSE );
294 /* draw button label, if any: */
295 if (wndPtr->text && wndPtr->text[0])
297 LOGBRUSH16 lb;
298 GetObject16( sysColorObjects.hbrushBtnFace, sizeof(lb), &lb );
299 if (wndPtr->dwStyle & WS_DISABLED &&
300 GetSysColor(COLOR_GRAYTEXT)==lb.lbColor)
301 /* don't write gray text on gray bkg */
302 PB_PaintGrayOnGray(hDC,infoPtr->hFont,&rc,wndPtr->text);
303 else
305 SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
306 GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNTEXT));
307 DrawText32A( hDC, wndPtr->text, -1, &rc,
308 DT_SINGLELINE | DT_CENTER | DT_VCENTER );
309 /* do we have the focus? */
310 if (infoPtr->state & BUTTON_HASFOCUS)
312 RECT32 r = { 0, 0, 0, 0 };
313 INT32 xdelta, ydelta;
315 DrawText32A( hDC, wndPtr->text, -1, &r,
316 DT_SINGLELINE | DT_CALCRECT );
317 xdelta = ((rc.right - rc.left) - (r.right - r.left) - 1) / 2;
318 ydelta = ((rc.bottom - rc.top) - (r.bottom - r.top) - 1) / 2;
319 if (xdelta < 0) xdelta = 0;
320 if (ydelta < 0) ydelta = 0;
321 InflateRect32( &rc, -xdelta, -ydelta );
322 DrawFocusRect32( hDC, &rc );
327 SelectObject( hDC, hOldPen );
328 SelectObject( hDC, hOldBrush );
332 /**********************************************************************
333 * Push Button sub function [internal]
334 * using a raster brush to avoid gray text on gray background
337 void PB_PaintGrayOnGray(HDC32 hDC,HFONT32 hFont,RECT32 *rc,char *text)
339 static int Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55};
340 HBITMAP16 hbm = CreateBitmap(8, 8, 1, 1, Pattern);
341 HDC32 hdcMem = CreateCompatibleDC(hDC);
342 HBITMAP16 hbmMem;
343 HBRUSH16 hBr;
344 RECT32 rect,rc2;
346 rect=*rc;
347 DrawText32A( hDC, text, -1, &rect, DT_SINGLELINE | DT_CALCRECT);
348 rc2=rect;
349 rect.left=(rc->right-rect.right)/2; /* for centering text bitmap */
350 rect.top=(rc->bottom-rect.bottom)/2;
351 hbmMem = CreateCompatibleBitmap( hDC,rect.right,rect.bottom);
352 SelectObject( hdcMem, hbmMem);
353 hBr = SelectObject( hdcMem,CreatePatternBrush(hbm));
354 DeleteObject( hbm);
355 PatBlt( hdcMem,0,0,rect.right,rect.bottom,WHITENESS);
356 if (hFont) SelectObject( hdcMem, hFont);
357 DrawText32A( hdcMem, text, -1, &rc2, DT_SINGLELINE);
358 PatBlt( hdcMem,0,0,rect.right,rect.bottom,0xFA0089);
359 DeleteObject( SelectObject( hdcMem,hBr));
360 BitBlt( hDC,rect.left,rect.top,rect.right,rect.bottom,hdcMem,0,0,0x990000);
361 DeleteDC( hdcMem);
362 DeleteObject( hbmMem);
366 /**********************************************************************
367 * Check Box & Radio Button Functions
370 static void CB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
372 RECT16 rc;
373 HBRUSH16 hBrush;
374 int textlen, delta, x, y;
375 TEXTMETRIC16 tm;
376 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
378 GetClientRect16(wndPtr->hwndSelf, &rc);
380 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
381 hBrush = BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
382 if (action == ODA_DRAWENTIRE) FillRect16( hDC, &rc, hBrush );
384 GetTextMetrics16(hDC, &tm);
385 delta = (rc.bottom - rc.top - tm.tmHeight) >> 1;
387 /* Draw the check-box bitmap */
388 x = y = 0;
389 if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
390 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
391 if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
392 ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
393 else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
394 GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rc.left, rc.top + delta,
395 x, y, checkBoxWidth, checkBoxHeight );
396 rc.left += checkBoxWidth + tm.tmAveCharWidth / 2;
398 if (!wndPtr->text) return;
399 textlen = strlen( wndPtr->text );
401 if (action == ODA_DRAWENTIRE)
403 if (wndPtr->dwStyle & WS_DISABLED)
404 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
405 DrawText16( hDC, wndPtr->text, textlen, &rc,
406 DT_SINGLELINE | DT_VCENTER | DT_NOCLIP );
409 if ((action == ODA_FOCUS) ||
410 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
412 RECT16 rect = { 0, 0, 0, 0 };
413 DrawText16( hDC, wndPtr->text, textlen, &rect,
414 DT_SINGLELINE | DT_CALCRECT );
415 if (delta > 1)
417 rc.top += delta - 1;
418 rc.bottom -= delta + 1;
420 rc.left--;
421 rc.right = rc.left + rect.right + 2;
422 DrawFocusRect16( hDC, &rc );
427 /**********************************************************************
428 * BUTTON_CheckAutoRadioButton
430 * wndPtr is checked, uncheck everything else in group
432 static void BUTTON_CheckAutoRadioButton( WND *wndPtr )
434 HWND32 parent, sibling;
435 if (!(wndPtr->dwStyle & WS_CHILD)) return;
436 parent = wndPtr->parent->hwndSelf;
437 for(sibling = GetNextDlgGroupItem32( parent, wndPtr->hwndSelf, FALSE );
438 sibling != wndPtr->hwndSelf;
439 sibling = GetNextDlgGroupItem32( parent, sibling, FALSE ))
440 SendMessage32A( sibling, BM_SETCHECK32, BUTTON_UNCHECKED, 0 );
444 /**********************************************************************
445 * Group Box Functions
448 static void GB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
450 RECT16 rc;
451 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
453 if (action != ODA_DRAWENTIRE) return;
455 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
456 BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
457 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
459 GetClientRect16( wndPtr->hwndSelf, &rc);
461 MoveTo( hDC, rc.left, rc.top+2 );
462 LineTo( hDC, rc.right-1, rc.top+2 );
463 LineTo( hDC, rc.right-1, rc.bottom-1 );
464 LineTo( hDC, rc.left, rc.bottom-1 );
465 LineTo( hDC, rc.left, rc.top+2 );
467 if (!wndPtr->text) return;
468 if (wndPtr->dwStyle & WS_DISABLED)
469 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
470 rc.left += 10;
471 DrawText16( hDC, wndPtr->text, -1, &rc, DT_SINGLELINE | DT_NOCLIP );
475 /**********************************************************************
476 * User Button Functions
479 static void UB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
481 RECT16 rc;
482 HBRUSH16 hBrush;
483 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
485 if (action == ODA_SELECT) return;
487 GetClientRect16( wndPtr->hwndSelf, &rc);
489 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
490 hBrush = BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
491 FillRect16( hDC, &rc, hBrush );
493 if ((action == ODA_FOCUS) ||
494 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
495 DrawFocusRect16( hDC, &rc );
499 /**********************************************************************
500 * Ownerdrawn Button Functions
503 static void OB_Paint( WND *wndPtr, HDC32 hDC, WORD action )
505 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
506 DRAWITEMSTRUCT32 dis;
508 dis.CtlType = ODT_BUTTON;
509 dis.CtlID = wndPtr->wIDmenu;
510 dis.itemID = 0;
511 dis.itemAction = action;
512 dis.itemState = ((infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) |
513 ((infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) |
514 ((wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0);
515 dis.hwndItem = wndPtr->hwndSelf;
516 dis.hDC = hDC;
517 dis.itemData = 0;
518 GetClientRect32( wndPtr->hwndSelf, &dis.rcItem );
519 SendMessage32A( GetParent32(wndPtr->hwndSelf), WM_DRAWITEM,
520 wndPtr->wIDmenu, (LPARAM)&dis );