|
|
//
// 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; }
|