home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / sampleda.pit / SampleDA.pit / Sample.c < prev    next >
Encoding:
Text File  |  1985-11-16  |  24.9 KB  |  1,004 lines

  1. /*    Sample desk accessory using DA.h     (tabs=4) */
  2.  
  3. /*    (C) Copyright 1985 by Roy A. Leban
  4.  *
  5.  * This program is free.  It is not, however, Public Domain.
  6.  * You may distribute it free of charge to anyone, provided that
  7.  * this comment, as well as the copyright notice is left intact.
  8.  * If you modify this sample program and distribute it, you
  9.  * must include comments to indicate which changes are yours.
  10.  * You may not sell this source file without my permission.
  11.  * You may, however, modify this program and incorporate into
  12.  * any Desk Accessory you want (which you may sell if you wish).
  13.  * If you do so, you must include a credit notice which says:
  14.  *        "Portions of this program Copyright 1985 by Roy A. Leban"
  15.  * You must include this notice whether or not you sell the DA.
  16.  * If you distribute the source to your DA in any fashion, you
  17.  * must include this entire comment.  You may, of course, include
  18.  * any copyright of your own, with any appropriate notice.
  19.  * You may not publish this DA in any magazine, electronic, printed
  20.  * or otherwise, without my permission.  This does not include posting
  21.  * on public or private bulletin boards or conferencing systems.
  22.  *
  23.  */
  24.  
  25. /*
  26.  * This program is designed to be a simple Desk Accessory which
  27.  * implements all the parts of a DA.  Basically, it does nothing,
  28.  * but it does it very well.  It includes support for all events,
  29.  * Horizontal and Vertical Scroll Bars and the Grow Box.  More
  30.  * Controls can be added fairly easily.  The entire DA fits in
  31.  * approximately 5K.  It is written for Manx Aztec C and
  32.  * has been completely tested with version 1.06F.  It should work
  33.  * fine with other C compilers as well, but I don't know what changes
  34.  * would be necessary.  Obviously, the header file might need to
  35.  * be changed to pass the arguments correctly.  Most of the
  36.  * functionality is fairly obvious.  Comments are placed where
  37.  * things may not be so clear.  Routines which have no functionality
  38.  * in the sample DA, such as Cut/Copy/Paste and MouseEvent (in content),
  39.  * have a call to the routine NotUsed(), which simply calls SysBeep(1).
  40.  * In a functioning DA, you should modify the NotUsed function as
  41.  * appropriate or remove it entirely. I can't guarantee this code is
  42.  * perfect, but I have written several sophisticated DA's based
  43.  * on it.  If you have questions, you can call or write me at:
  44.  *        Roy A. Leban
  45.  *        314 Packard, #3
  46.  *        Ann Arbor, Michigan  48104
  47.  *        (313)761-5869
  48.  * I'll try to help if I can, but I won't write your DA's for you.
  49.  * Have fun.
  50.  *
  51.  */
  52.  
  53. /*
  54.  * Notes on the Driver Flags and Data:
  55.  *
  56.  *    dNeedLock
  57.  *        This is necessary for re-entrant DA's to work
  58.  *        properly, because of a problem in the Desk Manager.
  59.  *        When the inner call returns, the Desk Manager unlocks
  60.  *        the driver, not noticing the outer call.
  61.  *    dNeedTime
  62.  *        This causes drvrCtl to get called frequently without
  63.  *        user intervention, useful for doing things like 
  64.  *        calling TEIdle.  drvrDelay contains the frequency
  65.  *        in Clock Ticks.  Note that you may not get called
  66.  *        that frequently, depending on the Application, but
  67.  *        you won't be called more frequently.  A drvrDelay 
  68.  *        of 0 means you'll get called as often as possible.
  69.  *    dNeedGoodBye
  70.  *        Means that your application gets a GoodBye "kiss"
  71.  *        if the Application quites while your DA is open.
  72.  *    dCtlEnable
  73.  *        Enables the drvrCtl (Control) calls.
  74.  *    drvrEMask
  75.  *        This is the mask of events you'll handle.  You'll
  76.  *        get Update and Activate Events no matter what.
  77.  */
  78.  
  79. #asm
  80. drvrFlags    equ    $7400        ; drvrFlags: dNeedLock + dNeedTime +
  81.                             ;             dNeedGoodBye + dCtlEnable
  82. drvrDelay    equ    6            ; drvrDelay: Call every 1/10th second
  83. drvrEMask    equ    $002A        ; drvrEMask: MouseDown + KeyDown + AutoKey
  84. #endasm
  85.  
  86. #include    <DA.h>
  87.  
  88.  
  89. #define    _DRIVER
  90. #include    <types.h>
  91. #include    <quickdraw.h>
  92. #include    <toolutil.h>
  93. #include    <window.h>
  94. #include    <control.h>
  95. #include    <menu.h>
  96. #include    <memory.h>
  97. #include    <osutil.h>
  98. #include    <event.h>
  99. #include    <resource.h>
  100. #include    <packages.h>
  101. #include    <pb.h>
  102. #include    <desk.h>
  103. #include    <scrap.h>
  104.  
  105. #define    NULL    0L
  106.  
  107. /*
  108.  * General note concerning data:  If you have pre-initialized data
  109.  * which you modify, it may not be restored when the DA is restarted.
  110.  * It is only restored if the driver is flushed from memory.
  111.  */
  112.  
  113. /*
  114.  * The following hex data defines a + cursor which will appear
  115.  * inside the DA window.  This hex data was extracted from a
  116.  * ResEdit "Open General" box.  You can also use CURS resources
  117.  * if you wish.
  118.  */
  119. static Cursor theCursor = {
  120. 0x0000, 0x0100, 0x0100, 0x0100,
  121. 0x0100, 0x0100, 0x0100, 0x7FFC,
  122. 0x0100, 0x0100, 0x0100, 0x0100,
  123. 0x0100, 0x0100, 0x0000, 0x0000,
  124. 0x0000, 0x0000, 0x0000, 0x0000,
  125. 0x0000, 0x0000, 0x0000, 0x0000,
  126. 0x0000, 0x0000, 0x0000, 0x0000,
  127. 0x0000, 0x0000, 0x0000, 0x0000,
  128. 0x0007, 0x0007 };
  129.  
  130. static int theID;                        /* DA resource information */
  131. static ResType theType;
  132. static Str255 theName;
  133.  
  134. static char Active = FALSE;                /* DA Window Active */
  135.  
  136. #define    BufferSize    1L                    /* Size of extra buffer */
  137. #define    ExtraSpace    2048L                /* Extra space needed to execute */
  138.  
  139. static Handle BufferHandle;                /* Same as dCtl->dCtlStorage */
  140. static char *BufferPtr;                    /* Valid while buffer locked */
  141. static int NLock;                        /* Number of LockBuffers */
  142.  
  143. static WindowRecord deskRecord;            /* Window Record for DA Window */
  144. static Rect StdSize =      { 50, 50, 250, 250};    /* Change as desired */
  145. static Rect SizeLimits = { 80, 80, 300, 500};
  146. static int Width;
  147. static int Height;
  148.  
  149. #define    QuitItem        1                /* See Menu in Sample.r */
  150. #define    AboutItem        3
  151. static int MenuRsrc;                    /* Resource ID of Menu */
  152. static MenuHandle DeskMenu = NULL;        /* Handle of menu */
  153. static char MenuPresent = FALSE;        /* Menu is currently enabled */
  154. static char KeepMenu;                    /* Keep menu during dialog box */
  155.  
  156. #define    GrowBoxSize        16
  157. static char Grow = TRUE;                /* Grow Box exists */
  158. static char GrowDrawn;                    /* Grow Box has been drawn */
  159. static Rect GrowBox;                    /* Box for CursorSelect */
  160.  
  161. #define    ControlWidth    16
  162. #define enableControl    0
  163. #define    disableControl    255
  164. static char Vflag = TRUE;                /* Vertical Scroll Bar exists */
  165. static char Hflag = TRUE;                /* Horizontal Scrol Bar exists */
  166. static ControlHandle Vscroll,Hscroll;    /* Handles for Scroll Bars */
  167. static Rect Vbox,Hbox;                    /* Boxes for CursorSelect */
  168. static int Vvalue,Hvalue;                /* Current Scroll Bar Values */
  169. static int Vinit = 0;                    /* Arbitrary values.. */
  170. static int Vmin = 0;                    /* ..Change these as appropriate */
  171. static int Vmax = 100;
  172. static int Vpage = 20;
  173. static int Hinit = 0;
  174. static int Hmin = 0;
  175. static int Hmax = 100;
  176. static int Hpage = 20;
  177.  
  178. static GrafPort *infoWindow;
  179. static WindowRecord infoRecord;
  180. static Rect infoSize =    { 80, 106, 255, 406 };
  181. static PicHandle infoPicture;
  182. static int infoPICT;
  183.  
  184. static Rect tempRect;
  185.  
  186. /* Declarations of routines that return values */
  187. WindowPtr GetDeskWindow();
  188. Str255 *PascalString();
  189. char *CString();
  190. char Truth();
  191.  
  192.  
  193. drvrOpen(dCtl,Pb)
  194.   register DCEPtr dCtl;
  195.   register ParmBlkPtr Pb;
  196. {
  197.   register WindowPtr deskWindow;
  198.   int bit;
  199.  
  200.     if (dCtl->dCtlWindow != NULL) {        /* Window allocated already? */
  201.         SelectWindow(dCtl->dCtlWindow);    /* Yes..bring to front */
  202.         Active = TRUE;
  203.         return;
  204.         }
  205.  
  206.     GetResInfo(dCtl->dCtlDriver,&theID,&theType,&theName);
  207.     MenuRsrc = -16384 + (32 * theID) + 0;    /* DA Menu */
  208.     infoPICT = -16384 + (32 * theID) + 1;    /* About... Picture, if any */
  209.     /* Rsrc2 = -16384 + (32 * theID) + 2; */
  210.  
  211.     if (!AllocBuffers(dCtl)) {        /* Try to Allocate Buffer(s) */
  212.         Active = FALSE;
  213.         SysBeep(3);                    /* Not enough memory - Don't Load */
  214.         return;
  215.         }
  216.  
  217.     deskWindow = GetDeskWindow(dCtl->dCtlRefNum);
  218.  
  219.     GetDeskMenu(dCtl);
  220.  
  221.     ControlInit(deskWindow);
  222.     GrowInit();
  223.     GrowIcon(deskWindow);
  224.  
  225.     Enable(deskWindow);
  226.     Refresh(deskWindow,TRUE);
  227.  
  228.     dCtl->dCtlWindow = deskWindow;    /* Other routines can now execute */
  229.     Active = TRUE;                    /* ..and Window is active */
  230.     }
  231.  
  232. drvrPrime(dCtl,Pb)
  233.   register DCEPtr dCtl;
  234.   register ParmBlkPtr Pb;
  235. {
  236.     /* Should never get called in a DA */
  237.     }
  238.  
  239. drvrCtl(dCtl,Pb)
  240.   register DCEPtr dCtl;
  241.   register ParmBlkPtr Pb;
  242. {
  243.   register int code;
  244.   Point pos;
  245.  
  246.     if (dCtl->dCtlWindow == NULL)    /* Check if we have a window yet.. */
  247.         return;                        /* If not..drvrOpen hasn't finished */
  248.  
  249.     code = Pb->u.cp.csCode;
  250.  
  251.     /*
  252.      * Special case the Cursor Select events, since they're so
  253.      * frequent.  We get called all the time, not just while our
  254.      * window is active.  If the DA isn't the active window, we
  255.      * return immediately.
  256.      */
  257.     if (code == accCursor) {
  258.         if (Active) {
  259.             CursorSelect(dCtl,Pb);
  260.             return;
  261.             }
  262.         }
  263.  
  264.     /*
  265.      * Set the Port to our window, unless it's GoodBye, in
  266.      * which case it's possible that the application blindly
  267.      * closed our window for us.
  268.      */
  269.     if (code != -1)
  270.         SetPort(dCtl->dCtlWindow);
  271.  
  272.     switch(code) {
  273.         case accRun:        RunEvent(dCtl,Pb);        break;
  274.         case accEvent:        DeskEvent(dCtl,Pb);        break;
  275.         case accMenu:        MenuEvent(dCtl,Pb);        break;
  276.         case accUndo:        UndoEvent(dCtl,Pb);        break;
  277.         case accCut:        CutEvent(dCtl,Pb);        break;
  278.         case accCopy:        CopyEvent(dCtl,Pb);        break;
  279.         case accPaste:        PasteEvent(dCtl,Pb);    break;
  280.         case accClear:        ClearEvent(dCtl,Pb);    break;
  281.         case -1:            GoodBye(dCtl,Pb);        break;
  282.         }
  283.     }
  284.     
  285. drvrStatus(dCtl,Pb)
  286.   register DCEPtr dCtl;
  287.   register ParmBlkPtr Pb;
  288. {
  289.     /* Should never get called in a DA */
  290.     }
  291.  
  292. drvrClose(dCtl,Pb)
  293.   register DCEPtr dCtl;
  294.   register ParmBlkPtr Pb;
  295. {
  296.   register WindowPtr deskWindow;
  297.  
  298.     if (dCtl->dCtlWindow == NULL)
  299.         return;
  300.  
  301.     deskWindow = dCtl->dCtlWindow;
  302.     dCtl->dCtlWindow = NULL;
  303.  
  304.     ReleaseBuffers(dCtl);
  305.     QuitWindow(deskWindow);
  306.     if (MenuPresent)
  307.         RemoveMenu();
  308.     }
  309.  
  310.  
  311. /*
  312.  *    Event Management (called by drvrCtl)
  313.  */
  314.  
  315. CursorSelect(dCtl,Pb)
  316.   register DCEPtr dCtl;
  317.   register ParmBlkPtr Pb; 
  318. {
  319.   Point loc;
  320.  
  321.     SetPort(dCtl->dCtlWindow);
  322.     GetMouse(&loc);
  323.  
  324.     if (PtInRect(pass(loc), &(dCtl->dCtlWindow->portRect))) {
  325.         /*
  326.          * If the mouse is in the window, see if it's in a control
  327.          * or the Grow Box.  If it is, then the cursor should be the
  328.          * normal cursor anyway.  The Grow Box area is checked if
  329.          * there isn't a Grow Box, but both Scroll Bars exist,
  330.          * in which case the space is empty.
  331.          */
  332.         if ((Grow || (Vflag && Hflag)) && PtInRect(pass(loc),&GrowBox))
  333.             InitCursor();
  334.         else if (Vflag && PtInRect(pass(loc),&Vbox))
  335.             InitCursor();
  336.         else if (Hflag && PtInRect(pass(loc),&Hbox))
  337.             InitCursor();
  338.         else
  339.             SetCursor(&theCursor);
  340.         }
  341.     else {
  342.         InitCursor();
  343.         }
  344.     }
  345.  
  346. RunEvent(dCtl,Pb)
  347.   register DCEPtr dCtl;
  348.   register ParmBlkPtr Pb; 
  349. {
  350.     /*
  351.      * This is the routine called if dNeedTime is set.
  352.      * We don't call NotUsed() here because that would cause
  353.      * an almost continuous beep to be sounded.
  354.      */
  355.     }
  356.  
  357. DeskEvent(dCtl,Pb)
  358.   register DCEPtr dCtl;
  359.   register ParmBlkPtr Pb; 
  360. {
  361.   register EventRecord *e;
  362.   register WindowPtr deskWindow;
  363.  
  364.     e = *(EventRecord **)&Pb->u.cp.csParam;
  365.  
  366.     switch (e->what) {
  367.         case mouseDown:
  368.             MouseEvent(dCtl,Pb,&(e->where));
  369.             break;
  370.         case keyDown:
  371.             KeyEvent(dCtl,Pb,FALSE);
  372.             break;
  373.         case autoKey:
  374.             KeyEvent(dCtl,Pb,TRUE);
  375.             break;
  376.         case activateEvt:
  377.             if (e->modifiers & 1)
  378.                 Enable(dCtl->dCtlWindow);
  379.             else
  380.                 Disable(dCtl->dCtlWindow);
  381.             break;
  382.         case updateEvt:
  383.             deskWindow = dCtl->dCtlWindow;
  384.             BeginUpdate(deskWindow);
  385.             GrowIcon(deskWindow);
  386.             DrawControls(deskWindow);
  387.             Refresh(deskWindow,FALSE);
  388.             EndUpdate(deskWindow);
  389.             break;
  390.         default:
  391.             SysBeep(1);
  392.             break;            /* Shouldn't get any other events */
  393.         }
  394.     }
  395.  
  396. MenuEvent(dCtl,Pb)                        /* Menu selection made */
  397.   register DCEPtr dCtl;
  398.   register ParmBlkPtr Pb; 
  399. {
  400.   int theItem;
  401.   WindowPtr deskWindow;
  402.  
  403.     theItem = ((int *)&Pb->u.cp.csParam)[1];
  404.  
  405.     switch(theItem) {
  406.         case QuitItem:
  407.             CloseDeskAcc(dCtl->dCtlRefNum);        /* Strange, but it works */
  408.             break;
  409.         case AboutItem:
  410.             About(dCtl->dCtlWindow);
  411.             break;
  412.         }
  413.  
  414.     HiliteMenu(0);
  415.     } /* MenuEvent */
  416.  
  417. UndoEvent(dCtl,Pb)
  418.   register DCEPtr dCtl;
  419.   register ParmBlkPtr Pb;
  420. {
  421.     NotUsed();
  422.     }
  423.  
  424. CutEvent(dCtl,Pb)
  425.   register DCEPtr dCtl;
  426.   register ParmBlkPtr Pb;
  427. {
  428.     NotUsed();
  429.     }
  430.  
  431. CopyEvent(dCtl,Pb)
  432.   register DCEPtr dCtl;
  433.   register ParmBlkPtr Pb;
  434. {
  435.     NotUsed();
  436.     }
  437.  
  438. PasteEvent(dCtl,Pb)
  439.   register DCEPtr dCtl;
  440.   register ParmBlkPtr Pb;
  441. {
  442.     NotUsed();
  443.     }
  444.  
  445. ClearEvent(dCtl,Pb)
  446.   register DCEPtr dCtl;
  447.   register ParmBlkPtr Pb;
  448. {
  449.     NotUsed();
  450.     }
  451.  
  452. GoodBye(dCtl,Pb)
  453.   register DCEPtr dCtl;
  454.   register ParmBlkPtr Pb;
  455. {
  456.     /*
  457.      * Called when the Application quits without closing the
  458.      * DA.  It's a good idea to check if the window still
  459.      * exists before using it, as it may have been closed by
  460.      * the application.  Because of this, drvrCtl does not
  461.      * do a SetPort before calling this routine.  Note that
  462.      * QuitWindow checks to make sure the window still exists
  463.      * before disposing of it.
  464.      */
  465.     QuitWindow(dCtl->dCtlWindow);
  466.     }
  467.  
  468. /*
  469.  *  Secondary Event Routines
  470.  */
  471.  
  472. MouseEvent(dCtl,Pb,locp)
  473.   register DCEPtr dCtl;
  474.   register ParmBlkPtr Pb; 
  475.   Point *locp;
  476. {
  477.   Point loc;
  478.   int code,page,offset;
  479.   long GrowVal;
  480.   ControlHandle whichControl;
  481.   char flag;
  482.   int CurVal,MinVal,MaxVal,NewVal,*valp;
  483.  
  484.     loc = *locp;
  485.     SetPort(dCtl->dCtlWindow);
  486.     GlobalToLocal(&loc);        /* Convert to window-relative */
  487.  
  488.     code = FindControl(pass(loc),dCtl->dCtlWindow,&whichControl);
  489.  
  490.     /*
  491.      * If you have any other controls, you need to insert code
  492.      * to check for them here.
  493.      */
  494.     if (whichControl == Vscroll)
  495.         valp = &Vvalue;
  496.     else
  497.         valp = &Hvalue;
  498.     if (code == inThumb) {                        /* Pressed in thumb */
  499.         code = TrackControl(whichControl,pass(loc),-1L);
  500.         if (code != 0) {
  501.             *valp = GetCtlValue(whichControl);
  502.             Refresh(dCtl->dCtlWindow,FALSE);
  503.             }
  504.         return;
  505.         }
  506.     else if ((code == inUpButton) || (code == inDownButton) ||
  507.              (code == inPageUp)   || (code == inPageDown)) {
  508.         if (whichControl == Vscroll)
  509.             page = Vpage;
  510.         else
  511.             page = Hpage;
  512.         switch (code) {
  513.             case inUpButton:    offset = -1;        break;
  514.             case inDownButton:    offset = 1;            break;
  515.             case inPageUp:        offset = -page;        break;
  516.             case inPageDown:    offset = page;        break;
  517.             }
  518.         flag = TRUE;
  519.         while (flag) {
  520.             if (TestControl(whichControl,pass(loc)) == code) {
  521.                 HiliteControl(whichControl,code);
  522.                 CurVal = GetCtlValue(whichControl);
  523.                 MinVal = GetCtlMin(whichControl);
  524.                 MaxVal = GetCtlMax(whichControl);
  525.                 NewVal = CurVal + offset;
  526.                 if ((NewVal > MinVal && NewVal < MaxVal) ||
  527.                     (CurVal != MinVal && CurVal != MaxVal)) {
  528.                     SetCtlValue(whichControl,NewVal);
  529.                     *valp = GetCtlValue(whichControl);
  530.                     Refresh(dCtl->dCtlWindow,FALSE);
  531.                     }
  532.                 }
  533.             else {
  534.                 HiliteControl(whichControl,0);
  535.                 }
  536.             GetMouse(&loc);
  537.             flag = StillDown();
  538.             }
  539.         HiliteControl(whichControl,0);
  540.         return;
  541.         }
  542.  
  543.     if (Grow && PtInRect(pass(loc),&GrowBox)) {        /* In grow box? */
  544.         LocalToGlobal(&loc);                /* GrowWindow wants global */
  545.         GrowVal = GrowWindow(dCtl->dCtlWindow,pass(loc),&SizeLimits);
  546.         if (GrowVal != 0) {
  547.             Width = (int)(GrowVal & 0xFFFF);
  548.             Height = (int)(GrowVal >> 16);
  549.             SizeWindow(dCtl->dCtlWindow,Width,Height,TRUE);
  550.             GrowIcon(dCtl->dCtlWindow);            /* Draw new Grow Box */
  551.             ChangeControls(dCtl->dCtlWindow);    /* Draw new controls */
  552.             Refresh(dCtl->dCtlWindow,FALSE);    /* Refresh window */
  553.             }
  554.         return;
  555.         }
  556.  
  557.     /* Mouse pressed in content */
  558.     NotUsed();
  559.  
  560.     }
  561.  
  562. KeyEvent(dCtl,Pb,autoFlag)
  563.   register DCEPtr dCtl;
  564.   register ParmBlkPtr Pb; 
  565.   char autoFlag;                /* TRUE if from AutoKey event */
  566. {
  567.     NotUsed();
  568.     }
  569.  
  570. About(oldWindow)
  571.   WindowPtr oldWindow;
  572. {
  573.   Handle tempHandle;
  574.   long size;
  575.   char pic;
  576.  
  577.     HideCursor();
  578.     infoWindow = NewWindow(&infoRecord, &infoSize, "\P",
  579.             TRUE, altDBoxProc, -1L, FALSE, 6L);
  580.     SelectWindow(infoWindow);
  581.     ShowWindow(infoWindow);
  582.     SetPort(infoWindow);
  583.     SetResLoad(FALSE);
  584.     infoPicture = GetResource('PICT',infoPICT);        /* Picture? */
  585.     if (infoPicture == NULL) {
  586.         pic = FALSE;                                /* No picture */
  587.         SetResLoad(TRUE);
  588.         }
  589.     else {
  590.         size = SizeResource(infoPicture);
  591.         SetResLoad(TRUE);
  592.         tempHandle = NewHandle(size+256);
  593.         if (tempHandle != 0L) {
  594.             pic = TRUE;                                /* Picture available */
  595.             DisposHandle(tempHandle);
  596.             }
  597.         else {
  598.             pic = FALSE;                            /* Not enough memory */
  599.             }
  600.         }
  601.     if (pic) {
  602.         LoadResource(infoPicture);
  603.         DrawPicture(infoPicture,&(*infoPicture)->picFrame);
  604.         }
  605.     else {
  606.         /*
  607.          * This code gets executed if you don't have an Info
  608.          * Picture, or if there's not enough memory to load it.
  609.          * Replace this with your About... message.  If you
  610.          * don't want a Picture, you can remove the code above.
  611.          */
  612.         TextFont(0);    /* Chicago */
  613.         TextFace(0);    /* Normal */
  614.         TextSize(12);    /* 12 Point */
  615.         CenterString(50,300,"\PSample DA by Roy A. Leban");
  616.         CenterString(130,300,"\P\251Copyright 1985 by Roy A. Leban");
  617.         }
  618.  
  619.     while (!Button())
  620.         ;        /* Wait until button pressed - any animation goes here */
  621.     while (Button())
  622.         ;        /* ... and released */
  623.     FlushEvents(mDownMask+mUpMask,0);
  624.     HideWindow(infoWindow);
  625.     SetPort(oldWindow);
  626.     CloseWindow(infoWindow);
  627.     ShowCursor();
  628.     }
  629.  
  630. CenterString(y,width,s)
  631.   int y,width;
  632.   Str255 *s;
  633. {
  634.   int swidth;
  635.  
  636.     swidth = StringWidth(s);
  637.     MoveTo((width-swidth)/2,y);
  638.     DrawString(s);
  639.     }
  640.  
  641. /*
  642.  *    Window Management Routines
  643.  */
  644.  
  645. WindowPtr GetDeskWindow(RefNum)
  646.   int RefNum;
  647. {
  648.   register WindowPtr deskWindow;
  649.  
  650.     deskWindow = NewWindow(&deskRecord, &StdSize, "\PSample",
  651.                    TRUE, documentProc, -1L, TRUE, NULL);
  652.     SetPort(deskWindow);
  653.     ((WindowPeek)deskWindow)->windowKind = RefNum;
  654.  
  655.     Width = StdSize.right-StdSize.left;
  656.     Height = StdSize.bottom-StdSize.top;
  657.  
  658.     GrowDrawn = FALSE;
  659.     }
  660.  
  661. Enable(deskWindow)                    /* Enable Window */
  662.   register WindowPtr deskWindow;
  663. {
  664.     GrowIcon(deskWindow);
  665.     Hilite(enableControl);
  666.     AddMenu();
  667.     Active = TRUE;
  668.     }
  669.  
  670. Disable(deskWindow)                    /* Disable Window */
  671.   register WindowPtr deskWindow;
  672. {
  673.     GrowIcon(deskWindow);
  674.     Hilite(disableControl);
  675.     Active = FALSE;
  676.     RemoveMenu();
  677.     }
  678.  
  679. Refresh(deskWindow,firstFlag)        /* Refresh Window */
  680.   register WindowPtr deskWindow;
  681.   char firstFlag;
  682. {
  683.     /*
  684.      * This is called in several places: When the window
  685.      * is created; when an Update event occurs and when
  686.      * one of the scroll bars is scrolled or the window is
  687.      * resized.  The firstFlag parameter is TRUE if this
  688.      * is the first time Refresh is being called (right
  689.      * after the window is opened).  Refresh should
  690.      * perform whatever action is necessary to draw the
  691.      * window contents.  It also may be desirable to call
  692.      * this routine in other places to keep the places where
  693.      * the window contents are changed centralized.
  694.      */
  695.     NotUsed();
  696.     }
  697.  
  698. QuitWindow(deskWindow)                /* Close window if it still exists */
  699.   register WindowPtr deskWindow;
  700. {
  701.   register WindowPtr tempWindow;
  702.  
  703.     tempWindow = FrontWindow();
  704.     while (tempWindow != NULL && tempWindow != deskWindow)
  705.         tempWindow = ((WindowPeek)tempWindow)->nextWindow;
  706.     if (tempWindow != NULL) {
  707.         KillControls(deskWindow);        /* Not really necessary */
  708.         CloseWindow(deskWindow);
  709.         }
  710.     }
  711.  
  712. /*
  713.  *    Menu Management Routines
  714.  *
  715.  *    The KeepMenu flag should be set whenever a dialog box
  716.  *    is used as a result of a Menu Selection.  This will
  717.  *    result in the menu remaining highlighted during the
  718.  *    dialog box (and until the menu action is completed).
  719.  */
  720.  
  721. GetDeskMenu(dCtl)
  722.   register DCEPtr dCtl;
  723. {
  724.     DeskMenu = GetMenu(MenuRsrc);
  725.     dCtl->dCtlMenu = MenuRsrc;            /* Change to avoid collision */
  726.     (*DeskMenu)->menuID = MenuRsrc;        /* Use Resource ID for Menu ID */
  727.     MenuPresent = FALSE;
  728.     KeepMenu = FALSE;
  729.     /*
  730.      * It is necessary to perform any initial enabling, disabling
  731.      * or checking of menu items now, because the Menu isn't reloaded
  732.      * each time the DA is restarted.  Thus, the menu will appear as
  733.      * it did the last time the DA was closed.
  734.      */
  735.     }
  736.  
  737. AddMenu() {                                /* Add Scissors menu */
  738.     if (!KeepMenu) {
  739.         InsertMenu(DeskMenu, 0);        /* Add new menu at end */
  740.         DrawMenuBar();
  741.         MenuPresent = TRUE;
  742.         }
  743.     }
  744.  
  745. RemoveMenu() {                            /* Remove Scissors menu */
  746.     if (!KeepMenu) {
  747.         DeleteMenu(MenuRsrc);
  748.         DrawMenuBar();
  749.         MenuPresent = FALSE;
  750.         }
  751.     }
  752.  
  753. /*
  754.  *    Control and Grow Box Management Routines
  755.  *
  756.  *    The Control routines are grouped with the Grow Box support
  757.  *    routines because there is a lot of interaction between them.
  758.  *
  759.  *    The Control routines will draw vertical and horizontal scroll
  760.  *    bars if Vflag and Hflag are TRUE.  If there is only one
  761.  *    control and no grow box, the control extends the full width
  762.  *    or height of the window.  Controls may be changed on the fly
  763.  *    by changing Vflag or Hflag and calling ChangeControls.
  764.  *    To change the control values, change Vvalue and/or Hvalue
  765.  *    and call ChangeControls.  Note that the controls exist
  766.  *    even if they're not used.
  767.  *
  768.  *    GrowIcon draws the Grow Box, if Grow is TRUE.  Note
  769.  *    that it draws only the Grow Box and not the scroll bar
  770.  *    lines.  The Grow Box may be modified on the fly by
  771.  *    changing Grow and calling GrowIcon.  This routine should
  772.  *    be called when the window changes size or Grow is changed.
  773.  */
  774.  
  775. ControlInit(deskWindow)
  776.   WindowPtr deskWindow;
  777. {
  778.     ControlSize();
  779.  
  780.     Vvalue = Vinit;
  781.     Hvalue = Hinit;
  782.  
  783.     Vscroll = NewControl(deskWindow, &Vbox, "\P", Truth(Vflag),
  784.                          Vinit, Vmin, Vmax, scrollBarProc, 0L);
  785.     Hscroll = NewControl(deskWindow, &Hbox, "\P", Truth(Hflag),
  786.                          Hinit, Hmin, Hmax, scrollBarProc, 1L);
  787.     }
  788.     
  789. Hilite(n)
  790.   int n;
  791. {
  792.     HiliteControl(Vscroll,n);
  793.     HiliteControl(Hscroll,n);
  794.     }
  795.     
  796. ChangeControls(deskWindow)
  797.   register WindowPtr deskWindow;
  798. {
  799.   Rect v,h;
  800.   char vf,hf;
  801.  
  802.     v = Vbox;                    /* Old Locations */
  803.     h = Hbox;
  804.  
  805.     ControlSize();
  806.  
  807.     vf = !EqualRect(&v,&Vbox);        /* TRUE if moved or resized */
  808.     hf = !EqualRect(&h,&Hbox);
  809.  
  810.     /* Hide before changing.  Note that HideControl alters the Grow Box */
  811.     if (vf || !Vflag) {
  812.         HideControl(Vscroll);
  813.         if (GrowDrawn) ShowGrowIcon(deskWindow);
  814.         }
  815.     if (hf || !Hflag ) {
  816.         HideControl(Hscroll);
  817.         if (GrowDrawn) ShowGrowIcon(deskWindow);
  818.         }
  819.  
  820.     if (vf) {
  821.         MoveControl(Vscroll,Vbox.left,Vbox.top);
  822.         SizeControl(Vscroll,16,Vbox.bottom-Vbox.top);
  823.         }
  824.     if (hf) {
  825.         MoveControl(Hscroll,Hbox.left,Hbox.top);
  826.         SizeControl(Hscroll,Hbox.right-Hbox.left,16);
  827.         }
  828.  
  829.     SetCtlValue(Vscroll,Vvalue);
  830.     SetCtlValue(Hscroll,Hvalue);
  831.  
  832.     if (Vflag) {
  833.         ShowControl(Vscroll);
  834.         ValidRect(&Vbox);
  835.         }
  836.     if (Hflag) {
  837.         ShowControl(Hscroll);
  838.         ValidRect(&Hbox);
  839.         }
  840.     }
  841.  
  842. ControlSize() {
  843.     /* This code must be adjusted if you change the origin */
  844.     SetRect(&Vbox, Width-ControlWidth+1,-1,
  845.             Width+1,Height-ControlWidth+2);
  846.     SetRect(&Hbox, -1,Height-ControlWidth+1,
  847.             Width-ControlWidth+2,Height+1);
  848.  
  849.     if (!Grow) {                /* No Grow Box - see if only one control */
  850.         if (!Vflag)                /* If so..the Control expands. */
  851.             Hbox.right += GrowBoxSize;
  852.         else if (!Hflag)
  853.             Vbox.bottom += GrowBoxSize;
  854.         }
  855.     }
  856.  
  857. GrowInit() {
  858.     SetRect(&GrowBox,0,0,0,0);
  859.     GrowDrawn = FALSE;
  860.     }
  861.  
  862. GrowIcon(deskWindow)
  863.   register WindowPtr deskWindow;
  864. {
  865.     if (GrowDrawn) {                    /* Erase previous Grow Box */
  866.         if (Vflag) ++GrowBox.top;
  867.         if (Hflag) ++GrowBox.left;
  868.         EraseRect(&GrowBox);
  869.         InvalRect(&GrowBox);
  870.         GrowDrawn = FALSE;
  871.         }
  872.  
  873.     /* This code must be adjusted if you change the origin */
  874.     SetRect(&GrowBox, Width-GrowBoxSize+1,Height-GrowBoxSize+1,
  875.                       Width,Height);
  876.  
  877.     if (Grow) {
  878.         if ((Vflag || Hflag) && !(Vflag && Hflag))
  879.             ChangeControls(deskWindow);
  880.         ShowGrowIcon(deskWindow);
  881.         GrowDrawn = TRUE;
  882.         }
  883.     else if (Vflag && Hflag) {        /* Erase space between Scroll Bars */
  884.         tempRect = GrowBox;
  885.         ++tempRect.top;
  886.         ++tempRect.left;
  887.         EraseRect(&tempRect);
  888.         ValidRect(&GrowBox);
  889.         GrowDrawn = FALSE;
  890.         }
  891.     else if (Vflag || Hflag) {        /* Control expands to cover Grow area */
  892.         ChangeControls(deskWindow);
  893.         ValidRect(&GrowBox);
  894.         GrowDrawn = FALSE;
  895.         }
  896.     else {                            /* No Grow Box; No space reserved */
  897.         GrowDrawn = FALSE;
  898.         }
  899.     }
  900.  
  901. ShowGrowIcon(deskWindow)
  902.   register WindowPtr deskWindow;
  903. {
  904.   RgnHandle oldClip;
  905.  
  906.     oldClip = NewRgn();
  907.     GetClip(oldClip);
  908.     ClipRect(&GrowBox);
  909.     DrawGrowIcon(deskWindow);
  910.     SetClip(oldClip);
  911.     DisposeRgn(oldClip);
  912.     ValidRect(&GrowBox);
  913.     }
  914.  
  915. /*
  916.  *    Buffer Management Routines.
  917.  *
  918.  *    The LockBuffers and UnlockBuffers routines should be
  919.  *    called whenever it is desired to make heavy use of
  920.  *    the buffer.  After a LockBuffers, the variable BufferPtr
  921.  *    will contain a pointer to the actual buffer.  Note that
  922.  *    Lock/Unlock calls may be nested, if desired.  This is
  923.  *    essential for re-entrant code to work correctly.
  924.  */
  925.  
  926. AllocBuffers(dCtl)                /* Allocate buffer space */
  927.   register DCEPtr dCtl;
  928. {
  929.   int i;
  930.   Handle tempHandle;
  931.  
  932.     NLock = 0;
  933.     BufferHandle = NewHandle(BufferSize);
  934.     if (BufferHandle != NULL) {
  935.         tempHandle = NewHandle(ExtraSpace);        /* Space for stack, etc.? */
  936.         if (tempHandle != NULL) {
  937.             DisposHandle(tempHandle);
  938.             dCtl->dCtlStorage = BufferHandle;
  939.             return(TRUE);
  940.             }
  941.         DisposHandle(BufferHandle);
  942.         }
  943.     dCtl->dCtlStorage = NULL;
  944.     return(FALSE);                /* Couldn't allocate anything */
  945.     }
  946.  
  947. ReleaseBuffers(dCtl)                /* Release the bitmap image */
  948.   register DCEPtr dCtl;
  949. {
  950.     DisposHandle(BufferHandle);
  951.     dCtl->dCtlStorage = NULL;
  952.     NLock = 0;
  953.     }
  954.  
  955. LockBuffers(dCtl)                    /* Lock buffers while it's in use */
  956.   register DCEPtr dCtl;
  957. {
  958.     ++NLock;
  959.     HLock(BufferHandle);
  960.     BufferPtr = *(char **)BufferHandle;
  961.     }
  962.  
  963. UnlockBuffers(dCtl)                    /* Unlock Buffers when not in use */
  964.   register DCEPtr dCtl;
  965. {
  966.     if (NLock == 0 || --NLock == 0) {
  967.         HUnlock(BufferHandle);
  968.         }
  969.     }
  970.  
  971.  
  972. /* General Purpose Utility Routines */
  973.  
  974. static char StringBuffer[256];
  975.  
  976. NotUsed() {
  977.     SysBeep(1);
  978.     }
  979.  
  980. /* Convert C String to Pascal string and return */
  981. Str255 *PascalString(str)
  982.   char *str;
  983. {
  984.     strcpy(StringBuffer,str);
  985.     ctop(StringBuffer);
  986.     return(StringBuffer);
  987.     }
  988.  
  989. /* Convert Pascal String to C string and return */
  990. char *CString(str)
  991.   char *str;
  992. {
  993.     strncpy(StringBuffer,str,256);
  994.     ptoc(StringBuffer);
  995.     return(StringBuffer);
  996.     }
  997.  
  998. /* Used for calling ToolBox routines with C char flags */
  999. char Truth(value)
  1000.   char value;
  1001. {
  1002.     return(value?TRUE:FALSE);
  1003.     }
  1004.