home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d502 / cells.lha / CELLS / CELLSSource.lzh / cDoHelp.c < prev    next >
C/C++ Source or Header  |  1991-04-20  |  18KB  |  634 lines

  1. /*
  2.  *  CELLS       An Implementation of the WireWorld cellular automata
  3.  *              as described in Scientific American, Jan 1990.
  4.  *
  5.  *              Copyright 1990 by Davide P. Cervone.
  6.  *  You may use this code, provided this copyright notice is kept intact.
  7.  *  See the CELLS.HELP file for complete information on distribution conditions.
  8.  */
  9.  
  10. /*
  11.  *  File:  cDoHelp.c            Handles the Help facility
  12.  */
  13.  
  14.  
  15. #include "cGadget.h"
  16. #include "cRequest.h"
  17. #include "cHelp.h"
  18. #include "cReqHelp.h"
  19. #include <ctype.h>
  20.  
  21. #define ABTTEXT     ABTRequest.er_Request.ReqText
  22. #define HLPGADGET   HLPRequest.er_Request.ReqGadget
  23.  
  24.  
  25. extern char HlpNameBuf[];                   /* Help name gadget buffer */
  26. int HelpActive;                             /* TRUE if help requester is up */
  27. HELPITEM *DefaultHelpTopic = &DefaultHelp;  /* HELP button on HELP requester */
  28.  
  29. static HELPITEM *CurrentRoot;       /* root of current Help tree */
  30. static HELPITEM *CurrentNode;       /* current topic in Help tree */
  31. static HELPITEM *OldNode;           /* topic in use before HELP was pressed */
  32. static int HelpOnHelp;              /* TRUE if HELP pressed during Help */
  33. static int HelpMode;                /* Text or Topic mode */
  34.    #define HM_TEXT      0
  35.    #define HM_TOPICS    1
  36.  
  37. /*
  38.  *  return values from keyword match test
  39.  */
  40.  
  41. #define NOMATCH     0
  42. #define MATCHED     1
  43. #define MORETOPIC   2
  44.  
  45.  
  46. /*
  47.  *  PrefixMatch()
  48.  *
  49.  *  Compare two keyword strings:
  50.  *  find the first character that does not match (or the end of the string)
  51.  *  If we matched all of string 1, return MATCHED,
  52.  *  Otherwise, if we matched at least one character,
  53.  *    if the last matched character was a space, go back to that space
  54.  *    otherwise, if the unmatched character was a space, skip to the
  55.  *      first non-space.
  56.  *    if we matched up to a space,
  57.  *      set the return string to the unmatched character,
  58.  *      if there are more un-matched characters, return MORETOPIC
  59.  *      otherwise return completely matched (MATCHED)
  60.  */
  61.  
  62. static int PrefixMatch(Src,Target)
  63. char **Src,*Target;
  64. {
  65.    char c1,c2;
  66.    char *s = *Src;
  67.    int status = NOMATCH;
  68.    
  69.    c1 = toupper(*s); c2 = toupper(*Target);
  70.    while (c1 && c1 == c2)
  71.    {
  72.       s++; Target++;
  73.       c1 = toupper(*s); c2 = toupper(*Target);
  74.    }
  75.    if (c1 == 0)
  76.    {
  77.       status = MATCHED;
  78.       *Src = s;
  79.    } else if (s > *Src) {
  80.       if (*s != ' ' && *(s-1) == ' ') s--;
  81.       else if (*s == ' ') while (*(s+1) == ' ') s++;
  82.       if (*s == ' ')
  83.       {
  84.          s++; *Src = s;
  85.          if (*s) status = MORETOPIC; else status = MATCHED;
  86.       }
  87.    }
  88.    return(status);
  89. }
  90.  
  91.  
  92. /*
  93.  *  FindHelp()
  94.  *
  95.  *  Starting at the bottom of the item list containing the specified item,
  96.  *  while there are more items and we have not found the one we want,
  97.  *    match the rest of the name agains the test topic
  98.  *    If an exact match, we're done.
  99.  *    if there is more to the topic,
  100.  *      save the topic (if one was not already saved, or this one matches more)
  101.  *      then go on to the "next" topic
  102.  *    If no match (or more topic)
  103.  *      go to the next item (the previous one in the list)
  104.  *      if we're at the end of the list and there was a partial match
  105.  *        starting with the rest of the topic name
  106.  *        and looking at the subtopics of the matched topic
  107.  *          (at the end of the list)
  108.  *        keep looking for more matches
  109.  *  If not found go back to the last topic matched.
  110.  *  If there's still more topics unmatched, give a warning
  111.  *  return the last matched item.
  112.  */
  113.  
  114. static HELPITEM *FindHelp(theItem,Name)
  115. HELPITEM *theItem;
  116. char *Name;
  117. {
  118.    HELPITEM *Parent = theItem;
  119.    HELPITEM *LastMatch = NULL;
  120.    char *RestOfTopics = NULL;
  121.    char *Remainder;
  122.    int NotFound = TRUE;
  123.  
  124.    theItem = Parent->SubTopics;
  125.    if (theItem) while (theItem->Next) theItem = theItem->Next;
  126.    while (theItem && NotFound)
  127.    {
  128.       Remainder = Name;
  129.       switch(PrefixMatch(&Remainder,theItem->Name))
  130.       {
  131.          case MATCHED:
  132.             NotFound = FALSE;
  133.             Name = Remainder;
  134.             break;
  135.  
  136.          case MORETOPIC:
  137.             if (LastMatch == NULL || Remainder > RestOfTopics)
  138.             {
  139.                LastMatch = theItem;
  140.                RestOfTopics = Remainder;
  141.             }
  142.          case NOMATCH:
  143.             theItem = theItem->Prev;
  144.             if (theItem == NULL && LastMatch)
  145.             {
  146.                Name = RestOfTopics; RestOfTopics = NULL;
  147.                Parent = LastMatch; LastMatch = NULL;
  148.                theItem = Parent->SubTopics;
  149.                if (theItem) while (theItem->Next) theItem = theItem->Next;
  150.             }
  151.             break;
  152.       }
  153.    }
  154.    if (NotFound) theItem = Parent;
  155.    if (Name && Name[0]) DoError("Can't Find Topic '%s'",Name);
  156.    return(theItem);
  157. }
  158.  
  159.  
  160. /*
  161.  * SetHelpPen()
  162.  *
  163.  *  Set the pen color of the IntuiTexts for the Help list gadget
  164.  *  (depending on whether we're in Text Mode or Topic Mode).
  165.  */
  166.  
  167. static void SetHelpPen(thePen)
  168. int thePen;
  169. {
  170.    int i;
  171.  
  172.    for (i=0; i<HlpListInfo.Height; HlpListInfo.IText[i++].FrontPen = thePen);
  173. }
  174.  
  175.  
  176. /*
  177.  *  SetHelpText()
  178.  *
  179.  *  If the topic's text lines are not loaded, load them.
  180.  *  If there are text lines,
  181.  *    Unset the previous nodes INUSE flag,
  182.  *    Set the current node to this one, and set its INUSE flag
  183.  *    Set the requester buttons and titles properly
  184.  *    and if the Help requester is already up, unselect any items
  185.  *    set the IText pens, and set the list to showing the text lines
  186.  *    If the requester is already active,
  187.  *      clear the name string,
  188.  *      refresh the name, title and topics gadgets,
  189.  *      (refresh the topic gadget twice if it is selected, since it inverts)
  190.  *    set TEXT mode
  191.  *  Otherwise
  192.  *    give a warning about no text items
  193.  */
  194.  
  195. static void SetHelpText(theItem)
  196. HELPITEM *theItem;
  197. {
  198.    if ((theItem->Flags & HLP_LOADED) == 0) LoadItem(theItem);
  199.    if (theItem->Text)
  200.    {
  201.       CurrentNode->Flags &= ~HLP_INUSE;
  202.       CurrentNode = theItem; CurrentNode->Flags |= HLP_INUSE;
  203.       HLPGADGET[HLP_TOPICS].GadgetText->IText = "Topics";
  204.       HLPGADGET[HLP_TOPICS].GadgetID = HLP_TOPICS;
  205.       if (theItem->Title)
  206.          HLPGADGET[HLP_TITLE].GadgetText->IText = theItem->Title;
  207.         else
  208.          HLPGADGET[HLP_TITLE].GadgetText->IText = theItem->Name;
  209.       HLPGADGET[HLP_TITLE].GadgetText->LeftEdge = (HLP_TITLEW -
  210.          strlen(HLPGADGET[HLP_TITLE].GadgetText->IText)*CHAR_WIDTH) / 2;
  211.       if (ActiveRequest == &HLPRequest) UnsetListSelect(&HlpListInfo,TRUE);
  212.       SetHelpPen(TEXTPEN);
  213.       SetList(&(HLPGADGET[HLP_LIST]),theItem->Text,NULL);
  214.       if (ActiveRequest == &HLPRequest)
  215.       {
  216.          SetStringInfo(&HLPGADGET[HLP_NAME],"");
  217.          RefreshRequest(&HLPRequest,HLP_NAME,NULL);
  218.          RefreshRequest(&HLPRequest,HLP_TITLE,NULL);
  219.          RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
  220.          if (HLPGADGET[HLP_TOPICS].Flags & SELECTED)
  221.             RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
  222.       }
  223.       HelpMode = HM_TEXT;
  224.    } else {
  225.       DoError("No Text for this Help Topic");
  226.    }
  227. }
  228.  
  229. /*
  230.  *  SetHelpTopics()
  231.  *
  232.  *  If the item has no sub-topics, go to the parent for a topic list
  233.  *  If there are sub-topics
  234.  *    Clear the INUSE flag of the previous node,
  235.  *    Set the current node and set its INUSE flag
  236.  *    Set the gadget names, title, etc.
  237.  *    If the Help requester is already active, unselect any items
  238.  *    Set the IText pens
  239.  *    Set the gadget list to the list of topics
  240.  *    If the help request is active
  241.  *      clear the name gadget,
  242.  *      refresh the Name, Title, and Topic gadgets
  243.  *      (refresh the topic gadget twice if it is selected, since it inverts)
  244.  *    set the mode to TOPICS
  245.  *  Otherwise
  246.  *    display an error message
  247.  */
  248.  
  249. static void SetHelpTopics(theItem,SelectedItem)
  250. HELPITEM *theItem;
  251. HELPITEM *SelectedItem;
  252. {
  253.    while (theItem->SubTopics == NULL && theItem->Parent)
  254.       theItem = theItem->Parent;
  255.    if (theItem->SubTopics)
  256.    {
  257.       CurrentNode->Flags &= ~HLP_INUSE;
  258.       CurrentNode = theItem; CurrentNode->Flags |= HLP_INUSE;
  259.       HLPGADGET[HLP_TOPICS].GadgetText->IText = " Text ";
  260.       HLPGADGET[HLP_TOPICS].GadgetID = HLP_TEXT;
  261.       HLPGADGET[HLP_TITLE].GadgetText->IText = "Double-Click to Pick a Topic:";
  262.       HLPGADGET[HLP_TITLE].GadgetText->LeftEdge = (HLP_TITLEW-30*CHAR_WIDTH)/2;
  263.       if (ActiveRequest == &HLPRequest) UnsetListSelect(&HlpListInfo,TRUE);
  264.       SetHelpPen(TOPICPEN);
  265.       SetList(&(HLPGADGET[HLP_LIST]),theItem->SubTopics,SelectedItem);
  266.       if (ActiveRequest == &HLPRequest)
  267.       {
  268.          SetStringInfo(&HLPGADGET[HLP_NAME],"");
  269.          RefreshRequest(&HLPRequest,HLP_NAME,NULL);
  270.          RefreshRequest(&HLPRequest,HLP_TITLE,NULL);
  271.          RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
  272.          if (HLPGADGET[HLP_TOPICS].Flags & SELECTED)
  273.             RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
  274.       }
  275.       HelpMode = HM_TOPICS;
  276.    } else {
  277.       DoError("No Sub-Topics Available for this Topic");
  278.    }
  279. }
  280.  
  281.  
  282. /*
  283.  *  SetHelp()
  284.  *
  285.  *  If an item was specified,
  286.  *    if the item is a link to another topic,
  287.  *      find the linked item in the current tree,
  288.  *      if it can't be found, display an error and go back to the current node
  289.  *    Load the topics text if necessary
  290.  *    if there is text for this topic, set TEXT mode else set TOPIC mode
  291.  *  Otherwise (no topic)
  292.  *    Clear the title and the item list
  293.  */
  294.  
  295. static void SetHelp(theItem)
  296. HELPITEM *theItem;
  297. {
  298.    if (theItem)
  299.    {
  300.       if (theItem->Flags & HLP_LINKED)
  301.       {
  302.          theItem = FindHelp(CurrentRoot,theItem->Title);
  303.          if (theItem == NULL)
  304.          {
  305.             theItem = CurrentNode;
  306.             DoError("Target of LINK not Found");
  307.          }
  308.       }
  309.       if ((theItem->Flags & HLP_LOADED) == 0) LoadItem(theItem);
  310.       if (theItem->Text)
  311.          SetHelpText(theItem);
  312.         else
  313.          SetHelpTopics(theItem,CurrentNode);
  314.    } else {
  315.       HLPGADGET[HLP_TITLE].GadgetText->IText = NULL;
  316.       if (ActiveRequest == &HLPRequest)
  317.          RefreshRequest(&HLPRequest,HLP_TITLE,NULL);
  318.       SetList(&(HLPGADGET[HLP_LIST]),NULL,NULL);
  319.    }
  320. }
  321.  
  322.  
  323. /*
  324.  *  DoParent()
  325.  *
  326.  *  if there is a parent to the current item
  327.  *    set the parent's help text or topics, as needed
  328.  *  otherwise display an error message
  329.  */
  330.  
  331. static void DoParent()
  332. {
  333.    if (CurrentNode->Parent)
  334.    {
  335.       if (HelpMode == HM_TEXT)
  336.          SetHelpText(CurrentNode->Parent);
  337.         else
  338.          SetHelpTopics(CurrentNode->Parent,CurrentNode);
  339.    } else {
  340.       DoError("There is No Parent for this Help Item");
  341.    }
  342. }
  343.  
  344.  
  345. /*
  346.  *  HLPGadgetUp()
  347.  *
  348.  *  Do the right thing for each gadget up message:
  349.  *
  350.  *    DONE:
  351.  *      Clear the INUSE flag, clear the HelpActive flag, and remove
  352.  *      the requester.  Inverse the HELP button and reset the pointer color.
  353.  *
  354.  *    PARENT:
  355.  *      if SHIFT pressed, go to the help root, otherwise go to the parent.
  356.  *      activate the help name gadget.
  357.  *
  358.  *    TOPICS:
  359.  *      Set to the topic list of the current node.
  360.  *
  361.  *    TEXT:
  362.  *      Set to the help text of the current node.
  363.  *
  364.  *    MORE:
  365.  *      If there are more items not shown below,
  366.  *        if we're in text mode,
  367.  *          set the selected item to the last one on the previous page
  368.  *          (so that if there's not enough to fill an entire new page,
  369.  *          we can still see where the last page ended - the last line will
  370.  *          flash selected for a moment)
  371.  *        scroll down by a page
  372.  *      Otherwise (at the bottom of the list)
  373.  *        if in text mode, show topics, otherwise go to the parent
  374.  *        if text mode, delay a little, and activate the name gadget
  375.  *          this will deselect the last line of text selected above.
  376.  *
  377.  *    NAME:
  378.  *      if topics were selected (or typed)
  379.  *        find the selected item and display it
  380.  *      otherwise (name gadget it blank)
  381.  *        go to the parent
  382.  *      reactivate the name gadget.
  383.  *
  384.  *    SLIDER:
  385.  *      stop sliding the list.
  386.  */
  387.  
  388. static void HLPGadgetUp(theGadget,theMessage)
  389. struct Gadget *theGadget;
  390. struct IntuiMessage *theMessage;
  391. {
  392.    HELPITEM *theItem;
  393.  
  394.    switch(theGadget->GadgetID)
  395.    {
  396.       case HLP_DONE:
  397.          CurrentNode->Flags &= ~HLP_INUSE;
  398.          HelpActive = FALSE;
  399.          RemoveRequest(&HLPRequest);
  400.          InvertGadget(&cGadget[ID_HELP]);
  401.          if (MouseMoveType == MM_NONE && !Running)
  402.             SetPointerColor(PenInUse);
  403.          break;
  404.  
  405.       case HLP_PARENT:
  406.          if (theMessage->Qualifier & SHIFTKEYS)
  407.             SetHelp(CurrentRoot);
  408.            else
  409.             DoParent();
  410.          if (HelpMode == HM_TEXT) ActivateName(&HlpListInfo);
  411.          break;
  412.  
  413.       case HLP_TOPICS:
  414.          SetHelpTopics(CurrentNode,CurrentNode);
  415.          break;
  416.  
  417.       case HLP_TEXT:
  418.          SetHelpText(CurrentNode);
  419.          ActivateName(&HlpListInfo);
  420.          break;
  421.  
  422.       case HLP_MORE:
  423.          if (HlpListInfo.TopItem + HlpListInfo.Height < HlpListInfo.ListLen)
  424.          {
  425.             if (HelpMode == HM_TEXT)
  426.                HlpListInfo.SelectedItem = HlpListInfo.Height-1;
  427.             DoListPageDown(&HlpListInfo);
  428.          } else {
  429.             if (HelpMode == HM_TEXT)
  430.                SetHelpTopics(CurrentNode,CurrentNode);
  431.               else
  432.                DoParent();
  433.          }
  434.          if (HelpMode == HM_TEXT)
  435.          {
  436.             Delay(6L);
  437.             ActivateName(&HlpListInfo);
  438.          }
  439.          break;
  440.  
  441.       case HLP_NAME:
  442.          if (HlpNameBuf[0])
  443.          {
  444.             theItem = FindHelp(CurrentNode,HlpNameBuf);
  445.             if (theItem) SetHelp(theItem);
  446.          } else {
  447.             DoParent();
  448.          }
  449.          ActivateName(&HlpListInfo);
  450.          break;
  451.  
  452.       case HLP_SLIDE:
  453.          EndListSlider(theGadget->UserData);
  454.          break;
  455.    }
  456. }
  457.  
  458.  
  459. /*
  460.  * HLPGadgetDown()
  461.  *
  462.  *  Do the right thing for each gadget down event:
  463.  *
  464.  *    LIST:
  465.  *      If the mode is TOPICS,
  466.  *        Find the item selected and set to it,
  467.  *      Otherwise activate the name gadget
  468.  *
  469.  *    HELP:
  470.  *      if already showing help on help,
  471.  *        restore the CurrentRoot to the root of the Help tree
  472.  *        set the node to the Old Node,
  473.  *        clear the HelpOnHelp flag
  474.  *      otherwise
  475.  *        save the current node for later
  476.  *        set the root to the default help
  477.  *        display the root of the default help
  478.  *        set the HelpOnHelp flag
  479.  *
  480.  *    Arrows:
  481.  *      Scroll the list.
  482.  *
  483.  *    SLIDER:
  484.  *      start sliding the list.
  485.  *
  486.  *    NAME:
  487.  *      Unselect any selected topics.
  488.  */
  489.  
  490. void HLPGadgetDown(theGadget,theMessage)
  491. struct Gadget *theGadget;
  492. struct IntuiMessage *theMessage;
  493. {
  494.    HELPITEM *theItem;
  495.  
  496.    switch(theGadget->GadgetID)
  497.    {
  498.       case HLP_LIST:
  499.          if (HelpMode == HM_TOPICS)
  500.          {
  501.             theItem = (HELPITEM *)DoListHit(theGadget->UserData,theMessage);
  502.             if (theItem) SetHelp(theItem);
  503.          } else {
  504.             ActivateName(&HlpListInfo);
  505.          }
  506.          break;
  507.  
  508.       case HLP_HELP:
  509.          if (HelpOnHelp)
  510.          {
  511.             CurrentRoot = &HelpRoot;
  512.             SetHelp(OldNode);
  513.             HelpOnHelp = FALSE;
  514.          } else {
  515.             OldNode = CurrentNode;
  516.             CurrentRoot = DefaultHelpTopic;
  517.             SetHelp(CurrentRoot);
  518.             HelpOnHelp = TRUE;
  519.          }
  520.          break;
  521.  
  522.       case HLP_UARROW:
  523.          DoListScrollUp(theGadget->UserData,theGadget,theMessage);
  524.          break;
  525.  
  526.       case HLP_DARROW:
  527.          DoListScrollDown(theGadget->UserData,theGadget,theMessage);
  528.          break;
  529.  
  530.       case HLP_SLIDE:
  531.          StartListSlider(theGadget->UserData);
  532.          break;
  533.  
  534.       case HLP_NAME:
  535.          UnsetListSelect(theGadget->UserData,TRUE);
  536.          break;
  537.    }
  538. }
  539.  
  540.  
  541. /*
  542.  *  DoHelp()
  543.  *
  544.  *  If the help requester is not already showing,
  545.  *    invert the HELP button and restore the pointer colors
  546.  *    Set the HelpActive flag
  547.  *    If we can (or already have) loaded the help tree
  548.  *      set the current root and node, and display to root item
  549.  *      make sure the HELP button is not selected, clear the name gadget,
  550.  *      and then activate the requester
  551.  *    If not loaded (or the requester is not activated)
  552.  *      clean up.
  553.  */
  554.  
  555. void DoHelp()
  556. {
  557.    extern void DoListMouse();
  558.    int LoadedOK = FALSE;
  559.  
  560.    if (ActiveRequest != &HLPRequest)
  561.    {
  562.       InvertGadget(&cGadget[ID_HELP]);
  563.       RestorePointerColor();
  564.       HelpActive = TRUE;
  565.       if (LoadHelp())
  566.       { 
  567.          CurrentRoot = CurrentNode = &HelpRoot; SetHelp(CurrentNode);
  568.          HLPGADGET[HLP_HELP].Flags &= ~SELECTED; HelpOnHelp = FALSE;
  569.          SetStringInfo(&(HLPGADGET[HLP_NAME]),"");
  570.          AddRequest(&HLPRequest,HLPGadgetDown,HLPGadgetUp,DoListMouse);
  571.          if (ActiveRequest) LoadedOK = TRUE;
  572.       }
  573.       if (LoadedOK == FALSE)
  574.       {
  575.          InvertGadget(&cGadget[ID_HELP]);
  576.          if (MouseMoveType == MM_NONE && !Running)
  577.             SetPointerColor(PenInUse);
  578.          HelpActive = FALSE;
  579.       }
  580.    }
  581. }
  582.  
  583.  
  584. /*
  585.  *  ABTGadgetUp()
  586.  *
  587.  *  If the OK button is pressed,
  588.  *    remove the requester and clearn up
  589.  */
  590.  
  591. static void ABTGadgetUp(theGadget,theMessage)
  592. struct Gadget *theGadget;
  593. struct IntuiMEssage *theMessage;
  594. {
  595.    if (theGadget->GadgetID == ABT_OK)
  596.    {
  597.       RemoveRequest(&ABTRequest);
  598.       InvertGadget(&cGadget[ID_HELP]);
  599.       if (MouseMoveType == MM_NONE && !Running)
  600.          SetPointerColor(PenInUse);
  601.    }
  602. }
  603.  
  604.  
  605. /*
  606.  *  DoAbout()
  607.  *
  608.  *  If the about box is not already active,
  609.  *    Invert the ABOUT gadget and restore the pointer.
  610.  *    set the title and the free memory counter.
  611.  *    open the requester
  612.  *    if it could not be activated, clean up
  613.  */
  614.  
  615. void DoAbout()
  616. {
  617.    extern long AvailMem();
  618.  
  619.    if (ActiveRequest != &ABTRequest)
  620.    {
  621.       InvertGadget(&cGadget[ID_HELP]);
  622.       RestorePointerColor();
  623.       sprintf(ABTTEXT[ABTT_TITLE].IText,"About%s",myWindow->ScreenTitle);
  624.       sprintf(ABTTEXT[ABTT_FREE].IText,"Free Memory:  %dK",AvailMem(0)/1024);
  625.       AddRequest(&ABTRequest,NULL,ABTGadgetUp,NULL);
  626.       if (ActiveRequest == NULL)
  627.       {
  628.          InvertGadget(&cGadget[ID_HELP]);
  629.          if (MouseMoveType == MM_NONE && !Running)
  630.             SetPointerColor(PenInUse);
  631.       }
  632.    }
  633. }
  634.