|
|
#include "precomp.h"
#pragma hdrstop
/*****************************************************************************
* * * SBUTTON.C * * * * Program Description: Implements "3-D" buttons * * * ****************************************************************************** * * * Revision History: Created by Todd Laney, Munged 3/27/89 by Robert Bunney * * 7/25/89 - revised by Chris Guzak for transparent * * color bitmaps. * * 7/26/89 - revised by Todd Laney to handle multi-res * * bitmaps. * * windows 3 support * * * *****************************************************************************/
#define NOCOMM
//
// if WIN2 is defined the code will work in windows 2.x and windows 3.0
// otherwise windows 3.0 is required
//
/*****************************************************************************
* * * Defines * * * *****************************************************************************/
#if DBG
#define PRIV
#else
#define PRIV static
#endif
#define rgbWhite RGB(255,255,255)
#define rgbBlack RGB(0,0,0)
#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
#define BEVEL 2
#define FRAME 1
#define GWW_HBM 0
#define GWW_STATE GWW_HBM + sizeof(PVOID)
#define GWW_FLAGS GWW_STATE + sizeof(DWORD)
#define GWW_CHECK GWW_FLAGS + sizeof(DWORD)
#define GWW_SIZE GWW_CHECK + sizeof(DWORD)
#define GETSTYLE(hwnd) (LOWORD(GetWindowLong(hwnd,GWL_STYLE)))
#define GETSTATE(hwnd) GetWindowLong(hwnd,GWW_STATE)
#define GETFLAGS(hwnd) GetWindowLong(hwnd,GWW_FLAGS)
#define GETCHECK(hwnd) GetWindowLong(hwnd,GWW_CHECK)
#define GETHBM(hwnd) GetWindowLongPtr(hwnd,GWW_HBM)
#define lpCreate ((LPCREATESTRUCT)lParam)
#define DPSoa 0x00A803A9L
#define DSPDxax 0x00E20746L
#define EraseButton(hwnd,hdc,prc) ExtTextOut(hdc,0,0,ETO_OPAQUE,prc,NULL,0,NULL)
#define NearestColor(hdc,rgb) (GetNearestColor(hdc,rgb) & 0x00FFFFFFL)
/*****************************************************************************
* * * Prototypes * * * *****************************************************************************/
PRIV VOID DrawGrayButton (HWND, HDC, LPRECT, WORD, WORD); PRIV VOID DrawButtonFace (HWND, HDC, PRECT, WORD); PRIV BOOL PaintButton (HWND, HDC); PRIV VOID NotifyParent (HWND); PRIV VOID PatB (HDC, int, int, int, int, DWORD); PRIV HBITMAP LoadBitmapResource(HANDLE hInst, LPSTR lpName); PRIV VOID BitmapColorTranslate(HDC hdcBits, BITMAP* pbm, DWORD rgb);
/*****************************************************************************
* * * Variabls * * * *****************************************************************************/
HBRUSH hbrGray = NULL; // Gray for text
HBRUSH hbrFocus = NULL; // focus for text
DWORD rgbButtonFocus; DWORD rgbButtonFace; DWORD rgbButtonText; DWORD rgbButtonShadow;
PRIV char szColor[] = "Colors"; // Name of color section
PRIV char szButton[] = "sbutton";
/*---------------------------------------------------------------------------*\
| ButtonControlInit( hInst ) | | | | Description: | | This is called when the application is first loaded into | | memory. It performs all button initialization. | | | | Arguments: | | hInst instance handle of current instance | | | | Returns: | | TRUE if successful, FALSE if not | | | \*----------------------------------------------------------------------------*/
BOOL ButtonControlInit( IN HANDLE hInst ) { WNDCLASS cls; UINT patGray[8]; HBITMAP hbmGray; int i; HDC hdc;
/* initialize the brushes */
for (i=0; i<8; i+=2) { patGray[i] = 0x0000AAAA; patGray[i+1] = 0x00005555; }
hbmGray = CreateBitmap(8, 8, 1, 1, (LPSTR)patGray); hbrGray = CreatePatternBrush(hbmGray); if (hbmGray) { DeleteObject(hbmGray); }
hdc = GetDC(NULL);
if (hdc) { rgbButtonFace = GetSysColor(COLOR_BTNFACE); rgbButtonShadow = GetSysColor(COLOR_BTNSHADOW); rgbButtonText = GetSysColor(COLOR_BTNTEXT); rgbButtonFocus = rgbWhite; // ??
rgbButtonFace = NearestColor(hdc,rgbButtonFace); rgbButtonShadow = NearestColor(hdc,rgbButtonShadow); rgbButtonText = NearestColor(hdc,rgbButtonText); rgbButtonFocus = NearestColor(hdc,rgbButtonFocus); if (rgbButtonFocus == rgbButtonFace) rgbButtonFocus = rgbButtonText; ReleaseDC(NULL,hdc);
}
hbrFocus = CreateSolidBrush(rgbButtonFocus);
cls.hCursor = LoadCursor(NULL,IDC_ARROW); cls.hIcon = NULL; cls.lpszMenuName = NULL; cls.lpszClassName = (LPSTR)szButton; cls.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); cls.hInstance = hInst; cls.style = CS_HREDRAW | CS_VREDRAW; cls.lpfnWndProc = fnButton; cls.cbClsExtra = 0; cls.cbWndExtra = GWW_SIZE;
return(RegisterClass(&cls)); }
VOID ButtonControlTerm( VOID ) { if (hbrGray) DeleteObject(hbrGray);
if (hbrFocus) DeleteObject(hbrFocus);
UnregisterClass(szButton,hInst); }
/*----------------------------------------------------------------------------*\
| | | Custom push-button | | | \*----------------------------------------------------------------------------*/
PRIV BOOL PaintButton(HWND hwnd, HDC hdc) { WORD style; RECT rc; WORD f;
HDC hdcMem; HBITMAP hbmMem,hbmT;
GetClientRect(hwnd,&rc);
if (!RectVisible(hdc,&rc)) return TRUE;
style = (WORD)((DWORD)GETSTYLE(hwnd) | ((DWORD)GETFLAGS(hwnd) & 0xFF00)); f = (WORD)GETSTATE(hwnd);
hdcMem = CreateCompatibleDC(hdc); hbmMem = CreateCompatibleBitmap(hdc,rc.right,rc.bottom);
switch (LOBYTE(style)) { case BS_PUSHBUTTON: case BS_DEFPUSHBUTTON: if (hdcMem && hbmMem) { hbmT = SelectObject(hdcMem,hbmMem); DrawGrayButton(hwnd, hdcMem, &rc, style, f); BitBlt(hdc,0,0,rc.right,rc.bottom,hdcMem,0,0,SRCCOPY); SelectObject(hdcMem,hbmT); } else { DrawGrayButton(hwnd, hdc, &rc, style, f); } break; }
if (hbmMem) DeleteObject(hbmMem); if (hdcMem) DeleteDC(hdcMem); return TRUE; }
/*******************
** ** Name: ButtonState ** ** Purpose: Compares the passed state (f) with the current state. If ** they differ, the button is invalidated and TRUE is ** is returned. ** ** Arguments: hwnd - window handle of the button ** f - state to set ** ** Returns: TRUE iff the current state is different than f ** *******************/
BOOL ButtonState(HWND hwnd, WORD f) { WORD state;
state = (WORD)GETSTATE(hwnd);
if (state != f) { SetWindowLong(hwnd,GWW_STATE,f); InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); return TRUE; } return FALSE; }
/*******************
** ** Name: fnButton ** ** Purpose: Window proc for buttons ** ** Arguments: Standard window proc ** *******************/
LRESULT APIENTRY fnButton(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { HANDLE hbm; PAINTSTRUCT ps; RECT rc; LONG l;
switch (message) { case WM_CREATE: SetWindowLongPtr(hwnd,GWW_HBM,0); SetWindowLong(hwnd,GWW_STATE,0); SetWindowLong(hwnd,GWW_FLAGS,lpCreate->style & 0x0000FF00); SetWindowText(hwnd,lpCreate->lpszName); SetWindowLong(hwnd,GWL_STYLE,lpCreate->style & 0xFFFF00FF); break;
case WM_LBUTTONDOWN: if (!IsWindowEnabled(hwnd)) return 0L;
if (GetCapture() != hwnd) /* ignore multiple DOWN's */ { ButtonState(hwnd,TRUE); SetCapture(hwnd); if (!(GETFLAGS(hwnd) & BS_NOFOCUS)) SetFocus(hwnd); } return 0L;
case WM_MOUSEMOVE: if (GetCapture() == hwnd) { POINT point;
point.x = (LONG)(LOWORD(lParam)); point.y = (LONG)(HIWORD(lParam));
GetClientRect(hwnd,&rc); ButtonState(hwnd,(WORD)PtInRect(&rc,point)); } return 0L;
case WM_LBUTTONUP: if (GetCapture() == hwnd) { ReleaseCapture(); if (ButtonState(hwnd,FALSE)) NotifyParent(hwnd); } return 0L;
case WM_DESTROY: if (hbm = (HBITMAP)GETHBM(hwnd)) DeleteObject(hbm); break;
case WM_SETTEXT: if (hbm = (HBITMAP)GETHBM(hwnd)) DeleteObject(hbm);
if (*(LPSTR)lParam == '#') { hbm = LoadBitmapResource( (HINSTANCE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE), (LPSTR)lParam+1 ); } else { hbm = NULL; } SetWindowLongPtr(hwnd,GWW_HBM,(LONG_PTR)hbm); InvalidateRect(hwnd,NULL,TRUE); break;
case WM_ENABLE: case WM_KILLFOCUS: case WM_SETFOCUS: InvalidateRect(hwnd,NULL,TRUE); break;
case WM_KEYDOWN: if (wParam == VK_SPACE && IsWindowEnabled(hwnd)) ButtonState(hwnd,TRUE); break;
case WM_KEYUP: case WM_SYSKEYUP: if (wParam == VK_SPACE && IsWindowEnabled(hwnd)) { if (ButtonState(hwnd,FALSE)) NotifyParent(hwnd); } break;
case BM_GETSTATE: return((LONG)GETSTATE(hwnd));
case BM_SETSTATE: if (ButtonState(hwnd,(WORD)wParam) && !wParam) // NotifyParent(hwnd);
break;
case BM_GETCHECK: return((LONG)GETCHECK(hwnd));
case BM_SETCHECK: SetWindowLong(hwnd,GWW_CHECK,(DWORD)wParam); break;
case BM_SETSTYLE: l = GetWindowLong(hwnd,GWL_STYLE); SetWindowLong(hwnd,GWL_STYLE,MAKELONG((WORD)wParam,HIWORD(l))); if (lParam) InvalidateRect(hwnd, NULL, TRUE); break;
case WM_SETCURSOR: SetCursor(CurrentCursor); return(TRUE); // don't mess with cursor
case WM_GETDLGCODE: switch (LOBYTE(GETSTYLE(hwnd))) { case BS_DEFPUSHBUTTON: wParam = DLGC_DEFPUSHBUTTON; break;
case BS_PUSHBUTTON: wParam = DLGC_UNDEFPUSHBUTTON; break;
default: wParam = 0; }
return((LONG)(wParam | DLGC_BUTTON));
case WM_ERASEBKGND: return 0L;
case WM_PAINT: BeginPaint(hwnd, &ps); PaintButton(hwnd,ps.hdc); EndPaint(hwnd, &ps); return 0L; } return DefWindowProc(hwnd, message, wParam, lParam); }
/*---------------------------------------------------------------------------*/ /* */ /* DrawGrayButton() - */ /* */ /*---------------------------------------------------------------------------*/
PRIV VOID DrawGrayButton(HWND hwnd,HDC hdc,RECT *lprc,WORD style,WORD fInvert) { RECT rc; int dx,dy; HBRUSH hbr; int i; int iFrame;
SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
hbr = (HBRUSH)SendMessage(GetParent(hwnd), WM_CTLCOLORBTN, (WPARAM)hdc, (LONG_PTR)hwnd); FillRect(hdc, lprc, hbr);
rc = *lprc; dx = rc.right - rc.left; dy = rc.bottom - rc.top;
iFrame = FRAME;
if (LOBYTE(style) == BS_DEFPUSHBUTTON) iFrame *= 2;
PatB(hdc, rc.left , rc.top , dx , iFrame, rgbBlack); PatB(hdc, rc.left , rc.bottom-iFrame, dx , iFrame, rgbBlack); PatB(hdc, rc.left , rc.top+1 , iFrame, dy-2, rgbBlack); PatB(hdc, rc.right-iFrame, rc.top+1 , iFrame, dy-2, rgbBlack);
InflateRect(&rc,-iFrame,-iFrame); dx = rc.right - rc.left; dy = rc.bottom - rc.top;
SetBkColor(hdc,rgbButtonFace); EraseButton(hwnd,hdc,&rc);
if (fInvert) { PatB(hdc, rc.left, rc.top, 1,dy, rgbButtonShadow); PatB(hdc, rc.left, rc.top, dx,1, rgbButtonShadow); rc.left += BEVEL*2; rc.top += BEVEL*2; } else { for (i=0; i<BEVEL; i++) { PatB(hdc, rc.left, rc.top, 1,dy, rgbWhite); PatB(hdc, rc.left, rc.top, dx,1, rgbWhite); PatB(hdc, rc.right-1,rc.top+1, 1,dy-1, rgbButtonShadow); PatB(hdc, rc.left+1, rc.bottom-1, dx-1,1,rgbButtonShadow);
InflateRect(&rc,-1,-1); dx -= 2; dy -= 2; } }
SetBkColor(hdc,rgbButtonFace);
if (GetFocus() == hwnd) SetTextColor(hdc,rgbButtonFocus); else SetTextColor(hdc,rgbButtonText);
DrawButtonFace(hwnd,hdc,&rc,style); }
/*******************
** ** Name: DrawButtonFace ** ** Purpose: Responsible for the rendering of the text or bitmap on ** on a button. ** ** Arguments: hwnd - window handle of button ** hdc - hdc for window ** prc - clipping rect ** sytle - button style (push button or default pushbutton) ** *******************/
PRIV VOID DrawButtonFace(HWND hwnd, HDC hdc, PRECT prc, WORD style) { RECT rc; HBITMAP hbm; HDC hdcBits; BITMAP bm; BOOL fMono;
rc = *prc;
SaveDC(hdc);
IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
if ((hbm = (HBITMAP)GETHBM(hwnd))) { hdcBits = CreateCompatibleDC(hdc); if (hdcBits) { SelectObject(hdcBits,hbm); GetObject(hbm,sizeof(bm),(LPSTR)&bm); fMono = (bm.bmPlanes == 1) && (bm.bmBitsPixel == 1); BitmapColorTranslate(hdcBits, &bm, rgbButtonFace); if (!(style & BS_STRETCH)) { // now center this thing on the button face
rc.left += (rc.right - rc.left - (signed)bm.bmWidth) / 2; rc.top += (rc.bottom - rc.top - (signed)bm.bmHeight) / 2; rc.right = rc.left + bm.bmWidth; rc.bottom = rc.top + bm.bmHeight; } SetStretchBltMode (hdc,fMono ? BLACKONWHITE : COLORONCOLOR); if (IsWindowEnabled(hwnd)) { StretchBlt(hdc,rc.left,rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcBits,0,0, bm.bmWidth,bm.bmHeight, SRCCOPY); } else { SetBkColor(hdc,rgbWhite); SetTextColor(hdc,rgbBlack); SelectObject(hdc,hbrGray); StretchBlt(hdc,rc.left,rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcBits,0,0, bm.bmWidth,bm.bmHeight, DPSoa); } DeleteDC(hdcBits); } }
RestoreDC(hdc, -1); }
/*
* using the first pixel as the "transparent" color, make all pixels * in the hdc that are equal to the "transparent" color the passed * color. */ PRIV VOID BitmapColorTranslate(HDC hdcBits, BITMAP* pbm, DWORD rgb) { HDC hdcMask; HBITMAP hbmMask, hbmT; HBRUSH hbrT; BOOL fMono;
/*
* is the bitmap mono, or the first pixel is already equal to the * passed color? if so we have nothing to do. */
fMono = pbm->bmPlanes == 1 && pbm->bmBitsPixel == 1; if (fMono || GetPixel(hdcBits, 0, 0) == rgb) return;
// create a mask bitmap and associated DC
if ((hbmMask = CreateBitmap(pbm->bmWidth, pbm->bmHeight, 1, 1, NULL))) { hdcMask = CreateCompatibleDC(hdcBits);
// select the mask bitmap into the mono DC
hbmT = SelectObject(hdcMask, hbmMask);
// create the brush and select it into the bits DC
hbrT = SelectObject(hdcBits, CreateSolidBrush(rgb));
// do a color to mono bitblt to build the mask
// generate 1's where the source is equal to the background is
if (hdcMask) { SetBkColor(hdcBits, GetPixel(hdcBits, 0, 0)); BitBlt(hdcMask, 0, 0, pbm->bmWidth, pbm->bmHeight, hdcBits, 0, 0, SRCCOPY); // where the mask is 1 lay down the brush, where it is 0 leave the desitnation
SetBkColor(hdcBits, rgbWhite); SetTextColor(hdcBits, rgbBlack); BitBlt(hdcBits, 0, 0, pbm->bmWidth, pbm->bmHeight, hdcMask, 0, 0, DSPDxax); DeleteObject(SelectObject(hdcBits, hbrT)); DeleteObject(SelectObject(hdcMask, hbmT)); DeleteDC(hdcMask); } } }
/*******************
** ** Name: NotifyParent ** *******************/
PRIV VOID NotifyParent(HWND hwnd) { PostMessage(GetParent(hwnd),WM_COMMAND,MAKELONG(GetWindowLong(hwnd,GWL_ID),BN_CLICKED),(LONG_PTR)hwnd); }
/*******************
** ** Name: PatB ** ** Fast Solid color PatBlt() using ExtTextOut() ** *******************/
PRIV VOID PatB(HDC hdc,int x,int y,int dx,int dy, DWORD rgb) { RECT rc;
SetBkColor(hdc,rgb); rc.left = x; rc.top = y; rc.right = x + dx; rc.bottom = y + dy;
ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL); }
/*
* LoadBitmapResource() * * load a bitmap from a resource file that is specific to a device. * */ PRIV HBITMAP LoadBitmapResource(HANDLE hInst, LPSTR lpName) { char szName[80]; HBITMAP hbm; DWORD nColors = 0; DWORD dxScreen = 0; DWORD dyScreen = 0; HDC hdc;
hdc = GetDC(NULL);
if (hdc) { nColors = GetDeviceCaps(hdc,NUMCOLORS); dxScreen = GetSystemMetrics(SM_CXSCREEN); dyScreen = GetSystemMetrics(SM_CYSCREEN); ReleaseDC(NULL,hdc); }
/* look for a resource of the form WxHxC */
wsprintf(szName, "%s%dx%dx%d", lpName, dxScreen, dyScreen, nColors);
hbm = LoadBitmap(hInst,szName);
/* look for a resource of the form WxH */
if (!hbm) { wsprintf(szName,"%s%dx%d", lpName, dxScreen, dyScreen); hbm = LoadBitmap(hInst,szName); }
/* look for the default resource name */
if (!hbm) { hbm = LoadBitmap(hInst,lpName); }
return hbm; }
#if 0
/*******************
** ** Name: FindGray ** ** Purpose: Responsible for finding (if possible) a dark gray ** on the curent device. ** ** Arguments: rgb - value for gray ** ** Returns: RGB value for dark gray ** *******************/
DWORD FindGray(DWORD rgb) { int r,g,b; HDC hdc;
hdc = GetDC(NULL);
rgb == NearestColor(hdc,rgb);
r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb);
while ((r>0 || g>0 || b>0) && rgb == NearestColor(hdc,RGB(r,g,b))) { if (r > 0) r -= 63; if (g > 0) g -= 63; if (b > 0) b -= 63; }
rgb = NearestColor(hdc,RGB(r,g,b));
ReleaseDC(NULL,hdc); return rgb; }
#endif
|