From 6117fc4165ea9ba7668a5da4fc793622f4bf1d3a Mon Sep 17 00:00:00 2001 From: Serge Ivanov Date: Wed, 13 Sep 2000 00:00:55 +0000 Subject: [PATCH] (Merged by Marcus Meissner ) Fixed problem with origin for DST_COMPLEX style. Fixed handling of DSS_DISABLED and DSS_DEFAULT styles. Added handling of BS_MULTILINE style, label alignment styles (BS_RIGHT, etc.) and some exotic styles BS_FLAT (only pushbuttons for now), and BS_PUSHLIKE. Modified label drawing procedure: now all kinds of buttons use common BUTTON_DrawLabel function. Actual label drawing is performed by DrawStateW function. GroupBox must use WM_CTLCOLORSTATIC instead of WM_CTLCOLORBTN message. --- controls/button.c | 614 +++++++++++++++++++++++++-------------------- windows/painting.c | 66 +++-- 2 files changed, 385 insertions(+), 295 deletions(-) diff --git a/controls/button.c b/controls/button.c index 88fd9741a4..560746bd2e 100644 --- a/controls/button.c +++ b/controls/button.c @@ -6,6 +6,7 @@ */ #include +#include /* for abs() */ #include "win.h" #include "button.h" #include "winbase.h" @@ -14,9 +15,6 @@ #include "wine/winuser16.h" #include "tweak.h" -static void PaintGrayOnGray( HDC hDC,HFONT hFont,RECT *rc, - LPCWSTR text, UINT format ); - 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 ); @@ -280,21 +278,37 @@ static inline LRESULT WINAPI ButtonWndProc_locked(WND* wndPtr, UINT uMsg, break; case BM_SETIMAGE: - oldHbitmap = infoPtr->hImage; - if ((wndPtr->dwStyle & BS_BITMAP) || (wndPtr->dwStyle & BS_ICON)) + /* Check that image format confirm button style */ + if ((wndPtr->dwStyle & (BS_BITMAP|BS_ICON)) == BS_BITMAP) { - infoPtr->hImage = (HANDLE) lParam; - InvalidateRect( hWnd, NULL, FALSE ); + 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 (wParam == IMAGE_BITMAP) - return (HBITMAP)infoPtr->hImage; - else if (wParam == IMAGE_ICON) - return (HICON)infoPtr->hImage; - else + 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; + return infoPtr->hImage; case BM_GETCHECK16: case BM_GETCHECK: @@ -380,6 +394,213 @@ static void PB_Paint( WND *wndPtr, HDC hDC, WORD action ) bHighLighted); } +/********************************************************************** + * 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; + + GetObjectA (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 (!GetObjectA (infoPtr->hImage, sizeof(BITMAP), &bm)) + 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 be DrawStateA function. + */ +static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int cx, int cy) +{ + RECT rc = {0, 0, cx, 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) +{ + 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. @@ -390,30 +611,33 @@ static void BUTTON_DrawPushButton( WORD action, BOOL pushedState ) { - RECT rc, focus_rect; - HPEN hOldPen; - HBRUSH hOldBrush; BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; - int xBorderOffset, yBorderOffset; - xBorderOffset = yBorderOffset = 0; + 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) */ + /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */ if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); BUTTON_SEND_CTLCOLOR( wndPtr, hDC ); hOldPen = (HPEN)SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME)); hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE)); - SetBkMode(hDC, TRANSPARENT); + 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, GetSysColor(COLOR_WINDOW) ); - SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) ); - SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) ); - SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW)); + 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 ); } @@ -431,24 +655,19 @@ static void BUTTON_DrawPushButton( 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 ); - rc.left += 2; /* To position the text down and right */ - rc.top += 2; } else { rc.right++, rc.bottom++; DrawEdge( hDC, &rc, EDGE_RAISED, BF_RECT ); - - /* To place the bitmap correctly */ - xBorderOffset += GetSystemMetrics(SM_CXEDGE); - yBorderOffset += GetSystemMetrics(SM_CYEDGE); - rc.right--, rc.bottom--; } } else { - UINT uState = DFCS_BUTTONPUSH; + UINT uState = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT; - if (pushedState) + if (wndPtr->dwStyle & BS_FLAT) + uState |= DFCS_MONO; + else if (pushedState) { if ( (wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON ) uState |= DFCS_FLAT; @@ -456,211 +675,54 @@ static void BUTTON_DrawPushButton( uState |= DFCS_PUSHED; } + if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) + uState |= DFCS_CHECKED; + DrawFrameControl( hDC, &rc, DFC_BUTTON, uState ); - InflateRect( &rc, -2, -2 ); focus_rect = rc; - - if (pushedState) - { - rc.left += 2; /* To position the text down and right */ - rc.top += 2; - } } - /* draw button label, if any: - * - * In win9x we don't show text if there is a bitmap or icon. - * I don't know about win31 so I leave it as it was for win31. - * Dennis Björklund 12 Jul, 99 - */ - if ( wndPtr->text && wndPtr->text[0] - && (TWEAK_WineLook == WIN31_LOOK || !(wndPtr->dwStyle & (BS_ICON|BS_BITMAP))) ) + /* 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) { - LOGBRUSH lb; - GetObjectA( GetSysColorBrush(COLOR_BTNFACE), sizeof(lb), &lb ); - if (wndPtr->dwStyle & WS_DISABLED && - GetSysColor(COLOR_GRAYTEXT)==lb.lbColor) - /* don't write gray text on gray background */ - PaintGrayOnGray( hDC,infoPtr->hFont,&rc,wndPtr->text, - DT_CENTER | DT_VCENTER ); - else - { - SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ? - GetSysColor(COLOR_GRAYTEXT) : - GetSysColor(COLOR_BTNTEXT) ); - DrawTextW( hDC, wndPtr->text, -1, &rc, - DT_SINGLELINE | DT_CENTER | DT_VCENTER ); - /* do we have the focus? - * Win9x draws focus last with a size prop. to the button - */ - if (TWEAK_WineLook == WIN31_LOOK - && infoPtr->state & BUTTON_HASFOCUS) - { - RECT r = { 0, 0, 0, 0 }; - INT xdelta, ydelta; - - DrawTextW( hDC, wndPtr->text, -1, &r, - DT_SINGLELINE | DT_CALCRECT ); - xdelta = ((rc.right - rc.left) - (r.right - r.left) - 1) / 2; - ydelta = ((rc.bottom - rc.top) - (r.bottom - r.top) - 1) / 2; - if (xdelta < 0) xdelta = 0; - if (ydelta < 0) ydelta = 0; - InflateRect( &rc, -xdelta, -ydelta ); - DrawFocusRect( hDC, &rc ); - } - } - } - if ( ((wndPtr->dwStyle & BS_ICON) || (wndPtr->dwStyle & BS_BITMAP) ) && - (infoPtr->hImage != 0) ) - { - int yOffset, xOffset; - int imageWidth, imageHeight; - - /* - * We extract the size of the image from the handle. - */ - if (wndPtr->dwStyle & BS_ICON) - { - ICONINFO iconInfo; - BITMAP bm; - - GetIconInfo((HICON)infoPtr->hImage, &iconInfo); - GetObjectA (iconInfo.hbmColor, sizeof(BITMAP), &bm); - - imageWidth = bm.bmWidth; - imageHeight = bm.bmHeight; - - DeleteObject(iconInfo.hbmColor); - DeleteObject(iconInfo.hbmMask); - - } - else - { - BITMAP bm; - - GetObjectA (infoPtr->hImage, sizeof(BITMAP), &bm); - - imageWidth = bm.bmWidth; - imageHeight = bm.bmHeight; - } - - /* Center the bitmap */ - xOffset = (((rc.right - rc.left) - 2*xBorderOffset) - imageWidth ) / 2; - yOffset = (((rc.bottom - rc.top) - 2*yBorderOffset) - imageHeight) / 2; - - /* If the image is too big for the button then create a region */ - if(xOffset < 0 || yOffset < 0) - { - HRGN hBitmapRgn = 0; - hBitmapRgn = CreateRectRgn( - rc.left + xBorderOffset, rc.top +yBorderOffset, - rc.right - xBorderOffset, rc.bottom - yBorderOffset); - SelectClipRgn(hDC, hBitmapRgn); - DeleteObject(hBitmapRgn); - } - - /* Let minimum 1 space from border */ - xOffset++, yOffset++; - - /* - * Draw the image now. - */ - if (wndPtr->dwStyle & BS_ICON) - { - DrawIcon(hDC, - rc.left + xOffset, rc.top + yOffset, - (HICON)infoPtr->hImage); - } - else - { - HDC hdcMem; - - hdcMem = CreateCompatibleDC (hDC); - SelectObject (hdcMem, (HBITMAP)infoPtr->hImage); - BitBlt(hDC, - rc.left + xOffset, - rc.top + yOffset, - imageWidth, imageHeight, - hdcMem, 0, 0, SRCCOPY); - - DeleteDC (hdcMem); - } - - if(xOffset < 0 || yOffset < 0) - { - SelectClipRgn(hDC, 0); - } + focus_rect = r; + InflateRect(&focus_rect, 2, 0); } - if (TWEAK_WineLook != WIN31_LOOK - && infoPtr->state & BUTTON_HASFOCUS) + 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 ); } - + cleanup: SelectObject( hDC, hOldPen ); SelectObject( hDC, hOldBrush ); + SetBkMode(hDC, oldBkMode); } - -/********************************************************************** - * PB_Paint & CB_Paint sub function [internal] - * Paint text using a raster brush to avoid gray text on gray - * background. 'format' can be a combination of DT_CENTER and - * DT_VCENTER to use this function in both PB_PAINT and - * CB_PAINT. - Dirk Thierbach - * - * FIXME: This and TEXT_GrayString should be eventually combined, - * so calling one common function from PB_Paint, CB_Paint and - * TEXT_GrayString will be enough. Also note that this - * function ignores the CACHE_GetPattern funcs. - */ - -void PaintGrayOnGray(HDC hDC, HFONT hFont, RECT *rc, LPCWSTR text, - UINT format) -{ -/* This is the standard gray on gray pattern: - static const WORD Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}; -*/ -/* This pattern gives better readability with X Fonts. - FIXME: Maybe the user should be allowed to decide which he wants. */ - static const WORD Pattern[] = {0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF}; - - HBITMAP hbm = CreateBitmap( 8, 8, 1, 1, Pattern ); - HDC hdcMem = CreateCompatibleDC(hDC); - HBITMAP hbmMem; - HBRUSH hBr; - RECT rect,rc2; - - rect=*rc; - DrawTextW( hDC, text, -1, &rect, DT_SINGLELINE | DT_CALCRECT); - /* now text width and height are in rect.right and rect.bottom */ - rc2=rect; - rect.left = rect.top = 0; /* drawing pos in hdcMem */ - if (format & DT_CENTER) rect.left=(rc->right-rect.right)/2; - if (format & DT_VCENTER) rect.top=(rc->bottom-rect.bottom)/2; - hbmMem = CreateCompatibleBitmap( hDC,rect.right,rect.bottom ); - SelectObject( hdcMem, hbmMem); - PatBlt( hdcMem,0,0,rect.right,rect.bottom,WHITENESS); - /* will be overwritten by DrawText, but just in case */ - if (hFont) SelectObject( hdcMem, hFont); - DrawTextW( hdcMem, text, -1, &rc2, DT_SINGLELINE); - /* After draw: foreground = 0 bits, background = 1 bits */ - hBr = SelectObject( hdcMem, CreatePatternBrush(hbm) ); - DeleteObject( hbm ); - PatBlt( hdcMem,0,0,rect.right,rect.bottom,0xAF0229); - /* only keep the foreground bits where pattern is 1 */ - DeleteObject( SelectObject( hdcMem,hBr) ); - BitBlt(hDC,rect.left,rect.top,rect.right,rect.bottom,hdcMem,0,0,SRCAND); - /* keep the background of the dest */ - DeleteDC( hdcMem); - DeleteObject( hbmMem ); -} - - /********************************************************************** * Check Box & Radio Button Functions */ @@ -669,17 +731,14 @@ static void CB_Paint( WND *wndPtr, HDC hDC, WORD action ) { RECT rbox, rtext, client; HBRUSH hBrush; - int textlen, delta; + int delta; BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + UINT dtFlags; + HRGN hRgn; - /* - * if the button has a bitmap/icon, draw a normal pushbutton - * instead of a radion button. - */ - if (infoPtr->hImage != 0) + if (wndPtr->dwStyle & BS_PUSHLIKE) { - BOOL bHighLighted = ((infoPtr->state & BUTTON_HIGHLIGHTED) || - (infoPtr->state & BUTTON_CHECKED)); + BOOL bHighLighted = (infoPtr->state & BUTTON_HIGHLIGHTED); BUTTON_DrawPushButton(wndPtr, hDC, @@ -688,18 +747,14 @@ static void CB_Paint( WND *wndPtr, HDC hDC, WORD action ) return; } - textlen = 0; GetClientRect(wndPtr->hwndSelf, &client); rbox = rtext = client; if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); - /* Something is still not right, checkboxes (and edit controls) - * in wsping32 have white backgrounds instead of dark grey. - * BUTTON_SEND_CTLCOLOR() is even worse since it returns 0 in this - * particular case and the background is not painted at all. + /* 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) @@ -715,9 +770,7 @@ static void CB_Paint( WND *wndPtr, HDC hDC, WORD action ) rbox.right = checkBoxWidth; } - /* Draw the check-box bitmap */ - - if (wndPtr->text) textlen = lstrlenW( wndPtr->text ); + /* Draw the check-box bitmap */ if (action == ODA_DRAWENTIRE || action == ODA_SELECT) { if( TWEAK_WineLook == WIN31_LOOK ) @@ -781,40 +834,31 @@ static void CB_Paint( WND *wndPtr, HDC hDC, WORD action ) DrawFrameControl( hDC, &rbox, DFC_BUTTON, state ); } - - if( textlen && action != ODA_SELECT ) - { - if (wndPtr->dwStyle & WS_DISABLED && - GetSysColor(COLOR_GRAYTEXT)==GetBkColor(hDC)) { - /* don't write gray text on gray background */ - PaintGrayOnGray( hDC, infoPtr->hFont, &rtext, wndPtr->text, - DT_VCENTER); - } else { - if (wndPtr->dwStyle & WS_DISABLED) - SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) ); - DrawTextW( hDC, wndPtr->text, textlen, &rtext, - DT_SINGLELINE | DT_VCENTER ); - } - } } + /* 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))) { - /* again, this is what CTL3D expects */ - - SetRectEmpty(&rbox); - if( textlen ) - DrawTextW( hDC, wndPtr->text, textlen, &rbox, - DT_SINGLELINE | DT_CALCRECT ); - textlen = rbox.bottom - rbox.top; - delta = ((rtext.bottom - rtext.top) - textlen)/2; - rbox.bottom = (rbox.top = rtext.top + delta - 1) + textlen + 2; - textlen = rbox.right - rbox.left; - rbox.right = (rbox.left += --rtext.left) + textlen + 2; - IntersectRect(&rbox, &rbox, &rtext); - DrawFocusRect( hDC, &rbox ); + rtext.left--; + rtext.right++; + IntersectRect(&rtext, &rtext, &client); + DrawFocusRect( hDC, &rtext ); } + SelectClipRgn(hDC, 0); } @@ -852,10 +896,16 @@ static void GB_Paint( WND *wndPtr, HDC hDC, WORD action ) { RECT rc, rcFrame; BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + HBRUSH hbr; + UINT dtFlags; if (action != ODA_DRAWENTIRE) return; - BUTTON_SEND_CTLCOLOR( wndPtr, hDC ); + 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) { @@ -871,21 +921,29 @@ static void GB_Paint( WND *wndPtr, HDC hDC, WORD action ) TEXTMETRICA tm; rcFrame = rc; - if (infoPtr->hFont) - SelectObject (hDC, infoPtr->hFont); GetTextMetricsA (hDC, &tm); rcFrame.top += (tm.tmHeight / 2) - 1; - DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT); + DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT | + ((wndPtr->dwStyle & BS_FLAT) ? BF_FLAT : 0)); } - if (wndPtr->text) - { - if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); - if (wndPtr->dwStyle & WS_DISABLED) - SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) ); - rc.left += 10; - DrawTextW( hDC, wndPtr->text, -1, &rc, DT_SINGLELINE | DT_NOCLIP ); - } + 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 + * that label will be drawn out of client rect. + * But Windows doesn't clip label's rect, so do I. + */ + + /* There is 1-pixel marging at the left, right, and bottom */ + rc.left--; rc.right++; rc.bottom++; + FillRect(hDC, &rc, hbr); + rc.left++; rc.right--; rc.bottom--; + + BUTTON_DrawLabel(wndPtr, hDC, dtFlags, &rc); } @@ -930,7 +988,7 @@ static void OB_Paint( WND *wndPtr, HDC hDC, WORD action ) dis.itemAction = action; dis.itemState = ((infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) | ((infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) | - ((wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0); + (IsWindowEnabled(wndPtr->hwndSelf) ? 0: ODS_DISABLED); dis.hwndItem = wndPtr->hwndSelf; dis.hDC = hDC; dis.itemData = 0; diff --git a/windows/painting.c b/windows/painting.c index 083eb999c4..a8eea979ab 100644 --- a/windows/painting.c +++ b/windows/painting.c @@ -1451,12 +1451,19 @@ static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode, return retval; case DST_COMPLEX: - if(func) + if(func) { + BOOL bRet; + /* DRAWSTATEPROC assumes that it draws at the center of coordinates */ + + OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL); if(_32bit) - return func(hdc, lp, wp, cx, cy); + bRet = func(hdc, lp, wp, cx, cy); else - return (BOOL)((DRAWSTATEPROC16)func)((HDC16)hdc, (LPARAM)lp, (WPARAM16)wp, (INT16)cx, (INT16)cy); - else + bRet = (BOOL)((DRAWSTATEPROC16)func)((HDC16)hdc, (LPARAM)lp, (WPARAM16)wp, (INT16)cx, (INT16)cy); + /* Restore origin */ + OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL); + return bRet; + } else return FALSE; } return FALSE; @@ -1472,7 +1479,7 @@ static BOOL PAINTING_DrawState(HDC hdc, HBRUSH hbr, { HBITMAP hbm, hbmsave; HFONT hfsave; - HBRUSH hbsave; + HBRUSH hbsave, hbrtmp = 0; HDC memdc; RECT rc; UINT dtflags = DT_NOCLIP; @@ -1572,32 +1579,56 @@ static BOOL PAINTING_DrawState(HDC hdc, HBRUSH hbr, SetBkColor(memdc, RGB(255, 255, 255)); SetTextColor(memdc, RGB(0, 0, 0)); hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT)); - if(!hfsave && (opcode == DST_TEXT || opcode == DST_PREFIXTEXT)) goto cleanup; + + /* DST_COMPLEX may draw text as well, + * so we must be sure that correct font is selected + */ + if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup; tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode, _32bit); if(hfsave) SelectObject(memdc, hfsave); if(!tmp) goto cleanup; - /* These states cause the image to be dithered */ - if(flags & (DSS_UNION|DSS_DISABLED)) + /* This state cause the image to be dithered */ + if(flags & DSS_UNION) { hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush()); if(!hbsave) goto cleanup; tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089); - if(hbsave) SelectObject(memdc, hbsave); + SelectObject(memdc, hbsave); if(!tmp) goto cleanup; } - hbsave = (HBRUSH)SelectObject(hdc, hbr ? hbr : GetStockObject(WHITE_BRUSH)); - if(!hbsave) goto cleanup; + if (flags & DSS_DISABLED) + hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT)); + else if (flags & DSS_DEFAULT) + hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW)); + + /* Draw light or dark shadow */ + if (flags & (DSS_DISABLED|DSS_DEFAULT)) + { + if(!hbrtmp) goto cleanup; + hbsave = (HBRUSH)SelectObject(hdc, hbrtmp); + if(!hbsave) goto cleanup; + if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup; + SelectObject(hdc, hbsave); + DeleteObject(hbrtmp); + hbrtmp = 0; + } + + if (flags & DSS_DISABLED) + { + hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW)); + if(!hbrtmp) goto cleanup; + } + else if (!hbr) + { + hbr = (HBRUSH)GetStockObject(BLACK_BRUSH); + } + + hbsave = (HBRUSH)SelectObject(hdc, hbr); if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup; - /* DSS_DEFAULT makes the image boldface */ - if(flags & DSS_DEFAULT) - { - if(!BitBlt(hdc, x+1, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup; - } - retval = TRUE; /* We succeeded */ cleanup: @@ -1606,6 +1637,7 @@ cleanup: if(hbsave) SelectObject(hdc, hbsave); if(hbmsave) SelectObject(memdc, hbmsave); + if(hbrtmp) DeleteObject(hbrtmp); if(hbm) DeleteObject(hbm); if(memdc) DeleteDC(memdc);