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

Last change on this file since 1203 was 1203, checked in by cbratschi, 26 years ago

merged with WINE, other fixes

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