source: trunk/src/user32/new/button.cpp@ 402

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

keyboard support and other updates

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