|
|
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.