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

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

Native resource management

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