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
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)
75 WND *wndPtr = WIN_FindWndPtr(hWnd);
76 LONG style = wndPtr->dwStyle & 0x0000000F;
77 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
84 return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
85 case BS_DEFPUSHBUTTON:
86 return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
88 case BS_AUTORADIOBUTTON:
89 return DLGC_BUTTON | DLGC_RADIOBUTTON;
95 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
99 if (!hbitmapCheckBoxes)
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)
112 infoPtr->state = BUTTON_UNCHECKED;
122 if (btnPaintFunc[style])
125 HDC hdc = BeginPaint( hWnd, &ps );
126 (btnPaintFunc[style])( hWnd, hdc, ODA_DRAWENTIRE );
127 ReleaseDC( hWnd, hdc );
132 SendMessage( hWnd, BM_SETSTATE, TRUE, 0 );
139 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
140 SendMessage( hWnd, BM_SETSTATE, FALSE, 0 );
141 GetClientRect( hWnd, &rect );
142 if (PtInRect( &rect, MAKEPOINT(lParam) ))
146 case BS_AUTOCHECKBOX:
147 SendMessage( hWnd, BM_SETCHECK,
148 !(infoPtr->state & BUTTON_CHECKED), 0 );
150 case BS_AUTORADIOBUTTON:
151 SendMessage( hWnd, BM_SETCHECK, TRUE, 0 );
154 SendMessage( hWnd, BM_SETCHECK,
155 (infoPtr->state & BUTTON_3STATE) ? 0 :
156 ((infoPtr->state & 3) + 1), 0 );
159 SendMessage( GetParent(hWnd), WM_COMMAND,
160 wndPtr->wIDmenu, MAKELPARAM(hWnd,BN_CLICKED));
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 );
175 if(style == BS_GROUPBOX) return HTTRANSPARENT;
176 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
180 DEFWND_SetText( hWnd, (LPSTR)PTR_SEG_TO_LIN(lParam) );
181 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
185 infoPtr->hFont = wParam;
187 PAINT_BUTTON( hWnd, style, ODA_DRAWENTIRE );
191 return infoPtr->hFont;
194 infoPtr->state |= BUTTON_HASFOCUS;
195 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
199 infoPtr->state &= ~BUTTON_HASFOCUS;
200 PAINT_BUTTON( hWnd, style, ODA_FOCUS );
203 case WM_SYSCOLORCHANGE:
204 InvalidateRect(hWnd, NULL, FALSE);
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 );
216 lResult = infoPtr->state & 3;
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);
232 lResult = infoPtr->state;
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 );
245 lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
253 /**********************************************************************
254 * Push Button Functions
257 static void PB_Paint( HWND hButton, HDC hDC, WORD action )
265 WND *wndPtr = WIN_FindWndPtr( hButton );
266 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
268 GetClientRect(hButton, &rc);
270 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
271 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
272 SendMessage( GetParent(hButton), WM_CTLCOLOR, (WORD)hDC,
273 MAKELPARAM(hButton, CTLCOLOR_BTN) );
274 hOldPen = (HPEN)SelectObject(hDC, sysColorObjects.hpenWindowFrame);
275 hOldBrush = (HBRUSH)SelectObject(hDC, sysColorObjects.hbrushBtnFace);
276 SetBkMode(hDC, TRANSPARENT);
277 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
278 if (action == ODA_DRAWENTIRE)
280 SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
281 SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
282 SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
283 SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
285 InflateRect( &rc, -1, -1 );
287 if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
289 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
290 InflateRect( &rc, -1, -1 );
293 if (infoPtr->state & BUTTON_HIGHLIGHTED)
295 /* draw button shadow: */
296 SelectObject(hDC, sysColorObjects.hbrushBtnShadow );
297 PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
298 PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
299 rc.left += 2; /* To position the text down and right */
302 else GRAPH_DrawReliefRect( hDC, &rc, 2, 2, FALSE );
304 /* draw button label, if any: */
305 text = USER_HEAP_LIN_ADDR( wndPtr->hText );
308 SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
309 GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNTEXT));
310 DrawText(hDC, text, -1, &rc,
311 DT_SINGLELINE | DT_CENTER | DT_VCENTER);
312 /* do we have the focus? */
313 if (infoPtr->state & BUTTON_HASFOCUS)
315 short xdelta, ydelta;
316 dwTextSize = GetTextExtent( hDC, text, strlen(text) );
317 GetTextMetrics( hDC, &tm );
318 xdelta = ((rc.right - rc.left) - LOWORD(dwTextSize) - 1) / 2;
319 ydelta = ((rc.bottom - rc.top) - tm.tmHeight - 1) / 2;
320 if (xdelta < 0) xdelta = 0;
321 if (ydelta < 0) ydelta = 0;
322 InflateRect( &rc, -xdelta, -ydelta );
323 DrawFocusRect( hDC, &rc );
327 SelectObject(hDC, (HANDLE)hOldPen);
328 SelectObject(hDC, (HANDLE)hOldBrush);
332 /**********************************************************************
333 * Check Box & Radio Button Functions
336 static void CB_Paint( HWND hWnd, HDC hDC, WORD action )
340 int textlen, delta, x, y;
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_LIN_ADDR( wndPtr->hText );
357 textlen = strlen( text );
359 /* Draw the check-box bitmap */
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 );
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);
384 rc.bottom -= delta + 1;
387 rc.right = min( rc.left + size.cx + 2, rc.right );
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);
402 for(sibling = GetNextDlgGroupItem(parent,hWnd,FALSE);
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 )
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_LIN_ADDR( wndPtr->hText );
437 GetTextExtentPoint(hDC, text, strlen(text), &size);
439 rc.right = rc.left + size.cx + 1;
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 )
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 )
480 WND *wndPtr = WIN_FindWndPtr( hWnd );
481 BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
483 dis.CtlType = ODT_BUTTON;
484 dis.CtlID = wndPtr->wIDmenu;
486 dis.itemAction = action;
487 dis.itemState = (infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0 |
488 (infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0 |
489 (wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0;
492 GetClientRect( hWnd, &dis.rcItem );
494 SendMessage(GetParent(hWnd), WM_DRAWITEM, 1, MAKE_SEGPTR(&dis) );