/* These are the common routines for MT1 and MT2&3 on the Macintosh*/ #define TTHREE #ifdef TONE #include "macteach1.h" #else #include "macteach23.h" #endif #include //#include #define SDInumber 0xAA68 #define WNEnumber 0xA860 #define Unimplemented 0xA89F #define ENTER 3 Boolean AppleEventsInstalled () { OSErr err; long result; // THINK C's MacTraps library provides glue for Gestalt, so // it can be called safely under System 6. If an error is // returned, then Gestalt for the AppleEvents Selector is // not available (this also means that Apple Events are // not available) err = Gestalt (gestaltAppleEventsAttr, &result); return (!err && ((result >> gestaltAppleEventsPresent) & 0x0001)); // return TRUE if there is no // error and the proper bit of // result is set } void InitToolbox(void) { InitGraf(&qd.thePort); // Standard initialization calls InitFonts(); FlushEvents(everyEvent, 0); InitWindows(); InitMenus(); TEInit(); // InitDialogs(); InitCursor(); } void initMac(void) { Boolean aEvents; Boolean gDone = FALSE; // short doWhat,itemHit; // short fileCnt; // short i; // EventRecord *theEvent; OSErr err; InitToolbox(); aEvents = AppleEventsInstalled(); gSDI = TrapAvailable (SDInumber); if (aEvents) { err = AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc(MyHandleODoc),0, FALSE); err = AEInstallEventHandler (kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc(MyHandleOApp),0, FALSE); err = AEInstallEventHandler (kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerProc(MyHandlePDoc),0, FALSE); err = AEInstallEventHandler (kCoreEventClass,kAEQuitApplication, NewAEEventHandlerProc(MyHandleQUIT),0,FALSE); } /* else { //Get number of files double-clicked on by the user CountAppFiles ( &doWhat, &fileCnt ); if (fileCnt > 0) { // if the user selected one or more files if (doWhat == appOpen) { for (i = 1; i <= fileCnt; i++) { GetAppFiles ( i, &fileStuff ); PStrCpy( filename, fileStuff.fName); // JPJ: Try to keep fName a valid pascal string PtoCstr((StringPtr)filename); // JPJ PStrCpy(gInReply.fName,fileStuff.fName); doopen(); } } else if (doWhat == appPrint) { printf ("Files to print:\n"); for (i = 1; i <= fileCnt; i++) { GetAppFiles ( i, &fileStuff ); printf ("%s\n", PtoCstr (fileStuff.fName)); } } for (i = 0; i < fileCnt; i++) ClrAppFiles(i); } else { if (!gInReply.fName[0]) { #ifdef TONE i = 999; #else i = 997; #endif gAbtDialog = GetNewDialog(i, &gAbtRecord, (DialogPtr)-1L); outlin(1,gAbtDialog); if (gSDI) SetDialogCancelItem (gAbtDialog,2) ; ModalDialog(0L,&itemHit); CloseDialog(gAbtDialog); if (itemHit==2) dohelp(); else doopen(); } } }*/ gDragRect = (*GetGrayRgn())->rgnBBox; InsetRect(&gDragRect, 4, 4); } void alert(short n, short m) /* Display an alert dialog when an abnormal condition arises. On entry n is the alert type (note, warning, fatal), and m the message number */ { const short alertID = 998; //Resource number for Alert dialog message(n,m,0L,alertID); } void checkCursor(CursHandle iBeam) /* This routine examines to see if the cursor is present in an data entry type dialog box, and if so changes it to an I-bar. Otherwise it is the standard arrow cursor*/ { Point temp; static short i; if (gHelp) return; if (FrontWindow() == gMainDialog) { GetMouse(&temp); if (PtInRect(temp,&gReptBox) || PtInRect(temp,&gTimeBox)){ SetCursor(*iBeam); return; } else SetCursor(&qd.arrow); } } void demote(short n) /* After an error response, show card n, sound an alarm, and place the card in the error box */ { if (!reviewflag) { if (strcmp(instring,"TIME'S UP!!!!")) { SetDialogItemText(gItemHdl[fAns],(unsigned char *)"\pIncorrect!"); #ifdef TONE HiliteControl ((ControlHandle) gItemHdl[CANERR],0); #endif } #ifdef TONE else HiliteControl ((ControlHandle) gItemHdl[CANERR],255); #endif SetDialogItemText(gItemHdl[fAns],(unsigned char *)"\pIncorrect!"); SysBeep(6); flasharray[n].flag[curflag] = '5'; #ifdef TONE // Do not do this reset for MT 4 if (prog != '5') flasharray[n].flag[rrflag -'1'+2] = '0'; #endif } } void display(void) /* Display the current file, configuration, distribution of cards,and statistics of the latest test, if any */ { short i,j; char mystr[40]; SetPort(gMainDialog); #ifdef TTHREE curflag = rrflag + 3 - 2 * affixflag + '0';/*Determine configuration*/ #else curflag = rrflag - '1'; #endif countflag(); /* Obtain the card distribution */ /* JPJ: changed \p strings to c-strings in sprintf: no null byte corrupts heap */ sprintf(mystr,"%03d In deck",r[0]); SetDialogItemText(gMainHdl[mInDeck],CtoPstr(mystr)); sprintf(mystr,(char*)"%03d in Rung 1",r[1]); SetControlTitle((ControlHandle)gMainHdl[mRung1],CtoPstr(mystr)); sprintf(mystr,"%03d in Rung 2",r[2]); SetControlTitle((ControlHandle)gMainHdl[mRung2],CtoPstr(mystr)); sprintf(mystr,"%03d in Rung 3",r[3]); SetControlTitle((ControlHandle)gMainHdl[mRung3],CtoPstr(mystr)); sprintf(mystr,"%03d on Top",r[4]); SetControlTitle((ControlHandle)gMainHdl[mTop],CtoPstr(mystr)); sprintf(mystr,"%03d in Error Box",r[5]); SetControlTitle((ControlHandle)gMainHdl[mErrorBox],CtoPstr(mystr)); if (tested) { sprintf(mystr,"Tested: %d Correct: %d, %d%%", tested, right, (100*right)/tested); SetDialogItemText(gMainHdl[mPcent],CtoPstr(mystr)); showstat(); /*Max and min times, standard deviation and timeouts*/ } for (i=1; i<6; ++i) { j = r[i] ? 0 : 255; HiliteControl((ControlHandle)gMainHdl[i+2],j); //Rungx buttons } if (!r[0]) HiliteControl((ControlHandle)gMainHdl[mSelect],255); else HiliteControl((ControlHandle)gMainHdl[mSelect],0); while((!r[rungflag-'0'] || rungflag=='4') && rungflag !='1') setrung(rungflag-1); if (rungflag==1 && !r[rungflag]) rungflag = '5'; while((!r[rungflag-'0'] || rungflag=='4') && rungflag !='1') setrung(rungflag-1); ShowWindow(gMainDialog); SelectWindow(gMainDialog); } void doabout(void) /* Display the about dialog from the apple menu. If the gHelp button is pushed, show the gHelp window*/ { short rsrc,itemHit; const short aboutID = 999; const short aboutID2 = 998; rsrc = (prog == '2' || prog == '4') ? aboutID2 : aboutID; gAbtDialog = GetNewDialog(rsrc,&gAbtRecord,(DialogPtr) -1L); outlin(1,gAbtDialog); if (gSDI) SetDialogCancelItem (gAbtDialog,2) ; SetPort(gAbtDialog); ShowWindow(gAbtDialog); ModalDialog(0L, &itemHit); CloseDialog(gAbtDialog); if(itemHit==2) dohelp(); } short doClose(void) /* If the file has been changed, ask if it should be saved. If yes, save the file and statistics, close the files and fix the menu highlighting.*/ { short theType; const short dType = 4; // A dialog window instead of alert const short dMess = 2; // Save ladder and statistics before closing? if (inpfile) { if (dirty) { theType = message(dType,dMess,NULL,402); switch(theType) { case 1: SetCursor(*gWatch); savedo(); SetCursor(&qd.arrow); if (testtotl) savestat(); case 2: dirty = FALSE; break; default: return theType; } } fclose(inp); #ifdef TONE fclose(cmt); #endif inpfile = FALSE; gInReply.fName[0] = NUL; EnableItem(gMyMenus[1],flOpen); DisableItem(gMyMenus[1],flClose); DisableItem(gMyMenus[1],flSave); DisableItem(gMyMenus[1],flSaveAs); } return theType; } void docommand(unsigned long mResult) /*This routine handles mouse down in the menu. mResult is the menu and item hit */ { Str255 name; short theMenu, theItem,theType; short resval; // long ticks; /*There are a individual gHelp items for each of the menu items. As the menus are not identical for the two programs, the value of the gHelp item is adjusted according to the program. A group of the higher number items have the same gHelp item. If the gHelp flag is on, show the gHelp instead of doing the menu action */ theMenu = mResult >> 16; theItem = mResult; resval = (theMenu-256)*16 + theItem; if (resval>50) resval = 52; #ifdef TONE if (resval>37 && resval<48) ++resval; #endif if (gHelp) { if(resval== 43) dohelp(); showhelp(resval); return; } switch(theMenu) { case appleMenu: GetMenuItemText(gMyMenus[0], theItem, name); if(theItem==1) doabout(); /*apple menu About... item*/ else { EnableItem(gMyMenus[2],0); DrawMenuBar(); OpenDeskAcc( name); } break; case fileMenu: switch(theItem) { case flOpen: doopen(); break; case flQuit: theType = doClose(); /* JPJ: did not match prototype */ #ifdef IBM free (gMyPtr); #else DisposePtr(gMyPtr); #endif if (theType != 3) exit(0); break; case flClose: doClose(); /* JPJ: did not match prototype */ break; case flSave: SetCursor(*gWatch); /*Activate the delay cursor*/ savedo(); SetCursor(&qd.arrow); /*Restore regular cursor*/ break; case flSaveAs: SetCursor(*gWatch); saveasdo(); SetCursor(&qd.arrow); break; default: break; } break; case editMenu: break; case commandMenu: switch(theItem) { case cReset: restore(); display(); break; case cReview: HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); reviewflag = 1; dotest(cReview); reviewflag = 0; break; case cSelect: #ifdef TTHREE if (prog=='2') { HiliteControl ((ControlHandle) gMainHdl[mShuffle],255); DisableItem(gMyMenus[4],moRecall); DisableItem(gMyMenus[3],cShuffle); } else { HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); } #endif doselect(); display(); break; case cTest: HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); reviewflag = 0; dotest(cTest); if (testtotl) { HiliteControl((ControlHandle) gMainHdl[mStats],0); EnableItem (gMyMenus[3],cStats); } break; #ifdef TTHREE case cLookup: doseek(); break; #endif case cBrush: brush(); setshuf(1); break; case cHelp: dohelp(); break; case cStats: sessions(); break; case cShuffle: shufflag ^= 1; setshuf(shufflag); break; default: break; } break; case modeMenu: switch(theItem) { case moRecog: if(testtotl) { savestat(); } setrr('1'); break; case moRecall: if(testtotl) savestat(); setrr('2'); break; case moRung1: case moRung2: case moRung3: case moTop: case moErrBox: setrung(theItem-moRung1+'1'); break; default: break; } break; default: break; } HiliteMenu(0); } void dodrill(void) { char cnt[4]; GetDialogItemText(gMainHdl[mDrill],(unsigned char *)cnt); drillflg = cnt[1]-'0'; sprintf(instring,"%d",drillflg); SetDialogItemText(gMainHdl[mDrill],CtoPstr(instring)); } void dohelp(void) /* Provide gHelp to the user. Toggle the gHelp flag. If it is now on set the cursor to a ?, toggle the menu item, get the main gHelp description, adjust the scroll bars, and enable all menu items. If gHelp now off and no input file yet, request one, then reverse the above changes. */ { CursHandle Query; /*Question mark cursor for help*/ gHelp ^= 1; if (gHelp) { Query = GetCursor(128); if (FrontWindow() != gMainDialog) ShowWindow(gMainDialog); ShowWindow(gHelpWindow); SetCursor(*Query); SelectWindow(gHelpWindow); SetControlTitle((ControlHandle)gMainHdl[mHelp],(unsigned char *)"\pHelp Off"); SetMenuItemText(gMyMenus[3],cHelp,(unsigned char *)"\pHelp Off"); SelectWindow(gHelpWindow); (*ghTE)->hText = GetResource('TEXT',(textID)); (*ghTE)->teLength = GetResourceSizeOnDisk((*ghTE)->hText); TECalText(ghTE); setscroll(); SetControlValue(gvScroll,0); EnableItem (gMyMenus[3],0); EnableItem (gMyMenus[3],cStats); EnableItem (gMyMenus[3],cShuffle); EnableItem (gMyMenus[4],0); EnableItem (gMyMenus[1],flOpen); EnableItem (gMyMenus[1],flClose); EnableItem (gMyMenus[1],flSave); EnableItem (gMyMenus[1],flSaveAs); EnableItem (gMyMenus[1],flQuit); DrawMenuBar(); } else { if (!inpfile) { DisableItem(gMyMenus[3],0); DisableItem(gMyMenus[4],0); doopen(); } if (!testtotl) DisableItem(gMyMenus[3],cStats); SetControlTitle((ControlHandle)gMainHdl[mHelp],(unsigned char *)"\pHelp?"); SetMenuItemText(gMyMenus[3],cHelp,(unsigned char *)"\pHelp"); HideWindow(gHelpWindow); SelectWindow(gMainDialog); SetPort(gMainDialog); SetCursor(&qd.arrow); } } void domouse(WindowPtr whichWindow) /*This is the mouse handling routine. It is fairly standard*/ { short code; short myControl; /*current control handle*/ code = FindWindow(gMyEvent.where, &whichWindow); if (code != inSysWindow) { /*Not a desk accessory operation*/ DisableItem (gMyMenus[2],0); DrawMenuBar(); } switch (code) { case inMenuBar: /*Process a menu event*/ docommand(MenuSelect(gMyEvent.where)); break; case inSysWindow: /*In a desk accessory. Enable the edit menu*/ SystemClick(&gMyEvent, whichWindow); EnableItem (gMyMenus[2],0); DrawMenuBar(); break; case inDrag: /*In the title bar. Move the window*/ DragWindow(whichWindow,gMyEvent.where, &gDragRect); break; case inGoAway: /*Close the window. Mouse clicked in close box*/ if (TrackGoAway(whichWindow, gMyEvent.where)) { HideWindow(whichWindow); if (inpfile) { /*If an input file active, show the main dialog*/ display(); DisableItem(gMyMenus[1],flOpen); } else { /*Open an input if not one open*/ SetPort(gMainDialog); doopen(); DisableItem(gMyMenus[1],flClose); DisableItem(gMyMenus[1],flSave); DisableItem(gMyMenus[1],flSaveAs); DisableItem(gMyMenus[3],0); DisableItem(gMyMenus[4],0); DrawMenuBar(); } } break; case inGrow: /*In Size Box. Change the window size if active, else select it.*/ if (whichWindow == FrontWindow() && whichWindow==gHelpWindow) GrowWnd(whichWindow); else SelectWindow(whichWindow); break; case inContent:/*Select if not active, else handle scroll or content*/ if (whichWindow != FrontWindow()) { SelectWindow(whichWindow); SetPort(whichWindow); } else if (whichWindow == gHelpWindow) { GlobalToLocal(&gMyEvent.where); ResizePRect(whichWindow); if (!PtInRect(gMyEvent.where,&gpRect)) { myControl = FindControl(gMyEvent.where, whichWindow, &gWhichControl); switch(myControl) { /*Handle scrolling*/ case kControlUpButtonPart: // TrackControl(gWhichControl,gMyEvent.where, // (ProcPtr)ScrollUp); case kControlDownButtonPart: // TrackControl(gWhichControl,gMyEvent.where, // (ProcPtr)ScrollDown); break; case kControlPageUpPart: PageScroll(myControl, 1-winht); break; case kControlPageDownPart: PageScroll(myControl, winht-1); break; case kControlIndicatorPart: // if (TrackControl(gWhichControl,gMyEvent.where, // (ProcPtr)-1L)) ScrollBits(); break; } } } break; default: /*No other action valid*/ break; } } void domulti(void) // These are standard borrowed routines for ensuring multifinder compatibility { DialogPtr ResumeWindow,SuspendWindow; // short sysresult; if (gMyEvent.message & 1) { /*Resume*/ ResumeWindow = FrontWindow(); } else { /*Suspend*/ SuspendWindow = FrontWindow(); } } void doopen(void) /*Get a file name, open it and read it. Fix the shuffle menu and dialog item. Initialize the cursor, set the appropriate rung and mode flags, threshold time and error box settings and dialog title*/ { opentext(); readfile(); #ifdef TTHREE if (prog=='2') { HiliteControl ((ControlHandle) gMainHdl[mShuffle],255); DisableItem(gMyMenus[3],cShuffle); } else { HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); } #endif SetCursor(&qd.arrow); setrr(rrflag); #ifdef TTHREE setaffix(affixflag); #endif setrung(rungflag); sprintf(instring,"%d",drillflg); SetDialogItemText(gMainHdl[mDrill],CtoPstr(instring)); sprintf(instring,"%1d.%1d",threshld/factor, ((threshld%factor)*10)/factor); SetDialogItemText(gMainHdl[mTime],CtoPstr(instring)); setshuf(shufflag); EnableItem (gMyMenus[3],0); EnableItem (gMyMenus[4],0); HiliteControl((ControlHandle) gMainHdl[mStats],255); switch(prog) { case '2': case '4': SetWTitle(gMainDialog,(unsigned char *)"\pMacTeach 3: Learning Loglan Affixes"); break; default: break; } DrawMenuBar(); } pascal Boolean Timeget(DialogPtr theDialog, EventRecord *theEvent, short *item) /*This routine is necessary as a user hook to enable getting a user time to the first keystroke, and notifying if the time exceeds the threshold alloted. It has to handle the CR and Enter buttons since this part of the normal routine is replaced by the user routine*/ { short k; if (theEvent->what != keyDown && !ind1) { if ((TickCount()-macticks) >threshld) { ticks = threshld; SetDialogItemText(gItemHdl[3],(unsigned char *)"\pTIME'S UP!!!!"); ++tmouts; *item = 1; return TRUE; } else ticks = TickCount()-macticks; return FALSE; } else { ind1 = 1; k = theEvent->message&0xFF; if(k==CR || k==ENTER) { *item = 1; return TRUE; } } return FALSE; } void dotimeout(void) /* This is Macintosh specific for setting the maximum time permitted for response. The response in seconds and fractions is converted to sixtieths of a second. It is reconverted, clipped and reentered in the dialog box. */ { char thno[256]; /* JPJ: increased size: better safe than sorry */ GetDialogItemText(gMainHdl[mTime],(unsigned char *)thno); PtoCstr((unsigned char *)thno); if (isdigit(thno[0])) { switch(strlen(thno)) { case 3: if (thno[1] != '.' || !isdigit(thno[2])) break; thno[1] = thno[2]; thno[2] = '\0'; ind1 = atoi(thno) * (factor/10); break; case 1: ind1 = atoi(thno) * factor; break; default: ind1 = threshld; break; } } if (ind1>1 && ind1<(93 * factor/10)) threshld = ind1; sprintf(instring,"%1d.%1d",threshld/factor, ((threshld%factor)*10)/factor); SetDialogItemText(gMainHdl[mTime],CtoPstr(instring)); } void DrawWindow(WindowPtr theWindow) /*On entry theWindow is the window pointer of the window to be drawn. This routine handles drawing of the window. If it is gHelp, the scroll bars must be drawn and the gHelp text clipped and updated, otherwise the main dialog window is drawn*/ { //short i,vpos; if (theWindow==gHelpWindow) { ClipRect(&theWindow->portRect); EraseRect(&theWindow->portRect); ResizePRect(theWindow); DrawGrowIcon(theWindow); TEUpdate(&theWindow->portRect, ghTE); SetControlValue(gvScroll,0); DrawControls(theWindow); } else { if (inpfile) display(); } } void eventloop(void) /* This is a standard event-handling loop for the teach programs. It is multifinder compatible */ { long uptime,sleep; WindowPtr whichWindow; /*current active window*/ CursHandle iBeam; GrafPtr savePort; /*Temporary saving of grafport*/ Boolean WNE; short itemHit; WNE = TrapAvailable(WNEnumber); sleep = 10; iBeam = GetCursor(iBeamCursor); for (;;) { /*For Multifinder*/ checkCursor(iBeam); if (WNE) WaitNextEvent(everyEvent,&gMyEvent,sleep,0L); else { SystemTask(); GetNextEvent(everyEvent, &gMyEvent); } itemHit = 0; if (IsDialogEvent(&gMyEvent)) { /*Check dialog first*/ if (gMyEvent.what == keyDown) { itemHit = keyequiv(1); /*For CR and Enter keys*/ if (gMyEvent.modifiers & cmdKey) continue; } if(!itemHit) DialogSelect(&gMyEvent,&gMainDialog,&itemHit); switch(itemHit) { case 1: /* This is an OK button. Set the error-box repeat count and threshold time*/ dodrill(); dotimeout(); break; case 2:/*Toggle the shuffle item. This is the select button*/ if (gHelp) { showhelp(33); break; } #ifdef TTHREE if (curflag==2) { HiliteControl ((ControlHandle) gMainHdl[mShuffle],255); DisableItem(gMyMenus[3],cShuffle); } else { HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); } #endif doselect(); display(); break; case 3: /*Rung radio buttons*/ case 4: case 5: case 6: case 7: if (gHelp) { showhelp(52); break; } setrung(itemHit + '.'); /* itemHit -2 + '0' */ break; case 9: /*Test button*/ if (gHelp) { showhelp(35); break; } HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); reviewflag = 0; dodrill(); dotimeout(); dotest(cTest); if (testtotl) { HiliteControl((ControlHandle) gMainHdl[mStats],0); } break; case 10: /*Review button*/ if (gHelp) { showhelp(34); break; } HiliteControl ((ControlHandle) gMainHdl[mShuffle],0); EnableItem(gMyMenus[3],cShuffle); reviewflag = 1; dotest(cReview); reviewflag = 0; break; case 11: /*Statistics button*/ if (gHelp) { showhelp(40); break; } sessions(); break; case 12: if (gHelp) showhelp(9); break; case 15: if (gHelp) showhelp(8); break; case 16: /*Shuffle check box*/ if (gHelp) { showhelp(37); break; } shufflag ^= 1; setshuf(shufflag); break; case 18: if (gHelp) { showhelp(49); break; } case 19: /*Quit button*/ if (gHelp) { showhelp(50); break; } if(testtotl) { savestat(); } setrr(itemHit-17+'0'); break; case 26: /*Help button*/ dohelp(); break; default: break; } } else { /*Not a dialog event*/ switch(gMyEvent.what) { case mouseDown: domouse(whichWindow); break; case mouseUp: uptime = gMyEvent.when; break; case keyDown: case autoKey: if (gMyEvent.modifiers & cmdKey) docommand(MenuKey((char)gMyEvent.message)); break; case MFEVENT: domulti(); break; case kHighLevelEvent: if (AEProcessAppleEvent(&gMyEvent)!=noErr) alert(0,151); //Apple Event Error break; case activateEvt: whichWindow = (WindowPtr) gMyEvent.message; if (whichWindow == gHelpWindow) { SetPort(gHelpWindow); DrawGrowIcon(gHelpWindow); if (gMyEvent.modifiers&1) { TEActivate(ghTE); ShowControl(gvScroll); } else { TEDeactivate(ghTE); HideControl(gvScroll); HideWindow(gHelpWindow); } } break; case updateEvt: whichWindow = (WindowPtr) gMyEvent.message; GetPort(&savePort); SetPort(whichWindow); InvalRect(&whichWindow->portRect); BeginUpdate(whichWindow); DrawWindow(whichWindow); EndUpdate(whichWindow); SetPort(savePort); break; case diskEvt: if (gMyEvent.message) DIBadMount(gOrigin,gMyEvent.message); break; default: break; } } } } void GrowWnd(WindowPtr whichWindow) /* On entry whichWindow is the Window pointer. The window is changed to the new size and the scroll bars adjusted. This is fairly standard Macintosh stuff, largely borrowed.*/ { long longResult; short height, Width; Rect growRect; // Rect temrect; Rect screen; screen = qd.screenBits.bounds; SetRect(&growRect,screen.left + 30,screen.top+51, screen.right - 8,screen.bottom - 8); SetPort(whichWindow); longResult = GrowWindow(whichWindow, gMyEvent.where, &growRect); if (longResult == 0 || longResult == -1) return; height = longResult >> 16; Width = longResult; SizeWindow(whichWindow, Width, height, TRUE); if (whichWindow==gHelpWindow) { MoveScrollBars(gHelpWindow,gvScroll,0L); SetControlValue(gvScroll,0); ResizePRect(gHelpWindow); (*ghTE)->viewRect = gpRect; (*ghTE)->destRect.right = gpRect.right; TECalText(ghTE); setscroll(); } } void initteach(void) /* These are the startup items required for the teach programs. If a file has been double clicked it loads it and proceeds immediately, otherwise it gives the About Dialog window. The various cursors, scroll bars, text sizes and fonts, and text edit (for Help) are initialized. */ { short i,theType; const short pwindID = 128; // Resource number of main window const short hwindID = 128; /*Resource number of help window*/ setupmenu(); DisableItem (gMyMenus[3],cStats); inpfile = gHelp = 0; factor = 60; /* for time conversion*/ gWatch = GetCursor(watchCursor); gHelpWindow = GetNewWindow(hwindID,&gHlpRecord,(WindowPtr)-1L); SetPort(gHelpWindow); TextFont(2); TextSize(12); gvScroll = GetNewControl(256, gHelpWindow); MoveScrollBars(gHelpWindow,gvScroll,0L); ResizePRect(gHelpWindow); ghTE = TENew(&gpRect, &gpRect); gMainDialog = GetNewDialog(pwindID,&gMainRecord,(DialogPtr)-1L); HMSetDialogResID(128); for (i=1; iportRect; if (tgvScroll) { HideControl(tgvScroll); MoveControl(tgvScroll, rp->right-15, rp->top-1); SizeControl(tgvScroll, 16, rp->bottom-rp->top-13); ShowControl(tgvScroll); } if (thscroll) { HideControl(thscroll); MoveControl(thscroll, rp->left, rp->bottom-15); SizeControl(thscroll, rp->right-rp->left-13,16); ShowControl(thscroll); } } void mycpy(char *stra, char *strb) /* copy strb to stra, removing control punctuation such as :,&,\. '/' is inserted but a space added, Sp,=,+ and - become just space, '|' becomes a double return and indent, otherwise the character is copied as is. */ { char *s1,*s2,ch; s1 = stra; s2 = strb; while (ch = *s2++) { switch(ch) { case ':': case '&': break; case '/': *s1++ = ch; *s1++ = SP; break; case '\\': *s1++ = *(s2++); break; case ' ': case '=': case '-': case '+': *s1++ = SP; break; case '|': *s1++ = '\r'; *s1++ = '\r'; *s1++ = SP; *s1++ = SP; break; default: *s1++ = ch; } } *s1++ = SP; *s1 = '\0'; } void opentext(void) /* This routine calls the standard file package to select a file name, and then opens the selected file. */ { FInfo theInfo; // OSType stype; OSErr resultCode; /*Result code from I/O operations*/ // short n; SFTypeList myType; myType[0] = 'TEXT'; if (!gInReply.fName[0]) { SFGetFile (gOrigin,NULL,NULL,(short)3,myType,NULL,&gInReply); if (!gInReply.good) exit(0); resultCode = GetFInfo(gInReply.fName,gInReply.vRefNum, &theInfo); IOCheck(resultCode); #ifdef TTHREE theInfo.fdCreator = 'LOGN'; /* JPJ: changed fName[0] to fName[1] (its a p-string) */ #else theInfo.fdCreator = 'Log3'; #endif theInfo.fdType = 'TEXT'; resultCode = SetFInfo(gInReply.fName,gInReply.vRefNum, &theInfo); IOCheck(resultCode); PStrCpy( filename, gInReply.fName); /* JPJ */ PtoCstr((StringPtr)filename); /* JPJ */ } if (!(inp = fopen(filename,"r+"))) alert(1,3); SetDialogItemText(gMainHdl[mFile],gInReply.fName); /* JPJ: used to be CtoPstr(filename) */ DisableItem(gMyMenus[1],flOpen); EnableItem(gMyMenus[1],flClose); EnableItem(gMyMenus[1],flSave); EnableItem(gMyMenus[1],flSaveAs); } void outlin(short no, DialogPtr dialog) /* This routine outlines button no in dialog dialog*/ { short theType; SetPort(dialog); GetDialogItem(dialog,no,&theType,&gItemHdl[0],&gItemBox); PenSize(3,3); InsetRect(&gItemBox,-4,-4); FrameRoundRect(&gItemBox,16,16); } void PageScroll(short code, short amount) /*This is one of the standard scrolling routines for the Macintosh, and scrolls when the mouse is between the thumb and one of the arrows. Code is the control part where the mouse is, and amount is the amount required for a page scroll*/ { short maxht; Point myPt; do { GetMouse(&myPt); if (TestControl(gWhichControl,myPt) == code) { maxht = (*ghTE)->nLines; SetControlValue(gWhichControl, GetControlValue(gWhichControl) + (amount * maxht)/(maxht-winht)); ScrollBits(); } } while (StillDown()); } void ResizePRect(WindowPtr theWindow) /*This creates the usable window by insetting the portRect by the scroll bar widths and allowing a slight margin*/ { gpRect = theWindow->portRect; gpRect.left += 4; gpRect.right -= 20; gpRect.bottom -= 20; } void saveasdo(void) /* Allow a file to be saved under a different name. Uses the Standard File Package to get the name. Sets the file and user type appropriately for each programme */ { //short i; FInfo theInfo; OSErr resultCode; /*Result code from I/O operations*/ // OSType stype; SFReply outReply; /*standard reply for output files*/ char *outReplyFile[256]; /* JPJ: c-string version of outReply.fName */ dirty = TRUE; SFPutFile(gOrigin,(unsigned char *)"\pSave output in what file?", (unsigned char *)"\pStudy.fil", NULL, &outReply); if (outReply.good) { if (fclose(inp)) alert(1,6); inpfile = FALSE; resultCode = GetFInfo(outReply.fName,outReply.vRefNum, &theInfo); PStrCpy( outReplyFile, outReply.fName); /* JPJ: make copy of the file name */ PtoCstr((StringPtr)outReplyFile); /* JPJ: make it a c-string */ switch (resultCode) { case noErr: break; case fnfErr: /* PtoCstr(outReply.fName); JPJ: need to convert outside the switch() */ #ifdef TTHREE /* JPJ: changed fName[0] to fName[1]: this is a p-string */ resultCode = Create (outReply.fName,outReply.vRefNum,'LOGN', 'TEXT'); #else resultCode = Create (outReply.fName,outReply.vRefNum,'LOG3', 'TEXT'); #endif IOCheck(resultCode); break; default: IOCheck(resultCode); } #ifdef THINK_C /* JPJ : Think C doesn't do the vRefNum filename trick */ sprintf(filename,"%s",outReplyFile); #else sprintf(filename,"%d:%s",outReply.vRefNum,outReplyFile); #endif if (!(inp = fopen(filename,"w"))) alert(1,3); inpfile = TRUE; writefile(inp); } } void savestat(void) /* appends the session statistics to the appropriate statistics file, dependent on programme and mode, and creates the file if it does not already exist*/ {// short i; sessions(); #ifdef TTHREE if (rrflag == '1' && affixflag == '1') if (!(stats = fopen("Stats3.paf","a"))) alert(1,3); if (rrflag == '1' && affixflag == '2') if (!(stats = fopen("Stats2.le","a"))) alert(1,3); if (rrflag == '2' && affixflag == '1') if (!(stats = fopen("Stats3.afp","a"))) alert(1,3); if (rrflag == '2' && affixflag == '2') if (!(stats = fopen("Stats2.el","a"))) alert(1,3); #else if (rrflag == '1') { if (!(stats = fopen("Stats1.le","a"))) alert(1,3); } else if (!(stats = fopen("Stats1.el","a"))) alert(1,3); #endif statline(); testtotl = righttot = tested = maximum = 0; sqtotal = ticktotl = timetotl = 0L; minimum = 10000; DisableItem (gMyMenus[3],cStats); HiliteControl((ControlHandle) gMainHdl[mStats],255); } void ScrollBits(void) /* A standard borrowed Macintosh routine for doing the actual scrolling of a Text Edit record */ { Point oldOrigin; short dh, dv,maxht; maxht = (*ghTE)->nLines; oldOrigin = gTheOrigin; gTheOrigin.v = (GetControlValue(gvScroll) * (maxht-winht))/maxht; gTheOrigin.v *= (*ghTE)->lineHeight; dh = oldOrigin.h - gTheOrigin.h; dv = oldOrigin.v - gTheOrigin.v; TEScroll(dh, dv, ghTE); } pascal void ScrollDown(ControlHandle WhichControl, short theCode) /*These are standard routines for scrolling when the mouse is in one of the arrow buttons of a scroll bar*/ { if (theCode == (short)kControlDownButtonPart) { SetControlValue(gWhichControl, GetControlValue(WhichControl)+1); ScrollBits(); } } pascal void ScrollUp(ControlHandle WhichControl, short theCode) /*These are standard routines for scrolling when the mouse is in one of the arrow buttons of a scroll bar*/ { if (theCode == (short)kControlUpButtonPart) { SetControlValue(WhichControl, GetControlValue(WhichControl)-1); ScrollBits(); } } /* Calculate and write the session statistics */ void sessions(void) /* Calculate and write the session statistics in a screen window */ {// long temp; short i,item,theType; DialogPtr statDialog; /*Dialog pointer for statistics record*/ DialogRecord statRecord; Handle itemHdl[9]; /*Storage for handles of Test/Review dialog*/ setstat(); getend(); statDialog = GetNewDialog(statID,&statRecord,(DialogPtr)-1L); ShowWindow(statDialog); outlin(1,statDialog); for (i=2; i<9; ++i) GetDialogItem(statDialog,i,&theType,&itemHdl[i],&gItemBox); sprintf (instring,"%2d/%02d/%02d",stime->tm_mon+1,stime->tm_mday, stime->tm_year); SetDialogItemText(itemHdl[2],CtoPstr(instring)); sprintf(instring,"%2d:%02d",shour,smin); SetDialogItemText(itemHdl[3],CtoPstr(instring)); sprintf(instring,"%2d:%02d",etime->tm_hour,etime->tm_min); SetDialogItemText(itemHdl[4],CtoPstr(instring)); sprintf (instring,"%d",testtotl); SetDialogItemText(itemHdl[5],CtoPstr(instring)); sprintf(instring,"%d",righttot); SetDialogItemText(itemHdl[6],CtoPstr(instring)); sprintf(instring,"%d%%",percent); SetDialogItemText(itemHdl[7],CtoPstr(instring)); sprintf (instring,"%d.%02d ± %d.%02d secs",average/60, ((average%60)*5)/3,sdevn/60,((sdevn%60)*5)/3); SetDialogItemText(itemHdl[8],CtoPstr(instring)); GetDialogItem(statDialog,17,&theType,&itemHdl[1],&gItemBox); sprintf (instring,"%d",tmouts); SetDialogItemText(itemHdl[1],CtoPstr(instring)); ModalDialog(0L,&item); DisposeDialog(statDialog); SetPort(gMainDialog); } void setrr(short val) /* Set the recognition-recall flag to value val and check the appropriate menu item */ { short j; switch(prog) { case '2': case '4': j = (prog=='2') ? 255 : 0; HiliteControl((ControlHandle)gMainHdl[mRecall],j); break; default: break; } CheckItem(gMyMenus[4],rrflag-'0',FALSE); /*uncheck current item */ SetControlValue((ControlHandle)gMainHdl[rrflag + 17 -'0'],BtnOff); //Recognize or Recall rrflag = val; /*Reset the flag*/ CheckItem(gMyMenus[4],rrflag-'0',TRUE); /*and check the new value*/ SetControlValue((ControlHandle)gMainHdl[rrflag + 17 - '0'],BtnOn);//Recognize or Recall tested = 0; display(); } void setrung(short val) /* Set the rung flag to value val and check the appropriate menu item */ { CheckItem(gMyMenus[4],rungflag+moRung1-'1',FALSE);/*uncheck current item */ SetControlValue((ControlHandle)gMainHdl[rungflag-'.'],BtnOff); //Old Rungx button rungflag = val; /*Reset the flag*/ CheckItem(gMyMenus[4],rungflag+moRung1-'1',TRUE);/*and check the new value*/ SetControlValue((ControlHandle)gMainHdl[rungflag-'.'],BtnOn);//New Rungx button } void setscroll(void) /* Adjust the scroll bar range according to the text length and window height*/ { short maxl; winht = (gHelpWindow->portRect.bottom - gHelpWindow->portRect.top - 30) /(*ghTE)->lineHeight; maxl = (*ghTE)->nLines; if (maxl<=winht) { HiliteControl(gvScroll,255); } else HiliteControl(gvScroll,0); SetControlMaximum(gvScroll,maxl); ScrollBits(); } void setshuf(short val) /* Set the shuffle flag to value val and check the appropriate menu item */ { shufflag = val; SetControlValue((ControlHandle) gMainHdl[mShuffle],val); SetMenuItemText(gMyMenus[3],cShuffle,(unsigned char *)(shufflag)?"\pNo Shuffle":"\pShuffle"); } void setupmenu(void) /*Get the various menu resources, insert them and draw the menu bar*/ { short i; gMyMenus[0] = GetMenu((short)appleMenu); AppendResMenu(gMyMenus[0], 'DRVR'); gMyMenus[1] = GetMenu((short)fileMenu); gMyMenus[2] = GetMenu((short)editMenu); gMyMenus[3] = GetMenu((short)commandMenu); gMyMenus[4] = GetMenu((short)modeMenu); for (i=0;ihText = GetResource('TEXT',n); if (!(*ghTE)->hText) return; (*ghTE)->teLength = GetResourceSizeOnDisk((*ghTE)->hText); TECalText(ghTE); setscroll(); InvalRect(&gHelpWindow->portRect); SelectWindow(gHelpWindow); HiliteMenu(0); return; } void showstat(void) /* Calculate and display the statistics for a single test */ { char mystr[40]; long temp; testav = ticktotl/tested; temp = testav - moment; tsd = isqrt(labs(temp*temp - square/tested)); sprintf (mystr,"Average time: %d.%02d ± %d.%02d secs", testav/60,((testav%60)*5)/3,tsd/60,((tsd%60)*5)/3); SetDialogItemText(gMainHdl[mAvTim],CtoPstr(mystr)); sprintf (mystr,"Range: %d.%02d - %d.%02d, Overtime: %d", minimum/60,((minimum%60)*5)/3,maximum/60,((maximum%60)*5)/3,tmouts); SetDialogItemText(gMainHdl[mConfL],CtoPstr(mystr)); } OSErr MyGotRequiredParams (AppleEvent *theAppleEvent) { DescType returnedType; Size actualSize; OSErr err; err = AEGetAttributePtr (theAppleEvent, keyMissedKeywordAttr, typeWildCard, &returnedType, nil, 0, &actualSize); if (err == errAEDescNotFound) // you got all the required parameters return noErr; else if (!err) // you missed a required parameter return errAEEventNotHandled; else // the call to AEGetAttributePtr failed return err; } pascal OSErr MyHandleOApp (AppleEvent *theAppleEvent, AppleEvent *reply, long Refcon) { OSErr err; short i,itemHit; if (err = MyGotRequiredParams(theAppleEvent)) return err; if (!gInReply.fName[0]) { #ifdef TONE i = 999; #else i = 997; #endif gAbtDialog = GetNewDialog(i, &gAbtRecord, (DialogPtr)-1L); outlin(1,gAbtDialog); SetDialogCancelItem (gAbtDialog,2) ; ModalDialog(0L,&itemHit); CloseDialog(gAbtDialog); if (itemHit==2) dohelp(); else doopen(); } return noErr; } pascal OSErr MyHandleODoc (AppleEvent *theAppleEvent, AppleEvent* reply, long RefCon) { FSSpec myFSS; AEDescList docList; OSErr err; long index,itemsInList; Size actualSize; AEKeyword keywd; DescType returnedType; // get the direct parameter--a descriptor list--and put it into a docList err = AEGetParamDesc (theAppleEvent, keyDirectObject, typeAEList, &docList); if (err) return err; // check for missing parameters err = MyGotRequiredParams (theAppleEvent); if (err) return err; // count the number of descriptor records in the list err = AECountItems (&docList, &itemsInList); if (err) return err; // now get each descriptor record from the list, coerce the returned // data to an FSSpec record, and open the associated file // printf ("Files to open:\n"); for (index = 1; index <= itemsInList; index++) { err = AEGetNthPtr (&docList, index, typeFSS, &keywd, &returnedType, (Ptr) &myFSS, sizeof(myFSS), &actualSize); if (err) return err; PStrCpy(filename,myFSS.name); PtoCstr((StringPtr)filename); PStrCpy(gInReply.fName,myFSS.name); doopen(); } err = AEDisposeDesc (&docList); return noErr; } pascal OSErr MyHandlePDoc(AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefCon) { FSSpec myFSS; AEDescList docList; OSErr err; long index, itemsInList; Size actualSize; AEKeyword keywd; DescType returnedType; // get the direct parameter--a descriptor list--and put it into a docList err = AEGetParamDesc (theAppleEvent, keyDirectObject, typeAEList, &docList); if (err) return err; // check for missing parameters err = MyGotRequiredParams (theAppleEvent); if (err) return err; // count the number of descriptor records in the list err = AECountItems (&docList, &itemsInList); if (err) return err; // now get each descriptor record from the list, coerce the returned // data to an FSSpec record, and open the associated file printf ("Files to print:\n"); for (index = 1; index <= itemsInList; index++) { err = AEGetNthPtr (&docList, index, typeFSS, &keywd, &returnedType, (Ptr) &myFSS, sizeof(myFSS), &actualSize); if (err) return err; printf ("%s\n", PtoCstr(myFSS.name)); } err = AEDisposeDesc (&docList); return noErr; } pascal OSErr MyHandleQUIT (AppleEvent *theAppleEvent, AppleEvent *reply, long Refcon) { OSErr iErr; if ( iErr = MyGotRequiredParams(theAppleEvent)) return iErr; else { doClose(); exit(1); } return noErr; } Boolean TrapAvailable(short theTrap) { TrapType tType; tType = GetTrapType(theTrap); if (tType==ToolTrap) if ((theTrap&&0x7ff)>=NumToolboxTraps()) theTrap=Unimplemented; return NGetTrapAddress(theTrap,tType) != NGetTrapAddress(Unimplemented,ToolTrap); } short NumToolboxTraps(void) { // const short _InitGraf = 0xA86E; /* JPJ: added for THINK C */ return(NGetTrapAddress(0xA86E, ToolTrap) == NGetTrapAddress(0xaa6e,ToolTrap)) ? 0x200 : 0x400; } TrapType GetTrapType(short theTrap) { return ((theTrap&&0x800)>0)? ToolTrap : OSTrap; }