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

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

Button from WINE, first user32.cpp work

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