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

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

CVS headers added

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