diff options
Diffstat (limited to 'private/oleutest/letest/bttncur/bttncur.c')
-rw-r--r-- | private/oleutest/letest/bttncur/bttncur.c | 1070 |
1 files changed, 1070 insertions, 0 deletions
diff --git a/private/oleutest/letest/bttncur/bttncur.c b/private/oleutest/letest/bttncur/bttncur.c new file mode 100644 index 000000000..4e5dee40f --- /dev/null +++ b/private/oleutest/letest/bttncur/bttncur.c @@ -0,0 +1,1070 @@ +/* + * BTTNCUR.C + * Buttons & Cursors Version 1.1, Win32 version August 1993 + * + * Public functions to generate different states of toolbar buttons from + * a single bitmap. States are normal, pressed, checked, and disabled. + * + * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved, + * as applied to redistribution of this source code in source form + * License is granted to use of compiled code in shipped binaries. + */ + +#ifdef WIN32 +#define _INC_OLE +#define __RPC_H__ +#endif + +#include <windows.h> +#include <memory.h> +#include "bttncur.h" +#include "bttncuri.h" + + +//Display sensitive information +TOOLDISPLAYDATA tdd; + +//Library instance +HINSTANCE ghInst; + + +//Cache GDI objects to speed drawing. +HDC hDCGlyphs = NULL; +HDC hDCMono = NULL; +HBRUSH hBrushDither = NULL; + +// Common clean up code +void FAR PASCAL WEP(int bSystemExit); + + +//Standard images to use in case caller doesn't provide them +HBITMAP rghBmpStandardImages[3]; + +//Standard button colors. +const COLORREF crStandard[4]={ RGB(0, 0, 0) //STDCOLOR_BLACK + , RGB(128, 128, 128) //STDCOLOR_DKGRAY + , RGB(192, 192, 192) //STDCOLOR_LTGRAY + , RGB(255, 255, 255)}; //STDCOLOR_WHITE + + +/* + * Mapping from image identifier to button type (command/attribute). + * Version 1.00 of this DLL has no attribute images defined, so + * the code will only support three states for each command + * button. Any state is, however, valid for an application + * defined image. + */ + +UINT mpButtonType[TOOLIMAGE_MAX-TOOLIMAGE_MIN+1]= + { + BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, + BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, + BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND + }; + + + +/* + * LibMain + * + * Purpose: + * Entry point conditionally compiled for Windows NT and Windows + * 3.1. Provides the proper structure for each environment + * and calls InternalLibMain for real initialization. + */ + +#ifdef WIN32 +BOOL _cdecl LibMain( + HINSTANCE hDll, + DWORD dwReason, + LPVOID lpvReserved) + { + if (DLL_PROCESS_ATTACH == dwReason) + { + return FInitialize(hDll); + } + else if (DLL_PROCESS_DETACH == dwReason) + { + WEP(0); + } + else + { + return TRUE; + } + } + +#else +HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg + , WORD cbHeapSize, LPSTR lpCmdLine) + { + //Perform global initialization. + if (FInitialize(hInstance)) + { + if (0!=cbHeapSize) + UnlockData(0); + } + + return hInstance; + } +#endif + + + + +/* + * FInitialize + * + * Purpose: + * Initialization function for the DLL. + * + * Parameters: + * hInstance HANDLE instance of the DLL. + * + * Return Value: + * BOOL TRUE if the function was successful, FALSE otherwise. + */ + +BOOL FInitialize(HANDLE hInstance) + { + UINT i; + + /* + * To remain backwards compatible with 1.0 we'll default to 96DPI + * like we forced in the older version. If the application calls + * UIToolButtonDraw we use the values here. If the application + * calls UIToolButtonDrawTDD then we use the pointer to the + * application-provided TOOLDISPLAYDATA structure. + */ + tdd.uDPI =96; + tdd.cyBar =CYBUTTONBAR96; + tdd.cxButton =TOOLBUTTON_STD96WIDTH; + tdd.cyButton =TOOLBUTTON_STD96HEIGHT; + tdd.cxImage =TOOLBUTTON_STD96IMAGEWIDTH; + tdd.cyImage =TOOLBUTTON_STD96IMAGEHEIGHT; + tdd.uIDImages=IDB_STANDARDIMAGES96; + + for (i=0; i < 3; i++) + { + rghBmpStandardImages[i]=LoadBitmap(hInstance + , MAKEINTRESOURCE(IDB_STANDARDIMAGESMIN+i)); + + if (NULL==rghBmpStandardImages[i]) + return FALSE; + } + + ghInst=hInstance; + + //Perform global initialization. + if (ToolButtonInit()) + { + CursorsCache(hInstance); + return TRUE; + } + + return FALSE; + } + + + + +/* + * WEP + * + * Purpose: + * Required DLL Exit function. Does nothing. + * + * Parameters: + * bSystemExit BOOL indicating if the system is being shut + * down or the DLL has just been unloaded. + * + * Return Value: + * void + * + */ + +void FAR PASCAL WEP(int bSystemExit) + { + /* + * **Developers: Note that WEP is called AFTER Windows does any + * automatic task cleanup. You may see warnings for + * that two DCs, a bitmap, and a brush, were not + * deleted before task termination. THIS IS NOT A + * PROBLEM WITH THIS CODE AND IT IS NOT A BUG. This + * WEP function is properly called and performs the + * cleanup as appropriate. The fact that Windows is + * calling WEP after checking task cleanup is not + * something we can control. Just to prove it, the + * OutputDebugStrings in this and ToolButtonFree + * show that the code is exercised. + */ + + #ifdef DEBUG + OutputDebugString("BTTNCUR.DLL: WEP Entry\r\n"); + OutputDebugString("BTTNCUR.DLL: The two DC's, the brush, and the three\r\n"); + OutputDebugString("BTTNCUR.DLL: bitmaps that Debug Windows shows\r\n"); + OutputDebugString("BTTNCUR.DLL: above were detected BEFORE this WEP\r\n"); + OutputDebugString("BTTNCUR.DLL: had a chance to do it! NOT A BUG!\r\n"); + #endif + + CursorsFree(); + ToolButtonFree(); + + #ifdef DEBUG + OutputDebugString("BTTNCUR.DLL: WEP Exit\r\n"); + #endif + return; + } + + + + + +/* + * UIToolConfigureForDisplay + * Public API + * + * Purpose: + * Initializes the library to scale button images for the display type. + * Without calling this function the library defaults to 96 DPI (VGA). + * By calling this function an application acknowledges that it must + * use the data returned from this function to configure itself for + * the display. + * + * Parameters: + * lpDD LPTOOLDISPLAYDATA to fill with the display-sensitive + * size values. + * + * Return Value: + * BOOL TRUE if the sizes were obtained, FALSE otherwise. + */ + +BOOL WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA lpDD) + { + int cy; + HDC hDC; + + + if (NULL==lpDD || IsBadWritePtr(lpDD, sizeof(TOOLDISPLAYDATA))) + return FALSE; + + /* + * Determine the aspect ratio of the display we're currently + * running on and calculate the necessary information. + * + * By retrieving the logical Y extent of the display driver, you + * only have limited possibilities: + * LOGPIXELSY Display + * ---------------------------------------- + * 48 CGA (unsupported) + * 72 EGA + * 96 VGA + * 120 8514/a (i.e. HiRes VGA) + */ + + hDC=GetDC(NULL); + + if (NULL==hDC) + return FALSE; + + cy=GetDeviceCaps(hDC, LOGPIXELSY); + ReleaseDC(NULL, hDC); + + /* + * Instead of single comparisons, check ranges instead, so in case + * we get something funky, we'll act reasonable. + */ + if (72 >=cy) + { + lpDD->uDPI =72; + lpDD->cyBar =CYBUTTONBAR72; + lpDD->cxButton =TOOLBUTTON_STD72WIDTH; + lpDD->cyButton =TOOLBUTTON_STD72HEIGHT; + lpDD->cxImage =TOOLBUTTON_STD72IMAGEWIDTH; + lpDD->cyImage =TOOLBUTTON_STD72IMAGEHEIGHT; + lpDD->uIDImages=IDB_STANDARDIMAGES72; + } + else + { + if (72 < cy && 120 > cy) + { + lpDD->uDPI =96; + lpDD->cyBar =CYBUTTONBAR96; + lpDD->cxButton =TOOLBUTTON_STD96WIDTH; + lpDD->cyButton =TOOLBUTTON_STD96HEIGHT; + lpDD->cxImage =TOOLBUTTON_STD96IMAGEWIDTH; + lpDD->cyImage =TOOLBUTTON_STD96IMAGEHEIGHT; + lpDD->uIDImages=IDB_STANDARDIMAGES96; + } + else + { + lpDD->uDPI =120; + lpDD->cyBar =CYBUTTONBAR120; + lpDD->cxButton =TOOLBUTTON_STD120WIDTH; + lpDD->cyButton =TOOLBUTTON_STD120HEIGHT; + lpDD->cxImage =TOOLBUTTON_STD120IMAGEWIDTH; + lpDD->cyImage =TOOLBUTTON_STD120IMAGEHEIGHT; + lpDD->uIDImages=IDB_STANDARDIMAGES120; + } + } + + return TRUE; + } + + + + + + + + +/* + * ToolButtonInit + * Internal + * + * Purpose: + * Initializes GDI objects for drawing images through UIToolButtonDraw. + * If the function fails, the function has already performed proper + * cleanup. + * + * Parameters: + * None + * + * Return Value: + * BOOL TRUE if initialization succeeded. FALSE otherwise. + */ + +static BOOL ToolButtonInit(void) + { + COLORREF rgbHi; + + //DC for BitBltting the image (the glyph) + hDCGlyphs=CreateCompatibleDC(NULL); + + //Create a monochrome DC and a brush for doing pattern dithering. + hDCMono=CreateCompatibleDC(NULL); + + //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white. + if (0x0300 < (UINT)GetVersion()) + rgbHi=GetSysColor(COLOR_BTNHIGHLIGHT); + else + rgbHi=crStandard[STDCOLOR_WHITE]; + + hBrushDither=HBrushDitherCreate(GetSysColor(COLOR_BTNFACE), rgbHi); + + if (NULL==hDCGlyphs || NULL==hDCMono || NULL==hBrushDither) + { + //On failure, cleanup whatever might have been allocated. + ToolButtonFree(); + return FALSE; + } + + return TRUE; + } + + + + + +/* + * ToolButtonFree + * Internal + * + * Purpose: + * Free all GDI allocations made during initialization. Note that the + * DEBUG output included here shows that WEP is called and cleanup actually + * occurs. However, if you watch debug output in DBWIN or on a terminal, + * the debugging version of Windows does automatic app cleanup before WEP + * is called, leading some to believe that this code is buggy. The + * debug output below shows that we do perform all necessary cleanup. + * + * Parameters: + * None + * + * Return Value: + * None + */ + +static void ToolButtonFree(void) + { + UINT i; + + if (NULL!=hDCMono) + DeleteDC(hDCMono); + + hDCMono=NULL; + + if (NULL!=hDCGlyphs) + DeleteDC(hDCGlyphs); + + hDCGlyphs=NULL; + + if (NULL!=hBrushDither) + DeleteObject(hBrushDither); + + hBrushDither=NULL; + + for (i=0; i < 3; i++) + { + if (NULL!=rghBmpStandardImages[i]) + DeleteObject(rghBmpStandardImages[i]); + rghBmpStandardImages[i]=NULL; + } + + return; + } + + + + + +/* + * HBrushDitherCreate + * Internal + * + * Purpose: + * Creates and returns a handle to a pattern brush created from + * an 8*8 monochrome pattern bitmap. We use the button face and + * highlight colors to indicate the resulting colors of a PatBlt + * using this brush. + * + * Parameters: + * rgbFace COLORREF of the button face color. + * rgbHilight COLORREF of the button highlight color. + * + * Return Value: + * HBITMAP Handle to the dither bitmap. + */ + +static HBRUSH HBrushDitherCreate(COLORREF rgbFace, COLORREF rgbHilight) + { + struct //BITMAPINFO with 16 colors + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[16]; + } bmi; + + HBRUSH hBrush=NULL; + DWORD patGray[8]; + HDC hDC; + HBITMAP hBmp; + static COLORREF rgbFaceOld =0xFFFFFFFF; //Initially an impossible color + static COLORREF rgbHilightOld=0xFFFFFFFF; //so at first we always create + + /* + * If the colors haven't changed from last time, just return the + * existing brush. + */ + if (rgbFace==rgbFaceOld && rgbHilight==rgbHilightOld) + return hBrushDither; + + rgbFaceOld=rgbFace; + rgbHilightOld=rgbHilight; + + /* + * We're going to create an 8*8 brush for PatBlt using the + * button face color and button highlight color. We use this + * brush to affect the pressed state and the disabled state. + */ + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 8; + bmi.bmiHeader.biHeight = 8; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter= 0; + bmi.bmiHeader.biYPelsPerMeter= 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + bmi.bmiColors[0].rgbBlue = GetBValue(rgbFace); + bmi.bmiColors[0].rgbGreen = GetGValue(rgbFace); + bmi.bmiColors[0].rgbRed = GetRValue(rgbFace); + bmi.bmiColors[0].rgbReserved = 0; + + bmi.bmiColors[1].rgbBlue = GetBValue(rgbHilight); + bmi.bmiColors[1].rgbGreen = GetGValue(rgbHilight); + bmi.bmiColors[1].rgbRed = GetRValue(rgbHilight); + bmi.bmiColors[1].rgbReserved = 0; + + //Create the byte array for CreateDIBitmap. + patGray[6]=patGray[4]=patGray[2]=patGray[0]=0x5555AAAAL; + patGray[7]=patGray[5]=patGray[3]=patGray[1]=0xAAAA5555L; + + //Create the bitmap + hDC=GetDC(NULL); + hBmp=CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT, patGray + , (LPBITMAPINFO)&bmi, DIB_RGB_COLORS); + ReleaseDC(NULL, hDC); + + //Create the brush from the bitmap + if (NULL!=hBmp) + { + hBrush=CreatePatternBrush(hBmp); + DeleteObject(hBmp); + } + + /* + * If we could recreate a brush, clean up and make it the current + * pattern. Otherwise the best we can do it return the old one, + * which will be colored wrong, but at least it works. + */ + if (NULL!=hBrush) + { + if (NULL!=hBrushDither) + DeleteObject(hBrushDither); + + hBrushDither=hBrush; + } + + return hBrushDither; + } + + + + + +/* + * UIToolButtonDraw + * Public API + * + * Purpose: + * Draws the complete image of a toolbar-style button with a given + * image in the center and in a specific state. The button is drawn + * on a specified hDC at a given location, so this function is useful + * on standard owner-draw buttons as well as on toolbar controls that + * have only one window but show images of multiple buttons. + * + * Parameters: + * hDC HDC on which to draw. + * x, y int coordinates at which to draw. + * dx, dy int dimensions of the *button*, not necessarily the image. + * hBmp HBITMAP from which to draw the image. + * bmx, bmy int dimensions of each bitmap in hBmp. If hBmp is NULL + * then these are forced to the standard sizes. + * iImage int index to the image to draw in the button + * uStateIn UINT containing the state index for the button and the + * color control bits. + * + * Return Value: + * BOOL TRUE if drawing succeeded, FALSE otherwise meaning that + * hDC is NULL or hBmp is NULL and iImage is not a valid + * index for a standard image. + */ + +BOOL WINAPI UIToolButtonDraw(HDC hDC, int x, int y, int dx, int dy + , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn) + { + return UIToolButtonDrawTDD(hDC, x, y, dx, dy, hBmp, bmx, bmy, iImage + , uStateIn, &tdd); + } + + + + + + +/* + * UIToolButtonDrawTDD + * Public API + * + * Purpose: + * Draws the complete image of a toolbar-style button with a given + * image in the center and in a specific state. The button is drawn + * on a specified hDC at a given location, so this function is useful + * on standard owner-draw buttons as well as on toolbar controls that + * have only one window but show images of multiple buttons. + * + * This is the same as UIToolButtonDraw but adds the pTDD configuration + * structure. UIToolButtonDraw calls us with that pointing to the + * default 96dpi structure. + * + * Parameters: + * hDC HDC on which to draw. + * x, y int coordinates at which to draw. + * dx, dy int dimensions of the *button*, not necessarily the image. + * hBmp HBITMAP from which to draw the image. + * bmx, bmy int dimensions of each bitmap in hBmp. If hBmp is NULL + * then these are forced to the standard sizes. + * iImage int index to the image to draw in the button + * uStateIn UINT containing the state index for the button and the + * color control bits. + * pTDD LPTOOLDISPLAYDATA containing display configuration. + * Can be NULL if hBmp is non-NULL. + * + * Return Value: + * BOOL TRUE if drawing succeeded, FALSE otherwise meaning that + * hDC is NULL or hBmp is NULL and iImage is not a valid + * index for a standard image. + */ + +BOOL WINAPI UIToolButtonDrawTDD(HDC hDC, int x, int y, int dx, int dy + , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn + , LPTOOLDISPLAYDATA pTDD) + { + static COLORREF crSys[5]; //Avoid stack arrays in DLLs: use static + UINT uState=(UINT)LOBYTE((WORD)uStateIn); + UINT uColors=(UINT)HIBYTE((WORD)uStateIn & PRESERVE_ALL); + int xOffsetGlyph, yOffsetGlyph; + int i, iSaveDC; + HDC hMemDC; + HGDIOBJ hObj; + HBRUSH hBR; + HBITMAP hBmpT; + HBITMAP hBmpMono; + HBITMAP hBmpMonoOrg; + HBITMAP hBmpSave=NULL; + + if (NULL==hDC) + return FALSE; + + /* + * If we're given no image bitmap, then use the standard and validate the + * image index. We also enforce the standard bitmap size and the size of + * the button (as requested by User Interface designers). + */ + if (NULL==hBmp && !(uState & BUTTONGROUP_BLANK)) + { + hBmp=rghBmpStandardImages[pTDD->uIDImages-IDB_STANDARDIMAGESMIN]; + + bmx=pTDD->cxImage; //Force bitmap dimensions + bmy=pTDD->cyImage; + + dx=pTDD->cxButton; //Force button dimensions + dy=pTDD->cyButton; + + if (iImage > TOOLIMAGE_MAX) + return FALSE; + + /* + * If we are using a standard command button, verify that the state + * does not contain the LIGHTFACE group which only applies to + * attribute buttons. + */ + if (BUTTONTYPE_COMMAND==mpButtonType[iImage] + && (uState & BUTTONGROUP_LIGHTFACE)) + return FALSE; + } + + //Create a dithered bitmap. + hBmpMono=CreateBitmap(dx-2, dy-2, 1, 1, NULL); + + if (NULL==hBmpMono) + return FALSE; + + hBmpMonoOrg=(HBITMAP)SelectObject(hDCMono, hBmpMono); + + + //Save the DC state before we munge on it. + iSaveDC=SaveDC(hDC); + + /* + * Draw a button sans image. This also fills crSys with the system + * colors for us which has space for five colors. We don't use the + * fifth, the frame color, in this function. + */ + DrawBlankButton(hDC, x, y, dx, dy, (BOOL)(uState & BUTTONGROUP_DOWN), crSys); + + //Shift coordinates to account for the button's border + x++; + y++; + dx-=2; + dy-=2; + + /* + * Determine the offset necessary to center the image but also reflect + * the pushed-in state, which means just adding 1 to the up state. + */ + i=(uState & BUTTONGROUP_DOWN) ? 1 : 0; + xOffsetGlyph=((dx-bmx) >> 1)+i; + yOffsetGlyph=((dy-bmy) >> 1)+i; + + + //Select the given image bitmap into the glyph DC before calling MaskCreate + if (NULL!=hBmp) + hBmpSave=(HBITMAP)SelectObject(hDCGlyphs, hBmp); + + + /* + * Draw the face on the button. If we have an up or [mouse]down + * button then we can just draw it as-is. For indeterminate, + * disabled, or down disabled we have to gray the image and possibly + * add a white shadow to it (disabled/down disabled). + * + * Also note that for the intermediate state we first draw the normal + * up state, then proceed to add disabling looking highlights. + */ + + //Up, mouse down, down, indeterminate + if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK)) + { + BOOL fColorsSame=TRUE; + + /* + * In here we pay close attention to the system colors. Where + * the source image is black, we paint COLOR_BTNTEXT. Where + * light gray, we paint COLOR_BTNFACE. Where dark gray we paint + * COLOR_BTNSHADOW, and where white we paint COLOR_BTNHILIGHT. + * + * The uColors variable contains flags to prevent color + * conversion. To do a little optimization, we just do a + * single BitBlt if we're preserving all colors or if no colors + * are different than the standards, which is by far the most + * common case. Otherwise, cycle through the four colors we can + * convert and do a BitBlt that converts it to the system color. + */ + + //See what colors are different. + for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++) + fColorsSame &= (crSys[i]==crStandard[i]); + + if (PRESERVE_ALL==uColors || fColorsSame) + { + BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, bmx, bmy + , hDCGlyphs, iImage*bmx, 0, SRCCOPY); + } + else + { + /* + * Cycle through hard-coded colors and create a mask that has all + * regions of that color in white and all other regions black. + * Then we select a pattern brush of the color to convert to: + * if we aren't converting the color then we use a brush of + * the standard hard-coded color, otherwise we use the actual + * system color. The ROP_DSPDxax means that anything that's + * 1's in the mask get the pattern, anything that's 0 is unchanged + * in the destination. + * + * To prevent too many Blts to the screen, we use an intermediate + * bitmap and DC. + */ + + hMemDC=CreateCompatibleDC(hDC); + + //Make sure conversion of monochrome to color stays B&W + SetTextColor(hMemDC, 0L); //0's in mono -> 0 + SetBkColor(hMemDC, (COLORREF)0x00FFFFFF); //1's in mono -> 1 + + hBmpT=CreateCompatibleBitmap(hDC, bmx, bmy); + SelectObject(hMemDC, hBmpT); + + //Copy the unmodified bitmap to the temporary bitmap + BitBlt(hMemDC, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY); + + for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++) + { + //Convert pixels of the color to convert to 1's in the mask + SetBkColor(hDCGlyphs, crStandard[i]); + BitBlt(hDCMono, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY); + + //Preserve or modify the color depending on the flag. + hBR=CreateSolidBrush((uColors & (1 << i)) + ? crStandard[i] : crSys[i]); + + if (NULL!=hBR) + { + hObj=SelectObject(hMemDC, hBR); + + if (NULL!=hObj) + { + BitBlt(hMemDC, 0, 0, dx-1, dy-1, hDCMono, 0, 0, ROP_DSPDxax); + SelectObject(hMemDC, hObj); + } + + DeleteObject(hBR); + } + } + + //Now put the final version on the display and clean up + BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, dx-1, dy-1 + , hMemDC, 0, 0, SRCCOPY); + + DeleteDC(hMemDC); + DeleteObject(hBmpT); + + } + } + + + //Disabled and indeterminate states (unless we're blank) + if ((uState & BUTTONGROUP_DISABLED || ATTRIBUTEBUTTON_INDETERMINATE==uState) + && !(uState & BUTTONGROUP_BLANK)) + { + //Grayed state (up or down, no difference) + MaskCreate(iImage, dx, dy, bmx, bmy, xOffsetGlyph, yOffsetGlyph, 0); + + //Make sure conversion of monochrome to color stays B&W + SetTextColor(hDC, 0L); //0's in mono -> 0 + SetBkColor(hDC, (COLORREF)0x00FFFFFF); //1's in mono -> 1 + + //If we're disabled, up or down, draw the highlighted shadow. + if (uState & BUTTONGROUP_DISABLED) + { + hBR=CreateSolidBrush(crSys[SYSCOLOR_HILIGHT]); + + if (NULL!=hBR) + { + hObj=SelectObject(hDC, hBR); + + if (NULL!=hObj) + { + //Draw hilight color where we have 0's in the mask + BitBlt(hDC, x+1, y+1, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax); + SelectObject(hDC, hObj); + } + DeleteObject(hBR); + } + } + + //Draw the gray image. + hBR=CreateSolidBrush(crSys[SYSCOLOR_SHADOW]); + + if (NULL!=hBR) + { + hObj=SelectObject(hDC, hBR); + + if (NULL!=hObj) + { + //Draw the shadow color where we have 0's in the mask + BitBlt(hDC, x, y, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax); + SelectObject(hDC, hObj); + } + + DeleteObject(hBR); + } + } + + //If the button is selected do the dither brush avoiding the glyph + if (uState & BUTTONGROUP_LIGHTFACE) + { + HBRUSH hBRDither; + + /* + * Get the dither brush. This function will recreate it if + * necessary or return the global one if the colors already match. + */ + hBRDither=HBrushDitherCreate(crSys[SYSCOLOR_FACE], crSys[SYSCOLOR_HILIGHT]); + hObj=SelectObject(hDC, hBRDither); + + if (NULL!=hObj) + { + /* + * The mask we create now determines where the dithering + * ends up. In the down disabled state, we have to preserve + * the highlighted shadow, so the mask we create must have + * two masks of the original glyph, one of them offset by + * one pixel in both x & y. For the indeterminate state, + * we have to mask all highlighted areas. The state passed + * to MaskCreate matters here (we've used zero before). + */ + MaskCreate(iImage, dx, dy, bmx, bmy + , xOffsetGlyph-1, yOffsetGlyph-1, uState); + + //Convert monochrome masks to B&W color bitmap in the BitBlt. + SetTextColor(hDC, 0L); + SetBkColor(hDC, (COLORREF)0x00FFFFFF); + + /* + * Only draw the dither brush where the mask is 1's. For + * the indeterminate state we have to not overdraw the + * shadow highlight so we use dx-3, dy-3 instead of dx-1 + * and dy-1. We do this whether or not we're blank. + */ + i=(ATTRIBUTEBUTTON_INDETERMINATE==uState + || BLANKBUTTON_INDETERMINATE==uState) ? 3 : 1; + + BitBlt(hDC, x+1, y+1, dx-i, dy-i, hDCMono, 0, 0, ROP_DSPDxax); + SelectObject(hDC, hObj); + } + + //DO NOT delete hBRDither! It's a reference to a shared global. + } + + //Cleanup hDCGlyphs: Must do AFTER calling MaskCreate + if (NULL!=hBmpSave) + SelectObject(hDCGlyphs, hBmpSave); + + SelectObject(hDCMono, hBmpMonoOrg); + DeleteObject(hBmpMono); + + //Restore everything in the DC. + RestoreDC(hDC, iSaveDC); + return TRUE; + } + + + + + + +/* + * DrawBlankButton + * + * Purpose: + * Draws a button with no face using the current system colors in either + * an up or down state. + * + * Parameters: + * hDC HDC on which to draw + * x, y int coordinates where we start drawing + * dx,dy int size of the button + * fDown BOOL indicating the up or down state of the button + * pcr COLORREF FAR * to five colors in which we store text, + * shadow, face, highlight, and frame colors. This is + * a matter of convenience for the caller, since we have + * to load these colors anyway we might as well send them + * back. + * + * Return Value: + * None + */ + +static void DrawBlankButton(HDC hDC, int x, int y, int dx, int dy + , BOOL fDown, COLORREF FAR *pcr) + { + //Get the current system colors for buttons. + pcr[0]=GetSysColor(COLOR_BTNTEXT); + pcr[1]=GetSysColor(COLOR_BTNSHADOW); + pcr[2]=GetSysColor(COLOR_BTNFACE); + + //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white. + if (0x0300 < (UINT)GetVersion()) + pcr[3]=GetSysColor(COLOR_BTNHIGHLIGHT); + else + pcr[3]=crStandard[STDCOLOR_WHITE]; + + pcr[4]=GetSysColor(COLOR_WINDOWFRAME); + + //Draw the border around the button. + PatB(hDC, x+1, y, dx-2, 1, pcr[4]); + PatB(hDC, x+1, y+dy-1, dx-2, 1, pcr[4]); + PatB(hDC, x, y+1, 1, dy-2, pcr[4]); + PatB(hDC, x+dx-1, y+1, 1, dy-2, pcr[4]); + + //Shift coordinates to account for the border we just drew + x++; + y++; + dx-=2; + dy-=2; + + //Paint the interior grey as a default. + PatB(hDC, x, y, dx, dy, pcr[2]); + + /* + * Draw shadows and highlights. The DOWN grouping that contains + * down, mouse down, and down disabled are drawn depressed. Up, + * indeterminate, and disabled are drawn up. + */ + + if (fDown) + { + PatB(hDC, x, y, 1, dy, pcr[1]); + PatB(hDC, x, y, dx, 1, pcr[1]); + } + else + { + //Normal button look. + PatB(hDC, x, y, 1, dy-1, pcr[3]); + PatB(hDC, x, y, dx-1, 1, pcr[3]); + + PatB(hDC, x+dx-1, y, 1, dy, pcr[1]); + PatB(hDC, x, y+dy-1, dx, 1, pcr[1]); + + PatB(hDC, x+1+dx-3, y+1, 1, dy-2, pcr[1]); + PatB(hDC, x+1, y+dy-2, dx-2, 1, pcr[1]); + } + + return; + } + + + + + + +/* + * PatB + * Internal + * + * Purpose: + * A more convenient PatBlt operation for drawing button borders and + * highlights. + * + * Parameters: + * hDC HDC on which to paint. + * x, y int coordinates at which to paint. + * dx, dy int dimensions of rectangle to paint. + * rgb COLORREF to use as the background color. + * + * Return Value: + * None + */ + +static void PatB(HDC hDC, int x, int y, int dx, int dy, COLORREF rgb) + { + RECT rc; + + SetBkColor(hDC, rgb); + SetRect(&rc, x, y, x+dx, y+dy); + ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); + } + + + + +/* + * MaskCreate + * Internal + * + * Purpose: + * Creates a monochrome mask bitmap of the given image at the given offset + * in the global hDCMono. Anywhere in the image that you have the light + * gray (STDCOLOR_LTGRAY) or the white highlight (STDCOLOR_WHITE) you get + * get 1's. All other pixels are 0's + * + * Parameters: + * iImage UINT index of the image for which to create a mask. + * dx, dy int dimensions of the button. + * bmx, bmy int dimensions of the bitmap to use. + * xOffset int offset for x inside hDCMono where we paint. + * yOffset int offset for y inside hDCMono where we paint. + * uState UINT state of the image. Special cases are made + * for ATTRIBUTEBUTTON_DOWNDISABLED and + * ATTRIBUTEBUTTON_INDETERMINATE. In any case where you + * do not want a special case, pass zero here, regardless + * of the true button state. + * + * Return Value: + * None + */ + +static void MaskCreate(UINT iImage, int dx, int dy, int bmx, int bmy + ,int xOffset, int yOffset, UINT uState) + { + //Initalize whole area with zeros + PatBlt(hDCMono, 0, 0, dx, dy, WHITENESS); + + if (uState & BUTTONGROUP_BLANK) + return; + + //Convert face colored pixels to 1's. all others to black. + SetBkColor(hDCGlyphs, crStandard[STDCOLOR_LTGRAY]); + BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY); + + //In the indeterminate state, don't turn highlight's to 1's. Leave black. + if (ATTRIBUTEBUTTON_INDETERMINATE!=uState) + { + //Convert highlight colored pixels to 1's and OR them with the previous. + SetBkColor(hDCGlyphs, crStandard[STDCOLOR_WHITE]); + BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCPAINT); + } + + /* + * For the down disabled state, AND this same mask with itself at an + * offset of 1, which accounts for the highlight shadow. + */ + if (ATTRIBUTEBUTTON_DOWNDISABLED==uState) + BitBlt(hDCMono, 1, 1, dx-1, dy-1, hDCMono, 0, 0, SRCAND); + + return; + } |