windows-nt/Source/XPSP1/NT/multimedia/media/mplayer2/trackmap.c
2020-09-26 16:20:57 +08:00

540 lines
19 KiB
C

/*-----------------------------------------------------------------------------+
| TRACKMAP.C |
| |
| This file contains the code that implements the "MPlayerTrackMap" control. |
| The control displays the list of tracks contained in the current medium, or |
| a time scale appropriate to the length of the medium, in such a way as to |
| serve as a scale for the scrollbar. |
| |
| (C) Copyright Microsoft Corporation 1991. All rights reserved. |
| |
| Revision History |
| Oct-1992 MikeTri Ported to WIN32 / WIN16 common code |
| |
+-----------------------------------------------------------------------------*/
/* include files */
#include <windows.h>
#include <mmsystem.h>
#include "mplayer.h"
#include "toolbar.h"
typedef struct tagScale {
DWORD dwInterval;
UINT wScale;
} SCALE;
STATICDT SCALE aScale[] =
{
{ 1, SCALE_SECONDS },
{ 2, SCALE_SECONDS },
{ 5, SCALE_SECONDS },
{ 10, SCALE_SECONDS },
{ 25, SCALE_SECONDS },
{ 50, SCALE_SECONDS },
{ 100, SCALE_SECONDS },
{ 250, SCALE_SECONDS },
{ 500, SCALE_SECONDS },
{ 1000, SCALE_SECONDS },
{ 2000, SCALE_SECONDS },
{ 5000, SCALE_SECONDS },
{ 10000, SCALE_SECONDS },
{ 15000, SCALE_MINUTES },
{ 30000, SCALE_MINUTES },
{ 60000, SCALE_MINUTES },
{ 120000, SCALE_MINUTES },
{ 300000, SCALE_MINUTES },
{ 600000, SCALE_HOURS },
{ 1800000, SCALE_HOURS },
{ 3600000, SCALE_HOURS },
{ 7200000, SCALE_HOURS },
{ 18000000, SCALE_HOURS },
{ 36000000, SCALE_HOURS },
{ 72000000, SCALE_HOURS }
};
STATICDT SZCODE aszNULL[] = TEXT("");
STATICDT SZCODE aszOneDigit[] = TEXT("0");
STATICDT SZCODE aszTwoDigits[] = TEXT("00");
STATICDT SZCODE aszPositionFormat[] = TEXT("%0d");
STATICDT SZCODE aszMSecFormat[] = TEXT("%d");
STATICDT SZCODE aszHourFormat[] = TEXT("%d%c");
STATICDT SZCODE aszMinuteFormat[] = TEXT("%d%c");
STATICDT SZCODE aszSecondFormat[] = TEXT("%d%c");
STATICDT SZCODE aszSecondFormatNoLzero[] = TEXT("%c");
STATICDT SZCODE aszDecimalFormat[] = TEXT("%02d");
/*
* fnMPlayerTrackMap()
*
* This is the window procedure for windows of class "MPlayerTrackMap".
* This window shows the position of the start of each track of the
* current medium or a time scale, displayed above the scrollbar which shows
* the current play position within the medium.
*
*/
void FAR PASCAL CalcTicsOfDoom(void);
extern UINT gwCurScale; /* The current scale in which to draw the track map*/
extern BOOL gfCurrentCDNotAudio;/* TRUE when we have a CD that we can't play */
LRESULT FAR PASCAL fnMPlayerTrackMap(
HWND hwnd, /*handle to a MPlayerTrackMap window*/
UINT wMsg, /* message number */
WPARAM wParam, /* message-dependent parameter */
LPARAM lParam) /* message-dependent parameter */
{
PAINTSTRUCT ps; /* paint structure for the window */
RECT rc, rcSB; /* dimensions of the windows */
POINT ptExtent; /* extent of the track marks */
TCHAR szLabel[20]; /* string holding the current label */
TCHAR szLabel2[20]; /* string holding the current label */
UINT wNumTics,
wTicNo,
wTemp,
wHour,
wMin,
wSec,
wMsec;
int iOldPosition = -1000;
int iNewPosition;
UINT wScale;
DWORD dwMarkValue;
int iLargeMarkSize, iFit, iLastPos, iLen;
BOOL fForceTextDraw = FALSE;
HBRUSH hbr;
switch (wMsg) {
case WM_PAINT:
BeginPaint(hwnd, &ps);
GetClientRect(ghwndTrackbar, &rcSB);
GetClientRect(hwnd, &rc);
/* Set background and text colours */
(VOID)SendMessage(ghwndApp, WM_CTLCOLORSTATIC,
(WPARAM)ps.hdc, (LONG_PTR)hwnd);
/* Get the length of the scrollbar we're putting tics under */
/* Use these numbers for size and position calculations */
GetClientRect(ghwndMap, &rc);
/*
* Check to see if we actually have a valid device loaded up;
* if not, don't display anything
*
*/
if (gwDeviceID == 0
|| gwStatus == MCI_MODE_OPEN
|| gwStatus == MCI_MODE_NOT_READY || gdwMediaLength == 0
|| !gfValidMediaInfo
|| gfCurrentCDNotAudio) {
EndPaint(hwnd,&ps);
//VIJR-SBSetWindowText(ghwndStatic, aszNULL);
WriteStatusMessage(ghwndStatic, (LPTSTR)aszNULL);
return 0L;
}
/* Select the font to use */
if (ghfontMap != NULL)
SelectObject(ps.hdc, ghfontMap);
/*
* Because the scrollbar thumb takes up space in the inner part
* of the scrollbar, compute its width so that we can compensate
* for it while displaying the trackmap.
*
*/
/*
* Get the child window rectangle and reduce it such that
* it is the same width as the inner part of the scrollbar.
*
*/
//rc.left; //!!! GetSystemMetrics(SM_CXHSCROLL);
//rc.right; //!!!(GetSystemMetrics(SM_CXHSCROLL));
/* Now, Put text underneath the TICS */
if (gwCurScale == ID_TRACKS) {
SIZE Size;
GetTextExtentPoint32( ps.hdc, aszTwoDigits, 2, &Size );
ptExtent.x = Size.cx;
ptExtent.y = Size.cy;
/*
* Based on the width of the child window, compute the positions
* to place the track markers.
*
*/
wNumTics = (UINT)SendMessage(ghwndTrackbar, TBM_GETNUMTICS, 0, 0L);
/*
* TBM_GETNUMTICS returns the number of visible tics
* which includes the first and last tics not created
* by media player. Subtract 2 to account for the
* the first and last tics.
*
*/
if (wNumTics >= 2)
wNumTics = wNumTics - 2;
for(wTicNo = 0; wTicNo < wNumTics; wTicNo++) {
/* Get the position of the next tic */
iNewPosition = (int)SendMessage(ghwndTrackbar, TBM_GETTICPOS,
(WPARAM)wTicNo, 0L);
/* Centre it above the marker. */
iNewPosition -= ptExtent.x / 4;
/*
* Check to make sure that we are not overwriting the
* text from the previous marker.
*
*/
if (iNewPosition > iOldPosition) {
wsprintf(szLabel, aszPositionFormat, wTicNo + gwFirstTrack);
TextOut(ps.hdc,
iNewPosition + rc.left,
0, szLabel,
(wTicNo + gwFirstTrack < 10) ? 1 : 2 );
/* Finish the end of the text string we just printed */
iOldPosition = iNewPosition +
((wTicNo + gwFirstTrack < 10)
? ptExtent.x / 2 : ptExtent.x);
}
}
} else {
#define ONE_HOUR (60ul*60ul*1000ul)
#define ONE_MINUTE (60ul*1000ul)
#define ONE_SECOND (1000ul)
/*
* The scale is set to display time - find out what units
* (msec, sec, min, or hour) are most appropriate, for the
* scale. This requires us to look at both the overall length
* of the medium and the distance between markers (or
* granularity).
*
*/
/*
* Find the maximum number of markers that we can draw without
* cluttering the display too badly, and find the granularity
* between these markers.
*
*/
SIZE Size;
GetTextExtentPoint32( ps.hdc, aszOneDigit, 1, &Size );
ptExtent.x = Size.cx;
ptExtent.y = Size.cy;
if (gdwMediaLength < 10)
iLargeMarkSize = 1;
else if (gdwMediaLength < 100)
iLargeMarkSize = 2;
else if (gdwMediaLength < 1000)
iLargeMarkSize = 3;
else if (gdwMediaLength < 10000)
iLargeMarkSize = 4;
else
iLargeMarkSize = 5;
wNumTics = (UINT)SendMessage(ghwndTrackbar, TBM_GETNUMTICS,
0, 0L);
/*
* TBM_GETNUMTICS returns the number of visible tics
* which includes the first and last tics not created
* by media player. Subtract 2 to account for the
* the first and last tics.
*
*/
if (wNumTics >= 2)
wNumTics = wNumTics - 2;
/* Where the text for the last mark will begin */
if (wNumTics > 1) {
iLastPos = (int)SendMessage(ghwndTrackbar,
TBM_GETTICPOS, (WPARAM)wNumTics - 1, 0L);
iLastPos -= ptExtent.x / 2; // centre 1st numeral
}
/* What scale do we use? Hours, minutes, or seconds? */
/* NOTE: THIS MUST AGREE WITH WHAT FormatTime() does */
/* in mplayer.c !!! */
if (gwCurScale == ID_FRAMES)
wScale = SCALE_FRAMES;
else {
if (gdwMediaLength > ONE_HOUR)
wScale = SCALE_HOURS;
else if (gdwMediaLength > ONE_MINUTE)
wScale = SCALE_MINUTES;
else
wScale = SCALE_SECONDS;
}
for (wTicNo = 0; wTicNo < wNumTics; wTicNo++) {
/* The text for the last tic is always drawn */
if (wTicNo == wNumTics - 1)
fForceTextDraw = TRUE;
dwMarkValue = (DWORD)SendMessage(ghwndTrackbar, TBM_GETTIC,
(WPARAM)wTicNo, 0L);
iNewPosition = (int)SendMessage(ghwndTrackbar, TBM_GETTICPOS,
(WPARAM)wTicNo, 0L);
/*
* Get the text ready for printing and centre it above the
* marker.
*
*/
switch ( wScale ) {
case SCALE_FRAMES:
case SCALE_MSEC:
wsprintf(szLabel, aszMSecFormat, dwMarkValue);
break;
case SCALE_HOURS:
wHour = (WORD)(dwMarkValue / 3600000);
wMin = (WORD)((dwMarkValue % 3600000) / 60000);
wsprintf(szLabel2,aszDecimalFormat,wMin);
wsprintf(szLabel,aszHourFormat,wHour, chTime);
lstrcat(szLabel,szLabel2);
break;
case SCALE_MINUTES :
wMin = (WORD)(dwMarkValue / 60000);
wSec = (WORD)((dwMarkValue % 60000) / 1000);
wsprintf(szLabel2,aszDecimalFormat,wSec);
wsprintf(szLabel,aszMinuteFormat,wMin,chTime);
lstrcat(szLabel,szLabel2);
break;
case SCALE_SECONDS :
wSec = (WORD)((dwMarkValue + 5) / 1000);
wMsec = (WORD)(((dwMarkValue + 5) % 1000) / 10);
wsprintf(szLabel2,aszDecimalFormat,wMsec);
if (!wSec && chLzero == TEXT('0'))
wsprintf(szLabel, aszSecondFormatNoLzero, chDecimal);
else
wsprintf(szLabel, aszSecondFormat, wSec, chDecimal);
lstrcat(szLabel,szLabel2);
break;
}
wTemp = STRLEN(szLabel);
iNewPosition -= ptExtent.x / 2; // centre 1st numeral
/* The position after which text will be cut off the */
/* right edge of the window */
iFit = rc.right - rc.left - (ptExtent.x * iLargeMarkSize);
/* Calculate the length of the text we just printed. */
/* Leave a little space at the end, too. */
iLen = (ptExtent.x * wTemp) + ptExtent.x / 2;
/* Display the mark if we can without overlapping either
* the previous mark or the final mark or going off the
* edge of the window. */
if (fForceTextDraw ||
(iNewPosition >= iOldPosition &&
iNewPosition <= iFit &&
iNewPosition + iLen <= iLastPos)) {
TextOut(ps.hdc, iNewPosition + rc.left, 0,
szLabel, wTemp );
/* Calculate the end pos of the text we just printed. */
iOldPosition = iNewPosition + iLen;
} else {
DPF("Didn't display mark: iNew = %d; iOld = %d; iFit = %d; iLen = %d, iLast = %d\n", iNewPosition, iOldPosition, iFit, iLen, iLastPos);
}
}
}
EndPaint(hwnd, &ps);
return 0L;
case WM_ERASEBKGND:
GetClientRect(hwnd, &rc);
hbr = (HBRUSH)SendMessage(ghwndApp, WM_CTLCOLORSTATIC,
wParam, (LONG_PTR)hwnd);
if (hbr != NULL)
FillRect((HDC)wParam, &rc, hbr);
return TRUE;
}
/* Let DefWindowProc() process all other window messages */
return DefWindowProc(hwnd, wMsg, wParam, lParam);
}
/* Gee thanks for the helpful spec for this routine! */
void FAR PASCAL CalcTicsOfDoom(void)
{
UINT wMarkNo;
int iTableIndex;
DWORD dwMarkValue,
dwNewPosition;
BOOL fDidLastMark = FALSE;
if (gfPlayOnly && !gfOle2IPEditing)
return;
DPF2("CalcTicsOfDoom\n");
SendMessage(ghwndTrackbar, TBM_CLEARTICS, (WPARAM)FALSE, 0L);
if (gwCurScale == ID_TRACKS) {
/*
* Based on the width of the child window, compute the positions
* to place the track marker tics.
*
*/
for (wMarkNo = 0; wMarkNo < gwNumTracks; wMarkNo++) {
/* If zero length, don't mark it, unless it is the end */
if ((wMarkNo < gwNumTracks - 1) &&
(gadwTrackStart[wMarkNo] == gadwTrackStart[wMarkNo + 1]))
continue;
/* Compute the centre point and place a marker there */
if (gdwMediaLength == 0)
dwNewPosition = 0;
else
dwNewPosition = gadwTrackStart[wMarkNo];
SendMessage(ghwndTrackbar,
TBM_SETTIC,
(WPARAM)FALSE,
(LPARAM)dwNewPosition);
}
} else {
/*
* The scale is set to display time - find out what units
* (msec, sec, min, or hour) are most appropriate, for the
* scale. This requires us to look at both the overall length
* of the medium and the distance between markers (or
* granularity).
*
*/
/*
* Find the maximum number of markers that we can draw without
* cluttering the display too badly, and find the granularity
* between these markers.
*
*/
UINT wNumTicks;
RECT rc;
if(!GetClientRect(ghwndMap, &rc)) {
DPF0("GetClientRect failed in CalcTicsOfDoom: Error %d\n", GetLastError());
}
wNumTicks = rc.right / 60;
if (0 == gdwMediaLength) {
iTableIndex = 0;
} else {
DPF4("Checking the scale for media length = %d, tick count = %d\n", gdwMediaLength, wNumTicks);
for (iTableIndex = (sizeof(aScale) / sizeof(SCALE)) -1;
(int)iTableIndex >= 0;
iTableIndex--) {
DPF4("Index %02d: %d\n", aScale[iTableIndex].dwInterval * wNumTicks);
if ((aScale[iTableIndex].dwInterval * wNumTicks)
<= gdwMediaLength)
break;
}
}
#ifdef DEBUG
if ((int)iTableIndex == -1) {
DPF("BAD TABLEINDEX\n");
DebugBreak();
}
#endif
// We have enough room to show every tick. Don't let our index wrap
// around, or we won't see ANY ticks which would look odd.
if (iTableIndex <0)
iTableIndex = 0;
dwMarkValue = gdwMediaStart;
do {
/* Compute the centre point and place a marker there */
if (gdwMediaLength == 0)
dwNewPosition = 0;
else
dwNewPosition = dwMarkValue; // HACK!! - gdwMediaStart;
SendMessage(ghwndTrackbar,
TBM_SETTIC,
(WPARAM)FALSE,
(LPARAM)dwNewPosition);
/* If this is the first mark, adjust so it's going
/* by the right interval. */
if (dwMarkValue == gdwMediaStart) {
dwMarkValue += aScale[iTableIndex].dwInterval
- (dwMarkValue % aScale[iTableIndex].dwInterval);
} else {
dwMarkValue += aScale[iTableIndex].dwInterval;
}
/* If we're almost done, do the final mark. */
if ((dwMarkValue >= (gdwMediaLength + gdwMediaStart))
&& !(fDidLastMark)) {
fDidLastMark = TRUE;
dwMarkValue = gdwMediaLength + gdwMediaStart;
}
} while (dwMarkValue <= gdwMediaStart + gdwMediaLength);
}
InvalidateRect(ghwndTrackbar, NULL, FALSE);
InvalidateRect(ghwndMap, NULL, TRUE);
}