windows-nt/Source/XPSP1/NT/multimedia/directx/gamectrl/default/gradient.cpp
2020-09-26 16:20:57 +08:00

204 lines
6.2 KiB
C++

//
// GradientProgressCtrl.cpp : implementation file
//
#include "afxcmn.h"
#include "Gradient.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGradientProgressCtrl
CGradientProgressCtrl::CGradientProgressCtrl()
{
// Defaults assigned by CProgressCtrl()
m_nLower = 0;
m_nUpper = 100;
m_nCurrentPosition = 0;
m_nStep = 10;
// Default is vertical, because the only clients are the Test page and
// the calibration wizard, and hitting the test page is Far more common.
m_nDirection = VERTICAL;
// Initial colors
// m_clrStart = COLORREF(RGB(255, 0,0));
// m_clrEnd = COLORREF(RGB(255,128,192));
m_clrStart = COLORREF(RGB(255,0,0));
m_clrEnd = COLORREF(RGB(0,0,255));
m_clrBkGround = GetSysColor(COLOR_WINDOW);
m_clrText = COLORREF(RGB(255,255,255));
// Initial show percent
m_bShowPercent = FALSE;
}
CGradientProgressCtrl::~CGradientProgressCtrl()
{
}
BEGIN_MESSAGE_MAP(CGradientProgressCtrl, CProgressCtrl)
//{{AFX_MSG_MAP(CGradientProgressCtrl)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGradientProgressCtrl message handlers
void CGradientProgressCtrl::OnPaint()
{
PAINTSTRUCT ps;
::BeginPaint(this->m_hWnd, &ps);
CDC *pDC=GetDC();
HDC hDC = pDC->m_hDC;
if ((m_nLower < 0) || (m_nUpper < 0))
m_nCurrentPosition -= m_nLower;
// Figure out what part should be visible so we can stop the gradient when needed
RECT rectClient;
::GetClientRect(this->m_hWnd, &rectClient);
float nTmp = ((float)m_nCurrentPosition/(float)abs(m_nLower - m_nUpper));
// Draw the gradient
DrawGradient(hDC, rectClient, (short)(nTmp * ((m_nDirection == VERTICAL) ? rectClient.bottom : rectClient.right)));
// Show percent indicator if needed
if (m_bShowPercent)
{
TCHAR tszBuff[5];
wsprintf(tszBuff, TEXT("%d%%"), (short)(100*nTmp));
::SetTextColor(hDC, m_clrText);
::SetBkMode(hDC, TRANSPARENT);
::DrawText(hDC, tszBuff, lstrlen(tszBuff), &rectClient, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
}
ReleaseDC(pDC);
::EndPaint(this->m_hWnd, &ps);
// Do not call CProgressCtrl::OnPaint() for painting messages
}
/*************************************************************************/
// Need to keep track of where the indicator thinks it is.
/*************************************************************************/
void CGradientProgressCtrl:: SetRange(long nLower, long nUpper)
{
m_nCurrentPosition = m_nLower = nLower;
m_nUpper = nUpper;
}
/*************************************************************************/
// Where most of the actual work is done. The general version would fill the entire rectangle with
// a gradient, but we want to truncate the drawing to reflect the actual progress control position.
/*************************************************************************/
void CGradientProgressCtrl::DrawGradient(const HDC hDC, const RECT &rectClient, const short &nMaxWidth)
{
// First find out the largest color distance between the start and end colors. This distance
// will determine how many steps we use to carve up the client region and the size of each
// gradient rect.
// Get the color differences
short r = (GetRValue(m_clrEnd) - GetRValue(m_clrStart));
short g = (GetGValue(m_clrEnd) - GetGValue(m_clrStart));
short b = (GetBValue(m_clrEnd) - GetBValue(m_clrStart));
// Make the number of steps equal to the greatest distance
short nSteps = max(abs(r), max(abs(g), abs(b)));
// Determine how large each band should be in order to cover the
// client with nSteps bands (one for every color intensity level)
float fStep = ((m_nDirection == VERTICAL) ? (float)rectClient.bottom : (float)rectClient.right) / (float)nSteps;
// Calculate the step size for each color
float rStep = r/(float)nSteps;
float gStep = g/(float)nSteps;
float bStep = b/(float)nSteps;
// Reset the colors to the starting position
r = GetRValue(m_clrStart);
g = GetGValue(m_clrStart);
b = GetBValue(m_clrStart);
RECT rectFill; // Rectangle for filling band
// Start filling bands
for (short iOnBand = 0; iOnBand < nSteps; iOnBand++)
{
if (m_nDirection == VERTICAL)
{
// This provides the "velvet" look...
::SetRect(&rectFill,
(int)(iOnBand * fStep), // Upper left X
0, // Upper left Y
(int)((iOnBand+1) * fStep), // Lower right X
rectClient.bottom+1); // Lower right Y
/* Use this if we want the gradient to go up/down
::SetRect(&rectFill,
0, // Upper left Y
(int)(iOnBand * fStep), // Upper left X
rectClient.bottom+1, // Lower right Y
(int)((iOnBand+1) * fStep)); // Lower right X
*/
}
else
{
// Use this if we want the gradient to go left/right
::SetRect(&rectFill,
(int)(iOnBand * fStep), // Upper left X
0, // Upper left Y
(int)((iOnBand+1) * fStep), // Lower right X
rectClient.bottom+1); // Lower right Y
}
// Home-brew'd FillSolidRect... Much more effecient!
::SetBkColor(hDC, RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand));
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rectFill, NULL, 0, NULL);
if (m_nDirection == VERTICAL)
{
// Grey Rect
::SetRect(&rectFill, 0, 0, rectClient.right, nMaxWidth);
::SetBkColor(hDC, m_clrBkGround);
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rectFill, NULL, 0, NULL);
}
else
{
// If we are past the maximum for the current position we need to get out of the loop.
// Before we leave, we repaint the remainder of the client area with the background color.
if (rectFill.right > nMaxWidth)
{
::SetRect(&rectFill, rectFill.right, 0, rectClient.right, rectClient.bottom);
::SetBkColor(hDC, m_clrBkGround);
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rectFill, NULL, 0, NULL);
return;
}
}
}
}
/*************************************************************************/
// All drawing is done in the OnPaint function
/*************************************************************************/
BOOL CGradientProgressCtrl::OnEraseBkgnd(CDC *pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;
}