windows-nt/Source/XPSP1/NT/base/fs/utils/dfrg/graphix.cpp
2020-09-26 16:20:57 +08:00

756 lines
19 KiB
C++

/*****************************************************************************************************************
FILENAME: Graphix.cpp
COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
*/
#include "stdafx.h"
#ifndef SNAPIN
#include <windows.h>
#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; i<iWidth && iStart < iEnd; i++, iStart++) {
// Move to the top-left corner to start.
MoveToEx(hdcOutput, iStart, prect->top, 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; i<iWidth && iStart < iEnd; i++, iStart++) {
// Move to the top-left corner to start.
MoveToEx(hdcOutput, iStart, prect->top, 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;
}