/* abCalcNDA.c By: Jeremy Rand */ #pragma nda NDAOpen NDAClose NDAAction NDAInit -1 0xFFFF " abCalc\\H**" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "abCalcNDA.defs" #include "abCalc.h" #include "abCStack.h" #include "abCError.h" #include "expr/abCExpr.h" #include "ops/abCOp.h" #define MIN_STACK_ITEMS 4 void UpdateStack(void); typedef struct listElement { char *memPtr; Byte memFlag; } listElement; static BOOLEAN gListStarted = FALSE; static Handle gSANEDirectPage = NULL; static BOOLEAN gCalcActive = FALSE; static GrafPortPtr gCalcWinPtr = NULL; static unsigned int gUserId; static unsigned int gResourceId; listElement *gOpList = NULL; listElement gStackList[AB_CALC_STACK_DEPTH]; abCalcExpr gNDAExpr; static Str255 gStrBuf; static int gSelectedStackItem = -1; char *gBuffer = NULL; void NDAClose(void) { int i; if (gCalcActive) { CloseWindow(gCalcWinPtr); gCalcWinPtr = NULL; gCalcActive = FALSE; } if (gBuffer != NULL) { free(gBuffer); gBuffer = NULL; } if (gOpList != NULL) { free(gOpList); gOpList = NULL; } for (i = 0; i < AB_CALC_STACK_DEPTH; i++) { if (gStackList[i].memPtr != NULL) { free(gStackList[i].memPtr); gStackList[i].memPtr = NULL; } } CloseResourceFile(gResourceId); ResourceShutDown(); } void NDAInit(int code) { int i; if (code) { gCalcActive = FALSE; gUserId = MMStartUp(); if (!ListStatus()) { LoadOneTool(0x1c, 0); ListStartUp(); gListStarted = TRUE; } if (!SANEStatus()) { LoadOneTool(0x0a, 0); gSANEDirectPage = NewHandle(256, gUserId, attrBank | attrFixed | attrLocked | attrPage, NULL); SANEStartUp((Word) *gSANEDirectPage); } abCalcInit(); for (i = 0; i < AB_CALC_STACK_DEPTH; i++) { gStackList[i].memPtr = NULL; } } else { if (gSANEDirectPage) { SANEShutDown(); DisposeHandle(gSANEDirectPage); UnloadOneTool(0x0a); gSANEDirectPage = NULL; } if (gListStarted) { ListShutDown(); UnloadOneTool(0x1c); gListStarted = FALSE; } } } #pragma databank 1 void DrawContents(void) { PenNormal(); DrawControls(GetPort()); } #pragma databank 0 GrafPortPtr NDAOpen(void) { Pointer pathToSelf; unsigned int oldResourceApp; LevelRecGS levelDCB; unsigned int oldLevel; SysPrefsRecGS prefsDCB; unsigned int oldPrefs; int numOps; int i; Handle opListCtl; if (gCalcActive) return NULL; oldResourceApp = GetCurResourceApp(); ResourceStartUp(gUserId); pathToSelf = LGetPathname2(gUserId, 1); levelDCB.pCount = 2; GetLevelGS(&levelDCB); oldLevel = levelDCB.level; levelDCB.level = 0; SetLevelGS(&levelDCB); prefsDCB.pCount = 1; GetSysPrefsGS(&prefsDCB); oldPrefs = prefsDCB.preferences; prefsDCB.preferences = (prefsDCB.preferences & 0x1fff) | 0x8000; SetSysPrefsGS(&prefsDCB); gResourceId = OpenResourceFile(readEnable, NULL, pathToSelf); gCalcWinPtr = NewWindow2("\p abCalc ", 0, DrawContents, NULL, refIsResource, abCalcWinNum, rWindParam1); SetSysWindow(gCalcWinPtr); ShowWindow(gCalcWinPtr); SelectWindow(gCalcWinPtr); SetPort(gCalcWinPtr); if (gOpList == NULL) { numOps = abCalcOpNumOps(); gOpList = malloc(sizeof(*gOpList) * numOps); for (i = 0; i < numOps; i++) { gOpList[i].memPtr = abCalcOpNth(i)->name; gOpList[i].memFlag = 0; } } opListCtl = (Handle)GetCtlHandleFromID(gCalcWinPtr, abCalcOpList); NewList2(NULL, 1, (Ref)gOpList, 0, numOps, opListCtl); UpdateStack(); gCalcActive = TRUE; prefsDCB.preferences = oldPrefs; SetSysPrefsGS(&prefsDCB); levelDCB.level = oldLevel; SetLevelGS(&levelDCB); SetCurResourceApp(oldResourceApp); return gCalcWinPtr; } void UpdateStack(void) { Handle stackListCtl; int i; int numToDisplay = abCalcStackNumItems(); if (numToDisplay < MIN_STACK_ITEMS) { numToDisplay = MIN_STACK_ITEMS; } stackListCtl = (Handle)GetCtlHandleFromID(gCalcWinPtr, abCalcStackList); for (i = numToDisplay - 1; i >= 0; i--) { if (gStackList[i].memPtr == NULL) { gStackList[i].memPtr = malloc(AB_CALC_EXPR_STRING_MAX + 8); } abCalcStackExprStringAt(numToDisplay - i - 1, gStackList[i].memPtr, TRUE); gStackList[i].memFlag = 0; } NewList2(NULL, numToDisplay - 3, (Ref)gStackList, 0, numToDisplay, stackListCtl); gSelectedStackItem = -1; } BOOLEAN ErrorRaised(void) { char *errorString = abCalcGetError(); if (errorString == NULL) { return FALSE; } AlertWindow(awCString+awResource, (Pointer)&errorString, abCalcErrorAlert); abCalcClearError(); return TRUE; } void PushCalcEntry(CtlRecHndl entryBox) { abCalcOp *op; GetLETextByID(gCalcWinPtr, abCalcEntryBox, &gStrBuf); if (gStrBuf.textLength > 0) { gStrBuf.text[gStrBuf.textLength] = '\0'; op = abCalcOpLookup(gStrBuf.text); if (op != NULL) { op->execute(); } else if (abCalcParseExpr(&gNDAExpr, gStrBuf.text) != NULL) { abCalcStackExprPush(&gNDAExpr); } else { LERecHndl leHandle; HLock((Handle)entryBox); leHandle = (LERecHndl)(*entryBox)->ctlData; HUnlock((Handle)entryBox); LESetSelect(0, gStrBuf.textLength, leHandle); abCalcRaiseError(abCalcSyntaxError, NULL); return; } gStrBuf.textLength = 0; SetLETextByID(gCalcWinPtr, abCalcEntryBox, &gStrBuf); } } void ExecCalcCmd(char *cmd) { abCalcOp *op = abCalcOpLookup(cmd); CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); PushCalcEntry(entryBox); if ((!ErrorRaised()) && (op != NULL)) { op->execute(); } ErrorRaised(); UpdateStack(); } void InsertChar(CtlRecHndl entryBox, char ch) { LERecHndl leHandle; HLock((Handle)entryBox); leHandle = (LERecHndl)(*entryBox)->ctlData; HUnlock((Handle)entryBox); LEDelete(leHandle); LEInsert(&ch, 1, leHandle); } void ExecMinusButton(void) { int i; char aChar; BOOLEAN doCmd = FALSE; BOOLEAN dotSeen = FALSE; CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); GetLETextByID(gCalcWinPtr, abCalcEntryBox, &gStrBuf); if (gStrBuf.textLength > 0) { doCmd = TRUE; gStrBuf.text[gStrBuf.textLength] = '\0'; aChar = gStrBuf.text[gStrBuf.textLength - 1]; if (((aChar == 'e') || (aChar == 'E')) && (gStrBuf.textLength > 1)) { doCmd = FALSE; for (i = 0; i < gStrBuf.textLength - 1; i++) { switch (gStrBuf.text[i]) { case '-': if (i != 0) { doCmd = TRUE; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case '.': if (dotSeen) { doCmd = TRUE; } else { dotSeen = TRUE; } break; default: doCmd = TRUE; break; } if (doCmd) break; } } } if (doCmd) { ExecCalcCmd("-"); } else { InsertChar(entryBox, '-'); } return; } void HandleEntryBox(void) { Handle stackListCtl = (Handle)GetCtlHandleFromID(gCalcWinPtr, abCalcStackList); if (gSelectedStackItem != -1) { ResetMember2(stackListCtl); DrawMember2(gSelectedStackItem, stackListCtl); gSelectedStackItem = -1; } } void HandleStackClick(void) { Handle stackListCtl = (Handle)GetCtlHandleFromID(gCalcWinPtr, abCalcStackList); int nthOp; int numStackItems = abCalcStackNumItems(); int numDisplayed = numStackItems; int selectedStackItem = -1; nthOp = NextMember2(0, stackListCtl); if (nthOp == gSelectedStackItem) { ResetMember2(stackListCtl); DrawMember2(gSelectedStackItem, stackListCtl); gSelectedStackItem = -1; nthOp = NextMember2(0, stackListCtl); } if (nthOp == 0) return; if (numDisplayed < MIN_STACK_ITEMS) numDisplayed = MIN_STACK_ITEMS; selectedStackItem = numDisplayed + 1 - nthOp; if (selectedStackItem > numStackItems) { ResetMember2(stackListCtl); DrawMember2(nthOp, stackListCtl); gSelectedStackItem = -1; } else { gSelectedStackItem = nthOp; } } void HandleOpClick(void) { Handle opListCtl = (Handle)GetCtlHandleFromID(gCalcWinPtr, abCalcOpList); int nthOp = ResetMember2(opListCtl); abCalcOp *op; if (nthOp > 0) { nthOp--; op = abCalcOpNth(nthOp); if (op != NULL) { CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); PushCalcEntry(entryBox); if (!ErrorRaised()) { op->execute(); } ErrorRaised(); UpdateStack(); } DrawMember2(nthOp + 1, opListCtl); } } void HandleControl(EventRecord *event) { CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); SetPort(gCalcWinPtr); switch (event->wmTaskData4) { case abCalcBtn0: InsertChar(entryBox, '0'); break; case abCalcBtn1: InsertChar(entryBox, '1'); break; case abCalcBtn2: InsertChar(entryBox, '2'); break; case abCalcBtn3: InsertChar(entryBox, '3'); break; case abCalcBtn4: InsertChar(entryBox, '4'); break; case abCalcBtn5: InsertChar(entryBox, '5'); break; case abCalcBtn6: InsertChar(entryBox, '6'); break; case abCalcBtn7: InsertChar(entryBox, '7'); break; case abCalcBtn8: InsertChar(entryBox, '8'); break; case abCalcBtn9: InsertChar(entryBox, '9'); break; case abCalcBtnEnter: PushCalcEntry(entryBox); ErrorRaised(); UpdateStack(); break; case abCalcBtnDot: InsertChar(entryBox, '.'); break; case abCalcBtnNum: InsertChar(entryBox, '#'); break; case abCalcBtnAdd: ExecCalcCmd("+"); break; case abCalcBtnSub: ExecMinusButton(); break; case abCalcBtnMult: ExecCalcCmd("*"); break; case abCalcBtnDiv: ExecCalcCmd("/"); break; case abCalcBtnPow: ExecCalcCmd("^"); break; case abCalcBtnA: InsertChar(entryBox, 'A'); break; case abCalcBtnB: InsertChar(entryBox, 'B'); break; case abCalcBtnC: InsertChar(entryBox, 'C'); break; case abCalcBtnD: InsertChar(entryBox, 'D'); break; case abCalcBtnE: InsertChar(entryBox, 'E'); break; case abCalcBtnF: InsertChar(entryBox, 'F'); break; case abCalcEntryBox: HandleEntryBox(); break; case abCalcStackList: HandleStackClick(); break; case abCalcOpList: HandleOpClick(); break; } } void DoCut(void) { LERecHndl leHandle; CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); HLock((Handle)entryBox); leHandle = (LERecHndl)(*entryBox)->ctlData; HUnlock((Handle)entryBox); LECut(leHandle); LEToScrap(); } void DoCopy(void) { Handle stackListCtl = (Handle)GetCtlHandleFromID(gCalcWinPtr, abCalcStackList); LERecHndl leHandle; CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); int numStackItems = abCalcStackNumItems(); int numDisplayed = numStackItems; int selectedStackItem; if (gSelectedStackItem == -1) { HLock((Handle)entryBox); leHandle = (LERecHndl)(*entryBox)->ctlData; HUnlock((Handle)entryBox); LECopy(leHandle); LEToScrap(); return; } if (numDisplayed < MIN_STACK_ITEMS) numDisplayed = MIN_STACK_ITEMS; selectedStackItem = numDisplayed - gSelectedStackItem; if (gBuffer == NULL) { gBuffer = malloc(AB_CALC_EXPR_STRING_MAX); } if ((selectedStackItem >= 0) && (selectedStackItem < numStackItems) && (abCalcStackExprStringAt(selectedStackItem, gBuffer, FALSE) != NULL)) { ZeroScrap(); PutScrap(strlen(gBuffer), textScrap, gBuffer); } SetPort(gCalcWinPtr); ResetMember2(stackListCtl); DrawMember2(gSelectedStackItem, stackListCtl); gSelectedStackItem = -1; } void DoPaste(void) { LERecHndl leHandle; CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); HLock((Handle)entryBox); leHandle = (LERecHndl)(*entryBox)->ctlData; HUnlock((Handle)entryBox); LEFromScrap(); LEPaste(leHandle); } void DoClear(void) { LERecHndl leHandle; CtlRecHndl entryBox = GetCtlHandleFromID(gCalcWinPtr, abCalcEntryBox); HLock((Handle)entryBox); leHandle = (LERecHndl)(*entryBox)->ctlData; HUnlock((Handle)entryBox); LEDelete(leHandle); } void HandleMenu(int menuItem) { SetPort(gCalcWinPtr); switch (menuItem) { case cutAction: DoCut(); break; case copyAction: DoCopy(); break; case pasteAction: DoPaste(); break; case clearAction: DoClear(); break; default: break; } } void HandleKey(EventRecord *event) { BOOLEAN appleKeyPressed = ((event->modifiers & appleKey) != 0); char key = (event->message & 0xff); if (!appleKeyPressed) return; switch (key) { case 'C': case 'c': DoCopy(); break; case 'X': case 'x': DoCut(); break; case 'V': case 'v': DoPaste(); break; } } BOOLEAN NDAAction(EventRecord *sysEvent, int code) { int event; static EventRecord localEvent; unsigned int eventCode; BOOLEAN result = FALSE; switch (code) { case runAction: return result; case eventAction: BlockMove((Pointer)sysEvent, (Pointer)&localEvent, 16); localEvent.wmTaskMask = 0x001FFFFF; eventCode = TaskMasterDA(0, &localEvent); switch(eventCode) { case updateEvt: BeginUpdate(gCalcWinPtr); DrawContents(); EndUpdate(gCalcWinPtr); break; case wInControl: HandleControl(&localEvent); break; case keyDownEvt: case autoKeyEvt: HandleKey(&localEvent); break; } break; case cutAction: case copyAction: case pasteAction: case clearAction: result = TRUE; HandleMenu(code); break; } return result; }