Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
6.2 KiB

  1. //
  2. // GradientProgressCtrl.cpp : implementation file
  3. //
  4. #include "afxcmn.h"
  5. #include "Gradient.h"
  6. #ifdef _DEBUG
  7. #define new DEBUG_NEW
  8. #undef THIS_FILE
  9. static char THIS_FILE[] = __FILE__;
  10. #endif
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CGradientProgressCtrl
  13. CGradientProgressCtrl::CGradientProgressCtrl()
  14. {
  15. // Defaults assigned by CProgressCtrl()
  16. m_nLower = 0;
  17. m_nUpper = 100;
  18. m_nCurrentPosition = 0;
  19. m_nStep = 10;
  20. // Default is vertical, because the only clients are the Test page and
  21. // the calibration wizard, and hitting the test page is Far more common.
  22. m_nDirection = VERTICAL;
  23. // Initial colors
  24. // m_clrStart = COLORREF(RGB(255, 0,0));
  25. // m_clrEnd = COLORREF(RGB(255,128,192));
  26. m_clrStart = COLORREF(RGB(255,0,0));
  27. m_clrEnd = COLORREF(RGB(0,0,255));
  28. m_clrBkGround = GetSysColor(COLOR_WINDOW);
  29. m_clrText = COLORREF(RGB(255,255,255));
  30. // Initial show percent
  31. m_bShowPercent = FALSE;
  32. }
  33. CGradientProgressCtrl::~CGradientProgressCtrl()
  34. {
  35. }
  36. BEGIN_MESSAGE_MAP(CGradientProgressCtrl, CProgressCtrl)
  37. //{{AFX_MSG_MAP(CGradientProgressCtrl)
  38. ON_WM_PAINT()
  39. ON_WM_ERASEBKGND()
  40. //}}AFX_MSG_MAP
  41. END_MESSAGE_MAP()
  42. /////////////////////////////////////////////////////////////////////////////
  43. // CGradientProgressCtrl message handlers
  44. void CGradientProgressCtrl::OnPaint()
  45. {
  46. PAINTSTRUCT ps;
  47. ::BeginPaint(this->m_hWnd, &ps);
  48. CDC *pDC=GetDC();
  49. HDC hDC = pDC->m_hDC;
  50. if ((m_nLower < 0) || (m_nUpper < 0))
  51. m_nCurrentPosition -= m_nLower;
  52. // Figure out what part should be visible so we can stop the gradient when needed
  53. RECT rectClient;
  54. ::GetClientRect(this->m_hWnd, &rectClient);
  55. float nTmp = ((float)m_nCurrentPosition/(float)abs(m_nLower - m_nUpper));
  56. // Draw the gradient
  57. DrawGradient(hDC, rectClient, (short)(nTmp * ((m_nDirection == VERTICAL) ? rectClient.bottom : rectClient.right)));
  58. // Show percent indicator if needed
  59. if (m_bShowPercent)
  60. {
  61. TCHAR tszBuff[5];
  62. wsprintf(tszBuff, TEXT("%d%%"), (short)(100*nTmp));
  63. ::SetTextColor(hDC, m_clrText);
  64. ::SetBkMode(hDC, TRANSPARENT);
  65. ::DrawText(hDC, tszBuff, lstrlen(tszBuff), &rectClient, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
  66. }
  67. ReleaseDC(pDC);
  68. ::EndPaint(this->m_hWnd, &ps);
  69. // Do not call CProgressCtrl::OnPaint() for painting messages
  70. }
  71. /*************************************************************************/
  72. // Need to keep track of where the indicator thinks it is.
  73. /*************************************************************************/
  74. void CGradientProgressCtrl:: SetRange(long nLower, long nUpper)
  75. {
  76. m_nCurrentPosition = m_nLower = nLower;
  77. m_nUpper = nUpper;
  78. }
  79. /*************************************************************************/
  80. // Where most of the actual work is done. The general version would fill the entire rectangle with
  81. // a gradient, but we want to truncate the drawing to reflect the actual progress control position.
  82. /*************************************************************************/
  83. void CGradientProgressCtrl::DrawGradient(const HDC hDC, const RECT &rectClient, const short &nMaxWidth)
  84. {
  85. // First find out the largest color distance between the start and end colors. This distance
  86. // will determine how many steps we use to carve up the client region and the size of each
  87. // gradient rect.
  88. // Get the color differences
  89. short r = (GetRValue(m_clrEnd) - GetRValue(m_clrStart));
  90. short g = (GetGValue(m_clrEnd) - GetGValue(m_clrStart));
  91. short b = (GetBValue(m_clrEnd) - GetBValue(m_clrStart));
  92. // Make the number of steps equal to the greatest distance
  93. short nSteps = max(abs(r), max(abs(g), abs(b)));
  94. // Determine how large each band should be in order to cover the
  95. // client with nSteps bands (one for every color intensity level)
  96. float fStep = ((m_nDirection == VERTICAL) ? (float)rectClient.bottom : (float)rectClient.right) / (float)nSteps;
  97. // Calculate the step size for each color
  98. float rStep = r/(float)nSteps;
  99. float gStep = g/(float)nSteps;
  100. float bStep = b/(float)nSteps;
  101. // Reset the colors to the starting position
  102. r = GetRValue(m_clrStart);
  103. g = GetGValue(m_clrStart);
  104. b = GetBValue(m_clrStart);
  105. RECT rectFill; // Rectangle for filling band
  106. // Start filling bands
  107. for (short iOnBand = 0; iOnBand < nSteps; iOnBand++)
  108. {
  109. if (m_nDirection == VERTICAL)
  110. {
  111. // This provides the "velvet" look...
  112. ::SetRect(&rectFill,
  113. (int)(iOnBand * fStep), // Upper left X
  114. 0, // Upper left Y
  115. (int)((iOnBand+1) * fStep), // Lower right X
  116. rectClient.bottom+1); // Lower right Y
  117. /* Use this if we want the gradient to go up/down
  118. ::SetRect(&rectFill,
  119. 0, // Upper left Y
  120. (int)(iOnBand * fStep), // Upper left X
  121. rectClient.bottom+1, // Lower right Y
  122. (int)((iOnBand+1) * fStep)); // Lower right X
  123. */
  124. }
  125. else
  126. {
  127. // Use this if we want the gradient to go left/right
  128. ::SetRect(&rectFill,
  129. (int)(iOnBand * fStep), // Upper left X
  130. 0, // Upper left Y
  131. (int)((iOnBand+1) * fStep), // Lower right X
  132. rectClient.bottom+1); // Lower right Y
  133. }
  134. // Home-brew'd FillSolidRect... Much more effecient!
  135. ::SetBkColor(hDC, RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand));
  136. ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rectFill, NULL, 0, NULL);
  137. if (m_nDirection == VERTICAL)
  138. {
  139. // Grey Rect
  140. ::SetRect(&rectFill, 0, 0, rectClient.right, nMaxWidth);
  141. ::SetBkColor(hDC, m_clrBkGround);
  142. ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rectFill, NULL, 0, NULL);
  143. }
  144. else
  145. {
  146. // If we are past the maximum for the current position we need to get out of the loop.
  147. // Before we leave, we repaint the remainder of the client area with the background color.
  148. if (rectFill.right > nMaxWidth)
  149. {
  150. ::SetRect(&rectFill, rectFill.right, 0, rectClient.right, rectClient.bottom);
  151. ::SetBkColor(hDC, m_clrBkGround);
  152. ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rectFill, NULL, 0, NULL);
  153. return;
  154. }
  155. }
  156. }
  157. }
  158. /*************************************************************************/
  159. // All drawing is done in the OnPaint function
  160. /*************************************************************************/
  161. BOOL CGradientProgressCtrl::OnEraseBkgnd(CDC *pDC)
  162. {
  163. // TODO: Add your message handler code here and/or call default
  164. return TRUE;
  165. }