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.

627 lines
23 KiB

  1. /*-----------------------------------------------------------------------------+
  2. | FRAMEBOX.C |
  3. | |
  4. | Code to handle the frame edit boxes for MPlayer. |
  5. | |
  6. | This code handles the edit box that goes between time, track & |
  7. | frame view. When a FrameBox is created we will create an |
  8. | Edit box and spin arrows for it. By checking the |
  9. | <gwCurScale> flag we will display text in either frame, track |
  10. | or in time mode. The displayed time mode will be HH:MM:SS.ss |
  11. | Track mode is TT HH:MM:SS or maybe TT MM:SS or something. |
  12. | GETTEXT will return a frame number in frame mode or a millisec |
  13. | value in time or track mode. |
  14. | |
  15. | (C) Copyright Microsoft Corporation 1991. All rights reserved. |
  16. | |
  17. | Revision History |
  18. | Oct-1992 MikeTri Ported to WIN32 / WIN16 common code |
  19. | |
  20. +-----------------------------------------------------------------------------*/
  21. #include <windows.h>
  22. #include <mmsystem.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include "mplayer.h"
  27. #include "framebox.h"
  28. extern int gInc; // amount spin arrows inc/dec by
  29. #define SPINARROWWIDTH 6 /* In dialog base units */
  30. #define IDC_EDITBOX 5000
  31. #define IDC_SPINARROW 5001
  32. // extra fields in window instance data
  33. #define GWI_EDITBOX (0 * sizeof(INT)) // edit box window handle
  34. #define GWI_SPINARROWS (1 * sizeof(INT)) // spinarrow window handle
  35. #define GWL_MAXFRAME (2 * sizeof(INT)) // max frame value
  36. #define GWI_ALLOCATE (2 * sizeof(INT) + sizeof(LONG)) // number of BYTEs to allocate
  37. #define GETEDITBOXWND(hwnd) (HWND)GetWindowLongPtr (hwnd, GWI_EDITBOX)
  38. #define GETSPINARRWND(hwnd) (HWND)GetWindowLongPtr (hwnd, GWI_SPINARROWS)
  39. #define SETEDITBOXWND(hwnd, hwndEdit) \
  40. SETWINDOWUINT(hwnd, GWI_EDITBOX, hwndEdit)
  41. #define SETSPINARRWND(hwnd, hwndArr) \
  42. SETWINDOWUINT(hwnd, GWI_SPINARROWS, hwndArr)
  43. #define HILIGHTEDITBOX(hwnd) \
  44. SendMessage(GETEDITBOXWND(hwnd), EM_SETSEL, (WPARAM)0, (LPARAM)(UINT)-1);
  45. #define GETMAXFRAME(hwnd) (DWORD)GetWindowLongPtr(hwnd, GWL_MAXFRAME)
  46. #define SETMAXFRAME(hwnd, l) SetWindowLongPtr(hwnd, GWL_MAXFRAME, (LONG_PTR)l)
  47. // internal functions
  48. LONG_PTR FAR PASCAL _EXPORT frameboxWndProc(HWND hwnd, unsigned wMsg, WPARAM wParam, LPARAM lParam);
  49. LONG_PTR NEAR PASCAL frameboxiSetText(HWND hwnd, LPTSTR lpsz);
  50. LONG_PTR NEAR PASCAL frameboxiGetText(HWND hwnd, UINT_PTR wStrLen, LPTSTR lpsz);
  51. LONG_PTR NEAR PASCAL frameboxiArrowEdit(HWND hwnd, WPARAM wParam, LONG_PTR lParam);
  52. // strings
  53. TCHAR szFrameBoxClass[] = TEXT("aviframebox");
  54. /*--------------------------------------------------------------+
  55. | ******************** EXTERNAL FUNCTIONS ********************* |
  56. +--------------------------------------------------------------*/
  57. /*--------------------------------------------------------------+
  58. | frameboxInit() - initialize by registering our class. |
  59. | NOTE: Even if we return FALSE, nobody should |
  60. | care, because we don't register these classes|
  61. | at AppInit time, but on demand, so only the |
  62. | first call will succeed. Complain to Todd. |
  63. | (DM). |
  64. | |
  65. +--------------------------------------------------------------*/
  66. BOOL FAR PASCAL frameboxInit(HANDLE hInst, HANDLE hPrev)
  67. {
  68. WNDCLASS cls;
  69. if (1) {
  70. cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  71. cls.hIcon = NULL;
  72. cls.lpszMenuName = NULL;
  73. cls.lpszClassName = szFrameBoxClass;
  74. cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  75. cls.hInstance = ghInst;
  76. cls.style = CS_HREDRAW | CS_VREDRAW;
  77. cls.lpfnWndProc = frameboxWndProc;
  78. cls.cbClsExtra = 0;
  79. cls.cbWndExtra = GWI_ALLOCATE; // room for stuff
  80. if (!RegisterClass(&cls))
  81. return FALSE;
  82. if (!ArrowInit(hInst))
  83. return FALSE;
  84. }
  85. return TRUE;
  86. }
  87. /*--------------------------------------------------------------+
  88. | frameboxSetText() - set the text for the window passed in |
  89. | <hwnd>. |
  90. | |
  91. +--------------------------------------------------------------*/
  92. LONG_PTR FAR PASCAL frameboxSetText(HWND hwnd, LPTSTR lpsz)
  93. {
  94. LONG_PTR l;
  95. TCHAR achTimeString[20];
  96. BOOL fFrameFormat = (gwCurScale == ID_FRAMES);
  97. UINT wCurScaleSave = gwCurScale;
  98. if (fFrameFormat || *lpsz == TEXT('\0')){
  99. /* we are in frame format - this is easy and all we need*/
  100. /* to do is to return what is in the Edit box */
  101. l = SendMessage(hwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)lpsz);
  102. } else {
  103. /* we are in time/track format - need to convert to a time string */
  104. /* based on the msec value we have been passed in. */
  105. DWORD_PTR dwmSecs;
  106. /* get into local buffer */
  107. lstrcpy((LPTSTR)achTimeString, (LPTSTR)lpsz);
  108. dwmSecs = (DWORD_PTR)ATOL(achTimeString);
  109. /* It's meaningless to print track style numbers for the length of */
  110. /* the selection, so use ordinary time mode. */
  111. if (GetParent(hwnd) ==
  112. GetDlgItem(GetParent(GetParent(hwnd)), IDC_EDITNUM))
  113. gwCurScale = ID_TIME;
  114. FormatTime(dwmSecs, (LPTSTR)achTimeString, NULL, FALSE);
  115. gwCurScale = wCurScaleSave;
  116. /* send it to the control */
  117. l = SendMessage(hwnd,
  118. WM_SETTEXT,
  119. (WPARAM)0,
  120. (LPARAM)(LPTSTR)achTimeString);
  121. }
  122. return l;
  123. }
  124. /*--------------------------------------------------------------+
  125. | *********************** WINDOW PROC ************************* |
  126. +--------------------------------------------------------------*/
  127. /*--------------------------------------------------------------+
  128. | frameboxWndProc - window process to handle the FrameBox |
  129. | |
  130. +--------------------------------------------------------------*/
  131. LONG_PTR FAR PASCAL _EXPORT frameboxWndProc(HWND hwnd, unsigned wMsg,
  132. WPARAM wParam, LPARAM lParam)
  133. {
  134. HWND hwndNew;
  135. RECT rc;
  136. UINT wArrowWidth;
  137. switch(wMsg){
  138. case WM_CREATE:
  139. /* create the Edit box and the spin arrows for this */
  140. /* FrameBox window. */
  141. GetClientRect(hwnd, (LPRECT)&rc);
  142. /* Calculate arrow width in pixels */
  143. wArrowWidth = ((SPINARROWWIDTH * LOWORD(GetDialogBaseUnits()))
  144. / 4) - 1;
  145. /* create the edit box */
  146. hwndNew = CreateWindowEx(gfdwFlagsEx,
  147. TEXT("edit"),
  148. TEXT(""),
  149. WS_CHILD|WS_TABSTOP|ES_LEFT|WS_BORDER,
  150. 0,
  151. 0,
  152. rc.right - wArrowWidth,
  153. rc.bottom,
  154. hwnd,
  155. (HMENU)IDC_EDITBOX,
  156. GETHWNDINSTANCE(hwnd),
  157. 0L);
  158. if (!hwndNew){
  159. return 0L;
  160. }
  161. SETEDITBOXWND(hwnd, hwndNew);
  162. /* limit this box to 15 chars of input */
  163. SendMessage(hwndNew, EM_LIMITTEXT, (WPARAM)15, (LPARAM)0L);
  164. ShowWindow(hwndNew, SW_SHOW);
  165. /* create the spin arrows */
  166. hwndNew = CreateWindowEx(gfdwFlagsEx,
  167. TEXT("comarrow"),
  168. TEXT(""),
  169. WS_CHILD|WS_TABSTOP|WS_BORDER,
  170. rc.right - wArrowWidth,
  171. 0,
  172. wArrowWidth,
  173. rc.bottom,
  174. hwnd,
  175. (HMENU)IDC_SPINARROW,
  176. GETHWNDINSTANCE(hwnd),
  177. 0L);
  178. if (!hwndNew){
  179. return 0L;
  180. }
  181. SETSPINARRWND(hwnd, hwndNew);
  182. ShowWindow(hwndNew, SW_SHOW);
  183. /* set the max to be the end of the media by default */
  184. SETMAXFRAME(hwnd, (DWORD)(gdwMediaStart + gdwMediaLength));
  185. break;
  186. case WM_DESTROY:
  187. /* Delete the Edit box and the spin arrows */
  188. DestroyWindow(GETEDITBOXWND(hwnd));
  189. DestroyWindow(GETSPINARRWND(hwnd));
  190. break;
  191. case WM_SETFONT:
  192. return SendMessage(GETEDITBOXWND(hwnd), wMsg, wParam, lParam);
  193. case WM_SETFOCUS:
  194. /* when we get the focus just send it on to the edit control */
  195. SetFocus(GETEDITBOXWND(hwnd));
  196. break;
  197. case WM_SETTEXT:
  198. /* set the text which is a frame number or time in */
  199. /* msec to be a frame or time mode string */
  200. return frameboxiSetText(hwnd, (LPTSTR)lParam);
  201. case WM_GETTEXT:
  202. /* get the text from the Edit box and translate to a */
  203. /* frame number or time in msec. */
  204. return frameboxiGetText(hwnd, wParam, (LPTSTR)lParam);
  205. case WM_VSCROLL:
  206. /* handle the scrolling via spin arrows */
  207. return frameboxiArrowEdit(hwnd, wParam, lParam);
  208. case WM_COMMAND:
  209. switch (LOWORD(wParam) ){
  210. case IDC_EDITBOX:
  211. // route editbox messages back to our parent
  212. SendMessage(GetParent(hwnd),
  213. WM_COMMAND,
  214. GETWINDOWID(hwnd),
  215. lParam);
  216. break;
  217. }
  218. break;
  219. case EM_SETSEL:
  220. /* Perhaps we should only let this through if the caller
  221. ** is trying to select the entire contents of the edit box,
  222. ** because otherwise we'll have to map the range.
  223. */
  224. SendMessage(GETEDITBOXWND(hwnd), wMsg, wParam, lParam);
  225. break;
  226. #pragma message("Should we be supporting other EM_* messages?")
  227. /* handle special case messages for the FrameBox control */
  228. case FBOX_SETMAXFRAME:
  229. /* set the max frames to allow spin arrows to go */
  230. SETMAXFRAME(hwnd, lParam);
  231. break;
  232. default:
  233. return(DefWindowProc(hwnd, wMsg, wParam, lParam));
  234. break;
  235. }
  236. return (0L);
  237. }
  238. /*--------------------------------------------------------------+
  239. | ******************** INTERNAL FUNCTIONS ********************* |
  240. +--------------------------------------------------------------*/
  241. /*--------------------------------------------------------------+
  242. | frameboxiSetText() - handle setting the text depending on if |
  243. | we are in time or frame format. |
  244. | |
  245. +--------------------------------------------------------------*/
  246. LONG_PTR NEAR PASCAL frameboxiSetText(HWND hwnd, LPTSTR lpsz)
  247. {
  248. LONG_PTR l;
  249. /* We want to set the text even if it's identical because someone might */
  250. /* have typed 03 06:00 and if track 3 if only 4 minutes long we want it */
  251. /* to change to 04 02:00. Clever, eh? */
  252. #if 0
  253. TCHAR ach[12];
  254. /* see if we are setting the same string as what is there */
  255. /* and just don't do it if so to avoid flicker. */
  256. l = frameboxiGetText(hwnd, CHAR_COUNT(ach), (LPTSTR)ach);
  257. if (lstrcmp((LPTSTR)ach, lpsz) == 0)
  258. goto HighLight;
  259. #endif
  260. /* call generic function to handle this */
  261. l = frameboxSetText(GETEDITBOXWND(hwnd), lpsz);
  262. #if 0
  263. HighLight:
  264. #endif
  265. /* now let's highlight the whole thing */
  266. HILIGHTEDITBOX(hwnd);
  267. return l;
  268. }
  269. #define IsCharNumeric( ch ) ( IsCharAlphaNumeric( ch ) && !IsCharAlpha( ch ) )
  270. /*--------------------------------------------------------------+
  271. | frameboxiGetText() - handle getting the text depending on if |
  272. | we are in time or frame format. Either |
  273. | returns a frame number or msec number |
  274. | depending on the mode. |
  275. | |
  276. +--------------------------------------------------------------*/
  277. LONG_PTR NEAR PASCAL frameboxiGetText(HWND hwnd, UINT_PTR wStrLen, LPTSTR lpsz)
  278. {
  279. UINT wCurScaleSave = gwCurScale;
  280. if (gwCurScale == ID_FRAMES) {
  281. LPTSTR p;
  282. LPTSTR pStart;
  283. UINT w;
  284. /* we are in frame format - this is easy and all we need*/
  285. /* to do is to return what is in the Edit box */
  286. if (GetWindowText(GETEDITBOXWND(hwnd), lpsz, (int)wStrLen) == 0)
  287. goto LB_Error;
  288. /* cut through leading white space */
  289. for (pStart = lpsz; *pStart == TEXT(' ') || *pStart == TEXT('\t'); pStart++)
  290. ;
  291. /* now rip out trailing white space */
  292. if (*pStart) { // don't backtrack before beginning of string
  293. for (p=pStart; *p; p++)
  294. ;
  295. for (--p; *p == TEXT(' ') || *p == TEXT('\t'); --p)
  296. ;
  297. *++p = TEXT('\0');
  298. }
  299. // make sure digits only were entered
  300. for (p=pStart, w=0; *p; p++, w++)
  301. if (!IsCharNumeric(*p))
  302. goto LB_Error;
  303. // copy over only the part you need and return #chars
  304. lstrcpy(lpsz, pStart);
  305. return w;
  306. } else {
  307. /* we are in time or track format - we need to convert the time */
  308. /* to msec. */
  309. PTSTR pStart; // pointer to achTime buffer
  310. TCHAR achTime[20]; // buffer for time string (input)
  311. DWORD dwmSecs; // total mSecs for this thing */
  312. TCHAR *pDelim; // pointer to next delimeter
  313. TCHAR *p; // general pointer
  314. DWORD dwTrack = 0; // track number
  315. DWORD dwHours = 0; // # of hours
  316. DWORD dwMins = 0; // # of minutes
  317. DWORD dwSecs = 0; // # of seconds
  318. DWORD wmsec = 0; // # hundredths
  319. DWORD w;
  320. /* It's meaningless to use track style numbers for the length of */
  321. /* the selection, so use ordinary time mode. */
  322. if (hwnd == GetDlgItem(GetParent(hwnd), IDC_EDITNUM))
  323. gwCurScale = ID_TIME;
  324. /* get the string from the edit box */
  325. SendMessage(GETEDITBOXWND(hwnd),
  326. WM_GETTEXT,
  327. (WPARAM)CHAR_COUNT(achTime),
  328. (LPARAM)(LPTSTR) achTime);
  329. if (achTime[0] == TEXT('\0'))
  330. goto LB_Error; // bad char so error out
  331. /* go past any white space up front */
  332. for (pStart = achTime; *pStart == TEXT(' ') || *pStart == TEXT('\t'); pStart++)
  333. ;
  334. /* now rip out trailing white space */
  335. if (*pStart) { // don't backtrack before beginning of string
  336. for (p=pStart; *p; p++)
  337. ;
  338. for (--p; *p == TEXT(' ') || *p == TEXT('\t'); --p)
  339. ;
  340. *++p = TEXT('\0');
  341. }
  342. /* We're in track mode so peel the track number off the front */
  343. if (gwCurScale == ID_TRACKS) {
  344. /* First non-digit better be a space */
  345. for (p = pStart; *p && *p != TEXT(' '); p++){
  346. if (!IsCharNumeric(*p))
  347. goto LB_Error; // bad char so error out
  348. }
  349. /* It is, so just grab the first numeric and use the rest of */
  350. /* the string as the time. */
  351. dwTrack = ATOI(pStart);
  352. if ((int)dwTrack < (int)gwFirstTrack || dwTrack >= gwFirstTrack +
  353. gwNumTracks)
  354. goto LB_Error;
  355. /* Now bypass the spaces between track number and time */
  356. pStart = p;
  357. while (*pStart == TEXT(' '))
  358. pStart++;
  359. /* There is nothing after the track number. Use it. */
  360. if (*pStart == TEXT('\0'))
  361. goto MAKETOTAL;
  362. }
  363. /* rip through the whole string and look for illegal chars */
  364. for (p = pStart; *p ; p++){
  365. if (!IsCharNumeric(*p) && *p != chDecimal && *p != chTime)
  366. goto LB_Error; // bad char so error out
  367. }
  368. /*
  369. * The reason for the slightly odd "if" statements of the form:
  370. *
  371. * if (pDelim) {
  372. * if (*pDelim){
  373. *
  374. * is because strchr(...) returns an offset OR NULL. As this is then promptly
  375. * dereferenced to see what character (if any) is there we have a problem.
  376. * Win16 is allows this sort of thing, but Win32
  377. * will generate an address exception post haste...
  378. *
  379. * Hence we try to do it properly.
  380. *
  381. */
  382. /* go find the milliseconds portion if it exists */
  383. pDelim = STRCHR(pStart, chDecimal);
  384. if (pDelim) {
  385. if (*pDelim){
  386. p = STRRCHR(pStart, chDecimal);
  387. if (pDelim != p){
  388. goto LB_Error; // string has > 1 '.', return error
  389. }
  390. p++; // move up past delim
  391. if (STRLEN(p) > 3)
  392. *(p+3) = TEXT('\0'); // knock off all but thousandths
  393. wmsec = ATOI(p); // get the fractional part
  394. if (STRLEN(p) == 1) // adjust to a millisecond value
  395. wmsec *= 100;
  396. if (STRLEN(p) == 2)
  397. wmsec *= 10;
  398. *pDelim = TEXT('\0'); // null out this terminator
  399. }
  400. }
  401. /* try and find seconds */
  402. pDelim = STRRCHR(pStart, chTime); // get last ':'
  403. if (pDelim) {
  404. if (*pDelim)
  405. p = (pDelim+1);
  406. else
  407. p = pStart;
  408. dwSecs = ATOI(p);
  409. if (*pDelim)
  410. *pDelim = TEXT('\0');
  411. else
  412. goto MAKETOTAL;
  413. } else {
  414. p = pStart;
  415. dwSecs = ATOI(p);
  416. goto MAKETOTAL;
  417. }
  418. /* go and get the minutes part */
  419. pDelim = STRRCHR(pStart, chTime);
  420. if (pDelim) {
  421. if (*pDelim)
  422. p = (pDelim + 1);
  423. else {
  424. p = pStart;
  425. dwMins = ATOI(p);
  426. }
  427. } else {
  428. p = pStart;
  429. dwMins = ATOI(p);
  430. }
  431. if (pDelim)
  432. if (*pDelim)
  433. *pDelim = TEXT('\0');
  434. else
  435. goto MAKETOTAL;
  436. else
  437. goto MAKETOTAL;
  438. /* get the hours */
  439. p = pStart;
  440. dwHours = ATOI(p);
  441. MAKETOTAL:
  442. /* now we've got the hours, minutes, seconds and any */
  443. /* fractional part. Time to build up the total time */
  444. dwSecs += (dwHours * 3600); // add in hours worth of seconds
  445. dwSecs += (dwMins * 60); // add in minutes worth of seconds
  446. dwmSecs = (dwSecs * 1000L) + wmsec;
  447. /* For track mode, this is an offset into a track, so add track start */
  448. if (gwCurScale == ID_TRACKS) {
  449. dwmSecs += gadwTrackStart[dwTrack - 1];
  450. }
  451. /* build this into a string */
  452. wsprintf(achTime, TEXT("%ld"), dwmSecs);
  453. w = STRLEN(achTime);
  454. if (wCurScaleSave)
  455. gwCurScale = wCurScaleSave;
  456. /* copy to user buffer and return */
  457. lstrcpy(lpsz, achTime);
  458. return w;
  459. LB_Error:
  460. gwCurScale = wCurScaleSave;
  461. return LB_ERR;
  462. }
  463. }
  464. /*--------------------------------------------------------------+
  465. | frameboxiArrowEdit() - handle the spin arrows for msec mode. |
  466. | |
  467. +--------------------------------------------------------------*/
  468. LONG_PTR NEAR PASCAL frameboxiArrowEdit(HWND hwnd, WPARAM wParam, LONG_PTR lParam)
  469. {
  470. TCHAR achTime[20];
  471. DWORD dwmSecs, dwStart, dwEnd;
  472. if (hwnd == GetDlgItem(GetParent(hwnd), IDC_EDITNUM)) {
  473. dwStart = 0;
  474. dwEnd = gdwMediaLength;
  475. } else {
  476. dwStart = gdwMediaStart;
  477. dwEnd = GETMAXFRAME(hwnd);
  478. }
  479. frameboxiGetText(hwnd, CHAR_COUNT(achTime), (LPTSTR)achTime);
  480. dwmSecs = ATOL(achTime);
  481. if (LOWORD(wParam) == SB_LINEUP){
  482. if ((long)dwmSecs >= (long)dwStart - gInc &&
  483. (long)dwmSecs < (long)dwEnd) {
  484. dwmSecs += gInc;
  485. wsprintf(achTime, TEXT("%ld"), dwmSecs);
  486. /* bring focus here NOW! so update works */
  487. SendMessage(hwnd,
  488. WM_NEXTDLGCTL,
  489. (WPARAM)GETEDITBOXWND(hwnd),
  490. (LPARAM)1L);
  491. frameboxSetText(GETEDITBOXWND(hwnd), (LPTSTR)achTime);
  492. /* now let's highlight the whole thing */
  493. HILIGHTEDITBOX(hwnd);
  494. } else
  495. MessageBeep(MB_ICONEXCLAMATION);
  496. } else if (LOWORD(wParam) == SB_LINEDOWN){
  497. if ((long)dwmSecs > (long)dwStart &&
  498. (long)dwmSecs <= (long)dwEnd + gInc) {
  499. if ((long)dwmSecs - gInc < (long)dwStart)
  500. dwmSecs = dwStart;
  501. else
  502. dwmSecs -= gInc;
  503. wsprintf(achTime, TEXT("%ld"), dwmSecs);
  504. /* bring focus here NOW! so update works */
  505. SendMessage(hwnd,
  506. WM_NEXTDLGCTL,
  507. (WPARAM)GETEDITBOXWND(hwnd),
  508. (LPARAM)1L);
  509. frameboxSetText(GETEDITBOXWND(hwnd), (LPTSTR)achTime);
  510. /* now let's highlight the whole thing */
  511. HILIGHTEDITBOX(hwnd);
  512. } else
  513. MessageBeep(MB_ICONEXCLAMATION);
  514. }
  515. // now update the world by sending the proper message
  516. SendMessage(GetParent(hwnd),
  517. WM_COMMAND,
  518. (WPARAM)MAKELONG((WORD)GETWINDOWID(hwnd), EN_KILLFOCUS),
  519. (LPARAM)hwnd);
  520. return dwmSecs;
  521. }
  522.