|
|
1.1 ! root 1: /* ! 2: * BTTNCUR.C ! 3: * Buttons & Cursors Version 1.1, March 1993 ! 4: * ! 5: * Public functions to generate different states of toolbar buttons from ! 6: * a single bitmap. States are normal, pressed, checked, and disabled. ! 7: * ! 8: * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved, ! 9: * as applied to redistribution of this source code in source form ! 10: * License is granted to use of compiled code in shipped binaries. ! 11: */ ! 12: ! 13: #ifdef WIN32 ! 14: #define _INC_OLE ! 15: #define __RPC_H__ ! 16: #endif ! 17: ! 18: ! 19: #define STRICT ! 20: #include <windows.h> ! 21: #include <memory.h> ! 22: #include "bttncur.h" ! 23: #include "bttncuri.h" ! 24: ! 25: ! 26: ! 27: //Display sensitive information ! 28: TOOLDISPLAYDATA tdd; ! 29: ! 30: //Library instance ! 31: HINSTANCE ghInst; ! 32: ! 33: ! 34: //Cache GDI objects to speed drawing. ! 35: HDC hDCGlyphs = NULL; ! 36: HDC hDCMono = NULL; ! 37: HBRUSH hBrushDither = NULL; ! 38: ! 39: //Standard images to use in case caller doesn't provide them ! 40: HBITMAP rghBmpStandardImages[3]; ! 41: ! 42: //Standard button colors. ! 43: const COLORREF crStandard[4]={ RGB(0, 0, 0) //STDCOLOR_BLACK ! 44: , RGB(128, 128, 128) //STDCOLOR_DKGRAY ! 45: , RGB(192, 192, 192) //STDCOLOR_LTGRAY ! 46: , RGB(255, 255, 255)}; //STDCOLOR_WHITE ! 47: ! 48: ! 49: /* ! 50: * Mapping from image identifier to button type (command/attribute). ! 51: * Version 1.00 of this DLL has no attribute images defined, so ! 52: * the code will only support three states for each command ! 53: * button. Any state is, however, valid for an application ! 54: * defined image. ! 55: */ ! 56: ! 57: UINT mpButtonType[TOOLIMAGE_MAX-TOOLIMAGE_MIN+1]= ! 58: { ! 59: BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, ! 60: BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, ! 61: BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND ! 62: }; ! 63: ! 64: ! 65: ! 66: ! 67: /* ! 68: * LibMain ! 69: * ! 70: * Purpose: ! 71: * DLL-specific entry point called from LibEntry. Initializes ! 72: * global variables and loads standard image bitmaps. ! 73: * ! 74: * Parameters: ! 75: * hInstance HANDLE instance of the DLL. ! 76: * wDataSeg WORD segment selector of the DLL's data segment. ! 77: * wHeapSize WORD byte count of the heap. ! 78: * lpCmdLine LPSTR to command line used to start the module. ! 79: * ! 80: * Return Value: ! 81: * HANDLE Instance handle of the DLL. ! 82: */ ! 83: ! 84: BOOL xxxLibMain(HINSTANCE hInstance) ! 85: { ! 86: int i; ! 87: ! 88: ghInst=hInstance; ! 89: ! 90: tdd.uDPI =96; ! 91: tdd.cyBar =CYBUTTONBAR96; ! 92: tdd.cxButton =TOOLBUTTON_STD96WIDTH; ! 93: tdd.cyButton =TOOLBUTTON_STD96HEIGHT; ! 94: tdd.cxImage =TOOLBUTTON_STD96IMAGEWIDTH; ! 95: tdd.cyImage =TOOLBUTTON_STD96IMAGEHEIGHT; ! 96: tdd.uIDImages=IDB_STANDARDIMAGES96; ! 97: ! 98: for (i=0; i < 3; i++) ! 99: { ! 100: rghBmpStandardImages[i]=LoadBitmap(hInstance ! 101: , MAKEINTRESOURCE(IDB_STANDARDIMAGESMIN+i)); ! 102: ! 103: if (NULL==rghBmpStandardImages[i]) ! 104: return FALSE; ! 105: } ! 106: ! 107: ! 108: //Perform global initialization. ! 109: if (ToolButtonInit()) ! 110: { ! 111: CursorsCache(hInstance); ! 112: ! 113: ! 114: return TRUE; ! 115: } ! 116: ! 117: return FALSE; ! 118: ! 119: } ! 120: ! 121: #ifdef WIN32 ! 122: ! 123: extern BOOL WINAPI _CRT_INIT(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved); ! 124: extern _cexit(void); ! 125: void FAR PASCAL WEP(int); ! 126: ! 127: extern BOOL __stdcall LibMain ! 128: ( ! 129: HINSTANCE hInstance, ! 130: ULONG Reason, ! 131: PCONTEXT Context ! 132: ) ! 133: { ! 134: OutputDebugString("bttncur LibMain: bttncur.dll loaded\r\n"); ! 135: ! 136: UNREFERENCED_PARAMETER(Context); ! 137: ! 138: if (Reason == DLL_PROCESS_DETACH) { ! 139: ! 140: _CRT_INIT(hInstance,Reason,NULL); ! 141: WEP(0); ! 142: return TRUE; ! 143: } ! 144: else if (Reason != DLL_PROCESS_ATTACH) ! 145: return TRUE; ! 146: ! 147: if (!_CRT_INIT(hInstance,Reason,NULL)) ! 148: return FALSE; ! 149: ! 150: return xxxLibMain(hInstance); ! 151: ! 152: } ! 153: ! 154: #else ! 155: ! 156: HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg ! 157: , WORD cbHeapSize, LPSTR lpCmdLine) ! 158: { ! 159: ! 160: //Perform global initialization. ! 161: if (xxxLibMain(hInstance)) ! 162: if (0!=cbHeapSize) ! 163: UnlockData(0); ! 164: ! 165: return hInstance; ! 166: ! 167: } ! 168: ! 169: #endif ! 170: ! 171: ! 172: /* ! 173: * WEP ! 174: * ! 175: * Purpose: ! 176: * Required DLL Exit function. Does nothing. ! 177: * ! 178: * Parameters: ! 179: * bSystemExit BOOL indicating if the system is being shut ! 180: * down or the DLL has just been unloaded. ! 181: * ! 182: * Return Value: ! 183: * void ! 184: * ! 185: */ ! 186: ! 187: void FAR PASCAL WEP(int bSystemExit) ! 188: { ! 189: /* ! 190: * **Developers: Note that WEP is called AFTER Windows does any ! 191: * automatic task cleanup. You may see warnings for ! 192: * that two DCs, a bitmap, and a brush, were not ! 193: * deleted before task termination. THIS IS NOT A ! 194: * PROBLEM WITH THIS CODE AND IT IS NOT A BUG. This ! 195: * WEP function is properly called and performs the ! 196: * cleanup as appropriate. The fact that Windows is ! 197: * calling WEP after checking task cleanup is not ! 198: * something we can control. Just to prove it, the ! 199: * OutputDebugStrings in this and ToolButtonFree ! 200: * show that the code is exercised. ! 201: */ ! 202: ! 203: #ifdef DEBUG ! 204: OutputDebugString("WEP Entry\r\n"); ! 205: #endif ! 206: ! 207: CursorsFree(); ! 208: ToolButtonFree(); ! 209: ! 210: #ifdef DEBUG ! 211: OutputDebugString("WEP Exit\r\n"); ! 212: #endif ! 213: return; ! 214: } ! 215: ! 216: ! 217: ! 218: ! 219: ! 220: /* ! 221: * UIToolConfigureForDisplay ! 222: * Public API ! 223: * ! 224: * Purpose: ! 225: * Initializes the library to scale button images for the display type. ! 226: * Without calling this function the library defaults to 96 DPI (VGA). ! 227: * By calling this function an application acknowledges that it must ! 228: * use the data returned from this function to configure itself for ! 229: * the display. ! 230: * ! 231: * Parameters: ! 232: * lpDD LPTOOLDISPLAYDATA to fill with the display-sensitive ! 233: * size values. ! 234: * ! 235: * Return Value: ! 236: * BOOL TRUE if the sizes were obtained, FALSE otherwise. ! 237: */ ! 238: ! 239: BOOL WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA lpDD) ! 240: { ! 241: int cy; ! 242: HDC hDC; ! 243: ! 244: ! 245: if (NULL==lpDD || IsBadWritePtr(lpDD, sizeof(TOOLDISPLAYDATA))) ! 246: return FALSE; ! 247: ! 248: /* ! 249: * Determine the aspect ratio of the display we're currently ! 250: * running on and calculate the necessary information. ! 251: * ! 252: * By retrieving the logical Y extent of the display driver, you ! 253: * only have limited possibilities: ! 254: * LOGPIXELSY Display ! 255: * ---------------------------------------- ! 256: * 48 CGA (unsupported) ! 257: * 72 EGA ! 258: * 96 VGA ! 259: * 120 8514/a (i.e. HiRes VGA) ! 260: */ ! 261: ! 262: hDC=GetDC(NULL); ! 263: ! 264: if (NULL==hDC) ! 265: return FALSE; ! 266: ! 267: cy=GetDeviceCaps(hDC, LOGPIXELSY); ! 268: ReleaseDC(NULL, hDC); ! 269: ! 270: /* ! 271: * Instead of single comparisons, check ranges instead, so in case ! 272: * we get something funky, we'll act reasonable. ! 273: */ ! 274: if (72 >=cy) ! 275: { ! 276: lpDD->uDPI =72; ! 277: lpDD->cyBar =CYBUTTONBAR72; ! 278: lpDD->cxButton =TOOLBUTTON_STD72WIDTH; ! 279: lpDD->cyButton =TOOLBUTTON_STD72HEIGHT; ! 280: lpDD->cxImage =TOOLBUTTON_STD72IMAGEWIDTH; ! 281: lpDD->cyImage =TOOLBUTTON_STD72IMAGEHEIGHT; ! 282: lpDD->uIDImages=IDB_STANDARDIMAGES72; ! 283: } ! 284: else ! 285: { ! 286: if (72 < cy && 120 > cy) ! 287: { ! 288: lpDD->uDPI =96; ! 289: lpDD->cyBar =CYBUTTONBAR96; ! 290: lpDD->cxButton =TOOLBUTTON_STD96WIDTH; ! 291: lpDD->cyButton =TOOLBUTTON_STD96HEIGHT; ! 292: lpDD->cxImage =TOOLBUTTON_STD96IMAGEWIDTH; ! 293: lpDD->cyImage =TOOLBUTTON_STD96IMAGEHEIGHT; ! 294: lpDD->uIDImages=IDB_STANDARDIMAGES96; ! 295: } ! 296: else ! 297: { ! 298: lpDD->uDPI =120; ! 299: lpDD->cyBar =CYBUTTONBAR120; ! 300: lpDD->cxButton =TOOLBUTTON_STD120WIDTH; ! 301: lpDD->cyButton =TOOLBUTTON_STD120HEIGHT; ! 302: lpDD->cxImage =TOOLBUTTON_STD120IMAGEWIDTH; ! 303: lpDD->cyImage =TOOLBUTTON_STD120IMAGEHEIGHT; ! 304: lpDD->uIDImages=IDB_STANDARDIMAGES120; ! 305: } ! 306: } ! 307: ! 308: return TRUE; ! 309: } ! 310: ! 311: ! 312: ! 313: ! 314: ! 315: ! 316: ! 317: ! 318: /* ! 319: * ToolButtonInit ! 320: * Internal ! 321: * ! 322: * Purpose: ! 323: * Initializes GDI objects for drawing images through UIToolButtonDraw. ! 324: * If the function fails, the function has already performed proper ! 325: * cleanup. ! 326: * ! 327: * Parameters: ! 328: * None ! 329: * ! 330: * Return Value: ! 331: * BOOL TRUE if initialization succeeded. FALSE otherwise. ! 332: */ ! 333: ! 334: static BOOL ToolButtonInit(void) ! 335: { ! 336: COLORREF rgbHi; ! 337: ! 338: //DC for BitBltting the image (the glyph) ! 339: hDCGlyphs=CreateCompatibleDC(NULL); ! 340: ! 341: //Create a monochrome DC and a brush for doing pattern dithering. ! 342: hDCMono=CreateCompatibleDC(NULL); ! 343: ! 344: //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white. ! 345: if (0x0300 < (UINT)GetVersion()) ! 346: rgbHi=GetSysColor(COLOR_BTNHIGHLIGHT); ! 347: else ! 348: rgbHi=crStandard[STDCOLOR_WHITE]; ! 349: ! 350: hBrushDither=HBrushDitherCreate(GetSysColor(COLOR_BTNFACE), rgbHi); ! 351: ! 352: if (NULL==hDCGlyphs || NULL==hDCMono || NULL==hBrushDither) ! 353: { ! 354: //On failure, cleanup whatever might have been allocated. ! 355: ToolButtonFree(); ! 356: return FALSE; ! 357: } ! 358: ! 359: return TRUE; ! 360: } ! 361: ! 362: ! 363: ! 364: ! 365: ! 366: /* ! 367: * ToolButtonFree ! 368: * Internal ! 369: * ! 370: * Purpose: ! 371: * Free all GDI allocations made during initialization. Note that the ! 372: * DEBUG output included here shows that WEP is called and cleanup actually ! 373: * occurs. However, if you watch debug output in DBWIN or on a terminal, ! 374: * the debugging version of Windows does automatic app cleanup before WEP ! 375: * is called, leading some to believe that this code is buggy. The ! 376: * debug output below shows that we do perform all necessary cleanup. ! 377: * ! 378: * Parameters: ! 379: * None ! 380: * ! 381: * Return Value: ! 382: * None ! 383: */ ! 384: ! 385: static void ToolButtonFree(void) ! 386: { ! 387: UINT i; ! 388: ! 389: if (NULL!=hDCMono) ! 390: DeleteDC(hDCMono); ! 391: hDCMono=NULL; ! 392: ! 393: ! 394: if (NULL!=hDCGlyphs) ! 395: DeleteDC(hDCGlyphs); ! 396: hDCGlyphs=NULL; ! 397: ! 398: if (NULL!=hBrushDither) ! 399: DeleteObject(hBrushDither); ! 400: hBrushDither=NULL; ! 401: ! 402: for (i=0; i < 3; i++) ! 403: { ! 404: if (NULL!=rghBmpStandardImages[i]) ! 405: DeleteObject(rghBmpStandardImages[i]); ! 406: rghBmpStandardImages[i]=NULL; ! 407: } ! 408: ! 409: return; ! 410: } ! 411: ! 412: ! 413: ! 414: ! 415: ! 416: /* ! 417: * HBrushDitherCreate ! 418: * Internal ! 419: * ! 420: * Purpose: ! 421: * Creates and returns a handle to a pattern brush created from ! 422: * an 8*8 monochrome pattern bitmap. We use the button face and ! 423: * highlight colors to indicate the resulting colors of a PatBlt ! 424: * using this brush. ! 425: * ! 426: * Parameters: ! 427: * rgbFace COLORREF of the button face color. ! 428: * rgbHilight COLORREF of the button highlight color. ! 429: * ! 430: * Return Value: ! 431: * HBITMAP Handle to the dither bitmap. ! 432: */ ! 433: ! 434: static HBRUSH HBrushDitherCreate(COLORREF rgbFace, COLORREF rgbHilight) ! 435: { ! 436: struct //BITMAPINFO with 16 colors ! 437: { ! 438: BITMAPINFOHEADER bmiHeader; ! 439: RGBQUAD bmiColors[16]; ! 440: } bmi; ! 441: ! 442: HBRUSH hBrush=NULL; ! 443: DWORD patGray[8]; ! 444: HDC hDC; ! 445: HBITMAP hBmp; ! 446: static COLORREF rgbFaceOld =0xFFFFFFFF; //Initially an impossible color ! 447: static COLORREF rgbHilightOld=0xFFFFFFFF; //so at first we always create ! 448: ! 449: /* ! 450: * If the colors haven't changed from last time, just return the ! 451: * existing brush. ! 452: */ ! 453: if (rgbFace==rgbFaceOld && rgbHilight==rgbHilightOld) ! 454: return hBrushDither; ! 455: ! 456: rgbFaceOld=rgbFace; ! 457: rgbHilightOld=rgbHilight; ! 458: ! 459: /* ! 460: * We're going to create an 8*8 brush for PatBlt using the ! 461: * button face color and button highlight color. We use this ! 462: * brush to affect the pressed state and the disabled state. ! 463: */ ! 464: bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); ! 465: bmi.bmiHeader.biWidth = 8; ! 466: bmi.bmiHeader.biHeight = 8; ! 467: bmi.bmiHeader.biPlanes = 1; ! 468: bmi.bmiHeader.biBitCount = 1; ! 469: bmi.bmiHeader.biCompression = BI_RGB; ! 470: bmi.bmiHeader.biSizeImage = 0; ! 471: bmi.bmiHeader.biXPelsPerMeter= 0; ! 472: bmi.bmiHeader.biYPelsPerMeter= 0; ! 473: bmi.bmiHeader.biClrUsed = 0; ! 474: bmi.bmiHeader.biClrImportant = 0; ! 475: ! 476: bmi.bmiColors[0].rgbBlue = GetBValue(rgbFace); ! 477: bmi.bmiColors[0].rgbGreen = GetGValue(rgbFace); ! 478: bmi.bmiColors[0].rgbRed = GetRValue(rgbFace); ! 479: bmi.bmiColors[0].rgbReserved = 0; ! 480: ! 481: bmi.bmiColors[1].rgbBlue = GetBValue(rgbHilight); ! 482: bmi.bmiColors[1].rgbGreen = GetGValue(rgbHilight); ! 483: bmi.bmiColors[1].rgbRed = GetRValue(rgbHilight); ! 484: bmi.bmiColors[1].rgbReserved = 0; ! 485: ! 486: //Create the byte array for CreateDIBitmap. ! 487: patGray[6]=patGray[4]=patGray[2]=patGray[0]=0x5555AAAAL; ! 488: patGray[7]=patGray[5]=patGray[3]=patGray[1]=0xAAAA5555L; ! 489: ! 490: //Create the bitmap ! 491: hDC=GetDC(NULL); ! 492: hBmp=CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT, patGray ! 493: , (LPBITMAPINFO)&bmi, DIB_RGB_COLORS); ! 494: ReleaseDC(NULL, hDC); ! 495: ! 496: //Create the brush from the bitmap ! 497: if (NULL!=hBmp) ! 498: { ! 499: hBrush=CreatePatternBrush(hBmp); ! 500: DeleteObject(hBmp); ! 501: } ! 502: ! 503: /* ! 504: * If we could recreate a brush, clean up and make it the current ! 505: * pattern. Otherwise the best we can do it return the old one, ! 506: * which will be colored wrong, but at least it works. ! 507: */ ! 508: if (NULL!=hBrush) ! 509: { ! 510: if (NULL!=hBrushDither) ! 511: DeleteObject(hBrushDither); ! 512: ! 513: hBrushDither=hBrush; ! 514: } ! 515: ! 516: return hBrushDither; ! 517: } ! 518: ! 519: ! 520: ! 521: ! 522: ! 523: /* ! 524: * UIToolButtonDraw ! 525: * Public API ! 526: * ! 527: * Purpose: ! 528: * Draws the complete image of a toolbar-style button with a given ! 529: * image in the center and in a specific state. The button is drawn ! 530: * on a specified hDC at a given location, so this function is useful ! 531: * on standard owner-draw buttons as well as on toolbar controls that ! 532: * have only one window but show images of multiple buttons. ! 533: * ! 534: * Parameters: ! 535: * hDC HDC on which to draw. ! 536: * x, y int coordinates at which to draw. ! 537: * dx, dy int dimensions of the *button*, not necessarily the image. ! 538: * hBmp HBITMAP from which to draw the image. ! 539: * bmx, bmy int dimensions of each bitmap in hBmp. If hBmp is NULL ! 540: * then these are forced to the standard sizes. ! 541: * iImage int index to the image to draw in the button ! 542: * uStateIn UINT containing the state index for the button and the ! 543: * color control bits. ! 544: * ! 545: * Return Value: ! 546: * BOOL TRUE if drawing succeeded, FALSE otherwise meaning that ! 547: * hDC is NULL or hBmp is NULL and iImage is not a valid ! 548: * index for a standard image. ! 549: */ ! 550: ! 551: BOOL WINAPI UIToolButtonDraw(HDC hDC, int x, int y, int dx, int dy ! 552: , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn) ! 553: { ! 554: return UIToolButtonDrawTDD(hDC, x, y, dx, dy, hBmp, bmx, bmy, iImage ! 555: , uStateIn, &tdd); ! 556: } ! 557: ! 558: ! 559: ! 560: ! 561: ! 562: ! 563: /* ! 564: * UIToolButtonDrawTDD ! 565: * Public API ! 566: * ! 567: * Purpose: ! 568: * Draws the complete image of a toolbar-style button with a given ! 569: * image in the center and in a specific state. The button is drawn ! 570: * on a specified hDC at a given location, so this function is useful ! 571: * on standard owner-draw buttons as well as on toolbar controls that ! 572: * have only one window but show images of multiple buttons. ! 573: * ! 574: * This is the same as UIToolButtonDraw but adds the pTDD configuration ! 575: * structure. UIToolButtonDraw calls us with that pointing to the ! 576: * default 96dpi structure. ! 577: * ! 578: * Parameters: ! 579: * hDC HDC on which to draw. ! 580: * x, y int coordinates at which to draw. ! 581: * dx, dy int dimensions of the *button*, not necessarily the image. ! 582: * hBmp HBITMAP from which to draw the image. ! 583: * bmx, bmy int dimensions of each bitmap in hBmp. If hBmp is NULL ! 584: * then these are forced to the standard sizes. ! 585: * iImage int index to the image to draw in the button ! 586: * uStateIn UINT containing the state index for the button and the ! 587: * color control bits. ! 588: * pTDD LPTOOLDISPLAYDATA containing display configuration. ! 589: * Can be NULL if hBmp is non-NULL. ! 590: * ! 591: * Return Value: ! 592: * BOOL TRUE if drawing succeeded, FALSE otherwise meaning that ! 593: * hDC is NULL or hBmp is NULL and iImage is not a valid ! 594: * index for a standard image. ! 595: */ ! 596: ! 597: BOOL WINAPI UIToolButtonDrawTDD(HDC hDC, int x, int y, int dx, int dy ! 598: , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn ! 599: , LPTOOLDISPLAYDATA pTDD) ! 600: { ! 601: static COLORREF crSys[5]; //Avoid stack arrays in DLLs: use static ! 602: UINT uState=(UINT)LOBYTE((WORD)uStateIn); ! 603: UINT uColors=(UINT)HIBYTE((WORD)uStateIn & PRESERVE_ALL); ! 604: int xOffsetGlyph, yOffsetGlyph; ! 605: int i, iSaveDC; ! 606: HDC hMemDC; ! 607: HGDIOBJ hObj; ! 608: HBRUSH hBR; ! 609: HBITMAP hBmpT; ! 610: HBITMAP hBmpMono; ! 611: HBITMAP hBmpMonoOrg; ! 612: HBITMAP hBmpSave=NULL; ! 613: ! 614: if (NULL==hDC) ! 615: return FALSE; ! 616: ! 617: /* ! 618: * If we're given no image bitmap, then use the standard and validate the ! 619: * image index. We also enforce the standard bitmap size and the size of ! 620: * the button (as requested by User Interface designers). ! 621: */ ! 622: if (NULL==hBmp && !(uState & BUTTONGROUP_BLANK)) ! 623: { ! 624: hBmp=rghBmpStandardImages[pTDD->uIDImages-IDB_STANDARDIMAGESMIN]; ! 625: ! 626: bmx=pTDD->cxImage; //Force bitmap dimensions ! 627: bmy=pTDD->cyImage; ! 628: ! 629: dx=pTDD->cxButton; //Force button dimensions ! 630: dy=pTDD->cyButton; ! 631: ! 632: if (iImage > TOOLIMAGE_MAX) ! 633: return FALSE; ! 634: ! 635: /* ! 636: * If we are using a standard command button, verify that the state ! 637: * does not contain the LIGHTFACE group which only applies to ! 638: * attribute buttons. ! 639: */ ! 640: if (BUTTONTYPE_COMMAND==mpButtonType[iImage] ! 641: && (uState & BUTTONGROUP_LIGHTFACE)) ! 642: return FALSE; ! 643: } ! 644: ! 645: //Create a dithered bitmap. ! 646: hBmpMono=CreateBitmap(dx-2, dy-2, 1, 1, NULL); ! 647: ! 648: if (NULL==hBmpMono) ! 649: return FALSE; ! 650: ! 651: hBmpMonoOrg=(HBITMAP)SelectObject(hDCMono, hBmpMono); ! 652: ! 653: ! 654: //Save the DC state before we munge on it. ! 655: iSaveDC=SaveDC(hDC); ! 656: ! 657: /* ! 658: * Draw a button sans image. This also fills crSys with the system ! 659: * colors for us which has space for five colors. We don't use the ! 660: * fifth, the frame color, in this function. ! 661: */ ! 662: DrawBlankButton(hDC, x, y, dx, dy, (BOOL)(uState & BUTTONGROUP_DOWN), crSys); ! 663: ! 664: //Shift coordinates to account for the button's border ! 665: x++; ! 666: y++; ! 667: dx-=2; ! 668: dy-=2; ! 669: ! 670: /* ! 671: * Determine the offset necessary to center the image but also reflect ! 672: * the pushed-in state, which means just adding 1 to the up state. ! 673: */ ! 674: i=(uState & BUTTONGROUP_DOWN) ? 1 : 0; ! 675: xOffsetGlyph=((dx-bmx) >> 1)+i; ! 676: yOffsetGlyph=((dy-bmy) >> 1)+i; ! 677: ! 678: ! 679: //Select the given image bitmap into the glyph DC before calling MaskCreate ! 680: if (NULL!=hBmp) ! 681: hBmpSave=(HBITMAP)SelectObject(hDCGlyphs, hBmp); ! 682: ! 683: ! 684: /* ! 685: * Draw the face on the button. If we have an up or [mouse]down ! 686: * button then we can just draw it as-is. For indeterminate, ! 687: * disabled, or down disabled we have to gray the image and possibly ! 688: * add a white shadow to it (disabled/down disabled). ! 689: * ! 690: * Also note that for the intermediate state we first draw the normal ! 691: * up state, then proceed to add disabling looking highlights. ! 692: */ ! 693: ! 694: //Up, mouse down, down, indeterminate ! 695: if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK)) ! 696: { ! 697: BOOL fColorsSame=TRUE; ! 698: ! 699: /* ! 700: * In here we pay close attention to the system colors. Where ! 701: * the source image is black, we paint COLOR_BTNTEXT. Where ! 702: * light gray, we paint COLOR_BTNFACE. Where dark gray we paint ! 703: * COLOR_BTNSHADOW, and where white we paint COLOR_BTNHILIGHT. ! 704: * ! 705: * The uColors variable contains flags to prevent color ! 706: * conversion. To do a little optimization, we just do a ! 707: * single BitBlt if we're preserving all colors or if no colors ! 708: * are different than the standards, which is by far the most ! 709: * common case. Otherwise, cycle through the four colors we can ! 710: * convert and do a BitBlt that converts it to the system color. ! 711: */ ! 712: ! 713: //See what colors are different. ! 714: for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++) ! 715: fColorsSame &= (crSys[i]==crStandard[i]); ! 716: ! 717: if (PRESERVE_ALL==uColors || fColorsSame) ! 718: { ! 719: BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, bmx, bmy ! 720: , hDCGlyphs, iImage*bmx, 0, SRCCOPY); ! 721: } ! 722: else ! 723: { ! 724: /* ! 725: * Cycle through hard-coded colors and create a mask that has all ! 726: * regions of that color in white and all other regions black. ! 727: * Then we select a pattern brush of the color to convert to: ! 728: * if we aren't converting the color then we use a brush of ! 729: * the standard hard-coded color, otherwise we use the actual ! 730: * system color. The ROP_DSPDxax means that anything that's ! 731: * 1's in the mask get the pattern, anything that's 0 is unchanged ! 732: * in the destination. ! 733: * ! 734: * To prevent too many Blts to the screen, we use an intermediate ! 735: * bitmap and DC. ! 736: */ ! 737: ! 738: hMemDC=CreateCompatibleDC(hDC); ! 739: ! 740: //Make sure conversion of monochrome to color stays B&W ! 741: SetTextColor(hMemDC, 0L); //0's in mono -> 0 ! 742: SetBkColor(hMemDC, (COLORREF)0x00FFFFFF); //1's in mono -> 1 ! 743: ! 744: hBmpT=CreateCompatibleBitmap(hDC, bmx, bmy); ! 745: SelectObject(hMemDC, hBmpT); ! 746: ! 747: //Copy the unmodified bitmap to the temporary bitmap ! 748: BitBlt(hMemDC, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY); ! 749: ! 750: for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++) ! 751: { ! 752: //Convert pixels of the color to convert to 1's in the mask ! 753: SetBkColor(hDCGlyphs, crStandard[i]); ! 754: BitBlt(hDCMono, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY); ! 755: ! 756: //Preserve or modify the color depending on the flag. ! 757: hBR=CreateSolidBrush((uColors & (1 << i)) ! 758: ? crStandard[i] : crSys[i]); ! 759: ! 760: if (NULL!=hBR) ! 761: { ! 762: hObj=SelectObject(hMemDC, hBR); ! 763: ! 764: if (NULL!=hObj) ! 765: { ! 766: BitBlt(hMemDC, 0, 0, dx-1, dy-1, hDCMono, 0, 0, ROP_DSPDxax); ! 767: SelectObject(hMemDC, hObj); ! 768: } ! 769: ! 770: DeleteObject(hBR); ! 771: } ! 772: } ! 773: ! 774: //Now put the final version on the display and clean up ! 775: BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, dx-1, dy-1 ! 776: , hMemDC, 0, 0, SRCCOPY); ! 777: ! 778: DeleteDC(hMemDC); ! 779: DeleteObject(hBmpT); ! 780: ! 781: } ! 782: } ! 783: ! 784: ! 785: //Disabled and indeterminate states (unless we're blank) ! 786: if ((uState & BUTTONGROUP_DISABLED || ATTRIBUTEBUTTON_INDETERMINATE==uState) ! 787: && !(uState & BUTTONGROUP_BLANK)) ! 788: { ! 789: //Grayed state (up or down, no difference) ! 790: MaskCreate(iImage, dx, dy, bmx, bmy, xOffsetGlyph, yOffsetGlyph, 0); ! 791: ! 792: //Make sure conversion of monochrome to color stays B&W ! 793: SetTextColor(hDC, 0L); //0's in mono -> 0 ! 794: SetBkColor(hDC, (COLORREF)0x00FFFFFF); //1's in mono -> 1 ! 795: ! 796: //If we're disabled, up or down, draw the highlighted shadow. ! 797: if (uState & BUTTONGROUP_DISABLED) ! 798: { ! 799: hBR=CreateSolidBrush(crSys[SYSCOLOR_HILIGHT]); ! 800: ! 801: if (NULL!=hBR) ! 802: { ! 803: hObj=SelectObject(hDC, hBR); ! 804: ! 805: if (NULL!=hObj) ! 806: { ! 807: //Draw hilight color where we have 0's in the mask ! 808: BitBlt(hDC, x+1, y+1, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax); ! 809: SelectObject(hDC, hObj); ! 810: } ! 811: DeleteObject(hBR); ! 812: } ! 813: } ! 814: ! 815: //Draw the gray image. ! 816: hBR=CreateSolidBrush(crSys[SYSCOLOR_SHADOW]); ! 817: ! 818: if (NULL!=hBR) ! 819: { ! 820: hObj=SelectObject(hDC, hBR); ! 821: ! 822: if (NULL!=hObj) ! 823: { ! 824: //Draw the shadow color where we have 0's in the mask ! 825: BitBlt(hDC, x, y, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax); ! 826: SelectObject(hDC, hObj); ! 827: } ! 828: ! 829: DeleteObject(hBR); ! 830: } ! 831: } ! 832: ! 833: //If the button is selected do the dither brush avoiding the glyph ! 834: if (uState & BUTTONGROUP_LIGHTFACE) ! 835: { ! 836: HBRUSH hBRDither; ! 837: ! 838: /* ! 839: * Get the dither brush. This function will recreate it if ! 840: * necessary or return the global one if the colors already match. ! 841: */ ! 842: hBRDither=HBrushDitherCreate(crSys[SYSCOLOR_FACE], crSys[SYSCOLOR_HILIGHT]); ! 843: hObj=SelectObject(hDC, hBRDither); ! 844: ! 845: if (NULL!=hObj) ! 846: { ! 847: /* ! 848: * The mask we create now determines where the dithering ! 849: * ends up. In the down disabled state, we have to preserve ! 850: * the highlighted shadow, so the mask we create must have ! 851: * two masks of the original glyph, one of them offset by ! 852: * one pixel in both x & y. For the indeterminate state, ! 853: * we have to mask all highlighted areas. The state passed ! 854: * to MaskCreate matters here (we've used zero before). ! 855: */ ! 856: MaskCreate(iImage, dx, dy, bmx, bmy ! 857: , xOffsetGlyph-1, yOffsetGlyph-1, uState); ! 858: ! 859: //Convert monochrome masks to B&W color bitmap in the BitBlt. ! 860: SetTextColor(hDC, 0L); ! 861: SetBkColor(hDC, (COLORREF)0x00FFFFFF); ! 862: ! 863: /* ! 864: * Only draw the dither brush where the mask is 1's. For ! 865: * the indeterminate state we have to not overdraw the ! 866: * shadow highlight so we use dx-3, dy-3 instead of dx-1 ! 867: * and dy-1. We do this whether or not we're blank. ! 868: */ ! 869: i=(ATTRIBUTEBUTTON_INDETERMINATE==uState ! 870: || BLANKBUTTON_INDETERMINATE==uState) ? 3 : 1; ! 871: ! 872: BitBlt(hDC, x+1, y+1, dx-i, dy-i, hDCMono, 0, 0, ROP_DSPDxax); ! 873: SelectObject(hDC, hObj); ! 874: } ! 875: ! 876: //DO NOT delete hBRDither! It's a reference to a shared global. ! 877: } ! 878: ! 879: //Cleanup hDCGlyphs: Must do AFTER calling MaskCreate ! 880: if (NULL!=hBmpSave) ! 881: SelectObject(hDCGlyphs, hBmpSave); ! 882: ! 883: SelectObject(hDCMono, hBmpMonoOrg); ! 884: DeleteObject(hBmpMono); ! 885: ! 886: //Restore everything in the DC. ! 887: RestoreDC(hDC, iSaveDC); ! 888: return TRUE; ! 889: } ! 890: ! 891: ! 892: ! 893: ! 894: ! 895: ! 896: /* ! 897: * DrawBlankButton ! 898: * ! 899: * Purpose: ! 900: * Draws a button with no face using the current system colors in either ! 901: * an up or down state. ! 902: * ! 903: * Parameters: ! 904: * hDC HDC on which to draw ! 905: * x, y int coordinates where we start drawing ! 906: * dx,dy int size of the button ! 907: * fDown BOOL indicating the up or down state of the button ! 908: * pcr COLORREF FAR * to five colors in which we store text, ! 909: * shadow, face, highlight, and frame colors. This is ! 910: * a matter of convenience for the caller, since we have ! 911: * to load these colors anyway we might as well send them ! 912: * back. ! 913: * ! 914: * Return Value: ! 915: * None ! 916: */ ! 917: ! 918: static void DrawBlankButton(HDC hDC, int x, int y, int dx, int dy ! 919: , BOOL fDown, COLORREF FAR *pcr) ! 920: { ! 921: //Get the current system colors for buttons. ! 922: pcr[0]=GetSysColor(COLOR_BTNTEXT); ! 923: pcr[1]=GetSysColor(COLOR_BTNSHADOW); ! 924: pcr[2]=GetSysColor(COLOR_BTNFACE); ! 925: ! 926: //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white. ! 927: if (0x0300 < (UINT)GetVersion()) ! 928: pcr[3]=GetSysColor(COLOR_BTNHIGHLIGHT); ! 929: else ! 930: pcr[3]=crStandard[STDCOLOR_WHITE]; ! 931: ! 932: pcr[4]=GetSysColor(COLOR_WINDOWFRAME); ! 933: ! 934: //Draw the border around the button. ! 935: PatB(hDC, x+1, y, dx-2, 1, pcr[4]); ! 936: PatB(hDC, x+1, y+dy-1, dx-2, 1, pcr[4]); ! 937: PatB(hDC, x, y+1, 1, dy-2, pcr[4]); ! 938: PatB(hDC, x+dx-1, y+1, 1, dy-2, pcr[4]); ! 939: ! 940: //Shift coordinates to account for the border we just drew ! 941: x++; ! 942: y++; ! 943: dx-=2; ! 944: dy-=2; ! 945: ! 946: //Paint the interior grey as a default. ! 947: PatB(hDC, x, y, dx, dy, pcr[2]); ! 948: ! 949: /* ! 950: * Draw shadows and highlights. The DOWN grouping that contains ! 951: * down, mouse down, and down disabled are drawn depressed. Up, ! 952: * indeterminate, and disabled are drawn up. ! 953: */ ! 954: ! 955: if (fDown) ! 956: { ! 957: PatB(hDC, x, y, 1, dy, pcr[1]); ! 958: PatB(hDC, x, y, dx, 1, pcr[1]); ! 959: } ! 960: else ! 961: { ! 962: //Normal button look. ! 963: PatB(hDC, x, y, 1, dy-1, pcr[3]); ! 964: PatB(hDC, x, y, dx-1, 1, pcr[3]); ! 965: ! 966: PatB(hDC, x+dx-1, y, 1, dy, pcr[1]); ! 967: PatB(hDC, x, y+dy-1, dx, 1, pcr[1]); ! 968: ! 969: PatB(hDC, x+1+dx-3, y+1, 1, dy-2, pcr[1]); ! 970: PatB(hDC, x+1, y+dy-2, dx-2, 1, pcr[1]); ! 971: } ! 972: ! 973: return; ! 974: } ! 975: ! 976: ! 977: ! 978: ! 979: ! 980: ! 981: /* ! 982: * PatB ! 983: * Internal ! 984: * ! 985: * Purpose: ! 986: * A more convenient PatBlt operation for drawing button borders and ! 987: * highlights. ! 988: * ! 989: * Parameters: ! 990: * hDC HDC on which to paint. ! 991: * x, y int coordinates at which to paint. ! 992: * dx, dy int dimensions of rectangle to paint. ! 993: * rgb COLORREF to use as the background color. ! 994: * ! 995: * Return Value: ! 996: * None ! 997: */ ! 998: ! 999: static void PatB(HDC hDC, int x, int y, int dx, int dy, COLORREF rgb) ! 1000: { ! 1001: RECT rc; ! 1002: ! 1003: SetBkColor(hDC, rgb); ! 1004: SetRect(&rc, x, y, x+dx, y+dy); ! 1005: ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); ! 1006: } ! 1007: ! 1008: ! 1009: ! 1010: ! 1011: /* ! 1012: * MaskCreate ! 1013: * Internal ! 1014: * ! 1015: * Purpose: ! 1016: * Creates a monochrome mask bitmap of the given image at the given offset ! 1017: * in the global hDCMono. Anywhere in the image that you have the light ! 1018: * gray (STDCOLOR_LTGRAY) or the white highlight (STDCOLOR_WHITE) you get ! 1019: * get 1's. All other pixels are 0's ! 1020: * ! 1021: * Parameters: ! 1022: * iImage UINT index of the image for which to create a mask. ! 1023: * dx, dy int dimensions of the button. ! 1024: * bmx, bmy int dimensions of the bitmap to use. ! 1025: * xOffset int offset for x inside hDCMono where we paint. ! 1026: * yOffset int offset for y inside hDCMono where we paint. ! 1027: * uState UINT state of the image. Special cases are made ! 1028: * for ATTRIBUTEBUTTON_DOWNDISABLED and ! 1029: * ATTRIBUTEBUTTON_INDETERMINATE. In any case where you ! 1030: * do not want a special case, pass zero here, regardless ! 1031: * of the true button state. ! 1032: * ! 1033: * Return Value: ! 1034: * None ! 1035: */ ! 1036: ! 1037: static void MaskCreate(UINT iImage, int dx, int dy, int bmx, int bmy ! 1038: ,int xOffset, int yOffset, UINT uState) ! 1039: { ! 1040: //Initalize whole area with zeros ! 1041: PatBlt(hDCMono, 0, 0, dx, dy, WHITENESS); ! 1042: ! 1043: if (uState & BUTTONGROUP_BLANK) ! 1044: return; ! 1045: ! 1046: //Convert face colored pixels to 1's. all others to black. ! 1047: SetBkColor(hDCGlyphs, crStandard[STDCOLOR_LTGRAY]); ! 1048: BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY); ! 1049: ! 1050: //In the indeterminate state, don't turn highlight's to 1's. Leave black. ! 1051: if (ATTRIBUTEBUTTON_INDETERMINATE!=uState) ! 1052: { ! 1053: //Convert highlight colored pixels to 1's and OR them with the previous. ! 1054: SetBkColor(hDCGlyphs, crStandard[STDCOLOR_WHITE]); ! 1055: BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCPAINT); ! 1056: } ! 1057: ! 1058: /* ! 1059: * For the down disabled state, AND this same mask with itself at an ! 1060: * offset of 1, which accounts for the highlight shadow. ! 1061: */ ! 1062: if (ATTRIBUTEBUTTON_DOWNDISABLED==uState) ! 1063: BitBlt(hDCMono, 1, 1, dx-1, dy-1, hDCMono, 0, 0, SRCAND); ! 1064: ! 1065: return; ! 1066: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.