home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************************\
- | Purpose :: This is the CODE RESOURCE version of the MacTutor Help |
- | facility. It is language independent, and can be used in |
- | any development system which gives proper access to the |
- | Macintosh toolbox. |
- |-----------------------------------------------------------------------|
- | Copyright © Joe Pillera, 1990. All Rights Reserved. |
- | Copyright © MacTutor Magazine, 1990. All Rights Reserved. |
- \***********************************************************************/
-
- #include "help.h"
- #include <SetUpA4.h>
-
- /* Global variables */
- static ListHandle My_List_Handle; /* Handle for a list in the dialog */
- static Rect List_Rect; /* Rectangle (user-item) of topic list */
- static Rect Display_Rect; /* Rectangle (user-item) of the display */
- static Rect Scroller_Rect; /* Rectangle (computed) of scroll bar */
- static Rect Dest_Rect; /* Destination of TE rectangle */
- static Rect View_Rect; /* Actual viewing region of text */
- static Rect Frame_Rect; /* The rectangle to frame for text */
- static int Help_Topic; /* What topic does user want info on? */
- static int Current_Pict; /* Latest picture ID being displayed */
- static DialogPtr helpPtr; /* Pointer to the help dialog box */
- static TEHandle myTEHandle; /* The TE Manager data structure */
- static Handle myTEXTHandle; /* My handle to the TEXT resource */
- static ViewMode Last_Type; /* Was last one a pict or text? */
- static ControlHandle myControl; /* Handle to the text scroller */
- static GrafPtr savePort; /* Save a pointer to the old grafport */
- static int refnum; /* Result of trying to open help file */
-
- /* Keep track of the screen types */
- static ViewMode screen_mode[ MAX_TOPICS ];
-
- /* Number of user's help topics */
- static int Number_Of_Topics;
-
- /* Disable his menus */
- static int First_Menu;
- static int Last_Menu;
-
- /* Array traversal constants */
- static int START;
- static int FINIS;
-
- /* Log positions of 'PICT' & 'TEXT' resources */
- static Str255 topic_name[ MAX_TOPICS ];
- static int resource_start[ MAX_TOPICS ];
- static int resource_end[ MAX_TOPICS ];
-
-
- /***********************************************************************\
- | void Add_List_String( theString, theList ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To add a (pascal) string to a specified list. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | theString -> Pascal string to add. |
- | theList -> Pointer to the target list. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Add_List_String( theString, theList )
- Str255 *theString;
- ListHandle theList;
- {
- short theRow; /* The Row that we are adding */
- Point cSize; /* Pointer to a cell in a list */
-
- if (theList != NIL) {
- cSize.h = 0;
- theRow = LAddRow(1, 32000, theList);
- cSize.v = theRow;
- LSetCell((*theString + 1), *theString[0], cSize,theList);
- LDraw(cSize, theList);
- }
- }
-
-
- /***********************************************************************\
- | void Bold_Button( dPtr, itemNum ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To draw a thick black line around any dialog box item. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | dPtr -> Pointer to an already opened window. |
- | itemNum -> Item within the dialog to highlight. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Bold_Button( dPtr, itemNum )
- DialogPtr dPtr;
- int itemNum;
- {
- Rect iBox; /* The rectangle for the button */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
- PenState oldPenState; /* Preserve the old drawing state */
-
- SystemTask();
- SetPort(dPtr);
- GetPenState(&oldPenState);
- GetDItem(dPtr, itemNum, &iType, &iHandle, &iBox);
- InsetRect(&iBox, -4, -4);
- PenSize(3,3);
- FrameRoundRect(&iBox, 16, 16);
- SetPenState(&oldPenState);
- }
-
-
- /***********************************************************************\
- | void Center_Window( theWindow, bumpUp ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To center a currently opened - but still invisible - |
- | window on the screen. Once the window is centered, it |
- | should then be made visible for the user. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | theWindow -> Pointer to an already opened window. |
- | bumpUp -> A percentage from center to move the window up. |
- | Sometimes a perfectly centered window (bumpUp=0) is |
- | annoying to a user, so I provide this facility. Note |
- | that a negative value will push the window down. |
- | isModeless -> If so, add an additional 20 pixels for the drag bar. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Center_Window(theWindow,bumpUp,isModeless)
- DialogPtr theWindow;
- int bumpUp;
- Boolean isModeless;
- {
- Rect tempRect; /* Temporary rectangle */
- int pixels; /* Raise from center this amount */
- int menuBar = 20; /* Compensate 20 pixels for menu bar */
-
- /* Compute centering information */
- tempRect.top = theWindow->portRect.top;
- tempRect.left = theWindow->portRect.left;
- tempRect.bottom = theWindow->portRect.bottom;
- tempRect.right = theWindow->portRect.right;
- tempRect.top = ((screenBits.bounds.bottom + menuBar + (isModeless ? 20 : 0) -
- screenBits.bounds.top) - (tempRect.bottom - tempRect.top)) / 2;
- tempRect.left = ((screenBits.bounds.right - screenBits.bounds.left) -
- (tempRect.right - tempRect.left)) / 2;
-
- /* Apply any bump-up factor */
- pixels = tempRect.top * (bumpUp / 100.0);
- tempRect.top = tempRect.top - pixels;
-
- /* Now center window & make it visible */
- MoveWindow(theWindow, tempRect.left, tempRect.top, TRUE);
- SetPort(theWindow);
- }
-
-
- /***********************************************************************\
- | Boolean Create_Help( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To bring up and initialize MacTutor Help. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: TRUE if all went well, FALSE otherwise. |
- \***********************************************************************/
-
- static Boolean Create_Help()
- {
- int whatHit; /* The DITL item the user selected */
- int DType; /* Type of dialog item */
- Point cSize; /* Pointer to a cell in a list */
- Rect tempRect; /* Temporary rectangle */
- Rect dataBounds; /* Rect to setup the list */
- Handle DItem; /* Handle to the dialog item */
- FontInfo ThisFontInfo; /* Used to determine List element height */
- int index; /* Loop thru the topic list names */
- Rect iBox; /* The rectangle for the next/prev buttons */
- int iType; /* Type of dialog item (button) */
- Handle iHandle; /* Pointer to the item */
-
-
- /* -- Preserve pointer to former graf port -- */
- GetPort(&savePort);
-
- /* -- First make sure the help file is out there! -- */
- refnum = OpenResFile("\pHelp Data");
- if (refnum == NOT_FOUND) {
- helpPtr = GetNewDialog(Help_Not_Found, NIL, FRONT);
- Center_Window( helpPtr,50, FALSE );
- ShowWindow(helpPtr);
- Bold_Button( helpPtr, OK_Button );
- SysBeep(1);
- ModalDialog(NIL, &whatHit);
- DisposDialog(helpPtr);
- SetPort(savePort);
- return(FALSE);
- }
-
- /* Set up pointers to the introduction screen */
- Help_Topic = START;
- Current_Pict = resource_start[START];
- Last_Type = screen_mode[START];
-
- /* -- Bring up the help screen -- */
- helpPtr = GetNewDialog(Help_Window, NIL, FRONT);
- Center_Window(helpPtr,0,TRUE);
- ShowWindow(helpPtr);
- SelectWindow(helpPtr);
- SetPort(helpPtr);
- Bold_Button(helpPtr,OK_Button);
-
- /* Hide the next & previous buttons for the intro screen */
- GetDItem(helpPtr, Next_Button, &iType, &iHandle, &iBox);
- HideControl((ControlHandle)iHandle);
- GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &iBox);
- HideControl((ControlHandle)iHandle);
-
- /* -- Disable the "Next" & "Previous" buttons for now -- */
- Set_Button_State( Next_Button, FALSE );
- Set_Button_State( Prev_Button, FALSE );
-
- /* -- Now build the list -- */
- GetDItem(helpPtr, Topics_Area, &DType, &DItem, &tempRect);
- SetRect(&List_Rect, tempRect.left, tempRect.top, tempRect.right, tempRect.bottom);
- /* Start w/ full size of the dialog's user item */
- tempRect = List_Rect;
- /* Make room for the scroll bar on the right */
- tempRect.right = tempRect.right - 15;
- /* Safety check */
- if (tempRect.right <= (tempRect.left + 15))
- tempRect.right = tempRect.left + 15;
- /* Frame it */
- InsetRect(&tempRect, -1, -1);
- FrameRect(&tempRect);
- InsetRect(&tempRect, 1, 1);
- SetRect(&dataBounds, 0, 0, 1, 0);
- /* Width of the list */
- cSize.h = tempRect.right - tempRect.left;
- /* Geneva lists look more professional... */
- thePort->txFont = geneva;
- thePort->txSize = 10;
- /* Get the current font sizes */
- GetFontInfo(&ThisFontInfo);
- /* Height of a cell */
- cSize.v = ThisFontInfo.ascent + ThisFontInfo.descent + ThisFontInfo.leading;
- /* Make the list */
- My_List_Handle = LNew(&tempRect, &dataBounds, cSize, 0, helpPtr, TRUE, FALSE, FALSE, TRUE);
- /* Set the attributes */
- (*My_List_Handle)->selFlags = lOnlyOne + lNoNilHilite;
- /* Draw the list */
- LDoDraw(TRUE, My_List_Handle);
- cSize.v = 0;
- LSetSelect(TRUE, cSize, My_List_Handle);
- Refresh_Topics();
-
- /* -- Fill in the initial list contents -- */
- for ( index = START + 1; index <= FINIS; index++ )
- Add_List_String((Str255 *)topic_name[index], My_List_Handle);
-
- /* -- Compute critical info once & for all -- */
- GetDItem(helpPtr, Display_Area, &DType, &DItem, &tempRect);
-
- /* The entire display area */
- SetRect(&Display_Rect, tempRect.left,
- tempRect.top,
- tempRect.right,
- tempRect.bottom);
-
- /* The scroll bar to the right of it */
- SetRect(&Scroller_Rect, Display_Rect.right - 16,
- Display_Rect.top,
- Display_Rect.right,
- Display_Rect.bottom);
-
- /* Create the text-edit clipping regions */
- SetRect(&Frame_Rect,Display_Rect.left,
- Display_Rect.top,
- Display_Rect.right-17,
- Display_Rect.bottom);
-
- /* Compute the Text Edit destination rectangle */
- SetRect(&Dest_Rect, Frame_Rect.left+4,
- Frame_Rect.top+4,
- Frame_Rect.right-17,
- 9000);
-
- /* The clipping region for the actual text */
- SetRect(&View_Rect,Dest_Rect.left,
- Dest_Rect.top+2,
- Dest_Rect.right,
- Display_Rect.bottom-7);
-
- /* For simplicity's sake, assume intro */
- /* screen is always a picture resource. */
- Display_Pict( Initial_Picture );
- return(TRUE);
- }
-
-
- /***********************************************************************\
- | void Dialog_String( theDialog, theItem, theStr) |
- |-----------------------------------------------------------------------|
- | Purpose :: To write a string into a "static text" field of a dialog |
- | window. Assumes the dialog box has already been opened. |
- | This routine simply hides some messy data structures |
- | involved in this very necessary operation. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | theDialog -> Pointer to an already opened window. |
- | theItem -> Item within the dialog to set some text. |
- | theStr -> The actual message to be posted. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Dialog_String( theDialog, theItem, theStr )
- DialogPtr theDialog;
- int theItem;
- char *theStr;
- {
- Rect iBox; /* The rectangle for the item */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
-
- GetDItem(theDialog, theItem, &iType, &iHandle, &iBox);
- SetIText(iHandle, theStr);
- }
-
-
- /***********************************************************************\
- | void Display_Pict( whichOne ) |
- |-----------------------------------------------------------------------|
- | Purpose :: Display a new picture in the picture box! |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | whichOne -> An offset from the resource id of the first PICT in |
- | that category. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Display_Pict( whichOne )
- int whichOne;
- {
- int nextPict; /* Next picture to be displayed */
- Rect iBox; /* The rectangle of the picture */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
- PicHandle newPict; /* Pointer to the picture area */
- int mesg_this_one; /* The screen we're on now */
- int mesg_max_one; /* Total number of screens in topic */
- Str255 s1,s2,s3,s4,s5; /* Temporary strings for message */
-
-
- /* Dispose of previous text record, if there was one */
- if (Last_Type == text) {
- DisposeControl(myControl);
- TEDispose(myTEHandle);
- }
-
- /* Enable the next & previous buttons? */
- if ( (resource_end[Help_Topic] - resource_start[Help_Topic]) >= 1 ) {
- GetDItem(helpPtr, Next_Button, &iType, &iHandle, &iBox);
- ShowControl((ControlHandle)iHandle);
- GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &iBox);
- ShowControl((ControlHandle)iHandle);
- }
- else {
- GetDItem(helpPtr, Next_Button, &iType, &iHandle, &iBox);
- HideControl((ControlHandle)iHandle);
- GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &iBox);
- HideControl((ControlHandle)iHandle);
- }
-
- /* Compute which picture to display */
- nextPict = resource_start[ Help_Topic ] + whichOne;
- mesg_this_one = nextPict - resource_start[ Help_Topic ] + 1;
- mesg_max_one = resource_end[ Help_Topic ] - resource_start[ Help_Topic ] + 1;
-
- /* Display picture */
- newPict = GetPicture(nextPict);
-
- /* Saftey check */
- if (newPict == NIL)
- Error_Message( err_no_pict );
-
- GetDItem(helpPtr, Display_Area, &iType, &iHandle, &iBox);
- EraseRect(&iBox);
- DrawPicture(newPict,&iBox);
-
- /* Avoid an unnecessary update event */
- ValidRect(&iBox);
-
- /* Compute new text message */
- NumToString(mesg_this_one,s1);
- NumToString(mesg_max_one,s2);
- pStrCat( "\pStatus: Screen ", (char *) s1, (char *) s3);
- pStrCat( (char *) s3, "\p of ", (char *) s4 );
- pStrCat( (char *) s4, (char *) s2, (char *) s5);
- User_Message((char *)s5);
- Current_Pict = nextPict;
- Last_Type = pict;
- }
-
-
- /***********************************************************************\
- | void Display_Text( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: Display a text help system for the current topic. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Display_Text()
- {
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
- Rect tempRect; /* For moving the scroll bar */
-
- /* Dispose of previous text record, if there was one */
- if (Last_Type == text) {
- HUnlock(myTEXTHandle);
- HUnlock(myTEHandle);
- DisposeControl(myControl);
- TEDispose(myTEHandle);
- }
-
- /* Get a handle to the TEXT resource */
- myTEXTHandle = GetResource('TEXT', resource_start[ Help_Topic ]);
-
- /* Saftey check! */
- if (myTEXTHandle == NIL)
- Error_Message( err_no_text );
-
- HLock(myTEXTHandle);
-
- /* Hide the next & previous buttons */
- GetDItem(helpPtr, Next_Button, &iType, &iHandle, &tempRect);
- HideControl((ControlHandle)iHandle);
- GetDItem(helpPtr, Prev_Button, &iType, &iHandle, &tempRect);
- HideControl((ControlHandle)iHandle);
-
- /* Erase the display area */
- EraseRect(&Display_Rect);
-
- /* Bring up the control */
- myControl = NewControl(helpPtr,&Scroller_Rect,"",TRUE,1,1,10,16,NIL);
- HiliteControl(myControl,ON);
-
- /* Dim the picture scrolling buttons */
- Set_Button_State( Next_Button, FALSE );
- Set_Button_State( Prev_Button, FALSE );
-
- /* Frame the text box */
- MoveTo(Frame_Rect.right+1,Frame_Rect.top);
- LineTo(Frame_Rect.left,Frame_Rect.top);
- LineTo(Frame_Rect.left,Frame_Rect.bottom-1);
- LineTo(Frame_Rect.right+1,Frame_Rect.bottom-1);
-
- /* Create a text record */
- myTEHandle = TENew(&Dest_Rect,&View_Rect);
- HLock(myTEHandle);
-
- /* Display the goods */
- TESetText(*myTEXTHandle, SizeResource(myTEXTHandle), myTEHandle);
- TEUpdate(&View_Rect,myTEHandle);
- User_Message((char *)"\pStatus: < Text Mode >");
-
- /* Do we need an active scroll bar? */
- if ( ( (View_Rect.bottom - View_Rect.top) / (*myTEHandle)->lineHeight) <
- ( (*myTEHandle)->nLines ) )
- HiliteControl(myControl,ON);
- else
- HiliteControl(myControl,OFF);
-
- /* Avoid an unnecessary update event */
- ValidRect(&Display_Rect);
-
- /* Set important values and exit */
- SetCtlMax(myControl,((*myTEHandle)->nLines -
- ((View_Rect.bottom - View_Rect.top)/(*myTEHandle)->lineHeight)));
- Last_Type = text;
- }
-
-
- /***********************************************************************\
- | void Error_Message( theError ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To warn the user about bad information discovered while |
- | reading in the HTBL resource. |
- |-----------------------------------------------------------------------|
- | Arguments :: An enumerated type describing the error detected. |
- |-----------------------------------------------------------------------|
- | Returns :: Exits to Finder. |
- \***********************************************************************/
-
- static void Error_Message( theError )
- ErrorTypes theError;
- {
- Rect iBox; /* The rectangle for the button */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
- DialogPtr theBox; /* Pointer to this dialog */
- GrafPtr savePort; /* Save the old graf port */
- short whatHit; /* User selected 'Ok' or 'Cancel' */
-
- /* Bring up the correct alert */
- theBox = GetNewDialog(Help_Error, NIL, FRONT);
-
- /* Position it */
- Center_Window(theBox,50,FALSE);
- ShowWindow(theBox);
- Bold_Button(theBox, OK_Button);
- SysBeep(1);
-
- /* Fill in text message */
- switch (theError) {
- case err_no_HTBL :
- Dialog_String(theBox, 3, (char *) "\pNo HTBL (Help Table) [ID=128] resource");
- Dialog_String(theBox, 4, (char *) "\pwas found on your resource fork!");
- Dialog_String(theBox, 5, (char *) "\pPlease create one before continuing...");
- break;
-
- case err_min_res :
- Dialog_String(theBox, 3, (char *) "\pYou should have at least an intro");
- Dialog_String(theBox, 4, (char *) "\pscreen and one help screen for your");
- Dialog_String(theBox, 5, (char *) "\phelp system!");
- break;
-
- case err_intro_pict :
- Dialog_String(theBox, 3, (char *) "\pThis program assumes that the");
- Dialog_String(theBox, 4, (char *) "\pintroduction screen is always a");
- Dialog_String(theBox, 5, (char *) "\ppicture! Please change this screen.");
- break;
-
- case err_bad_type :
- Dialog_String(theBox, 3, (char *) "\pScreen types are either PICT or TEXT.");
- Dialog_String(theBox, 4, (char *) "\pOne of your HTBL fields for screen");
- Dialog_String(theBox, 5, (char *) "\ptype is incorrect...");
- break;
-
- case err_no_pict :
- Dialog_String(theBox, 3, (char *) "\pThe PICT(s) for this topic do not");
- Dialog_String(theBox, 4, (char *) "\pexist! Very uncool. I will exit");
- Dialog_String(theBox, 5, (char *) "\pto the Finder rather than crash...");
- break;
-
- case err_no_text :
- Dialog_String(theBox, 3, (char *) "\pThe TEXT for this topic does not");
- Dialog_String(theBox, 4, (char *) "\pexist! Very uncool. I will exit");
- Dialog_String(theBox, 5, (char *) "\pto the Finder rather than crash...");
- break;
-
- default : break;
- }
-
- /* Enter an event loop and poll the user */
- ModalDialog(NIL, &whatHit);
- DisposDialog(theBox);
- ExitToShell();
- }
-
-
- /***********************************************************************\
- | void Handle_List_Event( whatHit ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To process any mouse-downs in the topics list. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | whatHit -> Which item was selected by the user. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Handle_List_Event( whatHit )
- int whatHit;
- {
- /* Get the selected topic from the user */
- Help_Topic = whatHit + 1;
- /* If there is >1 screens, enable the "Next" button */
- if (resource_end[Help_Topic] - resource_start[Help_Topic]) {
- Set_Button_State( Next_Button, TRUE );
- Set_Button_State( Prev_Button, FALSE );
- }
- else {
- Set_Button_State( Next_Button, FALSE );
- Set_Button_State(Prev_Button, FALSE );
- }
-
- /* Display first screen in topic */
- if ( screen_mode[ Help_Topic ] == pict )
- Display_Pict( Initial_Picture );
- else if ( screen_mode[ Help_Topic ] == text )
- Display_Text();
- else
- SysBeep(1);
- }
-
-
- /***********************************************************************\
- | void Handle_Update( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To handle any update to the dialog. For example: it will |
- | refresh the screen when another dialog has been placed |
- | over it, etc. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Handle_Update()
- {
- Rect iBox; /* The rectangle of the picture */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
- PicHandle thePict; /* Pointer to the picture area */
- GrafPtr oldPort; /* Restore old graf port when done */
-
-
- GetPort(&oldPort);
- SetPort(helpPtr);
- BeginUpdate(helpPtr);
- Refresh_Topics();
- Bold_Button(helpPtr,OK_Button);
-
- /* Specific code for text or pictures... */
- if ( screen_mode[ Help_Topic ] == text ) {
- MoveTo(Frame_Rect.right+1,Frame_Rect.top);
- LineTo(Frame_Rect.left,Frame_Rect.top);
- LineTo(Frame_Rect.left,Frame_Rect.bottom-1);
- LineTo(Frame_Rect.right+1,Frame_Rect.bottom-1);
- TEUpdate(&View_Rect,myTEHandle);
- }
- else if ( screen_mode[ Help_Topic ] == pict ) {
- thePict = GetPicture(Current_Pict);
- /* Saftey check */
- if (thePict == NIL) {
- SysBeep(1);
- return;
- }
- GetDItem(helpPtr, Display_Area, &iType, &iHandle, &iBox);
- EraseRect(&iBox);
- DrawPicture(thePict,&iBox);
- }
- DrawDialog(helpPtr);
- EndUpdate(helpPtr);
- SetPort(oldPort);
- }
-
-
- /***********************************************************************\
- | void Help_Event_Loop( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To handle any events inside my window. Once an event |
- | takes place outside this window's domain, I return |
- | immediately, and let the main event loop handle it. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Help_Event_Loop()
- {
- EventRecord theEvent; /* Most current real-time user event */
- Point where; /* Where (mouse location) the event occured */
- Rect tempRect; /* Rectangle of the about... window */
- Point myPt; /* Current list selection point */
- WindowPtr wPtr; /* The pointer to the current window */
- int thePart; /* The type of mouse-down that occured */
- int key; /* Did the user hit the <return> key? */
- int whatHit; /* Integer id of the dialog item user hit */
- Rect DRect; /* Rectangle used for finding hit point */
- short DType; /* Type of dialog item (for OK button) */
- int itemHit; /* Get selection from the user */
- Handle DItem; /* Handle to the dialog item */
- long ticks; /* Highlight ok button when <return> hit */
- Boolean DoubleClick; /* Flag to see if double click on a list */
- int oldValue; /* Former value of scroll bar before event */
- int rc; /* Return code from TrackControl() - ignore */
- long cellHit; /* Find out where user single-clicked */
- ControlHandle aControl; /* Event took place in my scroller */
- static int lastHit = -1; /* Nicety: prevent redundant processing */
-
- /* -- Enter the event loop -- */
- InitCursor();
- HiliteMenu(0);
- for (;;) {
- SetPort(helpPtr);
- SelectWindow(helpPtr);
- InitCursor();
-
- if (GetNextEvent(everyEvent, &theEvent)) {
- switch (theEvent.what)
- {
- case updateEvt:
- if ((WindowPtr)theEvent.message == helpPtr)
- Handle_Update();
- break;
-
- case keyDown:
- /* If it's a <return> key I want it */
- key = ( (unsigned char) theEvent.message & charCodeMask );
- if ( (key == '\r') ) {
- /* Treat this like a mouse-down in the OK button */
- SetPort(helpPtr);
- GetDItem(helpPtr, OK_Button, &DType, &DItem, &DRect);
- HiliteControl((ControlHandle)DItem,1);
- Delay(8,&ticks);
- Kill_Window();
- return;
- }
- break;
-
- case mouseDown:
- thePart = FindWindow(theEvent.where, &wPtr);
- /* The following is very tricky code: it allows you */
- /* to switch tasks under Multifinder, but will not */
- /* let you pull down any of the disabled menus. */
- if ((DialogPtr)wPtr != helpPtr) {
- if (thePart != inMenuBar)
- SysBeep(1);
- continue;
- }
- switch (thePart)
- {
- case inMenuBar:
- rc = MenuSelect(theEvent.where);
- break;
-
- case inDrag:
- tempRect = screenBits.bounds;
- SetRect(&tempRect, tempRect.left + 10, tempRect.top + 25,
- tempRect.right - 10,tempRect.bottom - 10);
- DragWindow(helpPtr, theEvent.where, &tempRect);
- break;
-
- case inContent:
- if (DialogSelect(&theEvent, &helpPtr, &whatHit)) {
- myPt = theEvent.where;
- GlobalToLocal(&myPt);
-
- /* Is the user all done? */
- if (whatHit == OK_Button) {
- Kill_Window();
- return;
- }
-
- else if ((whatHit == Next_Button) || (whatHit == Prev_Button))
- Scroll_Picture( whatHit );
-
- /* Was it an event in the topics list? */
- else if (PtInRect(myPt,&List_Rect) == TRUE) {
- DoubleClick = LClick(myPt, theEvent.modifiers, My_List_Handle);
- cellHit = LLastClick(My_List_Handle);
- itemHit = HiWord( cellHit );
- if ((itemHit >= 0) && (itemHit != lastHit)) {
- lastHit = itemHit;
- Handle_List_Event(itemHit);
- }
- }
-
- /* Was it a text scroller event? */
- else if ( (PtInRect(myPt, &Scroller_Rect)) &&
- (screen_mode[ Help_Topic ] == text) ) {
- thePart = FindControl(myPt, wPtr, &aControl);
- oldValue = GetCtlValue(aControl);
- if ( thePart == inThumb ) {
- rc = TrackControl(aControl, myPt, (ProcPtr)0);
- Scroll_Text( oldValue, GetCtlValue(aControl) );
- }
- else if ( (thePart == inUpButton) || (thePart == inDownButton) ||
- (thePart == inPageUp) || (thePart == inPageDown) )
- rc = TrackControl(aControl, myPt, &My_Scroll_Filter);
- }
- }
- break;
- }
- }
- }
- }
- }
-
-
- /***********************************************************************\
- | void Init_Help( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: This code is called every time the Help system is invoked, |
- | because this is the code resource version. The HTBL is |
- | scanned, and its values are stored in global data structs. |
- | NOTE! This routine assumes HTBL has ID=128. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- void Init_Help()
- {
- int index; /* Loop thru user's information */
- char *HTBL_ptr; /* Establish the basline pointer */
- Help_Info_Handle h; /* Cast HTBL to this data structure */
- long mode; /* Longint version of PICT or TEXT */
- char ch; /* First letter of PICT or TEXT */
-
- /* Get handle to the HTBL resource */
- h = (Help_Info_Handle) GetResource('HTBL',128);
-
- /* No HTBL=128 resource? */
- if ((h == NIL) || (ResErr != noErr))
- Error_Message( err_no_HTBL );
-
- /* Lock it */
- HLock(h);
-
- /* Establish pointer to start of HTBL resource */
- HTBL_ptr = (char *) *h;
- First_Menu = ParseInt( (char **) &HTBL_ptr );
- Last_Menu = ParseInt( (char **) &HTBL_ptr );
- START = 0;
- FINIS = ParseInt( (char **) &HTBL_ptr );
-
- /* Enough help screens to proceed? */
- if (FINIS < 1)
- Error_Message( err_min_res );
-
- /* Now loop thru all screens & get the information */
- for (index = 0; index <= FINIS; index++) {
- /* Is this a 'PICT' or 'TEXT' screen? */
- mode = ParseOSType( (char **) &HTBL_ptr );
- ch = (char)(mode >> 24);
- if ( (ch == 'P') || (ch == 'p') )
- screen_mode[index] = pict;
- else if ( (ch == 'T') || (ch == 't') )
- screen_mode[index] = text;
- else
- /* Bad screen type! */
- Error_Message( err_bad_type );
-
- /* Is intro screen a PICT? */
- if ((index == 0) && (screen_mode[index] != pict))
- Error_Message( err_intro_pict );
-
- /* Get resource bounds */
- resource_start[index] = ParseInt( (char **) &HTBL_ptr );
- resource_end[index] = ParseInt( (char **) &HTBL_ptr );
-
- /* Retrieve title of this topic */
- ParseString( (char *)topic_name[index], (char **) &HTBL_ptr );
- }
- HUnlock(h);
- }
-
-
- /***********************************************************************\
- | void Kill_Window( void ) |
- |-----------------------------------------------------------------------|
- | Purpose: When we get here, the user has clicked on the "done" button. |
- | Dispose of all dynamic (heap) data structures and restore |
- | the original grafport. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: Void. |
- \***********************************************************************/
-
- static void Kill_Window()
- {
-
- if (Last_Type == text) {
- TEDispose(myTEHandle);
- }
- LDispose(My_List_Handle);
- DisposDialog(helpPtr);
- CloseResFile(refnum);
- SetPort(savePort);
- }
-
-
- /***********************************************************************\
- | void main( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To present an extensive help system to the user. This |
- | routine handles scrolling lists and dynamic pictures. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- pascal void main()
- {
- MenuHandle thisMenu; /* Current menu bar to disable */
- int index; /* Loop thru menu resources */
- Handle h; /* Lock this resource myself */
-
- /* Save the state of the registers */
- RememberA0();
- SetUpA4();
-
- /* Lock my code resource */
- asm {
- _RecoverHandle
- move.l a0, h
- }
- HLock(h);
-
- /* Re-initialize QuickDraw! */
- InitGraf(&thePort);
-
- /* Initialize the help system */
- Init_Help();
-
- /* Bring up the help box */
- if ( Create_Help() ) {
- /* Disable The Menus */
- for (index = First_Menu; index <= Last_Menu; index++) {
- thisMenu = GetMHandle(index);
- DisableItem(thisMenu,0);
- }
- DrawMenuBar();
-
- /* Trap help window events */
- Help_Event_Loop();
-
- /* Re-enable the menu bar and exit */
- for (index = First_Menu; index <= Last_Menu; index++) {
- thisMenu = GetMHandle(index);
- EnableItem(thisMenu,0);
- }
- DrawMenuBar();
- }
- /* Restore the registers & exit */
- HUnlock(h);
- RestoreA4();
- }
-
-
- /***********************************************************************\
- | void My_Scroll_Filter( theControl, thePart ) |
- |-----------------------------------------------------------------------|
- | Purpose: TrackControl() will call this routine for all events except |
- | dragging the thumb wheel by the user. All "up & down" |
- | events by the user are then translated into the correct |
- | TextEdit Manager calls to correctly position the text. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | theControl -> Handle the the scroller control. |
- | thePart -> That part of the scroller the user interacted with. |
- |-----------------------------------------------------------------------|
- | Returns :: Void. |
- \***********************************************************************/
-
- static pascal void My_Scroll_Filter( theControl, thePart )
- ControlHandle theControl;
- int thePart;
- {
- int start, stop; /* The outer boundry values of the scroller */
- int page; /* The computed amount to correctly page */
- int newValue; /* The new value to scroll up or down */
- int oldValue; /* The previous value of the control */
- long finalTicks; /* Slow down the action to appear natural */
-
- /* Get the upper & lower limits to perform saftey checks */
- start = (*theControl)->contrlMin;
- stop = (*theControl)->contrlMax;
- oldValue = GetCtlValue(theControl);
-
- /* Compute the amount of scrolling for page ups & downs */
- page = (Display_Rect.bottom - Display_Rect.top) / (*myTEHandle)->lineHeight;
-
- /* Get the current value of the control */
- newValue = GetCtlValue(theControl);
-
- /* Process the event accordingly */
- switch ( thePart ) {
-
- case inUpButton : /* Scroll up one line */
- newValue -= 1;
- /* Saftey check! */
- if (newValue < start)
- newValue = start;
- break;
-
- case inDownButton: /* Scroll down one line */
- newValue += 1;
- /* Saftey check! */
- if (newValue > stop)
- newValue = stop;
- break;
-
- case inPageUp : /* Perform a page up */
- newValue -= page;
- /* Saftey check! */
- if (newValue < start)
- newValue = start;
- break;
-
- case inPageDown : /* Perform a page down */
- newValue += page;
- /* Saftey check! */
- if (newValue > stop)
- newValue = stop;
- break;
-
- default : break;
- }
-
- /* Now set the control to the proper amount */
- SetCtlValue( theControl, newValue );
- Delay(2,&finalTicks);
- Scroll_Text( oldValue, newValue );
- }
-
-
- /***********************************************************************\
- | int ParseInt( pPointer ) |
- |-----------------------------------------------------------------------|
- | Purpose: Get the next integer from the HTBL resource. |
- |-----------------------------------------------------------------------|
- | Arguments :: Handle into the resource. |
- |-----------------------------------------------------------------------|
- | Returns :: Next integer in the HTBL resource. |
- \***********************************************************************/
-
- static int ParseInt( pPointer )
- char **pPointer;
- {
- int result=0; /* Final integer result */
- unsigned char hiWord, lowWord; /* Store 2 halves of the int */
-
- /* Get the raw data */
- hiWord = (unsigned char) *((*pPointer)++);
- lowWord = (unsigned char) *((*pPointer)++);
-
- /* Now pack these into the integer! */
- result = result | hiWord;
- result = (result << 8) | lowWord;
-
- return(result);
- }
-
-
- /***********************************************************************\
- | int ParseOSType( pPointer ) |
- |-----------------------------------------------------------------------|
- | Purpose: Get the next screen type ('PICT' or 'TEXT') from the HTBL |
- | resource. |
- |-----------------------------------------------------------------------|
- | Arguments :: Handle into the resource. |
- |-----------------------------------------------------------------------|
- | Returns :: Next longint in the HTBL resource. |
- \***********************************************************************/
-
- static long ParseOSType( pPointer )
- char **pPointer;
- {
- long result=0; /* Final longint to return */
- char nextByte; /* 1/4 of the longint */
- int index; /* Loop thru bytes in a long */
-
- /* Get the first of four bytes */
- nextByte = (char) *((*pPointer)++);
- result = result | (long) nextByte;
-
- /* Now loop thru the rest! */
- for (index = 1; index < sizeof(long); index++) {
- nextByte = (char) *((*pPointer)++);
- result = (result << 8) | (long) nextByte;
- }
- return(result);
- }
-
-
- /***********************************************************************\
- | int ParseString( pDest, pSource ) |
- |-----------------------------------------------------------------------|
- | Purpose: Get the next string from the HTBL resource. |
- |-----------------------------------------------------------------------|
- | Arguments :: pDest -> Returned string. |
- | pSource -> Handle to the HTBL resource. |
- |-----------------------------------------------------------------------|
- | Returns :: Final result. |
- \***********************************************************************/
-
- static void ParseString( pDest, pSource )
- char *pDest, **pSource;
- {
- int iLen = *pDest++ = *((*pSource)++);
-
- while (--iLen >= 0)
- *pDest++ = *((*pSource)++);
- }
-
-
- /***********************************************************************\
- | void pStrCat( p1, p2, p3 ) |
- |-----------------------------------------------------------------------|
- | Purpose :: Concatenate two pascal strings "p1" and "p2" together, |
- | giving result "p3". |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | p1 -> Source string one. |
- | p2 -> Source string two. |
- | p3 -> Destination string. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void pStrCat( p1, p2, p3 )
- char *p1, *p2, *p3;
- {
- int len1, len2;
-
- len1 = *p1++;
- len2 = *p2++;
-
- *p3++ = len1 + len2;
- while (--len1 >= 0) *p3++=*p1++;
- while (--len2 >= 0) *p3++=*p2++;
- }
-
-
- /***********************************************************************\
- | void pStrCopy( p1, p2 ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To copy one pascal string into another. Direction of |
- | copy: p1 --> p2. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | p1 -> Source string. |
- | p2 -> Destination string. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void pStrCopy( p1, p2 )
- char *p1, *p2;
- {
- int len;
-
- len = *p2++ = *p1++;
- while (--len>=0) *p2++=*p1++;
- }
-
-
- /***********************************************************************\
- | void Refresh_Topics( void ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To draw (or redraw) the contents of the topics list. |
- |-----------------------------------------------------------------------|
- | Arguments :: None. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Refresh_Topics()
- {
- Rect tempRect; /* Temporary rectangle */
- short DType; /* Type of dialog item */
- Handle DItem; /* Handle to dialog item */
-
- LUpdate(helpPtr->visRgn,My_List_Handle);
- tempRect = List_Rect;
- InsetRect(&tempRect, -1, -1);
- FrameRect(&tempRect);
- }
-
-
- /***********************************************************************\
- | void Scroll_Picture( whatHit ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To display the next (or previous) picture in a help topic. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | whatHit -> Equal to Next_Button or Prev_Button in the dialog box. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Scroll_Picture( whatHit )
- int whatHit;
- {
- int theMax; /* High bounds of help topic */
- int theMin; /* Low bounds of that topic */
-
- /* Find out which pictures are relivant */
- theMin = resource_start[ Help_Topic ];
- theMax = resource_end[ Help_Topic ];
-
- /* Compute the new picture to display! */
- if ( (whatHit == Next_Button) && (Current_Pict < theMax) ) {
- Current_Pict++;
- Set_Button_State( Prev_Button, TRUE );
- if (Current_Pict < theMax)
- Set_Button_State( Next_Button, TRUE );
- else
- Set_Button_State( Next_Button, FALSE );
- Display_Pict( Current_Pict - theMin );
- }
- else if ( (whatHit == Prev_Button) && (Current_Pict > theMin) ) {
- Current_Pict--;
- Set_Button_State( Next_Button, TRUE );
- if (Current_Pict > theMin)
- Set_Button_State( Prev_Button, TRUE );
- else
- Set_Button_State( Prev_Button, FALSE );
- Display_Pict( Current_Pict - theMin );
- }
- else
- SysBeep(1);
- }
-
-
- /***********************************************************************\
- | void Scroll_Text( old, new ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To dynamically scroll the text edit window for the user. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | old -> The previous value of the scroll bar before the user event. |
- | new -> The new value to scroll the text. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Scroll_Text( oldValue, newValue )
- int oldValue;
- int newValue;
- {
- TEScroll(0, (oldValue - newValue) * (*myTEHandle)->lineHeight, myTEHandle);
- }
-
-
- /***********************************************************************\
- | void Set_Button_State( itemNum, state ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To either enable or disable a button within a dialog box. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | itemNum -> Item within the dialog to modify. |
- | state -> TRUE = on, FALSE = off. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void Set_Button_State(itemNum, state )
- int itemNum;
- Boolean state;
- {
- Rect iBox; /* The rectangle for the button */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
-
- GetDItem(helpPtr, itemNum, &iType, &iHandle, &iBox);
- if ( state )
- HiliteControl( (ControlHandle) iHandle, 0 );
- else
- HiliteControl( (ControlHandle) iHandle, 255);
- }
-
-
-
- /***********************************************************************\
- | void User_Message( theStr ) |
- |-----------------------------------------------------------------------|
- | Purpose :: To display a status message in the "Picture Scrolling" |
- | window. |
- |-----------------------------------------------------------------------|
- | Arguments :: |
- | theStr -> The pascal string to display. |
- |-----------------------------------------------------------------------|
- | Returns :: void. |
- \***********************************************************************/
-
- static void User_Message( theStr )
- char *theStr;
- {
- Rect iBox; /* The rectangle of the picture */
- int iType; /* Type of dialog item */
- Handle iHandle; /* Pointer to the item */
-
- GetDItem(helpPtr, Message_Area, &iType, &iHandle, &iBox);
- SetIText(iHandle, theStr);
- DrawDialog(helpPtr);
- }
-