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.

1193 lines
26 KiB

  1. #include "precomp.h"
  2. #include "resource.h"
  3. #include "AudioLvl.h"
  4. static const int g_nAudIconWidth = 16;
  5. static const int g_nAudIconHeight = 16;
  6. static const int g_nAudChkbWidth = 13;
  7. static const int g_nAudChkbHeight = 13;
  8. static const int g_nAudChkbXMargin = 13;
  9. static const int g_nAudChkbYMargin = 12;
  10. static const int g_nAudIconXMargin = g_nAudChkbXMargin + g_nAudChkbWidth + 3;
  11. static const int g_nAudIconYMargin = 10;
  12. static const int g_nAudMeterXMargin = g_nAudIconXMargin + g_nAudIconWidth + 5;
  13. static const int g_nAudMeterHeight = 7;
  14. static const int g_nAudMeterYMargin = g_nAudIconYMargin + (g_nAudMeterHeight/2);
  15. static const int g_nAudMeterRightMargin = 5; // 5 pixels from end
  16. static const int g_nAudTrkRangeMin = 0;
  17. static const int g_nAudTrkRangeMax = 99;
  18. static const int g_nAudTrkRangeSeg = 0xFFFF / g_nAudTrkRangeMax;
  19. static const int g_nAudTrkTickFreq = 20;
  20. static const int g_nAudTrkRightGap = 3;
  21. static const int g_nAudTrkXMargin = g_nAudIconXMargin + g_nAudIconWidth + 5;
  22. static const int g_nAudTrkYMargin = 2;
  23. static const int g_nAudTrkHeight = 25;
  24. static const int g_nAudTrkMinWidth = 50;
  25. static const int RECTANGLE_WIDTH = 10;
  26. static const int RECTANGLE_LEADING = 1;
  27. static inline WORD ScaleMixer(DWORD dwVol)
  28. {
  29. // NOTE: the "+ g_nAudTrkRangeSeg - 1" provides for a correction that
  30. // takes place while truncating the position when we are setting the
  31. // volume. See bug 1634
  32. return (((LOWORD(dwVol) + g_nAudTrkRangeSeg - 1) *
  33. g_nAudTrkRangeMax) / 0xFFFF);
  34. }
  35. CAudioLevel::CAudioLevel(CAudioControl *pAudioControl) :
  36. m_hwndParent(NULL),
  37. m_hwndMicTrack(NULL),
  38. m_hwndMicTrackTT(NULL),
  39. m_hwndSpkTrack(NULL),
  40. m_hwndSpkTrackTT(NULL),
  41. m_hIconMic(NULL),
  42. m_hIconSpkr(NULL),
  43. m_hwndChkbRecMute(NULL),
  44. m_hwndChkbSpkMute(NULL),
  45. m_hwndChkbRecMuteTT(NULL),
  46. m_hwndChkbSpkMuteTT(NULL),
  47. m_fVisible(FALSE),
  48. m_fMicTrkVisible(TRUE),
  49. m_fSpkTrkVisible(TRUE),
  50. m_dwMicTrackPos(0xFFFFFFFF),
  51. m_dwSpkTrackPos(0xFFFFFFFF),
  52. m_dwMicLvl(0),
  53. m_dwSpkLvl(0),
  54. m_hGreyBrush(NULL), m_hBlackBrush(NULL), m_hRedBrush(NULL),
  55. m_hGreenBrush(NULL), m_hYellowBrush(NULL), m_hHiLitePen(NULL),
  56. m_hShadowPen(NULL), m_hDkShadowPen(NULL), m_hLitePen(NULL)
  57. {
  58. ClearStruct(&m_rect);
  59. m_pAudioControl = pAudioControl;
  60. // load icons
  61. m_hIconSpkr = (HICON) ::LoadImage( ::GetInstanceHandle(),
  62. MAKEINTRESOURCE(IDI_SPKEMPTY),
  63. IMAGE_ICON,
  64. g_nAudIconWidth,
  65. g_nAudIconHeight,
  66. LR_DEFAULTCOLOR | LR_SHARED);
  67. m_hIconMic = (HICON) ::LoadImage( ::GetInstanceHandle(),
  68. MAKEINTRESOURCE(IDI_MICEMPTY),
  69. IMAGE_ICON,
  70. g_nAudIconWidth,
  71. g_nAudIconHeight,
  72. LR_DEFAULTCOLOR | LR_SHARED);
  73. // create the brushes used for painting the signal level
  74. CreateBrushes();
  75. }
  76. CAudioLevel::~CAudioLevel()
  77. {
  78. if (m_hGreyBrush)
  79. DeleteObject(m_hGreyBrush);
  80. if (m_hRedBrush)
  81. DeleteObject(m_hRedBrush);
  82. if (m_hYellowBrush)
  83. DeleteObject(m_hYellowBrush);
  84. if (m_hGreenBrush)
  85. DeleteObject(m_hGreenBrush);
  86. if (m_hBlackBrush)
  87. DeleteObject(m_hBlackBrush);
  88. if (m_hHiLitePen)
  89. DeleteObject(m_hHiLitePen);
  90. if (m_hDkShadowPen)
  91. DeleteObject(m_hDkShadowPen);
  92. if (m_hShadowPen)
  93. DeleteObject(m_hShadowPen);
  94. if (m_hLitePen)
  95. DeleteObject(m_hLitePen);
  96. }
  97. CAudioLevel::Create(HWND hwndParent)
  98. {
  99. BOOL fCanSetRecVolume, fCanSetSpkVolume;
  100. BOOL fCheck;
  101. m_hwndParent = hwndParent;
  102. m_hwndParentParent = GetParent(hwndParent);
  103. fCanSetRecVolume = m_pAudioControl->CanSetRecorderVolume();
  104. fCanSetSpkVolume = m_pAudioControl->CanSetSpeakerVolume();
  105. // create the mute check box for microphone
  106. m_hwndChkbRecMute = ::CreateWindow( _TEXT("BUTTON"),
  107. g_szEmpty,
  108. WS_CHILD | WS_CLIPSIBLINGS |
  109. BS_AUTOCHECKBOX,
  110. 0, 0, 0, 0,
  111. m_hwndParent,
  112. (HMENU) IDM_MUTE_MICROPHONE,
  113. GetInstanceHandle(),
  114. NULL);
  115. if (m_hwndChkbRecMute != NULL)
  116. {
  117. // mute is initially off
  118. fCheck = !(m_pAudioControl->IsRecMuted());
  119. ::SendMessage(m_hwndChkbRecMute, BM_SETCHECK, fCheck, 0);
  120. // create the tool tip
  121. m_hwndChkbRecMuteTT = CreateWindowEx(0,
  122. TOOLTIPS_CLASS,
  123. (LPSTR) NULL,
  124. 0, // styles
  125. CW_USEDEFAULT,
  126. CW_USEDEFAULT,
  127. CW_USEDEFAULT,
  128. CW_USEDEFAULT,
  129. m_hwndParent,
  130. (HMENU) NULL,
  131. ::GetInstanceHandle(),
  132. NULL);
  133. if (NULL != m_hwndChkbRecMuteTT)
  134. {
  135. TOOLINFO ti;
  136. ti.cbSize = sizeof(TOOLINFO);
  137. ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
  138. ti.hwnd = m_hwndParent;
  139. ti.hinst = ::GetInstanceHandle();
  140. ti.uId = (UINT) m_hwndChkbRecMute;
  141. ti.lpszText = (LPTSTR) IDS_AUDIO_REC_MUTE_TT;
  142. ::SendMessage( m_hwndChkbRecMuteTT, TTM_ADDTOOL, 0,
  143. (LPARAM) (LPTOOLINFO) &ti);
  144. }
  145. }
  146. // create the mute check box for speaker
  147. m_hwndChkbSpkMute = ::CreateWindow( _TEXT("BUTTON"),
  148. g_szEmpty,
  149. WS_CHILD | WS_CLIPSIBLINGS
  150. | BS_AUTOCHECKBOX,
  151. 0, 0, 0, 0,
  152. m_hwndParent,
  153. (HMENU) IDM_MUTE_SPEAKER,
  154. GetInstanceHandle(),
  155. NULL);
  156. if (NULL != m_hwndChkbSpkMute)
  157. {
  158. // set appropriate mute status in microphone's mute check box
  159. fCheck = !(m_pAudioControl->IsSpkMuted());
  160. // Mute is off - so check it
  161. ::SendMessage(m_hwndChkbSpkMute, BM_SETCHECK, fCheck, 0);
  162. // create the tool tip
  163. m_hwndChkbSpkMuteTT = CreateWindowEx(0,
  164. TOOLTIPS_CLASS,
  165. (LPSTR) NULL,
  166. 0, // styles
  167. CW_USEDEFAULT,
  168. CW_USEDEFAULT,
  169. CW_USEDEFAULT,
  170. CW_USEDEFAULT,
  171. m_hwndParent,
  172. (HMENU) NULL,
  173. ::GetInstanceHandle(),
  174. NULL);
  175. if (NULL != m_hwndChkbSpkMuteTT)
  176. {
  177. TOOLINFO ti;
  178. ti.cbSize = sizeof(TOOLINFO);
  179. ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
  180. ti.hwnd = m_hwndParent;
  181. ti.hinst = ::GetInstanceHandle();
  182. ti.uId = (UINT) m_hwndChkbSpkMute;
  183. ti.lpszText = (LPTSTR) IDS_AUDIO_SPK_MUTE_TT;
  184. ::SendMessage( m_hwndChkbSpkMuteTT, TTM_ADDTOOL, 0,
  185. (LPARAM) (LPTOOLINFO) &ti);
  186. }
  187. }
  188. // create the mic level trackbar:
  189. m_hwndMicTrack = ::CreateWindowEx( 0L,
  190. TRACKBAR_CLASS,
  191. g_szEmpty,
  192. WS_CHILD | WS_CLIPSIBLINGS
  193. | TBS_HORZ | TBS_NOTICKS | TBS_BOTH
  194. | (fCanSetRecVolume ? 0 : WS_DISABLED),
  195. 0, 0, 0, 0,
  196. m_hwndParent,
  197. (HMENU) ID_AUDIODLG_MIC_TRACK,
  198. ::GetInstanceHandle(),
  199. NULL);
  200. if (NULL != m_hwndMicTrack)
  201. {
  202. ::SendMessage( m_hwndMicTrack,
  203. TBM_SETRANGE,
  204. FALSE,
  205. MAKELONG(g_nAudTrkRangeMin, g_nAudTrkRangeMax));
  206. ::SendMessage( m_hwndMicTrack,
  207. TBM_SETTICFREQ,
  208. g_nAudTrkTickFreq,
  209. g_nAudTrkRangeMin);
  210. WORD wPos = (g_nAudTrkRangeMax - g_nAudTrkRangeMin) / 2;
  211. if (fCanSetRecVolume)
  212. {
  213. wPos = ScaleMixer(m_pAudioControl->GetRecorderVolume());
  214. }
  215. ::SendMessage( m_hwndMicTrack,
  216. TBM_SETPOS,
  217. TRUE,
  218. wPos);
  219. m_hwndMicTrackTT = CreateWindowEx( 0,
  220. TOOLTIPS_CLASS,
  221. (LPSTR) NULL,
  222. 0, // styles
  223. CW_USEDEFAULT,
  224. CW_USEDEFAULT,
  225. CW_USEDEFAULT,
  226. CW_USEDEFAULT,
  227. m_hwndParent,
  228. (HMENU) NULL,
  229. ::GetInstanceHandle(),
  230. NULL);
  231. if (NULL != m_hwndMicTrackTT)
  232. {
  233. TOOLINFO ti;
  234. ti.cbSize = sizeof(TOOLINFO);
  235. ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
  236. ti.hwnd = m_hwndParent;
  237. ti.hinst = ::GetInstanceHandle();
  238. ti.uId = (UINT) m_hwndMicTrack;
  239. ti.lpszText = (LPTSTR) IDS_AUDIO_MIC_TRACK_TT;
  240. ::SendMessage(m_hwndMicTrackTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
  241. }
  242. }
  243. // create the speaker level trackbar:
  244. m_hwndSpkTrack = ::CreateWindowEx( 0L,
  245. TRACKBAR_CLASS,
  246. g_szEmpty,
  247. WS_CHILD | WS_CLIPSIBLINGS
  248. | TBS_HORZ | TBS_NOTICKS | TBS_BOTH
  249. | (fCanSetSpkVolume ? 0 : WS_DISABLED),
  250. 0, 0, 0, 0,
  251. m_hwndParent,
  252. (HMENU) ID_AUDIODLG_SPKR_TRACK,
  253. ::GetInstanceHandle(),
  254. NULL);
  255. if (NULL != m_hwndSpkTrack)
  256. {
  257. ::SendMessage( m_hwndSpkTrack,
  258. TBM_SETRANGE,
  259. FALSE,
  260. MAKELONG(g_nAudTrkRangeMin, g_nAudTrkRangeMax));
  261. ::SendMessage( m_hwndSpkTrack,
  262. TBM_SETTICFREQ,
  263. g_nAudTrkTickFreq,
  264. g_nAudTrkRangeMin);
  265. WORD wPos = (g_nAudTrkRangeMax - g_nAudTrkRangeMin) / 2;
  266. if (fCanSetSpkVolume)
  267. {
  268. wPos = ScaleMixer(m_pAudioControl->GetSpeakerVolume());
  269. }
  270. ::SendMessage( m_hwndSpkTrack,
  271. TBM_SETPOS,
  272. TRUE,
  273. wPos);
  274. m_hwndSpkTrackTT = CreateWindowEx( 0,
  275. TOOLTIPS_CLASS,
  276. (LPSTR) NULL,
  277. 0, // styles
  278. CW_USEDEFAULT,
  279. CW_USEDEFAULT,
  280. CW_USEDEFAULT,
  281. CW_USEDEFAULT,
  282. m_hwndParent,
  283. (HMENU) NULL,
  284. ::GetInstanceHandle(),
  285. NULL);
  286. if (NULL != m_hwndSpkTrackTT)
  287. {
  288. TOOLINFO ti;
  289. ti.cbSize = sizeof(TOOLINFO);
  290. ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
  291. ti.hwnd = m_hwndParent;
  292. ti.hinst = ::GetInstanceHandle();
  293. ti.uId = (UINT) m_hwndSpkTrack;
  294. ti.lpszText = (LPTSTR) IDS_AUDIO_SPK_TRACK_TT;
  295. ::SendMessage(m_hwndSpkTrackTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
  296. }
  297. }
  298. return TRUE;
  299. }
  300. BOOL CAudioLevel::ForwardSysChangeMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  301. {
  302. CreateBrushes();
  303. if (NULL != m_hwndMicTrack)
  304. {
  305. ::SendMessage(m_hwndMicTrack, uMsg, wParam, lParam);
  306. }
  307. if (NULL != m_hwndSpkTrack)
  308. {
  309. ::SendMessage(m_hwndSpkTrack, uMsg, wParam, lParam);
  310. }
  311. return TRUE;
  312. }
  313. BOOL CAudioLevel::CreateBrushes()
  314. {
  315. // the background color may change on us!
  316. COLORREF GreyColor = GetSysColor(COLOR_3DFACE);
  317. COLORREF BlackColor = GetSysColor(COLOR_BTNTEXT);
  318. const COLORREF RedColor = RGB(255,0,0);
  319. const COLORREF YellowColor = RGB(255,255,0);
  320. const COLORREF GreenColor = RGB(0,255,0);
  321. COLORREF ShadowColor = GetSysColor(COLOR_3DSHADOW);
  322. COLORREF HiLiteColor = GetSysColor(COLOR_3DHIGHLIGHT);
  323. COLORREF LiteColor = GetSysColor(COLOR_3DLIGHT);
  324. COLORREF DkShadowColor = GetSysColor(COLOR_3DDKSHADOW);
  325. if (m_hGreyBrush)
  326. {
  327. DeleteObject(m_hGreyBrush);
  328. }
  329. m_hGreyBrush = CreateSolidBrush(GreyColor);
  330. if (m_hBlackBrush)
  331. {
  332. DeleteObject(m_hBlackBrush);
  333. }
  334. m_hBlackBrush = CreateSolidBrush(BlackColor);
  335. if (m_hHiLitePen)
  336. {
  337. DeleteObject(m_hHiLitePen);
  338. }
  339. m_hHiLitePen = CreatePen(PS_SOLID, 0, HiLiteColor);
  340. if (m_hLitePen)
  341. {
  342. DeleteObject(m_hLitePen);
  343. }
  344. m_hLitePen = CreatePen(PS_SOLID, 0, LiteColor);
  345. if (m_hDkShadowPen)
  346. {
  347. DeleteObject(m_hDkShadowPen);
  348. }
  349. m_hDkShadowPen = CreatePen(PS_SOLID, 0, DkShadowColor);
  350. if (m_hShadowPen)
  351. {
  352. DeleteObject(m_hShadowPen);
  353. }
  354. m_hShadowPen = CreatePen(PS_SOLID, 0, ShadowColor);
  355. // red, yellow, green will never change
  356. if (!m_hRedBrush)
  357. m_hRedBrush = CreateSolidBrush (RedColor);
  358. if (!m_hGreenBrush)
  359. m_hGreenBrush = CreateSolidBrush(GreenColor);
  360. if (!m_hYellowBrush)
  361. m_hYellowBrush = CreateSolidBrush(YellowColor);
  362. return TRUE;
  363. }
  364. BOOL CAudioLevel::OnCommand(WPARAM wParam, LPARAM lParam)
  365. {
  366. LRESULT lCheck;
  367. BOOL fSpeaker;
  368. switch (LOWORD(wParam))
  369. {
  370. default:
  371. return FALSE;
  372. case IDM_MUTE_MICROPHONE_ACCEL:
  373. lCheck = BST_CHECKED;
  374. fSpeaker = FALSE;
  375. break;
  376. case IDM_MUTE_MICROPHONE:
  377. lCheck = BST_UNCHECKED;
  378. fSpeaker = FALSE;
  379. break;
  380. case IDM_MUTE_SPEAKER_ACCEL:
  381. lCheck = BST_CHECKED;
  382. fSpeaker = TRUE;
  383. break;
  384. case IDM_MUTE_SPEAKER:
  385. lCheck = BST_UNCHECKED;
  386. fSpeaker = TRUE;
  387. break;
  388. }
  389. BOOL fMute = (lCheck == ::SendMessage(
  390. fSpeaker ? m_hwndChkbSpkMute : m_hwndChkbRecMute,
  391. BM_GETCHECK, 0, 0));
  392. m_pAudioControl->MuteAudio(fSpeaker, fMute);
  393. return TRUE;
  394. }
  395. BOOL CAudioLevel::ShiftFocus(HWND hwndCur, BOOL fForward)
  396. {
  397. BOOL bRet = FALSE;
  398. HWND aHwnds[] = {m_hwndChkbSpkMute,m_hwndSpkTrack,m_hwndChkbRecMute,m_hwndMicTrack};
  399. int nSizeArray = ARRAY_ELEMENTS(aHwnds);
  400. int nIndex, nSelect;
  401. HWND hwndNewFocus=NULL;
  402. if (m_fVisible)
  403. {
  404. if (hwndCur == NULL)
  405. {
  406. hwndNewFocus = m_hwndSpkTrack;
  407. }
  408. else
  409. {
  410. for (nIndex = 0; nIndex < nSizeArray; nIndex++)
  411. {
  412. if (aHwnds[nIndex] == hwndCur)
  413. {
  414. nSelect = (nIndex + (fForward ? 1 : -1)) % nSizeArray;
  415. if (nSelect < 0)
  416. nSelect += nSizeArray;
  417. hwndNewFocus = aHwnds[nSelect];
  418. break;
  419. }
  420. }
  421. }
  422. if (hwndNewFocus)
  423. {
  424. SetFocus(hwndNewFocus);
  425. bRet = TRUE;
  426. }
  427. }
  428. return bRet;
  429. }
  430. BOOL CAudioLevel::IsChildWindow(HWND hwnd)
  431. {
  432. if (hwnd)
  433. {
  434. if ((hwnd == m_hwndSpkTrack) || (hwnd == m_hwndMicTrack) ||
  435. (hwnd == m_hwndChkbRecMute) || (hwnd == m_hwndChkbSpkMute))
  436. {
  437. return TRUE;
  438. }
  439. }
  440. return FALSE;
  441. }
  442. BOOL CAudioLevel::OnMuteChange(BOOL fSpeaker, BOOL fMute)
  443. {
  444. SendMessage(fSpeaker ? m_hwndChkbSpkMute : m_hwndChkbRecMute,
  445. BM_SETCHECK, fMute ? BST_UNCHECKED : BST_CHECKED, 0);
  446. return TRUE;
  447. }
  448. BOOL CAudioLevel::OnPaint(PAINTSTRUCT* pps)
  449. {
  450. if (m_fVisible)
  451. {
  452. ASSERT(pps);
  453. ASSERT(pps->hdc);
  454. PaintIcons(pps->hdc);
  455. }
  456. return TRUE;
  457. }
  458. BOOL CAudioLevel::PaintChannel(BOOL fSpeaker, HDC hdc)
  459. {
  460. BOOL bGotDC = FALSE;
  461. DWORD dwVolume;
  462. int nVuWidth, nDiff;
  463. RECT rect, rectDraw;
  464. HBRUSH hCurrentBrush;
  465. HPEN hOldPen;
  466. int nRects;
  467. int nRectangleWidth;
  468. int nIndex;
  469. const int NUM_RECTANGLES_MAX = 16;
  470. const int NUM_RECTANGLES_MIN = 6;
  471. int nRectsTotal;
  472. bool bTransmitting;
  473. POINT ptOld, pt;
  474. if (fSpeaker)
  475. {
  476. dwVolume = LOWORD(m_dwSpkLvl);
  477. bTransmitting = HIWORD(m_dwSpkLvl) & SIGNAL_STATUS_TRANSMIT;
  478. }
  479. else
  480. {
  481. dwVolume = LOWORD(m_dwMicLvl);
  482. bTransmitting = HIWORD(m_dwMicLvl) & SIGNAL_STATUS_TRANSMIT;
  483. }
  484. if (!hdc)
  485. {
  486. if ((fSpeaker) && (m_hwndSpkTrack))
  487. hdc = GetDC(m_hwndSpkTrack);
  488. else if (m_hwndMicTrack)
  489. hdc = GetDC(m_hwndMicTrack);
  490. bGotDC = TRUE;
  491. }
  492. if (!hdc)
  493. return FALSE;
  494. // rectangle leading is 1
  495. if (dwVolume > 100)
  496. dwVolume = 100;
  497. if (fSpeaker)
  498. rect = m_rcChannelSpk;
  499. else
  500. rect = m_rcChannelMic;
  501. nVuWidth = rect.right - rect.left;
  502. if (nVuWidth < (NUM_RECTANGLES_MIN*2))
  503. return FALSE;
  504. // "rect" represents the edges of the meter's outer rectangle
  505. // compute the number of individual rectangles to use
  506. // we do the computation this way so that sizing the rebar band
  507. // makes the size changes consistant
  508. nRectsTotal = NUM_RECTANGLES_MAX;
  509. nRectsTotal = (nVuWidth + (g_nAudMeterHeight - 1)) / g_nAudMeterHeight;
  510. nRectsTotal = min(nRectsTotal, NUM_RECTANGLES_MAX);
  511. nRectsTotal = max(nRectsTotal, NUM_RECTANGLES_MIN);
  512. // nRectangleWidth - width of colored rectangle - no leading
  513. nRectangleWidth = ((nVuWidth-2)/nRectsTotal) - 1;
  514. // nVuWidth - width of entire VU meter including edges
  515. nVuWidth = (nRectangleWidth + 1)*nRectsTotal + 2;
  516. // re-adjust meter size to be an integral number of rects
  517. nDiff = rect.right - (rect.left + nVuWidth);
  518. rect.right = rect.left + nVuWidth;
  519. // center vu-meter across whole channel area so that the
  520. // slider's thumb is always covering some portion of the channel
  521. rect.left += (nDiff/2);
  522. rect.right += (nDiff/2);
  523. // draw the 3D frame border
  524. hOldPen = (HPEN) SelectObject (hdc, m_hHiLitePen);
  525. MoveToEx(hdc, rect.right, rect.top, &ptOld);
  526. LineTo(hdc, rect.right, rect.bottom);
  527. LineTo(hdc, rect.left-1, rect.bottom); // -1 because LineTo stops just short of this point
  528. SelectObject(hdc, m_hShadowPen);
  529. MoveToEx(hdc, rect.left, rect.bottom-1, &pt);
  530. LineTo(hdc, rect.left, rect.top);
  531. LineTo(hdc, rect.right, rect.top);
  532. SelectObject(hdc, m_hDkShadowPen);
  533. MoveToEx(hdc, rect.left+1, rect.bottom-2, &pt);
  534. LineTo(hdc, rect.left+1, rect.top+1);
  535. LineTo(hdc, rect.right-1, rect.top+1);
  536. SelectObject(hdc, m_hLitePen);
  537. MoveToEx(hdc, rect.left+1, rect.bottom-1, &pt);
  538. LineTo(hdc, rect.right-1, rect.bottom-1);
  539. LineTo(hdc, rect.right-1, rect.top);
  540. SelectObject(hdc, m_hShadowPen);
  541. // the top and left of the meter has a 2 line border
  542. // the bottom and right of the meter has a 2 line border
  543. rectDraw.top = rect.top + 2;
  544. rectDraw.bottom = rect.bottom - 1 ;
  545. rectDraw.left = rect.left + 2;
  546. rectDraw.right = rectDraw.left + nRectangleWidth;
  547. // how many colored rectangles do we draw ?
  548. nRects = (dwVolume * nRectsTotal) / 100;
  549. // not transmitting - don't show anything
  550. if ((false == bTransmitting) && (false == fSpeaker))
  551. nRects = 0;
  552. // transmitting or receiving something very quiet -
  553. // light up at least one rectangle
  554. else if ((bTransmitting) && (nRects == 0))
  555. nRects = 1;
  556. hCurrentBrush = m_hGreenBrush;
  557. for (nIndex = 0; nIndex < nRectsTotal; nIndex++)
  558. {
  559. // far left fourth of the bar is green
  560. // right fourth of the bar is red
  561. // middle is yellow
  562. if (nIndex > ((nRectsTotal*3)/4))
  563. hCurrentBrush = m_hRedBrush;
  564. else if (nIndex >= nRectsTotal/2)
  565. hCurrentBrush = m_hYellowBrush;
  566. if (nIndex >= nRects)
  567. hCurrentBrush = m_hGreyBrush;
  568. FillRect(hdc, &rectDraw, hCurrentBrush);
  569. if (nIndex != (nRectsTotal-1))
  570. {
  571. MoveToEx(hdc, rectDraw.left + nRectangleWidth, rectDraw.top, &pt);
  572. LineTo(hdc, rectDraw.left + nRectangleWidth, rectDraw.bottom);
  573. }
  574. rectDraw.left += nRectangleWidth + 1; // +1 for the leading
  575. rectDraw.right = rectDraw.left + nRectangleWidth;
  576. }
  577. MoveToEx(hdc, ptOld.x, ptOld.y, &pt);
  578. SelectObject (hdc, hOldPen);
  579. if (bGotDC)
  580. {
  581. DeleteDC(hdc);
  582. }
  583. return TRUE;
  584. }
  585. BOOL CAudioLevel::OnTimer(WPARAM wTimerID)
  586. {
  587. DWORD dwLevel;
  588. if (m_fVisible && (NULL != m_pAudioControl))
  589. {
  590. dwLevel = m_pAudioControl->GetAudioSignalLevel(FALSE /*fSpeaker*/); // This level ranges from 0-100
  591. if (dwLevel != m_dwMicLvl)
  592. {
  593. m_dwMicLvl = dwLevel;
  594. // HACK: SETRANGEMAX is the only way to force the slider to update itself...
  595. SendMessage(m_hwndMicTrack, TBM_SETRANGEMAX, TRUE, g_nAudTrkRangeMax);
  596. }
  597. dwLevel = m_pAudioControl->GetAudioSignalLevel(TRUE /*fSpeaker*/); // This level ranges from 0-100
  598. if (dwLevel != m_dwSpkLvl)
  599. {
  600. m_dwSpkLvl = dwLevel;
  601. SendMessage(m_hwndSpkTrack, TBM_SETRANGEMAX, TRUE, g_nAudTrkRangeMax);
  602. }
  603. }
  604. return TRUE;
  605. }
  606. // returns the coordinates of where one of the icons should be drawn
  607. BOOL CAudioLevel::GetIconArea(BOOL fSpeaker, RECT *pRect)
  608. {
  609. int nIconY;
  610. int nLeftMic;
  611. int nLeftSpk;
  612. nIconY = (m_rect.bottom - m_rect.top - g_nAudIconHeight - 1) / 2;
  613. pRect->top = m_rect.top + nIconY;
  614. pRect->bottom = pRect->top + g_nAudIconHeight;
  615. if (fSpeaker)
  616. {
  617. pRect->left = m_rect.left + ((m_rect.right - m_rect.left) / 2) + g_nAudIconXMargin;
  618. }
  619. else
  620. {
  621. pRect->left = m_rect.left + g_nAudIconXMargin;
  622. }
  623. pRect->right = pRect->left + g_nAudIconWidth;
  624. return TRUE;
  625. }
  626. BOOL CAudioLevel::PaintIcons(HDC hdc)
  627. {
  628. int nIconY;
  629. ASSERT(hdc);
  630. RECT rect;
  631. if (NULL != m_hIconMic)
  632. {
  633. GetIconArea(FALSE, &rect);
  634. DrawIconEx( hdc,
  635. rect.left,
  636. rect.top,
  637. m_hIconMic,
  638. rect.right - rect.left,
  639. rect.bottom - rect.top,
  640. 0,
  641. NULL,
  642. DI_NORMAL);
  643. }
  644. if (NULL != m_hIconSpkr)
  645. {
  646. GetIconArea(TRUE, &rect);
  647. DrawIconEx( hdc,
  648. rect.left,
  649. rect.top,
  650. m_hIconSpkr,
  651. rect.right - rect.left,
  652. rect.bottom - rect.top,
  653. 0,
  654. NULL,
  655. DI_NORMAL);
  656. }
  657. return TRUE;
  658. }
  659. BOOL CAudioLevel::OnDeviceStatusChanged(BOOL fSpeaker, UINT uEvent, UINT uSubCode)
  660. {
  661. UINT uIconID;
  662. HICON *phIcon;
  663. UINT *puIconID;
  664. RECT rectInvalid;
  665. switch (uEvent)
  666. {
  667. case NM_STREAMEVENT_DEVICE_CLOSED:
  668. {
  669. uIconID = fSpeaker ? IDI_SPKEMPTY : IDI_MICEMPTY;
  670. break;
  671. }
  672. case NM_STREAMEVENT_DEVICE_OPENED:
  673. {
  674. uIconID = fSpeaker ? IDI_SPEAKER : IDI_MICFONE;
  675. break;
  676. }
  677. case NM_STREAMEVENT_DEVICE_FAILURE:
  678. {
  679. uIconID = fSpeaker ? IDI_SPKERROR : IDI_MICERROR;
  680. break;
  681. }
  682. default:
  683. return FALSE;
  684. }
  685. phIcon = fSpeaker ? &m_hIconSpkr : &m_hIconMic;
  686. puIconID = fSpeaker ? &m_uIconSpkrID : &m_uIconMicID;
  687. if (*puIconID == uIconID)
  688. return TRUE;
  689. *phIcon = (HICON) ::LoadImage( ::GetInstanceHandle(),
  690. MAKEINTRESOURCE(uIconID),
  691. IMAGE_ICON,
  692. g_nAudIconWidth,
  693. g_nAudIconHeight,
  694. LR_DEFAULTCOLOR | LR_SHARED);
  695. // invalidate the icon regions
  696. if (m_hwndParentParent)
  697. {
  698. RECT rect;
  699. GetIconArea(fSpeaker, &rect);
  700. ::MapWindowPoints(m_hwndParent, m_hwndParentParent, (LPPOINT) &rect, 2);
  701. ::InvalidateRect(m_hwndParentParent, &rect, TRUE /* erase bkgnd */);
  702. ::UpdateWindow(m_hwndParentParent);
  703. }
  704. return TRUE;
  705. }
  706. BOOL CAudioLevel::Resize(int nLeft, int nTop, int nWidth, int nHeight)
  707. {
  708. int nCBY, nTBY; // checkbox, trackbar, and Icon y positions
  709. // Disable redraws:
  710. ASSERT(m_hwndChkbRecMute && m_hwndChkbSpkMute && m_hwndMicTrack && m_hwndSpkTrack);
  711. if (m_fVisible)
  712. {
  713. ::SendMessage(m_hwndChkbRecMute, WM_SETREDRAW, FALSE, 0);
  714. ::SendMessage(m_hwndChkbSpkMute, WM_SETREDRAW, FALSE, 0);
  715. ::SendMessage(m_hwndMicTrack, WM_SETREDRAW, FALSE, 0);
  716. ::SendMessage(m_hwndSpkTrack, WM_SETREDRAW, FALSE, 0);
  717. }
  718. m_rect.left = nLeft;
  719. m_rect.top = nTop;
  720. m_rect.right = nLeft + nWidth;
  721. m_rect.bottom = nTop + nHeight;
  722. nCBY = (m_rect.bottom - m_rect.top - g_nAudChkbHeight) / 2;
  723. if (nCBY < 0)
  724. nCBY = 0;
  725. // "+1" so the trackbar is better centered with the checkbox and icon
  726. nTBY = (m_rect.bottom - m_rect.top - g_nAudTrkHeight + 1) / 2;
  727. if (nTBY < 0)
  728. nTBY = 0;
  729. int nHalfPoint = nLeft + (nWidth / 2);
  730. if (NULL != m_hwndChkbRecMute)
  731. {
  732. ::MoveWindow( m_hwndChkbRecMute,
  733. nLeft + g_nAudChkbXMargin,
  734. nTop + nCBY,
  735. g_nAudChkbWidth,
  736. g_nAudChkbHeight,
  737. TRUE /* repaint */);
  738. }
  739. if (NULL != m_hwndChkbSpkMute)
  740. {
  741. ::MoveWindow( m_hwndChkbSpkMute,
  742. nHalfPoint + g_nAudChkbXMargin,
  743. nTop + nCBY,
  744. g_nAudChkbWidth,
  745. g_nAudChkbHeight,
  746. TRUE /* repaint */);
  747. }
  748. m_fMicTrkVisible = m_fVisible;
  749. if (NULL != m_hwndMicTrack)
  750. {
  751. int nMicTrkWidth = nHalfPoint - g_nAudTrkRightGap - (nLeft + g_nAudTrkXMargin);
  752. ::MoveWindow( m_hwndMicTrack,
  753. nLeft + g_nAudTrkXMargin,
  754. nTop + nTBY,
  755. nMicTrkWidth,
  756. g_nAudTrkHeight,
  757. FALSE /* don't repaint */);
  758. m_fMicTrkVisible = (nMicTrkWidth > g_nAudTrkMinWidth);
  759. }
  760. m_fSpkTrkVisible = m_fVisible;
  761. if (NULL != m_hwndSpkTrack)
  762. {
  763. int nSpkTrkWidth = nLeft + nWidth - g_nAudTrkRightGap
  764. - (nHalfPoint + g_nAudTrkXMargin);
  765. ::MoveWindow( m_hwndSpkTrack,
  766. nHalfPoint + g_nAudTrkXMargin,
  767. nTop + nTBY,
  768. nSpkTrkWidth,
  769. g_nAudTrkHeight,
  770. FALSE /* don't repaint */);
  771. m_fSpkTrkVisible = (nSpkTrkWidth > g_nAudTrkMinWidth);
  772. }
  773. // enable redraws
  774. if (m_fVisible)
  775. {
  776. ::SendMessage(m_hwndChkbRecMute, WM_SETREDRAW, TRUE, 0);
  777. ::SendMessage(m_hwndChkbSpkMute, WM_SETREDRAW, TRUE, 0);
  778. // Enable redraws:
  779. if (m_fMicTrkVisible)
  780. {
  781. ::SendMessage(m_hwndMicTrack, WM_SETREDRAW, TRUE, 0);
  782. }
  783. if (m_fSpkTrkVisible)
  784. {
  785. ::SendMessage(m_hwndSpkTrack, WM_SETREDRAW, TRUE, 0);
  786. }
  787. // Force the title area to repaint:
  788. ::InvalidateRect(m_hwndChkbRecMute, NULL, TRUE /* erase bkgnd */);
  789. ::InvalidateRect(m_hwndChkbSpkMute, NULL, TRUE /* erase bkgnd */);
  790. ::InvalidateRect(m_hwndMicTrack, NULL, TRUE /* erase bkgnd */);
  791. ::InvalidateRect(m_hwndSpkTrack, NULL, TRUE /* erase bkgnd */);
  792. ASSERT(m_hwndParent);
  793. ASSERT(m_hwndParentParent);
  794. RECT rctTemp = m_rect;
  795. ::MapWindowPoints(m_hwndParent, m_hwndParentParent, (LPPOINT) &rctTemp, 2);
  796. ::InvalidateRect(m_hwndParentParent, &rctTemp, TRUE /* erase bkgnd */);
  797. ::UpdateWindow(m_hwndParentParent);
  798. }
  799. return TRUE;
  800. }
  801. BOOL CAudioLevel::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *plRet)
  802. {
  803. LPNMCUSTOMDRAW pCustomDraw;
  804. BOOL bRet = FALSE, fSpeaker;
  805. RECT *pChannelRect;
  806. *plRet = 0;
  807. fSpeaker = (wParam == ID_AUDIODLG_SPKR_TRACK);
  808. if (fSpeaker)
  809. {
  810. pChannelRect = &m_rcChannelSpk;
  811. }
  812. else
  813. {
  814. pChannelRect = &m_rcChannelMic;
  815. }
  816. pCustomDraw = (LPNMCUSTOMDRAW)lParam;
  817. switch (pCustomDraw->dwDrawStage)
  818. {
  819. case CDDS_PREPAINT:
  820. bRet = TRUE;
  821. *plRet = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
  822. break;
  823. case CDDS_ITEMPREPAINT:
  824. if (pCustomDraw->dwItemSpec == TBCD_CHANNEL)
  825. {
  826. *plRet = CDRF_SKIPDEFAULT;
  827. bRet = TRUE;
  828. pCustomDraw->rc.top -= 2;
  829. pCustomDraw->rc.bottom += 2;
  830. *pChannelRect = pCustomDraw->rc;
  831. PaintChannel(fSpeaker, pCustomDraw->hdc);
  832. }
  833. break;
  834. default:
  835. break;
  836. }
  837. return bRet;
  838. }
  839. BOOL CAudioLevel::OnScroll(WPARAM wParam, LPARAM lParam)
  840. {
  841. BOOL bRet = FALSE;
  842. if ((HWND) lParam == m_hwndMicTrack)
  843. {
  844. DWORD dwCurMicTrackPos = ::SendMessage((HWND) lParam, TBM_GETPOS, 0, 0);
  845. if (m_dwMicTrackPos != dwCurMicTrackPos)
  846. {
  847. m_dwMicTrackPos = dwCurMicTrackPos;
  848. m_pAudioControl->SetRecorderVolume(
  849. (m_dwMicTrackPos * 0xFFFF) / g_nAudTrkRangeMax);
  850. }
  851. bRet = TRUE;
  852. }
  853. else if ((HWND) lParam == m_hwndSpkTrack)
  854. {
  855. DWORD dwCurSpkTrackPos = ::SendMessage((HWND) lParam, TBM_GETPOS, 0, 0);
  856. if (m_dwSpkTrackPos != dwCurSpkTrackPos)
  857. {
  858. m_dwSpkTrackPos = dwCurSpkTrackPos;
  859. m_pAudioControl->SetSpeakerVolume(
  860. (m_dwSpkTrackPos * 0xFFFF) / g_nAudTrkRangeMax);
  861. }
  862. bRet = TRUE;
  863. }
  864. return bRet;
  865. }
  866. BOOL CAudioLevel::OnLevelChange(BOOL fSpeaker, DWORD dwVolume)
  867. {
  868. if (fSpeaker)
  869. {
  870. if (NULL != m_hwndSpkTrack)
  871. {
  872. DWORD dwTrackPos = ScaleMixer(dwVolume);
  873. if (m_dwSpkTrackPos != dwTrackPos)
  874. {
  875. m_dwSpkTrackPos = dwTrackPos;
  876. TRACE_OUT(("Setting Spk Volume to %d", m_dwSpkTrackPos));
  877. ::SendMessage( m_hwndSpkTrack,
  878. TBM_SETPOS,
  879. TRUE,
  880. m_dwSpkTrackPos);
  881. }
  882. }
  883. }
  884. else
  885. {
  886. if (NULL != m_hwndMicTrack)
  887. {
  888. DWORD dwTrackPos = ScaleMixer(dwVolume);
  889. if (m_dwMicTrackPos != dwTrackPos)
  890. {
  891. m_dwMicTrackPos = dwTrackPos;
  892. TRACE_OUT(("Setting Mic Volume to %d", m_dwMicTrackPos));
  893. ::SendMessage( m_hwndMicTrack,
  894. TBM_SETPOS,
  895. TRUE,
  896. m_dwMicTrackPos);
  897. }
  898. }
  899. }
  900. return TRUE;
  901. }
  902. BOOL CAudioLevel::OnDeviceChanged(void)
  903. {
  904. ASSERT(m_pAudioControl);
  905. EnableWindow(m_hwndMicTrack, m_pAudioControl->CanSetRecorderVolume());
  906. EnableWindow(m_hwndSpkTrack, m_pAudioControl->CanSetSpeakerVolume());
  907. return TRUE;
  908. }
  909. BOOL CAudioLevel::Show(BOOL fVisible)
  910. {
  911. m_fVisible = fVisible;
  912. if (m_fVisible)
  913. {
  914. // Start mic sensitivity timer:
  915. ::SetTimer(m_hwndParent, AUDIODLG_MIC_TIMER, AUDIODLG_MIC_TIMER_PERIOD, NULL);
  916. }
  917. else
  918. {
  919. // Stop mic sensitivity timer:
  920. ::KillTimer(m_hwndParent, AUDIODLG_MIC_TIMER);
  921. }
  922. // Hide or show all windows:
  923. if (NULL != m_hwndChkbRecMute)
  924. {
  925. ::ShowWindow(m_hwndChkbRecMute, fVisible ? SW_SHOW : SW_HIDE);
  926. }
  927. if (NULL != m_hwndChkbSpkMute)
  928. {
  929. ::ShowWindow(m_hwndChkbSpkMute, fVisible ? SW_SHOW : SW_HIDE);
  930. }
  931. if (NULL != m_hwndMicTrack)
  932. {
  933. ::ShowWindow(m_hwndMicTrack, (fVisible && m_fMicTrkVisible) ? SW_SHOW : SW_HIDE);
  934. }
  935. if (NULL != m_hwndSpkTrack)
  936. {
  937. ::ShowWindow(m_hwndSpkTrack, (fVisible && m_fSpkTrkVisible) ? SW_SHOW : SW_HIDE);
  938. }
  939. return TRUE;
  940. }