home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / lang / simpleto.sou < prev    next >
Text File  |  1986-12-09  |  51KB  |  1,781 lines

  1.  7-Dec-86 16:37:13-MST,52827;000000000000
  2. Return-Path: <INFO-MAC-REQUEST@SUMEX-AIM.ARPA>
  3. Received: from SUMEX-AIM.ARPA by SIMTEL20.ARPA with TCP; Sun 7 Dec 86 16:34:58-MST
  4. Return-Path: <hpcea!hpsrla!hpsadla!erik@hplabs.HP.COM>
  5. Received: from hplabs.HP.COM by SUMEX-AIM.ARPA with TCP; Sat 6 Dec 86 13:57:40-PST
  6. Received: by hplabs.HP.COM ; Fri, 5 Dec 86 11:08:33 pst
  7. From: hpcea!hpsrla!hpsadla!erik@hplabs.HP.COM
  8. Received: by hpcea; Fri, 5 Dec 86 10:02:03 mst
  9. Received: by hpsrla; Fri, 5 Dec 86 08:56:30 pst
  10. Date: Fri, 5 Dec 86 08:56:30 pst
  11. To: INFO-MAC-REQUEST@SUMEX-AIM
  12. Subject: UTILITY-SIMPLETOOLS2-C.SOURCE
  13. ReSent-Date: Sun 7 Dec 86 15:28:08-PST
  14. ReSent-From: David Gelphman... <INFO-MAC-REQUEST@SUMEX-AIM.ARPA>
  15. ReSent-To: info-mac-redist: ;
  16. ReSent-Message-ID: <12260993367.33.INFO-MAC-REQUEST@SUMEX-AIM.ARPA>
  17.  
  18. /*
  19.     Title    : SimpleTools2.c
  20.     Author    : Erik Kilk  Copyright 1985, 1986
  21.     Date    : June 7, 1985, June 3, 1986, November 8, 1986
  22.           November 28, 1986
  23.     SimpleTools is a collection of routines to aid programming
  24.     simple "Macintosh looking" programs.  SimpleTools initializes
  25.     the toolbox, monitors & acts upon events, and provides generic
  26.     i/o routines for your application.  You initialize your program
  27.     by letting SimpleTools know what windows and menus you want along
  28.     with what functions SimpleTools should call when they are
  29.     selected.
  30.     
  31.     The purpose of SimpleTools is to encourage you to program those
  32.     simple programs or to pilot larger programs which you may not
  33.     do due to the enormous effort required to use the Macintosh
  34.     toolbox.  My goal was to study Inside Macintosh once to
  35.     Create SimpleTools and then be able to forget most of the usages
  36.     of the Toolbox routines.  Instead of thumbing through hundreds of
  37.     pages of Inside Macintosh just to get something up and running,
  38.     one need only remember a dozen generic calls.
  39.  
  40.     SimpleTools is very powerful, yet also very simple to use.  One
  41.     can get a program up and running with desk accessories, windows,
  42.     and menus in only a few minutes.  Advance features of SimpleTools
  43.     allow you to retrieve enough information from SimpleTools to call
  44.     any of the toolbox routines manually if need be.  
  45.     
  46. =========================================================================
  47.     You may use, study, copy, and freely distribute SimpleTools if:
  48.         1)  You mention "Programmed with the aid of SimpleTools
  49.             (c) Erik Kilk 1986" in your About... window of all
  50.             programs distributed free, share, or marketted.
  51.         2)  You register by sending $20 or more to:
  52.             Erik Kilk
  53.             4949 Snyder Lane, #247
  54.             Rohnert Park, CA  94928
  55.             (707) 794-2424 weekday afternoons
  56.             to encourage me to maintain and improve SimpleTools.
  57. ==>    For a diskette including the most recent version of SimpleTools, 
  58.     several detailed examples of using SimpleTools, and a MacWrite file
  59.     describing SimpleTools and its use in more detail, send me a
  60.     diskette with enough stamps to mail it back to you.  Make sure you
  61.     have registered as stated above.
  62.         
  63.     This is 128k, MFS, HFS, old ROM, new ROM, Mac+, & TMON compatible.
  64.     This file compiles and executes with Megamax 3.0 beta and
  65.     LightSpeed 2.1.  Adjust the definition in simple.h for your
  66.     compiler.  When porting to other compilers, pay particular
  67.     attention to where the Lightspeed and Megamax code is specified
  68.     since these places are the likely problem areas.
  69.     
  70.     LIGHTSPEED NOTE:
  71.     
  72.     Drag SimpleTools out of the main segment in your project window.
  73.     You do this by dragging it below the dotted horizontal Line in the
  74.     project window.
  75.     
  76.     MEGAMAX NOTE:
  77.     
  78.     Use Megamax's convert utility to convert all Mac names to all
  79.     lower case.  If you send me suggestions and/or new code for
  80.     SimpleTools, please convert back to mixed case first.
  81.     
  82. =========================================================================
  83.     
  84.     SimpleTools provides the following functions for your application
  85.     to call.  Note that your application need not call any Toolbox
  86.     routines directly.  The entire C program (including the standard
  87.     desk accessory support):
  88.     
  89.             main ()
  90.             {
  91.                 simpletools ("Skel");
  92.                 simplequits ();
  93.                 runsimpletools ();
  94.             }
  95.             
  96.     will execute as a Macintosh program, terminating upon the user
  97.     selecting Quit.  SimpleTools includes:
  98.     
  99.         simpletools ()        - init Toolbox and SimpleTools
  100.         simplequits ()        - add Transfer & Quit menus
  101.         simpleevents ()        - process next Mac event
  102.         runsimpletools ()    - continuously process events
  103.         
  104.         menu ("File","New",new) - install a menu
  105.         window ("My Window",..)    - install a window
  106.                     
  107.         run (function)        - install a periodic function
  108.         stop (function)        - remove a periodic function
  109.         
  110.         havenewrom ()        - test for new 128k ROM
  111.         withwindow("My Window")    - set output to a window
  112.         
  113.         stgotoxy (x, y)        - set pen to text position x, y
  114.         home ()            - clear window, set pen to home
  115.         getline (deflt, dest)    - with TE editing, get a Line
  116.         prompt (question, dest)    - with dialog box & TE, get a Line
  117.         message (string)    - with dialog box, print a string
  118.         getfile ("TEXT", name)    - with list, select a filename
  119.         putfile (orig, name)    - with list, select a filename
  120.         
  121.     
  122.     A complete Macintosh Style application (including windowing and 
  123.     menus) is given in the following trivial example...
  124.     
  125.         #include <simple.h>
  126.         
  127.         char name[50];
  128.         
  129.         got_beep()        
  130.         {
  131.             SysBeep (10);
  132.         }
  133.         
  134.         got_getname()
  135.         {
  136.             char newname[50];
  137.             *newname = 0;
  138.             if (prompt ("What is your name?", newname)) {
  139.                 strcpy (name, newname);
  140.                 withwindow ("My Window");
  141.                 home();
  142.                 update();
  143.             }
  144.         }
  145.         
  146.         in_content(x, y)
  147.         int x, y;
  148.         {
  149.             MoveTo (x, y); LineTo (x, y);
  150.         }
  151.         
  152.         update()
  153.         {
  154.             char outstring[100];
  155.             stgotoxy (1, 5);
  156.             sprintf (outstring,"Hello, %s", name);
  157.             #ifndef MEGAMAX
  158.               CtoPstr (outstring);
  159.             #endif
  160.             DrawString (outstring);
  161.         }
  162.         
  163.         main ()
  164.         {
  165.             simpletools ("Sample Program");
  166.             simplequits ();
  167.             menu ("Commands", "Beep", got_beep);
  168.             menu ("Commands", "Get Name", got_getname);
  169.             strcpy (name, "World");
  170.             window ("My Window",0,0,0,0,0L,0L,update,
  171.                 in_content);
  172.             runsimpletools ();
  173.         }
  174.         
  175. =========================================================================
  176.  
  177.     ROUTINES YOUR APPLICATION MAY CALL:
  178.     
  179.     
  180.     simpleevents ()
  181.     
  182.     To be called repeatedly by your program's main routine.  In
  183.     most SimpleTools programs, your main routine will initialize
  184.     and install SimpleTools followed by an loop such as:
  185.     
  186.         for (;;) simpleevents();
  187.         
  188.     This routine handles all window changes, menu requests, and
  189.     other Macintosh events.  There is also a routine called with
  190.     runsimpletools() which does not return.  It simply performs the
  191.     above loop.  Program exit is accomplished by assigning an
  192.     exiting routine to a menu, usually this is File/Quit.
  193.         
  194.     
  195.     simpletools (about_string)
  196.     char *about_string;
  197.     
  198.     To be called once at the very beginning of your main routine.
  199.     This routine initializes all the Macintosh software managers
  200.     and installs the basic Apple, File, and Edit menus.  The 
  201.     about_string is the name of the menu Item to appear first under
  202.     the Apple menu.
  203.     
  204.     
  205.     simplequits ()
  206.     
  207.     Installs a simple File/Quit and File/Transfer menu.  You only
  208.     want to installs these if no application dependent processing
  209.     must be done when the user selects Quit or Transfer.
  210.     
  211.     
  212.     menu (name, Item, routine)
  213.     char     *name;
  214.     char     *Item;
  215.     ProcPtr    routine;
  216.     
  217.     To be called when a new menu is to be installed on the menu bar
  218.     or when the characteristics of that menu are to be modified.
  219.     Name is the name of the menu to appear on the menu bar.  Item
  220.     is the name of the Item to appear under the menu name.  Routine
  221.     is the name of the routine to be executed when the stated menu/Item
  222.     has been selected.  The characteristics of the menu may be changed
  223.     by passing one of the constants itemdisable, itemenable, itemcheck,
  224.     or itemuncheck in place of the routine.
  225.     
  226.     
  227.     window (name, xtop, ytop, xbot, ybot, act, deact, update, content)
  228.     char     *name;
  229.     int      xtop, ytop;
  230.     int      xbot, ybot;
  231.     ProcPtr    act, deact, update, content;
  232.     
  233.     To be called when a new window is to be installed on the screen
  234.     or when the characteristics of that window are to be modified.
  235.     Name is the name of the window.  Xtop, ytop, xbot, and ybot are
  236.     the initial coordinates of the new window.  Act is the name of
  237.     the procedure to execute when the window becomes the top or
  238.     active window.  Deact is the name of the procedure to execute when
  239.     the window ceases being the top window and deactivates.  Update
  240.     is the name of the procedure called when the Macintosh needs to
  241.     redraw the window's contents.  Content is the name of the procedure
  242.     called when the mouse is pressed within the window.  The procedure
  243.     specified as content will be passed an x and y integer value
  244.     representing the local mouse coordinates.
  245.     
  246.     
  247.     withwindow (name)
  248.     char *name;
  249.     
  250.     To be called when you want to select which window will receive
  251.     output and drawings.  In most cases, SimpleTools will select the
  252.     appropriate window before calling your specified act, deact,
  253.     update, or content procedures.  Use this at other times.
  254.     
  255.     
  256.     run (routine)
  257.     ProcPtr    routine;
  258.     
  259.     To be called when you want a routine to be continuously executed
  260.     once each time simpleevents() is called.  Small, quickly running
  261.     routines should be used so as not to Delay the next event
  262.     processing.  Pseudo multiprocessing with each routine running in
  263.     its own window can be accomplished by making sure a run routine
  264.     uses withwindow() to direct its output to the proper window.
  265.     
  266.     
  267.     stop (routine)
  268.     ProcPtr routine;
  269.     
  270.     To be called when you want to remove a previously run() routine
  271.     from the list of routines to run.  50 routines can fit into the
  272.     run list.
  273.     
  274.     
  275.     home ()
  276.     
  277.     Clears the current window and positions the pen such that any
  278.     following text will appear in the upper left corner of the
  279.     window.
  280.     
  281.     
  282.     stgotoxy (column, row)
  283.     int column, row;
  284.     
  285.     Positions the pen in the current window so that the next text
  286.     output will appear in text row and column.  This is compatible
  287.     with some old text only terminals.  stgotoxy (1, 1) positions the
  288.     pen in the upper left corner.  Any negative coordinate leaves
  289.     that axis of the pen where it currently is.
  290.     
  291.     
  292.     getline (default, destination)
  293.     char *default;
  294.     char *destination;
  295.     
  296.     Calling this routine begins a "modal" mode where the user is
  297.     required to enter a Line of text.  This would be similar to
  298.     using scanf() on "non-Mac", text-only terminals.  This routine
  299.     uses the Macintoshes built in Text-Edit routines allowing the
  300.     user to edit his Line until <RETURN> is pressed.  The flashing
  301.     bar Cursor is positioned at the current pen location.  The 
  302.     resulting string is placed into destination.  Default contains
  303.     the initial value to be displayed on the screen.  You may use
  304.     the null string "" for default.
  305.     
  306.     
  307.     prompt (question, answer)
  308.     char *question;
  309.     char *answer;
  310.     
  311.     This routine places a small 3-lined Macintosh Style dialog window
  312.     prompting the user with question and getting the answer in a
  313.     boxed Text-Edit area.  Two buttons are displayed to terminate the
  314.     user entry.  If Cancel is clicked upon, FALSE is returned.  If
  315.     okay is clicked upon, TRUE is returned.  Answer must be set to
  316.     a default value, "" is okay.
  317.     
  318.     
  319.     message (message)
  320.     char *message;
  321.     
  322.     This routine is similar to prompt except no textual response is
  323.     asked from the user.  This is like an Alert dialog.  Just like
  324.     prompt, TRUE or FALSE is returned depending upon which Button the
  325.     user presses.
  326.     
  327.     
  328.     getfile (file_type, reply)
  329.     char *file_type;
  330.     char *replay;
  331.     
  332.     This routine places the standard Macintosh SFGetFile() window
  333.     up with a list of files of file_type.  Once the user selects a
  334.     file, the answer is returned in the string reply.  Also, and
  335.     very important for HFS, the working volume/folder is set so that
  336.     any subsequent open() with reply as the file name will open the
  337.     correct selected file.  The open() should be done before someone
  338.     has a chance to change the working volume.  This routine will 
  339.     return FALSE if the user selects the CANCEL Button.
  340.     
  341.     
  342.     putfile (origname, reply)
  343.     char *origname;
  344.     char *reply;
  345.     
  346.     This routine is like getfile, except the standard putfile window
  347.     is displayed with origname as the default name to save a file as.
  348.     The actual name selected by the user is returned in reply.  As
  349.     getfile, the working volume/folder is set properly for the next
  350.     open() call.
  351.  
  352. =========================================================================
  353.  
  354.     THE FOLLOWING IS THE FILE simple.h.  YOU SHOULD COPY THIS PORTION
  355.     INTO A NEW FILE NAMED simple.h SO YOU CAN #include IT INTO YOUR
  356.     SOURCE FILES.
  357.     
  358. =========================================================================
  359.  
  360. #define LIGHTSPEED    {define either LIGHTSPEED or MEGAMAX or your own}
  361.  
  362. #include <stdio.h>
  363.  
  364. #ifdef MEGAMAX
  365.   #include <menu.h>
  366.   #include <win.h>
  367. #endif
  368.  
  369. #ifdef LIGHTSPEED
  370.   #include <MenuMgr.h>
  371.   #include <WindowMgr.h>
  372. #endif
  373.  
  374. #define itemdisable    0L        
  375. #define itemenable    1L
  376. #define itemcheck    2L
  377. #define itemuncheck    3L
  378.  
  379. extern char         applestring[];
  380. extern WindowPtr     windowpoint();
  381. extern MenuHandle     mhand();
  382. extern int         windmenu;
  383. extern int         dogoaway;        
  384. extern int         wprocid;        
  385. extern int         sizeredraw;
  386. extern int        getlinecaps;
  387. extern ProcPtr         keydownproc;
  388. extern ProcPtr         autokeyproc;
  389. extern int        home();
  390.  
  391. =========================================================================
  392.  
  393.         Here begins SimpleTools.c
  394.         _________________________
  395. */
  396.  
  397. #include <simple.h>            /* define compiler in here    */
  398.  
  399. #ifdef MEGAMAX                            
  400.         overlay "simpletools"        /* compiler dependent        */
  401.  
  402.     #include <mem.h>
  403.     #include <qd.h>
  404.     #include <qdvars.h>
  405.     #include <misc.h>
  406.     #include <event.h>
  407.     #include <res.h>
  408.     #include <win.h>
  409.     #include <dialog.h>
  410.     #include <menu.h>
  411.     #include <string.h>
  412.     #include <stdio.h>
  413.     #include <pack.h>
  414.     #include <te.h>
  415.     #include <toolbox.h>
  416.     
  417.     #define  ZZ    &
  418. #else
  419.     #include <MemoryMgr.h>
  420.     #include <Quickdraw.h>
  421.     #include <EventMgr.h>
  422.     #include <ResourceMgr.h>
  423.     #include <WindowMgr.h>
  424.     #include <TextEdit.h>
  425.     #include <DialogMgr.h>
  426.     #include <MenuMgr.h>
  427.     #include <strings.h>
  428.     #include <stdio.h>
  429.     #include <PackageMgr.h>
  430.     #include <ToolboxUtil.h>
  431.     #include <StdFilePkg.h>
  432.     #include <pascal.h>
  433.     
  434.     #define  ZZ    
  435. #endif
  436.  
  437. #define TRUE (-1)        /* local definitions             */
  438. #define FALSE 0
  439. #define maxsruns 50        /* procedure table size            */
  440. #define MESSN 30        /* array size for message dialog items    */
  441. #define QUESN 40        /* array size for prompt dialog items    */
  442. #define ROM85   0x28E        /* new rom stuff             */
  443. #define NEWROM  0x7FFF
  444. #define inzoomout 8
  445. #define inzoomin  7
  446. #define zoomproc  8
  447.  
  448. typedef struct {            /* structure for an Item    */
  449.     char        itemname[40];
  450.     int        itemno;        /* Item number within menu     */
  451.     int        menuId;        /* menu id            */
  452.     MenuHandle    menuhand;    /* Item's menu's Handle                 */
  453.     ProcPtr        menurun;    /* procedure to run         */
  454.     Ptr        next;        /* pointer to the next Item     */
  455. } itemdatum;
  456.  
  457. typedef struct {            /* structure for a menu     */
  458.     char         menuname[20];    /* to allow reference by name     */
  459.     int         menuId;        /* menu id             */
  460.     MenuHandle    menuhand;    /* menu Handle to reference menu*/
  461.     itemdatum    **itemlist;    /* pointer to the list of items */
  462.     Ptr         next;        /* pointer to the next menu     */
  463. } menudatum;
  464.  
  465. typedef struct {            /* structure for a window     */
  466.     char        windname[80];    /* window's name and reference     */
  467.     WindowPtr    wptr;        /* window's pointer reference     */
  468.     ProcPtr    wact;            /* the activate procedure     */
  469.     ProcPtr    wdeact;            /* the deactivate procedure     */
  470.     ProcPtr    wupdate;        /* the update procedure     */
  471.     ProcPtr    wcontent;        /* the content procedure     */
  472.     Ptr        next;        /* pointer to the next window     */
  473. } winddatum;
  474.  
  475. #ifdef LIGHTSPEED
  476.   pascal Boolean     *TrackBox() = 0xA83B; 
  477.   pascal void         *ZoomWindow() = 0xA83A;
  478. #endif
  479.  
  480. WindowPtr windowpoint();
  481.  
  482. /* Local variables */
  483.  
  484. menudatum     **simplemenus;        /* Handle to menu data         */
  485. char         accname[80];        /* desk accessory name to open     */
  486. Rect         dragrect, sizerect;    /* limits for moving windows     */
  487. Rect         swholescreen;
  488. winddatum    **simplewinds;        /* Handle to window data     */
  489. int        firstwind;        /* if no windows have been made    */
  490. ProcPtr     simpleruns[maxsruns];    /* list of procedures to run     */
  491. WindowPtr    debugw;            /* window pointer for debugging */
  492. int        snewrom;
  493. int        getlinecaps = FALSE;
  494.  
  495. /************************************************************************/
  496. /* GLOBAL USER MODIFIABLE VARIABLES                     */
  497. /* These are variables that you can declare extern so that you can use    */
  498. /* them to change the SimpleTools defaults                */
  499. /************************************************************************/
  500.  
  501. /* wprocid = type of window to Create on next window() call        */
  502. /* For LightSpeed C, use a lower case d and upper case P for         */
  503. /*     DocumentProc.  Megamax conversion program does this wrong.    */
  504.  
  505. int         wprocid = documentProc;    
  506.  
  507. /* dogoaway = is the next created window to have a go-away box        */
  508.  
  509. int         dogoaway = TRUE;    
  510.  
  511. /* keydownproc = the procedure to be called when keyDown is detected    */
  512. /* autokeyproc = the procedure to be called when autoKey is detected    */
  513. /* BOTH OF THESE ARE PASSED THE EVENTRECORD SO THE KEY CAN BE FOUND    */
  514.  
  515. ProcPtr     keydownproc,
  516.           autokeyproc;         
  517.         
  518. /* applestring = a string containing the Apple for menu reference    */
  519.  
  520. char         applestring[2] 
  521.           = {'\024', '\0'};     
  522.  
  523. /* windmenu = does the next window created get a choice under the
  524.               window menu (so a closed window can be brought back    */
  525.               
  526. int         windmenu = TRUE;    
  527.  
  528. /* sizeredraw = is the window's content area erased and made
  529.                 updateable upon being resized                */
  530.                 
  531. int        sizeredraw = FALSE;    
  532.  
  533.  
  534. /******************************************************************/
  535. /* Dialog lists.  These were calculated by using the new resource */
  536. /* editor to make a template for a dialog and then using fedit to */
  537. /* list the hex listing of the Item list for the dialog.      */
  538. /******************************************************************/
  539.  
  540. int messd[MESSN] = {2,0,0,0x38,0xf1,0x4c,0x12d,0x402,0x4f4b,0,0,5,5,
  541.         0x36,0x12d,0x800,0,0,0x38,0xac,0x4c,0xe8,0x406,
  542.         0x4361,0x6e63,0x656c};
  543. int quesd[QUESN] = {3,0,0,0x21,0xf0,0x35,0x12c,0x402,0x4f4b,0,0,8,8,
  544.         0x28,0xe8,0x800,0,0,0x2b,8,0x4b,0xe8,0x1000,0,0,
  545.         8,0xf0,0x1c,0x12c,0x406,0x4361,0x6e63,0x656c};
  546.         
  547.         
  548. /* Local procedure */
  549.  
  550. stnop()                /* a no op procedure for defaults     */
  551. {
  552. }
  553.  
  554. char *ptoc(s)
  555. char *s;
  556. {
  557.     #ifndef MEGAMAX
  558.         return (PtoCstr(s));
  559.     #else
  560.         return (s);
  561.     #endif
  562. }
  563.  
  564. char *ctop(s)
  565. char *s;
  566. {
  567.     #ifndef MEGAMAX
  568.         return (CtoPstr(s));
  569.     #else
  570.         return (s);
  571.     #endif
  572. }
  573.  
  574. /* Given a menu name, find our data structure for it.  Return a Handle
  575.    to this structure.  This is a local procedure for SimpleTools use.
  576. */
  577.  
  578. /* local procedure */
  579.  
  580. menudatum **getourmenuhandle (name)
  581. char *name;                /* name of menu bar menu */
  582. {
  583.     menudatum **here, **temp;    /* hand to menu structure*/
  584.     here = simplemenus;
  585.  
  586.     /* find the menu name or the end of out menu list */
  587.     HLock (here);
  588.     while (strcmp(name,(**here).menuname) && (**here).next )  {
  589.         temp = here;
  590.         here = (menudatum **)(**here).next;
  591.         HUnlock (temp);
  592.         HLock (here);
  593.     }
  594.         
  595.     /* see if we found it or just the end of the list */
  596.     if (!strcmp(name,(**here).menuname)) {
  597.         HUnlock (here);
  598.         return (here);
  599.     } else {
  600.         HUnlock (here);
  601.         return ((menudatum **)0L);        
  602.     }
  603. }
  604.  
  605. /* This takes a Handle to our personal Item record and either a 
  606.    procedure name or a modifier code.  If it got a procedure name,
  607.    it sets it to the Item's procedure to run when the Item is chosen.
  608.    If it got a modifier code, it changes the state of the menu's Item
  609.    to checked, unchecked, enabled, or disabled.  It especially keeps 
  610.    track of the standard Edit menu items so we can restore them after
  611.    a desk accessory is finished.
  612. */
  613.  
  614. /* Local procedure */
  615.  
  616. setitems ( items, routine)    /* set a menu Item's routine or display */
  617. itemdatum    **items;    /* if items is neg, then whole menu     */
  618. ProcPtr    routine;
  619. {
  620.     int            inumber;
  621.     MenuHandle        mhand;
  622.     
  623.     /* check to see if a procedure pointer was given to us */
  624.     if ( (((long)items)>0L) && (routine > (ProcPtr)0x1000L)) {  
  625.                         /* good procedure value */
  626.         (**items).menurun = routine;
  627.         return;
  628.     }
  629.     
  630.     /* Calculate which Item number we are going to modify */
  631.     if ( (long)items < 0L) {        /* the whole menu     */
  632.         mhand = (MenuHandle) (0L - (long)items);
  633.         inumber = 0;
  634.     } else {                /* just one Item     */
  635.         mhand = (**items).menuhand;
  636.         inumber = (**items).itemno;
  637.     }
  638.  
  639.     /* If a NULL procedure pointer, then set to a no_op routine */
  640.     if ( (inumber > 0) && ((**items).menurun == (ProcPtr)0L) )
  641.         (**items).menurun = stnop;
  642.  
  643.     /* Now change the state of a menu Item */
  644.     switch ((int)routine) {
  645.         case itemdisable: 
  646.             DisableItem(mhand,inumber); break;
  647.         case itemenable:
  648.             EnableItem(mhand, inumber); break;
  649.         case itemcheck:
  650.             CheckItem(mhand, inumber, TRUE); break;
  651.         case itemuncheck:
  652.             CheckItem(mhand, inumber, FALSE); break;
  653.     }
  654.     if (inumber == 0) DrawMenuBar();  /* if main menu was changed     */
  655.     
  656. }
  657.  
  658. /* This routine is called by the simpletools() initial routine.  It gets
  659.    the pointer list of menus started, loads the desk accessories into
  660.    the Apple menu, and loads up some standard menu entries.  The reason
  661.    menu File has a New entry, and none others, is because as this code
  662.    currently stands, a menu must have at least one Item.  And since we
  663.    want File before Edit, I had to make an entry.  The most commonly used
  664.    Item under File is Quit.  But we like quit to be at the end of the list.
  665.    So, since New is usually always first when it is used, that the one
  666.    chosen to start File.  
  667. */
  668.  
  669. /* Local procedure */
  670.  
  671. initsmenus(about)            /* init simpletools' menus */
  672. char *about;
  673. {
  674.     itemdatum **items;
  675.  
  676.     simplemenus = (menudatum **) NewHandle ( (long)sizeof(menudatum));
  677.     HLock (simplemenus);
  678.  
  679.     strcpy ( (**simplemenus).menuname, applestring);
  680.     (**simplemenus).menuId = 1;
  681.     (**simplemenus).next = (Ptr) 0L;
  682.     ctop ((**simplemenus).menuname);
  683.     (**simplemenus).menuhand = NewMenu (1, (**simplemenus).menuname);
  684.     ptoc ((**simplemenus).menuname);
  685.     HUnlock ((**simplemenus).menuhand);
  686.  
  687.     (**simplemenus).itemlist = (itemdatum **)NewHandle ( 
  688.             (long)sizeof(itemdatum));
  689.     items = (itemdatum **) (**simplemenus).itemlist;
  690.     HLock (items);
  691.  
  692.     strcpy ((**items).itemname, about);
  693.     (**items).itemno = 1;
  694.     (**items).menuId = 1;
  695.     (**items).menuhand = (**simplemenus).menuhand;
  696.     (**items).menurun = stnop;
  697.     (**items).next = 0L;
  698.     HUnlock (items);
  699.  
  700.     ctop (about);
  701.     AppendMenu ((**simplemenus).menuhand, about);
  702.     ptoc (about);
  703.     DisableItem ((**simplemenus).menuhand, 1);
  704.     menu (applestring, "-", (ProcPtr) itemdisable);
  705.     #ifdef MEGAMAX
  706.       AddResMenu ((**simplemenus).menuhand, "DRVR");
  707.     #else
  708.       AddResMenu ((**simplemenus).menuhand, 'DRVR');
  709.     #endif
  710.     InsertMenu ((**simplemenus).menuhand, 0);
  711.     HUnlock (simplemenus);
  712.  
  713.     menu ("File", "New", (ProcPtr)itemdisable);
  714.     menu ("Edit", "Undo", stnop);
  715.     menu ("Edit", "-", (ProcPtr)itemdisable);
  716.     menu ("Edit", "Cut/X", stnop);
  717.     menu ("Edit", "Copy/C", stnop);
  718.     menu ("Edit", "Paste/V", stnop);
  719.     menu ("Edit", "Clear", stnop);
  720. }
  721.  
  722. /* Local procedure */
  723.  
  724. #ifndef LIGHTSPEED
  725. gottrans () 
  726. {
  727.   char prog[80];
  728.   char *argv[3];
  729.   if ( getfile("APPL", prog) ) {
  730.     argv[1] = NULL;
  731.     execv (prog, argv);
  732.   }
  733. }
  734. #endif
  735.  
  736. /* Local procedure */
  737.  
  738. gotquit ()
  739. {
  740.   exit(0);
  741. }
  742.  
  743. /* This routine is for the Windows menu Item.  The Windows menu is
  744.    set up when new windows are added.  It is used to bring forward and
  745.    bring into view windows that may be under other windows or have been
  746.    sent hiding by a click on their close box.
  747. */
  748.  
  749. /* Local procedure */
  750.  
  751. showawindow(name)            /* show the named window    */
  752. char *name;
  753. {
  754.     WindowPtr foo;
  755.     foo = windowpoint(name);    /* get its window pointer    */
  756.     if ( foo ) {
  757.         ShowWindow(foo);    /* show it on the screen    */
  758.         SetPort (foo);        /* set further output to it */
  759.         if ( foo != FrontWindow())    /* if it isn't active,    */
  760.             SelectWindow (foo);    /* activate it         */
  761.     }
  762. }
  763.  
  764. /* Local procedure */
  765.  
  766. winddatum **wdatum(windpt)        /* return Handle to window data */
  767. WindowPtr windpt;
  768. {
  769.     winddatum **wind, **temp;
  770.  
  771.     if (firstwind) return ((winddatum **) 0L);
  772.     wind = simplewinds;
  773.     HLock (wind);
  774.  
  775.     while ( ((**wind).wptr != windpt) && (**wind).next) {
  776.         temp = wind;
  777.         wind = (winddatum **) (**wind).next;
  778.         HUnlock (temp);
  779.         HLock (wind);
  780.     }
  781.  
  782.     if ( (**wind).wptr == windpt) {
  783.         HUnlock (wind);
  784.         return (wind);
  785.     } else {
  786.         HUnlock (wind);
  787.         return ((winddatum **) 0L);    /* zero if not found */
  788.     }
  789. }
  790.   
  791. /* Local procedure */
  792.  
  793. runruns(event)            /* run all the installed run procedures    */
  794. EventRecord *event;        /* returns number of routines run     */
  795. {
  796.     int i=0;
  797.     WindowPtr saveport;
  798.     GetPort (&saveport);
  799.     while ( simpleruns[i] )
  800.         (*(simpleruns[i++])) (event);
  801.     SetPort (saveport);
  802.     return(i);
  803. }
  804.  
  805. /* Local procedure */
  806.  
  807. stdialog( question, answer, type)  /* a general dialog displayer     */
  808. char *question;
  809. char *answer;
  810. int  type;            /* type:  1=prompt, 2=message         */
  811. {
  812.     DialogPtr dialog;    /* dialog reference             */
  813.     Handle Item, items;    /* handles for the dialog items     */
  814.     Rect screen, box;    /* rectangles for dialog/items         */
  815.     int dtype, hit, canc;    /* Item type and which was hit         */
  816.     char tempanswer[255];    /* address where answer is         */
  817.  
  818.     items = NewHandle (512L);/* get memory for items list         */
  819.     HLock (items);        /* lock it down             */
  820.     if (type == 1)
  821.         BlockMove (quesd, *items, (long) QUESN * 2L); 
  822.     else
  823.         BlockMove (messd, *items, (long) MESSN * 2L);
  824.     SetRect (&screen, 103, 50, 409, 137);        
  825.     
  826.     /* For LIGHTSPEED, use a lower case d and upper case B and P    */
  827.     /* for DBoxProc.  Megamax conversion utility does this wrong.    */
  828.     
  829.     dialog = NewDialog (0L, &screen, "", 0, dBoxProc, -1L, 0, 0L, items);
  830.     GetDItem (dialog, 2, &dtype, &Item, &box);
  831.     ctop (question);    
  832.     SetIText (Item, question);        /* set Item#2 text     */
  833.     ptoc (question);
  834.     if (type == 1) {            /* set default answer    */
  835.         GetDItem (dialog, 3, &dtype, &Item, &box);
  836.         ptoc (answer);
  837.         SetIText (Item, answer);
  838.         ctop (answer);
  839.         canc = 4;
  840.     } else
  841.         canc = 3;
  842.     ShowWindow (dialog);            /* display the dialog    */
  843.     do {
  844.         ModalDialog (0L, &hit);        /* process the dialog    */
  845.     } while ( (hit != 1) & (hit != canc) );
  846.     if (type == 1) {
  847.         GetDItem (dialog, 3, &dtype, &Item, &box);
  848.         HLock (Item);
  849.         GetIText (Item, tempanswer);    /* get Item#3 text     */
  850.         ptoc (tempanswer);
  851.         strcpy (answer, tempanswer);    /* make a copy of it     */
  852.         HUnlock (Item);
  853.     }
  854.     HUnlock(items);                /* unlock items memory    */
  855.     HPurge(items);                /* purge it         */
  856.     DisposDialog (dialog);            /* get rid of dialog    */
  857.     return ( hit==1 );            /* return true if ok    */
  858. }  
  859.   
  860. /* Local procedures */
  861.  
  862. docommand (which, thisevent)
  863. long which;
  864. EventRecord *thisevent;
  865. {
  866.     int themenu, theitem;
  867.     long size;
  868.     char *cpoint;
  869.     GrafPtr tempport;
  870.     menudatum **here, **temp;
  871.     itemdatum **items, **tempitems;
  872.     char **myreshandle;
  873.     Handle myhandle;
  874.   
  875.     themenu = HiWord (which);
  876.     theitem = LoWord (which);
  877.     if ((themenu == 1) && (theitem != 1)) {
  878.   
  879.         /* start up a desk accessory */
  880.         HLock (simplemenus);
  881.         GetItem ((**simplemenus).menuhand, theitem, accname);
  882.         SetResLoad (FALSE);
  883.         #ifdef MEGAMAX
  884.           myreshandle = GetNamedResource ("DRVR", accname);
  885.         #else
  886.           myreshandle = GetNamedResource ('DRVR', accname);
  887.         #endif
  888.         SetResLoad (TRUE);
  889.         size = SizeResource (myreshandle);
  890.         myhandle = NewHandle ( size + 3072L);
  891.         if (myhandle == 0L) 
  892.             message ("Not enough memory to do that.");
  893.         else {
  894.             DisposHandle (myhandle);
  895.             GetPort (&tempport);
  896.             OpenDeskAcc(accname);
  897.             SetPort (tempport);
  898.         }
  899.         HUnlock (simplemenus);
  900.         return;
  901.     }
  902.     if (themenu ==3) {
  903.         /* do any system edits */
  904.         if (SystemEdit(theitem -1))  return;
  905.     }
  906.   
  907.     /* now we run an installed menu procedure */
  908.     here = simplemenus;
  909.     HLock (here);
  910.   
  911.     /* find out menu structure given the menu id */
  912.     while ( ((**here).menuId != themenu) && (**here).next) {
  913.         temp = here;
  914.         here = (menudatum **)(**here).next;
  915.         HUnlock (temp);
  916.         HLock (here);
  917.     }
  918.   
  919.     if ((**here).menuId == themenu) {
  920.   
  921.         /* now find the Item structure */
  922.         items = (**here).itemlist;
  923.         HUnlock (here);
  924.         HLock (items);
  925.  
  926.         while ( ((**items).itemno != theitem) && (**items).next) {
  927.             tempitems = items;
  928.             items = (itemdatum **)(**items).next;
  929.             HUnlock (tempitems);
  930.             HLock (items);
  931.         }
  932.   
  933.         /* prepare to give the Item name to the procedure */
  934.         cpoint = (**items).itemname;
  935.         if ((**items).itemno == theitem) 
  936.         /* if we found the Item, call its procedure */
  937.             (*((**items).menurun))(cpoint,thisevent) ;
  938.         HUnlock (items);
  939.     }
  940. }
  941.  
  942. /* Local procedure */
  943.  
  944. domousedown(thisevent)        /* respond to mouse down events */
  945. EventRecord *thisevent;        /* passed the event record */
  946. {
  947.     WindowPtr whichwindow;
  948.     int code, x, y;
  949.     char *cpoint;
  950.     menudatum **omhand;
  951.     winddatum **thewdatum;
  952.     long newplace;
  953.     Point temp;
  954.     GrafPtr saveport;
  955.  
  956.     code = FindWindow(ZZ(thisevent->where), &whichwindow);
  957.     switch (code) {
  958.         case inMenuBar:
  959.         docommand(MenuSelect(ZZ(thisevent->where)),thisevent);
  960.         break;
  961.         case inSysWindow:
  962.         SystemClick(thisevent, whichwindow); break;
  963.         case inDrag:
  964.         DragWindow(whichwindow, ZZ(thisevent->where),
  965.             &dragrect); break;
  966.         case inGrow:
  967.         newplace= GrowWindow(whichwindow, ZZ(thisevent->where),
  968.             &sizerect);
  969.         SizeWindow(whichwindow, LoWord(newplace), 
  970.         HiWord(newplace), TRUE);
  971.         if (sizeredraw) {
  972.             GetPort (&saveport);
  973.             SetPort (whichwindow);
  974.             EraseRect (&swholescreen);
  975.             InvalRect (&swholescreen);
  976.             SetPort (saveport);
  977.         }
  978.         break;
  979.         case inGoAway:
  980.         if ( TrackGoAway(whichwindow, ZZ(thisevent->where))) {
  981.             HideWindow (whichwindow);
  982.         }
  983.         break;
  984.         case inzoomout:
  985.         case inzoomin:
  986.             #ifdef MEGAMAX
  987.           if ( trackbox(whichwindow, ZZ(thisevent->where), code)) {
  988.             zoomwindow (whichwindow, code, 0);
  989.         #else
  990.           if ( TrackBox(whichwindow, ZZ(thisevent->where), code)) {
  991.             ZoomWindow (whichwindow, code, 0);
  992.         #endif
  993.             GetPort (&saveport);
  994.             SetPort (whichwindow);
  995.             EraseRect (&swholescreen);
  996.             InvalRect (&swholescreen);
  997.             SetPort (saveport);
  998.         }
  999.         break;
  1000.         case inContent:
  1001.         
  1002.         /* make the window active if it isn't yet */
  1003.         if (whichwindow != FrontWindow()) {
  1004.             SelectWindow(whichwindow);
  1005.         }
  1006.   
  1007.         /* find our window data */
  1008.         thewdatum = wdatum (whichwindow);
  1009.         if (thewdatum) {
  1010.           
  1011.             /* convert the Point of click to the window's
  1012.                own coordinates since this will be always
  1013.                more useful than the global coordintates */
  1014.             temp = thisevent->where;
  1015.             SetPort (whichwindow);
  1016.             GlobalToLocal (&temp);
  1017.             #ifdef MEGAMAX
  1018.               x = temp.a.h;
  1019.               y = temp.a.v;
  1020.             #else
  1021.               x = temp.h;
  1022.               y = temp.v;
  1023.             #endif
  1024.             
  1025.             /* call the window's in content routine */
  1026.             HLock (thewdatum);
  1027.             (*((**thewdatum).wcontent))(x, y, whichwindow,
  1028.                 thisevent);
  1029.             HUnlock (thewdatum);
  1030.         }
  1031.         break;
  1032.     }
  1033. }
  1034.             
  1035.  
  1036. /************************************************************************/
  1037. /*     GLOBAL ROUTINES INTENDED TO BE USER CALLABLE PROCEDURES        */
  1038. /* THE FOLLOWING PROCEDURES HAVE BEEN WRITTEN FOR THE USER'S         */
  1039. /* APPLICATION TO CALL.                            */
  1040. /*                                     */
  1041. /************************************************************************/
  1042.  
  1043. havenewrom ()            /* returns true if new roms installed    */
  1044. {
  1045.     return ((*((int *)ROM85)) == NEWROM);
  1046. }
  1047.  
  1048. /* Menu is usually called like:
  1049.  
  1050.         menu ("File", "Print...", got_print)
  1051.         
  1052.    where the first argument is the name appearing on the menubar.  The
  1053.    2nd argument is the name appearing when the menu is pulled down.  The
  1054.    3rd argument is USUALLY the routine to be called when the user
  1055.    selects this particular menu.  Non-existant menus are created following
  1056.    the last.  The menu ordering may never be changed once created.
  1057.    Existint menus have their "routine-to-be-executed" assignment changed
  1058.    to the new routine.  If the long values 0L, 1L, 2L, or 3L are passed
  1059.    instead of a procedure, the menu characteristic is set as specified
  1060.    by the constants itemdisable, itemenable, itemcheck, itemuncheck.  For
  1061.    example:
  1062.            menu ("File", "Print...", itemdisable)
  1063.         
  1064.    PROCEDURES ASSIGNED TO MENUS ARE CALLED WITH TWO ARGUMENTS.  YOU
  1065.    DO NOT NEED TO DECLARE THESE IN YOUR PROCEDURE IF YOU DO NOT USE
  1066.    THEM.  FOR EXAMPLE, GOT_PRINT MAY BE DECLARED AS:
  1067.    
  1068.            got_print()
  1069.         char *itemname;
  1070.         EventRecord *current_event;
  1071.         {
  1072.             ...
  1073.         }
  1074.         
  1075.    Itemname is a char* pointing to the Item name.  This allows the same
  1076.    menu procedure to be used for multiple menu/Item pairs.  Maybe your
  1077.    Size menu just as items 9 Point, 10 Point, 12 Point, etc.  This way
  1078.    you can specify the same procedure for each and determine what to do
  1079.    by looking at itemname.  
  1080.    
  1081.    Current_event is a pointer to the current EventRecord that detected
  1082.    the menu selection.  You may look at this as needed.
  1083. */
  1084.    
  1085. menu (name, Item, routine)        /* install or change a menu    */
  1086. char *name;                /* the menu name         */
  1087. char *Item;                /* the Item name         */
  1088. ProcPtr routine;            /* a procedure or modifier     */
  1089. {
  1090.     menudatum **here,**temp;    /* a roving Handle to our data     */
  1091.     menudatum **ourmhandle;        /* another Handle to our data     */
  1092.     itemdatum **items,**tempitems;    /* a Handle to the Item     */
  1093.     int lastid, lastitem;
  1094.     
  1095.     /* get the Handle to menu named 'name' */
  1096.     if ((ourmhandle = getourmenuhandle (name)) == 0L) {
  1097.     
  1098.         /* make a new menu entry by finding the end of the list */
  1099.         here = simplemenus;
  1100.         HLock (here);
  1101.         while ((**here).next) {
  1102.             temp = here;
  1103.             here = (menudatum **)(**here).next;
  1104.             HUnlock (temp);
  1105.             HLock (here);
  1106.         }
  1107.             
  1108.         /* make a structure for our new entry */
  1109.         lastid = (**here).menuId;
  1110.         (**here).next = (Ptr)NewHandle ( (long)sizeof(menudatum));
  1111.         temp = here;
  1112.         here = (menudatum **)(**here).next;
  1113.         HUnlock (temp);
  1114.         HLock (here);
  1115.  
  1116.         strcpy ( (**here).menuname, name);
  1117.         (**here).menuId = ++lastid;
  1118.         (**here).next = (Ptr) 0L;
  1119.         
  1120.         /* make a new Item structure */
  1121.         (**here).itemlist = (itemdatum **)NewHandle ( 
  1122.             (long)sizeof(itemdatum));
  1123.             
  1124.         /* make a new menu entry for the Macintosh */
  1125.         ctop (name);
  1126.         (**here).menuhand = NewMenu (lastid, name);
  1127.         ptoc (name);
  1128.         items = (**here).itemlist;
  1129.  
  1130.         HLock (items);
  1131.         strcpy ((**items).itemname, Item);
  1132.         (**items).itemno = 1;
  1133.         (**items).menuId = lastid;
  1134.         (**items).menuhand = (**here).menuhand;
  1135.         (**items).menurun = (ProcPtr) 0L;
  1136.         (**items).next = 0L;
  1137.         HUnlock (items);
  1138.         
  1139.         /* install and display the menu */
  1140.         ctop (Item);
  1141.         AppendMenu ((**here).menuhand, Item);
  1142.         ptoc (Item);
  1143.         InsertMenu ((**here).menuhand,0);
  1144.         HUnlock (here);
  1145.  
  1146.         setitems (items, routine);
  1147.         DrawMenuBar();
  1148.         return(TRUE);
  1149.     }
  1150.     else {
  1151.         HLock (ourmhandle);
  1152.  
  1153.         if (strlen(Item) == 0) {
  1154.           /* then adjust main menu */
  1155.           setitems( 0L - (long) ((**ourmhandle).menuhand), routine);
  1156.           return(FALSE);
  1157.         }
  1158.  
  1159.         /* see if Item is in list */
  1160.         items = (**ourmhandle).itemlist;
  1161.         HLock (items);
  1162.  
  1163.         while ( strcmp(Item,(**items).itemname) && (**items).next) {
  1164.             tempitems = items;
  1165.             items = (itemdatum **)(**items).next;
  1166.             HUnlock (tempitems);
  1167.             HLock (items);
  1168.         }
  1169.         if (strcmp(Item,(**items).itemname) ==0) {
  1170.             setitems( items, routine);
  1171.             return(FALSE);
  1172.         }
  1173.         else {
  1174.             /* make new Item entry */
  1175.             lastitem = (**items).itemno;
  1176.             (**items).next =(Ptr)NewHandle((long)sizeof(itemdatum));
  1177.             tempitems = items;
  1178.             items = (itemdatum **)(**items).next;
  1179.             HUnlock (tempitems);
  1180.             HLock (items);
  1181.  
  1182.             strcpy ((**items).itemname, Item);
  1183.             (**items).itemno = ++lastitem;
  1184.             (**items).menuId = (**ourmhandle).menuId;
  1185.             (**items).menuhand = (**ourmhandle).menuhand;
  1186.             (**items).menurun = (ProcPtr) 0L;
  1187.             (**items).next = 0L;
  1188.             HUnlock (items);
  1189.  
  1190.             /* and install the Item in the menu bar */
  1191.             ctop (Item);
  1192.             AppendMenu ((**ourmhandle).menuhand,Item);
  1193.             ptoc (Item);
  1194.             HUnlock (ourmhandle);
  1195.             setitems (items, routine);
  1196.             return(TRUE);
  1197.         }
  1198.     }
  1199. }
  1200.  
  1201. /* Given a menu name, return the real menu Handle as used by most
  1202.    of the Macintosh toolbox menu manager routines.
  1203. */
  1204.  
  1205. MenuHandle mhand (name)            /* find MenuHandle        */
  1206. char *name;                /* given name of menu         */
  1207. {
  1208.     menudatum    **menu;    
  1209.     MenuHandle    temp;        /* a Handle to our data     */
  1210.  
  1211.     menu = getourmenuhandle(name);
  1212.     if ( menu ) {
  1213.         HLock (menu);
  1214.         temp = (**menu).menuhand;
  1215.         HUnlock (menu);
  1216.         return ( temp );    /* return menu Handle         */
  1217.     } else
  1218.         return ( (MenuHandle) 0 );    
  1219. }
  1220.  
  1221.     
  1222. /*  Call this routine if you want these SimpleTools defined quiting    */
  1223. /*  procedures.  You may just install your own instead.     The time to    */
  1224. /*  call this is after you have installed all your other "File" items.    */
  1225. /*  By calling this last, you will place Transfer and Quit on the end    */
  1226. /*  of the menu list.                            */
  1227.  
  1228. simplequits ()
  1229. {
  1230.     menu ("File", "-", itemdisable);
  1231.     
  1232.     #ifndef LIGHTSPEED
  1233.     menu ("File", "Transfer.../T", gottrans);
  1234.     #endif
  1235.     
  1236.     menu ("File", "Quit/Q", gotquit);
  1237. }
  1238.  
  1239. /* Given a window's name, return its window pointer so that other
  1240.    Macintosh Window Manager routines can be called for that window. */
  1241.  
  1242. WindowPtr windowpoint(name)        /* get window pointer         */
  1243. char *name;                /* given window's name         */
  1244. {
  1245.     winddatum **wind, **tempwind;    /* Handle to our window data     */
  1246.     WindowPtr    temp;
  1247.  
  1248.     if (firstwind) return ((WindowPtr)0); 
  1249.     wind = simplewinds;        /* look for the named window     */
  1250.     HLock (wind);
  1251.  
  1252.     while ( strcmp ((**wind).windname, name) && (**wind).next) {
  1253.         tempwind = wind;
  1254.         wind = (winddatum **) (**wind).next;
  1255.         HUnlock (tempwind);
  1256.         HLock (wind);
  1257.     }
  1258.     if ( strcmp ((**wind).windname, name) ==0) {
  1259.         temp = (**wind).wptr;
  1260.         HUnlock (wind);
  1261.         return ( temp );    /* return pointer        */
  1262.     } else {
  1263.         HUnlock (wind);
  1264.         return ( (WindowPtr) 0);/* or zero if it wasn't found    */
  1265.     }
  1266. }
  1267.  
  1268. /* This routine installs a new window onto the screen.  It also gives
  1269.    that window an Item in the Window menu.  This routine is also used
  1270.    to modify a window's associated routines.  The x,y positions are the
  1271.    top left and bottom right corners of where the window should originally
  1272.    be placed.  The coordinates are never used when this routine is called
  1273.    to update an already existing window.  But the spaces must be filled,
  1274.    so you can use zeros if you want.  Once the window has been displayed in
  1275.    its original position, the user has complete control of its size and
  1276.    placement with the mouse.
  1277.    
  1278.    YOU MUST ASSIGN PROCEDURES TO BE CALLED WHEN SIMPLETOOLS DETECTS THAT
  1279.    THIS WINDOW IS BECOMMING ACTIVE, DEACTIVATING, NEEDS UPDATING, OR
  1280.    THE MOUSE HAS BEEN PRESSED IN ITS CONTENT.  JUST LIKE THE MENU PROCEDURE,
  1281.    THESE PROCEDURES ARE PASSED SOME ARGUMENTS.  YOU DO NOT HAVE TO 
  1282.    DECLARE THESE IF YOU DON'T WHAT TO USE THEM.  IF YOU USE THE ARGUMENTS,
  1283.    YOU WOULD DECLAR THESE PROCEDURES AS FOLLOWS:
  1284.    
  1285.        my_activate (windp, event)    same as my_update
  1286.     my_deactivate (windp, event)    same as my_update
  1287.     
  1288.     my_update (windp, event)
  1289.     WindowPtr     windp;        the window being acted upon
  1290.     EventRecord     *event;        the current event record
  1291.     {
  1292.         ...
  1293.     }
  1294.     
  1295.     my_inContent (x, y, windp, event)
  1296.     int         x, y;        mouse position in local coords
  1297.     WindowPtr     windp;        like above
  1298.     EventRecord     *event;        like above
  1299.     {
  1300.         ...
  1301.     }
  1302. */
  1303.  
  1304. window(name, xtop, ytop, xbot, ybot, a, d, u, c)
  1305. char *name;            /* window's name             */
  1306. int xtop, ytop, xbot, ybot;    /* position if this is a new window     */
  1307. ProcPtr a, d, u, c;        /* activate, deactivate, update, and     */
  1308. {                /*  content procedures          */
  1309.     winddatum **wind, **temp;/* Handle to our window data         */
  1310.     winddatum **newentry;    /* another Handle             */
  1311.     Rect newplace;        /* rectable for the window's placement    */
  1312.  
  1313.     if (a == (ProcPtr) 0)
  1314.         a = stnop;
  1315.     if (d == (ProcPtr) 0)
  1316.         d = stnop;
  1317.     if (u == (ProcPtr) 0)
  1318.         u = stnop;
  1319.     if (c == (ProcPtr) 0)
  1320.         c = stnop;
  1321.     if ( !firstwind ) {
  1322.  
  1323.         /* see if window is in the list */
  1324.         wind = simplewinds;
  1325.         HLock (wind);
  1326.  
  1327.         while ( strcmp ((**wind).windname, name) && (**wind).next) {
  1328.             temp = wind;
  1329.             wind = (winddatum **) (**wind).next;
  1330.             HUnlock (temp);
  1331.             HLock (wind);
  1332.         }
  1333.         if ( strcmp ((**wind).windname, name) ==0) {
  1334.  
  1335.             /* reset the found window's parameters */
  1336.             (**wind).wact = (ProcPtr) a;
  1337.             (**wind).wdeact = (ProcPtr) d;
  1338.             (**wind).wupdate = (ProcPtr) u;
  1339.             (**wind).wcontent = (ProcPtr) c;
  1340.             SetPort ( (**wind).wptr);        
  1341.             HUnlock (wind);
  1342.  
  1343.             return(FALSE);
  1344.         }
  1345.     }
  1346.  
  1347.     /* make a new window entry */
  1348.     newentry = (winddatum **)NewHandle ( (long) sizeof (winddatum));
  1349.     if (firstwind)
  1350.         simplewinds = newentry;
  1351.     else
  1352.         (**wind).next = (Ptr) newentry;
  1353.     firstwind = 0;
  1354.     HUnlock (wind);
  1355.     HLock (newentry);
  1356.  
  1357.     strcpy ((**newentry).windname, name);
  1358.     SetRect (&newplace, xtop, ytop, xbot, ybot);
  1359.     if (EmptyRect (&newplace)) 
  1360.         SetRect (&newplace, 10, 42, 500, 330);
  1361.     ctop (name);
  1362.     (**newentry).wptr = NewWindow (0L, &newplace, name, -1, 
  1363.         wprocid, -1L, dogoaway, newentry);
  1364.     ptoc (name);
  1365.     (**newentry).wact = (ProcPtr) a;
  1366.     (**newentry).wdeact = (ProcPtr) d;
  1367.     (**newentry).wupdate = (ProcPtr) u;
  1368.     (**newentry).wcontent = (ProcPtr) c;
  1369.     (**newentry).next = (Ptr) 0;
  1370.     if (windmenu)
  1371.         menu ("Windows", name, showawindow); 
  1372.     SetPort ( (**newentry).wptr);        
  1373.     HUnlock (newentry);
  1374.  
  1375.     return(TRUE);
  1376. }
  1377.  
  1378. withwindow(name)            /* set output to window by name    */
  1379. char *name;                /* give it the window's name     */
  1380. {                    /* returns if window exists    */
  1381.     winddatum **wind, **temp;
  1382.     wind = simplewinds;
  1383.     if (firstwind) return(FALSE);    /* search for the window's name */
  1384.  
  1385.     HLock (wind);
  1386.     while ( strcmp ((**wind).windname, name) && (**wind).next) {
  1387.         temp = wind;
  1388.         wind = (winddatum **) (**wind).next;
  1389.         HUnlock (temp);
  1390.         HLock (wind);
  1391.     }
  1392.     if ( strcmp ((**wind).windname, name) ==0) {
  1393.         SetPort ( (**wind).wptr);    /* set output to it     */
  1394.         HUnlock (wind);
  1395.         return(TRUE);
  1396.     } else {
  1397.         HUnlock (wind);
  1398.         return(FALSE);
  1399.     }
  1400. }
  1401.   
  1402. /* This run procedure is used to install routines to be occasionally
  1403.    run.  The routine will be run once for each call to simpleevents()
  1404.    which is done repeatedly by runsimpletools().
  1405.    
  1406.    EACH ROUTINE INSERTED INTO THE RUN LIST IS RUN MULTIPLE TIMES UNTIL
  1407.    IT IS REMOVED BY CALLING STOP.  THE ROUTINE IS CALLED WITH A SINGLE
  1408.    ARGUMENT, A POINTER TO THE EVENT JUST RETURNED BY GETNEXTEVENT() AND
  1409.    BEFORE SIMPLETOOLS PROCESSES IT.
  1410. */
  1411.  
  1412. run(routine)            /* install a run procedure     */
  1413. ProcPtr routine;        /* give it the procedure     */
  1414. {                /* return TRUE if successful     */
  1415.     int i;
  1416.     i = 0;            /* add it to the end of the list */
  1417.     while ( simpleruns[i] != (ProcPtr) 0L) i++;
  1418.     if (i < maxsruns) {
  1419.         simpleruns[i] = routine;
  1420.         simpleruns[i+1] = (ProcPtr) 0L;
  1421.         return(TRUE);
  1422.     } else
  1423.         return(FALSE);
  1424. }
  1425.  
  1426. /* This routine removes a procedure from the list of run procedures */
  1427.  
  1428. stop(routine)            /* stop a procedure from running*/
  1429. ProcPtr routine;        /* give the procedure         */
  1430. {                /* return TRUE if successful     */
  1431.     int i = 0;
  1432.     while ( (simpleruns[i] != routine) && simpleruns[i])  i++;
  1433.     if (simpleruns[i]) {
  1434.         while ( simpleruns[i] != (ProcPtr)0 ) {
  1435.             simpleruns[i] = simpleruns[i+1];
  1436.             i++;
  1437.         }
  1438.         return(TRUE);
  1439.     } else {
  1440.         return(FALSE);
  1441.     }
  1442. }
  1443.  
  1444. home ()                /* text-based home of the pen with
  1445.                    the window being erased.        */
  1446. {
  1447.     GrafPtr    port;
  1448.     GetPort (&port);
  1449.     EraseRect (&(port->portRect));
  1450.     stgotoxy (1, 1);
  1451. }
  1452.  
  1453. stgotoxy (x, y)                /* goto text position x, y    */
  1454. int x, y;    
  1455. {
  1456.     Point        pt;
  1457.     int        newx, newy;
  1458.     FontInfo    font;
  1459.   
  1460.     GetFontInfo (&font);
  1461.     GetPen (&pt);
  1462.     #ifdef MEGAMAX
  1463.     if (x < 0) 
  1464.         newx = pt.a.h;
  1465.     else
  1466.         newx = font.widMax * (x);
  1467.     if (y < 0)
  1468.         newy = pt.a.v;
  1469.     #else
  1470.     if (x < 0) 
  1471.         newx = pt.h;
  1472.     else
  1473.         newx = font.widMax * (x);
  1474.     if (y < 0)
  1475.         newy = pt.v;
  1476.     #endif
  1477.     else
  1478.         newy = (font.ascent + font.descent + font.leading) * (y+1);
  1479.     MoveTo (newx, newy);
  1480. }
  1481.  
  1482. /* The getline procedure is to be called when you want to simply get a Line
  1483.    of text from the user at the current pen position on the screen.  You
  1484.    will probably preceed this with a call to stgotoxy(x,y).  You would call
  1485.    it like:    
  1486.            getline ("Erik", name);
  1487.         
  1488.    where name is a character array.  This works MUCH better than scanf()
  1489.    or gets() since it uses the Macintosh TextEdit routines to allow the
  1490.    user to edit the Line being input.
  1491.    
  1492.    Getline is very "modal" and no other events are handled while the
  1493.    user is expected to enter the Line.  Getline returns ONLY when the
  1494.    user presses <RETURN>.  
  1495.    
  1496.    Routines scheduled to run by the run() routine are called.  Make sure
  1497.    your run routines don't strip all <RETURNS> from the event record
  1498.    they get or getline will never stop.
  1499. */
  1500.    
  1501. getline (dfault, destination)        /* using TE, get a Line        */
  1502. char *dfault, *destination;        /* default string, dest     */
  1503. {
  1504.     TEHandle         hte;
  1505.     Rect            destRect;
  1506.     Point            pen,pt;
  1507.     FontInfo        FInfo;
  1508.     int            done, mask, code, in_already, nextcap;
  1509.     GrafPtr            port, window;
  1510.     EventRecord        event;
  1511.     char            key;
  1512.     CursHandle        c;
  1513.     
  1514.     GetPort (&port);        /* Calculate Rect for TE    */
  1515.     if (port != FrontWindow())  SelectWindow (port);
  1516.     GetPen (&pen);
  1517.     GetFontInfo (&FInfo);
  1518.     #ifdef MEGAMAX
  1519.         SetRect (&destRect, pen.a.h, pen.a.v - FInfo.ascent,
  1520.             1000, pen.a.v + FInfo.descent);
  1521.     #else
  1522.         SetRect (&destRect, pen.h, pen.v - FInfo.ascent,
  1523.             1000, pen.v + FInfo.descent);
  1524.     #endif
  1525.     EraseRect (&destRect);
  1526.     hte = TENew (&destRect, &destRect);    
  1527.     TESetText (dfault, (long)strlen(dfault), hte);
  1528.     TEActivate (hte);
  1529.     TEUpdate (&destRect, hte);
  1530.     mask = mDownMask + keyDownMask + autoKeyMask + mUpMask;
  1531.     done = FALSE;
  1532.     #ifdef MEGAMAX
  1533.       c = GetCursor (ibeamcursor);
  1534.     #else
  1535.       c = GetCursor (iBeamCursor);
  1536.     #endif
  1537.     in_already = FALSE;
  1538.     nextcap = getlinecaps;
  1539.     do {                /* "modal" loop until <cr>    */
  1540.         SystemTask ();
  1541.         TEIdle (hte);
  1542.         
  1543.         GetNextEvent (mask, &event);
  1544.         runruns (&event);
  1545.         GetMouse (&pt);        /* use I beam in TE        */
  1546.         if (PtInRect (ZZ(pt), &destRect)) {
  1547.           if ( ! in_already )  {
  1548.              SetCursor (*c);
  1549.              in_already = TRUE;
  1550.           }
  1551.         } else {
  1552.           if ( in_already ) {
  1553.               InitCursor ();
  1554.               in_already = FALSE;
  1555.           }
  1556.         }
  1557.         switch (event.what) {
  1558.             case mouseDown:
  1559.             code = FindWindow (ZZ(event.where),&window);
  1560.             if ((code == inContent) && (window == port)) {
  1561.                GlobalToLocal (&event.where);
  1562.                 if (PtInRect(ZZ(event.where),&destRect))
  1563.                     TEClick (ZZ(event.where), 0, hte);
  1564.                 else SysBeep (1);
  1565.             } else SysBeep (20);
  1566.             break;
  1567.             case keyDown:
  1568.             case autoKey:
  1569.                 key = (char) (event.message & 0xFFL);
  1570.             if (nextcap && (key >= 'a') && (key <= 'z')) 
  1571.                 key -= ' ';
  1572.             nextcap = FALSE;
  1573.             if (key == ' ') nextcap = getlinecaps;
  1574.             if (key != '\r')  TEKey (key, hte);
  1575.             else  done = TRUE;
  1576.             break;
  1577.         }
  1578.     } while (!done);
  1579.     TEDeactivate (hte);
  1580.     
  1581.     /* For LIGHTSPEED, use a lowercase te and upper case L in    */
  1582.     /* TElength.  Megamax conversion utility does this wrong too.    */
  1583.     
  1584.     strncpy (destination, *TEGetText(hte), (*hte)->teLength);
  1585.     destination[(*hte)->teLength] = 0;
  1586.  
  1587.     TEDispose (hte);
  1588.         InitCursor ();
  1589. }
  1590.  
  1591. /*  Use prompt when you want a tiny window to pop up to ask the user
  1592.     a question.  The question is drawn and a TextEdit box is provided
  1593.     to get the answer.  Whatever the user leaves in the answer box
  1594.     is returned in answer.  Two buttons are also displayed:  OK and
  1595.     CANCEL.  Prompt returns TRUE or FALSE depending on which Button was
  1596.     pressed.
  1597. */
  1598.  
  1599. prompt ( question, answer)        /* dialog box question/answer */
  1600. char *question;
  1601. char *answer;
  1602. {
  1603.     return (stdialog (question, answer, 1));
  1604. }
  1605.  
  1606. /* Message is just like prompt except no answer box is displayed.  An
  1607.    OK and CANCEL Button works just like prompt.
  1608. */
  1609.  
  1610. message ( message )            /* dialog box message         */
  1611. char *message;
  1612. {
  1613.     return (stdialog (message, message, 2));
  1614. }
  1615.   
  1616. /*  This routine is a simpler whay to call the toolbox SFGetFile()
  1617.     routine.  Simple call this like:
  1618.     
  1619.             getfile ("TEXT", filename)
  1620.         
  1621.     where filename is a character array.  Replace TEXT with whatever
  1622.     file type you desire.  The file manager's working directory is set
  1623.     correctly so that a subsequent open() call with filename will work.
  1624. */
  1625.  
  1626. getfile (ftype, reply)
  1627. char ftype[];
  1628. char reply[];
  1629. {
  1630.     Point where;
  1631.     SFReply frommac;
  1632.     
  1633.     #ifdef MEGAMAX
  1634.       where.a.h = 75; where.a.v = 50;
  1635.     #else
  1636.       where.h = 75; where.v = 50;
  1637.     #endif
  1638.     if (strlen(ftype) != 4)
  1639.       SFGetFile (ZZ(where), NULL, NULL, -1, NULL, NULL, &frommac);
  1640.     else
  1641.       SFGetFile (ZZ(where), NULL, NULL, 1, ftype, 0L, &frommac);
  1642.     if (frommac.good) {
  1643.       SetVol ("", frommac.vRefNum);
  1644.       strcpy (reply, frommac.fName);
  1645.       return (TRUE);
  1646.     }
  1647.     else return (FALSE);
  1648. }
  1649.  
  1650. /* This is like getfile, but may get a new file name from the user.
  1651.    Origname is the default you want to present to the user.
  1652. */
  1653.  
  1654. putfile (origname,reply)
  1655. char *origname;
  1656. SFReply *reply;
  1657. {
  1658.     Point where;
  1659.     SFReply frommac;
  1660.     
  1661.     #ifdef MEGAMAX
  1662.       where.a.h = 75; where.a.v = 50;
  1663.     #else
  1664.       where.h = 75; where.v = 50;
  1665.     #endif
  1666.     SFPutFile (ZZ(where), "", origname, 0L, &frommac);
  1667.     if (frommac.good) {
  1668.       SetVol ("", frommac.vRefNum);
  1669.       strcpy (reply, frommac.fName);
  1670.       return (TRUE);
  1671.     }
  1672.     return (FALSE);
  1673. }
  1674.  
  1675. /* This routine initializes SimpleTools and MUST be called before    */
  1676. /* most of the other SimpleTools routines are called.            */
  1677. /* The passed about string is the menu Item name to appear just under    */
  1678. /* the Apple menu.  This will be disabled and can be enabled using    */
  1679. /* a menu() call.  This routine also initializes the Macintosh         */
  1680. /* for application execution and desk accessory processing.        */
  1681.  
  1682. simpletools(about)    /* to be called at the beginning of program     */
  1683. char *about;
  1684. {
  1685.     #ifdef MEGAMAX
  1686.       maxapplzone();    /* allow maximum heap expansion     */
  1687.     #else
  1688.       MaxApplZone();
  1689.     #endif
  1690.     FlushEvents (everyEvent,0);  /* ignore left over events     */
  1691.     InitGraf (&thePort);    /* initialize the screen         */
  1692.     InitFonts();        
  1693.     InitWindows();
  1694.     InitMenus();
  1695.     InitCursor();        /* make the arrow Cursor         */
  1696.     TEInit();
  1697.     InitDialogs(0L);
  1698.     snewrom = havenewrom();
  1699.     
  1700.     /* Ugh.  For LightSpeed use a lower case d in DocumentProc.    */
  1701.     /* Megamax conversion utility is at fault here.            */
  1702.     
  1703.     wprocid = documentProc;
  1704.     if (snewrom) wprocid = zoomproc;
  1705.     SetRect ( &sizerect, 20, 50, 250, 330);
  1706.     simpleruns[0] = (ProcPtr) 0;  /* empty the run list         */
  1707.  
  1708.     /* These are the bounds we are allowed to size a window or
  1709.        Move a window to.  
  1710.     */
  1711.  
  1712.     swholescreen = dragrect = thePort -> portRect;
  1713.     InsetRect (&dragrect, 4, 4);
  1714.     SetRect ( &sizerect, 20, 20, 2048, 700);
  1715.     firstwind = 1;            /* empty window table        */
  1716.     keydownproc = stnop;        /* default key hit procedures     */
  1717.     autokeyproc = stnop;
  1718.     initsmenus(about);        /* install the menus         */
  1719. }
  1720.  
  1721. simpleevents()                /* to be called in the main loop */
  1722. {
  1723.     EventRecord newevent;
  1724.     winddatum **thewdatum;
  1725.     SystemTask();            /* Do the system D.A. etc. stuff */
  1726.     HiliteMenu(0);
  1727.     GetNextEvent(everyEvent, &newevent);
  1728.     runruns(&newevent);        /* Do our run procedures     */
  1729.     switch (newevent.what) {
  1730.         case mouseDown:
  1731.         domousedown(&newevent); break;
  1732.         case keyDown: 
  1733.         if (newevent.modifiers & cmdKey)
  1734.             docommand(MenuKey((char)(newevent.message & 0xffL)),
  1735.                 &newevent);
  1736.         (*(keydownproc))(&newevent);
  1737.          break;
  1738.         case autoKey: 
  1739.         if (newevent.modifiers & cmdKey)
  1740.             docommand(MenuKey((char)(newevent.message & 0xffL)),
  1741.                 &newevent);
  1742.         (*(autokeyproc))(&newevent);
  1743.         break;
  1744.         case activateEvt: 
  1745.         thewdatum = wdatum(newevent.message);
  1746.         if (thewdatum) {
  1747.             SetPort(newevent.message);
  1748.             HLock (thewdatum);
  1749.             if (newevent.modifiers & 1) {
  1750.  
  1751.                 (*((**thewdatum).wact))(newevent.message, 
  1752.                     &newevent);
  1753.             } else {
  1754.                 (*((**thewdatum).wdeact))(newevent.message,
  1755.                     &newevent);
  1756.             }
  1757.             HUnlock (thewdatum);
  1758.         }
  1759.         break;
  1760.         case updateEvt:
  1761.         thewdatum = wdatum(newevent.message);
  1762.         if (thewdatum) {
  1763.             SetPort (newevent.message);
  1764.             BeginUpdate (newevent.message);
  1765.             HLock (thewdatum);
  1766.             (*((**thewdatum).wupdate))(newevent.message,
  1767.                 &newevent);
  1768.             HUnlock (thewdatum);
  1769.             EndUpdate (newevent.message);
  1770.         }
  1771.         break;
  1772.     }
  1773. }
  1774.  
  1775. runsimpletools ()
  1776. {
  1777.     for (;;) simpleevents();
  1778. }
  1779.  
  1780.  
  1781.