/* -*- coding: utf-8 -*- */ /***************************************************************************** * * Rattail -- Retail Software Framework * Copyright © 2010-2013 Lance Edgar * * This file is part of Rattail. * * Rattail is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * Rattail is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for * more details. * * You should have received a copy of the GNU Affero General Public License * along with Rattail. If not, see . * *****************************************************************************/ /************************************************************ * Palm Includes ************************************************************/ #include /************************************************************ * Scanner Includes ************************************************************/ #ifdef SCANLIB_BCS2 #include "BCS2ScannerLib.h" #endif #ifdef SCANLIB_JANAM #include "JanamScnCompatible.h" #include "ScanMgr.h" #endif #ifdef SCANLIB_SYMBOL #include "Symbol/ScanMgrDef.h" #include "Symbol/ScanMgrStruct.h" #include "Symbol/ScanMgr.h" #endif /************************************************************ * Rattail Includes ************************************************************/ #include "AppResources.h" /* #include "AppMain.h" */ /************************************************************ * Palm App Constants ************************************************************/ #define appFileCreator 'RTTL' #define appVersionNum 0x01 #define appPrefID 0x00 #define appPrefVersionNum 0x01 /************************************************************ * Rattail App Constants ************************************************************/ #define appDbRattail "Rattail" #define dbScanRecords "Rattail_Scan" /* UInt16 cardNo = 0; */ #define cardNumber 0 #define COLUMN_BARCODE 0 #define COLUMN_CASES 1 #define COLUMN_UNITS 2 /************************************************************ * Scanner App Variables ************************************************************/ #ifdef SCANLIB_BCS2 UInt16 gBcs2RefNum = 0; #endif #ifdef SCANLIB_JANAM Boolean gBabbo = false; #endif #ifdef SCANLIB_SYMBOL // These are used for the data coming from the scanner. /* MemHandle hScanData; */ /* UInt8* pScanData; */ /* Int16 scanDataLength; */ #endif /************************************************************ * Rattail App Variables ************************************************************/ //UInt16 gNumCols = 3; //UInt16 gNumRows = 11; //MemHandle gHandles[11][3]; Int16 gTopVisibleRecord = -1; // This handle serves the barcode field. /* MemHandle hBarcode; */ // This string is used for the barcode field. /* Char gBarcodeText[15] = ""; */ // These track whether we have a working scanner, and whether it is currently // enabled. Boolean bHaveScanner = false; // This stores the resource ID of the selector trigger associated with the // quantity currently being edited with the Quantity Form. Its value will be // either MainFormCases or MainFormUnits. UInt16 gQuantityTriggerID; // This tracks whether the quantity form was initiated by the user manually // selecting a trigger, i.e. versus being auto-initiated by the scanning // workflow. Boolean gQuantityManual; // These buffers hold the current quantities as text. Char gCaseQuantity[4]; Char gUnitQuantity[4]; // This pointer refers to the quantity currently being edited. Char* gQuantity; // This tracks whether the quantity shown is the initial/original value, or // whether it has already been touched in some way. This is used to control // the behavior of the first number button pressed. Boolean gQuantityTouched; /************************************************************ * Type Definitions ************************************************************/ typedef struct { Char barcode[15]; Char cases[4]; Char units[4]; } RatScanDbRecord; /************************************************************ * Function Declarations ************************************************************/ // Application static Err AppStart(); static void AppEventLoop(); static void AppStop(); static Boolean AppHandleEvent(EventPtr event); // Database static DmOpenRef CreateScanDatabase(); static DmOpenRef OpenScanDatabase(); // Scanner static void EnableScanner(Boolean enable); // Main Form static Boolean MainFormHandleEvent(EventPtr event); static void MainFormInit(FormPtr form); static Boolean MainFormDoCommand(UInt16 command); // Main Form Table static void MainFormLoadTable(TablePtr table, Boolean updateScroll); static void DrawCustomTableItem(void* table, Int16 row, Int16 col, RectangleType* bounds); static void FocusBarcode(); #ifdef SCANLIB_SYMBOL static void FetchScanData(); #endif static void ProcessScan(); static void StoreScanData(); static Boolean IsChecked(FormPtr form, UInt16 controlID); static void ShowQuantityForm(UInt16 triggerID, Boolean manual); // Quantity Form static Boolean QuantityFormHandleEvent(EventPtr event); static void QuantityFormInit(FormPtr form); static void AppendQuantityDigit(UInt16 digit); static void UpdateQuantityDisplay(); static void QuantityFormAccept(); // Scanner-Specific #ifdef SCANLIB_BCS2 static Boolean OpenBCS2Scanner(); static void CloseBCS2Scanner(); #endif /************************************************************ * * FUNCTION: PilotMain * ************************************************************/ UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags) { Err error = errNone; #ifdef SCANLIB_BCS2 SysNotifyParamType* notifyParams = (SysNotifyParamType*) cmdPBP; Char * scancode; FormPtr form; FieldPtr barcode; MemHandle barcodeH; MemPtr barcodeP; #endif switch (cmd) { case sysAppLaunchCmdNormalLaunch: if ((error = AppStart()) == 0) { AppEventLoop(); AppStop(); } break; #ifdef SCANLIB_BCS2 case sysAppLaunchCmdNotify: if (notifyParams->notifyType == BCS2BarCodeReadyNotification) { // Get pointer to scanned data. scancode = (Char*) notifyParams->notifyDetailsP + 1; // Verify we got a good read from the scanner. if (StrCompareAscii(scancode, "NO READ") == 0) { SndPlaySystemSound(sndWarning); } else { SndPlaySystemSound(sndConfirmation); form = FrmGetFormPtr(MainForm); barcode = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormBarcode)); barcodeH = FldGetTextHandle(barcode); FldSetTextHandle(barcode, NULL); if (! barcodeH) { barcodeH = MemHandleNew(15); // ugh } barcodeP = MemHandleLock(barcodeH); StrCopy((Char*) barcodeP, scancode); MemHandleUnlock(barcodeH); FldSetTextHandle(barcode, barcodeH); FldDrawField(barcode); ProcessScan(); } } break; #endif default: break; } return error; } /************************************************************ * * FUNCTION: AppStart * ************************************************************/ static Err AppStart() { #ifdef SCANLIB_BCS2 OpenBCS2Scanner(); #endif #ifdef SCANLIB_JANAM //OpenBabboScanner(); #endif #ifdef SCANLIB_SYMBOL if (ScanOpenDecoder() == STATUS_OK) { bHaveScanner = true; } else { FrmAlert(AlertScannerOpenError); } #endif EnableScanner(false); // Initialize the barcode memory handle; needs 14 characters. /* hBarcode = MemHandleNew(15); */ FrmGotoForm(MainForm); return errNone; } /************************************************************ * * FUNCTION: AppStop * ************************************************************/ static void AppStop() { EnableScanner(false); #ifdef SCANLIB_BCS2 CloseBCS2Scanner(); #endif #ifdef SCANLIB_JANAM if (bHaveScanner) { ScnCloseDecoder(); } #endif #ifdef SCANLIB_SYMBOL if (bHaveScanner) { if (ScanCloseDecoder() != 0) { FrmAlert(AlertScannerCloseError); } } #endif /* if (hBarcode) { */ /* MemHandleFree(hBarcode); */ /* } */ FrmCloseAllForms(); } /************************************************************ * * FUNCTION: AppEventLoop * ************************************************************/ static void AppEventLoop() { Err error; EventType event; Boolean defaultSysHandler; do { EvtGetEvent(&event, evtWaitForever); defaultSysHandler = true; #ifdef SCANLIB_BCS2 // The "center" hardware key on Aceeca Meazura devices normally is // handled by the default system handler. But we want to use it to // trigger the scanner, so we must bypass the system handler and let // the event bubble up to the application handler instead. This is // possibly very bad form, but as of this writing I'm not sure how else // to accomplish using that button for a trigger. if (gBcs2RefNum && (event.eType == keyDownEvent) && (event.data.keyDown.chr == MzVCentreKey)) { defaultSysHandler = false; } #endif if (defaultSysHandler && SysHandleEvent(&event)) continue; if (MenuHandleEvent(0, &event, &error)) continue; if (AppHandleEvent(&event)) continue; FrmDispatchEvent(&event); } while (event.eType != appStopEvent); } /************************************************************ * * FUNCTION: AppHandleEvent * ************************************************************/ static Boolean AppHandleEvent(EventPtr event) { UInt16 formID; FormPtr form; Boolean handled = false; if (event->eType == frmLoadEvent) { // Load the form resource. formID = event->data.frmLoad.formID; form = FrmInitForm(formID); FrmSetActiveForm(form); // Set the event handler for the form. switch (formID) { case MainForm: FrmSetEventHandler(form, MainFormHandleEvent); break; case QuantityForm: FrmSetEventHandler(form, QuantityFormHandleEvent); break; default: break; } handled = true; } return handled; } /************************************************************ * * FUNCTION: MainFormHandleEvent * ************************************************************/ static Boolean MainFormHandleEvent(EventPtr event) { Boolean handled = false; FormPtr form; TablePtr table; //UInt16 objId; form = FrmGetFormPtr(MainForm); switch (event->eType) { case frmOpenEvent: MainFormInit(form); FrmDrawForm(form); handled = true; break; case menuEvent: handled = MainFormDoCommand(event->data.menu.itemID); break; #ifdef SCANLIB_SYMBOLY /* case fldEnterEvent: */ /* if (event->data.fldEnter.fieldID == MainFormBarcode) { */ /* ScanCmdScanEnable(); */ /* } */ /* break; */ /* case tblEnterEvent: */ /* if (event->data.tblEnter.tableID == MainFormScanRecords) { */ /* FrmAlert(1000); */ /* ScanCmdScanDisable(); */ /* } */ /* break; */ case scanDecodeEvent: FetchScanData(); /* ProcessScan(); */ handled = true; break; #endif case sclRepeatEvent: if (event->data.sclRepeat.newValue > event->data.sclRepeat.value) gTopVisibleRecord += (event->data.sclRepeat.newValue - event->data.sclRepeat.value); else { gTopVisibleRecord -= (event->data.sclRepeat.value - event->data.sclRepeat.newValue); } table = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormScanRecords)); MainFormLoadTable(table, false); TblRedrawTable(table); break; case keyDownEvent: if (event->data.keyDown.chr == chrLineFeed) { // We only have one field (barcode) on the main form. If it's // active then we can operate on the ENTER key. if (FrmGetActiveField(form)) { ProcessScan(); handled = true; } #ifdef SCANLIB_BCS2 } else if (event->data.keyDown.chr == MzVCentreKey) { // On Meazura devices, the "center" hardware key is our scan // trigger. But we'll only trigger the scanner if the barcode // field has focus. if (gBcs2RefNum && (FrmGetFocus(form) == FrmGetObjectIndex(form, MainFormBarcode))) { BCS2LibTriggerOn(gBcs2RefNum); } handled = true; #endif } /* // Pressing the ENTER (line feed) key will either advance focus */ /* // to the next quantity field marked to be stopped upon, or else */ /* // will validate and store the current data as a new scan record. */ /* if (event->data.keyDown.chr == chrLineFeed) { */ /* objId = GetActiveFieldId(form); */ /* if (objId == MainFormBarcode) { */ /* ProcessScan(); */ /* /\* */ /* } else if (objId == MainFormCases) { */ /* if (GetCheckedValue(MainFormStopOnUnits)) { */ /* SetFieldFocus(MainFormUnits); */ /* } else { */ /* StoreScanData(); */ /* } */ /* *\/ */ /* } else if (objId == MainFormUnits) { */ /* StoreScanData(); */ /* } */ /* // Until I have more to go on, I'm assuming that if a handheld has */ /* // a BCS2-capable scanner, then it is an Aceeca Meazura, and that its */ /* // "center" navigational (hardware) key should be used as the scan */ /* // trigger. */ /* } else if (event->data.keyDown.chr == MzVCentreKey) { */ /* if (gBcs2RefNum) { */ /* if (FrmGetFocus(form) == FrmGetObjectIndex(form, MainFormBarcode)) */ /* BCS2LibTriggerOn(gBcs2RefNum); */ /* } */ /* /\* */ /* // Handle Babbo key */ /* } else if ((event->data.keyDown.chr & vchrScanKey && */ /* (event->data.keyDown.keyCode == scanBitHard1)) || */ /* ((event->data.keyDown.chr & vchrScanKey) && */ /* (event->data.keyDown.keyCode == scanBitHard2))) { */ /* if (gBabbo) { */ /* if (ScnCmdStartDecode() != STATUS_OK) { */ /* SysFatalAlert("Start decode failed!"); */ /* } */ /* handled = true; */ /* } */ /* *\/ */ /* } */ break; /* // This event is passed by Babbo scanners (Janam handhelds). case scanDecodeEvent: if (gBabbo) { // just to be sure? if (ScnCmdBeep(One_Short_Low) != STATUS_OK) { SysFatalAlert("Beep failed!"); } } break; */ case ctlSelectEvent: switch (event->data.ctlSelect.controlID) { case MainFormCases: /* EnableScanner(false); */ ShowQuantityForm(MainFormCases, true); handled = true; break; case MainFormUnits: /* EnableScanner(false); */ ShowQuantityForm(MainFormUnits, true); handled = true; break; default: break; } break; default: break; } return handled; } /************************************************************ * * FUNCTION: MainFormInit * ************************************************************/ static void MainFormInit(FormPtr form) { TablePtr table; Int16 cols, col, rows, row; table = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormScanRecords)); TblHasScrollBar(table, true); cols = TblGetNumberOfColumns(table); rows = TblGetNumberOfRows(table); for (col = 0; col < cols; col++) { TblSetCustomDrawProcedure(table, col, DrawCustomTableItem); TblSetColumnUsable(table, col, true); for (row = 0; row < rows; row++) { TblSetItemStyle(table, row, col, customTableItem); TblSetRowUsable(table, row, false); } } MainFormLoadTable(table, true); TblRedrawTable(table); // Set initial quantity values. CtlSetLabel(FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormCases)), "0"); CtlSetLabel(FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormUnits)), "1"); // Only stop on unit quantity by default. CtlSetValue(FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormStopOnUnits)), 1); FocusBarcode(); } /************************************************************ * * FUNCTION: MainFormDoCommand * ************************************************************/ static Boolean MainFormDoCommand(UInt16 command) { Boolean handled = false; FormPtr form; switch (command) { case MainOptionsAboutStarterApp: form = FrmInitForm(AboutForm); FrmDoDialog(form); FrmDeleteForm(form); handled = true; break; } return handled; } /************************************************************ * * FUNCTION: DrawCustomTableItem * ************************************************************/ static void DrawCustomTableItem(void* table, Int16 row, Int16 col, RectangleType* bounds) { Char * text; UInt16 size; Coord x; text = (Char *) TblGetItemPtr(table, row, col); if (*text != 0) { size = StrLen(text); if (col == 0) { // barcode WinDrawChars(text, size, bounds->topLeft.x, bounds->topLeft.y); } else { // cases or units // Only draw value if nonzero. if (StrCompareAscii(text, "0") != 0) { // Draw value right-aligned. x = bounds->topLeft.x + bounds->extent.x - FntCharsWidth(text, size); WinDrawChars(text, size, x, bounds->topLeft.y); } } } } /************************************************************ * * FUNCTION: MainFormLoadTable * ************************************************************/ static void MainFormLoadTable(TablePtr table, Boolean updateScroll) { DmOpenRef db; UInt16 numRecords; MemHandle recordH; RatScanDbRecord* recordP; UInt16 rows, row, rowId; FormPtr form; ScrollBarPtr scroll; db = OpenScanDatabase(); if (db == NULL) return; numRecords = DmNumRecords(db); rows = (numRecords < 12) ? numRecords : 12; if (gTopVisibleRecord < 0) gTopVisibleRecord = (numRecords > 12) ? (numRecords - 12) : 0; for (row = 0; row < rows; row++) { rowId = gTopVisibleRecord + row; recordH = DmGetRecord(db, rowId); recordP = (MemPtr) MemHandleLock(recordH); TblSetItemPtr(table, row, 0, &recordP->barcode); if (StrCompareAscii(recordP->cases, "0") != 0) { TblSetItemPtr(table, row, 1, &recordP->cases); } else { TblSetItemPtr(table, row, 1, ""); } if (StrCompareAscii(recordP->units, "0") != 0) { TblSetItemPtr(table, row, 2, &recordP->units); } else { TblSetItemPtr(table, row, 2, ""); } MemHandleUnlock(recordH); DmReleaseRecord(db, rowId, false); TblSetRowID(table, row, rowId); TblSetRowUsable(table, row, true); } DmCloseDatabase(db); TblMarkTableInvalid(table); if (updateScroll) { form = FrmGetFormPtr(MainForm); scroll = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormScroller)); if (numRecords <= 12) { SclSetScrollBar(scroll, 0, 0, 0, 0); } else { SclSetScrollBar(scroll, gTopVisibleRecord, 0, numRecords - 12, 11); } } } /************************************************************ * * FUNCTION: OpenScanDatabase * ************************************************************/ static DmOpenRef OpenScanDatabase() { LocalID dbID; DmOpenRef db; dbID = DmFindDatabase(cardNumber, dbScanRecords); if (dbID == 0) { return CreateScanDatabase(); } db = DmOpenDatabase(cardNumber, dbID, dmModeWrite); if (db == 0) { return NULL; } return db; } #ifdef SCANLIB_BCS2 /************************************************************ * * FUNCTION: CloseBCS2Scanner * ************************************************************/ static void CloseBCS2Scanner() { LocalID dbId; if (! gBcs2RefNum) { return; } dbId = DmFindDatabase(cardNumber, appDbRattail); if (dbId) { SysNotifyUnregister(cardNumber, dbId, BCS2BarCodeReadyNotification, sysNotifyNormalPriority); } BCS2LibClose(gBcs2RefNum); SysLibRemove(gBcs2RefNum); gBcs2RefNum = 0; } #endif /************************************************************ * * FUNCTION: CreateScanDatabase * ************************************************************/ static DmOpenRef CreateScanDatabase() { Err err; LocalID dbID; UInt16 attrs, version; DmOpenRef db; err = DmCreateDatabase(cardNumber, dbScanRecords, appFileCreator, 'SCAN', false); if (err != errNone) return NULL; dbID = DmFindDatabase(cardNumber, dbScanRecords); if (dbID == 0) return NULL; // Set backup flag, version for database. attrs = dmHdrAttrBackup; version = 1; DmSetDatabaseInfo(cardNumber, dbID, NULL, &attrs, &version, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); db = DmOpenDatabase(cardNumber, dbID, dmModeWrite); if (db == 0) return NULL; return db; } /************************************************************ * * FUNCTION: IsChecked * ************************************************************/ static Boolean IsChecked(FormPtr form, UInt16 controlID) { return (Boolean) CtlGetValue(FrmGetObjectPtr(form, FrmGetObjectIndex(form, controlID))); } /************************************************************ * * FUNCTION: GetObjectPtr * ************************************************************/ /* static void *GetObjectPtr(UInt16 objectID) */ /* { */ /* FormPtr form; */ /* form = FrmGetActiveForm(); */ /* return FrmGetObjectPtr(form, FrmGetObjectIndex(form, objectID)); */ /* } */ /************************************************************ * * FUNCTION: FocusBarcode * ************************************************************/ static void FocusBarcode() { FormPtr form; UInt16 index; FieldPtr field; form = FrmGetFormPtr(MainForm); index = FrmGetObjectIndex(form, MainFormBarcode); field = FrmGetObjectPtr(form, index); FldSetSelection(field, 0, FldGetTextLength(field)); FrmSetFocus(form, index); EnableScanner(true); } /************************************************************ * * FUNCTION: EnableScanner * ************************************************************/ static void EnableScanner(Boolean enable) { #ifdef SCANLIB_SYMBOL if (bHaveScanner) { if (enable) { if (ScanGetScanEnabled() == 0) { if (ScanCmdScanEnable() != STATUS_OK) { FrmAlert(AlertScannerEnableError); } } } else { if (ScanGetScanEnabled() != 0) { ScanCmdScanDisable(); } } } #endif } #ifdef SCANLIB_SYMBOL /************************************************************ * * FUNCTION: FetchScanData * ************************************************************/ static void FetchScanData() { FormPtr form; FieldPtr field; #ifdef SCANLIB_SYMBOLY /* MESSAGE msg; */ /* MemPtr pBarcode; */ #endif form = FrmGetFormPtr(MainForm); field = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormBarcode)); #ifdef SCANLIB_SYMBOLY /* ScanGetDecodedData(&msg); */ /* scanDataLength = decodeDataMsg.length; */ /* hScanData = MemHandleNew(scanDataLength + 1); */ /* pScanData = (UInt8*) MemHandleLock(hScanData); */ /* MemMove(&pScanData[0], &decodeDataMsg.data[0], scanDataLength + 1); */ /* FldSetTextHandle(field, hScanData); */ /* FldDrawField(field); */ /* MemHandleUnlock(hScanData); */ /* MemHandleFree(hScanData); */ /* hBarcode = FldGetTextHandle(field); */ /* if (! hBarcode) { */ /* hBarcode = MemHandleNew(15); */ /* } else { */ /* FldSetTextHandle(field, NULL); */ /* } */ /* pBarcode = (UInt8*) MemHandleLock(hBarcode); */ /* MemMove(&pBarcode[0], &msg.data[0], msg.length + 1); */ /* MemHandleUnlock(hBarcode); */ /* FldSetTextHandle(field, hBarcode); */ /* FldDrawField(field); */ /* FldSetTextHandle(field, NULL); */ /* StrCopy(gBarcodeText, msg.data); */ /* FldSetTextHandle(field, gBarcodeText); */ /* FldDrawField(field); */ /* FldSetTextHandle(field, NULL); */ /* pBarcode = MemHandleLock(hBarcode); */ /* MemMove(pBarcode, msg.data, msg.length + 1); */ /* MemHandleUnlock(hBarcode); */ /* FldSetTextHandle(field, hBarcode); */ /* FldDrawField(field); */ #endif } #endif /************************************************************ * * FUNCTION: ProcessScan * ************************************************************/ static void ProcessScan() { FormPtr form; form = FrmGetFormPtr(MainForm); if (IsChecked(form, MainFormStopOnCases)) { ShowQuantityForm(MainFormCases, false); } else if (IsChecked(form, MainFormStopOnUnits)) { ShowQuantityForm(MainFormUnits, false); } else { StoreScanData(); } } /************************************************************ * * FUNCTION: StoreScanData * ************************************************************/ static void StoreScanData() { FormPtr form; FieldPtr barcode; ControlPtr cases, units; /* Char* quantity; */ UInt32 size, offset; DmOpenRef db; UInt16 recordIndex; MemHandle recordH; MemPtr recordP; TablePtr table; UInt16 row; // Get form and barcode field pointers. form = FrmGetFormPtr(MainForm); barcode = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormBarcode)); // Set focus to barcode field if empty. if (FldGetTextLength(barcode) == 0) { FocusBarcode(); return; } // Get case and unit field pointers. cases = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormCases)); units = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormUnits)); // Open the database and create a new record. db = OpenScanDatabase(); if (db == NULL) { return; } recordIndex = dmMaxRecordIndex; recordH = DmNewRecord(db, &recordIndex, sizeof(RatScanDbRecord)); if (recordH == 0) { DmCloseDatabase(db); return; } // Write scan data to the record... recordP = MemHandleLock(recordH); offset = 0; size = FldGetTextLength(barcode); DmWrite(recordP, offset, FldGetTextPtr(barcode), size); offset += size; size = 15 - size; DmSet(recordP, offset, size, 0); offset += size; /* size = FldGetTextLength(cases); DmWrite(recordP, offset, FldGetTextPtr(cases), size); offset += size; */ /* size = 2; */ /* DmWrite(recordP, offset, "0", 2); */ /* offset += size; */ /* quantity = CtlGetLabel(cases); */ /* size = StrLen(quantity); */ /* DmWrite(recordP, offset, quantity, size); */ /* offset += size; */ size = StrLen(CtlGetLabel(cases)); DmWrite(recordP, offset, CtlGetLabel(cases), size); offset += size; size = 4 - size; DmSet(recordP, offset, size, 0); offset += size; /* size = FldGetTextLength(units); */ /* DmWrite(recordP, offset, FldGetTextPtr(units), size); */ /* offset += size; */ size = StrLen(CtlGetLabel(units)); DmWrite(recordP, offset, CtlGetLabel(units), size); offset += size; size = 4 - size; DmSet(recordP, offset, size, 0); // ...then close the record and database. MemHandleUnlock(recordH); DmReleaseRecord(db, recordIndex, false); DmCloseDatabase(db); // Redraw the table. table = FrmGetObjectPtr(form, FrmGetObjectIndex(form, MainFormScanRecords)); row = TblGetLastUsableRow(table); if (row == tblUnusableRow) { gTopVisibleRecord = 0; } else if (row == 11) { gTopVisibleRecord = TblGetRowID(table, 1); } MainFormLoadTable(table, true); TblRedrawTable(table); FocusBarcode(); } #ifdef SCANLIB_JANAM /************************************************************ * * FUNCTION: OpenBabboScanner * ************************************************************/ /* static Boolean OpenBabboScanner() { Err err; if (! ScnIsJanamUnit()) { SysFatalAlert("Not a Janam unit!"); return false; } err = ScnOpenDecoder(); if (err) { SysFatalAlert("Open decoder failed!"); return false; } if (ScnCmdScanEnable() != STATUS_OK) { SysFatalAlert("Enable scanner failed!"); ScnCloseDecoder(); return false; } gBabbo = true; return true; } */ #endif #ifdef SCANLIB_BCS2 /************************************************************ * * FUNCTION: OpenBCS2Scanner * ************************************************************/ static Boolean OpenBCS2Scanner() { Err err; LocalID dbId; err = SysLibLoad('libr', 'BcAp', &gBcs2RefNum); if (err) { switch (err) { case sysErrLibNotFound: SysFatalAlert("BCS2 library not found!"); break; case sysErrNoFreeRAM: SysFatalAlert("Out of memory (RAM)!"); break; case sysErrNoFreeLibSlots: SysFatalAlert("No free library slots!"); break; default: SysFatalAlert("BCS2 library load failed!"); break; } gBcs2RefNum = 0; return false; } err = BCS2LibOpen(gBcs2RefNum); if (err) { switch (err) { case errBCS2MemoryError: SysFatalAlert("BCS2 threw memory error"); break; default: SysFatalAlert("BCS2 library open failed!"); break; } SysLibRemove(gBcs2RefNum); gBcs2RefNum = 0; return false; } dbId = DmFindDatabase(cardNumber, appDbRattail); if (! dbId) { SysFatalAlert("Find database failed!"); SysLibRemove(gBcs2RefNum); gBcs2RefNum = 0; return false; } err = SysNotifyRegister(cardNumber, dbId, BCS2BarCodeReadyNotification, NULL, sysNotifyNormalPriority, NULL); if (err != errNone) { SysFatalAlert("Notify registration failed!"); SysLibRemove(gBcs2RefNum); gBcs2RefNum = 0; return false; } return true; } #endif /************************************************************ * * FUNCTION: ShowQuantityForm * ************************************************************/ static void ShowQuantityForm(UInt16 triggerID, Boolean manual) { FormPtr form; ControlPtr ctrl; // Track whether the form is being shown due to manaul user initiation, // versus automatically as part of the scanning workflow. gQuantityManual = manual; // Store quantity trigger so we know which quantity we're editing. gQuantityTriggerID = triggerID; // Update the current quantity buffer from the trigger label. gQuantity = (triggerID == MainFormCases) ? gCaseQuantity : gUnitQuantity; form = FrmGetFormPtr(MainForm); ctrl = FrmGetObjectPtr(form, FrmGetObjectIndex(form, triggerID)); StrCopy(gQuantity, CtlGetLabel(ctrl)); // The quantity has yet to be touched by the user. gQuantityTouched = false; // Load and display the quantity form. FrmPopupForm(QuantityForm); } /************************************************************ * * FUNCTION: QuantityFormHandleEvent * ************************************************************/ static Boolean QuantityFormHandleEvent(EventPtr event) { Boolean handled = false; FormPtr form; switch (event->eType) { case frmOpenEvent: form = FrmGetActiveForm(); QuantityFormInit(form); FrmDrawForm(form); handled = true; break; case ctlSelectEvent: switch (event->data.ctlSelect.controlID) { case QuantityForm1: AppendQuantityDigit(1); break; case QuantityForm2: AppendQuantityDigit(2); break; case QuantityForm3: AppendQuantityDigit(3); break; case QuantityForm4: AppendQuantityDigit(4); break; case QuantityForm5: AppendQuantityDigit(5); break; case QuantityForm6: AppendQuantityDigit(6); break; case QuantityForm7: AppendQuantityDigit(7); break; case QuantityForm8: AppendQuantityDigit(8); break; case QuantityForm9: AppendQuantityDigit(9); break; case QuantityForm0: AppendQuantityDigit(0); break; case QuantityFormClear: StrCopy(gQuantity, "0"); UpdateQuantityDisplay(); break; case QuantityFormCancel: FrmReturnToForm(MainForm); FocusBarcode(); break; case QuantityFormOK: QuantityFormAccept(); break; default: break; } handled = true; break; case keyDownEvent: switch (event->data.keyDown.chr) { case chrLineFeed: QuantityFormAccept(); handled = true; break; case chrDigitZero: AppendQuantityDigit(0); handled = true; break; case chrDigitOne: AppendQuantityDigit(1); handled = true; break; case chrDigitTwo: AppendQuantityDigit(2); handled = true; break; case chrDigitThree: AppendQuantityDigit(3); handled = true; break; case chrDigitFour: AppendQuantityDigit(4); handled = true; break; case chrDigitFive: AppendQuantityDigit(5); handled = true; break; case chrDigitSix: AppendQuantityDigit(6); handled = true; break; case chrDigitSeven: AppendQuantityDigit(7); handled = true; break; case chrDigitEight: AppendQuantityDigit(8); handled = true; break; case chrDigitNine: AppendQuantityDigit(9); handled = true; break; default: break; } break; default: break; } return handled; } /************************************************************ * * FUNCTION: QuantityFormInit * ************************************************************/ static void QuantityFormInit(FormPtr form) { // Set form title according to what is being edited. if (gQuantityTriggerID == MainFormCases) { FrmSetTitle(form, "Case Quantity"); } else if (gQuantityTriggerID == MainFormUnits) { FrmSetTitle(form, "Unit Quantity"); } // Display current quantity value. FldSetTextPtr(FrmGetObjectPtr(form, FrmGetObjectIndex(form, QuantityFormQuantity)), gQuantity); } /************************************************************ * * FUNCTION: AppendQuantityDigit * ************************************************************/ static void AppendQuantityDigit(UInt16 digit) { Char digitText[2]; if (! gQuantityTouched) { // This is the first time the quantity is being touched; replace it // outright instead of appending the digit. StrIToA(gQuantity, digit); UpdateQuantityDisplay(); gQuantityTouched = true; } else if (StrLen(gQuantity) > 2) { // The current quantity already exceeds 2 digits; issue a warning beep // instead of appending the digit. SndPlaySystemSound(sndWarning); } else if (StrCompare(gQuantity, "0") == 0) { // The current quantity is zero; replace it outright instead of // appending the digit. StrIToA(gQuantity, digit); UpdateQuantityDisplay(); } else { // Okay, we can append the digit. StrIToA(digitText, digit); StrCat(gQuantity, digitText); UpdateQuantityDisplay(); } } /************************************************************ * * FUNCTION: UpdateQuantityDisplay * ************************************************************/ static void UpdateQuantityDisplay() { FormPtr form; FieldPtr field; form = FrmGetFormPtr(QuantityForm); field = FrmGetObjectPtr(form, FrmGetObjectIndex(form, QuantityFormQuantity)); FldSetTextPtr(field, gQuantity); FldDrawField(field); } /************************************************************ * * FUNCTION: QuantityFormAccept * ************************************************************/ static void QuantityFormAccept() { FormPtr form; ControlPtr control; form = FrmGetFormPtr(MainForm); // Close the quantity form and return to the main form. FrmReturnToForm(MainForm); // Update the selector trigger label with the new quantity. control = FrmGetObjectPtr(form, FrmGetObjectIndex(form, gQuantityTriggerID)); CtlSetLabel(control, gQuantity); // If the form was shown automatically as part of the scanning workflow, // then we'll keep that workflow going... if (! gQuantityManual) { if (gQuantityTriggerID == MainFormCases) { if (IsChecked(form, MainFormStopOnUnits)) { ShowQuantityForm(MainFormUnits, false); } else { StoreScanData(); } } else if (gQuantityTriggerID == MainFormUnits) { StoreScanData(); } #ifdef SCANLIB_SYMBOLY /* } else { */ /* EnableScanner(true); */ #endif } }