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

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

button, static, scroll and dialog fixes

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