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.

262 lines
8.2 KiB

  1. /**************************************************************************
  2. *
  3. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. * PURPOSE.
  7. *
  8. * Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved.
  9. *
  10. **************************************************************************/
  11. /****************************************************************************
  12. *
  13. * rlmeter.c: Audio recording level window
  14. *
  15. * Vidcap32 Source code
  16. *
  17. ***************************************************************************/
  18. /*
  19. * This window class acts as a 'VU Meter' showing the current and peak
  20. * volume. Set the volume via the WMRL_SETLEVEL message (lParam is new level).
  21. * The peak level will be tracked by the control by means of a 2-second timer.
  22. */
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. #include "rlmeter.h"
  26. #ifdef _WIN32
  27. #ifndef EXPORT
  28. #define EXPORT
  29. #endif
  30. #endif
  31. LRESULT FAR PASCAL EXPORT
  32. RLMeterProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  33. /*
  34. * generic window class to support a volume level display.
  35. *
  36. * The window has a white background, and draws a black filled
  37. * rectangle to show the current volume level, and a red line at the
  38. * peak. Every two seconds on a timer we lower the peak (we set the
  39. * saved peak value to 0 so that at the next update we move the line to
  40. * whatever is the current level.
  41. *
  42. * We store the pen and brush handles and the current and maximum levels
  43. * as window words using SetWindowWord on win16 and SetWindowLong on win32.
  44. */
  45. // window data layout
  46. #define WD_MAX 0 // current max
  47. #define WD_PREVMAX (WD_MAX + sizeof(UINT)) // currently drawn max
  48. #define WD_PREVLVL (WD_PREVMAX + sizeof(UINT)) // currently drawn level
  49. #define WD_PEN (WD_PREVLVL + sizeof(UINT)) // pen for max line
  50. #define WDBYTES (WD_PEN + sizeof(UINT_PTR)) // window bytes to alloc
  51. #ifdef _WIN32
  52. #define SetWindowUINT SetWindowLong
  53. #define GetWindowUINT GetWindowLong
  54. #define SetWindowUINTPtr SetWindowLongPtr
  55. #define GetWindowUINTPtr GetWindowLongPtr
  56. #else
  57. #define SetWindowUINT SetWindowWord
  58. #define GetWindowUINT GetWindowWord
  59. #define SetWindowUINTPtr SetWindowWord
  60. #define GetWindowUINTPtr GetWindowWord
  61. #endif
  62. // call (if first instance) to register class
  63. BOOL
  64. RLMeter_Register(HINSTANCE hInstance)
  65. {
  66. WNDCLASS cls;
  67. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  68. cls.hIcon = NULL;
  69. cls.lpszMenuName = NULL;
  70. cls.lpszClassName = RLMETERCLASS;
  71. cls.hbrBackground = GetStockObject(WHITE_BRUSH);
  72. cls.hInstance = hInstance;
  73. cls.style = CS_HREDRAW | CS_VREDRAW;
  74. cls.lpfnWndProc = RLMeterProc;
  75. cls.cbClsExtra = 0;
  76. cls.cbWndExtra = WDBYTES;
  77. return RegisterClass(&cls);
  78. }
  79. LRESULT FAR PASCAL EXPORT
  80. RLMeterProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  81. {
  82. switch(message) {
  83. case WM_CREATE:
  84. // init current level and max to 0
  85. SetWindowUINT(hwnd, WD_MAX, 0);
  86. SetWindowUINT(hwnd, WD_PREVMAX, 0);
  87. SetWindowUINT(hwnd, WD_PREVLVL, 0);
  88. // create a red pen for the max line and store this
  89. SetWindowUINTPtr(hwnd, WD_PEN,
  90. (UINT_PTR) CreatePen(PS_SOLID, 2, RGB(255, 0, 0)));
  91. break;
  92. case WM_DESTROY:
  93. // destroy the pen we created
  94. {
  95. HPEN hpen = (HPEN) GetWindowUINTPtr(hwnd, WD_PEN);
  96. if (hpen) {
  97. DeleteObject(hpen);
  98. SetWindowUINTPtr(hwnd, WD_PEN, 0);
  99. }
  100. // also kill the timer we created
  101. KillTimer(hwnd, 0);
  102. }
  103. break;
  104. case WM_PAINT:
  105. /*
  106. * paint the entire control
  107. *
  108. * nb we must paint exactly as it is currently drawn because we
  109. * may be clipped to only part of the control. Thus we must draw
  110. * the max at WD_PREVMAX as it is currently drawn, since WD_MAX
  111. * may have been set to 0 and not yet drawn - in this case, with
  112. * some unfortunate timing and clipping, we would have two max lines.
  113. */
  114. {
  115. PAINTSTRUCT ps;
  116. HDC hdc;
  117. RECT rc, rcFill;
  118. HPEN hpenOld, hpen;
  119. hdc = BeginPaint(hwnd, &ps);
  120. GetClientRect(hwnd, &rc);
  121. // treat the level as a percentage and fill that much of the
  122. // control with black (from left)
  123. rcFill = rc;
  124. rcFill.right = (rc.right * GetWindowUINT(hwnd, WD_PREVLVL)) / 100;
  125. SetBkColor(hdc, RGB(0,0,0));
  126. // easy way to fill without creating a brush
  127. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
  128. // draw the max line
  129. rcFill.right = (rc.right * GetWindowUINT(hwnd, WD_PREVLVL)) / 100;
  130. hpen = (HPEN) GetWindowUINTPtr(hwnd, WD_PEN);
  131. hpenOld = SelectObject(hdc, hpen);
  132. MoveToEx(hdc, rcFill.right, rcFill.top, NULL);
  133. LineTo(hdc, rcFill.right, rcFill.bottom);
  134. SelectObject(hdc, hpenOld);
  135. EndPaint(hwnd, &ps);
  136. }
  137. break;
  138. case WMRL_SETLEVEL:
  139. // set new level, and update the displayed level block and max line
  140. {
  141. RECT rc, rcFill;
  142. UINT uMax, uPrevMax, uPrevLevel, uLevel;
  143. HDC hdc;
  144. // new level is lParam
  145. uLevel = (UINT) lParam;
  146. // fetch other parameters
  147. uMax = GetWindowUINT(hwnd, WD_MAX);
  148. uPrevMax = GetWindowUINT(hwnd, WD_PREVMAX);
  149. uPrevLevel = GetWindowUINT(hwnd, WD_PREVLVL);
  150. // decay the max level. This rate works best if we are called
  151. // to update every 1/20th sec - in this case the decay will be
  152. // 64% in a second.
  153. if (uMax > 0) {
  154. uMax = (uMax * 2007) / 2048; // = 0.98 * uMax
  155. }
  156. hdc = GetDC(hwnd);
  157. GetClientRect(hwnd, &rc);
  158. rcFill = rc;
  159. // is the current level a new peak ?
  160. if (uLevel > uMax) {
  161. uMax = uLevel;
  162. }
  163. SetWindowUINT(hwnd, WD_MAX, uMax);
  164. // if the max has moved, erase the old line
  165. if (uMax != uPrevMax) {
  166. // white out the line by filling a 2-pixel wide rect
  167. rcFill.right = ((rc.right * uPrevMax) / 100) + 1;
  168. rcFill.left = rcFill.right - 2;
  169. SetBkColor(hdc, RGB(255, 255, 255));
  170. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
  171. }
  172. // calculate the area to update
  173. rcFill.right = (rc.right * uPrevLevel) / 100;
  174. rcFill.left = (rc.right * uLevel) / 100;
  175. // are we erasing (lowering level) or drawing more black?
  176. if (rcFill.right > rcFill.left) {
  177. // level has dropped - so fill with white down to new level
  178. SetBkColor(hdc, RGB(255, 255, 255));
  179. } else {
  180. // level has gone up so fill with black up to new level
  181. int t;
  182. t = rcFill.right;
  183. rcFill.right = rcFill.left;
  184. rcFill.left = t;
  185. SetBkColor(hdc, RGB(0, 0, 0));
  186. // fill a little extra to ensure no rounding gaps
  187. if (rcFill.left > 0) {
  188. rcFill.left -= 1;
  189. }
  190. }
  191. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
  192. SetWindowUINT(hwnd, WD_PREVLVL, uLevel);
  193. // draw the new max line if needed
  194. if (uMax != uPrevMax) {
  195. HPEN hpen, hpenOld;
  196. rcFill.right = (rc.right * uMax) /100;
  197. hpen = (HPEN) GetWindowUINTPtr(hwnd, WD_PEN);
  198. hpenOld = SelectObject(hdc, hpen);
  199. MoveToEx(hdc, rcFill.right, rcFill.top, NULL);
  200. LineTo(hdc, rcFill.right, rcFill.bottom);
  201. SelectObject(hdc, hpenOld);
  202. SetWindowUINT(hwnd, WD_PREVMAX, uMax);
  203. }
  204. ReleaseDC(hwnd, hdc);
  205. return(0);
  206. }
  207. }
  208. return DefWindowProc(hwnd, message, wParam, lParam);
  209. }