/***************************************************************************************************************** FILENAME: Graphix.cpp COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. */ #include "stdafx.h" #ifndef SNAPIN #include #endif #include "ErrMacro.h" #include "Graphix.h" /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: This routine draws a one line border with given dimensions in the given HDC. INPUT: OutputDC - The HDC to draw into. pRect - The rect for the border -- it'll be drawn just on the inside edge. BorderType - 1 means indented border, 2 means raised border. RETURN: TRUE - Success. FALSE - Failure. */ BOOL DrawBorder( HDC OutputDC, RECT * pRect, int BorderType) { HPEN hPen1, hPen2; HGDIOBJ hOld; //Depending whether it is a raised or sunken border, just swap //white and black pens. switch(BorderType){ case 1: hPen1 = (HPEN)GetStockObject(BLACK_PEN); EF_ASSERT(hPen1); hPen2 = (HPEN)GetStockObject(WHITE_PEN); EF_ASSERT(hPen2); break; case 2: hPen1 = (HPEN)GetStockObject(WHITE_PEN); EF_ASSERT(hPen1); hPen2 = (HPEN)GetStockObject(BLACK_PEN); EF_ASSERT(hPen2); break; default: return FALSE; } //Draw the left and upper edges. if (hPen1) hOld = SelectObject(OutputDC, hPen1); MoveToEx(OutputDC, pRect->right, pRect->top, NULL); LineTo(OutputDC, pRect->left, pRect->top); LineTo(OutputDC, pRect->left, pRect->bottom); //Draw the lower and right edges. if (hPen2) SelectObject(OutputDC, hPen2); LineTo(OutputDC, pRect->right, pRect->bottom); LineTo(OutputDC, pRect->right, pRect->top); SelectObject(OutputDC, hOld); return TRUE; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: This routine draws a one line box with given dimensions in the given HDC. INPUT: OutputDC - The HDC to draw into. pRect - The rect for the border -- it'll be drawn just on the inside edge. crColor - The color of the box. RETURN: TRUE - Success. FALSE - Failure. */ BOOL ESIDrawEdge( HDC OutputDC, int startX, int startY, int endX, int endY) { // Highlight color for three-dimensional display elements (white) // (for edges facing the light source.) HPEN pen3DHilight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT)); EF_ASSERT(pen3DHilight); // Light color for three-dimensional display elements // (for edges facing the light source.) (grey) HPEN pen3DLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT)); EF_ASSERT(pen3DLight); // Face color for three-dimensional display elements (grey) HPEN pen3DFace = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DFACE)); EF_ASSERT(pen3DFace); // Shadow color for three-dimensional display elements // (for edges facing away from the light source). (dark grey) HPEN pen3DShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW)); EF_ASSERT(pen3DShadow); // Dark shadow for three-dimensional display elements (black) HPEN pen3DDKShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); EF_ASSERT(pen3DDKShadow); HGDIOBJ hOld = SelectObject(OutputDC, pen3DLight); MoveToEx(OutputDC, startX, startY++, NULL); LineTo(OutputDC, endX, endY++); SelectObject(OutputDC, pen3DHilight); MoveToEx(OutputDC, startX, startY++, NULL); LineTo(OutputDC, endX, endY++); for (int i=0; i<3; i++){ hOld = SelectObject(OutputDC, pen3DLight); MoveToEx(OutputDC, startX, startY++, NULL); LineTo(OutputDC, endX, endY++); } SelectObject(OutputDC, pen3DShadow); MoveToEx(OutputDC, startX, startY++, NULL); LineTo(OutputDC, endX, endY++); SelectObject(OutputDC, pen3DDKShadow); MoveToEx(OutputDC, startX, startY++, NULL); LineTo(OutputDC, endX, endY++); SelectObject(OutputDC, hOld); DeleteObject(pen3DHilight); DeleteObject(pen3DLight); DeleteObject(pen3DFace); DeleteObject(pen3DShadow); DeleteObject(pen3DDKShadow); return TRUE; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: This routine draws a one line border of given types with given dimensions and given colors in the given HDC. The colors are light and dark for 3D effect except for the PLAIN_BORDER which uses the crLight color. NOTE: There is NO error checking on the MoveToEx() and LineTo() routines. This is to maximize performance. INPUT: hdcOutput - HDC to draw into. prect - rect for the border - it'll be drawn just on the inside edge. iBorderType - PLAIN_BORDER - 2D SUNKEN_BORDER - 3D RAISED_BORDER - 3D SUNKEN_BOX - 3D RAISED_BOX - 3D HRESULT: S_OK ERROR_INVALID_PARAMETER */ HRESULT DrawBorderEx( IN HDC hdcOutput, IN RECT rect, IN int iBorderType ) { // Validate input. if(hdcOutput == NULL) { return ERROR_INVALID_PARAMETER; } // Highlight color for three-dimensional display elements (white) // (for edges facing the light source.) HPEN pen3DHilight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT)); EE_ASSERT(pen3DHilight); // Light color for three-dimensional display elements // (for edges facing the light source.) (grey) HPEN pen3DLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT)); EE_ASSERT(pen3DLight); // Face color for three-dimensional display elements (grey) HPEN pen3DFace = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DFACE)); EE_ASSERT(pen3DFace); // Shadow color for three-dimensional display elements // (for edges facing away from the light source). (dark grey) HPEN pen3DShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW)); EE_ASSERT(pen3DShadow); // Dark shadow for three-dimensional display elements (black) HPEN pen3DDKShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); EE_ASSERT(pen3DDKShadow); HGDIOBJ hOld = SelectObject(hdcOutput, pen3DLight); // Move to the top-right corner to start. MoveToEx(hdcOutput, rect.right, rect.top, NULL); // Depending whether it is a raised or sunken, swap the Dark and Light colors. switch(iBorderType) { case SUNKEN_BOX: //Draw the top and left sides with black SelectObject(hdcOutput, pen3DDKShadow); LineTo(hdcOutput, rect.left, rect.top); LineTo(hdcOutput, rect.left, rect.bottom); //Draw the right and bottom sides with white SelectObject(hdcOutput, pen3DHilight); LineTo(hdcOutput, rect.right, rect.bottom); LineTo(hdcOutput, rect.right, rect.top); break; case SUNKEN_BORDER: //Draw the top, left, right and bottom sides with dark grey SelectObject(hdcOutput, pen3DShadow); LineTo(hdcOutput, rect.left, rect.top); LineTo(hdcOutput, rect.left, rect.bottom); LineTo(hdcOutput, rect.right, rect.bottom); LineTo(hdcOutput, rect.right, rect.top); //Draw the top and left sides with white SelectObject(hdcOutput, pen3DHilight); MoveToEx(hdcOutput, rect.right-1, rect.top+1, NULL); LineTo(hdcOutput, rect.left+1, rect.top+1); LineTo(hdcOutput, rect.left+1, rect.bottom); //Draw the bottom and right sides with white MoveToEx(hdcOutput, rect.left, rect.bottom+1, NULL); LineTo(hdcOutput, rect.right+1, rect.bottom+1); LineTo(hdcOutput, rect.right+1, rect.top-1); break; case PLAIN_BORDER: //Draw the top, left, right and bottom sides black SelectObject(hdcOutput, pen3DDKShadow); LineTo(hdcOutput, rect.left, rect.top); LineTo(hdcOutput, rect.left, rect.bottom); LineTo(hdcOutput, rect.right, rect.bottom); LineTo(hdcOutput, rect.right, rect.top); break; case RAISED_BORDER: //Draw the top, left, right and bottom sides SelectObject(hdcOutput, pen3DHilight); LineTo(hdcOutput, rect.left, rect.top); LineTo(hdcOutput, rect.left, rect.bottom); LineTo(hdcOutput, rect.right, rect.bottom); LineTo(hdcOutput, rect.right, rect.top); //Draw the top and left sides SelectObject(hdcOutput, pen3DShadow); MoveToEx(hdcOutput, rect.right-1, rect.top+1, NULL); LineTo(hdcOutput, rect.left+1, rect.top+1); LineTo(hdcOutput, rect.left+1, rect.bottom); //Draw the bottom and right sides MoveToEx(hdcOutput, rect.left, rect.bottom+1, NULL); LineTo(hdcOutput, rect.right+1, rect.bottom+1); LineTo(hdcOutput, rect.right+1, rect.top-1); break; case RAISED_BOX: //Draw the top and left sides with black SelectObject(hdcOutput, pen3DDKShadow); LineTo(hdcOutput, rect.left, rect.top); LineTo(hdcOutput, rect.left, rect.bottom); //Draw the right and bottom sides SelectObject(hdcOutput, pen3DShadow); LineTo(hdcOutput, rect.right, rect.bottom); LineTo(hdcOutput, rect.right, rect.top); break; default: return ERROR_INVALID_PARAMETER; } // Replace the saved object. SelectObject(hdcOutput, hOld); DeleteObject(pen3DHilight); DeleteObject(pen3DLight); DeleteObject(pen3DFace); DeleteObject(pen3DShadow); DeleteObject(pen3DDKShadow); return S_OK; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: This routine draws a progress display of the specified size, color and percent done value. NOTE: There is NO error checking on the MoveToEx() and LineTo() routines. This is to maximize perfromance. GLOBAL DATA: INPUT: hdcOutput - HDC to draw into. prect - rect for the border - it'll be drawn just on the inside edge. hFont - The font to write text in. iWidth - width of the bars in pixels iSpace - the space between the bars in pixels - can be zero for a solid progress dsiplay iPercent - the percent done between 0 - 100. RETURN: HRESULT - S_OK HRESULT - ERROR_INVALID_PARAMETER */ HRESULT ProgressBar( IN HDC hdcOutput, IN RECT* prect, IN HFONT hFont, IN int iWidth, IN int iSpace, IN int iPercent ) { // Validate input - note if iPercent is the same as previously do nothing. if(iPercent > 100 || iWidth < 1 || hdcOutput == NULL || prect == NULL) { return ERROR_INVALID_PARAMETER; } int i, iStart, iEnd; //////////////////////////////////// // Set the progress bar back to zero //////////////////////////////////// // the null bar color HPEN hBlankBar = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_INACTIVECAPTION)); // if can't do it, use a stock object (this can't fail) if (hBlankBar == NULL) { hBlankBar = (HPEN)GetStockObject(WHITE_PEN); } // Select the new pen and save the current pen HGDIOBJ hOld; if (hBlankBar) hOld = SelectObject(hdcOutput, hBlankBar); // Get the start and end iStart = prect->left; iEnd = prect->right; while(iStart < iEnd) { // Draw a bar for(i=0; itop, NULL); // Draw the one vertical line. LineTo(hdcOutput, iStart, prect->bottom); } // Make the space between the bars iStart += iSpace; } // Replace the previous pen SelectObject(hdcOutput, hOld); // delete the new pen DeleteObject(hBlankBar); if (iPercent < 0) iPercent = 0; // We are done if iPercent is zero. if (iPercent == 0) return S_OK; //////////////////////////////////// // Now draw the progress //////////////////////////////////// // Adjust iPercent for decimal point //iPercent = 1000 / iPercent; // Calculate the end based on iPercent //iEnd = (10 * (prect->right - prect->left - 30)) / iPercent) + prect->left + 30; iEnd = prect->left + 30 + (prect->right - prect->left - 30) * iPercent / 100; // Get the start. iStart = prect->left; // Save the old pen and set the new one // the colored bar color HPEN hColorBar = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_ACTIVECAPTION)); // if can't do it, use a stock object (this can't fail) bug 455614 if (hColorBar == NULL) { hColorBar = (HPEN)GetStockObject(BLACK_PEN); } if (hColorBar) hOld = SelectObject(hdcOutput, hColorBar); while(iStart < iEnd) { // Draw a solid bar of iWidth pixels in size for(i=0; itop, NULL); // Draw the one vertical line. LineTo(hdcOutput, iStart, prect->bottom); } // Make the space iStart += iSpace; } // Go back to the old pen SelectObject(hdcOutput, hOld); // delete the progress bar pen DeleteObject(hColorBar); return S_OK; } /***************************************************************************************************************** CLASS: CBMP COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. CLASS DESCRIPTION: CBmp is a bitmap class. It will draw the bitmap and do various actions on the bitmap automatically. */ // This is the constructor for a single bitmap. CBmp::CBmp(HINSTANCE hInstance, LPTSTR BitmapResource) { hInst = hInstance; // So as not to confuse the rest of the class that is built for multiple bitmaps, // set this bitmap into a single bitmap array. BitmapArray = new HBITMAP [1]; // load it if (BitmapArray != NULL) { iNumBitmaps = 1; if ((BitmapArray[0] = LoadBitmap((HINSTANCE) hInst, BitmapResource)) == NULL) { DeleteBitmaps(); EH(BitmapArray); } } // unless memory allocation failed else { iNumBitmaps = 0; } } // Constructor for loading multiple bitmaps. CBmp::CBmp(HINSTANCE hInstance, INT_PTR * piBitmapsToLoadArray, int iNumBitmapsToLoad) { hInst = hInstance; iNumBitmaps = 0; BitmapArray = NULL; // The person may not know what bitmaps to load yet -- if not he'll have to call // CBmp::LoadBitmaps() below and pass in 0 for iNumBitmapsToLoad. if (iNumBitmapsToLoad > 0) { LoadBitmaps(piBitmapsToLoadArray, iNumBitmapsToLoad); } } void CBmp::DeleteBitmaps() { if (BitmapArray != NULL) { for (int ii = 0; ii < iNumBitmaps; ii++) { DeleteObject(BitmapArray[ii]); } delete [] BitmapArray; BitmapArray = NULL; } iNumBitmaps = 0; } CBmp::~CBmp() { DeleteBitmaps(); } // If the user did't know what bitmaps he wanted when calling the class // he can call the multiple bitmap constructor and feed it a value of 0 bitmaps to load. // Then he must call this function before continuing. void CBmp::LoadBitmaps(INT_PTR * piBitmapsToLoadArray, int iNumBitmapsToLoad) { // If bitmaps are already loaded, then deallocate them and load again. DeleteBitmaps(); // load new stuff if (iNumBitmapsToLoad > 0) { BitmapArray = new HBITMAP [iNumBitmapsToLoad]; // load 'em if (BitmapArray != NULL) { iNumBitmaps = iNumBitmapsToLoad; // Load each bitmap the user requested in his array: piBitmapsToLoadArray. for (int ii = 0; ii < iNumBitmapsToLoad; ii++) { BitmapArray[ii] = LoadBitmap((HINSTANCE) hInst, (LPCTSTR) piBitmapsToLoadArray[ii]); // abort on failure if (BitmapArray[ii] == NULL) { DeleteBitmaps(); EH(BitmapArray); break; } } } // unless memory allocation failed else { iNumBitmaps = 0; } } } // Shell for the multiple version of ChangeColor -- allows user to use this class // for single bitmaps without the complexity of dealing with the bitmap number. BOOL CBmp::ChangeColor(int iOldColor, int iNewColor) { return ChangeColor(0, iOldColor, iNewColor); } // Changes the a color in the bitmap. // All iOldColor colored pixels are replaced with iNewColor. BOOL CBmp::ChangeColor(int iBitmap, int iOldColor, int iNewColor) { if (BitmapArray != NULL) { require(iBitmap < iNumBitmaps); BITMAP bmData; HBITMAP hBitmap = BitmapArray[iBitmap]; GetObject(hBitmap, sizeof(BITMAP), &bmData); // Must be one byte per pixel. // This function is only implemented for 256 color bitmaps. if ((bmData.bmPlanes != 1) && (bmData.bmBitsPixel != 8)) { return FALSE; } // Get the bitmap data. int iNumBitmapBytes = bmData.bmWidth * bmData.bmHeight; char * cBitData = new char [iNumBitmapBytes]; EF_ASSERT(cBitData); if (!GetBitmapBits(hBitmap, iNumBitmapBytes, cBitData)) { if (cBitData != NULL) { delete [] cBitData; } return FALSE; } // Swap colors. for (int ii = 0; ii < iNumBitmapBytes; ii++) { if (cBitData[ii] == (char) iOldColor) { cBitData[ii] = (char) iNewColor; } } // Replace the old bitmap with the one we just created. HBITMAP hNewBitmap = CreateBitmap(bmData.bmWidth, bmData.bmHeight, 1, 8, cBitData); if (hNewBitmap != NULL) { DeleteObject(BitmapArray[iBitmap]); BitmapArray[iBitmap] = hNewBitmap; } if (cBitData != NULL) { delete [] cBitData; } if (hNewBitmap != NULL) { return TRUE; } } return FALSE; } // Shell for multiple version of GetBmpSize. BOOL CBmp::GetBmpSize(int * piX, int * piY) { return GetBmpSize(0, piX, piY); } // Returns the size of the bitmap. BOOL CBmp::GetBmpSize(int iBitmap, int * piX, int * piY) { if (BitmapArray != NULL) { require(iBitmap < iNumBitmaps); BITMAP bmData; if (!GetObject(BitmapArray[iBitmap], sizeof(BITMAP), &bmData)) { return FALSE; } *piX = bmData.bmWidth; *piY = bmData.bmHeight; return TRUE; } return FALSE; } // Shell for multiple version of DrawBmpInHDC. BOOL CBmp::DrawBmpInHDC(HDC OutputDC, int iX, int iY) { return DrawBmpInHDC(OutputDC, 0, iX, iY); } // Draws the bitmap at location (iX, iY) in OutputDC. BOOL CBmp::DrawBmpInHDC(HDC OutputDC, int iBitmap, int iX, int iY) { if (BitmapArray != NULL) { require(iBitmap < iNumBitmaps); HBITMAP hBitmap = BitmapArray[iBitmap]; // BitBlt the bitmap into the OutputDC BITMAP bmData; if (!GetObject(hBitmap, sizeof(BITMAP), &bmData)) { return FALSE; } HDC CommonDC = CreateCompatibleDC(OutputDC); EF_ASSERT(CommonDC); HGDIOBJ hOld = SelectObject(CommonDC, hBitmap); BOOL ok = BitBlt(OutputDC, iX, iY, bmData.bmWidth, bmData.bmHeight, CommonDC, 0, 0, SRCCOPY); SelectObject(CommonDC, hOld); DeleteDC(CommonDC); if (ok) { return TRUE; } } return FALSE; } // Shell for multiple version of DrawBmpInHDCTruncate. BOOL CBmp::DrawBmpInHDCTruncate(HDC OutputDC, RECT * Rect) { return DrawBmpInHDCTruncate(OutputDC, 0, Rect); } // Draws the bitmap within RECT in OutputDC. BOOL CBmp::DrawBmpInHDCTruncate(HDC OutputDC, int iBitmap, RECT * Rect) { if (BitmapArray != NULL) { require(iBitmap < iNumBitmaps); HBITMAP hBitmap = BitmapArray[iBitmap]; // BitBlt the bitmap into the OutputDC BITMAP bmData; if (!GetObject(hBitmap, sizeof(BITMAP), &bmData)) { return FALSE; } int nWidth = (bmData.bmWidth > (Rect->right - Rect->left)) ? (Rect->right - Rect->left) : bmData.bmWidth; int nHeight = (bmData.bmHeight > (Rect->bottom - Rect->top)) ? (Rect->bottom - Rect->top) : bmData.bmHeight; HDC CommonDC = CreateCompatibleDC(OutputDC); EF_ASSERT(CommonDC); HGDIOBJ hOld = SelectObject(CommonDC, hBitmap); EH_ASSERT(hOld); BOOL ok = BitBlt(OutputDC, Rect->left, Rect->top, nWidth, nHeight, CommonDC, 0, 0, SRCCOPY); SelectObject(CommonDC, hOld); DeleteDC(CommonDC); if (ok) { return TRUE; } } return FALSE; }