|
|
/*-----------------------------------------------------------------------------+
| FRAMEBOX.C | | | | Code to handle the frame edit boxes for MPlayer. | | | | This code handles the edit box that goes between time, track & | | frame view. When a FrameBox is created we will create an | | Edit box and spin arrows for it. By checking the | | <gwCurScale> flag we will display text in either frame, track | | or in time mode. The displayed time mode will be HH:MM:SS.ss | | Track mode is TT HH:MM:SS or maybe TT MM:SS or something. | | GETTEXT will return a frame number in frame mode or a millisec | | value in time or track mode. | | | | (C) Copyright Microsoft Corporation 1991. All rights reserved. | | | | Revision History | | Oct-1992 MikeTri Ported to WIN32 / WIN16 common code | | | +-----------------------------------------------------------------------------*/
#include <windows.h>
#include <mmsystem.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "mplayer.h"
#include "framebox.h"
extern int gInc; // amount spin arrows inc/dec by
#define SPINARROWWIDTH 6 /* In dialog base units */
#define IDC_EDITBOX 5000
#define IDC_SPINARROW 5001
// extra fields in window instance data
#define GWI_EDITBOX (0 * sizeof(INT)) // edit box window handle
#define GWI_SPINARROWS (1 * sizeof(INT)) // spinarrow window handle
#define GWL_MAXFRAME (2 * sizeof(INT)) // max frame value
#define GWI_ALLOCATE (2 * sizeof(INT) + sizeof(LONG)) // number of BYTEs to allocate
#define GETEDITBOXWND(hwnd) (HWND)GetWindowLongPtr (hwnd, GWI_EDITBOX)
#define GETSPINARRWND(hwnd) (HWND)GetWindowLongPtr (hwnd, GWI_SPINARROWS)
#define SETEDITBOXWND(hwnd, hwndEdit) \
SETWINDOWUINT(hwnd, GWI_EDITBOX, hwndEdit) #define SETSPINARRWND(hwnd, hwndArr) \
SETWINDOWUINT(hwnd, GWI_SPINARROWS, hwndArr)
#define HILIGHTEDITBOX(hwnd) \
SendMessage(GETEDITBOXWND(hwnd), EM_SETSEL, (WPARAM)0, (LPARAM)(UINT)-1);
#define GETMAXFRAME(hwnd) (DWORD)GetWindowLongPtr(hwnd, GWL_MAXFRAME)
#define SETMAXFRAME(hwnd, l) SetWindowLongPtr(hwnd, GWL_MAXFRAME, (LONG_PTR)l)
// internal functions
LONG_PTR FAR PASCAL _EXPORT frameboxWndProc(HWND hwnd, unsigned wMsg, WPARAM wParam, LPARAM lParam);
LONG_PTR NEAR PASCAL frameboxiSetText(HWND hwnd, LPTSTR lpsz); LONG_PTR NEAR PASCAL frameboxiGetText(HWND hwnd, UINT_PTR wStrLen, LPTSTR lpsz); LONG_PTR NEAR PASCAL frameboxiArrowEdit(HWND hwnd, WPARAM wParam, LONG_PTR lParam);
// strings
TCHAR szFrameBoxClass[] = TEXT("aviframebox");
/*--------------------------------------------------------------+
| ******************** EXTERNAL FUNCTIONS ********************* | +--------------------------------------------------------------*/ /*--------------------------------------------------------------+
| frameboxInit() - initialize by registering our class. | | NOTE: Even if we return FALSE, nobody should | | care, because we don't register these classes| | at AppInit time, but on demand, so only the | | first call will succeed. Complain to Todd. | | (DM). | | | +--------------------------------------------------------------*/ BOOL FAR PASCAL frameboxInit(HANDLE hInst, HANDLE hPrev) { WNDCLASS cls;
if (1) { cls.hCursor = LoadCursor(NULL, IDC_ARROW); cls.hIcon = NULL; cls.lpszMenuName = NULL; cls.lpszClassName = szFrameBoxClass; cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); cls.hInstance = ghInst; cls.style = CS_HREDRAW | CS_VREDRAW; cls.lpfnWndProc = frameboxWndProc; cls.cbClsExtra = 0; cls.cbWndExtra = GWI_ALLOCATE; // room for stuff
if (!RegisterClass(&cls)) return FALSE;
if (!ArrowInit(hInst)) return FALSE; } return TRUE; }
/*--------------------------------------------------------------+
| frameboxSetText() - set the text for the window passed in | | <hwnd>. | | | +--------------------------------------------------------------*/ LONG_PTR FAR PASCAL frameboxSetText(HWND hwnd, LPTSTR lpsz) { LONG_PTR l; TCHAR achTimeString[20]; BOOL fFrameFormat = (gwCurScale == ID_FRAMES); UINT wCurScaleSave = gwCurScale;
if (fFrameFormat || *lpsz == TEXT('\0')){ /* we are in frame format - this is easy and all we need*/ /* to do is to return what is in the Edit box */ l = SendMessage(hwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)lpsz); } else { /* we are in time/track format - need to convert to a time string */ /* based on the msec value we have been passed in. */ DWORD_PTR dwmSecs;
/* get into local buffer */ lstrcpy((LPTSTR)achTimeString, (LPTSTR)lpsz); dwmSecs = (DWORD_PTR)ATOL(achTimeString);
/* It's meaningless to print track style numbers for the length of */ /* the selection, so use ordinary time mode. */ if (GetParent(hwnd) == GetDlgItem(GetParent(GetParent(hwnd)), IDC_EDITNUM)) gwCurScale = ID_TIME;
FormatTime(dwmSecs, (LPTSTR)achTimeString, NULL, FALSE); gwCurScale = wCurScaleSave;
/* send it to the control */ l = SendMessage(hwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPTSTR)achTimeString); } return l; }
/*--------------------------------------------------------------+
| *********************** WINDOW PROC ************************* | +--------------------------------------------------------------*/ /*--------------------------------------------------------------+
| frameboxWndProc - window process to handle the FrameBox | | | +--------------------------------------------------------------*/ LONG_PTR FAR PASCAL _EXPORT frameboxWndProc(HWND hwnd, unsigned wMsg, WPARAM wParam, LPARAM lParam) { HWND hwndNew; RECT rc; UINT wArrowWidth;
switch(wMsg){ case WM_CREATE: /* create the Edit box and the spin arrows for this */ /* FrameBox window. */ GetClientRect(hwnd, (LPRECT)&rc);
/* Calculate arrow width in pixels */ wArrowWidth = ((SPINARROWWIDTH * LOWORD(GetDialogBaseUnits())) / 4) - 1;
/* create the edit box */
hwndNew = CreateWindowEx(gfdwFlagsEx, TEXT("edit"), TEXT(""), WS_CHILD|WS_TABSTOP|ES_LEFT|WS_BORDER, 0, 0, rc.right - wArrowWidth, rc.bottom, hwnd, (HMENU)IDC_EDITBOX, GETHWNDINSTANCE(hwnd), 0L);
if (!hwndNew){ return 0L; } SETEDITBOXWND(hwnd, hwndNew);
/* limit this box to 15 chars of input */ SendMessage(hwndNew, EM_LIMITTEXT, (WPARAM)15, (LPARAM)0L); ShowWindow(hwndNew, SW_SHOW);
/* create the spin arrows */
hwndNew = CreateWindowEx(gfdwFlagsEx, TEXT("comarrow"), TEXT(""), WS_CHILD|WS_TABSTOP|WS_BORDER, rc.right - wArrowWidth, 0, wArrowWidth, rc.bottom, hwnd, (HMENU)IDC_SPINARROW, GETHWNDINSTANCE(hwnd), 0L);
if (!hwndNew){ return 0L; } SETSPINARRWND(hwnd, hwndNew); ShowWindow(hwndNew, SW_SHOW);
/* set the max to be the end of the media by default */ SETMAXFRAME(hwnd, (DWORD)(gdwMediaStart + gdwMediaLength)); break;
case WM_DESTROY: /* Delete the Edit box and the spin arrows */ DestroyWindow(GETEDITBOXWND(hwnd)); DestroyWindow(GETSPINARRWND(hwnd)); break;
case WM_SETFONT: return SendMessage(GETEDITBOXWND(hwnd), wMsg, wParam, lParam);
case WM_SETFOCUS: /* when we get the focus just send it on to the edit control */ SetFocus(GETEDITBOXWND(hwnd)); break;
case WM_SETTEXT: /* set the text which is a frame number or time in */ /* msec to be a frame or time mode string */ return frameboxiSetText(hwnd, (LPTSTR)lParam);
case WM_GETTEXT: /* get the text from the Edit box and translate to a */ /* frame number or time in msec. */ return frameboxiGetText(hwnd, wParam, (LPTSTR)lParam);
case WM_VSCROLL: /* handle the scrolling via spin arrows */ return frameboxiArrowEdit(hwnd, wParam, lParam);
case WM_COMMAND: switch (LOWORD(wParam) ){ case IDC_EDITBOX: // route editbox messages back to our parent
SendMessage(GetParent(hwnd), WM_COMMAND, GETWINDOWID(hwnd), lParam);
break; } break;
case EM_SETSEL: /* Perhaps we should only let this through if the caller
** is trying to select the entire contents of the edit box, ** because otherwise we'll have to map the range. */ SendMessage(GETEDITBOXWND(hwnd), wMsg, wParam, lParam); break;
#pragma message("Should we be supporting other EM_* messages?")
/* handle special case messages for the FrameBox control */ case FBOX_SETMAXFRAME: /* set the max frames to allow spin arrows to go */ SETMAXFRAME(hwnd, lParam); break;
default: return(DefWindowProc(hwnd, wMsg, wParam, lParam)); break;
} return (0L); }
/*--------------------------------------------------------------+
| ******************** INTERNAL FUNCTIONS ********************* | +--------------------------------------------------------------*/ /*--------------------------------------------------------------+
| frameboxiSetText() - handle setting the text depending on if | | we are in time or frame format. | | | +--------------------------------------------------------------*/ LONG_PTR NEAR PASCAL frameboxiSetText(HWND hwnd, LPTSTR lpsz) { LONG_PTR l;
/* We want to set the text even if it's identical because someone might */ /* have typed 03 06:00 and if track 3 if only 4 minutes long we want it */ /* to change to 04 02:00. Clever, eh? */ #if 0
TCHAR ach[12];
/* see if we are setting the same string as what is there */ /* and just don't do it if so to avoid flicker. */ l = frameboxiGetText(hwnd, CHAR_COUNT(ach), (LPTSTR)ach); if (lstrcmp((LPTSTR)ach, lpsz) == 0) goto HighLight; #endif
/* call generic function to handle this */ l = frameboxSetText(GETEDITBOXWND(hwnd), lpsz);
#if 0
HighLight: #endif
/* now let's highlight the whole thing */ HILIGHTEDITBOX(hwnd);
return l; }
#define IsCharNumeric( ch ) ( IsCharAlphaNumeric( ch ) && !IsCharAlpha( ch ) )
/*--------------------------------------------------------------+
| frameboxiGetText() - handle getting the text depending on if | | we are in time or frame format. Either | | returns a frame number or msec number | | depending on the mode. | | | +--------------------------------------------------------------*/ LONG_PTR NEAR PASCAL frameboxiGetText(HWND hwnd, UINT_PTR wStrLen, LPTSTR lpsz) { UINT wCurScaleSave = gwCurScale;
if (gwCurScale == ID_FRAMES) { LPTSTR p; LPTSTR pStart; UINT w;
/* we are in frame format - this is easy and all we need*/ /* to do is to return what is in the Edit box */ if (GetWindowText(GETEDITBOXWND(hwnd), lpsz, (int)wStrLen) == 0) goto LB_Error;
/* cut through leading white space */ for (pStart = lpsz; *pStart == TEXT(' ') || *pStart == TEXT('\t'); pStart++) ;
/* now rip out trailing white space */ if (*pStart) { // don't backtrack before beginning of string
for (p=pStart; *p; p++) ; for (--p; *p == TEXT(' ') || *p == TEXT('\t'); --p) ; *++p = TEXT('\0'); }
// make sure digits only were entered
for (p=pStart, w=0; *p; p++, w++) if (!IsCharNumeric(*p)) goto LB_Error;
// copy over only the part you need and return #chars
lstrcpy(lpsz, pStart); return w;
} else { /* we are in time or track format - we need to convert the time */ /* to msec. */ PTSTR pStart; // pointer to achTime buffer
TCHAR achTime[20]; // buffer for time string (input)
DWORD dwmSecs; // total mSecs for this thing */
TCHAR *pDelim; // pointer to next delimeter
TCHAR *p; // general pointer
DWORD dwTrack = 0; // track number
DWORD dwHours = 0; // # of hours
DWORD dwMins = 0; // # of minutes
DWORD dwSecs = 0; // # of seconds
DWORD wmsec = 0; // # hundredths
DWORD w;
/* It's meaningless to use track style numbers for the length of */ /* the selection, so use ordinary time mode. */ if (hwnd == GetDlgItem(GetParent(hwnd), IDC_EDITNUM)) gwCurScale = ID_TIME;
/* get the string from the edit box */ SendMessage(GETEDITBOXWND(hwnd), WM_GETTEXT, (WPARAM)CHAR_COUNT(achTime), (LPARAM)(LPTSTR) achTime);
if (achTime[0] == TEXT('\0')) goto LB_Error; // bad char so error out
/* go past any white space up front */ for (pStart = achTime; *pStart == TEXT(' ') || *pStart == TEXT('\t'); pStart++) ;
/* now rip out trailing white space */ if (*pStart) { // don't backtrack before beginning of string
for (p=pStart; *p; p++) ; for (--p; *p == TEXT(' ') || *p == TEXT('\t'); --p) ; *++p = TEXT('\0'); }
/* We're in track mode so peel the track number off the front */ if (gwCurScale == ID_TRACKS) {
/* First non-digit better be a space */ for (p = pStart; *p && *p != TEXT(' '); p++){ if (!IsCharNumeric(*p)) goto LB_Error; // bad char so error out
}
/* It is, so just grab the first numeric and use the rest of */ /* the string as the time. */ dwTrack = ATOI(pStart); if ((int)dwTrack < (int)gwFirstTrack || dwTrack >= gwFirstTrack + gwNumTracks) goto LB_Error;
/* Now bypass the spaces between track number and time */ pStart = p; while (*pStart == TEXT(' ')) pStart++;
/* There is nothing after the track number. Use it. */ if (*pStart == TEXT('\0')) goto MAKETOTAL;
}
/* rip through the whole string and look for illegal chars */ for (p = pStart; *p ; p++){ if (!IsCharNumeric(*p) && *p != chDecimal && *p != chTime) goto LB_Error; // bad char so error out
}
/*
* The reason for the slightly odd "if" statements of the form: * * if (pDelim) { * if (*pDelim){ * * is because strchr(...) returns an offset OR NULL. As this is then promptly * dereferenced to see what character (if any) is there we have a problem. * Win16 is allows this sort of thing, but Win32 * will generate an address exception post haste... * * Hence we try to do it properly. * */
/* go find the milliseconds portion if it exists */ pDelim = STRCHR(pStart, chDecimal); if (pDelim) { if (*pDelim){ p = STRRCHR(pStart, chDecimal); if (pDelim != p){ goto LB_Error; // string has > 1 '.', return error
} p++; // move up past delim
if (STRLEN(p) > 3) *(p+3) = TEXT('\0'); // knock off all but thousandths
wmsec = ATOI(p); // get the fractional part
if (STRLEN(p) == 1) // adjust to a millisecond value
wmsec *= 100; if (STRLEN(p) == 2) wmsec *= 10; *pDelim = TEXT('\0'); // null out this terminator
} }
/* try and find seconds */ pDelim = STRRCHR(pStart, chTime); // get last ':'
if (pDelim) { if (*pDelim) p = (pDelim+1); else p = pStart; dwSecs = ATOI(p);
if (*pDelim) *pDelim = TEXT('\0'); else goto MAKETOTAL; } else { p = pStart; dwSecs = ATOI(p);
goto MAKETOTAL; }
/* go and get the minutes part */ pDelim = STRRCHR(pStart, chTime); if (pDelim) { if (*pDelim) p = (pDelim + 1); else { p = pStart; dwMins = ATOI(p); } } else { p = pStart; dwMins = ATOI(p); }
if (pDelim) if (*pDelim) *pDelim = TEXT('\0'); else goto MAKETOTAL; else goto MAKETOTAL;
/* get the hours */ p = pStart; dwHours = ATOI(p);
MAKETOTAL: /* now we've got the hours, minutes, seconds and any */ /* fractional part. Time to build up the total time */
dwSecs += (dwHours * 3600); // add in hours worth of seconds
dwSecs += (dwMins * 60); // add in minutes worth of seconds
dwmSecs = (dwSecs * 1000L) + wmsec;
/* For track mode, this is an offset into a track, so add track start */ if (gwCurScale == ID_TRACKS) { dwmSecs += gadwTrackStart[dwTrack - 1]; }
/* build this into a string */ wsprintf(achTime, TEXT("%ld"), dwmSecs); w = STRLEN(achTime);
if (wCurScaleSave) gwCurScale = wCurScaleSave;
/* copy to user buffer and return */ lstrcpy(lpsz, achTime); return w;
LB_Error: gwCurScale = wCurScaleSave; return LB_ERR; } }
/*--------------------------------------------------------------+
| frameboxiArrowEdit() - handle the spin arrows for msec mode. | | | +--------------------------------------------------------------*/ LONG_PTR NEAR PASCAL frameboxiArrowEdit(HWND hwnd, WPARAM wParam, LONG_PTR lParam) { TCHAR achTime[20]; DWORD dwmSecs, dwStart, dwEnd;
if (hwnd == GetDlgItem(GetParent(hwnd), IDC_EDITNUM)) { dwStart = 0; dwEnd = gdwMediaLength; } else { dwStart = gdwMediaStart; dwEnd = GETMAXFRAME(hwnd); }
frameboxiGetText(hwnd, CHAR_COUNT(achTime), (LPTSTR)achTime); dwmSecs = ATOL(achTime); if (LOWORD(wParam) == SB_LINEUP){ if ((long)dwmSecs >= (long)dwStart - gInc && (long)dwmSecs < (long)dwEnd) { dwmSecs += gInc; wsprintf(achTime, TEXT("%ld"), dwmSecs); /* bring focus here NOW! so update works */ SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)GETEDITBOXWND(hwnd), (LPARAM)1L); frameboxSetText(GETEDITBOXWND(hwnd), (LPTSTR)achTime); /* now let's highlight the whole thing */
HILIGHTEDITBOX(hwnd);
} else MessageBeep(MB_ICONEXCLAMATION); } else if (LOWORD(wParam) == SB_LINEDOWN){ if ((long)dwmSecs > (long)dwStart && (long)dwmSecs <= (long)dwEnd + gInc) { if ((long)dwmSecs - gInc < (long)dwStart) dwmSecs = dwStart; else dwmSecs -= gInc; wsprintf(achTime, TEXT("%ld"), dwmSecs); /* bring focus here NOW! so update works */ SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)GETEDITBOXWND(hwnd), (LPARAM)1L); frameboxSetText(GETEDITBOXWND(hwnd), (LPTSTR)achTime); /* now let's highlight the whole thing */
HILIGHTEDITBOX(hwnd);
} else MessageBeep(MB_ICONEXCLAMATION); } // now update the world by sending the proper message
SendMessage(GetParent(hwnd), WM_COMMAND, (WPARAM)MAKELONG((WORD)GETWINDOWID(hwnd), EN_KILLFOCUS), (LPARAM)hwnd);
return dwmSecs; }
|