source: trunk/src/user32/button.cpp@ 1210

Last change on this file since 1210 was 1210, checked in by sandervl, 26 years ago

Syscolor + button WM_ENABLE fixes

File size: 31.5 KB
Line 
1/* $Id: button.cpp,v 1.6 1999-10-09 11:03:22 sandervl Exp $ */
2/* File: button.cpp -- Button type widgets
3 *
4 * Copyright (C) 1993 Johannes Ruscheinski
5 * Copyright (C) 1993 David Metcalfe
6 * Copyright (C) 1994 Alexandre Julliard
7 * Copyright (c) 1999 Christoph Bratschi
8 *
9 * WINE version: 990923
10 */
11
12/* CB: todo
13 - update checkboxes.bmp to Win9x style
14 + color and transparent mask
15*/
16
17#include <string.h>
18#include <stdlib.h>
19
20#include "winuser.h"
21#include "winbase.h"
22#include "controls.h"
23#include "button.h"
24#include <misc.h>
25
26//Prototypes
27
28static void PaintGrayOnGray(HDC hDC,HFONT hFont,RECT *rc,char *text,UINT format);
29
30static void PB_Paint(HWND hwnd,HDC hDC,WORD action);
31static void CB_Paint(HWND hwnd,HDC hDC,WORD action);
32static void GB_Paint(HWND hwnd,HDC hDC,WORD action);
33static void UB_Paint(HWND hwnd,HDC hDC,WORD action);
34static void OB_Paint(HWND hwnd,HDC hDC,WORD action);
35static void BUTTON_CheckAutoRadioButton(HWND hwnd);
36static void BUTTON_DrawPushButton(HWND hwnd,HDC hDC,WORD action,BOOL pushedState);
37static LRESULT BUTTON_LButtonDown(HWND hwnd,WPARAM wParam,LPARAM lParam);
38
39#define MAX_BTN_TYPE 12
40
41static const WORD maxCheckState[MAX_BTN_TYPE] =
42{
43 BUTTON_UNCHECKED, /* BS_PUSHBUTTON */
44 BUTTON_UNCHECKED, /* BS_DEFPUSHBUTTON */
45 BUTTON_CHECKED, /* BS_CHECKBOX */
46 BUTTON_CHECKED, /* BS_AUTOCHECKBOX */
47 BUTTON_CHECKED, /* BS_RADIOBUTTON */
48 BUTTON_3STATE, /* BS_3STATE */
49 BUTTON_3STATE, /* BS_AUTO3STATE */
50 BUTTON_UNCHECKED, /* BS_GROUPBOX */
51 BUTTON_UNCHECKED, /* BS_USERBUTTON */
52 BUTTON_CHECKED, /* BS_AUTORADIOBUTTON */
53 BUTTON_UNCHECKED, /* Not defined */
54 BUTTON_UNCHECKED /* BS_OWNERDRAW */
55};
56
57typedef void (*pfPaint)(HWND hwnd,HDC hdc,WORD action);
58
59static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
60{
61 PB_Paint, /* BS_PUSHBUTTON */
62 PB_Paint, /* BS_DEFPUSHBUTTON */
63 CB_Paint, /* BS_CHECKBOX */
64 CB_Paint, /* BS_AUTOCHECKBOX */
65 CB_Paint, /* BS_RADIOBUTTON */
66 CB_Paint, /* BS_3STATE */
67 CB_Paint, /* BS_AUTO3STATE */
68 GB_Paint, /* BS_GROUPBOX */
69 UB_Paint, /* BS_USERBUTTON */
70 CB_Paint, /* BS_AUTORADIOBUTTON */
71 NULL, /* Not defined */
72 OB_Paint /* BS_OWNERDRAW */
73};
74
75#define PAINT_BUTTON(hwnd,style,action) \
76 if (btnPaintFunc[style]) { \
77 HDC hdc = GetDC(hwnd); \
78 (btnPaintFunc[style])(hwnd,hdc,action); \
79 ReleaseDC(hwnd,hdc); }
80
81#define BUTTON_SEND_CTLCOLOR(hwnd,hdc) \
82 SendMessageA( GetParent(hwnd), WM_CTLCOLORBTN, \
83 (hdc),hwnd)
84
85static HBITMAP hbitmapCheckBoxes = 0;
86static WORD checkBoxWidth = 0, checkBoxHeight = 0;
87
88
89static LRESULT BUTTON_GetDlgCode(HWND hwnd,WPARAM wParam,LPARAM lParam)
90{
91 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
92
93 switch (dwStyle & 0x0f)
94 {
95 case BS_AUTOCHECKBOX:
96 case BS_CHECKBOX:
97 return DLGC_WANTCHARS | DLGC_BUTTON;
98
99 case BS_PUSHBUTTON:
100 return DLGC_UNDEFPUSHBUTTON;
101
102 case BS_DEFPUSHBUTTON:
103 return DLGC_DEFPUSHBUTTON;
104
105 case BS_AUTORADIOBUTTON:
106 case BS_RADIOBUTTON:
107 return DLGC_RADIOBUTTON;
108
109 case BS_GROUPBOX:;
110 return DLGC_STATIC;
111
112 default:
113 return DLGC_BUTTON;
114 }
115}
116
117static LRESULT BUTTON_Enable(HWND hwnd,WPARAM wParam,LPARAM lParam)
118{
119 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
120
121// PAINT_BUTTON(hwnd,dwStyle & 0x0f,ODA_DRAWENTIRE);
122 //SvL: 09/10/99 Force it to redraw properly
123 InvalidateRect( hwnd, NULL, FALSE );
124
125 return 0;
126}
127
128static LRESULT BUTTON_Create(HWND hwnd,WPARAM wParam,LPARAM lParam)
129{
130 BUTTONINFO* infoPtr;
131 DWORD style = GetWindowLongA(hwnd,GWL_STYLE) & 0x0f;
132
133 if (!hbitmapCheckBoxes)
134 {
135 BITMAP bmp;
136 HINSTANCE hinst;
137
138 //CB: Open32 hack to load our own bitmap
139 hinst = LoadLibraryA("USER32.DLL");
140 hbitmapCheckBoxes = NativeLoadBitmap(hinst,MAKEINTRESOURCEA(OBM_CHECKBOXES));
141 FreeLibrary(hinst);
142 if (GetObjectA(hbitmapCheckBoxes,sizeof(bmp),&bmp))
143 {
144 checkBoxWidth = bmp.bmWidth / 4;
145 checkBoxHeight = bmp.bmHeight / 3;
146 } else checkBoxWidth = checkBoxHeight = 0;
147 }
148 if (style < 0L || style >= MAX_BTN_TYPE) return -1; /* abort */
149
150 infoPtr = (BUTTONINFO*)malloc(sizeof(BUTTONINFO));
151 infoPtr->state = BUTTON_UNCHECKED;
152 infoPtr->hFont = 0;
153 infoPtr->hImage = NULL;
154 SetInfoPtr(hwnd,(DWORD)infoPtr);
155
156 return 0;
157}
158
159static LRESULT BUTTON_Destroy(HWND hwnd,WPARAM wParam,LPARAM lParam)
160{
161 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
162
163 free(infoPtr);
164
165 return 0;
166}
167
168static LRESULT BUTTON_EraseBkgnd(HWND hwnd,WPARAM wParam,LPARAM lParam)
169{
170 return 1;
171}
172
173static LRESULT BUTTON_Paint(HWND hwnd,WPARAM wParam,LPARAM lParam)
174{
175 DWORD style = GetWindowLongA(hwnd,GWL_STYLE) & 0x0f;
176
177 if (btnPaintFunc[style])
178 {
179 PAINTSTRUCT ps;
180
181 HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd,&ps);
182 SetBkMode(hdc,OPAQUE);
183 (btnPaintFunc[style])(hwnd,hdc,ODA_DRAWENTIRE);
184 if(!wParam) EndPaint(hwnd,&ps);
185 }
186
187 return 0;
188}
189
190static LRESULT BUTTON_LButtonDblClk(HWND hwnd,WPARAM wParam,LPARAM lParam)
191{
192 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
193 DWORD style = dwStyle & 0x0f;
194
195 if(dwStyle & BS_NOTIFY || style == BS_RADIOBUTTON ||
196 style == BS_USERBUTTON || style == BS_OWNERDRAW)
197 SendMessageA(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetWindowLongA(hwnd,GWL_ID),BN_DOUBLECLICKED),hwnd);
198 else BUTTON_LButtonDown(hwnd,wParam,lParam);
199
200 return 0;
201}
202
203static LRESULT BUTTON_LButtonDown(HWND hwnd,WPARAM wParam,LPARAM lParam)
204{
205 SetCapture(hwnd);
206 SetFocus(hwnd);
207 SendMessageA(hwnd,BM_SETSTATE,TRUE,0);
208
209 return 0;
210}
211
212static LRESULT BUTTON_LButtonUp(HWND hwnd,WPARAM wParam,LPARAM lParam)
213{
214 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
215 RECT rect;
216 POINT pt;
217
218 pt.x = LOWORD(lParam);
219 pt.y = HIWORD(lParam);
220
221 ReleaseCapture();
222 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) return 0;
223 SendMessageA(hwnd,BM_SETSTATE,FALSE,0);
224 GetClientRect(hwnd,&rect);
225 if (PtInRect(&rect,pt))
226 {
227 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
228 DWORD id = GetWindowLongA(hwnd,GWL_ID);
229
230 switch(dwStyle & 0x0f)
231 {
232 case BS_AUTOCHECKBOX:
233 SendMessageA(hwnd,BM_SETCHECK,!(infoPtr->state & BUTTON_CHECKED),0);
234 break;
235 case BS_AUTORADIOBUTTON:
236 SendMessageA(hwnd,BM_SETCHECK,TRUE,0);
237 break;
238 case BS_AUTO3STATE:
239 SendMessageA(hwnd,BM_SETCHECK,
240 (infoPtr->state & BUTTON_3STATE) ? 0 :
241 ((infoPtr->state & 3)+1),0);
242 break;
243 }
244 SendMessageA(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(id,BN_CLICKED),hwnd);
245 }
246
247 return 0;
248}
249
250static LRESULT BUTTON_MouseMove(HWND hwnd,WPARAM wParam,LPARAM lParam)
251{
252 if (GetCapture() == hwnd)
253 {
254 RECT rect;
255 POINT pt;
256
257 pt.x = LOWORD(lParam);
258 pt.y = HIWORD(lParam);
259
260 GetClientRect(hwnd,&rect);
261 SendMessageA(hwnd,BM_SETSTATE,PtInRect(&rect,pt),0);
262 }
263
264 return 0;
265}
266
267static LRESULT BUTTON_NCHitTest(HWND hwnd,WPARAM wParam,LPARAM lParam)
268{
269 DWORD style = GetWindowLongA(hwnd,GWL_STYLE) & 0x0f;
270
271 if (style == BS_GROUPBOX) return HTTRANSPARENT;
272
273 return DefWindowProcA(hwnd,WM_NCHITTEST,wParam,lParam);
274}
275
276static LRESULT BUTTON_SetText(HWND hwnd,WPARAM wParam,LPARAM lParam)
277{
278 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
279
280 DefWindowProcA(hwnd,WM_SETTEXT,wParam,lParam);
281 if (dwStyle & WS_VISIBLE) PAINT_BUTTON(hwnd,dwStyle & 0x0f,ODA_DRAWENTIRE);
282
283 return 0;
284}
285
286static LRESULT BUTTON_SetFont(HWND hwnd,WPARAM wParam,LPARAM lParam)
287{
288 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
289 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
290
291 infoPtr->hFont = (HFONT)wParam;
292 if (lParam && (dwStyle & WS_VISIBLE)) PAINT_BUTTON(hwnd,dwStyle & 0x0f,ODA_DRAWENTIRE);
293
294 return 0;
295}
296
297static LRESULT BUTTON_GetFont(HWND hwnd,WPARAM wParam,LPARAM lParam)
298{
299 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
300
301 return infoPtr->hFont;
302}
303
304static LRESULT BUTTON_KeyDown(HWND hwnd,WPARAM wParam,LPARAM lParam)
305{
306 if (wParam == VK_SPACE)
307 {
308 SendMessageA(hwnd,BM_SETSTATE,TRUE,0);
309 SetFocus(hwnd);
310 SetCapture(hwnd);
311 }
312
313 return 0;
314}
315
316static LRESULT BUTTON_KeyUp(HWND hwnd,WPARAM wParam,LPARAM lParam)
317{
318 if (wParam == VK_SPACE)
319 {
320 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
321 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
322 DWORD id = GetWindowLongA(hwnd,GWL_ID);
323
324 ReleaseCapture();
325 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) return 0;
326 SendMessageA(hwnd,BM_SETSTATE,FALSE,0);
327
328 switch(dwStyle & 0x0f)
329 {
330 case BS_AUTOCHECKBOX:
331 SendMessageA(hwnd,BM_SETCHECK,!(infoPtr->state & BUTTON_CHECKED),0);
332 break;
333 case BS_AUTORADIOBUTTON:
334 SendMessageA(hwnd,BM_SETCHECK,TRUE,0);
335 break;
336 case BS_AUTO3STATE:
337 SendMessageA(hwnd,BM_SETCHECK,
338 (infoPtr->state & BUTTON_3STATE) ? 0 :
339 ((infoPtr->state & 3)+1),0);
340 break;
341 }
342 SendMessageA(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(id,BN_CLICKED),hwnd);
343 } else if (wParam != VK_TAB) ReleaseCapture();
344
345 return 0;
346}
347
348static LRESULT BUTTON_SysKeyUp(HWND hwnd,WPARAM wParam,LPARAM lParam)
349{
350 if (wParam != VK_TAB) ReleaseCapture();
351
352 return 0;
353}
354
355static LRESULT BUTTON_SetFocus(HWND hwnd,WPARAM wParam,LPARAM lParam)
356{
357 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
358 DWORD style = GetWindowLongA(hwnd,GWL_STYLE) & 0x0f;
359
360 if ((style == BS_AUTORADIOBUTTON || style == BS_RADIOBUTTON) &&
361 (GetCapture() != hwnd) && !(SendMessageA(hwnd,BM_GETCHECK,0,0) & BST_CHECKED))
362 {
363 /* The notification is sent when the button (BS_AUTORADIOBUTTON)
364 is unckecked and the focus was not given by a mouse click. */
365 if (style == BS_AUTORADIOBUTTON) SendMessageA(hwnd,BM_SETCHECK,TRUE,0);
366 SendMessageA(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetWindowLongA(hwnd,GWL_ID),BN_CLICKED),hwnd);
367 }
368
369 infoPtr->state |= BUTTON_HASFOCUS;
370 PAINT_BUTTON(hwnd,style,ODA_FOCUS);
371
372 return 0;
373}
374
375static LRESULT BUTTON_KillFocus(HWND hwnd,WPARAM wParam,LPARAM lParam)
376{
377 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
378 DWORD style = GetWindowLongA(hwnd,GWL_STYLE) & 0x0f;
379
380 if (infoPtr->state & BUTTON_HASFOCUS)
381 {
382 infoPtr->state &= ~BUTTON_HASFOCUS;
383 PAINT_BUTTON(hwnd,style,ODA_FOCUS);
384 InvalidateRect(hwnd,NULL,TRUE);
385 }
386
387 return 0;
388}
389
390static LRESULT BUTTON_SysColorChange(HWND hwnd,WPARAM wParam,LPARAM lParam)
391{
392 InvalidateRect(hwnd,NULL,FALSE);
393
394 return 0;
395}
396
397static LRESULT BUTTON_Click(HWND hwnd,WPARAM wParam,LPARAM lParam)
398{
399 RECT rect;
400 LPARAM point;
401
402 GetClientRect(hwnd,&rect);
403 point = MAKELPARAM(rect.right/2,rect.bottom/2);
404 SendMessageA(hwnd,WM_LBUTTONDOWN,MK_LBUTTON,point);
405 Sleep(100);
406 SendMessageA(hwnd,WM_LBUTTONUP,0,point);
407
408 return 0;
409}
410
411static LRESULT BUTTON_SetStyle(HWND hwnd,WPARAM wParam,LPARAM lParam)
412{
413 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
414
415 if ((wParam & 0x0f) >= MAX_BTN_TYPE) return 0;
416 dwStyle = (dwStyle & 0xfffffff0) | (wParam & 0x0000000f);
417 SetWindowLongA(hwnd,GWL_STYLE,dwStyle);
418 PAINT_BUTTON(hwnd,dwStyle & 0x0f,ODA_DRAWENTIRE);
419
420 return 0;
421}
422
423static LRESULT BUTTON_SetImage(HWND hwnd,WPARAM wParam,LPARAM lParam)
424{
425 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
426 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
427 HANDLE oldHbitmap = infoPtr->hImage;
428
429 if (dwStyle & BS_BITMAP || dwStyle & BS_ICON) infoPtr->hImage = (HANDLE)lParam;
430
431 return oldHbitmap;
432}
433
434static LRESULT BUTTON_GetImage(HWND hwnd,WPARAM wParam,LPARAM lParam)
435{
436 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
437
438 switch(wParam)
439 {
440 case IMAGE_BITMAP:
441 return (HBITMAP)infoPtr->hImage;
442 case IMAGE_ICON:
443 return (HICON)infoPtr->hImage;
444 default:
445 return NULL;
446 }
447}
448
449static LRESULT BUTTON_GetCheck(HWND hwnd,WPARAM wParam,LPARAM lParam)
450{
451 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
452
453 return infoPtr->state & 3;
454}
455
456static LRESULT BUTTON_SetCheck(HWND hwnd,WPARAM wParam,LPARAM lParam)
457{
458 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
459 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
460 DWORD style = dwStyle & 0x0f;
461
462 if (wParam > maxCheckState[style]) wParam = maxCheckState[style];
463 if ((infoPtr->state & 3) != wParam)
464 {
465 if ((style == BS_RADIOBUTTON) || (style == BS_AUTORADIOBUTTON))
466 {
467 DWORD oldStyle = dwStyle;
468
469 if (wParam)
470 dwStyle |= WS_TABSTOP;
471 else
472 dwStyle &= ~WS_TABSTOP;
473
474 //if (oldStyle != dwStyle) SetWindowLongA(hwnd,GWL_STYLE,dwStyle);
475 }
476 infoPtr->state = (infoPtr->state & ~3) | wParam;
477 PAINT_BUTTON(hwnd,style,ODA_SELECT);
478 }
479 if ((style == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED))
480 BUTTON_CheckAutoRadioButton(hwnd);
481
482 return 0;
483}
484
485static LRESULT BUTTON_GetState(HWND hwnd,WPARAM wParam,LPARAM lParam)
486{
487 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
488
489 return infoPtr->state;
490}
491
492static LRESULT BUTTON_SetState(HWND hwnd,WPARAM wParam,LPARAM lParam)
493{
494 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
495 DWORD style = GetWindowLongA(hwnd,GWL_STYLE) & 0x0f;
496
497 if (wParam)
498 {
499 if (infoPtr->state & BUTTON_HIGHLIGHTED) return 0;
500 infoPtr->state |= BUTTON_HIGHLIGHTED;
501 } else
502 {
503 if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) return 0;
504 infoPtr->state &= ~BUTTON_HIGHLIGHTED;
505 }
506 PAINT_BUTTON(hwnd,style,ODA_SELECT);
507
508 return 0;
509}
510
511/***********************************************************************
512 * ButtonWndProc
513 */
514static
515LRESULT WINAPI ButtonWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
516{
517 switch (uMsg)
518 {
519 case WM_GETDLGCODE:
520 return BUTTON_GetDlgCode(hwnd,wParam,lParam);
521
522 case WM_ENABLE:
523 return BUTTON_Enable(hwnd,wParam,lParam);
524
525 case WM_CREATE:
526 return BUTTON_Create(hwnd,wParam,lParam);
527
528 case WM_DESTROY:
529 return BUTTON_Destroy(hwnd,wParam,lParam);
530
531 case WM_ERASEBKGND:
532 return BUTTON_EraseBkgnd(hwnd,wParam,lParam);
533
534 case WM_PAINT:
535 return BUTTON_Paint(hwnd,wParam,lParam);
536
537 case WM_LBUTTONDBLCLK:
538 return BUTTON_LButtonDblClk(hwnd,wParam,lParam);
539
540 case WM_LBUTTONDOWN:
541 return BUTTON_LButtonDown(hwnd,wParam,lParam);
542
543 case WM_LBUTTONUP:
544 return BUTTON_LButtonUp(hwnd,wParam,lParam);
545
546 case WM_MOUSEMOVE:
547 return BUTTON_MouseMove(hwnd,wParam,lParam);
548
549 case WM_NCHITTEST:
550 return BUTTON_NCHitTest(hwnd,wParam,lParam);
551
552 case WM_SETTEXT:
553 return BUTTON_SetText(hwnd,wParam,lParam);
554
555 case WM_SETFONT:
556 return BUTTON_SetFont(hwnd,wParam,lParam);
557
558 case WM_GETFONT:
559 return BUTTON_GetFont(hwnd,wParam,lParam);
560
561 case WM_KEYDOWN:
562 return BUTTON_KeyDown(hwnd,wParam,lParam);
563
564 case WM_KEYUP:
565 return BUTTON_KeyUp(hwnd,wParam,lParam);
566
567 case WM_SYSKEYUP:
568 return BUTTON_SysKeyUp(hwnd,wParam,lParam);
569
570 case WM_SETFOCUS:
571 return BUTTON_SetFocus(hwnd,wParam,lParam);
572
573 case WM_KILLFOCUS:
574 return BUTTON_KillFocus(hwnd,wParam,lParam);
575
576 case WM_SYSCOLORCHANGE:
577 return BUTTON_SysColorChange(hwnd,wParam,lParam);
578
579 case BM_CLICK:
580 return BUTTON_Click(hwnd,wParam,lParam);
581
582 case BM_SETSTYLE:
583 return BUTTON_SetStyle(hwnd,wParam,lParam);
584
585 case BM_SETIMAGE:
586 return BUTTON_SetImage(hwnd,wParam,lParam);
587
588 case BM_GETIMAGE:
589 return BUTTON_GetImage(hwnd,wParam,lParam);
590
591 case BM_GETCHECK:
592 return BUTTON_GetCheck(hwnd,wParam,lParam);
593
594 case BM_SETCHECK:
595 return BUTTON_SetCheck(hwnd,wParam,lParam);
596
597 case BM_GETSTATE:
598 return BUTTON_GetState(hwnd,wParam,lParam);
599
600 case BM_SETSTATE:
601 return BUTTON_SetState(hwnd,wParam,lParam);
602
603 default:
604 return DefWindowProcA(hwnd,uMsg,wParam,lParam);
605 }
606
607 return 0;
608}
609
610
611/**********************************************************************
612 * Push Button Functions
613 */
614static void PB_Paint( HWND hwnd, HDC hDC, WORD action )
615{
616 BUTTONINFO *infoPtr = (BUTTONINFO *)GetInfoPtr(hwnd);
617 BOOL bHighLighted = (infoPtr->state & BUTTON_HIGHLIGHTED);
618
619 /*
620 * Delegate this to the more generic pushbutton painting
621 * method.
622 */
623 BUTTON_DrawPushButton(hwnd,
624 hDC,
625 action,
626 bHighLighted);
627}
628
629/**********************************************************************
630 * This method will actually do the drawing of the pushbutton
631 * depending on it's state and the pushedState parameter.
632 */
633static void BUTTON_DrawPushButton(
634 HWND hwnd,
635 HDC hDC,
636 WORD action,
637 BOOL pushedState )
638{
639 RECT rc, focus_rect;
640 HPEN hOldPen;
641 HBRUSH hOldBrush;
642 BUTTONINFO *infoPtr = (BUTTONINFO *)GetInfoPtr(hwnd);
643 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
644 int xBorderOffset, yBorderOffset;
645 xBorderOffset = yBorderOffset = 0;
646 INT textLen;
647 char* text;
648
649 GetClientRect( hwnd, &rc );
650
651 /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
652 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
653 BUTTON_SEND_CTLCOLOR( hwnd, hDC );
654 hOldPen = (HPEN)SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
655 hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
656 SetBkMode(hDC, TRANSPARENT);
657
658 if ((dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
659 {
660 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
661 InflateRect( &rc, -1, -1 );
662 }
663
664 UINT uState = DFCS_BUTTONPUSH;
665
666 if (pushedState)
667 {
668 if ( (dwStyle & 0x000f) == BS_DEFPUSHBUTTON )
669 uState |= DFCS_FLAT;
670 else
671 uState |= DFCS_PUSHED;
672 }
673
674 DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
675 InflateRect( &rc, -2, -2 );
676
677 focus_rect = rc;
678
679 if (pushedState)
680 {
681 rc.left += 2; /* To position the text down and right */
682 rc.top += 2;
683 }
684
685
686 /* draw button label, if any:
687 *
688 * In win9x we don't show text if there is a bitmap or icon.
689 * I don't know about win31 so I leave it as it was for win31.
690 * Dennis Björklund 12 Jul, 99
691 */
692 textLen = GetWindowTextLengthA(hwnd);
693 if (textLen > 0 && (!(dwStyle & (BS_ICON|BS_BITMAP))))
694 {
695 LOGBRUSH lb;
696
697 textLen++;
698 text = (char*)malloc(textLen);
699 GetWindowTextA(hwnd,text,textLen);
700 GetObjectA( GetSysColorBrush(COLOR_BTNFACE), sizeof(lb), &lb );
701 if (dwStyle & WS_DISABLED && GetSysColor(COLOR_GRAYTEXT)==lb.lbColor)
702 {
703 dprintf(("Disable button"));
704 /* don't write gray text on gray background */
705 PaintGrayOnGray( hDC,infoPtr->hFont,&rc,text,
706 DT_CENTER | DT_VCENTER );
707 }
708 else
709 {
710 dprintf(("Enable button"));
711 SetTextColor( hDC, (dwStyle & WS_DISABLED) ?
712 GetSysColor(COLOR_GRAYTEXT) :
713 GetSysColor(COLOR_BTNTEXT) );
714 DrawTextA( hDC, text, -1, &rc,
715 DT_SINGLELINE | DT_CENTER | DT_VCENTER );
716 /* do we have the focus?
717 * Win9x draws focus last with a size prop. to the button
718 */
719 }
720 free(text);
721 }
722 if ( ((dwStyle & BS_ICON) || (dwStyle & BS_BITMAP) ) &&
723 (infoPtr->hImage != NULL) )
724 {
725 int yOffset, xOffset;
726 int imageWidth, imageHeight;
727
728 /*
729 * We extract the size of the image from the handle.
730 */
731 if (dwStyle & BS_ICON)
732 {
733 ICONINFO iconInfo;
734 BITMAP bm;
735
736 GetIconInfo((HICON)infoPtr->hImage, &iconInfo);
737 GetObjectA (iconInfo.hbmColor, sizeof(BITMAP), &bm);
738
739 imageWidth = bm.bmWidth;
740 imageHeight = bm.bmHeight;
741
742 DeleteObject(iconInfo.hbmColor);
743 DeleteObject(iconInfo.hbmMask);
744
745 }
746 else
747 {
748 BITMAP bm;
749
750 GetObjectA (infoPtr->hImage, sizeof(BITMAP), &bm);
751
752 imageWidth = bm.bmWidth;
753 imageHeight = bm.bmHeight;
754 }
755
756 /* Center the bitmap */
757 xOffset = (((rc.right - rc.left) - 2*xBorderOffset) - imageWidth ) / 2;
758 yOffset = (((rc.bottom - rc.top) - 2*yBorderOffset) - imageHeight) / 2;
759
760 /* If the image is too big for the button then create a region*/
761 if(xOffset < 0 || yOffset < 0)
762 {
763 HRGN hBitmapRgn = NULL;
764 hBitmapRgn = CreateRectRgn(
765 rc.left + xBorderOffset, rc.top +yBorderOffset,
766 rc.right - xBorderOffset, rc.bottom - yBorderOffset);
767 SelectClipRgn(hDC, hBitmapRgn);
768 DeleteObject(hBitmapRgn);
769 }
770
771 /* Let minimum 1 space from border */
772 xOffset++, yOffset++;
773
774 /*
775 * Draw the image now.
776 */
777 if (dwStyle & BS_ICON)
778 {
779 DrawIcon(hDC,
780 rc.left + xOffset, rc.top + yOffset,
781 (HICON)infoPtr->hImage);
782 }
783 else
784 {
785 HDC hdcMem;
786
787 hdcMem = CreateCompatibleDC (hDC);
788 SelectObject (hdcMem, (HBITMAP)infoPtr->hImage);
789 BitBlt(hDC,
790 rc.left + xOffset,
791 rc.top + yOffset,
792 imageWidth, imageHeight,
793 hdcMem, 0, 0, SRCCOPY);
794
795 DeleteDC (hdcMem);
796 }
797
798 if(xOffset < 0 || yOffset < 0)
799 {
800 SelectClipRgn(hDC, NULL);
801 }
802 }
803
804 if (infoPtr->state & BUTTON_HASFOCUS)
805 {
806 InflateRect( &focus_rect, -1, -1 );
807 DrawFocusRect( hDC, &focus_rect );
808 }
809
810
811 SelectObject( hDC, hOldPen );
812 SelectObject( hDC, hOldBrush );
813}
814
815/**********************************************************************
816 * PB_Paint & CB_Paint sub function [internal]
817 * Paint text using a raster brush to avoid gray text on gray
818 * background. 'format' can be a combination of DT_CENTER and
819 * DT_VCENTER to use this function in both PB_PAINT and
820 * CB_PAINT. - Dirk Thierbach
821 *
822 * FIXME: This and TEXT_GrayString should be eventually combined,
823 * so calling one common function from PB_Paint, CB_Paint and
824 * TEXT_GrayString will be enough. Also note that this
825 * function ignores the CACHE_GetPattern funcs.
826 */
827
828static void PaintGrayOnGray(HDC hDC,HFONT hFont,RECT *rc,char *text,
829 UINT format)
830{
831/* This is the standard gray on gray pattern:
832 static const WORD Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55};
833*/
834/* This pattern gives better readability with X Fonts.
835 FIXME: Maybe the user should be allowed to decide which he wants. */
836 static const WORD Pattern[] = {0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF};
837
838 HBITMAP hbm = CreateBitmap( 8, 8, 1, 1, Pattern );
839 HDC hdcMem = CreateCompatibleDC(hDC);
840 HBITMAP hbmMem;
841 HBRUSH hBr;
842 RECT rect,rc2;
843
844 rect=*rc;
845 DrawTextA( hDC, text, -1, &rect, DT_SINGLELINE | DT_CALCRECT);
846 /* now text width and height are in rect.right and rect.bottom */
847 rc2=rect;
848 rect.left = rect.top = 0; /* drawing pos in hdcMem */
849 if (format & DT_CENTER) rect.left=(rc->right-rect.right)/2;
850 if (format & DT_VCENTER) rect.top=(rc->bottom-rect.bottom)/2;
851 hbmMem = CreateCompatibleBitmap( hDC,rect.right,rect.bottom );
852 SelectObject( hdcMem, hbmMem);
853 PatBlt( hdcMem,0,0,rect.right,rect.bottom,WHITENESS);
854 /* will be overwritten by DrawText, but just in case */
855 if (hFont) SelectObject( hdcMem, hFont);
856 DrawTextA( hdcMem, text, -1, &rc2, DT_SINGLELINE);
857 /* After draw: foreground = 0 bits, background = 1 bits */
858 hBr = SelectObject( hdcMem, CreatePatternBrush(hbm) );
859 DeleteObject( hbm );
860 PatBlt( hdcMem,0,0,rect.right,rect.bottom,0xAF0229);
861 /* only keep the foreground bits where pattern is 1 */
862 DeleteObject( SelectObject( hdcMem,hBr) );
863 BitBlt(hDC,rect.left,rect.top,rect.right,rect.bottom,hdcMem,0,0,SRCAND);
864 /* keep the background of the dest */
865 DeleteDC( hdcMem);
866 DeleteObject( hbmMem );
867}
868
869
870/**********************************************************************
871 * Check Box & Radio Button Functions
872 */
873
874static void CB_Paint(HWND hwnd,HDC hDC,WORD action)
875{
876 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
877 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
878 RECT rbox, rtext, client;
879 HBRUSH hBrush;
880 int textLen, delta;
881 char* text = NULL;
882
883 /*
884 * if the button has a bitmap/icon, draw a normal pushbutton
885 * instead of a radion button.
886 */
887 if (infoPtr->hImage!=NULL)
888 {
889 BOOL bHighLighted = ((infoPtr->state & BUTTON_HIGHLIGHTED) ||
890 (infoPtr->state & BUTTON_CHECKED));
891
892 BUTTON_DrawPushButton(hwnd,
893 hDC,
894 action,
895 bHighLighted);
896 return;
897 }
898
899 textLen = 0;
900 GetClientRect(hwnd, &client);
901 rbox = rtext = client;
902
903 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
904
905 /* Something is still not right, checkboxes (and edit controls)
906 * in wsping32 have white backgrounds instead of dark grey.
907 * BUTTON_SEND_CTLCOLOR() is even worse since it returns 0 in this
908 * particular case and the background is not painted at all.
909 */
910 //SvL: 20/09/99: This works well for us. Now the background of
911 // the dialog button strings in Solitaire is gray
912 SendMessageA(GetParent(hwnd),WM_CTLCOLORBTN,hDC,hwnd);
913
914 hBrush = GetSysColorBrush(COLOR_BTNFACE);
915
916 if (dwStyle & BS_LEFTTEXT)
917 {
918 /* magic +4 is what CTL3D expects */
919
920 rtext.right -= checkBoxWidth + 4;
921 rbox.left = rbox.right - checkBoxWidth;
922 }
923 else
924 {
925 rtext.left += checkBoxWidth + 4;
926 rbox.right = checkBoxWidth;
927 }
928
929 /* Draw the check-box bitmap */
930
931 textLen = GetWindowTextLengthA(hwnd);
932 if (textLen > 0)
933 {
934 textLen++;
935 text = (char*)malloc(textLen);
936 GetWindowTextA(hwnd,text,textLen);
937 }
938 if (action == ODA_DRAWENTIRE || action == ODA_SELECT)
939 {
940 UINT state;
941
942 if (((dwStyle & 0x0f) == BS_RADIOBUTTON) ||
943 ((dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) state = DFCS_BUTTONRADIO;
944 else if (infoPtr->state & BUTTON_3STATE) state = DFCS_BUTTON3STATE;
945 else state = DFCS_BUTTONCHECK;
946
947 if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) state |= DFCS_CHECKED;
948
949 if (infoPtr->state & BUTTON_HIGHLIGHTED) state |= DFCS_PUSHED;
950
951 if (dwStyle & WS_DISABLED) state |= DFCS_INACTIVE;
952
953 DrawFrameControl( hDC, &rbox, DFC_BUTTON, state );
954
955 if( text && action != ODA_SELECT )
956 {
957 if (dwStyle & WS_DISABLED &&
958 GetSysColor(COLOR_GRAYTEXT) == GetBkColor(hDC)) {
959 /* don't write gray text on gray background */
960 PaintGrayOnGray( hDC, infoPtr->hFont, &rtext, text,
961 DT_VCENTER);
962 } else {
963 if (dwStyle & WS_DISABLED)
964 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
965 DrawTextA( hDC, text, -1, &rtext,
966 DT_SINGLELINE | DT_VCENTER );
967 }
968 }
969 }
970
971 if ((action == ODA_FOCUS) ||
972 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
973 {
974 /* again, this is what CTL3D expects */
975
976 SetRectEmpty(&rbox);
977 if(textLen > 0)
978 DrawTextA( hDC, text, -1, &rbox,
979 DT_SINGLELINE | DT_CALCRECT );
980 textLen = rbox.bottom - rbox.top;
981 delta = ((rtext.bottom - rtext.top) - textLen)/2;
982 rbox.bottom = (rbox.top = rtext.top + delta - 1) + textLen + 2;
983 textLen = rbox.right - rbox.left;
984 rbox.right = (rbox.left += --rtext.left) + textLen + 2;
985 IntersectRect(&rbox, &rbox, &rtext);
986 DrawFocusRect( hDC, &rbox );
987 }
988 if (text) free(text);
989}
990
991
992/**********************************************************************
993 * BUTTON_CheckAutoRadioButton
994 *
995 * wndPtr is checked, uncheck every other auto radio button in group
996 */
997static void BUTTON_CheckAutoRadioButton(HWND hwnd)
998{
999 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
1000 HWND parent, sibling, start;
1001
1002 if (!(dwStyle & WS_CHILD)) return;
1003 parent = GetParent(hwnd);
1004 /* assure that starting control is not disabled or invisible */
1005 start = sibling = GetNextDlgGroupItem( parent, hwnd, TRUE );
1006 do
1007 {
1008 if (!sibling) break;
1009 if ((hwnd != sibling) &&
1010 ((GetWindowLongA(sibling,GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON))
1011 SendMessageA( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 );
1012 sibling = GetNextDlgGroupItem( parent, sibling, FALSE );
1013 } while (sibling != start);
1014}
1015
1016
1017/**********************************************************************
1018 * Group Box Functions
1019 */
1020
1021static void GB_Paint(HWND hwnd,HDC hDC,WORD action)
1022{
1023 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
1024 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
1025 RECT rc, rcFrame;
1026 TEXTMETRICA tm;
1027 INT textLen;
1028 char* text;
1029
1030 if (action != ODA_DRAWENTIRE) return;
1031
1032 SendMessageA(GetParent(hwnd),WM_CTLCOLORBTN,hDC,hwnd);
1033
1034 GetClientRect(hwnd,&rc);
1035
1036 rcFrame = rc;
1037
1038 if (infoPtr->hFont)
1039 SelectObject (hDC, infoPtr->hFont);
1040 GetTextMetricsA (hDC, &tm);
1041 rcFrame.top += (tm.tmHeight / 2) - 1;
1042 DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT);
1043
1044 textLen = GetWindowTextLengthA(hwnd);
1045 if (textLen > 0)
1046 {
1047 textLen++;
1048 text = (char*)malloc(textLen);
1049 GetWindowTextA(hwnd,text,textLen);
1050 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
1051 if (dwStyle & WS_DISABLED)
1052 SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
1053 rc.left += 10;
1054 DrawTextA( hDC, text, -1, &rc, DT_SINGLELINE | DT_NOCLIP );
1055 free(text);
1056 }
1057}
1058
1059
1060/**********************************************************************
1061 * User Button Functions
1062 */
1063
1064static void UB_Paint(HWND hwnd,HDC hDC,WORD action)
1065{
1066 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
1067 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
1068 RECT rc;
1069 HBRUSH hBrush;
1070 if (action == ODA_SELECT) return;
1071
1072 GetClientRect(hwnd,&rc);
1073
1074 if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
1075 hBrush = GetSysColorBrush(COLOR_BTNFACE);
1076
1077 FillRect( hDC, &rc, hBrush );
1078 if ((action == ODA_FOCUS) ||
1079 ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
1080 DrawFocusRect( hDC, &rc );
1081}
1082
1083
1084/**********************************************************************
1085 * Ownerdrawn Button Functions
1086 */
1087
1088static void OB_Paint(HWND hwnd,HDC hDC,WORD action)
1089{
1090 BUTTONINFO* infoPtr = (BUTTONINFO*)GetInfoPtr(hwnd);
1091 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
1092 DRAWITEMSTRUCT dis;
1093
1094 dis.CtlType = ODT_BUTTON;
1095 dis.CtlID = GetWindowLongA(hwnd,GWL_ID);
1096 dis.itemID = 0;
1097 dis.itemAction = action;
1098 dis.itemState = ((infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) |
1099 ((infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) |
1100 ((dwStyle & WS_DISABLED) ? ODS_DISABLED : 0);
1101 dis.hwndItem = hwnd;
1102 dis.hDC = hDC;
1103 dis.itemData = 0;
1104 GetClientRect( hwnd, &dis.rcItem );
1105
1106 SetBkColor( hDC, GetSysColor( COLOR_BTNFACE ) );
1107 FillRect( hDC, &dis.rcItem, GetSysColorBrush( COLOR_BTNFACE ) );
1108
1109 SendMessageA( GetParent(hwnd), WM_DRAWITEM,
1110 GetWindowLongA(hwnd,GWL_ID), (LPARAM)&dis );
1111}
1112
1113BOOL BUTTON_Register()
1114{
1115 WNDCLASSA wndClass;
1116
1117 if (GlobalFindAtomA(BUTTONCLASSNAME)) return FALSE;
1118
1119 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
1120 wndClass.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW | CS_PARENTDC | CS_DBLCLKS;
1121 wndClass.lpfnWndProc = (WNDPROC)ButtonWndProc;
1122 wndClass.cbClsExtra = 0;
1123 wndClass.cbWndExtra = sizeof(BUTTONINFO);
1124 wndClass.hCursor = LoadCursorA(0,IDC_ARROWA);
1125 wndClass.hbrBackground = (HBRUSH)0;
1126 wndClass.lpszClassName = BUTTONCLASSNAME;
1127
1128 return RegisterClassA(&wndClass);
1129}
1130
1131BOOL BUTTON_Unregister()
1132{
1133 if (GlobalFindAtomA(BUTTONCLASSNAME))
1134 return UnregisterClassA(BUTTONCLASSNAME,(HINSTANCE)NULL);
1135 else return FALSE;
1136}
Note: See TracBrowser for help on using the repository browser.