home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Abalone 1.4.2 / src / DoEvent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-21  |  15.4 KB  |  746 lines  |  [TEXT/MPS ]

  1. #define DO_EVENT_C
  2. #include "DoEvent.h"
  3. #undef DO_EVENT_C
  4.  
  5.  
  6. #if defined(__MWERKS__)
  7. #pragma segment __%Main
  8. #else
  9. #pragma segment Main
  10. #endif
  11.    
  12.  
  13. void
  14. DoEndOfGame (short winner)
  15. {
  16.     Str32 empty = "\p";
  17.     ParamText (GetPlayerName (& gSet, winner), empty, empty, empty);
  18.     
  19.     CurrentCursor (arrowCursor);
  20.     switch (Alert (202, nil))
  21.     {
  22.         case 1:
  23.             InitGame();
  24.         break;
  25.         case 2:
  26.             DoMenuCommand ((EDIT_MENU << 16) + EDIT_UNDO);
  27.         break;
  28.         case 3:
  29.             Terminate();
  30.         break;
  31.     }
  32. }
  33.  
  34.  
  35.  
  36. void
  37. DoEvent (EventRecord *event)
  38. {
  39.     short        part;
  40.     WindowPtr    window;
  41.     char        key;
  42.  
  43.     switch (event->what)
  44.     {
  45.         case mouseDown:
  46.             part = FindWindow (event->where, &window);
  47.             switch (part)
  48.             {
  49.                 case inMenuBar:                //    process a mouse menu command (if any)
  50.                     AdjustMenus();
  51.                     DoMenuCommand (MenuSelect (event->where));
  52.                     AdjustMenus();
  53.                 break;
  54.                 case inSysWindow:            //    let the system handle the mouseDown
  55.                     SystemClick (event, window);
  56.                 break;
  57.                 case inContent:
  58.                     if (window != FrontWindow())
  59.                         SelectWindow (window);
  60.                     else
  61.                         DoContentClick (window, event);
  62.                 break;
  63.                 case inDrag:                //    pass screenBits.bounds to get all gDevices
  64.                     DragWindow (window, event->where, &qd.screenBits.bounds);
  65.                 break;
  66.                 case inGrow:                //    sorry, not all screen sizes are possible.
  67.                 break;
  68.                 case inGoAway:
  69.                     if (TrackGoAway (window, event->where))
  70.                         DoMenuCommand ((FILE_MENU << 16) + FILE_QUIT);
  71.                 break;
  72.                 case inZoomIn:
  73.                 case inZoomOut:
  74.                     if (TrackBox (window, event->where, part))
  75.                     {
  76.                         WStateData *state = *((WStateData **)((WindowPeek) window)->dataHandle);
  77.                         
  78.                     //    Since the hor/ver ratio is fixed, only some window sizes look good.
  79.                     //    Currently, only two window sizes are possible,
  80.                     //    so zooming in or out is alway toggling between two modes.
  81.                     //    the new sizes are computed first.
  82.                         
  83.                         if (gSet.FieldWidth < kHorLarge)    //    now small, so make big
  84.                         {
  85.                             gSet.FieldWidth  = kHorLarge;
  86.                             gSet.FieldHeight = kVerLarge;
  87.                             
  88.                             state->userState.right  = state->userState.left + kHorTotal;
  89.                             state->userState.bottom = state->userState.top  + kVerTotal;
  90.                         }
  91.                         else                        //    now big, so make small
  92.                         {
  93.                             gSet.FieldWidth  = kHorSmall;
  94.                             gSet.FieldHeight = kVerSmall;
  95.  
  96.                             state->stdState.right  = state->stdState.left + kHorTotal;
  97.                             state->stdState.bottom = state->stdState.top  + kVerTotal;
  98.                         }
  99.  
  100.                     //    Normally, ZoomWindow would be called now,
  101.                     //    but in this case SizeWindow suffices.
  102.  
  103.                         SizeWindow (window, kHorTotal, kVerTotal, true);
  104.                         SizeItems (window);
  105.  
  106.                         InvalBoard();
  107.                     }
  108.                 break;
  109.             }
  110.         break;
  111.         case keyDown:
  112.         case autoKey:
  113.         //    Check for menu key equivalents.
  114.             key = event->message & charCodeMask;
  115.             if (event->modifiers & cmdKey)    //    Command key down
  116.                 if (event->what == keyDown)
  117.                 {
  118.                     AdjustMenus();
  119.                     DoMenuCommand (MenuKey(key));
  120.                     AdjustMenus();
  121.                 }
  122.         break;
  123.         case activateEvt:
  124.             DoActivate ((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
  125.         break;
  126.         case updateEvt:
  127.             DoUpdate((WindowPtr) event->message);
  128.         break;
  129.         case kOSEvent:
  130.             switch (event->message >> 24)    //    high byte of message
  131.             {
  132.                 case kSuspendResumeMessage:    //    suspend/resume is also an activate/deactivate
  133.                     
  134.                     gInBackground = (event->message & kResumeMask) == 0;
  135.                     DoActivate (FrontWindow(), (event->message & kResumeMask) != 0);
  136.                 break;
  137.                 case mouseMovedMessage:
  138.                     AdjustCursor (& event->where);
  139.                 break;
  140.             }
  141.         break;
  142.         case kHighLevelEvent:
  143.             DoHighLevelEvent (event);
  144.         break;
  145.     }
  146. }
  147.  
  148.  
  149.  
  150. void
  151. DoUpdate (WindowPtr window)
  152. {
  153.     if (IsAppWindow (window) && window == gAbaloneWindow)
  154.         UpdateBoard (window);
  155. }
  156.  
  157.  
  158.  
  159. void
  160. DoActivate (WindowPtr window, Boolean becomingActive)
  161. {
  162.     static short    oldPixSize;
  163.     short            curPixSize = PixelSize();
  164.     
  165.     if (IsAppWindow (window))
  166.     {
  167.         if (becomingActive)
  168.         {
  169.             gBlackAndWhite = ! ColorQDAvailable() || curPixSize == 1;
  170.             
  171.             RestoreColors();
  172.                     
  173.             if (curPixSize != oldPixSize && ColorQDAvailable())
  174.             {
  175.                 Inval3D();
  176.                 AdjustMenus();
  177.             }
  178.             InvalBoard();
  179.         }
  180.         else
  181.         {
  182.             if (ColorQDAvailable())
  183.                 oldPixSize = curPixSize;
  184.                 
  185.             SndDisposeChannels ();
  186.         }
  187.     }
  188. }
  189.  
  190.  
  191.  
  192. void
  193. DoContentClick (WindowPtr window, EventRecord * event)
  194. {
  195. #if ! defined (__SC__) && ! defined(__MWERKS__)
  196. #pragma unused (window)
  197. #endif
  198.  
  199.     Point where = event->where;
  200.         
  201.     GlobalToLocal (& where);
  202.  
  203.     if (event->modifiers & shiftKey)
  204.         DoFieldShiftClick (LocToField (where.h, where.v));
  205.     else
  206.         DoFieldClick (LocToField (where.h, where.v));
  207. }
  208.  
  209.  
  210.  
  211. void
  212. DoAbout (short menu, short item)
  213. {
  214. //    These define the current number of help items in the respective menus
  215.  
  216.     #define        kAbaloneItems    3
  217.     #define        kProgramItems    7
  218.  
  219.     DialogPtr    aboutDialog = GetNewDialog (ABOUT_ABALONE_MENU - (gSet.FieldHeight==SMALL_HEIGHT ? 1 : 0), 0, (WindowPtr) -1);
  220.     Handle        moreItems;
  221.     short        origNumItems = CountDITL (aboutDialog);
  222.     short        newNumItems;
  223.     short         itemHit;
  224.     
  225.     CurrentCursor (arrowCursor);
  226.     
  227.     do {
  228.     //    Append a DITL containing a PICT depending on chosen menu and item.
  229.     //    The DITL is inserted relative to the first item.
  230.     
  231.         moreItems = GetResource ('DITL', ABOUT_ABALONE_MENU + (menu == ABOUT_ABALONE_MENU ? 0 : 10) + item);
  232.         AppendDITL (aboutDialog, moreItems, -1);
  233.         ReleaseResource (moreItems);
  234.         newNumItems = CountDITL (aboutDialog);    
  235.         ShowWindow (aboutDialog);
  236.     
  237.         do {
  238.             ModalDialog (0, & itemHit);
  239.         } while (! itemHit);
  240.  
  241.     //    Remove the appended items again:
  242.     //    either a different screen (different PICT) is wanted, or we quit.
  243.             
  244.         ShortenDITL (aboutDialog, newNumItems - origNumItems);    //    back origNumItems again
  245.  
  246.     //    Find out what menu/item to do now (or quit).
  247.         
  248.         switch (itemHit)
  249.         {
  250.             case 3:    //    prior item
  251.                 if (item == 1)    //    wrap if no prior item
  252.                 {
  253.                     if (menu == ABOUT_ABALONE_MENU)
  254.                     {
  255.                         menu += 10;
  256.                         item = kProgramItems;
  257.                     }
  258.                     else
  259.                     {
  260.                         menu -= 10;
  261.                         item = kAbaloneItems;
  262.                     }
  263.                 }
  264.                 else
  265.                 {
  266.                     item--;
  267.                 }
  268.             break;
  269.             case 4:    //    next iten
  270.                 if (item == kAbaloneItems && menu == ABOUT_ABALONE_MENU)    //    wrap if no next item
  271.                 {
  272.                     menu += 10;
  273.                     item =1;
  274.                 }
  275.                 else if (item == kProgramItems && menu == ABOUT_PROGRAM_MENU)
  276.                 {
  277.                     menu -= 10;
  278.                     item = 1;
  279.                 }
  280.                 else
  281.                 {
  282.                     item++;
  283.                 }
  284.             break;
  285.             case 2:
  286.                 DisposDialog (aboutDialog);
  287.         }
  288.     } while (itemHit != 2);
  289. }
  290.  
  291.  
  292.  
  293. void
  294. DoMenuCommand (long menuResult)
  295. {
  296.     short        menuID = HiWord (menuResult);    
  297.     short        menuItem = LoWord (menuResult);    
  298.  
  299.     switch (menuID)
  300.     {
  301.         case APPLE_MENU:
  302.         
  303.             switch (menuItem)
  304.             {
  305.                 case APPLE_ABOUT:
  306.                     ;
  307.                 break;
  308.                 default:
  309.                 {
  310.                     Str255        daName;
  311.                     short        daRefNum;
  312.                     
  313.                     GetItem (GetMHandle (APPLE_MENU), menuItem, daName);
  314.                     daRefNum = OpenDeskAcc (daName);
  315.                 }
  316.                 break;
  317.             }
  318.         break;
  319.                 
  320.         case ABOUT_ABALONE_MENU:
  321.         case ABOUT_PROGRAM_MENU:
  322.         {
  323.             DoAbout (menuID, menuItem);
  324.         }
  325.         break;
  326.                 
  327.         case FILE_MENU:
  328.         
  329.             gInterrupted |= (menuItem == FILE_NEW || menuItem == FILE_OPEN || menuItem == FILE_QUIT);
  330.             
  331.             switch (menuItem)
  332.             {
  333.                 case FILE_NEW:
  334.                     ConfirmAndSaveAndMaybeThen (& InitGame);
  335.                 break;
  336.  
  337.                 case FILE_QUIT:
  338.                     ConfirmAndSaveAndMaybeThen (& Terminate);
  339.                 break;
  340.                 
  341.                 case FILE_OPEN:
  342.                     ConfirmAndSaveAndMaybeThen (& OpenGame);
  343.                 break;
  344.                 
  345.                 case FILE_SAVE:
  346.                     SaveGame();
  347.                 break;
  348.                 
  349.                 case FILE_SAVE_AS:
  350.                     SaveGameAs();
  351.                 break;
  352.             }
  353.         break;
  354.         
  355.         case EDIT_MENU:
  356.         
  357.             if (SystemEdit (menuItem-1))
  358.                 break;
  359.             
  360.             switch (menuItem)
  361.             {
  362.                 case EDIT_UNDO:
  363.                     UndoLastMove();
  364.                 break;
  365.                 
  366.                 default:
  367.                 break;
  368.             }            
  369.         break;
  370.         
  371.         case SETTINGS_MENU:
  372.             switch (menuItem)
  373.             {
  374.                 default:
  375.                     DoSettingsMenu (menuItem);
  376.                 break;
  377.                 
  378.                 case SETTINGS_2_PLAYERS:
  379.                 case SETTINGS_3_PLAYERS:
  380.                 {
  381.                     short    players = menuItem - SETTINGS_2_PLAYERS + 2;
  382.                     if (gFileSaved)
  383.                     {
  384.                         gTheGame.Players = players;
  385.                         gSet.Players = players;
  386.                         Inval3D();    // number of players changes, so the palette must too
  387.                         InitGame();
  388.                     }
  389.                     else switch (AskSave())
  390.                     {
  391.                         case save:    // save first and fall through
  392.                             DoMenuCommand ((FILE_MENU << 16) + FILE_SAVE);
  393.                         case dont_save:
  394.                             gTheGame.Players = players;
  395.                             gSet.Players = players;
  396.                             Inval3D();    // number of players changes, so the palette must too
  397.                             InitGame();
  398.                         break;
  399.                         default:
  400.                             ;
  401.                     }
  402.                 break;
  403.                 }
  404.             }
  405.  
  406.         break;
  407.         
  408.         case OPTION_MENU:
  409.         
  410.             switch (menuItem)
  411.             {
  412.                 
  413.                 case OPTION_SOUND:
  414.                     gSet.SoundOn = ! gSet.SoundOn;
  415.                 break;
  416.                 
  417.                 case OPTION_3D_BALLS:
  418.                     gSet.Balls3D = ! gSet.Balls3D;
  419.                     Inval3D();    // palette must be allocated or disposed
  420.                     InvalBoard();
  421.                 break;
  422.                                 
  423.                 case OPTION_NOTATION:
  424.                     gSet.ShowNotation = ! gSet.ShowNotation;
  425.                     InvalItems (gAbaloneWindow);
  426.                 break;
  427.             }
  428.         break;
  429.         
  430.         case COLOR_MENU:
  431.             DoColorMenu (menuItem);
  432.         break;
  433.         
  434.         case BACKGROUND_MENU:
  435.             DoBackgroundMenu (menuItem);
  436.         break;
  437.  
  438.         #ifdef NETDEBUG        
  439.         case NETTEST_MENU:
  440.             DoNetTestMenu (menuItem);
  441.         break;
  442.         #endif
  443.     }
  444.     HiliteMenu(0);
  445. }
  446.  
  447.  
  448.  
  449. void
  450. DoColorMenu (short colorItem)
  451. {
  452.     RGBColor    selectColor;
  453.     Point        loc = {-1, -1}; // this centers the dialog automagically
  454.     
  455.     if (! ColorQDAvailable())
  456.         return;
  457.     
  458.     switch (colorItem)
  459.     {
  460.         case COLOR_WHITE:
  461.         case COLOR_BLACK:
  462.         case COLOR_GREEN:
  463.  
  464.             if    (GetColor    (    loc,
  465.                                 "\pSelect a color for this player",
  466.                                 & gSet.Color[colorItem],
  467.                                 & selectColor
  468.                             )
  469.                 )
  470.                 gSet.Color[colorItem] = selectColor;
  471.         break;
  472.         case COLOR_BACKGROUND:
  473.         
  474.             if    (GetColor    (    loc,
  475.                                 "\pSelect a background color",
  476.                                 & gSet.Color[0],
  477.                                 & selectColor
  478.                             )
  479.                 )
  480.             {
  481.                 gSet.Color[0] = selectColor;
  482.                 RGBBackColor (& gSet.Color[0]);
  483.                 PutSettings();    // to update the dctb
  484.             }
  485.         break;
  486.     }
  487.     Inval3D();    // Palette must be recomputed if a color has changed
  488.     InvalBoard();
  489. }
  490.  
  491.  
  492.  
  493. void
  494. DoBackgroundMenu (short item)
  495. {
  496.     DialogPtr    pictDialog = GetNewDialog (rBackgroundSelect, 0, (WindowPtr) -1);
  497.     Handle        moreItems;
  498.     short        origNumItems = CountDITL (pictDialog);
  499.     short         itemHit;
  500.     
  501.     Assert (item == 1, INTERNAL_ERROR);
  502.     Assert (gSet.Balls3D, INTERNAL_ERROR);
  503.     
  504.     CurrentCursor (arrowCursor);
  505.     
  506. //    Showing all the PICT's we have for the background costs a lot of memory.
  507. //    We can free a lot by very temporarily switching to simple graphics;
  508. //    it doesn't really show yet, and the background is bound to change anyhow.
  509.  
  510.     gSet.Balls3D = false;    //    just a while
  511.     Inval3D();                //    free up all background picture stuff
  512.     InvalBoard();
  513.  
  514. //    Append one or more DITL's containing pictures useable for the background.
  515.  
  516.     moreItems = GetResource ('DITL', rBackgroundSelectPict);
  517.     AppendDITL (pictDialog, moreItems, -1);
  518.     ReleaseResource (moreItems);
  519. //    newNumItems = CountDITL (pictDialog);    
  520.     ShowWindow (pictDialog);
  521.  
  522.     do {
  523.         ModalDialog (0, & itemHit);
  524.     } while (! itemHit);
  525.     
  526.     DisposDialog (pictDialog);
  527.     
  528. //    Now make the picture selected the background picture
  529.  
  530.     gSet.BackgroundPictID = 200 + itemHit - 2;
  531.     gSet.Balls3D = true;    //    switch back on
  532.     Inval3D();
  533. }
  534.  
  535.  
  536.  
  537. pascal void
  538. PlayerBallItemProc (WindowPtr wp, short item)
  539. {
  540.     short type;
  541.     Handle colorControl;
  542.     Rect box;
  543.     
  544.     GetDItem (wp, item, & type, & colorControl, & box);
  545.     
  546.     switch ((short) GetWRefCon (wp))
  547.     {
  548.         case 1:
  549.             PaintOval (& box);;
  550.         break;
  551.         case 2:
  552.             FrameOval (& box);        
  553.         break;
  554.         case 3:
  555.             PenPat ((ConstPatternParam) (& qd.gray));
  556.             PaintOval (& box);
  557.             PenNormal();
  558.         break;
  559.     }
  560.     FrameOval (& box);
  561. }
  562.  
  563.  
  564.  
  565. void
  566. DoSettingsMenu (short playerItem)
  567. {
  568.     DialogPtr playerDialog;
  569.     short item, type;
  570.     Handle colorControl, playerKindControl, strategyControl, levelControl, nameItem;
  571.     Rect box;
  572.  
  573. //    Create the strategy control on-the-fly.
  574.     
  575.     for (item = 0; gStrategies[item].JudgeProc.boardProc != NULL; item++)
  576.     {
  577.         AppendMenu (GetMenu (STRATEGY_MENU), (StringPtr) gStrategies[item].Name);
  578.     }
  579.     
  580.     playerDialog = GetNewDialog (200, nil, (WindowPtr) -1);
  581.     
  582.     
  583. //    Prepare all items to show their right settings, depending on global vars.
  584. //    Show dialog when done.
  585.      
  586.     GetDItem (playerDialog, 3, & type, & colorControl, & box);
  587.     SetDItem (playerDialog, 3, type, (Handle) (NewUserItemProc (PlayerBallItemProc)), & box);
  588.     
  589.     GetDItem (playerDialog, 4, & type, & playerKindControl, & box);
  590.     GetDItem (playerDialog, 5, & type, & strategyControl, & box);
  591.     GetDItem (playerDialog, 6, & type, & levelControl, & box);
  592.     GetDItem (playerDialog, 8, & type, & nameItem, & box);
  593.  
  594.     SetCtlValue ((ControlHandle) playerKindControl, gSet.PlayerKind[playerItem]);
  595.     SetCtlValue ((ControlHandle) strategyControl, gSet.Strategy[playerItem] + 1); // was +3
  596.     SetCtlValue ((ControlHandle) levelControl, gSet.Level[playerItem] + 1);
  597.     SetIText (nameItem, GetPlayerName (& gSet, playerItem));
  598.  
  599. //    All neat. Show it now.    
  600.     ShowWindow (playerDialog);
  601.  
  602. //    Use the refcon to pass the player item to the item proc
  603. //    (can't add a parameter to this pascal funtion)
  604.  
  605.     SetWRefCon (playerDialog, (long) playerItem);
  606.     
  607.     for (item = 6;;)
  608.     {
  609.         switch (item)
  610.         {
  611.             case 0:            //    nothing
  612.             default:        //    don't know
  613.             break;
  614.             case 1:            //    First do all settings stuff, then quit by falling through.
  615.                 gInterrupted = true;
  616.                 SetPlayerKind (& gSet, playerItem, GetCtlValue ((ControlHandle) playerKindControl));
  617.                 gSet.Strategy[playerItem] = GetCtlValue ((ControlHandle) strategyControl) - 1; // was -3
  618.                 {
  619.                 Str255 name;
  620.                 
  621.                 GetIText (nameItem, name);
  622.                 SetPlayerName (& gSet, playerItem, name);
  623.                 }
  624.                 gSet.Level[playerItem] = GetCtlValue ((ControlHandle) levelControl) - 1;
  625.                 if (GetCtlValue ((ControlHandle) playerKindControl) == networkPlayer)
  626.                 {
  627.                     if (Connected())
  628.                     {
  629.                         ReSyncProtocol();
  630.                     }
  631.                     else
  632.                     {
  633.                         CurrentCursor (arrowCursor);
  634.                         switch (Alert (rConnection, nil))
  635.                         {
  636.                             case 1:    //    Establish Connection
  637.                                 ConnectionProtocol();
  638.                             break;
  639.                             
  640.                             case 2:    //    Wait for other
  641.                                 ;
  642.                             break;
  643.                             
  644.                             case 3:    //    Cancel net play
  645.                                 SetPlayerKind (& gSet, playerItem, macPlayer);
  646.                             break;
  647.                         }
  648.                     }
  649.                 }
  650.             case 2:         //    just quit
  651.                 DisposDialog (playerDialog), playerDialog = 0;
  652.                 SetPort (FrontWindow());
  653.             return;
  654.             
  655.             case 3:
  656.                 DoColorMenu (playerItem);
  657.                 DisposDialog (playerDialog), playerDialog = 0;
  658.                 SetPort (FrontWindow());
  659.             return;
  660.             
  661.             case 4:
  662.             case 5:
  663.             case 6:
  664.             {
  665.                 short        playerKind = GetCtlValue ((ControlHandle) playerKindControl);
  666.                 Boolean        isMacKind = playerKind == macPlayer;
  667.                                         
  668.                 HiliteControl ((ControlHandle) strategyControl, isMacKind ? 0 : 255);
  669.                 HiliteControl ((ControlHandle) levelControl, isMacKind ? 0 : 255);
  670.  
  671.                 if (! ConfirmPlayerKind (playerItem, playerKind))
  672.                 {
  673.                 //    User cancelled in broken connection dialog.
  674.                 //    Player kind remains network player.
  675.                     SetCtlValue ((ControlHandle) playerKindControl, networkPlayer);
  676.                 }
  677.                     
  678.                 SelIText (playerDialog, 8, 0, 255);
  679.             }
  680.             break;
  681.         }
  682.         ModalDialog (nil, & item);
  683.     }
  684. }
  685.  
  686.  
  687.  
  688. Boolean
  689. DoCloseWindow (WindowPtr window)
  690. {
  691.     if (IsDAWindow (window))
  692.         CloseDeskAcc (((WindowPeek) window)->windowKind);
  693.     else if (IsAppWindow (window))
  694.         CloseWindow (window);
  695.         
  696.     return true;
  697. }
  698.  
  699.  
  700.  
  701. void
  702. Terminate (void)
  703. {
  704.     gQuitFlag = true;
  705.     HideWindow (gAbaloneWindow);
  706.     PutSettings();
  707. }
  708.  
  709.  
  710.  
  711. enum _answer
  712. AskSave (void)
  713. {
  714.     if (Connected())
  715.     {
  716.         if (ConfirmNetQuit())
  717.             return dont_save;
  718.         else
  719.             return cancel_it;
  720.     }
  721.     else
  722.     {
  723.         CurrentCursor (arrowCursor);
  724.         return (enum _answer) CautionAlert (201, NULL);
  725.     }
  726. }
  727.  
  728.  
  729.  
  730. void
  731. ConfirmAndSaveAndMaybeThen (void (*doMe)(void))
  732. {
  733.     if (gFileSaved && ! Connected())
  734.         (*doMe)();
  735.     else switch (AskSave())
  736.     {
  737.         case save:    //    Save first and then fall through.
  738.             DoMenuCommand ((FILE_MENU << 16) + FILE_SAVE);
  739.         case dont_save:
  740.             (*doMe)();
  741.         break;
  742.         default:
  743.             ;
  744.     }
  745. }
  746.