MAINWND.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:30k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*****************************************************************************
  2. *
  3. *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  4. *  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  5. *  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
  6. *  A PARTICULAR PURPOSE.
  7. *
  8. *  Copyright (C) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
  9. *
  10. ******************************************************************************
  11. *
  12. * MainWnd.C
  13. *
  14. * Message handlers and UI for the main window and associated controls
  15. *
  16. *****************************************************************************/
  17. #pragma warning(disable:4756)
  18. #define _INC_SHELLAPI
  19. #include <windows.h>
  20. #undef _INC_SHELLAPI
  21. #include <shellapi.h>
  22. #include <windowsx.h>
  23. #include <mmsystem.h>
  24. #include <commdlg.h>
  25. #include <commctrl.h>
  26. #include <ctype.h>
  27. #include "debug.h"
  28. #include "MIDIPlyr.H"
  29. #define BITMAP_COUNT    6           /* Number of buttons in bitmap */
  30. PRIVATE HWND            ghWndToolbar                    = NULL;
  31. PRIVATE HWND            ghWndStatus                     = NULL;
  32. PRIVATE HWND            ghWndTime                       = NULL;
  33. PRIVATE char            gszAppTitle[80]                 = "";
  34. PRIVATE int             gnSB_TFPaneSize                 = 0;
  35. PRIVATE char            gszOpenName[MAX_FILEPATH]       = "";
  36. PRIVATE char            gszOpenTitle[MAX_FILEPATH]      = "";
  37. PRIVATE char BCODE      gszFilter[]                      =
  38.     "MIDI File (*.MID;*.RMI)*.MID;*.RMI"
  39.     "All Files (*.*)*.*";
  40. PRIVATE char BCODE      gszDefExtension[]               = "MID";
  41. PRIVATE BOOL            gbAutoPlay                      = TRUE;
  42. PRIVATE UINT            guDevice                        = 0;
  43. PRIVATE TBBUTTON gatbButton[] =
  44. {
  45.     {0, -1,             TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0,  0, -1},
  46.     {0, IDM_OPEN,       TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0,  0, -1},
  47.     {0, -1,             TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0,  0, -1},
  48.     {2, IDM_PLAY,       0,               TBSTYLE_BUTTON, 0, 0,  0, -1},
  49.     {3, IDM_STOP,       0,               TBSTYLE_BUTTON, 0, 0,  0, -1},
  50.     {4, IDM_PAUSE,      0,               TBSTYLE_BUTTON, 0, 0,  0, -1},
  51. };
  52. #define BUTTON_COUNT (sizeof(gatbButton)/sizeof(gatbButton[0]))
  53. PRIVATE VOID FNLOCAL InitToolbar(HWND hWnd);
  54. PRIVATE VOID FNLOCAL InitStatusBar(HWND hWnd);
  55. PRIVATE VOID FNLOCAL ResizeStatusBar(HWND hWnd);
  56. PRIVATE VOID FNLOCAL SyncUI(HWND hWnd);
  57. PRIVATE VOID FNLOCAL SetOneAction(HWND hWnd, int nMenuID, BOOL fEnable);
  58. PRIVATE VOID FNLOCAL AttemptFileOpen(HWND hWnd);
  59. PRIVATE BOOL FNLOCAL PrerollAndWait(HWND hWnd);
  60. PRIVATE BOOL FNLOCAL MWnd_OnCreate(HWND hWnd, CREATESTRUCT FAR* lpCreateStruct);
  61. PRIVATE VOID FNLOCAL MWnd_OnGetMinMaxInfo(HWND hWnd, MINMAXINFO FAR* lpMinMaxInfo);
  62. PRIVATE VOID FNLOCAL MWnd_OnSize(HWND hWnd, UINT state, int cx, int cy);
  63. PRIVATE VOID FNLOCAL MWnd_OnPaint(HWND hWnd);
  64. PRIVATE VOID FNLOCAL MWnd_OnDropFiles(HWND hWnd, HDROP hDrop);
  65. PRIVATE VOID FNLOCAL MWnd_OnFileOpen(HWND hWnd);
  66. PRIVATE VOID FNLOCAL MWnd_OnCommandToggleChild(HWND hWnd, UINT id);
  67. PRIVATE VOID FNLOCAL MWnd_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify);
  68. PRIVATE VOID FNLOCAL MWnd_OnDestroy(HWND hWnd);
  69. /*****************************************************************************
  70. *
  71. * InitToolbar
  72. *
  73. * Called to create the toolbar
  74. *
  75. * HWND hWnd                 - Application window which toolbar is a child of
  76. *
  77. * Create and show the toolbar window.
  78. *
  79. *****************************************************************************/
  80. PRIVATE VOID FNLOCAL InitToolbar(
  81.     HWND                    hWnd)
  82. {
  83.     ghWndToolbar = CreateToolbarEx(hWnd,
  84.                                    WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
  85.                                    IDC_TOOLBAR,
  86.                                    BITMAP_COUNT,
  87.                                    ghInst,
  88.                                    IDB_TOOLBAR,
  89.                                    gatbButton,
  90.                                    BUTTON_COUNT,
  91.                                    0,  0,
  92.                                    0,  0,
  93.                                    sizeof(TBBUTTON));
  94.     if (ghWndToolbar)
  95.         ShowWindow(ghWndToolbar, SW_RESTORE);
  96. }
  97. /*****************************************************************************
  98. *
  99. * InitStatusBar
  100. *
  101. * Called to create the status bar
  102. *
  103. * HWND hWnd                 - Application window which status bar is a child of
  104. *
  105. * Create and show the status window.
  106. *
  107. *****************************************************************************/
  108. PRIVATE VOID FNLOCAL InitStatusBar(
  109.     HWND                    hWnd)
  110. {
  111.     HWND                    hWndDesktop;
  112.     HFONT                   hFontStat;
  113.     HDC                     hDC;
  114.     UINT                    idx;
  115.     SIZE                    size;
  116.     ghWndStatus = CreateStatusWindow(WS_CHILD|SBARS_SIZEGRIP,
  117.                                      "",
  118.                                      hWnd,
  119.                                      IDC_STATBAR);
  120.     if (ghWndStatus)
  121.     {
  122.         hWndDesktop = GetDesktopWindow();
  123.         hFontStat = (HFONT)SendMessage(ghWndStatus, WM_GETFONT, 0, 0L);
  124.         hDC = GetDC(hWndDesktop);
  125.         if (hFontStat != (HFONT)NULL && hDC != (HDC)NULL)
  126.         {
  127.             hFontStat = (HFONT)SelectObject(hDC, hFontStat);
  128.             gnSB_TFPaneSize = 0;
  129.             for (idx = 0; idx < N_TIME_FORMATS; idx++)
  130.             {
  131.                 GetTextExtentPoint(hDC,
  132.                                    grgszTimeFormats[idx],
  133.                                    lstrlen(grgszTimeFormats[idx]),
  134.                                    &size);
  135.                 gnSB_TFPaneSize = max(gnSB_TFPaneSize, size.cx);
  136.             }
  137.             SelectObject(hDC, hFontStat);
  138.             gnSB_TFPaneSize *= 2;
  139.         }
  140.         if (hDC != (HDC)NULL)
  141.             ReleaseDC(hWndDesktop, hDC);
  142.         ResizeStatusBar(hWnd);
  143.         
  144.         FORWARD_WM_COMMAND(hWnd, gnTimeFormat, 0, 0, SendMessage);
  145.         ShowWindow(ghWndStatus, SW_RESTORE);
  146.     }
  147. }
  148. /*****************************************************************************
  149. *
  150. * ResizeStatusBar
  151. *
  152. * Force the status bar to resize to fit in the main window
  153. *
  154. * HWND hWnd                 - Application window which status bar is a child of
  155. *
  156. * Figure out the pane sizes and send a message to the status bar to set them.
  157. *
  158. *****************************************************************************/
  159. PRIVATE VOID FNLOCAL ResizeStatusBar(
  160.     HWND                    hWnd)
  161. {
  162.     RECT                    rc;
  163.     int                     rnPaneEdge[SB_N_PANES];
  164.     GetClientRect(hWnd, &rc);
  165.     /* SB_SETPARTS expects:
  166.     **  wParam == Number of panes in status bar.
  167.     **  lParam == Pointer to an array of int's indicating the right-hand
  168.     **            coordinate of each pane.
  169.     */
  170.     rnPaneEdge[SB_PANE_STATE] = rc.right - gnSB_TFPaneSize;
  171.     rnPaneEdge[SB_PANE_TFMT]  = -1;
  172.     SendMessage(ghWndStatus,
  173.                 SB_SETPARTS,
  174.                 SB_N_PANES,
  175.                 (DWORD)(LPINT)(rnPaneEdge));
  176. }
  177. /*****************************************************************************
  178. *
  179. * SyncUI
  180. *
  181. * Bring all UI elements into sync with the state of the sequencer
  182. *
  183. * HWND hWnd                 - Application main window 
  184. *
  185. * Build a flag word of the actions which are allowed from the current state.
  186. * Set the menu items and toolbar buttons for each action appropriately.
  187. * Show the current state as a string in the status bar.
  188. * Depress the pause button if the sequencer is paused.
  189. * Cause the time window to update.
  190. *
  191. *****************************************************************************/
  192. #define SUI_F_CANPLAY       0x0001
  193. #define SUI_F_CANPAUSE      0x0002
  194. #define SUI_F_CANSTOP       0x0004
  195. #define SUI_F_CANSELDEVICE  0x0008
  196. PRIVATE VOID FNLOCAL SyncUI(
  197.     HWND                    hWnd)
  198. {
  199.     WORD                    wActionFlags;
  200.     UINT                    uState;
  201.     char                    szState[40];
  202.     BOOL                    fPress;
  203.     wActionFlags = 0;
  204.     uState = SEQ_S_NOFILE;
  205.     
  206.     if (gpSeq != NULL)
  207.     {
  208.         uState = gpSeq->uState;
  209.         switch (uState)
  210.         {
  211.         case SEQ_S_NOFILE:
  212.             wActionFlags = SUI_F_CANSELDEVICE;
  213.             break;
  214.         case SEQ_S_OPENED:
  215.         case SEQ_S_PREROLLED:
  216.             wActionFlags = SUI_F_CANPLAY|SUI_F_CANSELDEVICE;
  217.             break;
  218.         case SEQ_S_PAUSED:
  219.         case SEQ_S_PLAYING:
  220.             wActionFlags = SUI_F_CANPAUSE|SUI_F_CANSTOP;
  221.             break;
  222.         case SEQ_S_PREROLLING:
  223.         case SEQ_S_STOPPING:
  224. //            assert(0);
  225.             wActionFlags = 0;
  226.             break;
  227.         }
  228.     }
  229.     
  230.     fPress = (gpSeq->uState == SEQ_S_PAUSED);
  231.     SendMessage(ghWndToolbar,
  232.                 TB_PRESSBUTTON,
  233.                 IDM_PAUSE,
  234.                 fPress);
  235.     SetOneAction(hWnd, IDM_PLAY,   wActionFlags & SUI_F_CANPLAY);
  236.     SetOneAction(hWnd, IDM_PAUSE,  wActionFlags & SUI_F_CANPAUSE);
  237.     SetOneAction(hWnd, IDM_STOP,   wActionFlags & SUI_F_CANSTOP);
  238.     EnableMenuItem(GetMenu(hWnd),
  239.                    POS_PLAYTHRU,
  240.                    MF_BYPOSITION|((wActionFlags & SUI_F_CANSELDEVICE) ? MF_ENABLED : MF_DISABLED));
  241.     DrawMenuBar(hWnd);
  242.     szState[0] = '';
  243.     LoadString(ghInst, IDS_STATES + uState, szState, sizeof(szState));
  244.     SendMessage(ghWndStatus, SB_SETTEXT, SB_PANE_STATE, (LPARAM)(LPSTR)szState);
  245.     InvalidateRect(ghWndTime, NULL, TRUE);
  246. }
  247. /*****************************************************************************
  248. *
  249. * SetOneAction
  250. *
  251. * Update the state of one action in both the toolbar and action menu
  252. *
  253. * HWND hWnd                 - Application main window
  254. * int nMenuID               - Menu ID of action
  255. * BOOL fEnable              - Enable or disable this action
  256. *
  257. *****************************************************************************/
  258. PRIVATE VOID FNLOCAL SetOneAction(
  259.     HWND                hWnd,
  260.     int                 nMenuID,
  261.     BOOL                fEnable)
  262. {
  263.     EnableMenuItem(GetMenu(hWnd),
  264.                    nMenuID,
  265.                    MF_BYCOMMAND|(fEnable ? MF_ENABLED : MF_DISABLED));
  266.     SendMessage(ghWndToolbar,
  267.                 TB_ENABLEBUTTON,
  268.                 nMenuID,
  269.                 (DWORD)fEnable);
  270. }
  271. /*****************************************************************************
  272. *
  273. * AttemptFileOpen
  274. *
  275. * Try to open the given file in the sequencer.
  276. *
  277. * HWND hWnd                 - Application main window
  278. *
  279. * Stop and close the current file.
  280. * Open the new file.
  281. * Preroll the new file.
  282. * Set the title test for the main window.
  283. * Call SyncUI to update available actions.
  284. *
  285. *****************************************************************************/
  286. PRIVATE VOID FNLOCAL AttemptFileOpen(
  287.     HWND                    hWnd)
  288. {
  289.     MMRESULT                mmrc;
  290.     PSTR                    pStrFile    = gszUntitled;
  291.     
  292.     /* Stop, close, etc. if we're still playing
  293.     */
  294.     DPF(1, "AttemptFileOpen: Calling seqStop(); state = %u", gpSeq->uState);
  295.     
  296.     mmrc = seqStop(gpSeq);
  297. if (mmrc != MMSYSERR_NOERROR)
  298. {
  299. Error(hWnd, IDS_STOPFAILED, mmrc);
  300. return;
  301. }
  302.     DPF(1, "Calling seqCloseFile(); state = %u", gpSeq->uState);
  303.     seqCloseFile(gpSeq);
  304.     DPF(1, "Calling seqOpenFile(); state = %u", gpSeq->uState);
  305.     /* Open new file
  306.     */
  307.     gpSeq->pstrFile = gszOpenName;
  308.     mmrc = seqOpenFile(gpSeq);
  309.     if (mmrc != MMSYSERR_NOERROR)
  310.     {
  311.         Error(hWnd, IDS_OPENFAILED, mmrc);
  312.         return;
  313.     }
  314.     pStrFile = gszOpenTitle;
  315.     wsprintf(gszAppTitle, gszAppTitleMask, (LPSTR)pStrFile);
  316.     SetWindowText(hWnd, gszAppTitle);
  317.     SyncUI(hWnd);
  318. }
  319. /*****************************************************************************
  320. *
  321. * PrerollAndWait
  322. *
  323. * Prerolls the sequencer using the current device ID and file.
  324. *
  325. * HWND hWnd                 - Current window
  326. *
  327. * Just call preroll and loop processing messages until done.
  328. *
  329. *****************************************************************************/
  330. PRIVATE BOOL FNLOCAL PrerollAndWait(
  331.     HWND                    hWnd)
  332. {
  333.     PREROLL                 preroll;
  334.     MMRESULT                mmrc;
  335.     
  336.     preroll.tkBase = 0;
  337.     preroll.tkEnd  = gpSeq->tkLength;
  338.     gpSeq->uDeviceID = guDevice;
  339.     if (MMSYSERR_NOERROR != (mmrc = seqPreroll(gpSeq, &preroll)))
  340. {
  341.         Error(hWnd, IDS_PREROLLFAILED, mmrc);
  342.         return FALSE;
  343. }
  344. return TRUE;
  345. }
  346. /*****************************************************************************
  347. *
  348. * MWnd_OnCreate
  349. *
  350. * Handle WM_CREATE message to main application window.
  351. *
  352. * HWND hWnd                 - Window handle
  353. * CREATESTRUCT FAR* lpCreateStruct
  354. *                           - Pointer to creation parameters for the window.
  355. *
  356. * Returns TRUE on success. Returning FALSE will cause the window to be
  357. * destroyed and the application will exit.
  358. *
  359. * Set the default time format.
  360. * Create the tool and status bars.
  361. * Create the time window as a child of the main app window and show it.
  362. * Set the main window's title to show no document ('Untitled').
  363. * Accept drag/drop files.
  364. * Call SyncUI to update the enable status of the toolbar and menu items.
  365. *
  366. *****************************************************************************/
  367. PRIVATE BOOL FNLOCAL MWnd_OnCreate(
  368.     HWND                    hWnd,
  369.     CREATESTRUCT FAR*       lpCreateStruct)
  370. {
  371.     HMENU                   hMenu;
  372.     HMENU                   hMenuOptions;
  373.     HMENU                   hMenuPlayThru;
  374.     UINT                    cDevs;
  375.     UINT                    idx;
  376.     RECT                    rc;
  377.     MIDIOUTCAPS             moutCaps;
  378.     gnTimeFormat = IDS_TF_FIRST;
  379.     InitToolbar(hWnd);
  380.     InitStatusBar(hWnd);
  381.     
  382.     hMenu = GetMenu(hWnd);
  383.     hMenuOptions = GetSubMenu(hMenu, POS_OPTIONS);
  384.     hMenuPlayThru = GetSubMenu(hMenu, POS_PLAYTHRU);
  385.     AppendMenu(hMenuOptions, MF_SEPARATOR, 0, NULL);
  386.     
  387.     for (idx = 0; idx < N_TIME_FORMATS; idx++)
  388.     {
  389.         AppendMenu(hMenuOptions,
  390.                    MF_ENABLED|MF_STRING,
  391.                    IDS_TF_FIRST + idx,
  392.                    grgszTimeFormats[idx]);
  393.     }
  394.     cDevs = midiOutGetNumDevs();
  395.     if (cDevs)
  396.         AppendMenu(hMenuPlayThru, MF_SEPARATOR, 0, NULL);
  397.     
  398.     for (idx = 0; idx < cDevs; idx++)
  399.     {
  400.         if (midiOutGetDevCaps(idx, &moutCaps, sizeof(moutCaps)) == MMSYSERR_NOERROR)
  401.         {
  402.             AppendMenu(hMenuPlayThru,
  403.                        MF_ENABLED|MF_STRING,
  404.                        IDM_DEVICES + idx,
  405.                        moutCaps.szPname);
  406.         }
  407.     }
  408.     
  409.     CheckMenuItem(hMenu, IDM_TOOLBAR, MF_BYCOMMAND|MF_CHECKED);
  410.     CheckMenuItem(hMenu, IDM_STATUS,  MF_BYCOMMAND|MF_CHECKED);
  411.     CheckMenuItem(hMenu, IDM_AUTOPLAY,MF_BYCOMMAND|MF_CHECKED);
  412.     CheckMenuItem(hMenu, gnTimeFormat,MF_BYCOMMAND|MF_CHECKED);
  413.     CheckMenuItem(hMenu, IDM_DEVICES,  MF_BYCOMMAND|MF_CHECKED);  
  414.     GetClientRect(hWnd, &rc);
  415.     ghWndTime = CreateWindow(
  416.         gszTWndClass,
  417.         NULL,
  418.         WS_CHILD,
  419.         rc.left, rc.top,
  420.         rc.right-rc.left, rc.bottom-rc.top,
  421.         hWnd,
  422.         NULL,
  423.         lpCreateStruct->hInstance,
  424.         NULL);
  425.     ShowWindow(ghWndTime, SW_RESTORE);
  426.     wsprintf(gszAppTitle, gszAppTitleMask, (LPSTR)gszUntitled);
  427.     SetWindowText(hWnd, gszAppTitle);
  428.     DragAcceptFiles(hWnd, TRUE);
  429.     SyncUI(hWnd);
  430.     return TRUE;
  431. }
  432.                       
  433. /*****************************************************************************
  434. *
  435. * MWnd_OnGetMinMaxSize
  436. *
  437. * Handle WM_GETMINMAXSIZE message to main application window.
  438. *
  439. * HWND hWnd                 - Window handle
  440. * MINMAXINFO FAR* lpMinMaxInfo
  441. *                           - Pointer to min/max tracking information
  442. *
  443. * This message is sent to a window before resize tracking begins. The
  444. * lpMinMaxInfo structure contains the minimum and maximum x and y values
  445. * the window can be resized to.
  446. *
  447. * We don't allow resizing small enough to cause the status bar and toolbar
  448. * to overlap so they don't try to draw over each other. 
  449. *
  450. *****************************************************************************/
  451. PRIVATE VOID FNLOCAL MWnd_OnGetMinMaxInfo(
  452.     HWND                    hWnd,
  453.     MINMAXINFO FAR*         lpMinMaxInfo)
  454. {
  455.     RECT                    rc;
  456.     GetWindowRect(hWnd, &rc);
  457.     /* Only go small enough that our client area after children is zero.
  458.     */
  459.     lpMinMaxInfo->ptMinTrackSize.y =
  460.         (rc.bottom - rc.top) -
  461.         (grcTWnd.bottom - grcTWnd.top);                                      
  462. }
  463. /*****************************************************************************
  464. *
  465. * MWnd_OnSize
  466. *
  467. * Handle WM_SIZE message to main application window.
  468. *
  469. * HWND hWnd                 - Window handle
  470. * UINT state                - Some SIZE_xxx code indicating what type of
  471. *                             size operation this is.
  472. * int  cx, cy               - New x and y size of the window's client area.
  473. *
  474. * Get the new client area.
  475. * Adjust the client area for the toolbar and status bar if they exist.
  476. * Make sure the client area isn't a negative height and adjust if it is.
  477. * Resize the time window to fit in our new client area.
  478. * Forward the WM_SIZE to the time window so it can resize its font.
  479. *
  480. *****************************************************************************/
  481. PRIVATE VOID FNLOCAL MWnd_OnSize(
  482.     HWND                    hWnd,
  483.     UINT                    state,
  484.     int                     cx,
  485.     int                     cy)
  486. {
  487.     RECT                    rc;
  488.     RECT                    rcClient;
  489.     GetClientRect(hWnd, &rcClient);
  490.     if (ghWndToolbar != NULL)
  491.     {
  492.         /* Cause the toolbar to be aware of the size change
  493.         */
  494.         FORWARD_WM_SIZE(ghWndToolbar, SIZE_RESTORED, 0, 0, SendMessage);
  495.         
  496.         GetWindowRect(ghWndToolbar, &rc);
  497.         rcClient.top += (rc.bottom - rc.top);
  498.     }
  499.     if (ghWndStatus != NULL)
  500.     {
  501.         ResizeStatusBar(hWnd);
  502.         
  503.         /* Cause the status bar to be aware of the size change
  504.         */
  505.         FORWARD_WM_SIZE(ghWndStatus, SIZE_RESTORED, 0, 0, SendMessage);
  506.         
  507.         GetWindowRect(ghWndStatus, &rc);
  508.         rcClient.bottom -= (rc.bottom - rc.top);
  509.     }
  510.     /* Do we need to resize entire window so the tool/status bars
  511.     ** don't overlap? (The only case where this can happen is
  512.     ** on creation of one of the two -- we set minimum tracking so
  513.     ** a user can't manually resize the window to cause this
  514.     ** condition).
  515.     */
  516.     if (rcClient.bottom < rcClient.top)
  517.     {
  518.         GetWindowRect(hWnd, &rc);
  519.         SetWindowPos(hWnd,
  520.                      (HWND)NULL,
  521.                      0, 0,
  522.                      rc.right - rc.left + 1,
  523.                      rc.bottom - rc.top + 1 - rcClient.top - rcClient.bottom,
  524.                      SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
  525.     }
  526.     SetWindowPos(ghWndTime,
  527.                  (HWND)NULL,
  528.                  rcClient.left,
  529.                  rcClient.top,
  530.                  rcClient.right - rcClient.left,
  531.                  rcClient.bottom - rcClient.top,
  532.                  SWP_NOACTIVATE|SWP_NOZORDER);
  533.     FORWARD_WM_SIZE(ghWndTime, SIZE_RESTORED, 0, 0, SendMessage);
  534. }
  535. /*****************************************************************************
  536. *
  537. * MWnd_OnPaint
  538. *
  539. * Handle WM_PAINT message to main application window.
  540. *
  541. * HWND hWnd                 - Window handle
  542. *
  543. * Just do a BeginPaint/EndPaint pair so USER will mark the area
  544. *   as valid. All the real work of painting the time is done
  545. *   by the WM_PAINT handler for the time window.
  546. *
  547. *****************************************************************************/
  548. PRIVATE VOID FNLOCAL MWnd_OnPaint(
  549.     HWND                    hWnd)
  550. {
  551.     PAINTSTRUCT             ps;
  552.     HDC                     hDC;
  553.     hDC = BeginPaint(hWnd, &ps);
  554.     EndPaint(hWnd, &ps);
  555. }
  556. /*****************************************************************************
  557. *
  558. * MWnd_OnDropFiles
  559. *
  560. * Handle WM_DROPFILES message to main application window.
  561. *
  562. * HWND hWnd                 - Window handle
  563. * HDROP hDrop               - Handle to dropped file information
  564. *
  565. * Get the 0th filename and free the drop handle.
  566. * Extract the file title from the full pathname.
  567. * Open the file.
  568. * If we opened successfully, start playback by forwarding a WM_COMMAND
  569. *   of IDM_PLAY to the main window.
  570. *
  571. *****************************************************************************/
  572. PRIVATE VOID FNLOCAL MWnd_OnDropFiles(
  573.     HWND                    hWnd,
  574.     HDROP                   hDrop)
  575. {
  576.     PSTR                    pStr;
  577.     
  578.     /* For multiple selections, we only accept the first file
  579.     */
  580.     DragQueryFile(hDrop, 0, gszOpenName, sizeof(gszOpenName));
  581.     DragFinish(hDrop);
  582.     /* We don't get OpenTitle like we do from GetOpenFileName; need to
  583.     ** figure this out for ourselves
  584.     */
  585.     pStr = gszOpenName + lstrlen(gszOpenName) - 1;
  586.     while (pStr >= gszOpenName && *pStr != '/' && *pStr != '\' && *pStr != ':')
  587.         pStr--;
  588.     pStr++;
  589.     lstrcpy(gszOpenTitle, pStr);
  590.     AttemptFileOpen(hWnd);
  591.     if (gbAutoPlay && gpSeq->uState == SEQ_S_OPENED)
  592.         FORWARD_WM_COMMAND(hWnd, IDM_PLAY, (HWND)NULL, 0, SendMessage);
  593. }
  594. /*****************************************************************************
  595. *
  596. * MWnd_OnFileOpen
  597. *
  598. * Handle WM_COMMAND/IDM_OPEN message to main application window.
  599. *
  600. * HWND hWnd                 - Window handle
  601. *
  602. * Fill in the OPENFILENAME struct and call GetOpenFileName.
  603. * If not canceled, try to open the file.
  604. *
  605. *****************************************************************************/
  606. PRIVATE VOID FNLOCAL MWnd_OnFileOpen(
  607.     HWND                    hWnd)
  608. {
  609.     OPENFILENAME            ofn;
  610.     *gszOpenName = '';
  611.     
  612. ofn.lStructSize = sizeof(OPENFILENAME);
  613. ofn.hwndOwner = hWnd;
  614. ofn.lpstrFilter = gszFilter;
  615. ofn.lpstrCustomFilter = (LPSTR)NULL;
  616. ofn.nMaxCustFilter = 0L;
  617. ofn.nFilterIndex = 1L;
  618. ofn.lpstrFile = gszOpenName;
  619. ofn.nMaxFile = MAX_FILEPATH;
  620. ofn.lpstrFileTitle = gszOpenTitle;
  621. ofn.nMaxFileTitle = MAX_FILEPATH;
  622. ofn.lpstrTitle = (LPSTR)NULL;
  623. ofn.lpstrInitialDir = (LPSTR)NULL;
  624. ofn.Flags = OFN_HIDEREADONLY|OFN_FILEMUSTEXIST;
  625. ofn.nFileOffset = 0;
  626. ofn.nFileExtension = 0;
  627. ofn.lpstrDefExt = gszDefExtension;
  628.     if (!GetOpenFileName(&ofn))
  629.         return;
  630.     AttemptFileOpen(hWnd);
  631. }
  632. /*****************************************************************************
  633. *
  634. * MWnd_OnCommandToggleChild
  635. *
  636. * Handle WM_COMMAND message of toggle tool or status bar to main application
  637. * window.
  638. *
  639. * HWND hWnd                 - Window handle
  640. * UINT id                   - Control id of menu selection; either
  641. *                             IDM_TOOLBAR or IDM_STATUS
  642. *
  643. * Get the current menu item check state.
  644. * Destroy or create the child as needed.
  645. * Send a WM_SIZE to the main window so client area will be recalculated.
  646. * Toggle the menu item check state.
  647. *
  648. *****************************************************************************/
  649. PRIVATE VOID FNLOCAL MWnd_OnCommandToggleChild(
  650.     HWND                    hWnd,                                      
  651.     UINT                    id)
  652. {
  653.     HMENU                   hMenu;
  654.     UINT                    uState;
  655.     HWND*                   phWnd;
  656.     
  657.     phWnd = (id == IDM_TOOLBAR) ? &ghWndToolbar : &ghWndStatus;
  658.     hMenu = GetMenu(hWnd);
  659.     uState = GetMenuState(hMenu, id, MF_BYCOMMAND);
  660.     if (uState & MF_CHECKED)
  661.     {
  662.         DestroyWindow(*phWnd);
  663.         *phWnd = NULL;
  664.     }
  665.     else
  666.     {
  667.         if (id == IDM_TOOLBAR)
  668.             InitToolbar(hWnd);
  669.         else
  670.             InitStatusBar(hWnd);
  671.     }
  672.     SendMessage(hWnd, WM_SIZE, 0, 0L);
  673.     uState ^= MF_CHECKED;
  674.     uState &= MF_CHECKED;
  675.     CheckMenuItem(hMenu, id, MF_BYCOMMAND|uState);
  676.     SyncUI(hWnd);
  677. }
  678.                                           
  679.                             
  680. /*****************************************************************************
  681. *
  682. * MWnd_OnCommand
  683. *
  684. * Handle WM_COMMAND message to main application window.
  685. *
  686. * HWND hWnd                 - Window handle
  687. * int id                    - id of control or menu causing WM_COMMAND
  688. * HWND hwndCtl              - Window handle of child control, if any
  689. * UINT codeNotify           - Notification code if this message is from a
  690. *                             control.
  691. *
  692. * For a press of the toolbar buttons or their menu equivalents, just load
  693. * a resource string and display it in the status bar.
  694. *
  695. * For an exit request, send ourselves a WM_CLOSE message.
  696. *
  697. *****************************************************************************/
  698. PRIVATE VOID FNLOCAL MWnd_OnCommand(
  699.     HWND                    hWnd,
  700.     int                     id,
  701.     HWND                    hWndCtl,
  702.     UINT                    codeNotify)
  703. {
  704.     HMENU                   hMenu;
  705.     int                     nIdxFormat;
  706.     LPSTR                   lpstr;
  707.     
  708.     if (id >= IDS_TF_FIRST && id <= IDS_TF_LAST)
  709.     {
  710.         if (NULL != ghWndStatus)
  711.         {
  712.             nIdxFormat = id - IDS_TF_FIRST;
  713.             lpstr = (LPSTR)(grgszTimeFormats[nIdxFormat]);
  714.             
  715.             SendMessage(ghWndStatus,
  716.                         SB_SETTEXT,
  717.                         SB_PANE_TFMT,
  718.                         (LPARAM)lpstr);
  719.         }
  720.         hMenu = GetMenu(hWnd);
  721.         CheckMenuItem(hMenu, gnTimeFormat, MF_UNCHECKED|MF_BYCOMMAND);
  722.         CheckMenuItem(hMenu, id, MF_CHECKED|MF_BYCOMMAND);
  723.         gnTimeFormat = id;
  724.         
  725.         /* Force time window to update font and repaint entire time string
  726.          */
  727.         
  728.         if(ghWndTime) // for when WM_COMMAND is called before WM_CREATE
  729.          FORWARD_WM_SIZE(ghWndTime, SIZE_RESTORED, 0, 0, SendMessage);
  730.     }
  731.     else if (id >= IDM_DEVMIN && id <= IDM_DEVMAX)
  732.     {
  733.         hMenu = GetMenu(hWnd);
  734.                 
  735.         CheckMenuItem(hMenu, guDevice + IDM_DEVICES, MF_UNCHECKED|MF_BYCOMMAND);
  736.         guDevice = id - IDM_DEVICES;
  737.         CheckMenuItem(hMenu, guDevice + IDM_DEVICES, MF_CHECKED|MF_BYCOMMAND);
  738.     }
  739.     else switch(id)
  740.     {
  741.         case IDM_OPEN:
  742.             MWnd_OnFileOpen(hWnd);
  743.             break;
  744.         
  745.         case IDM_TOOLBAR:
  746.         case IDM_STATUS:
  747.             MWnd_OnCommandToggleChild(hWnd, id);
  748.             break;
  749.         case IDM_AUTOPLAY:
  750.             gbAutoPlay = !gbAutoPlay;
  751.             CheckMenuItem(GetMenu(hWnd),
  752.                           IDM_AUTOPLAY,
  753.                           MF_BYCOMMAND|(gbAutoPlay ? MF_CHECKED : MF_UNCHECKED));
  754.             break;
  755.         case IDM_PLAY:
  756.             FORWARD_WM_COMMAND(ghWndTime, IDM_PLAY, 0, 0, SendMessage);
  757.         
  758. if (gpSeq->uState != SEQ_S_OPENED)
  759. DPF(1, "IDM_PLAY: State %u", gpSeq->uState);
  760.              
  761.             if (PrerollAndWait(hWnd))                   
  762.              seqStart(gpSeq);
  763.             SyncUI(hWnd);
  764.             break;
  765.         case IDM_STOP:
  766.             FORWARD_WM_COMMAND(ghWndTime, IDM_STOP, 0, 0, SendMessage);
  767.             seqStop(gpSeq);
  768.             SyncUI(hWnd);
  769.             break;
  770.         case IDM_PAUSE:
  771.             if (gpSeq->uState == SEQ_S_PAUSED)
  772.             {
  773.                 seqRestart(gpSeq);
  774.             }
  775.             else
  776.             {
  777.                 seqPause(gpSeq);
  778.             }
  779.             SyncUI(hWnd);
  780.             break;
  781.         case IDM_SYNCUI:
  782.             SyncUI(hWnd);
  783.             break;
  784.             
  785.         case IDM_EXIT:
  786.             SendMessage(hWnd, WM_CLOSE, 0, 0L);
  787.             break;
  788.     }
  789. }
  790.                                    
  791. /*****************************************************************************
  792. *
  793. * MWnd_OnDestroy
  794. *
  795. * Handle WM_DESTROY message to main application window.
  796. *
  797. * HWND hWnd                 - Window handle
  798. *
  799. * Our main application window has been closed. PostQuitMessage so the main
  800. * message loop will exit and the app can terminate.
  801. *
  802. *****************************************************************************/
  803. PRIVATE VOID FNLOCAL MWnd_OnDestroy(
  804.     HWND                    hWnd)
  805. {
  806.     seqStop(gpSeq);
  807.     PostQuitMessage(0);
  808. }
  809. /*****************************************************************************
  810. *
  811. * MWnd_WndProc
  812. *
  813. * Window procedure for main application window.
  814. *
  815. * HWND hWnd                 - Window handle
  816. * UINT msg                  - Message code
  817. * WPARAM wParam             - Message specific parameter
  818. * LPARAM lParam             - Message specific parameter
  819. *
  820. * Dispatch messages we care about to the appropriate handler, else just
  821. * call DefWindowProc.
  822. *
  823. * Note this use of message cracker macros from windowsx.h. Using these
  824. * macros will shield you from the differences between Win16 and Win32;
  825. * if your app is cross-compilable, you should use these and save yourself
  826. * some headaches!
  827. *
  828. *****************************************************************************/
  829. LRESULT CALLBACK MWnd_WndProc(
  830.     HWND                    hWnd,
  831.     UINT                    msg,
  832.     WPARAM                  wParam,
  833.     LPARAM                  lParam)
  834. {
  835.     switch( msg )
  836.     {
  837.         HANDLE_MSG(hWnd, WM_CREATE,         MWnd_OnCreate);
  838.         HANDLE_MSG(hWnd, WM_GETMINMAXINFO,  MWnd_OnGetMinMaxInfo);
  839.         HANDLE_MSG(hWnd, WM_SIZE,           MWnd_OnSize);
  840.         HANDLE_MSG(hWnd, WM_PAINT,          MWnd_OnPaint);
  841.         HANDLE_MSG(hWnd, WM_DROPFILES,      MWnd_OnDropFiles);
  842.         HANDLE_MSG(hWnd, WM_COMMAND,        MWnd_OnCommand);
  843.         HANDLE_MSG(hWnd, WM_DESTROY,        MWnd_OnDestroy);
  844.         case MMSG_DONE:
  845.             FORWARD_WM_COMMAND(ghWndTime, IDM_STOP, 0, 0, SendMessage);
  846.             
  847. if (gpSeq->uState != SEQ_S_OPENED)
  848. DPF(1, "MMSG_DONE and state %u", gpSeq->uState);
  849.             SyncUI(hWnd);
  850.             break;
  851.         default:
  852.             return DefWindowProc(hWnd, msg, wParam, lParam);
  853.     }
  854.     return 0;
  855. }