home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.01 Jan 90 / MacTutor Help Source / Code Resource Version / Source Code / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-22  |  45.9 KB  |  1,293 lines  |  [TEXT/KAHL]

  1. /***********************************************************************\
  2. | Purpose :: This is the CODE RESOURCE version of the MacTutor Help        |
  3. |             facility.  It is language independent, and can be used in    |
  4. |             any development system which gives proper access to the    |
  5. |             Macintosh toolbox.                                            |
  6. |-----------------------------------------------------------------------|
  7. |        Copyright © Joe Pillera, 1990.  All Rights Reserved.            |
  8. |    Copyright © MacTutor Magazine, 1990.  All Rights Reserved.            |
  9. \***********************************************************************/
  10.  
  11. #include "help.h"
  12. #include <SetUpA4.h>
  13.  
  14. /* Global variables */
  15. static  ListHandle  My_List_Handle;       /* Handle for a list in the dialog         */
  16. static  Rect           List_Rect;             /* Rectangle (user-item) of topic list     */
  17. static    Rect        Display_Rect;        /* Rectangle (user-item) of the display */
  18. static    Rect        Scroller_Rect;        /* Rectangle (computed) of scroll bar    */
  19. static     Rect        Dest_Rect;            /* Destination of TE rectangle            */
  20. static    Rect        View_Rect;            /* Actual viewing region of text        */
  21. static    Rect        Frame_Rect;            /* The rectangle to frame for text        */
  22. static  int            Help_Topic;            /* What topic does user want info on?    */
  23. static  int            Current_Pict;        /* Latest picture ID being displayed    */
  24. static  DialogPtr    helpPtr;            /* Pointer to the help dialog box        */
  25. static  TEHandle    myTEHandle;            /* The TE Manager data structure        */
  26. static  Handle        myTEXTHandle;        /* My handle to the TEXT resource        */
  27. static  ViewMode    Last_Type;            /* Was last one a pict or text?            */ 
  28. static    ControlHandle myControl;        /* Handle to the text scroller            */
  29. static     GrafPtr        savePort;            /* Save a pointer to the old grafport    */
  30. static    int            refnum;                /* Result of trying to open help file    */
  31.  
  32. /* Keep track of the screen types */
  33. static    ViewMode    screen_mode[ MAX_TOPICS ];
  34.  
  35. /* Number of user's help topics */
  36. static    int            Number_Of_Topics;
  37.  
  38. /* Disable his menus */
  39. static    int            First_Menu;
  40. static    int            Last_Menu;
  41.  
  42. /* Array traversal constants */
  43. static    int            START;
  44. static    int            FINIS;
  45.  
  46. /* Log positions of 'PICT' & 'TEXT' resources */
  47. static    Str255        topic_name[ MAX_TOPICS ];
  48. static    int            resource_start[ MAX_TOPICS ];
  49. static    int            resource_end[ MAX_TOPICS ];
  50.  
  51.  
  52. /***********************************************************************\
  53. |                   void  Add_List_String( theString, theList )                |
  54. |-----------------------------------------------------------------------|
  55. | Purpose :: To add a (pascal) string to a specified list.                |
  56. |-----------------------------------------------------------------------|
  57. | Arguments ::                                                            |
  58. |     theString    -> Pascal string to add.                                |
  59. |     theList        -> Pointer to the target list.                            |
  60. |-----------------------------------------------------------------------|
  61. | Returns :: void.                                                        |
  62. \***********************************************************************/
  63.  
  64. static void  Add_List_String( theString, theList )
  65. Str255   *theString;                    
  66. ListHandle   theList;                   
  67.     short   theRow;         /* The Row that we are adding     */
  68.     Point   cSize;          /*  Pointer to a cell in a list */
  69.  
  70.     if (theList != NIL) {
  71.         cSize.h = 0;                    
  72.         theRow = LAddRow(1, 32000, theList);
  73.         cSize.v = theRow;               
  74.         LSetCell((*theString + 1), *theString[0], cSize,theList);
  75.         LDraw(cSize, theList);          
  76.     } 
  77. }
  78.  
  79.  
  80. /***********************************************************************\
  81. |                     void  Bold_Button( dPtr, itemNum )                    |
  82. |-----------------------------------------------------------------------|
  83. | Purpose :: To draw a thick black line around any dialog box item.        |
  84. |-----------------------------------------------------------------------|
  85. | Arguments ::                                                            |
  86. |     dPtr    -> Pointer to an already opened window.                        |
  87. |     itemNum    -> Item within the dialog to highlight.                        |
  88. |-----------------------------------------------------------------------|
  89. | Returns :: void.                                                        |
  90. \***********************************************************************/
  91.  
  92. static void Bold_Button( dPtr, itemNum )
  93. DialogPtr    dPtr;
  94. int            itemNum;
  95.  {
  96.      Rect        iBox;            /* The rectangle for the button        */
  97.      int            iType;            /* Type of dialog item                */
  98.      Handle        iHandle;        /* Pointer to the item                */
  99.      PenState    oldPenState;    /* Preserve the old drawing state    */
  100.      
  101.      SystemTask();
  102.      SetPort(dPtr);
  103.      GetPenState(&oldPenState);
  104.      GetDItem(dPtr, itemNum, &iType, &iHandle, &iBox);
  105.      InsetRect(&iBox, -4, -4);
  106.      PenSize(3,3);
  107.      FrameRoundRect(&iBox, 16, 16);
  108.      SetPenState(&oldPenState);
  109.  }
  110.  
  111.  
  112. /***********************************************************************\
  113. |                 void  Center_Window( theWindow, bumpUp )                |
  114. |-----------------------------------------------------------------------|
  115. | Purpose :: To center a currently opened - but still invisible -         |
  116. |             window on the screen.  Once the window is centered, it     |
  117. |             should then be made visible for the user.                    |
  118. |-----------------------------------------------------------------------|
  119. | Arguments ::                                                            |
  120. |     theWindow    -> Pointer to an already opened window.                    |
  121. |     bumpUp        -> A percentage from center to move the window up.        |
  122. |                   Sometimes a perfectly centered window (bumpUp=0) is    |
  123. |                   annoying to a user, so I provide this facility. Note    |
  124. |                   that a negative value will push the window down.        |
  125. |    isModeless    -> If so, add an additional 20 pixels for the drag bar. |
  126. |-----------------------------------------------------------------------|
  127. | Returns :: void.                                                        |
  128. \***********************************************************************/
  129.  
  130. static void Center_Window(theWindow,bumpUp,isModeless)
  131. DialogPtr    theWindow;
  132. int            bumpUp;
  133. Boolean        isModeless;
  134.  {
  135.     Rect    tempRect;       /* Temporary rectangle                     */
  136.     int        pixels;            /* Raise from center this amount        */
  137.     int        menuBar = 20;    /* Compensate 20 pixels for menu bar    */
  138.     
  139.     /* Compute centering information */
  140.      tempRect.top = theWindow->portRect.top;
  141.     tempRect.left = theWindow->portRect.left;
  142.     tempRect.bottom = theWindow->portRect.bottom;
  143.     tempRect.right = theWindow->portRect.right;
  144.     tempRect.top = ((screenBits.bounds.bottom + menuBar + (isModeless ? 20 : 0) - 
  145.                      screenBits.bounds.top) - (tempRect.bottom - tempRect.top)) / 2;
  146.     tempRect.left = ((screenBits.bounds.right - screenBits.bounds.left) - 
  147.                     (tempRect.right - tempRect.left)) / 2;
  148.  
  149.     /* Apply any bump-up factor */
  150.     pixels = tempRect.top * (bumpUp / 100.0);
  151.     tempRect.top = tempRect.top - pixels;
  152.  
  153.     /* Now center window & make it visible */
  154.     MoveWindow(theWindow, tempRect.left, tempRect.top, TRUE);
  155.     SetPort(theWindow);              
  156.   }
  157.   
  158.  
  159. /***********************************************************************\
  160. |                           Boolean Create_Help( void )                        |
  161. |-----------------------------------------------------------------------|
  162. | Purpose :: To bring up and initialize MacTutor Help.                    |
  163. |-----------------------------------------------------------------------|
  164. | Arguments :: None.                                                    |
  165. |-----------------------------------------------------------------------|
  166. | Returns :: TRUE if all went well, FALSE otherwise.                      |
  167. \***********************************************************************/
  168.  
  169. static Boolean Create_Help()
  170. {
  171.     int            whatHit;            /* The DITL item the user selected            */
  172.     int            DType;                 /* Type of dialog item                         */
  173.     Point       cSize;              /* Pointer to a cell in a list              */
  174.     Rect        tempRect;           /* Temporary rectangle                         */
  175.     Rect        dataBounds;         /* Rect to setup the list                      */
  176.     Handle       DItem;                /* Handle to the dialog item                 */
  177.     FontInfo       ThisFontInfo;        /* Used to determine List element height      */
  178.     int            index;                /* Loop thru the topic list names            */
  179.      Rect        iBox;                /* The rectangle for the next/prev buttons    */
  180.      int            iType;                /* Type of dialog item (button)                */
  181.      Handle        iHandle;            /* Pointer to the item                        */
  182.  
  183.  
  184.     /* -- Preserve pointer to former graf port -- */
  185.     GetPort(&savePort);
  186.     
  187.     /* -- First make sure the help file is out there! -- */
  188.     refnum = OpenResFile("\pHelp Data");
  189.     if (refnum == NOT_FOUND) {
  190.       helpPtr = GetNewDialog(Help_Not_Found, NIL, FRONT);
  191.       Center_Window( helpPtr,50, FALSE );
  192.       ShowWindow(helpPtr);
  193.       Bold_Button( helpPtr, OK_Button );
  194.       SysBeep(1);
  195.       ModalDialog(NIL, &whatHit);
  196.       DisposDialog(helpPtr);
  197.       SetPort(savePort);
  198.       return(FALSE);
  199.     }
  200.     
  201.     /* Set up pointers to the introduction screen */
  202.     Help_Topic = START;
  203.     Current_Pict = resource_start[START];
  204.     Last_Type = screen_mode[START];
  205.     
  206.     /* -- Bring up the help screen -- */
  207.     helpPtr = GetNewDialog(Help_Window, NIL, FRONT);
  208.     Center_Window(helpPtr,0,TRUE);
  209.     ShowWindow(helpPtr);           
  210.     SelectWindow(helpPtr);         
  211.     SetPort(helpPtr);          
  212.     Bold_Button(helpPtr,OK_Button);
  213.     
  214.     /* Hide the next & previous buttons for the intro screen */
  215.     GetDItem(helpPtr, Next_Button, &iType, &iHandle, &iBox);
  216.     HideControl((ControlHandle)iHandle);
  217.     GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &iBox);
  218.     HideControl((ControlHandle)iHandle);
  219.     
  220.     /* -- Disable the "Next" & "Previous" buttons for now -- */
  221.     Set_Button_State( Next_Button, FALSE );
  222.     Set_Button_State( Prev_Button, FALSE );
  223.  
  224.     /* -- Now build the list -- */
  225.     GetDItem(helpPtr, Topics_Area, &DType, &DItem, &tempRect);
  226.     SetRect(&List_Rect, tempRect.left, tempRect.top, tempRect.right, tempRect.bottom);
  227.     /* Start w/ full size of the dialog's user item */
  228.     tempRect = List_Rect;            
  229.     /* Make room for the scroll bar on the right */
  230.     tempRect.right = tempRect.right - 15;
  231.     /* Safety check */
  232.     if (tempRect.right <= (tempRect.left + 15)) 
  233.         tempRect.right = tempRect.left + 15;
  234.     /* Frame it */
  235.     InsetRect(&tempRect, -1, -1);       
  236.     FrameRect(&tempRect);               
  237.     InsetRect(&tempRect, 1, 1);         
  238.     SetRect(&dataBounds, 0, 0, 1, 0);
  239.     /* Width of the list */
  240.     cSize.h = tempRect.right - tempRect.left;
  241.     /* Geneva lists look more professional... */
  242.     thePort->txFont = geneva;
  243.     thePort->txSize = 10;
  244.     /* Get the current font sizes */
  245.     GetFontInfo(&ThisFontInfo);         
  246.     /* Height of a cell */
  247.     cSize.v = ThisFontInfo.ascent + ThisFontInfo.descent + ThisFontInfo.leading;
  248.     /* Make the list */
  249.     My_List_Handle =  LNew(&tempRect, &dataBounds, cSize, 0, helpPtr, TRUE, FALSE, FALSE, TRUE);
  250.     /* Set the attributes */
  251.     (*My_List_Handle)->selFlags = lOnlyOne + lNoNilHilite;
  252.     /* Draw the list */
  253.     LDoDraw(TRUE, My_List_Handle);        
  254.     cSize.v = 0;                        
  255.     LSetSelect(TRUE, cSize, My_List_Handle);
  256.     Refresh_Topics();  
  257.     
  258.     /* -- Fill in the initial list contents -- */
  259.     for ( index = START + 1; index <= FINIS; index++ ) 
  260.       Add_List_String((Str255 *)topic_name[index], My_List_Handle);
  261.     
  262.      /* -- Compute critical info once & for all -- */
  263.      GetDItem(helpPtr, Display_Area, &DType, &DItem, &tempRect);
  264.      
  265.      /* The entire display area */
  266.     SetRect(&Display_Rect,    tempRect.left,
  267.                               tempRect.top,
  268.                               tempRect.right,
  269.                               tempRect.bottom);
  270.                               
  271.      /* The scroll bar to the right of it */
  272.     SetRect(&Scroller_Rect,    Display_Rect.right - 16,
  273.                               Display_Rect.top,
  274.                               Display_Rect.right,
  275.                               Display_Rect.bottom);
  276.  
  277.     /* Create the text-edit clipping regions */
  278.     SetRect(&Frame_Rect,Display_Rect.left,
  279.                         Display_Rect.top,
  280.                         Display_Rect.right-17,
  281.                         Display_Rect.bottom);
  282.  
  283.     /* Compute the Text Edit destination rectangle */
  284.     SetRect(&Dest_Rect, Frame_Rect.left+4,
  285.                         Frame_Rect.top+4,
  286.                         Frame_Rect.right-17,
  287.                         9000);
  288.                         
  289.     /* The clipping region for the actual text */
  290.     SetRect(&View_Rect,Dest_Rect.left,
  291.                        Dest_Rect.top+2,
  292.                        Dest_Rect.right,
  293.                        Display_Rect.bottom-7);
  294.  
  295.     /*  For simplicity's sake, assume intro  */ 
  296.     /*  screen is always a picture resource. */          
  297.     Display_Pict( Initial_Picture ); 
  298.     return(TRUE);
  299. }
  300.  
  301.  
  302. /***********************************************************************\
  303. |               void  Dialog_String( theDialog, theItem, theStr)            |
  304. |-----------------------------------------------------------------------|
  305. | Purpose :: To write a string into a "static text" field of a dialog    |
  306. |             window.  Assumes the dialog box has already been opened.    |
  307. |             This routine simply hides some messy data structures        |
  308. |             involved in this very necessary operation.                    |
  309. |-----------------------------------------------------------------------|
  310. | Arguments ::                                                            |
  311. |     theDialog    -> Pointer to an already opened window.                    |
  312. |     theItem        -> Item within the dialog to set some text.                |
  313. |    theStr        -> The actual message to be posted.                        |
  314. |-----------------------------------------------------------------------|
  315. | Returns :: void.                                                        |
  316. \***********************************************************************/
  317.  
  318. static void Dialog_String( theDialog, theItem, theStr )
  319.   DialogPtr      theDialog;
  320.   int          theItem;
  321.   char            *theStr;
  322.   {
  323.       Rect        iBox;            /* The rectangle for the item    */
  324.      int            iType;            /* Type of dialog item            */
  325.      Handle        iHandle;        /* Pointer to the item            */
  326.  
  327.      GetDItem(theDialog, theItem, &iType, &iHandle, &iBox);
  328.       SetIText(iHandle, theStr);
  329.   }
  330.  
  331.  
  332. /***********************************************************************\
  333. |                       void  Display_Pict( whichOne )                        |
  334. |-----------------------------------------------------------------------|
  335. | Purpose :: Display a new picture in the picture box!                    |
  336. |-----------------------------------------------------------------------|
  337. | Arguments ::                                                            |
  338. |     whichOne    -> An offset from the resource id of the first PICT in    |
  339. |                   that category.                                        |
  340. |-----------------------------------------------------------------------|
  341. | Returns :: void.                                                        |
  342. \***********************************************************************/
  343.  
  344. static void Display_Pict( whichOne )
  345. int whichOne;
  346. {
  347.     int            nextPict;        /* Next picture to be displayed        */
  348.      Rect        iBox;            /* The rectangle of the picture        */
  349.      int            iType;            /* Type of dialog item                */
  350.      Handle        iHandle;        /* Pointer to the item                */
  351.     PicHandle    newPict;        /* Pointer to the picture area         */
  352.     int         mesg_this_one;    /* The screen we're on now            */
  353.     int            mesg_max_one;    /* Total number of screens in topic */
  354.     Str255         s1,s2,s3,s4,s5;    /* Temporary strings for message    */
  355.     
  356.     
  357.     /* Dispose of previous text record, if there was one */
  358.     if (Last_Type == text) {
  359.         DisposeControl(myControl);
  360.           TEDispose(myTEHandle); 
  361.     }
  362.  
  363.     /* Enable the next & previous buttons? */
  364.     if ( (resource_end[Help_Topic] - resource_start[Help_Topic]) >= 1 ) {
  365.         GetDItem(helpPtr, Next_Button, &iType, &iHandle, &iBox);
  366.         ShowControl((ControlHandle)iHandle);
  367.         GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &iBox);
  368.         ShowControl((ControlHandle)iHandle);
  369.     }
  370.     else {
  371.         GetDItem(helpPtr, Next_Button, &iType, &iHandle, &iBox);
  372.         HideControl((ControlHandle)iHandle);
  373.         GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &iBox);
  374.         HideControl((ControlHandle)iHandle);
  375.     }
  376.     
  377.     /* Compute which picture to display */
  378.     nextPict = resource_start[ Help_Topic ] + whichOne;
  379.     mesg_this_one = nextPict - resource_start[ Help_Topic ] + 1;
  380.     mesg_max_one = resource_end[ Help_Topic ] - resource_start[ Help_Topic ] + 1;
  381.  
  382.     /* Display picture */
  383.     newPict = GetPicture(nextPict);
  384.     
  385.     /* Saftey check */
  386.     if (newPict == NIL)
  387.       Error_Message( err_no_pict );
  388.  
  389.     GetDItem(helpPtr, Display_Area, &iType, &iHandle, &iBox);
  390.     EraseRect(&iBox);
  391.     DrawPicture(newPict,&iBox);
  392.     
  393.     /* Avoid an unnecessary update event */
  394.     ValidRect(&iBox);
  395.  
  396.     /* Compute new text message */
  397.     NumToString(mesg_this_one,s1);
  398.     NumToString(mesg_max_one,s2);
  399.     pStrCat( "\pStatus:  Screen ", (char *) s1, (char *) s3);
  400.     pStrCat( (char *) s3, "\p of ", (char *) s4 );
  401.     pStrCat( (char *) s4, (char *) s2, (char *) s5);
  402.     User_Message((char *)s5);
  403.     Current_Pict = nextPict;
  404.     Last_Type = pict;
  405. }
  406.  
  407.  
  408. /***********************************************************************\
  409. |                       void  Display_Text( void )                            |
  410. |-----------------------------------------------------------------------|
  411. | Purpose :: Display a text help system for the current topic.            |
  412. |-----------------------------------------------------------------------|
  413. | Arguments :: None.                                                    |
  414. |-----------------------------------------------------------------------|
  415. | Returns :: void.                                                        |
  416. \***********************************************************************/
  417.  
  418. static void Display_Text()
  419. {
  420.      int            iType;            /* Type of dialog item            */
  421.      Handle        iHandle;        /* Pointer to the item            */
  422.     Rect         tempRect;        /* For moving the scroll bar    */
  423.     
  424.     /* Dispose of previous text record, if there was one */
  425.     if (Last_Type == text) {
  426.         HUnlock(myTEXTHandle);
  427.         HUnlock(myTEHandle);
  428.         DisposeControl(myControl);
  429.           TEDispose(myTEHandle); 
  430.     }
  431.  
  432.     /* Get a handle to the TEXT resource */
  433.     myTEXTHandle = GetResource('TEXT', resource_start[ Help_Topic ]);
  434.     
  435.     /* Saftey check! */
  436.     if (myTEXTHandle == NIL)
  437.         Error_Message( err_no_text );
  438.  
  439.     HLock(myTEXTHandle);
  440.     
  441.     /* Hide the next & previous buttons */
  442.     GetDItem(helpPtr, Next_Button, &iType, &iHandle, &tempRect);
  443.     HideControl((ControlHandle)iHandle);
  444.     GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &tempRect);
  445.     HideControl((ControlHandle)iHandle);
  446.  
  447.     /* Erase the display area */
  448.     EraseRect(&Display_Rect);
  449.     
  450.     /* Bring up the control */
  451.     myControl = NewControl(helpPtr,&Scroller_Rect,"",TRUE,1,1,10,16,NIL);
  452.      HiliteControl(myControl,ON);
  453.     
  454.      /* Dim the picture scrolling buttons */
  455.      Set_Button_State( Next_Button, FALSE );
  456.       Set_Button_State( Prev_Button, FALSE );
  457.      
  458.     /* Frame the text box */                 
  459.        MoveTo(Frame_Rect.right+1,Frame_Rect.top);      
  460.     LineTo(Frame_Rect.left,Frame_Rect.top);     
  461.     LineTo(Frame_Rect.left,Frame_Rect.bottom-1);        
  462.     LineTo(Frame_Rect.right+1,Frame_Rect.bottom-1);        
  463.     
  464.     /* Create a text record */
  465.     myTEHandle = TENew(&Dest_Rect,&View_Rect);
  466.     HLock(myTEHandle);
  467.     
  468.     /* Display the goods */
  469.     TESetText(*myTEXTHandle, SizeResource(myTEXTHandle), myTEHandle);
  470.     TEUpdate(&View_Rect,myTEHandle);
  471.     User_Message((char *)"\pStatus:  < Text Mode >");
  472.     
  473.     /* Do we need an active scroll bar? */
  474.     if ( ( (View_Rect.bottom - View_Rect.top) / (*myTEHandle)->lineHeight)  <
  475.          ( (*myTEHandle)->nLines ) )
  476.       HiliteControl(myControl,ON);
  477.     else
  478.       HiliteControl(myControl,OFF);
  479.     
  480.     /* Avoid an unnecessary update event */
  481.     ValidRect(&Display_Rect);
  482.     
  483.     /* Set important values and exit */
  484.     SetCtlMax(myControl,((*myTEHandle)->nLines - 
  485.                          ((View_Rect.bottom - View_Rect.top)/(*myTEHandle)->lineHeight)));
  486.     Last_Type = text;
  487. }
  488.  
  489.  
  490. /***********************************************************************\
  491. |                         void  Error_Message( theError )                    |
  492. |-----------------------------------------------------------------------|
  493. | Purpose :: To warn the user about bad information discovered while    |
  494. |             reading in the HTBL resource.                                |
  495. |-----------------------------------------------------------------------|
  496. | Arguments ::    An enumerated type describing the error detected.        |
  497. |-----------------------------------------------------------------------|
  498. | Returns :: Exits to Finder.                                            |
  499. \***********************************************************************/
  500.  
  501. static void Error_Message( theError )
  502.   ErrorTypes    theError;
  503.   {
  504.      Rect        iBox;            /* The rectangle for the button            */
  505.      int            iType;            /* Type of dialog item                    */
  506.      Handle        iHandle;        /* Pointer to the item                    */
  507.     DialogPtr      theBox;          /* Pointer to this dialog                 */
  508.     GrafPtr        savePort;        /* Save the old graf port                */
  509.       short         whatHit;        /* User selected 'Ok' or 'Cancel'         */
  510.     
  511.     /* Bring up the correct alert */
  512.     theBox = GetNewDialog(Help_Error, NIL, FRONT);
  513.     
  514.     /* Position it */
  515.     Center_Window(theBox,50,FALSE);           
  516.     ShowWindow(theBox);
  517.     Bold_Button(theBox, OK_Button);
  518.       SysBeep(1);
  519.         
  520.       /* Fill in text message */
  521.       switch (theError) {
  522.           case err_no_HTBL :
  523.                Dialog_String(theBox, 3, (char *) "\pNo HTBL (Help Table) [ID=128] resource");
  524.              Dialog_String(theBox, 4, (char *) "\pwas found on your resource fork!");
  525.              Dialog_String(theBox, 5, (char *) "\pPlease create one before continuing...");
  526.               break;
  527.  
  528.           case err_min_res :
  529.                Dialog_String(theBox, 3, (char *) "\pYou should have at least an intro");
  530.              Dialog_String(theBox, 4, (char *) "\pscreen and one help screen for your");
  531.              Dialog_String(theBox, 5, (char *) "\phelp system!");
  532.               break;
  533.  
  534.           case err_intro_pict :
  535.                Dialog_String(theBox, 3, (char *) "\pThis program assumes that the");
  536.              Dialog_String(theBox, 4, (char *) "\pintroduction screen is always a");
  537.              Dialog_String(theBox, 5, (char *) "\ppicture!  Please change this screen.");
  538.               break;
  539.  
  540.           case err_bad_type :
  541.                Dialog_String(theBox, 3, (char *) "\pScreen types are either PICT or TEXT.");
  542.              Dialog_String(theBox, 4, (char *) "\pOne of your HTBL fields for screen");
  543.              Dialog_String(theBox, 5, (char *) "\ptype is incorrect...");
  544.               break;
  545.           
  546.           case err_no_pict :
  547.                Dialog_String(theBox, 3, (char *) "\pThe PICT(s) for this topic do not");
  548.              Dialog_String(theBox, 4, (char *) "\pexist!  Very uncool.  I will exit");
  549.              Dialog_String(theBox, 5, (char *) "\pto the Finder rather than crash...");
  550.               break;
  551.  
  552.           case err_no_text :
  553.                Dialog_String(theBox, 3, (char *) "\pThe TEXT for this topic does not");
  554.              Dialog_String(theBox, 4, (char *) "\pexist!  Very uncool.  I will exit");
  555.              Dialog_String(theBox, 5, (char *) "\pto the Finder rather than crash...");
  556.               break;
  557.  
  558.           default : break;
  559.       }
  560.       
  561.       /* Enter an event loop and poll the user */
  562.      ModalDialog(NIL, &whatHit); 
  563.      DisposDialog(theBox);
  564.      ExitToShell();
  565.   }
  566.  
  567.  
  568. /***********************************************************************\
  569. |                   void  Handle_List_Event( whatHit )                        |
  570. |-----------------------------------------------------------------------|
  571. | Purpose :: To process any mouse-downs in the topics list.                |
  572. |-----------------------------------------------------------------------|
  573. | Arguments ::                                                            |
  574. |     whatHit        -> Which item was selected by the user.                    |
  575. |-----------------------------------------------------------------------|
  576. | Returns :: void.                                                        |
  577. \***********************************************************************/
  578.  
  579. static void Handle_List_Event( whatHit )
  580. int            whatHit;    
  581. {
  582.       /* Get the selected topic from the user */
  583.       Help_Topic = whatHit + 1;
  584.       /* If there is >1 screens, enable the "Next" button */
  585.       if (resource_end[Help_Topic] - resource_start[Help_Topic]) {
  586.             Set_Button_State( Next_Button, TRUE );
  587.             Set_Button_State( Prev_Button, FALSE );
  588.       }
  589.       else {
  590.             Set_Button_State( Next_Button, FALSE );
  591.             Set_Button_State(Prev_Button, FALSE );
  592.       }
  593.       
  594.       /* Display first screen in topic */
  595.       if ( screen_mode[ Help_Topic ] == pict )
  596.             Display_Pict( Initial_Picture );
  597.       else if ( screen_mode[ Help_Topic ] == text )
  598.             Display_Text();
  599.       else
  600.             SysBeep(1);
  601.  }
  602.  
  603.  
  604. /***********************************************************************\
  605. |                     void  Handle_Update( void )                            |
  606. |-----------------------------------------------------------------------|
  607. | Purpose :: To handle any update to the dialog.  For example: it will    |
  608. |             refresh the screen when another dialog has been placed        |
  609. |             over it, etc.                                                |
  610. |-----------------------------------------------------------------------|
  611. | Arguments ::    None.                                                    |
  612. |-----------------------------------------------------------------------|
  613. | Returns :: void.                                                        |
  614. \***********************************************************************/
  615.  
  616. static void Handle_Update()
  617. {
  618.      Rect        iBox;            /* The rectangle of the picture        */
  619.      int            iType;            /* Type of dialog item                */
  620.      Handle        iHandle;        /* Pointer to the item                */
  621.     PicHandle    thePict;        /* Pointer to the picture area         */
  622.     GrafPtr        oldPort;        /* Restore old graf port when done    */
  623.  
  624.  
  625.     GetPort(&oldPort);
  626.     SetPort(helpPtr);            
  627.     BeginUpdate(helpPtr);
  628.     Refresh_Topics();
  629.     Bold_Button(helpPtr,OK_Button);
  630.  
  631.     /* Specific code for text or pictures... */
  632.     if ( screen_mode[ Help_Topic ] == text ) {
  633.            MoveTo(Frame_Rect.right+1,Frame_Rect.top);      
  634.         LineTo(Frame_Rect.left,Frame_Rect.top);     
  635.         LineTo(Frame_Rect.left,Frame_Rect.bottom-1);        
  636.         LineTo(Frame_Rect.right+1,Frame_Rect.bottom-1);        
  637.         TEUpdate(&View_Rect,myTEHandle);
  638.     }
  639.     else if ( screen_mode[ Help_Topic ] == pict ) {
  640.         thePict = GetPicture(Current_Pict);
  641.         /* Saftey check */
  642.         if (thePict == NIL) {
  643.               SysBeep(1);
  644.               return;
  645.         }
  646.         GetDItem(helpPtr, Display_Area, &iType, &iHandle, &iBox);
  647.         EraseRect(&iBox);
  648.         DrawPicture(thePict,&iBox);
  649.     }
  650.     DrawDialog(helpPtr);
  651.     EndUpdate(helpPtr);
  652.     SetPort(oldPort);
  653. }
  654.  
  655.  
  656. /***********************************************************************\
  657. |                     void  Help_Event_Loop( void )                        |
  658. |-----------------------------------------------------------------------|
  659. | Purpose :: To handle any events inside my window.  Once an event         |
  660. |             takes place outside this window's domain, I return            |
  661. |             immediately, and let the main event loop handle it.        |
  662. |-----------------------------------------------------------------------|
  663. | Arguments ::    None.                                                    |
  664. |-----------------------------------------------------------------------|
  665. | Returns :: void.                                                        |
  666. \***********************************************************************/
  667.  
  668. static void Help_Event_Loop()
  669. {
  670.     EventRecord         theEvent;        /* Most current real-time user event        */
  671.     Point                 where;            /* Where (mouse location) the event occured */
  672.     Rect                tempRect;        /* Rectangle of the about... window            */
  673.     Point               myPt;            /* Current list selection point             */
  674.     WindowPtr             wPtr;            /* The pointer to the current window        */
  675.     int                 thePart;        /* The type of mouse-down that occured        */
  676.     int                 key;            /* Did the user hit the <return> key?        */
  677.     int                    whatHit;        /* Integer id of the dialog item user hit    */
  678.     Rect                   DRect;            /* Rectangle used for finding hit point     */
  679.     short                DType;             /* Type of dialog item (for OK button)        */
  680.     int                    itemHit;           /* Get selection from the user                */
  681.     Handle               DItem;            /* Handle to the dialog item                 */
  682.     long                ticks;            /* Highlight ok button when <return> hit    */
  683.     Boolean               DoubleClick;      /* Flag to see if double click on a list     */
  684.     int                    oldValue;        /* Former value of scroll bar before event  */
  685.     int                 rc;                /* Return code from TrackControl() - ignore    */
  686.     long                 cellHit;        /* Find out where user single-clicked         */
  687.     ControlHandle          aControl;        /* Event took place in my scroller            */
  688.     static  int         lastHit = -1;    /* Nicety: prevent redundant processing     */
  689.  
  690.     /* -- Enter the event loop -- */
  691.     InitCursor();
  692.     HiliteMenu(0);
  693.     for (;;) {
  694.         SetPort(helpPtr);
  695.         SelectWindow(helpPtr);
  696.         InitCursor();
  697.  
  698.         if (GetNextEvent(everyEvent, &theEvent)) {
  699.             switch (theEvent.what)
  700.             {
  701.               case updateEvt:
  702.                   if ((WindowPtr)theEvent.message == helpPtr) 
  703.                     Handle_Update();
  704.                    break;
  705.               
  706.               case keyDown:
  707.                 /* If it's a <return> key I want it  */
  708.                 key = ( (unsigned char) theEvent.message & charCodeMask );
  709.                 if ( (key == '\r') ) {
  710.                     /* Treat this like a mouse-down in the OK button */
  711.                     SetPort(helpPtr);
  712.                     GetDItem(helpPtr, OK_Button, &DType, &DItem, &DRect);
  713.                     HiliteControl((ControlHandle)DItem,1);
  714.                     Delay(8,&ticks);
  715.                     Kill_Window();
  716.                     return;
  717.                 }
  718.                   break;
  719.  
  720.               case mouseDown:
  721.                   thePart = FindWindow(theEvent.where, &wPtr);
  722.                   /* The following is very tricky code: it allows you */
  723.                   /* to switch tasks under Multifinder, but will not  */
  724.                   /* let you pull down any of the disabled menus.     */
  725.                  if ((DialogPtr)wPtr != helpPtr) {
  726.                       if (thePart != inMenuBar)
  727.                         SysBeep(1);
  728.                       continue;
  729.                   } 
  730.                   switch (thePart)
  731.                 {
  732.                   case inMenuBar:
  733.                       rc = MenuSelect(theEvent.where);
  734.                       break;
  735.                       
  736.                     case inDrag:
  737.                     tempRect = screenBits.bounds;
  738.                     SetRect(&tempRect, tempRect.left + 10, tempRect.top + 25, 
  739.                                        tempRect.right - 10,tempRect.bottom - 10);
  740.                         DragWindow(helpPtr, theEvent.where, &tempRect);
  741.                         break;
  742.  
  743.                     case inContent:
  744.                         if (DialogSelect(&theEvent, &helpPtr, &whatHit)) {
  745.                         myPt = theEvent.where;         
  746.                         GlobalToLocal(&myPt);           
  747.                             
  748.                               /* Is the user all done? */
  749.                               if (whatHit == OK_Button) {
  750.                                 Kill_Window();
  751.                                 return;
  752.                             }
  753.         
  754.                             else if ((whatHit == Next_Button) || (whatHit == Prev_Button))
  755.                               Scroll_Picture( whatHit );
  756.  
  757.                         /* Was it an event in the topics list? */
  758.                         else if (PtInRect(myPt,&List_Rect) == TRUE)  {
  759.                             DoubleClick = LClick(myPt, theEvent.modifiers, My_List_Handle);
  760.                             cellHit = LLastClick(My_List_Handle);    
  761.                             itemHit = HiWord( cellHit );    
  762.                             if ((itemHit >= 0) && (itemHit != lastHit)) {
  763.                                   lastHit = itemHit;
  764.                                   Handle_List_Event(itemHit);
  765.                             }
  766.                          } 
  767.          
  768.                         /* Was it a text scroller event? */
  769.                         else if ( (PtInRect(myPt, &Scroller_Rect))  && 
  770.                                     (screen_mode[ Help_Topic ] == text) ) {
  771.                               thePart = FindControl(myPt, wPtr, &aControl);
  772.                               oldValue = GetCtlValue(aControl);
  773.                               if ( thePart == inThumb ) {
  774.                                  rc = TrackControl(aControl, myPt, (ProcPtr)0);
  775.                                  Scroll_Text( oldValue, GetCtlValue(aControl) );
  776.                               }
  777.                               else if ( (thePart == inUpButton) || (thePart == inDownButton) ||
  778.                                       (thePart == inPageUp)   || (thePart == inPageDown) ) 
  779.                                  rc = TrackControl(aControl, myPt, &My_Scroll_Filter);
  780.                                 }                       
  781.                     }
  782.                     break;
  783.                 }
  784.             }
  785.         }
  786.     }
  787. }
  788.  
  789.  
  790. /***********************************************************************\
  791. |                               void Init_Help( void )                        |
  792. |-----------------------------------------------------------------------|
  793. | Purpose :: This code is called every time the Help system is invoked,    |
  794. |             because this is the code resource version.  The HTBL is    |
  795. |             scanned, and its values are stored in global data structs.    |
  796. |             NOTE!  This routine assumes HTBL has ID=128.                |
  797. |-----------------------------------------------------------------------|
  798. | Arguments ::    None.                                                    |
  799. |-----------------------------------------------------------------------|
  800. | Returns :: void.                                                        |
  801. \***********************************************************************/
  802.  
  803. void Init_Help()
  804. {    
  805.     int                    index;        /* Loop thru user's information     */
  806.     char                *HTBL_ptr;    /* Establish the basline pointer    */
  807.     Help_Info_Handle    h;            /* Cast HTBL to this data structure    */
  808.     long                mode;        /* Longint version of PICT or TEXT    */
  809.     char                ch;            /* First letter of PICT or TEXT     */
  810.     
  811.     /* Get handle to the HTBL resource */
  812.     h = (Help_Info_Handle) GetResource('HTBL',128);
  813.     
  814.     /* No HTBL=128 resource? */
  815.     if ((h == NIL) || (ResErr != noErr))
  816.         Error_Message( err_no_HTBL );
  817.     
  818.     /* Lock it */
  819.     HLock(h);
  820.     
  821.     /* Establish pointer to start of HTBL resource */
  822.      HTBL_ptr = (char *) *h;
  823.     First_Menu = ParseInt( (char **) &HTBL_ptr );
  824.     Last_Menu = ParseInt( (char **) &HTBL_ptr );
  825.     START = 0;
  826.     FINIS = ParseInt( (char **) &HTBL_ptr );
  827.     
  828.     /* Enough help screens to proceed? */
  829.     if (FINIS < 1) 
  830.         Error_Message( err_min_res );
  831.     
  832.     /* Now loop thru all screens & get the information */
  833.       for (index = 0; index <= FINIS; index++) {
  834.           /* Is this a 'PICT' or 'TEXT' screen? */
  835.         mode = ParseOSType( (char **) &HTBL_ptr );
  836.         ch = (char)(mode >> 24);
  837.         if ( (ch == 'P') || (ch == 'p') ) 
  838.             screen_mode[index]      = pict;
  839.         else if ( (ch == 'T') || (ch == 't') )
  840.             screen_mode[index]      = text;
  841.         else 
  842.             /* Bad screen type! */
  843.             Error_Message( err_bad_type );
  844.         
  845.         /* Is intro screen a PICT? */
  846.         if ((index == 0) && (screen_mode[index] != pict)) 
  847.             Error_Message( err_intro_pict );
  848.         
  849.         /* Get resource bounds */
  850.         resource_start[index] = ParseInt( (char **) &HTBL_ptr );
  851.         resource_end[index]   = ParseInt( (char **) &HTBL_ptr );
  852.         
  853.         /* Retrieve title of this topic */
  854.         ParseString( (char *)topic_name[index], (char **) &HTBL_ptr );
  855.     }
  856.     HUnlock(h);
  857. }
  858.  
  859.  
  860. /***********************************************************************\
  861. |                          void Kill_Window( void )                        |
  862. |-----------------------------------------------------------------------|
  863. | Purpose: When we get here, the user has clicked on the "done" button.    |
  864. |           Dispose of all dynamic (heap) data structures and restore    | 
  865. |           the original grafport.                                        |
  866. |-----------------------------------------------------------------------|
  867. | Arguments ::    None.                                                    |
  868. |-----------------------------------------------------------------------|
  869. | Returns :: Void.                                                        |
  870. \***********************************************************************/
  871.  
  872. static void Kill_Window()
  873. {
  874.  
  875.     if (Last_Type == text) {
  876.           TEDispose(myTEHandle); 
  877.     }
  878.     LDispose(My_List_Handle);
  879.     DisposDialog(helpPtr);         
  880.     CloseResFile(refnum);
  881.     SetPort(savePort);
  882. }
  883.  
  884.  
  885. /***********************************************************************\
  886. |                           void  main( void )                                |
  887. |-----------------------------------------------------------------------|
  888. | Purpose :: To present an extensive help system to the user.  This        |
  889. |             routine handles scrolling lists and dynamic pictures.        |
  890. |-----------------------------------------------------------------------|
  891. | Arguments ::    None.                                                    |
  892. |-----------------------------------------------------------------------|
  893. | Returns :: void.                                                        |
  894. \***********************************************************************/
  895.  
  896. pascal void main()
  897. {
  898.     MenuHandle    thisMenu;        /* Current menu bar to disable  */
  899.     int            index;            /* Loop thru menu resources        */
  900.     Handle        h;                /* Lock this resource myself    */
  901.     
  902.     /* Save the state of the registers */
  903.     RememberA0();
  904.     SetUpA4();
  905.     
  906.     /* Lock my code resource */
  907.     asm {
  908.         _RecoverHandle
  909.         move.l  a0, h
  910.     }
  911.     HLock(h);
  912.     
  913.     /* Re-initialize QuickDraw! */
  914.     InitGraf(&thePort);
  915.     
  916.     /* Initialize the help system */
  917.     Init_Help();
  918.     
  919.     /* Bring up the help box */
  920.     if ( Create_Help() ) {
  921.         /* Disable The Menus */
  922.         for (index = First_Menu; index <= Last_Menu; index++) {
  923.             thisMenu = GetMHandle(index);
  924.             DisableItem(thisMenu,0);
  925.         }
  926.         DrawMenuBar();
  927.         
  928.         /* Trap help window events */
  929.         Help_Event_Loop();
  930.     
  931.         /* Re-enable the menu bar and exit */
  932.         for (index = First_Menu; index <= Last_Menu; index++) {
  933.             thisMenu = GetMHandle(index);
  934.             EnableItem(thisMenu,0);
  935.         }
  936.         DrawMenuBar();
  937.     }
  938.     /* Restore the registers & exit */
  939.     HUnlock(h);
  940.     RestoreA4();
  941. }
  942.  
  943.  
  944. /***********************************************************************\
  945. |                  void My_Scroll_Filter( theControl, thePart )            |
  946. |-----------------------------------------------------------------------|
  947. | Purpose: TrackControl() will call this routine for all events except    |
  948. |           dragging the thumb wheel by the user.  All "up & down"         | 
  949. |           events by the user are then translated into the correct        |
  950. |           TextEdit Manager calls to correctly position the text.        |
  951. |-----------------------------------------------------------------------|
  952. | Arguments ::                                                            |
  953. |     theControl    -> Handle the the scroller control.                        |
  954. |     thePart        -> That part of the scroller the user interacted with.    |
  955. |-----------------------------------------------------------------------|
  956. | Returns :: Void.                                                        |
  957. \***********************************************************************/
  958.  
  959. static pascal void My_Scroll_Filter( theControl, thePart )
  960. ControlHandle     theControl;
  961. int                thePart;
  962. {
  963.     int        start, stop;    /* The outer boundry values of the scroller */
  964.     int        page;            /* The computed amount to correctly page    */
  965.     int        newValue;        /* The new value to scroll up or down        */
  966.     int        oldValue;        /* The previous value of the control        */
  967.     long    finalTicks;        /* Slow down the action to appear natural    */
  968.     
  969.     /* Get the upper & lower limits to perform saftey checks */
  970.     start = (*theControl)->contrlMin;    
  971.     stop  = (*theControl)->contrlMax;
  972.     oldValue = GetCtlValue(theControl);
  973.     
  974.     /* Compute the amount of scrolling for page ups & downs */
  975.     page = (Display_Rect.bottom - Display_Rect.top) / (*myTEHandle)->lineHeight;
  976.     
  977.     /* Get the current value of the control */
  978.     newValue = GetCtlValue(theControl);
  979.  
  980.     /* Process the event accordingly */
  981.     switch ( thePart ) {
  982.     
  983.         case inUpButton    :     /* Scroll up one line */
  984.                                 newValue -= 1;
  985.                                 /* Saftey check! */
  986.                                 if (newValue < start)
  987.                               newValue = start;
  988.                               break;
  989.                   
  990.         case inDownButton:     /* Scroll down one line */
  991.                               newValue += 1;
  992.                               /* Saftey check! */
  993.                               if (newValue > stop)
  994.                               newValue = stop;
  995.                               break;
  996.  
  997.         case inPageUp    :     /* Perform a page up */
  998.                               newValue -= page;
  999.                               /* Saftey check! */
  1000.                               if (newValue < start)
  1001.                               newValue = start;
  1002.                               break;
  1003.  
  1004.         case inPageDown    :     /* Perform a page down */
  1005.                               newValue += page;
  1006.                               /* Saftey check! */
  1007.                               if (newValue > stop)
  1008.                               newValue = stop;
  1009.                               break;
  1010.  
  1011.         default            :     break;
  1012.     }
  1013.     
  1014.     /* Now set the control to the proper amount */
  1015.     SetCtlValue( theControl, newValue );
  1016.     Delay(2,&finalTicks); 
  1017.     Scroll_Text( oldValue, newValue );
  1018. }
  1019.   
  1020.  
  1021. /***********************************************************************\
  1022. |                          int ParseInt( pPointer )                        |
  1023. |-----------------------------------------------------------------------|
  1024. | Purpose: Get the next integer from the HTBL resource.                    |
  1025. |-----------------------------------------------------------------------|
  1026. | Arguments ::    Handle into the resource.                                |
  1027. |-----------------------------------------------------------------------|
  1028. | Returns :: Next integer in the HTBL resource.                            |
  1029. \***********************************************************************/
  1030.  
  1031. static int ParseInt( pPointer )
  1032. char    **pPointer;
  1033. {
  1034.     int                result=0;            /* Final integer result         */
  1035.     unsigned char    hiWord, lowWord;    /* Store 2 halves of the int */
  1036.     
  1037.     /* Get the raw data */
  1038.     hiWord = (unsigned char) *((*pPointer)++);
  1039.     lowWord = (unsigned char) *((*pPointer)++);
  1040.     
  1041.     /* Now pack these into the integer! */
  1042.     result = result | hiWord;
  1043.     result = (result << 8) | lowWord;
  1044.     
  1045.      return(result);
  1046. }
  1047.     
  1048.     
  1049. /***********************************************************************\
  1050. |                          int ParseOSType( pPointer )                        |
  1051. |-----------------------------------------------------------------------|
  1052. | Purpose: Get the next screen type ('PICT' or 'TEXT') from the HTBL     |
  1053. |           resource.                                                    |
  1054. |-----------------------------------------------------------------------|
  1055. | Arguments ::    Handle into the resource.                                |
  1056. |-----------------------------------------------------------------------|
  1057. | Returns :: Next longint in the HTBL resource.                            |
  1058. \***********************************************************************/
  1059.  
  1060. static long ParseOSType( pPointer )
  1061. char    **pPointer;
  1062. {
  1063.      long    result=0;        /* Final longint to return        */
  1064.     char    nextByte;        /* 1/4 of the longint             */
  1065.     int        index;            /* Loop thru bytes in a long    */
  1066.     
  1067.     /* Get the first of four bytes */
  1068.     nextByte = (char) *((*pPointer)++);
  1069.     result = result | (long) nextByte;
  1070.     
  1071.     /* Now loop thru the rest! */
  1072.     for (index = 1; index < sizeof(long); index++) {
  1073.         nextByte = (char) *((*pPointer)++);
  1074.         result = (result << 8) | (long) nextByte;
  1075.     }
  1076.      return(result);
  1077. }
  1078.  
  1079.  
  1080. /***********************************************************************\
  1081. |                      int ParseString( pDest, pSource )                    |
  1082. |-----------------------------------------------------------------------|
  1083. | Purpose: Get the next string from the HTBL resource.                    |
  1084. |-----------------------------------------------------------------------|
  1085. | Arguments ::    pDest ->   Returned string.                                |
  1086. |                pSource -> Handle to the HTBL resource.                    |
  1087. |-----------------------------------------------------------------------|
  1088. | Returns :: Final result.                                                |
  1089. \***********************************************************************/
  1090.  
  1091. static void ParseString( pDest, pSource )
  1092. char    *pDest, **pSource;
  1093. {
  1094.     int iLen = *pDest++ = *((*pSource)++);
  1095.     
  1096.     while (--iLen >= 0) 
  1097.         *pDest++ = *((*pSource)++);
  1098. }
  1099.  
  1100.  
  1101. /***********************************************************************\
  1102. |                         void  pStrCat( p1, p2, p3 )                        |
  1103. |-----------------------------------------------------------------------|
  1104. | Purpose :: Concatenate two pascal strings "p1" and "p2" together,     |
  1105. |             giving    result "p3".                                        |
  1106. |-----------------------------------------------------------------------|
  1107. | Arguments ::                                                            |
  1108. |     p1    -> Source string one.                                            |
  1109. |     p2    -> Source string two.                                            |
  1110. |     p3    -> Destination string.                                            |
  1111. |-----------------------------------------------------------------------|
  1112. | Returns :: void.                                                        |
  1113. \***********************************************************************/
  1114.  
  1115. static void pStrCat( p1, p2, p3 )
  1116. char *p1, *p2, *p3; 
  1117. {
  1118.     int len1, len2;
  1119.     
  1120.     len1 = *p1++;
  1121.     len2 = *p2++;
  1122.     
  1123.     *p3++ = len1 + len2;
  1124.     while (--len1 >= 0) *p3++=*p1++;
  1125.     while (--len2 >= 0) *p3++=*p2++;
  1126. }
  1127.  
  1128.  
  1129. /***********************************************************************\
  1130. |                         void  pStrCopy( p1, p2 )                        |
  1131. |-----------------------------------------------------------------------|
  1132. | Purpose :: To copy one pascal string into another.  Direction of         |
  1133. |             copy:  p1 --> p2.                                            |
  1134. |-----------------------------------------------------------------------|
  1135. | Arguments ::                                                            |
  1136. |     p1    -> Source string.                                                |
  1137. |     p2    -> Destination string.                                            |
  1138. |-----------------------------------------------------------------------|
  1139. | Returns :: void.                                                        |
  1140. \***********************************************************************/
  1141.  
  1142. static void pStrCopy( p1, p2 )
  1143. char *p1, *p2; 
  1144. {
  1145.     int len;
  1146.     
  1147.     len = *p2++ = *p1++;
  1148.     while (--len>=0) *p2++=*p1++;
  1149. }
  1150.  
  1151.  
  1152. /***********************************************************************\
  1153. |                       void  Refresh_Topics( void )                        |
  1154. |-----------------------------------------------------------------------|
  1155. | Purpose :: To draw (or redraw) the contents of the topics list.        |
  1156. |-----------------------------------------------------------------------|
  1157. | Arguments ::    None.                                                    |
  1158. |-----------------------------------------------------------------------|
  1159. | Returns :: void.                                                        |
  1160. \***********************************************************************/
  1161.  
  1162. static void  Refresh_Topics() 
  1163.     Rect     tempRect;       /* Temporary rectangle         */
  1164.     short    DType;         /* Type of dialog item         */
  1165.     Handle   DItem;            /* Handle to dialog item     */
  1166.  
  1167.     LUpdate(helpPtr->visRgn,My_List_Handle);
  1168.     tempRect = List_Rect;            
  1169.     InsetRect(&tempRect, -1, -1);       
  1170.     FrameRect(&tempRect);               
  1171.  
  1172.  
  1173. /***********************************************************************\
  1174. |                   void  Scroll_Picture( whatHit )                            |
  1175. |-----------------------------------------------------------------------|
  1176. | Purpose :: To display the next (or previous) picture in a help topic.    |
  1177. |-----------------------------------------------------------------------|
  1178. | Arguments ::                                                            |
  1179. |     whatHit    -> Equal to Next_Button or Prev_Button in the dialog box.    |
  1180. |-----------------------------------------------------------------------|
  1181. | Returns :: void.                                                        |
  1182. \***********************************************************************/
  1183.  
  1184. static void Scroll_Picture( whatHit )
  1185. int              whatHit;
  1186. {
  1187.     int        theMax;            /* High bounds of help topic     */
  1188.     int        theMin;            /* Low bounds of that topic         */
  1189.     
  1190.     /* Find out which pictures are relivant */
  1191.     theMin = resource_start[ Help_Topic ];
  1192.     theMax = resource_end[ Help_Topic ];
  1193.      
  1194.      /* Compute the new picture to display! */
  1195.      if ( (whatHit == Next_Button) && (Current_Pict < theMax) ) {
  1196.         Current_Pict++;
  1197.          Set_Button_State( Prev_Button, TRUE );
  1198.          if (Current_Pict < theMax)
  1199.            Set_Button_State( Next_Button, TRUE );
  1200.          else
  1201.            Set_Button_State( Next_Button, FALSE );
  1202.          Display_Pict( Current_Pict - theMin );
  1203.        }
  1204.        else if ( (whatHit == Prev_Button) && (Current_Pict > theMin) ) {
  1205.         Current_Pict--;
  1206.          Set_Button_State( Next_Button, TRUE );
  1207.          if (Current_Pict > theMin)
  1208.            Set_Button_State( Prev_Button, TRUE );
  1209.          else
  1210.            Set_Button_State( Prev_Button, FALSE );
  1211.          Display_Pict( Current_Pict - theMin );
  1212.        }
  1213.        else
  1214.            SysBeep(1);
  1215. }
  1216.  
  1217.  
  1218. /***********************************************************************\
  1219. |                   void  Scroll_Text( old, new )                            |
  1220. |-----------------------------------------------------------------------|
  1221. | Purpose :: To dynamically scroll the text edit window for the user.    |
  1222. |-----------------------------------------------------------------------|
  1223. | Arguments ::                                                            |
  1224. |     old    -> The previous value of the scroll bar before the user event.    |
  1225. |     new    -> The new value to scroll the text.                            |
  1226. |-----------------------------------------------------------------------|
  1227. | Returns :: void.                                                        |
  1228. \***********************************************************************/
  1229.  
  1230. static void Scroll_Text( oldValue, newValue )
  1231. int        oldValue;
  1232. int        newValue;
  1233. {
  1234.   TEScroll(0, (oldValue - newValue) * (*myTEHandle)->lineHeight, myTEHandle);
  1235. }
  1236.  
  1237.  
  1238. /***********************************************************************\
  1239. |             void  Set_Button_State( itemNum, state )                    |
  1240. |-----------------------------------------------------------------------|
  1241. | Purpose :: To either enable or disable a button within a dialog box.    |
  1242. |-----------------------------------------------------------------------|
  1243. | Arguments ::                                                            |
  1244. |     itemNum    -> Item within the dialog to modify.                        |
  1245. |    state    -> TRUE = on, FALSE = off.                                    |
  1246. |-----------------------------------------------------------------------|
  1247. | Returns :: void.                                                        |
  1248. \***********************************************************************/
  1249.  
  1250. static void Set_Button_State(itemNum, state )
  1251. int            itemNum;
  1252. Boolean        state;
  1253.  {
  1254.      Rect        iBox;            /* The rectangle for the button        */
  1255.      int            iType;            /* Type of dialog item                */
  1256.      Handle        iHandle;        /* Pointer to the item                */
  1257.      
  1258.      GetDItem(helpPtr, itemNum, &iType, &iHandle, &iBox);
  1259.      if ( state )
  1260.        HiliteControl( (ControlHandle) iHandle, 0 );
  1261.      else
  1262.        HiliteControl( (ControlHandle) iHandle, 255);
  1263.  }
  1264.  
  1265.  
  1266.  
  1267. /***********************************************************************\
  1268. |                         void  User_Message( theStr )                    |
  1269. |-----------------------------------------------------------------------|
  1270. | Purpose :: To display a status message in the "Picture Scrolling"        |
  1271. |             window.                                                    |
  1272. |-----------------------------------------------------------------------|
  1273. | Arguments ::                                                            |
  1274. |     theStr    -> The pascal string to display.                            |
  1275. |-----------------------------------------------------------------------|
  1276. | Returns :: void.                                                        |
  1277. \***********************************************************************/
  1278.  
  1279. static void User_Message( theStr )
  1280. char  *theStr;
  1281. {
  1282.      Rect        iBox;            /* The rectangle of the picture        */
  1283.      int            iType;            /* Type of dialog item                */
  1284.      Handle        iHandle;        /* Pointer to the item                */
  1285.  
  1286.     GetDItem(helpPtr, Message_Area, &iType, &iHandle, &iBox);
  1287.     SetIText(iHandle, theStr);
  1288.     DrawDialog(helpPtr); 
  1289. }
  1290.