Newer
Older
* Copyright (C) 1993 Johannes Ruscheinski
* Copyright (C) 1993 David Metcalfe
#include <stdlib.h> /* for abs() */
#include "winbase.h"
#include "windef.h"
#include "wingdi.h"
#include "controls.h"
#include "user.h"
/* Note: under MS-Windows, state is a BYTE and this structure is
* only 3 bytes long. I don't think there are programs out there
* broken enough to rely on this :-)
*/
typedef struct
{
WORD state; /* Current state */
HFONT16 hFont; /* Button font (or 0 for system font) */
HANDLE hImage; /* Handle to the image or the icon */
} BUTTONINFO;
/* Button state values */
#define BUTTON_UNCHECKED 0x00
#define BUTTON_CHECKED 0x01
#define BUTTON_3STATE 0x02
#define BUTTON_HIGHLIGHTED 0x04
#define BUTTON_HASFOCUS 0x08
#define BUTTON_NSTATES 0x0F
/* undocumented flags */
#define BUTTON_BTNPRESSED 0x40
#define BUTTON_UNKNOWN2 0x20
#define BUTTON_UNKNOWN3 0x10
static void PB_Paint( WND *wndPtr, HDC hDC, WORD action );
static void CB_Paint( WND *wndPtr, HDC hDC, WORD action );
static void GB_Paint( WND *wndPtr, HDC hDC, WORD action );
static void UB_Paint( WND *wndPtr, HDC hDC, WORD action );
static void OB_Paint( WND *wndPtr, HDC hDC, WORD action );
static void BUTTON_CheckAutoRadioButton( WND *wndPtr );
static void BUTTON_DrawPushButton( WND *wndPtr, HDC hDC, WORD action, BOOL pushedState);
static LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
static LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
{
BUTTON_UNCHECKED, /* BS_PUSHBUTTON */
BUTTON_UNCHECKED, /* BS_DEFPUSHBUTTON */
BUTTON_CHECKED, /* BS_CHECKBOX */
BUTTON_CHECKED, /* BS_AUTOCHECKBOX */
BUTTON_CHECKED, /* BS_RADIOBUTTON */
BUTTON_3STATE, /* BS_3STATE */
BUTTON_3STATE, /* BS_AUTO3STATE */
BUTTON_UNCHECKED, /* BS_GROUPBOX */
BUTTON_UNCHECKED, /* BS_USERBUTTON */
BUTTON_CHECKED, /* BS_AUTORADIOBUTTON */
BUTTON_UNCHECKED, /* Not defined */
BUTTON_UNCHECKED /* BS_OWNERDRAW */
};
typedef void (*pfPaint)( WND *wndPtr, HDC hdc, WORD action );
{
PB_Paint, /* BS_PUSHBUTTON */
PB_Paint, /* BS_DEFPUSHBUTTON */
CB_Paint, /* BS_CHECKBOX */
CB_Paint, /* BS_AUTOCHECKBOX */
CB_Paint, /* BS_RADIOBUTTON */
CB_Paint, /* BS_3STATE */
CB_Paint, /* BS_AUTO3STATE */
GB_Paint, /* BS_GROUPBOX */
UB_Paint, /* BS_USERBUTTON */
CB_Paint, /* BS_AUTORADIOBUTTON */
NULL, /* Not defined */
OB_Paint /* BS_OWNERDRAW */
HDC hdc = GetDC( (wndPtr)->hwndSelf ); \
ReleaseDC( (wndPtr)->hwndSelf, hdc ); }
SendMessageW( GetParent((wndPtr)->hwndSelf), WM_CTLCOLORBTN, \
static HBITMAP hbitmapCheckBoxes = 0;
static WORD checkBoxWidth = 0, checkBoxHeight = 0;
/*********************************************************************
* button class descriptor
*/
const struct builtin_class_descr BUTTON_builtin_class =
{
"Button", /* name */
CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style */
ButtonWndProcA, /* procA */
ButtonWndProcW, /* procW */
sizeof(BUTTONINFO), /* extra */
IDC_ARROWA, /* cursor */
0 /* brush */
};
/***********************************************************************
* ButtonWndProc_locked
*
* Called with window lock held.
static inline LRESULT WINAPI ButtonWndProc_locked(WND* wndPtr, UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL unicode )
RECT rect;
HWND hWnd = wndPtr->hwndSelf;
BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
LONG style = wndPtr->dwStyle & 0x0f;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
switch (uMsg)
{
case WM_GETDLGCODE:
switch(style)
{
case BS_PUSHBUTTON: return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
case BS_DEFPUSHBUTTON: return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
case BS_RADIOBUTTON:
case BS_AUTORADIOBUTTON: return DLGC_BUTTON | DLGC_RADIOBUTTON;
default: return DLGC_BUTTON;
}
case WM_ENABLE:
PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
break;
BITMAP bmp;
hbitmapCheckBoxes = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CHECKBOXES));
GetObjectW( hbitmapCheckBoxes, sizeof(bmp), &bmp );
checkBoxWidth = bmp.bmWidth / 4;
checkBoxHeight = bmp.bmHeight / 3;
}
if (style < 0L || style >= MAX_BTN_TYPE)
return -1; /* abort */
infoPtr->state = BUTTON_UNCHECKED;
infoPtr->hFont = 0;
PAINTSTRUCT ps;
HDC hdc = wParam ? (HDC)wParam : BeginPaint( hWnd, &ps );
int nOldMode = SetBkMode( hdc, OPAQUE );
(btnPaintFunc[style])( wndPtr, hdc, ODA_DRAWENTIRE );
SetBkMode(hdc, nOldMode); /* reset painting mode */
if( !wParam ) EndPaint( hWnd, &ps );
case WM_KEYDOWN:
if (wParam == VK_SPACE)
{
SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
infoPtr->state |= BUTTON_BTNPRESSED;
}
break;
if(wndPtr->dwStyle & BS_NOTIFY ||
style==BS_RADIOBUTTON ||
style==BS_USERBUTTON ||
style==BS_OWNERDRAW) {
SendMessageW( GetParent(hWnd), WM_COMMAND,
MAKEWPARAM( wndPtr->wIDmenu, BN_DOUBLECLICKED ), hWnd);
break;
}
/* fall through */
case WM_LBUTTONDOWN:
SetCapture( hWnd );
SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
infoPtr->state |= BUTTON_BTNPRESSED;
case WM_KEYUP:
if (wParam != VK_SPACE)
break;
/* fall through */
if (!(infoPtr->state & BUTTON_BTNPRESSED)) break;
infoPtr->state &= BUTTON_NSTATES;
if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) {
ReleaseCapture();
break;
}
SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 );
ReleaseCapture();
GetClientRect( hWnd, &rect );
if (uMsg == WM_KEYUP || PtInRect( &rect, pt ))
SendMessageW( hWnd, BM_SETCHECK,
SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 );
SendMessageW( hWnd, BM_SETCHECK,
(infoPtr->state & BUTTON_3STATE) ? 0 :
((infoPtr->state & 3) + 1), 0 );
SendMessageW( GetParent(hWnd), WM_COMMAND,
MAKEWPARAM( wndPtr->wIDmenu, BN_CLICKED ), hWnd);
}
break;
case WM_CAPTURECHANGED:
if (infoPtr->state & BUTTON_BTNPRESSED) {
infoPtr->state &= BUTTON_NSTATES;
if (infoPtr->state & BUTTON_HIGHLIGHTED)
SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 );
}
break;
if (GetCapture() == hWnd)
GetClientRect( hWnd, &rect );
SendMessageW( hWnd, BM_SETSTATE, PtInRect(&rect, pt), 0 );
if (unicode) DEFWND_SetTextW( wndPtr, (LPCWSTR)lParam );
else DEFWND_SetTextA( wndPtr, (LPCSTR)lParam );
if( wndPtr->dwStyle & WS_VISIBLE )
PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
return 1; /* success. FIXME: check text length */
if (lParam && (wndPtr->dwStyle & WS_VISIBLE))
PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
return infoPtr->hFont;
if ((style == BS_RADIOBUTTON || style == BS_AUTORADIOBUTTON) && (GetCapture() != hWnd) &&
!(SendMessageW(hWnd, BM_GETCHECK, 0, 0) & BST_CHECKED))
{
/* The notification is sent when the button (BS_AUTORADIOBUTTON)
is unchecked and the focus was not given by a mouse click. */
if (style == BS_AUTORADIOBUTTON)
SendMessageW( hWnd, BM_SETCHECK, BUTTON_CHECKED, 0 );
SendMessageW( GetParent(hWnd), WM_COMMAND,
MAKEWPARAM( wndPtr->wIDmenu, BN_CLICKED ), hWnd);
}
infoPtr->state |= BUTTON_HASFOCUS;
PAINT_BUTTON( wndPtr, style, ODA_FOCUS );
break;
case WM_KILLFOCUS:
infoPtr->state &= ~BUTTON_HASFOCUS;
InvalidateRect( hWnd, NULL, TRUE );
InvalidateRect( hWnd, NULL, FALSE );
case BM_SETSTYLE:
if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0)
| (wParam & 0x0000000f);
style = wndPtr->dwStyle & 0x0000000f;
/* Only redraw if lParam flag is set.*/
if (lParam)
PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
case BM_CLICK:
SendMessageW( hWnd, WM_LBUTTONDOWN, 0, 0 );
SendMessageW( hWnd, WM_LBUTTONUP, 0, 0 );
break;
/* Check that image format confirm button style */
if ((wndPtr->dwStyle & (BS_BITMAP|BS_ICON)) == BS_BITMAP)
if (wParam != (WPARAM) IMAGE_BITMAP)
return (HICON)0;
else if ((wndPtr->dwStyle & (BS_BITMAP|BS_ICON)) == BS_ICON)
{
if (wParam != (WPARAM) IMAGE_ICON)
return (HICON)0;
} else
return (HICON)0;
oldHbitmap = infoPtr->hImage;
infoPtr->hImage = (HANDLE) lParam;
InvalidateRect( hWnd, NULL, FALSE );
return oldHbitmap;
case BM_GETIMAGE:
if ((wndPtr->dwStyle & (BS_BITMAP|BS_ICON)) == BS_BITMAP)
{
if (wParam != (WPARAM) IMAGE_BITMAP)
return (HICON)0;
}
else if ((wndPtr->dwStyle & (BS_BITMAP|BS_ICON)) == BS_ICON)
{
if (wParam != (WPARAM) IMAGE_ICON)
return (HICON)0;
} else
return infoPtr->hImage;
case BM_GETCHECK:
return infoPtr->state & 3;
case BM_SETCHECK:
if (wParam > maxCheckState[style]) wParam = maxCheckState[style];
if ((infoPtr->state & 3) != wParam)
{
if ((style == BS_RADIOBUTTON) || (style == BS_AUTORADIOBUTTON))
{
if (wParam)
wndPtr->dwStyle |= WS_TABSTOP;
else
wndPtr->dwStyle &= ~WS_TABSTOP;
}
infoPtr->state = (infoPtr->state & ~3) | wParam;
PAINT_BUTTON( wndPtr, style, ODA_SELECT );
}
if ((style == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED))
BUTTON_CheckAutoRadioButton( wndPtr );
break;
case BM_GETSTATE:
return infoPtr->state;
case BM_SETSTATE:
if (wParam)
{
if (infoPtr->state & BUTTON_HIGHLIGHTED) break;
infoPtr->state |= BUTTON_HIGHLIGHTED;
}
else
{
if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
infoPtr->state &= ~BUTTON_HIGHLIGHTED;
}
PAINT_BUTTON( wndPtr, style, ODA_SELECT );
break;
case WM_NCHITTEST:
if(style == BS_GROUPBOX) return HTTRANSPARENT;
/* fall through */
return unicode ? DefWindowProcW(hWnd, uMsg, wParam, lParam) :
DefWindowProcA(hWnd, uMsg, wParam, lParam);
/***********************************************************************
* ButtonWndProcW
* The button window procedure. This is just a wrapper which locks
* the passed HWND and calls the real window procedure (with a WND*
* pointer pointing to the locked windowstructure).
*/
static LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
LRESULT res = 0;
WND *wndPtr = WIN_FindWndPtr(hWnd);
if (wndPtr)
{
res = ButtonWndProc_locked(wndPtr,uMsg,wParam,lParam,TRUE);
WIN_ReleaseWndPtr(wndPtr);
}
return res;
}
/***********************************************************************
* ButtonWndProcA
*/
static LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
LRESULT res = 0;
WND *wndPtr = WIN_FindWndPtr(hWnd);
if (wndPtr)
{
res = ButtonWndProc_locked(wndPtr,uMsg,wParam,lParam,FALSE);
WIN_ReleaseWndPtr(wndPtr);
}
return res;
}
/**********************************************************************
* Push Button Functions
*/
static void PB_Paint( WND *wndPtr, HDC hDC, WORD action )
{
BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
BOOL bHighLighted = (infoPtr->state & BUTTON_HIGHLIGHTED);
/*
* Delegate this to the more generic pushbutton painting
* method.
*/
BUTTON_DrawPushButton(wndPtr,
hDC,
action,
bHighLighted);
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
/**********************************************************************
* Convert button styles to flags used by DrawText.
* TODO: handle WS_EX_RIGHT extended style.
*/
static UINT BUTTON_BStoDT(DWORD style)
{
UINT dtStyle = DT_NOCLIP; /* We use SelectClipRgn to limit output */
/* "Convert" pushlike buttons to pushbuttons */
if (style & BS_PUSHLIKE)
style &= ~0x0F;
if (!(style & BS_MULTILINE))
dtStyle |= DT_SINGLELINE;
else
dtStyle |= DT_WORDBREAK;
switch (style & BS_CENTER)
{
case BS_LEFT: /* DT_LEFT is 0 */ break;
case BS_RIGHT: dtStyle |= DT_RIGHT; break;
case BS_CENTER: dtStyle |= DT_CENTER; break;
default:
/* Pushbutton's text is centered by default */
if ((style & 0x0F) <= BS_DEFPUSHBUTTON)
dtStyle |= DT_CENTER;
/* all other flavours have left aligned text */
}
/* DrawText ignores vertical alignment for multiline text,
* but we use these flags to align label manualy.
*/
if ((style & 0x0F) != BS_GROUPBOX)
{
switch (style & BS_VCENTER)
{
case BS_TOP: /* DT_TOP is 0 */ break;
case BS_BOTTOM: dtStyle |= DT_BOTTOM; break;
case BS_VCENTER: /* fall through */
default: dtStyle |= DT_VCENTER; break;
}
}
else
/* GroupBox's text is always single line and is top aligned. */
dtStyle |= DT_SINGLELINE;
return dtStyle;
}
/**********************************************************************
* BUTTON_CalcLabelRect
*
* Calculates label's rectangle depending on button style.
*
* Returns flags to be passed to DrawText.
* Calculated rectangle doesn't take into account button state
* (pushed, etc.). If there is nothing to draw (no text/image) output
* rectangle is empty, and return value is (UINT)-1.
*/
static UINT BUTTON_CalcLabelRect(WND *wndPtr, HDC hdc, RECT *rc)
{
BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
ICONINFO iconInfo;
BITMAP bm;
UINT dtStyle = BUTTON_BStoDT(wndPtr->dwStyle);
RECT r = *rc;
INT n;
/* Calculate label rectangle according to label type */
switch (wndPtr->dwStyle & (BS_ICON|BS_BITMAP))
{
case BS_TEXT:
if (wndPtr->text && wndPtr->text[0])
DrawTextW(hdc, wndPtr->text, -1, &r, dtStyle | DT_CALCRECT);
else
goto empty_rect;
break;
case BS_ICON:
if (!GetIconInfo((HICON)infoPtr->hImage, &iconInfo))
goto empty_rect;
GetObjectW (iconInfo.hbmColor, sizeof(BITMAP), &bm);
r.right = r.left + bm.bmWidth;
r.bottom = r.top + bm.bmHeight;
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
break;
case BS_BITMAP:
if (!GetObjectW (infoPtr->hImage, sizeof(BITMAP), &bm))
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
goto empty_rect;
r.right = r.left + bm.bmWidth;
r.bottom = r.top + bm.bmHeight;
break;
default:
empty_rect:
r.right = r.left;
r.bottom = r.top;
return (UINT)(LONG)-1;
}
/* Position label inside bounding rectangle according to
* alignment flags. (calculated rect is always left-top aligned).
* If label is aligned to any side - shift label in opposite
* direction to leave extra space for focus rectangle.
*/
switch (dtStyle & (DT_CENTER|DT_RIGHT))
{
case DT_LEFT: r.left++; r.right++; break;
case DT_CENTER: n = r.right - r.left;
r.left = rc->left + ((rc->right - rc->left) - n) / 2;
r.right = r.left + n; break;
case DT_RIGHT: n = r.right - r.left;
r.right = rc->right - 1;
r.left = r.right - n;
break;
}
switch (dtStyle & (DT_VCENTER|DT_BOTTOM))
{
case DT_TOP: r.top++; r.bottom++; break;
case DT_VCENTER: n = r.bottom - r.top;
r.top = rc->top + ((rc->bottom - rc->top) - n) / 2;
r.bottom = r.top + n; break;
case DT_BOTTOM: n = r.bottom - r.top;
r.bottom = rc->bottom - 1;
r.top = r.bottom - n;
break;
}
*rc = r;
return dtStyle;
}
/**********************************************************************
* BUTTON_DrawTextCallback
*
* Callback function used by DrawStateW function.
*/
static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int cx, int cy)
{
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = cx;
rc.bottom = cy;
DrawTextW(hdc, (LPCWSTR)lp, -1, &rc, (UINT)wp);
return TRUE;
}
/**********************************************************************
* BUTTON_DrawLabel
*
* Common function for drawing button label.
*/
static void BUTTON_DrawLabel(WND *wndPtr, HDC hdc, UINT dtFlags, RECT *rc)
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
{
BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
DRAWSTATEPROC lpOutputProc = NULL;
LPARAM lp;
WPARAM wp = 0;
HBRUSH hbr = 0;
UINT flags = IsWindowEnabled(wndPtr->hwndSelf) ? DSS_NORMAL : DSS_DISABLED;
/* Fixme: To draw disabled label in Win31 look-and-feel, we probably
* must use DSS_MONO flag and COLOR_GRAYTEXT brush (or maybe DSS_UNION).
* I don't have Win31 on hand to verify that, so I leave it as is.
*/
if ((wndPtr->dwStyle & BS_PUSHLIKE) && (infoPtr->state & BUTTON_3STATE))
{
hbr = GetSysColorBrush(COLOR_GRAYTEXT);
flags |= DSS_MONO;
}
switch (wndPtr->dwStyle & (BS_ICON|BS_BITMAP))
{
case BS_TEXT:
/* DST_COMPLEX -- is 0 */
lpOutputProc = BUTTON_DrawTextCallback;
lp = (LPARAM)wndPtr->text;
wp = (WPARAM)dtFlags;
break;
case BS_ICON:
flags |= DST_ICON;
lp = (LPARAM)infoPtr->hImage;
break;
case BS_BITMAP:
flags |= DST_BITMAP;
lp = (LPARAM)infoPtr->hImage;
break;
default:
return;
}
DrawStateW(hdc, hbr, lpOutputProc, lp, wp, rc->left, rc->top,
rc->right - rc->left, rc->bottom - rc->top, flags);
}
/**********************************************************************
* This method will actually do the drawing of the pushbutton
* depending on it's state and the pushedState parameter.
*/
static void BUTTON_DrawPushButton(
WND* wndPtr,
HDC hDC,
WORD action,
BOOL pushedState )
RECT rc, focus_rect, r;
UINT dtFlags;
HRGN hRgn;
HPEN hOldPen;
HBRUSH hOldBrush;
INT oldBkMode;
COLORREF oldTxtColor;
GetClientRect( wndPtr->hwndSelf, &rc );
/* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
hOldPen = (HPEN)SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
oldBkMode = SetBkMode(hDC, TRANSPARENT);
if ( TWEAK_WineLook == WIN31_LOOK)
COLORREF clr_wnd = GetSysColor(COLOR_WINDOW);
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
SetPixel( hDC, rc.left, rc.top, clr_wnd);
SetPixel( hDC, rc.left, rc.bottom-1, clr_wnd);
SetPixel( hDC, rc.right-1, rc.top, clr_wnd);
SetPixel( hDC, rc.right-1, rc.bottom-1, clr_wnd);
InflateRect( &rc, -1, -1 );
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
InflateRect( &rc, -1, -1 );
if (TWEAK_WineLook == WIN31_LOOK)
{
/* draw button shadow: */
SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW));
PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
} else {
rc.right++, rc.bottom++;
DrawEdge( hDC, &rc, EDGE_RAISED, BF_RECT );
rc.right--, rc.bottom--;
}
}
else
{
UINT uState = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT;
if (wndPtr->dwStyle & BS_FLAT)
uState |= DFCS_MONO;
else if (pushedState)
{
if ( (wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON )
uState |= DFCS_FLAT;
else
uState |= DFCS_PUSHED;
}
if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE))
uState |= DFCS_CHECKED;
DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
focus_rect = rc;
/* draw button label */
r = rc;
dtFlags = BUTTON_CalcLabelRect(wndPtr, hDC, &r);
if (dtFlags == (UINT)-1L)
goto cleanup;
if (pushedState)
OffsetRect(&r, 1, 1);
if(TWEAK_WineLook == WIN31_LOOK)
{
focus_rect = r;
InflateRect(&focus_rect, 2, 0);
}
hRgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
SelectClipRgn(hDC, hRgn);
oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
BUTTON_DrawLabel(wndPtr, hDC, dtFlags, &r);
SetTextColor( hDC, oldTxtColor );
SelectClipRgn(hDC, 0);
DeleteObject(hRgn);
if (infoPtr->state & BUTTON_HASFOCUS)
{
InflateRect( &focus_rect, -1, -1 );
IntersectRect(&focus_rect, &focus_rect, &rc);
DrawFocusRect( hDC, &focus_rect );
}
SelectObject( hDC, hOldPen );
SelectObject( hDC, hOldBrush );
SetBkMode(hDC, oldBkMode);
}
/**********************************************************************
static void CB_Paint( WND *wndPtr, HDC hDC, WORD action )
RECT rbox, rtext, client;
HBRUSH hBrush;
UINT dtFlags;
HRGN hRgn;
if (wndPtr->dwStyle & BS_PUSHLIKE)
BOOL bHighLighted = (infoPtr->state & BUTTON_HIGHLIGHTED);
BUTTON_DrawPushButton(wndPtr,
hDC,
action,
bHighLighted);
return;
GetClientRect(wndPtr->hwndSelf, &client);
if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
/* GetControlBrush16 sends WM_CTLCOLORBTN, plus it returns default brush
* if parent didn't return valid one. So we kill two hares at once
hBrush = GetControlBrush16( wndPtr->hwndSelf, hDC, CTLCOLOR_BTN );
if (wndPtr->dwStyle & BS_LEFTTEXT)
{
/* magic +4 is what CTL3D expects */
rtext.right -= checkBoxWidth + 4;
rbox.left = rbox.right - checkBoxWidth;
}
else
{
rtext.left += checkBoxWidth + 4;
rbox.right = checkBoxWidth;
}
/* Draw the check-box bitmap */
if (action == ODA_DRAWENTIRE || action == ODA_SELECT)
{
/* Since WM_ERASEBKGND does nothing, first prepare background */
if (action == ODA_SELECT) FillRect( hDC, &rbox, hBrush );
else FillRect( hDC, &client, hBrush );
if( TWEAK_WineLook == WIN31_LOOK )
{
HDC hMemDC = CreateCompatibleDC( hDC );
delta = (rbox.bottom - rbox.top - checkBoxHeight) / 2;
/* Check in case the client area is smaller than the checkbox bitmap */
if (delta < 0) delta = 0;
if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
/* The bitmap for the radio button is not aligned with the
* left of the window, it is 1 pixel off. */
if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON))
rbox.left += 1;
SelectObject( hMemDC, hbitmapCheckBoxes );
BitBlt( hDC, rbox.left, rbox.top + delta, checkBoxWidth,
checkBoxHeight, hMemDC, x, y, SRCCOPY );
DeleteDC( hMemDC );
}
else
{
UINT state;
if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) state = DFCS_BUTTONRADIO;
else if (infoPtr->state & BUTTON_3STATE) state = DFCS_BUTTON3STATE;
else state = DFCS_BUTTONCHECK;
if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) state |= DFCS_CHECKED;
if (infoPtr->state & BUTTON_HIGHLIGHTED) state |= DFCS_PUSHED;
if (wndPtr->dwStyle & WS_DISABLED) state |= DFCS_INACTIVE;
/* rbox must have the correct height */
delta = rbox.bottom - rbox.top - checkBoxHeight;
if (delta > 0)
{
int ofs = (abs(delta) / 2);
rbox.bottom -= ofs + 1;
rbox.top = rbox.bottom - checkBoxHeight;
}
else if (delta < 0)
{
int ofs = (abs(delta) / 2);
rbox.top -= ofs + 1;
rbox.bottom = rbox.top + checkBoxHeight;
}
DrawFrameControl( hDC, &rbox, DFC_BUTTON, state );
}
/* Draw label */
client = rtext;
dtFlags = BUTTON_CalcLabelRect(wndPtr, hDC, &rtext);
if (dtFlags == (UINT)-1L) /* Noting to draw */
return;
hRgn = CreateRectRgn(client.left, client.top, client.right, client.bottom);
SelectClipRgn(hDC, hRgn);
DeleteObject(hRgn);
if (action == ODA_DRAWENTIRE)
BUTTON_DrawLabel(wndPtr, hDC, dtFlags, &rtext);
/* ... and focus */
if ((action == ODA_FOCUS) ||
((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
rtext.left--;
rtext.right++;
IntersectRect(&rtext, &rtext, &client);
DrawFocusRect( hDC, &rtext );
SelectClipRgn(hDC, 0);
/**********************************************************************
* BUTTON_CheckAutoRadioButton
*
* wndPtr is checked, uncheck every other auto radio button in group
static void BUTTON_CheckAutoRadioButton( WND *wndPtr )
HWND parent, sibling, start;
if (!(wndPtr->dwStyle & WS_CHILD)) return;
parent = wndPtr->parent->hwndSelf;
/* assure that starting control is not disabled or invisible */
start = sibling = GetNextDlgGroupItem( parent, wndPtr->hwndSelf, TRUE );
tmpWnd = WIN_FindWndPtr(sibling);
((tmpWnd->dwStyle & 0x0f) == BS_AUTORADIOBUTTON))
SendMessageW( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 );
sibling = GetNextDlgGroupItem( parent, sibling, FALSE );
WIN_ReleaseWndPtr(tmpWnd);
/**********************************************************************
* Group Box Functions
*/
static void GB_Paint( WND *wndPtr, HDC hDC, WORD action )
RECT rc, rcFrame;
HBRUSH hbr;
UINT dtFlags;
if (infoPtr->hFont)
SelectObject (hDC, infoPtr->hFont);
/* GroupBox acts like static control, so it sends CTLCOLORSTATIC */
hbr = GetControlBrush16( wndPtr->hwndSelf, hDC, CTLCOLOR_STATIC );
GetClientRect( wndPtr->hwndSelf, &rc);
if (TWEAK_WineLook == WIN31_LOOK) {
HPEN hPrevPen = SelectObject( hDC,
GetSysColorPen(COLOR_WINDOWFRAME));
HBRUSH hPrevBrush = SelectObject( hDC,
GetStockObject(NULL_BRUSH) );
Rectangle( hDC, rc.left, rc.top + 2, rc.right - 1, rc.bottom - 1 );
SelectObject( hDC, hPrevBrush );
SelectObject( hDC, hPrevPen );
DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT |
((wndPtr->dwStyle & BS_FLAT) ? BF_FLAT : 0));
InflateRect(&rc, -7, 1);
dtFlags = BUTTON_CalcLabelRect(wndPtr, hDC, &rc);
if (dtFlags == (UINT)-1L)
return;
/* Because buttons have CS_PARENTDC class style, there is a chance