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

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

Lots of changes again

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