home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Snippets / DialogControls 1.1.1 / DialogControls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-09  |  23.6 KB  |  622 lines  |  [TEXT/CWIE]

  1. /******************************************************************************
  2.  DialogControls.c by Todd Clements (tclement@hmc.edu)
  3.     This demo shows how to do different things with dialogs:
  4.         1) Set the window font and size
  5.         2) Patch NewControl() so that you have controls in the window font
  6.             (thanks to Jens Alfke <jens_alfke@powertalk.apple.com> for the code)
  7.         3) Use Popup Menus in modal dialogs
  8.         4) Use AppendDITL() to get a NewsWatcher-like preferences box
  9.         5) Use styled text edit records from resources to display text
  10.         6) Write a filter for a ModalDialog
  11.         7) Use MovableModal dialog boxes
  12.         
  13.     Some some of this code is stolen from my own program, others stolen from other
  14.     people, but it's all here for you!
  15.     
  16.     If you have any comments about the code, any improvements/additions/bugs,
  17.     please feel free to contact me at the above address.
  18.     
  19.     I make no guarantees regarding the decency of this code.  Run it and use
  20.     it at your own risk.
  21.     
  22.     January 26, 1995    -    1.0 - First release
  23.     May 9, 1995            -    1.1 - Second release
  24.                                     Changed to MovableModal dialog box
  25.                                     Added "Reset Panel to Defaults" button
  26.                                     Disabled controls when window deactivated
  27. ******************************************************************************/
  28.  
  29.  
  30. #include "DialogControls.h"
  31. #include "Functions.h"
  32. #include "PatchNewControl.h"
  33. #include "MyMenus.h"
  34. #include "MovableModal.h"
  35.  
  36. /******************************************************************************
  37.     Comments about the resource file for DialogControls.c
  38.     
  39.     The heights of the control items in my dialog have been adjusted to reflect
  40.     the smaller size of the geneva font.  There is probably a standard size I
  41.     should use, but I didn't bother to look it up.  If you care, you should probably
  42.     look it up.  (But, if you care, you'll know that Apple tells you not to use
  43.     custom fonts for control items (although, see just about any System 7.5 control
  44.     panel, and then scratch your head...))
  45.     
  46.     All the controls in the dialog box are the same width, per Apple HIGs (Human
  47.     Interface Guidelines).  This is so that for scripts that read from right
  48.     to left, the controls will appear correctly.
  49.     
  50.     See the note in CheckHamburgerItems() about the true grey in dimmed controls.
  51.     
  52.     Note that the procIDs for the popup menus are different.  1008 is for a standard
  53.     popup.  1016 is for a popup in the window font.
  54. ******************************************************************************/
  55.  
  56. #define        pbOK            1
  57. #define        pbCancel        2
  58. #define        pbRevert        9
  59.  
  60. #define        rFirstOutline    4
  61. #define        rLastOutline    8
  62.  
  63. /** Defines for the menus **/
  64. #define        mApple            128
  65. #define        mFile            129
  66. #define        mEdit            130
  67.  
  68. #define        miAbout            1
  69.  
  70. #define        miOpen            1
  71. #define        miClose            2
  72. #define        miQuit            7
  73.  
  74. #define        popmiHotDog        1
  75. #define        popmiHamburger    2
  76.  
  77. /** Defines for the two windows that have stuff in them **/
  78.  
  79. #define        ditlHamburger    301
  80. #define        ditlHotDog        300
  81.  
  82. #define        wPreferences    128
  83.  
  84. #define        popWhichFood    3
  85.  
  86. /* This is for hamburger */
  87. #define        rbBeef        1
  88. #define        rbChicken    2
  89. #define        rbOther        3
  90. #define        cbLie        4
  91. #define        cbHamRelish    5
  92. #define        cbHamOnion    6
  93. #define        cbHamKetchup    7
  94. #define        cbHamMustard    8
  95. #define        cbHamTomato        9
  96. #define        cbHamLettuce    10
  97. #define        cbHamPickle        11
  98.  
  99. /* This is for hot dog */
  100. #define        rbChargeThroughNose    1
  101. #define        rbBeReasonable        2
  102. #define        rbArmAndLeg            3
  103. #define        rbGiveAway            4
  104. #define        cbHotRelish            5
  105. #define        cbHotOnion            6
  106. #define        cbHotKetchup        7
  107. #define        cbHotMustard        8
  108. #define        popHotType            9
  109.  
  110. #define        popmiRegular        1
  111. #define        popmiPolish            2
  112. #define        popmiKosher            3
  113. #define        popmiVeggie            4
  114.  
  115.  
  116. FoodPtr            food;                // Variable storing all checkbox/radio button information
  117. Boolean            gDone = false;        // Should the program terminate?
  118. EventRecord        event;                // The event
  119. TEHandle        aboutText;            // Handle to the text edit record (we need it in various places)
  120.  
  121.  
  122. /** This is where all the meat to the program is. =) **/
  123. void    main( void )
  124. {
  125.     InitToolBox();
  126.     SetUpGlobals();
  127.     SetupMenus();
  128.     EventLoop();
  129. }
  130.  
  131.  
  132.  
  133. /** Just your standard routines here **/
  134. void     InitToolBox( void )
  135. {
  136.     InitGraf(&(qd.thePort));
  137.     InitFonts();
  138.     InitWindows();
  139.     InitMenus();
  140.     TEInit();
  141.     InitDialogs(0L);    // I don't remember if this is supposed to be something else…
  142.     InitCursor();
  143.  
  144.     MaxApplZone();
  145.     MoreMasters();
  146.     MoreMasters();
  147. }
  148.  
  149.  
  150. /** Allocate memory for, and initialize our global memory. **/
  151. void    SetUpGlobals( void )
  152. {
  153.     food = (FoodPtr) NewPtr( sizeof( Food ) );
  154.     if( !food ) /* We're all left hungry */
  155.     {
  156.         SysBeep( 10 );
  157.         ExitToShell();
  158.     }
  159.     
  160.     DefaultHotDogSettings( food );
  161.     DefaultHamburgerSettings( food );
  162.  
  163. }
  164.  
  165.  
  166. /** Set the defaults for the Hot Dog settings.  Used for
  167.     initialization and "Reset" button.                    **/
  168. void    DefaultHotDogSettings( FoodPtr theFood )
  169. {
  170.     theFood->hotDog.price = rbGiveAway;
  171.     theFood->hotDog.relish = true;
  172.     theFood->hotDog.onion = true;
  173.     theFood->hotDog.ketchup = true;
  174.     theFood->hotDog.mustard = false;
  175.     theFood->hotDog.hotType = popmiRegular;
  176. }
  177.  
  178.  
  179. /** Set the defaults for the Hamburger settings.  Used for
  180.     initialization and "Reset" button.                    **/
  181. void    DefaultHamburgerSettings( FoodPtr theFood )
  182. {
  183.     theFood->ham.hamType = rbBeef;
  184.     theFood->ham.lie = false;
  185.     theFood->ham.relish = true;
  186.     theFood->ham.onion = true;
  187.     theFood->ham.ketchup = true;
  188.     theFood->ham.mustard = false;
  189.     theFood->ham.tomato = false;
  190.     theFood->ham.lettuce = true;
  191.     theFood->ham.pickle = true;
  192. }
  193.  
  194.  
  195. /** Get the menus from the resource and display them. **/
  196. void    SetupMenus( void )
  197. {
  198.     Handle        menuBar;
  199.     MenuHandle    menu;
  200.     
  201.     menuBar = GetNewMBar( 128 );
  202.     if( menuBar == nil )
  203.     {
  204.         SysBeep( 10 ); /* Probably should display error */
  205.         ExitToShell();
  206.     }
  207.     
  208.     SetMenuBar( menuBar );
  209.     
  210.     menu = GetMenuHandle( 128 );
  211.     AppendResMenu( menu, 'DRVR' );
  212.     
  213.     // MenuEnable is my own function (see Functions.c) that allows you to use the menu resource number
  214.     // followed by the menu item to enable/disable menu items.  0 as the menu item means the menu itself.
  215.     // You'll see a lot of my canned functions throughout this program.
  216.     MenuEnable( mEdit, 0, false );
  217.     MenuEnable( mFile, miClose, false ); /* We have no use for this menu item*/
  218.     
  219.     DrawMenuBar();
  220. }
  221.  
  222. /** Where everything exciting gets passed on to other people **/
  223. void    EventLoop( void )
  224. {
  225.     while( !gDone )
  226.     {
  227.         if( WaitNextEvent( everyEvent, &event, 60, nil ) )
  228.         {
  229.             switch( event.what )
  230.             {
  231.                 case    mouseDown:
  232.                     HandleMouseDown( );
  233.                     break;
  234.                 case    keyDown:
  235.                     HandleKeyDown( );
  236.                     break;
  237.                 case    activateEvt:
  238.                 case    autoKey:
  239.                 case    updateEvt:
  240.                     break;
  241.                 default:
  242.                     break;
  243.                     
  244.             }
  245.         }
  246.     }
  247. }
  248.  
  249.  
  250. /** Did someone press the mouse?
  251.     This function doesn't do much because, well, this program doesn't do much.
  252.     However, a lot of the switches were left in so you could just add your own code
  253.     if you wanted to. **/
  254. void    HandleMouseDown( void )
  255. {
  256.     short        code;
  257.     WindowPtr    window;
  258.     GrafPtr        thePort;
  259.     
  260.     code = FindWindow( event.where, &window );
  261.     
  262.     switch( code )
  263.     {
  264.         case    inMenuBar:
  265.             InterpretMenu( );
  266.             break;
  267.         case    inSysWindow:
  268.             GetPort( &thePort );
  269.             SystemClick( &(event), window );
  270.             SetPort( thePort );
  271.             break;
  272.         case     inDrag:                        //    These are here to show possible
  273.         case     inGoAway:                    //    events you could handle.  I'm
  274.         case    inContent:                    //    completely modal, so I don't
  275.         case     inGrow:                        //    have to handle them. 
  276.         case     inZoomIn: case     inZoomOut:
  277.             break;
  278.         default:
  279.             break;
  280.     }
  281. }
  282.  
  283.  
  284. /** A key was pressed.
  285.     All we care about here is if the key is a menu item equivalent.  If it is, pass
  286.     it to our menu handling function. **/
  287. void    HandleKeyDown( void )
  288. {
  289.     int        menu, menuItem;
  290.     long    theMenu;
  291.  
  292.     if(( event.modifiers & cmdKey ) != 0 )
  293.     {
  294.         theMenu = MenuKey( event.message & charCodeMask );
  295.         menu = HiWord( theMenu );
  296.         menuItem = LoWord( theMenu );
  297.         HiliteMenu( menu );
  298.         HandleMenu( menu, menuItem );
  299.     }
  300. }
  301.  
  302. /** If there was a mouseDown in a menu, we have to find out which menu item was selected. **/
  303. void    InterpretMenu( void )
  304. {
  305.     long    menuChoice;
  306.     
  307.     menuChoice = MenuSelect( event.where );
  308.     DoThisMenu( menuChoice );
  309. }
  310.  
  311. /** If the user chose a desk accessory, launch it. **/
  312. void    HandleDeskAccessory( int    menuItem )
  313. {
  314.     Str255        accName;
  315.     
  316.     MenuHandle    appleMenu = GetMenuHandle( 128 );
  317.     GetMenuItemText( appleMenu, menuItem, accName );
  318.     OpenDeskAcc( accName );
  319. }
  320.  
  321. /** Needed for the MovableModal thing…it breaks a menu code into a menu and a menu item. **/
  322. void    DoThisMenu( long menuCode )
  323. {
  324.     int        theMenu;
  325.     int        theMenuItem;
  326.     
  327.     theMenu = HiWord( menuCode );
  328.     theMenuItem = LoWord( menuCode );
  329.     
  330.     HandleMenu( theMenu, theMenuItem );
  331. }
  332.  
  333.  
  334. /** Here is where we give away all the menu power. **/
  335. void     HandleMenu( int menu, int menuItem )
  336. {
  337.     switch( menu )
  338.     {
  339.         case mApple:
  340.             switch( menuItem )
  341.             {
  342.                 case 1:
  343.                     DoAboutMenu();
  344.                     break;
  345.                 default:
  346.                     HandleDeskAccessory( menuItem );
  347.                     break;
  348.             }
  349.             break;
  350.         case mFile:
  351.             switch(menuItem)
  352.             {
  353.                 case miQuit:
  354.                     gDone = true;
  355.                     break;
  356.                 case miOpen:
  357.                     DoTheMagic();
  358.                     break;
  359.                 default:
  360.                     break;
  361.             }
  362.             break;
  363.         case mEdit:
  364.             break;
  365.         default:
  366.             break;
  367.     }
  368.     // The menu manager hilites the menu, but waits for you to unhilite it.
  369.     HiliteMenu( 0 );
  370. }
  371.  
  372.  
  373. /** The about menu simply puts up a styled text block and waits for a clickzeof( Food ) );
  374.  
  375.     // We could just use SnatchHandle here, but I decided not to for some odd reason
  376.     GetDialogItem( dialog, popWhichFood, &itemType, &foodPopHandle, &foodPopRect );
  377.     SetControlValue( (ControlHandle) foodPopHandle, whichFood );
  378.  
  379.     // Count the number of items we have in our dialog before we add new ones
  380.     standardDITL = CountDITL( dialog );
  381.  
  382.     // Add the correct DITL (based on whichFood), and check the correct stuff
  383.     SetUpFoodDitl( dialog, standardDITL, whichFood, &newFood );
  384.  
  385.     // We aren't doing drawing routines here because when a dialog is put up, it
  386.     // automatically generates an updateEvt, so you don't have to deal with it specifically.
  387.         
  388.     while( !done )
  389.     {
  390.         MovableModalDialog( 0L, &hit, dialog );
  391.         
  392.         switch( hit )
  393.         {
  394.             case pbOK:
  395.                 BlockMove( &newFood, food, sizeof( Food ) );
  396.                 done = true;
  397.                 break;
  398.             case pbCancel:
  399.                 done = true;
  400.                 break;
  401.             case popWhichFood:
  402.                 GetDialogItem( dialog, popWhichFood, &itemType, &foodPopHandle, &foodPopRect );
  403.                 newValue = GetControlValue( (ControlHandle) foodPopHandle );
  404.                 if( whichFood == newValue )
  405.                     break;
  406.                 else
  407.                 {
  408.                     whichFood = newValue;
  409.                     TakeOutCurrentDITL( dialog, standardDITL );
  410.                     SetUpFoodDitl( dialog, standardDITL, whichFood, &newFood );
  411.                 }
  412.             
  413.                 break;
  414.             default:
  415.                 switch( whichFood )
  416.                 {
  417.                     case popmiHotDog:
  418.                         HandleHotDogItems( dialog, standardDITL, &newFood, hit );
  419.                         break;
  420.                     case popmiHamburger:
  421.                         HandleHamburgerItems( dialog, standardDITL, &newFood, hit );
  422.                         break;
  423.                 }
  424.                 break;
  425.         }
  426.     }
  427.  
  428.     UnPatchNewControl();
  429.     TwiddleMenus();
  430.  
  431.     DisposeDialog( dialog );
  432.  
  433. }
  434.  
  435. /* I use this as a quick way to get a new dialog, put it behind any window I want,
  436.     as well as set the window font all in one fell swoop. */
  437. DialogPtr    MyGetNewDialogFont( int    rsrcId, Boolean moveToFront, WindowPtr behindWhich,
  438.                     short fontNo, short textSize )
  439. {
  440.     DialogPtr        window;
  441.     
  442.     if( moveToFront ) behindWhich = (WindowPtr) -1L;
  443.  
  444.     window = GetNewDialog( rsrcId, nil, behindWhich );
  445.     
  446.     if( !window )
  447.     {
  448.         SysBeep( 10 );
  449.         return nil;
  450.     }
  451.  
  452.     SetWRefCon( window, (long) rsrcId );
  453.     SetPort( (GrafPtr) window );
  454.     
  455.     SetDialogFontAndSize( window, fontNo, textSize );
  456.     
  457.     ShowWindow( window );
  458.     return window;
  459. }
  460.  
  461. /* Also stolen from an unknown source */
  462. void    SetDialogFontAndSize( DialogPtr theDialog, short fontNo, short fontSize )
  463. {
  464.     FontInfo    fInfo;
  465.  
  466.     TextFont( fontNo );
  467.     TextSize( fontSize );
  468.     GetFontInfo( &fInfo );
  469.     
  470.     (**(((DialogPeek)theDialog)->textH)).txFont = geneva;
  471.     (**(((DialogPeek)theDialog)->textH)).txSize = 9;
  472.     
  473.     (**(((DialogPeek)theDialog)->textH)).lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
  474.     (**(((DialogPeek)theDialog)->textH)).fontAscent = fInfo.ascent;
  475. }
  476.  
  477. /** Frame the options area **/
  478. void    FrameOptions( DialogPtr dialog )
  479. {
  480.     int        i;
  481.     Rect    theRect;
  482.     
  483.     for( i = rFirstOutline; i <= rLastOutline; i++ )
  484.     {
  485.         GetDialogItemRect( dialog, i, &theRect );
  486.         FrameRect( &theRect );
  487.     }
  488. }
  489.  
  490. /** Add the correct DITLs, and then call the checking procedure **/
  491. void    SetUpFoodDitl( DialogPtr window, short standardDITL, short whichFood, FoodPtr newFood )
  492. {
  493.     Handle        addDitl;
  494.     
  495.     addDitl = GetResource( 'DITL', whichFood + ditlHotDog - 1 );
  496.     if( !addDitl )
  497.     {
  498.         SysBeep( 10 );
  499.         ExitToShell();
  500.     }
  501.     
  502.     HLock( addDitl );
  503.     AppendDITL( window, addDitl, overlayDITL );
  504.     HUnlock( addDitl );
  505.     ReleaseResource( addDitl );
  506.     
  507.     SelectTheRightStuff( window, standardDITL, whichFood, newFood );
  508. }
  509.  
  510. /** Remove the current EXTRA items in the dialog box, to set up for the next one **/
  511. void    TakeOutCurrentDITL( DialogPtr window, short standardDITL )
  512. {
  513.     short        ditlCount;
  514.     
  515.     ditlCount = CountDITL( window );
  516.     
  517.     ShortenDITL( window, ditlCount - standardDITL );
  518. }
  519.  
  520. /** Just sees which item we wish to go through and make sure everything is checked for **/
  521. void    SelectTheRightStuff( DialogPtr window, short standardDITL, short whichFood, FoodPtr newFood )
  522. {
  523.     switch( whichFood )
  524.     {
  525.         case popmiHotDog:
  526.             CheckHotDogItems( window, whichFood, standardDITL, newFood );
  527.             break;
  528.         case popmiHamburger:
  529.             CheckHamburgerItems( window, whichFood, standardDITL, newFood );
  530.             breakdardDITL, FoodPtr newFood, short hit )
  531. {
  532.     if ( hit == pbRevert )
  533.     {
  534.         DefaultHamburgerSettings( newFood );
  535.         CheckHamburgerItems( window, 0, standardDITL, newFood );
  536.         return;
  537.     }
  538.  
  539.     switch( hit - standardDITL)
  540.     {
  541.         case rbBeef: case rbChicken: case rbOther:
  542.             SelectButton( window, newFood->ham.hamType+standardDITL, false );
  543.             SelectButton( window, hit, true );
  544.             newFood->ham.hamType = hit-standardDITL;
  545.             if( newFood->ham.hamType == rbOther )
  546.                 EnableButton( window, cbLie+standardDITL, true );
  547.             else
  548.             {
  549.                 EnableButton( window, cbLie+standardDITL, false );
  550.                 newFood->ham.lie = false;
  551.                 SelectButton( window, cbLie+standardDITL, false );
  552.             }
  553.             break;
  554.         case cbLie:
  555.             CheckButton( window, cbLie+standardDITL );
  556.             newFood->ham.lie = !(newFood->ham.lie);
  557.             break;
  558.         case cbHamRelish:
  559.             CheckButton( window, cbHamRelish+standardDITL );
  560.             newFood->ham.relish = !(newFood->ham.relish);
  561.             break;
  562.         case cbHamOnion:
  563.             CheckButton( window, cbHamOnion+standardDITL );
  564.             newFood->ham.onion = !(newFood->ham.onion);
  565.             break;
  566.         case cbHamKetchup:
  567.             CheckButton( window, cbHamKetchup+standardDITL );
  568.             newFood->ham.ketchup = !(newFood->ham.ketchup);
  569.             break;
  570.         case cbHamMustard:
  571.             CheckButton( window, cbHamMustard+standardDITL );
  572.             newFood->ham.mustard = !(newFood->ham.mustard);
  573.             break;
  574.         case cbHamTomato:
  575.             CheckButton( window, cbHamTomato+standardDITL );
  576.             newFood->ham.tomato = !(newFood->ham.tomato);
  577.             break;
  578.         case cbHamLettuce:
  579.             CheckButton( window, cbHamLettuce+standardDITL );
  580.             newFood->ham.lettuce = !(newFood->ham.lettuce);
  581.             break;
  582.         case cbHamPickle:
  583.             CheckButton( window, cbHamPickle+standardDITL );
  584.             newFood->ham.pickle = !(newFood->ham.pickle);
  585.             break;
  586.     }
  587. }
  588.  
  589. /** This function is a hack.  You should do a better job with it. =)  **/
  590. void    FindWindowToUpdate( WindowPtr window )
  591. {
  592.     long        ID;
  593.     GrafPtr        old;
  594.     
  595.     // I store the window number in the ref con of the window (see MyGetNewDialogFont())
  596.     // Normally I have a function to do this, but in this case, I only call it once.
  597.     ID = (long) GetWRefCon( window );
  598.     
  599.     GetPort( &old );
  600.  
  601.     SetPort( window );
  602.     
  603.     switch (ID)
  604.     {
  605.         case wPreferences:
  606.             // This is a weird thing.  Normally you stick redrawing functions within the BeginUpdate()
  607.             // and EndUpdate() calls, but here, if I try, they don't draw correctly.  It's possible
  608.             // that the dialog manager draws over anything I draw, and that's why, but I haven't
  609.             // run across that in any other program I've written.  Any ideas anyone?
  610.             BeginUpdate( window );
  611.             EndUpdate( window );
  612.     
  613.             FrameOptions( (DialogPtr) window );
  614.             break;
  615.         default:
  616.             break;
  617.     }
  618.  
  619.     SetPort( old );
  620. }
  621. /** THE END!!!!! **/
  622.