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

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

transparent text

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