home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / c_helpte.sit < prev    next >
Encoding:
Text File  |  1988-06-20  |  32.2 KB  |  1,229 lines

  1. 18-Jun-88 14:32:13-MDT,34128;000000000000
  2. Return-Path: <u-lchoqu%sunset@cs.utah.edu>
  3. Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:31:32 MDT
  4. Received: by cs.utah.edu (5.54/utah-2.0-cs)
  5.     id AA22255; Sat, 18 Jun 88 14:31:31 MDT
  6. Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
  7.     id AA24639; Sat, 18 Jun 88 14:31:25 MDT
  8. Date: Sat, 18 Jun 88 14:31:25 MDT
  9. From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
  10. Message-Id: <8806182031.AA24639@sunset.utah.edu>
  11. To: rthum@simtel20.arpa
  12. Subject: HelpText.c
  13.  
  14. /*
  15.  * HelpText.c - source file for the "HELP << >> TEXT" application
  16.  *
  17.  * Kent Kersten, 7-Jul-85
  18.  *
  19.  * This program takes a 'TEXT' type file and writes it to a given
  20.  * file's resource fork, under the resource name of 'HELP', with
  21.  * a given id # and (optional) name.  It can also perform the reverse
  22.  * operation, taking a HELP resource and writing a TEXT file.  This
  23.  * is helpful for preparing 'help' type dialogs, such as the type
  24.  * that Microsoft Multiplan has.
  25.  *
  26.  * NOTE:  The maximum size of a resource or text file is 32K bytes;
  27.  *        this is because we use TextEdit, and it has that limitation.
  28.  *        Also, you can't write a single resource that is greater
  29.  *        than 32K, so it works out all around.  Even so, I can't
  30.  *        imagine a single HELP selection being anywhere near that long!
  31.  *
  32.  * TEXT >> HELP command instructions:
  33.  *     When you have a 'TEXT' type file, such as created with Edit,
  34.  *     and you wish to convert it to a HELP resource, this is the command
  35.  *     to use.  You will be presented with a Standard File dialog to
  36.  *     choose a TEXT type file to read from.  You will then be
  37.  *     prompted to enter a filename to save the HELP resource in.
  38.  *     The final dialog will ask you what resource number and name
  39.  *     you wish to assign to the resource.  If all goes well, you
  40.  *     will get a message to that effect; if not, then an appropriate
  41.  *     error message will be displayed.
  42.  *
  43.  * HELP << TEXT command instructions:
  44.  *     When you want to convert a HELP resource to a TEXT file, use
  45.  *     this command.  You will be prompted with a Standard File dialog
  46.  *     to choose a file to read the HELP resource from.  After that,
  47.  *     a dialog will open asking for the HELP resource number to use.
  48.  *     You will then be asked to name the TEXT file that the resource
  49.  *     will be written to.
  50.  *
  51.  * Please note that this program only works for vanilla text files.
  52.  * No formatting information is kept, such as with Microsoft Word.
  53.  *
  54.  * This program and its associated modules
  55.  * are the property of and copyright (c) 1985 by:
  56.  *     Kent Kersten
  57.  *     Harrison Systems
  58.  *     437 Atlas Drive
  59.  *     Nashville, TN  37211
  60.  *     (615) 834-1366
  61.  *     CompuServe [72277,2726]
  62.  */
  63.  
  64. #include  <quickdraw.h>
  65. #include  <window.h>
  66. #include  <menu.h>
  67. #include  <resource.h>
  68. #include  <packages.h>
  69. #include  <event.h>
  70. #include  <desk.h>
  71. #include  <control.h>
  72. #include  <textedit.h>
  73. #include  <dialog.h>
  74. #include  <font.h>
  75. #include  <osutil.h>
  76.  
  77. #define   copyright_string  "Copyright (c) 1985 by Kent Kersten"
  78.  
  79. #define   HELP_FILE        "\007HT.Help"
  80.  
  81. #define   ABOUT_DLOG        256
  82. #define   HELP_DLOG        257
  83. #define   RSRC_DLOG        300
  84. #define   RSRC_2_DLOG        301
  85. #define   OVERWRITE_DLOG    320
  86. #define   CONV_DLOG        350
  87. #define   GENERAL_ERROR_ALRT    400
  88.  
  89. #define   KENT_ICON        306
  90.  
  91. #define   nil            (long) 0
  92.  
  93. #define   NUM_MENUS        3
  94. #define   AppleMenu        256
  95. #define   FileMenu        257
  96. #define   EditMenu        258
  97.  
  98. #define   Helvetica        21        /* font for help boxes */
  99.  
  100. #define   MAX_TITLES_IN_BOX    7        /* how many can be seen at once */
  101. #define   MAX_HELP_TITLES    64
  102. #define   MAX_LINES_IN_BOX    14        /* # of lines in help text box */
  103.  
  104. MenuHandle HTMenu[NUM_MENUS];
  105.  
  106. char *calloc(), *realloc();
  107.  
  108. Boolean ProcessEvents(), DoCommand();
  109. Boolean ReadTextFile(), WriteTextFile();
  110. Boolean ReadRsrcFile(), WriteRsrcFile();
  111. Boolean OverWriteDialog(), RsrcDialog();
  112.  
  113. Point         whereOpen   = { 80, 80 };        /* where to put the SF dialog */
  114. Point         whereSaveAs = { 85, 95 };
  115.  
  116. struct hNode {
  117.      char *hName;            /* Pascal string */
  118.      int  hNum;
  119. } *hNodeList[MAX_HELP_TITLES];
  120.  
  121. Boolean noHelpResources, inHelpTextBox;
  122. int  selection, hTListNum;
  123. ControlHandle vsb;
  124. Rect htBox;
  125. TEHandle  hTE;
  126. pascal void DScrollUp(), DScrollDown();
  127.  
  128.  
  129. main()
  130. {
  131.      InitGraf(&thePort);
  132.      InitFonts();
  133.      InitWindows();
  134.      InitMenus();
  135.      InitDialogs(nil);
  136.      TEInit();
  137.  
  138.      FlushEvents(everyEvent, 0);        /* flush ALL events */
  139.      GetHelpTitles();
  140.      FormMenuBar();
  141.      InitCursor();
  142.  
  143.      Introduction();
  144.  
  145.      while(ProcessEvents())
  146.           ;
  147. }
  148.  
  149.  
  150. /*
  151.  * Create our menu bar.
  152.  */
  153.  
  154. FormMenuBar()
  155. {
  156.      int  i;
  157.  
  158.      HTMenu[0] = GetMenu(AppleMenu);
  159.      HTMenu[1] = GetMenu(FileMenu);
  160.      HTMenu[2] = GetMenu(EditMenu);
  161.      AddResMenu(HTMenu[0], 'DRVR');
  162.      
  163.      for(i = 0;i < NUM_MENUS;++i)
  164.           InsertMenu(HTMenu[i], 0);
  165.  
  166.      DrawMenuBar();
  167. }
  168.  
  169.  
  170. /*
  171.  * Get events and process them.
  172.  */
  173.  
  174. Boolean ProcessEvents()
  175. {
  176.      char         theChar;
  177.      Boolean      NoQuitFlag = TRUE;
  178.      WindowPtr    whichWindow;
  179.      EventRecord  EditEvent;
  180.      GrafPtr      savePort;
  181.  
  182.      HiliteMenu(0);            /* turn off any highlighting in menu bar */
  183.      SystemTask();
  184.  
  185.      GetNextEvent(everyEvent, &EditEvent);
  186.      switch(EditEvent.what) {
  187.           case mouseDown:
  188.                switch(FindWindow(pass(EditEvent.where), &whichWindow)) {    /* major Aztec C68K hack-ack */
  189.                     case inDesk:
  190.                          break;
  191.                     case inMenuBar:
  192.                          NoQuitFlag = DoCommand(MenuSelect(pass(EditEvent.where)));    /* Aztec hack */
  193.                          break;
  194.                     case inSysWindow:
  195.                          SystemClick(&EditEvent,whichWindow);
  196.                          break;
  197.                     case inGrow:
  198.                          break;
  199.                     case inContent:
  200.                          break;
  201.                     case inDrag:
  202.                          break;
  203.                     case inGoAway:
  204.                          break;
  205.                }
  206.                break;
  207.           case keyDown:
  208.           case autoKey:
  209.                theChar = EditEvent.message % 256;
  210.                if((EditEvent.modifiers & cmdKey) != 0)        /* command key pressed */
  211.                     NoQuitFlag = DoCommand(MenuKey(theChar));
  212.                break;
  213.           case updateEvt:
  214.                GetPort(&savePort);
  215.                SetPort(EditEvent.message);
  216.                BeginUpdate(EditEvent.message);
  217.                EndUpdate(EditEvent.message);
  218.                SetPort(savePort);
  219.                break;
  220.           case activateEvt:
  221.                break;
  222.      }
  223.  
  224.      return NoQuitFlag;
  225. }
  226.  
  227.  
  228. /*
  229.  * Decipher menu commands here.
  230.  */
  231.  
  232. Boolean DoCommand(command)
  233. long command;
  234. {
  235.      int     refNum;
  236.      char    name[256];
  237.      short   MenuNum, ItemNum;
  238.      Boolean NoQuitFlag = TRUE;
  239.  
  240.      InitCursor();
  241.      MenuNum = HiWord(command);
  242.      ItemNum = LoWord(command);
  243.  
  244.      switch(MenuNum) {
  245.           case AppleMenu:
  246.                if(ItemNum == 1) {
  247.             /* we have to bracket the call to our 'About' box with */
  248.             /* the open & close resource file calls, otherwise */
  249.             /* we could erroneously pick off a HELP resource from */
  250.             /* our .Help file when in 'HELPConvert()' */
  251.                     refNum = OpenResFile(HELP_FILE);
  252.                     AboutHT();
  253.                     CloseResFile(refNum);
  254.                }
  255.                else {
  256.                     GetItem(HTMenu[0], ItemNum, name);
  257.                     OpenDeskAcc(name);
  258.                }
  259.                break;
  260.           case FileMenu:
  261.                switch(ItemNum) {
  262.                     case 1:
  263.                          TEXTConvert();
  264.                          break;
  265.                     case 2:
  266.                          HELPConvert();
  267.                          break;
  268.                     case 3:
  269.                          NoQuitFlag = FALSE;
  270.                          break;
  271.                }
  272.                break;
  273.           case EditMenu:
  274.                switch(ItemNum) {
  275.                     case 1:
  276.                          if(FrontWindow() != nil)
  277.                               SystemEdit(undoCmd);
  278.                          break;
  279.                     case 3:
  280.                          if(FrontWindow() != nil)
  281.                               SystemEdit(cutCmd);
  282.                          break;
  283.                     case 4:
  284.                          if(FrontWindow() != nil)
  285.                               SystemEdit(copyCmd);
  286.                          break;
  287.                     case 5:
  288.                          if(FrontWindow() != nil)
  289.                               SystemEdit(pasteCmd);
  290.                          break;
  291.                     case 6:
  292.                          if(FrontWindow() != nil)
  293.                               SystemEdit(clearCmd);
  294.                          break;
  295.                }
  296.                break;
  297.      }
  298.  
  299.      return NoQuitFlag;
  300. }
  301.  
  302.  
  303. /*
  304.  * Get the string resource whose number was passed and
  305.  * call the GeneralError alert function.
  306.  */
  307.  
  308. ErrorCall(num)
  309. int  num;
  310. {
  311.      Handle hdl;
  312.  
  313.      hdl = GetString(num);
  314.      HLock(hdl);
  315.      GeneralError(*hdl, nil, nil, nil);
  316.      HUnlock(hdl);
  317.      ReleaseResource(hdl);
  318. }
  319.  
  320.  
  321. /*
  322.  * Convert a 'HELP' resource file to a 'TEXT' file.
  323.  */
  324.  
  325. HELPConvert()
  326. {
  327.      SFReply    rec, rec2;
  328.      int        id, number, refNum;
  329.      long       grow, theType;
  330.      char       name[256];
  331.      Handle     hdl;
  332.      Rect       tRect;
  333.      TEHandle   hTE;
  334.      WindowPtr  wptr;        /* a necessary hack, as it turns out */
  335.  
  336.      MaxMem(&grow);        /* free up some heap space */
  337.  
  338.      ParamText("\030Read HELP resource from:", nil, nil, nil);
  339.  
  340.      SFGetFile(pass(whereOpen), nil, nil, 0, nil, nil, &rec);
  341.  
  342.      if(rec.good == 0)                /* 'Cancel' button hit */
  343.           return;
  344.  
  345.      if(!RsrcDialog(&number, name, TRUE))
  346.           return;                /* 'Cancel' hit */
  347.  
  348.      if((refNum = OpenResFile(rec.fName)) < 0) { /* get the name of the resource */
  349.           ErrorCall(303);
  350.           return;
  351.      }
  352.  
  353.      if((hdl = GetResource('HELP', number)) == nil) {
  354.           CloseResFile(refNum);
  355.           ErrorCall(304);
  356.           return;
  357.      }
  358.      GetResInfo(hdl, &id, &theType, name);
  359.      ReleaseResource(hdl);
  360.      CloseResFile(refNum);
  361.  
  362.      hdl = GetString(257);
  363.      HLock(hdl);
  364.      SFPutFile(pass(whereSaveAs), *hdl, name, nil, &rec2);    /* text file to write to */
  365.      HUnlock(hdl);
  366.  
  367.      if(rec2.good == 0)                /* 'Cancel' hit */
  368.           return -1;
  369.  
  370.      SetRect(&tRect, 5000, 5000, 5050, 5050);    /* off the screen and invisible */
  371.      wptr = NewWindow(nil, &tRect, "\004Hack", FALSE, 0, (long) -1, FALSE, (long) 0);
  372.      tRect = wptr->portRect;
  373.      hTE = TENew(&tRect, &tRect);
  374.  
  375.      if(!ReadRsrcFile(rec.fName, number, hTE)) {
  376.           TEDispose(hTE);
  377.           DisposeWindow(wptr);
  378.           return;
  379.      }
  380.  
  381.      TECalText(hTE);        /* co-conspirators in the hack */
  382.      TEUpdate(&tRect, hTE);
  383.  
  384.      if(!WriteTextFile(rec2.fName, rec2.vRefNum, hTE)) {
  385.           TEDispose(hTE);
  386.           DisposeWindow(wptr);
  387.           return;
  388.      }
  389.  
  390.      TEDispose(hTE);
  391.      DisposeWindow(wptr);
  392.  
  393.      ConversionCompleted();
  394. }
  395.  
  396.  
  397. /*
  398.  * Convert a 'TEXT' file to a 'HELP' resource file.
  399.  */
  400.  
  401. TEXTConvert()
  402. {
  403.      SFReply    rec, rec2;
  404.      SFTypeList typeList;
  405.      short      numTypes = 1;
  406.      int        number;
  407.      long       grow;
  408.      char       temp[256], name[256];
  409.      Handle     hdl, hdl2;
  410.      Rect       tRect;
  411.      TEHandle   hTE;
  412.  
  413.      MaxMem(&grow);            /* clear out some heap space */
  414.  
  415.      typeList[0] = 'TEXT';
  416.  
  417.      ParamText("\017Read TEXT from:", nil, nil, nil);
  418.  
  419.      SFGetFile(pass(whereOpen), nil, nil, numTypes, typeList, nil, &rec);
  420.  
  421.      if(rec.good == 0)                /* 'Cancel' button hit */
  422.           return;
  423.  
  424.      Pstrcpy(temp, rec.fName);
  425.      ptoc(temp);
  426.      strcat(temp, ".Rsrc");        /* append ".Rsrc" to original filename */
  427.      ctop(temp);
  428.  
  429.      hdl = GetString(256);
  430.      HLock(hdl);
  431.      SFPutFile(pass(whereSaveAs), *hdl, temp, nil, &rec2);
  432.      HUnlock(hdl);
  433.  
  434.      if(rec2.good == 0)                /* 'Cancel' hit */
  435.           return -1;
  436.  
  437.      Pstrcpy(name, rec.fName);
  438.      if(!RsrcDialog(&number, name, FALSE))
  439.           return;            /* 'Cancel' hit */
  440.  
  441.      SetRect(&tRect, 2000, 2000, 2020, 2020);
  442.      hTE = TENew(&tRect, &tRect);
  443.  
  444.      if(!ReadTextFile(rec.fName, rec.vRefNum, hTE)) {
  445.           TEDispose(hTE);
  446.           return;
  447.      }
  448.  
  449.      if(!WriteRsrcFile(rec2.fName, name, number, hTE)) {
  450.           TEDispose(hTE);
  451.           return;
  452.      }
  453.  
  454.      TEDispose(hTE);
  455.  
  456.      ConversionCompleted();
  457. }
  458.  
  459.  
  460. /*
  461.  * Read from the resource file from the given filename & resource number,
  462.  * and put the info into the textedit handle passed.
  463.  */
  464.  
  465. Boolean ReadRsrcFile(fName, rNum, hTE)
  466. char *fName;
  467. int  rNum;
  468. TEHandle hTE;
  469. {
  470.      int  refNum;
  471.      Handle hdl;
  472.  
  473.      if((refNum = OpenResFile(fName)) < 0) {
  474.           ErrorCall(303);
  475.           return FALSE;
  476.      }
  477.  
  478.      if((hdl = GetResource('HELP', rNum)) == nil) {
  479.           CloseResFile(refNum);
  480.           ErrorCall(304);
  481.           return FALSE;
  482.      }
  483.  
  484.      TESetText(*hdl, SizeResource(hdl), hTE);
  485.  
  486.      ReleaseResource(hdl);
  487.      CloseResFile(refNum);
  488.  
  489.      return TRUE;
  490. }
  491.  
  492.  
  493. /*
  494.  * Read a TEXT file from the filename and refnum passed, and put the
  495.  * text into the textedit handle passed.
  496.  */
  497.  
  498. Boolean ReadTextFile(fname, vRefNum, hTE)
  499. char *fname;
  500. int  vRefNum;
  501. TEHandle hTE;
  502. {
  503.      int  refNum;
  504.      long logEOF;
  505.  
  506.      if(FSOpen(fname, vRefNum, &refNum) != 0) {
  507.           FSClose(refNum);
  508.           ErrorCall(300);
  509.           return FALSE;                /* file wasn't read */
  510.      }
  511.  
  512.      if(GetEOF(refNum, &logEOF) != 0) {
  513.           FSClose(refNum);
  514.           ErrorCall(312);
  515.           return FALSE;
  516.      }
  517.  
  518.      if(logEOF > 32000) {
  519.           FSClose(refNum);
  520.           ErrorCall(302);
  521.           return FALSE;
  522.      }
  523.  
  524.      SetHandleSize((*hTE)->hText, logEOF);
  525.  
  526.      if(FSRead(refNum, &logEOF, *((*hTE)->hText)) != 0) {
  527.           FSClose(refNum);
  528.           ErrorCall(313);
  529.           return FALSE;
  530.      }
  531.  
  532.      if(FSClose(refNum) != 0) {
  533.           ErrorCall(314);
  534.           return FALSE;
  535.      }
  536.  
  537.      (*hTE)->teLength = (int) logEOF;
  538.  
  539.      return TRUE;
  540. }
  541.  
  542.  
  543. /*
  544.  * Write to the resource file from the given filename, resource name & number,
  545.  * using the text referenced by the textedit handle.  Check to see if the
  546.  * resource already exists, and if so, allow them to cancel or continue.
  547.  */
  548.  
  549. Boolean WriteRsrcFile(fName, rName, rNum, hTE)
  550. char *fName, *rName;
  551. int  rNum;
  552. TEHandle hTE;
  553. {
  554.      int  refNum;
  555.      Handle hdl, hdl2;
  556.  
  557.      if((refNum = OpenResFile(fName)) < 0) {    /* doesn't exist, create it */
  558.           CreateResFile(fName);
  559.           if((refNum = OpenResFile(fName)) < 0) {    /* fatal error of some kind */
  560.                ErrorCall(305);
  561.                return FALSE;
  562.           }
  563.      }
  564.  
  565.      if((hdl = GetResource('HELP', rNum)) != nil)
  566.           if(!OverWriteDialog(fName, rName, rNum)) {
  567.                CloseResFile(refNum);
  568.                return FALSE;
  569.           }
  570.           else {
  571.                RmveResource(hdl);
  572.                if(ResError() < 0) {            /* remove failed */
  573.                     hdl2 = GetString(316);
  574.                     HLock(hdl2);
  575.                     GeneralError(*hdl2, nil, nil, nil);
  576.                     HUnlock(hdl2);
  577.                     CloseResFile(refNum);
  578.                     return FALSE;
  579.                }
  580.                DisposHandle(hdl);
  581.                UpdateResFile(refNum);
  582.           }
  583.  
  584.      AddResource((*hTE)->hText, 'HELP', rNum, rName);
  585.      UpdateResFile(refNum);
  586.      CloseResFile(refNum);
  587.  
  588.      return TRUE;
  589. }
  590.  
  591.  
  592. /*
  593.  * Write out the file, using the filename and refnum passed, and the
  594.  * text to write is referenced by the textedit handle.
  595.  */
  596.  
  597. Boolean WriteTextFile(fname, vRefNum, hTE)
  598. char *fname;
  599. int  vRefNum;
  600. TEHandle hTE;
  601. {
  602.      int  io_code, refNum;
  603.      long count;
  604.  
  605.      count = (long) (*hTE)->teLength;
  606.  
  607.      if((io_code = FSOpen(fname, vRefNum, &refNum)) != 0) {
  608.           if(io_code == -43) {            /* 'file not found' - create it! */
  609.                if(Create(fname, vRefNum, '    ', 'TEXT') != 0) {
  610.                     ErrorCall(315);
  611.                     return FALSE;
  612.                }
  613.                if(FSOpen(fname, vRefNum, &refNum) != 0) {
  614.                     ErrorCall(306);
  615.                     return FALSE;
  616.                }
  617.           }
  618.           else {
  619.                ErrorCall(307);
  620.                return FALSE;            /* error occurred during open */
  621.           }
  622.      }
  623.  
  624.      if(FSWrite(refNum, &count, *((*hTE)->hText)) != 0) {
  625.           ErrorCall(308);
  626.           return FALSE;
  627.      }
  628.  
  629.      if(SetEOF(refNum, count) != 0) {
  630.           ErrorCall(309);
  631.           return FALSE;
  632.      }
  633.  
  634.      if(FSClose(refNum) != 0) {
  635.           ErrorCall(310);
  636.           return FALSE;
  637.      }
  638.  
  639.      if(FlushVol(nil, vRefNum) != 0) {
  640.           ErrorCall(311);
  641.           return FALSE;
  642.      }
  643.  
  644.      return TRUE;
  645. }
  646.  
  647.  
  648. /********** dialog & alert routines begin here ***********/
  649.  
  650.  
  651. /*
  652.  * Pop up our 'About...' box.
  653.  */
  654.  
  655. AboutHT()
  656. {
  657.      int         i, type, itemHit = 0;
  658.      DialogPtr   DPtr;
  659.      Rect        tRect, i3Rect, i4Rect, i5Rect, i9Rect;
  660.      Handle      item, icon;
  661.      static long lastClickTime = 0;
  662.  
  663.      selection = 0;
  664.      inHelpTextBox = FALSE;
  665.  
  666.      icon = GetIcon(KENT_ICON);
  667.  
  668.      DPtr = GetNewDialog(ABOUT_DLOG, nil, (long) -1);    /* invisible */
  669.  
  670.      GetDItem(DPtr, 9, &type, &item, &i9Rect);        /* icon */
  671.      GetDItem(DPtr, 3, &type, &item, &i3Rect);        /* big box for help titles */
  672.      htBox = i3Rect;
  673.      GetDItem(DPtr, 4, &type, &item, &i4Rect);        /* scroll bar */
  674.      GetDItem(DPtr, 5, &type, &item, &i5Rect);        /* dashed line */
  675.  
  676.      ShowWindow(DPtr);
  677.      SetPort(DPtr);
  678.  
  679.      PlotIcon(&i9Rect, icon);
  680.  
  681.      PenPat(&gray);                /* dashed seperator line */
  682.      MoveTo(i5Rect.left, i5Rect.top);
  683.      LineTo(i5Rect.left, i5Rect.bottom);
  684.      PenNormal();
  685.  
  686.      FrameRect(&i3Rect);            /* big help titles box */
  687.  
  688.      vsb = NewControl(DPtr, &i4Rect, "\003vsb", (Boolean) -1, 0, 0, 0, scrollBarProc, (long) 0);
  689.  
  690.      GetDItem(DPtr, 2, &type, &item, &tRect);
  691.      if(noHelpResources)
  692.           HiliteControl((ControlHandle) item, 255);    /* disable 'Help' button */
  693.      else {                    /* put help titles into box */
  694.           if(hTListNum > MAX_TITLES_IN_BOX)
  695.                SetCtlMax(vsb, hTListNum - MAX_TITLES_IN_BOX);
  696.           HTDisplay();
  697.      }
  698.  
  699.      while(1) {
  700.           inHelpTextBox = FALSE;
  701.           ModalDialog(nil, &itemHit);
  702.           if(itemHit == 1) {                /* 'Cancel' */
  703.                CloseDialog(DPtr);
  704.                break;
  705.           }
  706.           else if(itemHit == 2) {            /* 'Help' */
  707.                CloseDialog(DPtr);
  708.                HelpDialog();
  709.                break;
  710.           }
  711.           else if(itemHit == 3) {            /* a title was selected */
  712.                if(noHelpResources)
  713.                     continue;
  714.                while(Button())            /* check for double-click */
  715.                     ;
  716.                if(TickCount() - lastClickTime <= GetDbleTime()) {
  717.                     CloseDialog(DPtr);
  718.                     HelpDialog();
  719.                     break;
  720.                }
  721.                else
  722.                     HTSelect();
  723.                lastClickTime = TickCount();
  724.           }
  725.           else if(itemHit == 4)                /* in scroll bar */
  726.                MyScroll((WindowPtr) DPtr);
  727.      }
  728. }
  729.  
  730.  
  731. /*
  732.  * This dialog tells the user that conversion process is over.
  733.  */
  734.  
  735. ConversionCompleted()
  736. {
  737.      int         itemHit = 0;
  738.      DialogPtr   DPtr;
  739.      EventRecord myRec;
  740.  
  741.      HiliteMenu(0);
  742.  
  743.      DPtr = GetNewDialog(CONV_DLOG, nil, (long) -1);
  744.      SetPort(DPtr);
  745.      DrawDialog(DPtr);
  746.  
  747.      while(!EventAvail(mDownMask | keyDownMask, &myRec))
  748.           ;            /* wait for a mouse down or key down event */
  749.  
  750.      CloseDialog(DPtr);
  751. }
  752.  
  753.  
  754. /*
  755.  * Pop up an alert box and pass some strings to tell what happened.
  756.  */
  757.  
  758. GeneralError(str1, str2, str3, str4)
  759. char *str1, *str2, *str3, *str4;            /* Pascal format */
  760. {
  761.      ParamText("\000", "\000", "\000", "\000");
  762.      ParamText(str1, str2, str3, str4);
  763.      StopAlert(GENERAL_ERROR_ALRT, nil);
  764. }
  765.  
  766.  
  767. /*
  768.  * Pop up the dialog box that actually displays the text of the help messages.
  769.  */
  770.  
  771. HelpDialog()
  772. {
  773.      int       itemHit, type;
  774.      Rect      box, textBox;
  775.      Handle    hdl;
  776.      DialogPtr DPtr;
  777.  
  778.      DPtr = GetNewDialog(HELP_DLOG, nil, (long) -1);
  779.      SetPort(DPtr);
  780.  
  781.      GetDItem(DPtr, 6, &type, &hdl, &textBox);
  782.      FrameRect(&textBox);
  783.      textBox.top += 1;                /* borders for help text */
  784.      textBox.left += 5;
  785.      textBox.bottom -= 1;
  786.      textBox.right -= 5;
  787.  
  788.      GetDItem(DPtr, 7, &type, &hdl, &box);
  789.      vsb = NewControl(DPtr, &box, "\003vsb", (Boolean) -1, 0, 0, 0, scrollBarProc, (long) 0);
  790.  
  791. loop:
  792.      inHelpTextBox = TRUE;
  793.  
  794.      GetDItem(DPtr, 3, &type, &hdl, &box);
  795.      if(selection == (hTListNum - 1))            /* disable 'Next' */
  796.           HiliteControl((ControlHandle) hdl, 255);
  797.      else
  798.           HiliteControl((ControlHandle) hdl, 0);
  799.  
  800.      GetDItem(DPtr, 4, &type, &hdl, &box);
  801.      if(selection == 0)                    /* disable 'Previous' */
  802.           HiliteControl((ControlHandle) hdl, 255);
  803.      else
  804.           HiliteControl((ControlHandle) hdl, 0);
  805.  
  806.      GetDItem(DPtr, 5, &type, &hdl, &box);        /* help title */
  807.      EraseRect(&box);
  808.      TextFont(systemFont);
  809.      MoveTo(box.left+2, box.bottom-3);
  810.      DrawString(hNodeList[selection]->hName);
  811.  
  812.      if((hdl = GetResource('HELP', hNodeList[selection]->hNum)) == nil) {
  813.           hdl = GetString(270);
  814.           HLock(hdl);
  815.           GeneralError(*hdl, nil, nil, nil);
  816.           HUnlock(hdl);
  817.           CloseDialog(DPtr);
  818.           return;
  819.      }
  820.  
  821.      hTE = TENew(&textBox, &textBox);
  822.      TESetText(*hdl, SizeResource(hdl) - 1, hTE);
  823.      ReleaseResource(hdl);        /* free the resource handle */
  824.  
  825.      (*hTE)->txFont = Helvetica;    /* Helvetica-12, in .Help file */
  826.      (*hTE)->crOnly = -1;        /* signals a wrap at newline only */
  827.      TECalText(hTE);
  828.      EraseRect(&textBox);        /* wipe out what was there before */
  829.      TEUpdate(&textBox, hTE);
  830.  
  831.      SetCtlValue(vsb, 0);
  832.  
  833.      if((*hTE)->nLines > MAX_LINES_IN_BOX)
  834.           SetCtlMax(vsb, (*hTE)->nLines - MAX_LINES_IN_BOX);
  835.      else
  836.           SetCtlMax(vsb, 0);
  837.  
  838.      while(1) {
  839.           ModalDialog(nil, &itemHit);
  840.           if(itemHit == 1) {                /* 'Cancel' */
  841.                CloseDialog(DPtr);
  842.                TEDispose(hTE);
  843.                break;
  844.           }
  845.           else if(itemHit == 2) {            /* 'Topics' */
  846.                CloseDialog(DPtr);
  847.                TEDispose(hTE);
  848.                AboutHT();
  849.                break;
  850.           }
  851.           else if(itemHit == 3) {            /* 'Next' */
  852.                TEDispose(hTE);
  853.                ++selection;
  854.                goto loop;
  855.           }
  856.           else if(itemHit == 4) {            /* 'Previous' */
  857.                TEDispose(hTE);
  858.                --selection;
  859.                goto loop;
  860.           }
  861.           else if(itemHit == 7)                /* scroll bar */
  862.                MyScroll();
  863.      }
  864. }
  865.  
  866.  
  867. /*
  868.  * A small graphical introduction to our program.
  869.  */
  870.  
  871. Introduction()
  872. {
  873.      Rect        boundsRect, theFrame;
  874.      DialogPtr   DPtr;
  875.      PicHandle   myPic;
  876.      EventRecord myRec;
  877.  
  878.      myPic = GetPicture(256);
  879.      theFrame = (*myPic)->picFrame;
  880.      OffsetRect(&theFrame, -theFrame.left + 5, -theFrame.top + 10);
  881.  
  882.      SetRect(&boundsRect, 120,60,390,250);
  883.  
  884.      DPtr = NewDialog(nil, &boundsRect, "\000", TRUE, 3, (long) -1, FALSE, (long) 0, nil);
  885.      SetPort(DPtr);
  886.  
  887.      HLock(myPic);
  888.      DrawPicture(myPic, &theFrame);
  889.      HUnlock(myPic);
  890.  
  891.      while(!EventAvail(mDownMask | keyDownMask, &myRec))    /* wait for a mouse or key event */
  892.           ;
  893.  
  894.      KillPicture(myPic);            /* free up the space */
  895.      CloseDialog(DPtr);
  896. }
  897.  
  898.  
  899. /*
  900.  * Pop up this dialog if a resource being written to already exists.
  901.  * The user has the option to cancel the operation or overwrite the
  902.  * existing resource in favor of the new one being created.
  903.  * Return TRUE to overwrite, FALSE otherwise.
  904.  */
  905.  
  906. Boolean OverWriteDialog(fileName, resName, resNumber)
  907. char *fileName, *resName;
  908. int  resNumber;
  909. {
  910.      int       itemHit = 0;
  911.      char      str[256];
  912.      DialogPtr DPtr;
  913.  
  914.      SysBeep(3);
  915.      sprintf(str, "%d", resNumber);
  916.      ParamText(fileName, ctop(str), resName, nil);
  917.  
  918.      DPtr = GetNewDialog(OVERWRITE_DLOG, nil, (long) -1);
  919.      SetPort(DPtr);
  920.  
  921.      while(1) {
  922.           ModalDialog(nil, &itemHit);
  923.           if(itemHit == 1) {                /* 'Overwrite' */
  924.                CloseDialog(DPtr);
  925.                return TRUE;
  926.           }
  927.           else if(itemHit == 2) {            /* 'Cancel' */
  928.                CloseDialog(DPtr);
  929.                return FALSE;
  930.           }
  931.      }
  932. }
  933.  
  934.  
  935. /*
  936.  * This dialog asks the user to input the resource name & number
  937.  * to use in the conversion process.  Return FALSE if the Cancel
  938.  * button was hit, else return TRUE.
  939.  */
  940.  
  941. Boolean RsrcDialog(number, name, use_help_dialog)
  942. int  *number;
  943. char *name;
  944. Boolean use_help_dialog;
  945. {
  946.      int       type, itemHit = 0;
  947.      char      str[256];
  948.      DialogPtr DPtr;
  949.      Handle    hdl;
  950.      Rect      box;
  951.  
  952.      if(use_help_dialog)
  953.           DPtr = GetNewDialog(RSRC_2_DLOG, nil, (long) -1);
  954.      else {
  955.           DPtr = GetNewDialog(RSRC_DLOG, nil, (long) -1);
  956.           GetDItem(DPtr, 6, &type, &hdl, &box);    /* resource number */
  957.           SetIText(hdl, name);        /* the text file's name as a default */
  958.      }
  959.  
  960.      SetPort(DPtr);
  961.  
  962.      while(1) {
  963.           ModalDialog(nil, &itemHit);
  964.           if(itemHit == 1) {                /* 'OK' */
  965.                GetDItem(DPtr, 4, &type, &hdl, &box);    /* resource number */
  966.                GetIText(hdl, &str);
  967.                *number = atoi(ptoc(str));
  968.                if(*number < 0 || *number > 32767) {
  969.                     hdl = GetString(317);
  970.                     HLock(hdl);
  971.                     GeneralError(*hdl, nil, nil, nil);
  972.                     HUnlock(hdl);
  973.                     continue;
  974.                }
  975.                GetDItem(DPtr, 6, &type, &hdl, &box);    /* resource name */
  976.                GetIText(hdl, &str);
  977.                Pstrcpy(name, str);
  978.                CloseDialog(DPtr);
  979.                return TRUE;
  980.           }
  981.           else if(itemHit == 2) {            /* 'Cancel' */
  982.                CloseDialog(DPtr);
  983.                return FALSE;
  984.           }
  985.      }
  986. }
  987.  
  988.  
  989. /********** support routines for the 'help' dialog stuff start here *********/
  990.  
  991.  
  992. /*
  993.  * Read the 'help' resource file and load all of the available
  994.  * names into the global list.  This is done at startup
  995.  * time, so that it will not have to be done every time that
  996.  * the 'About...' box is opened, thus saving some time.
  997.  */
  998.  
  999. GetHelpTitles()
  1000. {
  1001.      int    i, num, refNum;
  1002.      long   rType;
  1003.      char   name[256];
  1004.      Rect   tRect;
  1005.      Handle hdl;
  1006.  
  1007.      if((refNum = OpenResFile(HELP_FILE)) == -1)
  1008.           noHelpResources = TRUE;
  1009.      else {        /* check to make sure there are 'HELP' resources there */
  1010.           if((hTListNum = CountResources('HELP')) == 0)    /* how many titles */
  1011.                noHelpResources = TRUE;
  1012.           else {
  1013.                noHelpResources = FALSE;
  1014.                for(i = 0;i < hTListNum;++i) {
  1015.                     hdl = GetIndResource('HELP', i+1);
  1016.                     GetResInfo(hdl, &num, &rType, name);
  1017.                     hNodeList[i] = (struct hNode *) calloc(1, sizeof(struct hNode));
  1018.                     hNodeList[i]->hName = calloc(1, (int) (name[0] + 1));
  1019.                     Pstrcpy(hNodeList[i]->hName, name);
  1020.                     hNodeList[i]->hNum = num;
  1021.                     ReleaseResource(hdl);
  1022.                }
  1023.           }
  1024.  
  1025.           CloseResFile(refNum);
  1026.      }
  1027. }
  1028.  
  1029.  
  1030. /*
  1031.  * Show the strings in a textbox sort of environment just like the
  1032.  * standard file package.  If one of the visible titles is selected,
  1033.  * then invert the rectangle around it, thus highlighting it.
  1034.  */
  1035.  
  1036. HTDisplay()
  1037. {
  1038.      int  i, ctl_value;
  1039.      Rect tRect;
  1040.  
  1041.      tRect = htBox;
  1042.  
  1043.      tRect.top += 1;
  1044.      tRect.left += 1;
  1045.      tRect.bottom = tRect.top + 16;
  1046.      tRect.right -= 1;
  1047.      ctl_value = GetCtlValue(vsb);
  1048.  
  1049.      for(i = ctl_value;i < hTListNum;++i) {
  1050.           if((i - ctl_value) == MAX_TITLES_IN_BOX)
  1051.                break;
  1052.           EraseRect(&tRect);
  1053.           MoveTo(tRect.left+2, tRect.bottom-4);
  1054.           DrawString(hNodeList[i]->hName);
  1055.  
  1056.           if(i == selection)
  1057.                InvertRect(&tRect);
  1058.           tRect.top += 16;
  1059.           tRect.bottom += 16;
  1060.      }
  1061. }
  1062.  
  1063.  
  1064. /*
  1065.  * Handle a mouse-down event in our 'box' that shows all of the
  1066.  * titles the user has to choose from.
  1067.  */
  1068.  
  1069. HTSelect()
  1070. {
  1071.      int  i, temp_i;
  1072.      Rect new_sel_rect, old_sel_rect, tRect;
  1073.      Point pt;
  1074.  
  1075.      SetRect(&old_sel_rect, 0, 0, 0, 0);        /* empty rect */
  1076.      new_sel_rect = old_sel_rect;
  1077.  
  1078.      tRect = htBox;
  1079.      tRect.top += 1;
  1080.      tRect.left += 1;
  1081.      tRect.bottom = tRect.top + 16;
  1082.      tRect.right -= 1;
  1083.      GetMouse(&pt);
  1084.  
  1085.      for(i = 0;i < MAX_TITLES_IN_BOX;++i) {
  1086.           if(PtInRect(pass(pt), &tRect)) {
  1087.                temp_i = i;
  1088.                new_sel_rect = tRect;
  1089.           }
  1090.  
  1091.           if(selection == (i + GetCtlValue(vsb)))
  1092.                old_sel_rect = tRect;
  1093.  
  1094.           tRect.top += 16;
  1095.           tRect.bottom += 16;
  1096.      }
  1097.  
  1098.      if(!EqualRect(&old_sel_rect, &new_sel_rect)) {    /* is the selection the same? */
  1099.           if(!EmptyRect(&old_sel_rect))            /* is it visible? */
  1100.                InvertRect(&old_sel_rect);
  1101.           if(temp_i < hTListNum) {
  1102.                selection = temp_i + GetCtlValue(vsb);
  1103.                InvertRect(&new_sel_rect);
  1104.           }
  1105.      }
  1106. }
  1107.  
  1108.  
  1109. /*
  1110.  * Handle the scroll bar we set up in our dialog.  This routine can
  1111.  * handle the titles box and the box where the help text appears, since
  1112.  * they are done differently.
  1113.  */
  1114.  
  1115. MyScroll(wptr)
  1116. WindowPtr wptr;
  1117. {
  1118.      int   max, oldValue;
  1119.      Point pt;
  1120.      ControlHandle whichControl;
  1121.  
  1122.      GetMouse(&pt);
  1123.      if(inHelpTextBox)
  1124.           max = MAX_LINES_IN_BOX;
  1125.      else
  1126.           max = MAX_TITLES_IN_BOX;
  1127.  
  1128.      switch(FindControl(pass(pt), wptr, &whichControl)) {
  1129.           case inUpButton:
  1130.                TrackControl(vsb, pass(pt), DScrollUp);
  1131.                break;
  1132.           case inDownButton:
  1133.                TrackControl(vsb, pass(pt), DScrollDown);
  1134.                break;
  1135.           case inPageUp:
  1136.                do {
  1137.                     GetMouse(&pt);
  1138.                     if(TestControl(whichControl, pass(pt)) == inPageUp) {
  1139.                          if(inHelpTextBox) {
  1140.                               oldValue = GetCtlValue(whichControl);
  1141.                               SetCtlValue(whichControl, oldValue - MAX_LINES_IN_BOX);
  1142.                               TEScroll(0, (oldValue - GetCtlValue(whichControl)) * (*hTE)->lineHeight, hTE);
  1143.                          }
  1144.                          else {
  1145.                               SetCtlValue(whichControl, GetCtlValue(whichControl) - MAX_TITLES_IN_BOX);
  1146.                               HTDisplay();
  1147.                          }
  1148.                     }
  1149.                } while(StillDown());
  1150.                break;
  1151.           case inPageDown:
  1152.                do {
  1153.                     GetMouse(&pt);
  1154.                     if(TestControl(whichControl, pass(pt)) == inPageDown) {
  1155.                          if(inHelpTextBox) {
  1156.                               oldValue = GetCtlValue(whichControl);
  1157.                               SetCtlValue(whichControl, oldValue + MAX_LINES_IN_BOX);
  1158.                               TEScroll(0, (oldValue - GetCtlValue(whichControl)) * (*hTE)->lineHeight, hTE);
  1159.                          }
  1160.                          else {
  1161.                               SetCtlValue(whichControl, GetCtlValue(whichControl) + MAX_TITLES_IN_BOX);
  1162.                               HTDisplay();
  1163.                          }
  1164.                     }
  1165.                } while(StillDown());
  1166.                break;
  1167.           case inThumb:
  1168.                oldValue = GetCtlValue(whichControl);
  1169.                TrackControl(whichControl, pass(pt), nil);
  1170.                if(inHelpTextBox)
  1171.                     TEScroll(0, (oldValue - GetCtlValue(whichControl)) * (*hTE)->lineHeight, hTE);
  1172.                else
  1173.                     HTDisplay();
  1174.                break;
  1175.      }
  1176.  
  1177. }
  1178.  
  1179.  
  1180. pascal void DScrollDown(theControl,theCode)
  1181. ControlHandle theControl;
  1182. int  theCode;
  1183. {
  1184.      if(theCode == inDownButton) {
  1185.           if(GetCtlValue(theControl) == GetCtlMax(theControl))
  1186.                return;                /* don't whip a dead horse */
  1187.           SetCtlValue(theControl, GetCtlValue(theControl) + 1);
  1188.           if(inHelpTextBox)
  1189.                TEScroll(0, -(*hTE)->lineHeight, hTE);
  1190.           else
  1191.                HTDisplay();
  1192.      }
  1193. }
  1194.  
  1195.  
  1196. pascal void DScrollUp(theControl,theCode)
  1197. ControlHandle theControl;
  1198. int  theCode;
  1199. {
  1200.      if(theCode == inUpButton) {
  1201.           if(GetCtlValue(theControl) == GetCtlMin(theControl))
  1202.                return;
  1203.           SetCtlValue(theControl, GetCtlValue(theControl) - 1);
  1204.           if(inHelpTextBox)
  1205.                TEScroll(0, (*hTE)->lineHeight, hTE);
  1206.           else
  1207.                HTDisplay();
  1208.      }
  1209. }
  1210.  
  1211.  
  1212. /************* miscellaneous routines that don't fit elsewhere *************/
  1213.  
  1214.  
  1215. /*
  1216.  * Copy a Pascal string to a pascal string.
  1217.  */
  1218.  
  1219. Pstrcpy(dest, src)
  1220. char *dest, *src;
  1221. {
  1222.      int  i;
  1223.  
  1224.      for(i = 1;i <= src[0];++i)
  1225.           dest[i] = src[i];
  1226.  
  1227.      dest[0] = src[0];
  1228. }
  1229.