Leaked source code of windows server 2003
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.

539 lines
20 KiB

  1. /*-----------------------------------------------------------------------------+
  2. | TRACKMAP.C |
  3. | |
  4. | This file contains the code that implements the "MPlayerTrackMap" control. |
  5. | The control displays the list of tracks contained in the current medium, or |
  6. | a time scale appropriate to the length of the medium, in such a way as to |
  7. | serve as a scale for the scrollbar. |
  8. | |
  9. | (C) Copyright Microsoft Corporation 1991. All rights reserved. |
  10. | |
  11. | Revision History |
  12. | Oct-1992 MikeTri Ported to WIN32 / WIN16 common code |
  13. | |
  14. +-----------------------------------------------------------------------------*/
  15. /* include files */
  16. #include <windows.h>
  17. #include <mmsystem.h>
  18. #include "mplayer.h"
  19. #include "toolbar.h"
  20. typedef struct tagScale {
  21. DWORD dwInterval;
  22. UINT wScale;
  23. } SCALE;
  24. STATICDT SCALE aScale[] =
  25. {
  26. { 1, SCALE_SECONDS },
  27. { 2, SCALE_SECONDS },
  28. { 5, SCALE_SECONDS },
  29. { 10, SCALE_SECONDS },
  30. { 25, SCALE_SECONDS },
  31. { 50, SCALE_SECONDS },
  32. { 100, SCALE_SECONDS },
  33. { 250, SCALE_SECONDS },
  34. { 500, SCALE_SECONDS },
  35. { 1000, SCALE_SECONDS },
  36. { 2000, SCALE_SECONDS },
  37. { 5000, SCALE_SECONDS },
  38. { 10000, SCALE_SECONDS },
  39. { 15000, SCALE_MINUTES },
  40. { 30000, SCALE_MINUTES },
  41. { 60000, SCALE_MINUTES },
  42. { 120000, SCALE_MINUTES },
  43. { 300000, SCALE_MINUTES },
  44. { 600000, SCALE_HOURS },
  45. { 1800000, SCALE_HOURS },
  46. { 3600000, SCALE_HOURS },
  47. { 7200000, SCALE_HOURS },
  48. { 18000000, SCALE_HOURS },
  49. { 36000000, SCALE_HOURS },
  50. { 72000000, SCALE_HOURS }
  51. };
  52. STATICDT SZCODE aszNULL[] = TEXT("");
  53. STATICDT SZCODE aszOneDigit[] = TEXT("0");
  54. STATICDT SZCODE aszTwoDigits[] = TEXT("00");
  55. STATICDT SZCODE aszPositionFormat[] = TEXT("%0d");
  56. STATICDT SZCODE aszMSecFormat[] = TEXT("%d");
  57. STATICDT SZCODE aszHourFormat[] = TEXT("%d%c");
  58. STATICDT SZCODE aszMinuteFormat[] = TEXT("%d%c");
  59. STATICDT SZCODE aszSecondFormat[] = TEXT("%d%c");
  60. STATICDT SZCODE aszSecondFormatNoLzero[] = TEXT("%c");
  61. STATICDT SZCODE aszDecimalFormat[] = TEXT("%02d");
  62. /*
  63. * fnMPlayerTrackMap()
  64. *
  65. * This is the window procedure for windows of class "MPlayerTrackMap".
  66. * This window shows the position of the start of each track of the
  67. * current medium or a time scale, displayed above the scrollbar which shows
  68. * the current play position within the medium.
  69. *
  70. */
  71. void FAR PASCAL CalcTicsOfDoom(void);
  72. extern UINT gwCurScale; /* The current scale in which to draw the track map*/
  73. extern BOOL gfCurrentCDNotAudio;/* TRUE when we have a CD that we can't play */
  74. LRESULT FAR PASCAL fnMPlayerTrackMap(
  75. HWND hwnd, /*handle to a MPlayerTrackMap window*/
  76. UINT wMsg, /* message number */
  77. WPARAM wParam, /* message-dependent parameter */
  78. LPARAM lParam) /* message-dependent parameter */
  79. {
  80. PAINTSTRUCT ps; /* paint structure for the window */
  81. RECT rc, rcSB; /* dimensions of the windows */
  82. POINT ptExtent; /* extent of the track marks */
  83. TCHAR szLabel[20]; /* string holding the current label */
  84. TCHAR szLabel2[20]; /* string holding the current label */
  85. UINT wNumTics,
  86. wTicNo,
  87. wTemp,
  88. wHour,
  89. wMin,
  90. wSec,
  91. wMsec;
  92. int iOldPosition = -1000;
  93. int iNewPosition;
  94. UINT wScale;
  95. DWORD dwMarkValue;
  96. int iLargeMarkSize, iFit, iLastPos, iLen;
  97. BOOL fForceTextDraw = FALSE;
  98. HBRUSH hbr;
  99. switch (wMsg) {
  100. case WM_PAINT:
  101. BeginPaint(hwnd, &ps);
  102. GetClientRect(ghwndTrackbar, &rcSB);
  103. GetClientRect(hwnd, &rc);
  104. /* Set background and text colours */
  105. (VOID)SendMessage(ghwndApp, WM_CTLCOLORSTATIC,
  106. (WPARAM)ps.hdc, (LONG_PTR)hwnd);
  107. /* Get the length of the scrollbar we're putting tics under */
  108. /* Use these numbers for size and position calculations */
  109. GetClientRect(ghwndMap, &rc);
  110. /*
  111. * Check to see if we actually have a valid device loaded up;
  112. * if not, don't display anything
  113. *
  114. */
  115. if (gwDeviceID == 0
  116. || gwStatus == MCI_MODE_OPEN
  117. || gwStatus == MCI_MODE_NOT_READY || gdwMediaLength == 0
  118. || !gfValidMediaInfo
  119. || gfCurrentCDNotAudio) {
  120. EndPaint(hwnd,&ps);
  121. //VIJR-SBSetWindowText(ghwndStatic, aszNULL);
  122. WriteStatusMessage(ghwndStatic, (LPTSTR)aszNULL);
  123. return 0L;
  124. }
  125. /* Select the font to use */
  126. if (ghfontMap != NULL)
  127. SelectObject(ps.hdc, ghfontMap);
  128. /*
  129. * Because the scrollbar thumb takes up space in the inner part
  130. * of the scrollbar, compute its width so that we can compensate
  131. * for it while displaying the trackmap.
  132. *
  133. */
  134. /*
  135. * Get the child window rectangle and reduce it such that
  136. * it is the same width as the inner part of the scrollbar.
  137. *
  138. */
  139. //rc.left; //!!! GetSystemMetrics(SM_CXHSCROLL);
  140. //rc.right; //!!!(GetSystemMetrics(SM_CXHSCROLL));
  141. /* Now, Put text underneath the TICS */
  142. if (gwCurScale == ID_TRACKS) {
  143. SIZE Size;
  144. GetTextExtentPoint32( ps.hdc, aszTwoDigits, 2, &Size );
  145. ptExtent.x = Size.cx;
  146. ptExtent.y = Size.cy;
  147. /*
  148. * Based on the width of the child window, compute the positions
  149. * to place the track markers.
  150. *
  151. */
  152. wNumTics = (UINT)SendMessage(ghwndTrackbar, TBM_GETNUMTICS, 0, 0L);
  153. /*
  154. * TBM_GETNUMTICS returns the number of visible tics
  155. * which includes the first and last tics not created
  156. * by media player. Subtract 2 to account for the
  157. * the first and last tics.
  158. *
  159. */
  160. if (wNumTics >= 2)
  161. wNumTics = wNumTics - 2;
  162. for(wTicNo = 0; wTicNo < wNumTics; wTicNo++) {
  163. /* Get the position of the next tic */
  164. iNewPosition = (int)SendMessage(ghwndTrackbar, TBM_GETTICPOS,
  165. (WPARAM)wTicNo, 0L);
  166. /* Centre it above the marker. */
  167. iNewPosition -= ptExtent.x / 4;
  168. /*
  169. * Check to make sure that we are not overwriting the
  170. * text from the previous marker.
  171. *
  172. */
  173. if (iNewPosition > iOldPosition) {
  174. wsprintf(szLabel, aszPositionFormat, wTicNo + gwFirstTrack);
  175. TextOut(ps.hdc,
  176. iNewPosition + rc.left,
  177. 0, szLabel,
  178. (wTicNo + gwFirstTrack < 10) ? 1 : 2 );
  179. /* Finish the end of the text string we just printed */
  180. iOldPosition = iNewPosition +
  181. ((wTicNo + gwFirstTrack < 10)
  182. ? ptExtent.x / 2 : ptExtent.x);
  183. }
  184. }
  185. } else {
  186. #define ONE_HOUR (60ul*60ul*1000ul)
  187. #define ONE_MINUTE (60ul*1000ul)
  188. #define ONE_SECOND (1000ul)
  189. /*
  190. * The scale is set to display time - find out what units
  191. * (msec, sec, min, or hour) are most appropriate, for the
  192. * scale. This requires us to look at both the overall length
  193. * of the medium and the distance between markers (or
  194. * granularity).
  195. *
  196. */
  197. /*
  198. * Find the maximum number of markers that we can draw without
  199. * cluttering the display too badly, and find the granularity
  200. * between these markers.
  201. *
  202. */
  203. SIZE Size;
  204. GetTextExtentPoint32( ps.hdc, aszOneDigit, 1, &Size );
  205. ptExtent.x = Size.cx;
  206. ptExtent.y = Size.cy;
  207. if (gdwMediaLength < 10)
  208. iLargeMarkSize = 1;
  209. else if (gdwMediaLength < 100)
  210. iLargeMarkSize = 2;
  211. else if (gdwMediaLength < 1000)
  212. iLargeMarkSize = 3;
  213. else if (gdwMediaLength < 10000)
  214. iLargeMarkSize = 4;
  215. else
  216. iLargeMarkSize = 5;
  217. wNumTics = (UINT)SendMessage(ghwndTrackbar, TBM_GETNUMTICS,
  218. 0, 0L);
  219. /*
  220. * TBM_GETNUMTICS returns the number of visible tics
  221. * which includes the first and last tics not created
  222. * by media player. Subtract 2 to account for the
  223. * the first and last tics.
  224. *
  225. */
  226. if (wNumTics >= 2)
  227. wNumTics = wNumTics - 2;
  228. /* Where the text for the last mark will begin */
  229. if (wNumTics > 1) {
  230. iLastPos = (int)SendMessage(ghwndTrackbar,
  231. TBM_GETTICPOS, (WPARAM)wNumTics - 1, 0L);
  232. iLastPos -= ptExtent.x / 2; // centre 1st numeral
  233. }
  234. /* What scale do we use? Hours, minutes, or seconds? */
  235. /* NOTE: THIS MUST AGREE WITH WHAT FormatTime() does */
  236. /* in mplayer.c !!! */
  237. if (gwCurScale == ID_FRAMES)
  238. wScale = SCALE_FRAMES;
  239. else {
  240. if (gdwMediaLength > ONE_HOUR)
  241. wScale = SCALE_HOURS;
  242. else if (gdwMediaLength > ONE_MINUTE)
  243. wScale = SCALE_MINUTES;
  244. else
  245. wScale = SCALE_SECONDS;
  246. }
  247. for (wTicNo = 0; wTicNo < wNumTics; wTicNo++) {
  248. /* The text for the last tic is always drawn */
  249. if (wTicNo == wNumTics - 1)
  250. fForceTextDraw = TRUE;
  251. dwMarkValue = (DWORD)SendMessage(ghwndTrackbar, TBM_GETTIC,
  252. (WPARAM)wTicNo, 0L);
  253. iNewPosition = (int)SendMessage(ghwndTrackbar, TBM_GETTICPOS,
  254. (WPARAM)wTicNo, 0L);
  255. /*
  256. * Get the text ready for printing and centre it above the
  257. * marker.
  258. *
  259. */
  260. switch ( wScale ) {
  261. case SCALE_FRAMES:
  262. case SCALE_MSEC:
  263. wsprintf(szLabel, aszMSecFormat, dwMarkValue);
  264. break;
  265. case SCALE_HOURS:
  266. wHour = (WORD)(dwMarkValue / 3600000);
  267. wMin = (WORD)((dwMarkValue % 3600000) / 60000);
  268. wsprintf(szLabel2,aszDecimalFormat,wMin);
  269. wsprintf(szLabel,aszHourFormat,wHour, chTime);
  270. lstrcat(szLabel,szLabel2);
  271. break;
  272. case SCALE_MINUTES :
  273. wMin = (WORD)(dwMarkValue / 60000);
  274. wSec = (WORD)((dwMarkValue % 60000) / 1000);
  275. wsprintf(szLabel2,aszDecimalFormat,wSec);
  276. wsprintf(szLabel,aszMinuteFormat,wMin,chTime);
  277. lstrcat(szLabel,szLabel2);
  278. break;
  279. case SCALE_SECONDS :
  280. wSec = (WORD)((dwMarkValue + 5) / 1000);
  281. wMsec = (WORD)(((dwMarkValue + 5) % 1000) / 10);
  282. wsprintf(szLabel2,aszDecimalFormat,wMsec);
  283. if (!wSec && chLzero == TEXT('0'))
  284. wsprintf(szLabel, aszSecondFormatNoLzero, chDecimal);
  285. else
  286. wsprintf(szLabel, aszSecondFormat, wSec, chDecimal);
  287. lstrcat(szLabel,szLabel2);
  288. break;
  289. }
  290. wTemp = STRLEN(szLabel);
  291. iNewPosition -= ptExtent.x / 2; // centre 1st numeral
  292. /* The position after which text will be cut off the */
  293. /* right edge of the window */
  294. iFit = rc.right - rc.left - (ptExtent.x * iLargeMarkSize);
  295. /* Calculate the length of the text we just printed. */
  296. /* Leave a little space at the end, too. */
  297. iLen = (ptExtent.x * wTemp) + ptExtent.x / 2;
  298. /* Display the mark if we can without overlapping either
  299. * the previous mark or the final mark or going off the
  300. * edge of the window. */
  301. if (fForceTextDraw ||
  302. (iNewPosition >= iOldPosition &&
  303. iNewPosition <= iFit &&
  304. iNewPosition + iLen <= iLastPos)) {
  305. TextOut(ps.hdc, iNewPosition + rc.left, 0,
  306. szLabel, wTemp );
  307. /* Calculate the end pos of the text we just printed. */
  308. iOldPosition = iNewPosition + iLen;
  309. } else {
  310. DPF("Didn't display mark: iNew = %d; iOld = %d; iFit = %d; iLen = %d, iLast = %d\n", iNewPosition, iOldPosition, iFit, iLen, iLastPos);
  311. }
  312. }
  313. }
  314. EndPaint(hwnd, &ps);
  315. return 0L;
  316. case WM_ERASEBKGND:
  317. GetClientRect(hwnd, &rc);
  318. hbr = (HBRUSH)SendMessage(ghwndApp, WM_CTLCOLORSTATIC,
  319. wParam, (LONG_PTR)hwnd);
  320. if (hbr != NULL)
  321. FillRect((HDC)wParam, &rc, hbr);
  322. return TRUE;
  323. }
  324. /* Let DefWindowProc() process all other window messages */
  325. return DefWindowProc(hwnd, wMsg, wParam, lParam);
  326. }
  327. /* Gee thanks for the helpful spec for this routine! */
  328. void FAR PASCAL CalcTicsOfDoom(void)
  329. {
  330. UINT wMarkNo;
  331. int iTableIndex;
  332. DWORD dwMarkValue,
  333. dwNewPosition;
  334. BOOL fDidLastMark = FALSE;
  335. if (gfPlayOnly && !gfOle2IPEditing)
  336. return;
  337. DPF2("CalcTicsOfDoom\n");
  338. SendMessage(ghwndTrackbar, TBM_CLEARTICS, (WPARAM)FALSE, 0L);
  339. if (gwCurScale == ID_TRACKS) {
  340. /*
  341. * Based on the width of the child window, compute the positions
  342. * to place the track marker tics.
  343. *
  344. */
  345. for (wMarkNo = 0; wMarkNo < gwNumTracks; wMarkNo++) {
  346. /* If zero length, don't mark it, unless it is the end */
  347. if ((wMarkNo < gwNumTracks - 1) &&
  348. (gadwTrackStart[wMarkNo] == gadwTrackStart[wMarkNo + 1]))
  349. continue;
  350. /* Compute the centre point and place a marker there */
  351. if (gdwMediaLength == 0)
  352. dwNewPosition = 0;
  353. else
  354. dwNewPosition = gadwTrackStart[wMarkNo];
  355. SendMessage(ghwndTrackbar,
  356. TBM_SETTIC,
  357. (WPARAM)FALSE,
  358. (LPARAM)dwNewPosition);
  359. }
  360. } else {
  361. /*
  362. * The scale is set to display time - find out what units
  363. * (msec, sec, min, or hour) are most appropriate, for the
  364. * scale. This requires us to look at both the overall length
  365. * of the medium and the distance between markers (or
  366. * granularity).
  367. *
  368. */
  369. /*
  370. * Find the maximum number of markers that we can draw without
  371. * cluttering the display too badly, and find the granularity
  372. * between these markers.
  373. *
  374. */
  375. UINT wNumTicks;
  376. RECT rc;
  377. if(!GetClientRect(ghwndMap, &rc)) {
  378. DPF0("GetClientRect failed in CalcTicsOfDoom: Error %d\n", GetLastError());
  379. }
  380. wNumTicks = rc.right / 60;
  381. if (0 == gdwMediaLength) {
  382. iTableIndex = 0;
  383. } else {
  384. DPF4("Checking the scale for media length = %d, tick count = %d\n", gdwMediaLength, wNumTicks);
  385. for (iTableIndex = (sizeof(aScale) / sizeof(SCALE)) -1;
  386. (int)iTableIndex >= 0;
  387. iTableIndex--) {
  388. DPF4("Index %02d: %d\n", aScale[iTableIndex].dwInterval * wNumTicks);
  389. if ((aScale[iTableIndex].dwInterval * wNumTicks)
  390. <= gdwMediaLength)
  391. break;
  392. }
  393. }
  394. #ifdef DEBUG
  395. if ((int)iTableIndex == -1) {
  396. DPF("BAD TABLEINDEX\n");
  397. DebugBreak();
  398. }
  399. #endif
  400. // We have enough room to show every tick. Don't let our index wrap
  401. // around, or we won't see ANY ticks which would look odd.
  402. if (iTableIndex <0)
  403. iTableIndex = 0;
  404. dwMarkValue = gdwMediaStart;
  405. do {
  406. /* Compute the centre point and place a marker there */
  407. if (gdwMediaLength == 0)
  408. dwNewPosition = 0;
  409. else
  410. dwNewPosition = dwMarkValue; // HACK!! - gdwMediaStart;
  411. SendMessage(ghwndTrackbar,
  412. TBM_SETTIC,
  413. (WPARAM)FALSE,
  414. (LPARAM)dwNewPosition);
  415. /* If this is the first mark, adjust so it's going
  416. /* by the right interval. */
  417. if (dwMarkValue == gdwMediaStart) {
  418. dwMarkValue += aScale[iTableIndex].dwInterval
  419. - (dwMarkValue % aScale[iTableIndex].dwInterval);
  420. } else {
  421. dwMarkValue += aScale[iTableIndex].dwInterval;
  422. }
  423. /* If we're almost done, do the final mark. */
  424. if ((dwMarkValue >= (gdwMediaLength + gdwMediaStart))
  425. && !(fDidLastMark)) {
  426. fDidLastMark = TRUE;
  427. dwMarkValue = gdwMediaLength + gdwMediaStart;
  428. }
  429. } while (dwMarkValue <= gdwMediaStart + gdwMediaLength);
  430. }
  431. InvalidateRect(ghwndTrackbar, NULL, FALSE);
  432. InvalidateRect(ghwndMap, NULL, TRUE);
  433. }