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

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

resource and other fixes

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