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