home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
500-599
/
ff502.lzh
/
CELLS
/
CELLSSource.lzh
/
cDoHelp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-20
|
18KB
|
634 lines
/*
* CELLS An Implementation of the WireWorld cellular automata
* as described in Scientific American, Jan 1990.
*
* Copyright 1990 by Davide P. Cervone.
* You may use this code, provided this copyright notice is kept intact.
* See the CELLS.HELP file for complete information on distribution conditions.
*/
/*
* File: cDoHelp.c Handles the Help facility
*/
#include "cGadget.h"
#include "cRequest.h"
#include "cHelp.h"
#include "cReqHelp.h"
#include <ctype.h>
#define ABTTEXT ABTRequest.er_Request.ReqText
#define HLPGADGET HLPRequest.er_Request.ReqGadget
extern char HlpNameBuf[]; /* Help name gadget buffer */
int HelpActive; /* TRUE if help requester is up */
HELPITEM *DefaultHelpTopic = &DefaultHelp; /* HELP button on HELP requester */
static HELPITEM *CurrentRoot; /* root of current Help tree */
static HELPITEM *CurrentNode; /* current topic in Help tree */
static HELPITEM *OldNode; /* topic in use before HELP was pressed */
static int HelpOnHelp; /* TRUE if HELP pressed during Help */
static int HelpMode; /* Text or Topic mode */
#define HM_TEXT 0
#define HM_TOPICS 1
/*
* return values from keyword match test
*/
#define NOMATCH 0
#define MATCHED 1
#define MORETOPIC 2
/*
* PrefixMatch()
*
* Compare two keyword strings:
* find the first character that does not match (or the end of the string)
* If we matched all of string 1, return MATCHED,
* Otherwise, if we matched at least one character,
* if the last matched character was a space, go back to that space
* otherwise, if the unmatched character was a space, skip to the
* first non-space.
* if we matched up to a space,
* set the return string to the unmatched character,
* if there are more un-matched characters, return MORETOPIC
* otherwise return completely matched (MATCHED)
*/
static int PrefixMatch(Src,Target)
char **Src,*Target;
{
char c1,c2;
char *s = *Src;
int status = NOMATCH;
c1 = toupper(*s); c2 = toupper(*Target);
while (c1 && c1 == c2)
{
s++; Target++;
c1 = toupper(*s); c2 = toupper(*Target);
}
if (c1 == 0)
{
status = MATCHED;
*Src = s;
} else if (s > *Src) {
if (*s != ' ' && *(s-1) == ' ') s--;
else if (*s == ' ') while (*(s+1) == ' ') s++;
if (*s == ' ')
{
s++; *Src = s;
if (*s) status = MORETOPIC; else status = MATCHED;
}
}
return(status);
}
/*
* FindHelp()
*
* Starting at the bottom of the item list containing the specified item,
* while there are more items and we have not found the one we want,
* match the rest of the name agains the test topic
* If an exact match, we're done.
* if there is more to the topic,
* save the topic (if one was not already saved, or this one matches more)
* then go on to the "next" topic
* If no match (or more topic)
* go to the next item (the previous one in the list)
* if we're at the end of the list and there was a partial match
* starting with the rest of the topic name
* and looking at the subtopics of the matched topic
* (at the end of the list)
* keep looking for more matches
* If not found go back to the last topic matched.
* If there's still more topics unmatched, give a warning
* return the last matched item.
*/
static HELPITEM *FindHelp(theItem,Name)
HELPITEM *theItem;
char *Name;
{
HELPITEM *Parent = theItem;
HELPITEM *LastMatch = NULL;
char *RestOfTopics = NULL;
char *Remainder;
int NotFound = TRUE;
theItem = Parent->SubTopics;
if (theItem) while (theItem->Next) theItem = theItem->Next;
while (theItem && NotFound)
{
Remainder = Name;
switch(PrefixMatch(&Remainder,theItem->Name))
{
case MATCHED:
NotFound = FALSE;
Name = Remainder;
break;
case MORETOPIC:
if (LastMatch == NULL || Remainder > RestOfTopics)
{
LastMatch = theItem;
RestOfTopics = Remainder;
}
case NOMATCH:
theItem = theItem->Prev;
if (theItem == NULL && LastMatch)
{
Name = RestOfTopics; RestOfTopics = NULL;
Parent = LastMatch; LastMatch = NULL;
theItem = Parent->SubTopics;
if (theItem) while (theItem->Next) theItem = theItem->Next;
}
break;
}
}
if (NotFound) theItem = Parent;
if (Name && Name[0]) DoError("Can't Find Topic '%s'",Name);
return(theItem);
}
/*
* SetHelpPen()
*
* Set the pen color of the IntuiTexts for the Help list gadget
* (depending on whether we're in Text Mode or Topic Mode).
*/
static void SetHelpPen(thePen)
int thePen;
{
int i;
for (i=0; i<HlpListInfo.Height; HlpListInfo.IText[i++].FrontPen = thePen);
}
/*
* SetHelpText()
*
* If the topic's text lines are not loaded, load them.
* If there are text lines,
* Unset the previous nodes INUSE flag,
* Set the current node to this one, and set its INUSE flag
* Set the requester buttons and titles properly
* and if the Help requester is already up, unselect any items
* set the IText pens, and set the list to showing the text lines
* If the requester is already active,
* clear the name string,
* refresh the name, title and topics gadgets,
* (refresh the topic gadget twice if it is selected, since it inverts)
* set TEXT mode
* Otherwise
* give a warning about no text items
*/
static void SetHelpText(theItem)
HELPITEM *theItem;
{
if ((theItem->Flags & HLP_LOADED) == 0) LoadItem(theItem);
if (theItem->Text)
{
CurrentNode->Flags &= ~HLP_INUSE;
CurrentNode = theItem; CurrentNode->Flags |= HLP_INUSE;
HLPGADGET[HLP_TOPICS].GadgetText->IText = "Topics";
HLPGADGET[HLP_TOPICS].GadgetID = HLP_TOPICS;
if (theItem->Title)
HLPGADGET[HLP_TITLE].GadgetText->IText = theItem->Title;
else
HLPGADGET[HLP_TITLE].GadgetText->IText = theItem->Name;
HLPGADGET[HLP_TITLE].GadgetText->LeftEdge = (HLP_TITLEW -
strlen(HLPGADGET[HLP_TITLE].GadgetText->IText)*CHAR_WIDTH) / 2;
if (ActiveRequest == &HLPRequest) UnsetListSelect(&HlpListInfo,TRUE);
SetHelpPen(TEXTPEN);
SetList(&(HLPGADGET[HLP_LIST]),theItem->Text,NULL);
if (ActiveRequest == &HLPRequest)
{
SetStringInfo(&HLPGADGET[HLP_NAME],"");
RefreshRequest(&HLPRequest,HLP_NAME,NULL);
RefreshRequest(&HLPRequest,HLP_TITLE,NULL);
RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
if (HLPGADGET[HLP_TOPICS].Flags & SELECTED)
RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
}
HelpMode = HM_TEXT;
} else {
DoError("No Text for this Help Topic");
}
}
/*
* SetHelpTopics()
*
* If the item has no sub-topics, go to the parent for a topic list
* If there are sub-topics
* Clear the INUSE flag of the previous node,
* Set the current node and set its INUSE flag
* Set the gadget names, title, etc.
* If the Help requester is already active, unselect any items
* Set the IText pens
* Set the gadget list to the list of topics
* If the help request is active
* clear the name gadget,
* refresh the Name, Title, and Topic gadgets
* (refresh the topic gadget twice if it is selected, since it inverts)
* set the mode to TOPICS
* Otherwise
* display an error message
*/
static void SetHelpTopics(theItem,SelectedItem)
HELPITEM *theItem;
HELPITEM *SelectedItem;
{
while (theItem->SubTopics == NULL && theItem->Parent)
theItem = theItem->Parent;
if (theItem->SubTopics)
{
CurrentNode->Flags &= ~HLP_INUSE;
CurrentNode = theItem; CurrentNode->Flags |= HLP_INUSE;
HLPGADGET[HLP_TOPICS].GadgetText->IText = " Text ";
HLPGADGET[HLP_TOPICS].GadgetID = HLP_TEXT;
HLPGADGET[HLP_TITLE].GadgetText->IText = "Double-Click to Pick a Topic:";
HLPGADGET[HLP_TITLE].GadgetText->LeftEdge = (HLP_TITLEW-30*CHAR_WIDTH)/2;
if (ActiveRequest == &HLPRequest) UnsetListSelect(&HlpListInfo,TRUE);
SetHelpPen(TOPICPEN);
SetList(&(HLPGADGET[HLP_LIST]),theItem->SubTopics,SelectedItem);
if (ActiveRequest == &HLPRequest)
{
SetStringInfo(&HLPGADGET[HLP_NAME],"");
RefreshRequest(&HLPRequest,HLP_NAME,NULL);
RefreshRequest(&HLPRequest,HLP_TITLE,NULL);
RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
if (HLPGADGET[HLP_TOPICS].Flags & SELECTED)
RefreshRequest(&HLPRequest,HLP_TOPICS,NULL);
}
HelpMode = HM_TOPICS;
} else {
DoError("No Sub-Topics Available for this Topic");
}
}
/*
* SetHelp()
*
* If an item was specified,
* if the item is a link to another topic,
* find the linked item in the current tree,
* if it can't be found, display an error and go back to the current node
* Load the topics text if necessary
* if there is text for this topic, set TEXT mode else set TOPIC mode
* Otherwise (no topic)
* Clear the title and the item list
*/
static void SetHelp(theItem)
HELPITEM *theItem;
{
if (theItem)
{
if (theItem->Flags & HLP_LINKED)
{
theItem = FindHelp(CurrentRoot,theItem->Title);
if (theItem == NULL)
{
theItem = CurrentNode;
DoError("Target of LINK not Found");
}
}
if ((theItem->Flags & HLP_LOADED) == 0) LoadItem(theItem);
if (theItem->Text)
SetHelpText(theItem);
else
SetHelpTopics(theItem,CurrentNode);
} else {
HLPGADGET[HLP_TITLE].GadgetText->IText = NULL;
if (ActiveRequest == &HLPRequest)
RefreshRequest(&HLPRequest,HLP_TITLE,NULL);
SetList(&(HLPGADGET[HLP_LIST]),NULL,NULL);
}
}
/*
* DoParent()
*
* if there is a parent to the current item
* set the parent's help text or topics, as needed
* otherwise display an error message
*/
static void DoParent()
{
if (CurrentNode->Parent)
{
if (HelpMode == HM_TEXT)
SetHelpText(CurrentNode->Parent);
else
SetHelpTopics(CurrentNode->Parent,CurrentNode);
} else {
DoError("There is No Parent for this Help Item");
}
}
/*
* HLPGadgetUp()
*
* Do the right thing for each gadget up message:
*
* DONE:
* Clear the INUSE flag, clear the HelpActive flag, and remove
* the requester. Inverse the HELP button and reset the pointer color.
*
* PARENT:
* if SHIFT pressed, go to the help root, otherwise go to the parent.
* activate the help name gadget.
*
* TOPICS:
* Set to the topic list of the current node.
*
* TEXT:
* Set to the help text of the current node.
*
* MORE:
* If there are more items not shown below,
* if we're in text mode,
* set the selected item to the last one on the previous page
* (so that if there's not enough to fill an entire new page,
* we can still see where the last page ended - the last line will
* flash selected for a moment)
* scroll down by a page
* Otherwise (at the bottom of the list)
* if in text mode, show topics, otherwise go to the parent
* if text mode, delay a little, and activate the name gadget
* this will deselect the last line of text selected above.
*
* NAME:
* if topics were selected (or typed)
* find the selected item and display it
* otherwise (name gadget it blank)
* go to the parent
* reactivate the name gadget.
*
* SLIDER:
* stop sliding the list.
*/
static void HLPGadgetUp(theGadget,theMessage)
struct Gadget *theGadget;
struct IntuiMessage *theMessage;
{
HELPITEM *theItem;
switch(theGadget->GadgetID)
{
case HLP_DONE:
CurrentNode->Flags &= ~HLP_INUSE;
HelpActive = FALSE;
RemoveRequest(&HLPRequest);
InvertGadget(&cGadget[ID_HELP]);
if (MouseMoveType == MM_NONE && !Running)
SetPointerColor(PenInUse);
break;
case HLP_PARENT:
if (theMessage->Qualifier & SHIFTKEYS)
SetHelp(CurrentRoot);
else
DoParent();
if (HelpMode == HM_TEXT) ActivateName(&HlpListInfo);
break;
case HLP_TOPICS:
SetHelpTopics(CurrentNode,CurrentNode);
break;
case HLP_TEXT:
SetHelpText(CurrentNode);
ActivateName(&HlpListInfo);
break;
case HLP_MORE:
if (HlpListInfo.TopItem + HlpListInfo.Height < HlpListInfo.ListLen)
{
if (HelpMode == HM_TEXT)
HlpListInfo.SelectedItem = HlpListInfo.Height-1;
DoListPageDown(&HlpListInfo);
} else {
if (HelpMode == HM_TEXT)
SetHelpTopics(CurrentNode,CurrentNode);
else
DoParent();
}
if (HelpMode == HM_TEXT)
{
Delay(6L);
ActivateName(&HlpListInfo);
}
break;
case HLP_NAME:
if (HlpNameBuf[0])
{
theItem = FindHelp(CurrentNode,HlpNameBuf);
if (theItem) SetHelp(theItem);
} else {
DoParent();
}
ActivateName(&HlpListInfo);
break;
case HLP_SLIDE:
EndListSlider(theGadget->UserData);
break;
}
}
/*
* HLPGadgetDown()
*
* Do the right thing for each gadget down event:
*
* LIST:
* If the mode is TOPICS,
* Find the item selected and set to it,
* Otherwise activate the name gadget
*
* HELP:
* if already showing help on help,
* restore the CurrentRoot to the root of the Help tree
* set the node to the Old Node,
* clear the HelpOnHelp flag
* otherwise
* save the current node for later
* set the root to the default help
* display the root of the default help
* set the HelpOnHelp flag
*
* Arrows:
* Scroll the list.
*
* SLIDER:
* start sliding the list.
*
* NAME:
* Unselect any selected topics.
*/
void HLPGadgetDown(theGadget,theMessage)
struct Gadget *theGadget;
struct IntuiMessage *theMessage;
{
HELPITEM *theItem;
switch(theGadget->GadgetID)
{
case HLP_LIST:
if (HelpMode == HM_TOPICS)
{
theItem = (HELPITEM *)DoListHit(theGadget->UserData,theMessage);
if (theItem) SetHelp(theItem);
} else {
ActivateName(&HlpListInfo);
}
break;
case HLP_HELP:
if (HelpOnHelp)
{
CurrentRoot = &HelpRoot;
SetHelp(OldNode);
HelpOnHelp = FALSE;
} else {
OldNode = CurrentNode;
CurrentRoot = DefaultHelpTopic;
SetHelp(CurrentRoot);
HelpOnHelp = TRUE;
}
break;
case HLP_UARROW:
DoListScrollUp(theGadget->UserData,theGadget,theMessage);
break;
case HLP_DARROW:
DoListScrollDown(theGadget->UserData,theGadget,theMessage);
break;
case HLP_SLIDE:
StartListSlider(theGadget->UserData);
break;
case HLP_NAME:
UnsetListSelect(theGadget->UserData,TRUE);
break;
}
}
/*
* DoHelp()
*
* If the help requester is not already showing,
* invert the HELP button and restore the pointer colors
* Set the HelpActive flag
* If we can (or already have) loaded the help tree
* set the current root and node, and display to root item
* make sure the HELP button is not selected, clear the name gadget,
* and then activate the requester
* If not loaded (or the requester is not activated)
* clean up.
*/
void DoHelp()
{
extern void DoListMouse();
int LoadedOK = FALSE;
if (ActiveRequest != &HLPRequest)
{
InvertGadget(&cGadget[ID_HELP]);
RestorePointerColor();
HelpActive = TRUE;
if (LoadHelp())
{
CurrentRoot = CurrentNode = &HelpRoot; SetHelp(CurrentNode);
HLPGADGET[HLP_HELP].Flags &= ~SELECTED; HelpOnHelp = FALSE;
SetStringInfo(&(HLPGADGET[HLP_NAME]),"");
AddRequest(&HLPRequest,HLPGadgetDown,HLPGadgetUp,DoListMouse);
if (ActiveRequest) LoadedOK = TRUE;
}
if (LoadedOK == FALSE)
{
InvertGadget(&cGadget[ID_HELP]);
if (MouseMoveType == MM_NONE && !Running)
SetPointerColor(PenInUse);
HelpActive = FALSE;
}
}
}
/*
* ABTGadgetUp()
*
* If the OK button is pressed,
* remove the requester and clearn up
*/
static void ABTGadgetUp(theGadget,theMessage)
struct Gadget *theGadget;
struct IntuiMEssage *theMessage;
{
if (theGadget->GadgetID == ABT_OK)
{
RemoveRequest(&ABTRequest);
InvertGadget(&cGadget[ID_HELP]);
if (MouseMoveType == MM_NONE && !Running)
SetPointerColor(PenInUse);
}
}
/*
* DoAbout()
*
* If the about box is not already active,
* Invert the ABOUT gadget and restore the pointer.
* set the title and the free memory counter.
* open the requester
* if it could not be activated, clean up
*/
void DoAbout()
{
extern long AvailMem();
if (ActiveRequest != &ABTRequest)
{
InvertGadget(&cGadget[ID_HELP]);
RestorePointerColor();
sprintf(ABTTEXT[ABTT_TITLE].IText,"About%s",myWindow->ScreenTitle);
sprintf(ABTTEXT[ABTT_FREE].IText,"Free Memory: %dK",AvailMem(0)/1024);
AddRequest(&ABTRequest,NULL,ABTGadgetUp,NULL);
if (ActiveRequest == NULL)
{
InvertGadget(&cGadget[ID_HELP]);
if (MouseMoveType == MM_NONE && !Running)
SetPointerColor(PenInUse);
}
}
}