home *** CD-ROM | disk | FTP | other *** search
/ linuxmafia.com 2016 / linuxmafia.com.tar / linuxmafia.com / pub / palmos / palmmetex-0.0.3.tar.gz / palmmetex-0.0.3.tar / palmmetex-0.0.3 / PMetex.c < prev    next >
C/C++ Source or Header  |  2000-04-24  |  22KB  |  977 lines

  1. /* Main code for PalmMetex */
  2. /* $Id: PMetex.c,v 1.9 1999/08/30 18:41:20 bodo Exp $ */
  3.  
  4. #include <Pilot.h>
  5. #include <SerialMgr.h>
  6. #include <SysEvtMgr.h>
  7. #include "callback.h"
  8.  
  9. #include "PMetexRsc.h"
  10.  
  11. #define DBTYPE 'Data'
  12.  
  13. #define noRecordSelected 0xffff
  14.  
  15. typedef struct {
  16.     UInt version;
  17.     ULong appID;
  18.     Int baudRate;
  19.     UChar time;  /* sec */
  20.     } rec0valT;
  21.     
  22. typedef struct {
  23.     ULong when;
  24.     Char display[14];
  25.     } recT;
  26.  
  27. /* begin globals */
  28.  
  29. Long aktList = 0;
  30. UInt nextRec = 0;
  31. Boolean running = false;
  32. UInt refNum = 0;
  33. Boolean alertOnTimeout = false;
  34. DmOpenRef myDB = 0;
  35. Char dbName[] = "PalmMetexDB";
  36. rec0valT rec0val = {
  37.     1,
  38.     APPID,
  39.     1200,
  40.     5
  41.     };
  42. Boolean logIt = true;
  43.  
  44. /**************************/
  45.  
  46. static Word CurrentRecord = noRecordSelected;
  47. static Word TopVisibleRecord = 1;
  48.  
  49. /* end globals */
  50.  
  51. VoidPtr GetObjectPtr(Int objectID)
  52. {
  53.     FormPtr pfrm;
  54.     
  55.     pfrm = FrmGetActiveForm();
  56.     return FrmGetObjectPtr(pfrm, FrmGetObjectIndex(pfrm, objectID));
  57. }
  58.  
  59. Boolean InitSerialPort(Int baudrate)
  60. {
  61.     SerSettingsType settings; 
  62.     Err retval;
  63.     
  64.     settings.baudRate   = baudrate;
  65.     settings.flags      = serSettingsFlagStopBits2 |
  66.               serSettingsFlagBitsPerChar7;
  67.     settings.ctsTimeout = serDefaultCTSTimeout;
  68.                             
  69.     retval = SysLibFind("Serial Library", &refNum);
  70.     ErrFatalDisplayIf(retval != 0, "Couln't find serial library!");
  71.  
  72.     retval = SerOpen(refNum, 0, baudrate);
  73.     if (retval != 0) {
  74.     if (retval == serErrAlreadyOpen) {
  75.         SerClose(refNum);
  76.         FrmAlert(SerialInUseAlert);
  77.     } else {
  78.         FrmAlert(CantOpenSerialAlert);
  79.     }
  80.     return 0;
  81.     }
  82.  
  83.     retval = SerSetSettings(refNum, &settings);
  84.     if (retval == serErrNotOpen)
  85.     ErrFatalDisplay("Serial port not opened!");
  86.     else if (retval == serErrBadParam)
  87.     ErrFatalDisplay("Bad serial parameters");
  88.  
  89.     return 1;
  90. }
  91.  
  92. void read_dmm(void)
  93. {
  94.     Char buf[15];
  95.     Err retval;
  96.     RectangleType r;
  97.     CustomPatternType p;
  98.     Word err;
  99.     BooleanPtr ctsOnP = NULL;
  100.     BooleanPtr dsrOnP = NULL;
  101.     VoidHand RecHandle;
  102.     Ptr RecPointer;
  103.     recT record;
  104.     
  105.     r.topLeft.x = 50;
  106.     r.topLeft.y = 100;
  107.     r.extent.x  = 140;
  108.     r.extent.y  = 10;
  109.     
  110.     p[0] = 0;
  111.     p[1] = 0;
  112.     p[2] = 0;
  113.     p[3] = 0;
  114.  
  115.     WinSetPattern(p);
  116.  
  117.     EvtResetAutoOffTimer();
  118.     
  119.     StrCopy(buf, "              ");
  120.     SerSend10(refNum, "D\n", 2);
  121.      retval = SerReceive10(refNum, buf, 14, 1 * sysTicksPerSecond);
  122.     if (retval == serErrLineErr) {
  123.     err = SerGetStatus(refNum, ctsOnP, dsrOnP);
  124.     SerClearErr(refNum);
  125.     FrmCustomAlert(SerErrAlert, StrIToA(buf, err),
  126.                                 err == 12 ? "Try disconecting RTS (Pin 4)" : " ",
  127.                                 " ");
  128.     } else {
  129.     if (retval != serErrTimeOut) {
  130.         buf[13] = '\0';
  131.         WinFillRectangle(&r, 0);
  132.         WinDrawChars(buf, 13, 50, 100);
  133.         if (logIt) {
  134.         StrNCopy(record.display, buf, sizeof(record.display));
  135.         record.when = TimGetSeconds();
  136.         RecHandle = DmNewRecord(myDB, &nextRec, sizeof(record));
  137.         RecPointer = MemHandleLock(RecHandle);
  138.         DmWrite(RecPointer, 0, &record, sizeof(record));
  139.         MemPtrUnlock(RecPointer);
  140.         DmReleaseRecord(myDB, nextRec, true);
  141.         nextRec++;
  142.         }
  143.     } else {
  144.         if (alertOnTimeout)
  145.         FrmAlert(TimeoutAlert);
  146.     }
  147.     }
  148. }
  149.  
  150. Boolean doitall(void)
  151. {
  152.     if (!running) /* paranoia checking */
  153.     return false;
  154.  
  155.     if (InitSerialPort(rec0val.baudRate)) {
  156.     read_dmm();
  157.     SerClose(refNum);
  158.     return true;
  159.     }
  160.     return false;
  161. }
  162.  
  163. static int findBaudSelectionByValue(long value)
  164. {
  165.     switch(value) {
  166.     case  300: return 0; break;
  167.     case  600: return 1; break;
  168.     case 1200: return 2; break;
  169.     case 9600: return 3; break;
  170.     default  : return 4; break;
  171.     }
  172. }
  173.  
  174. static int findTimeSelectionByValue(long value)
  175. {
  176.     switch(value) {
  177.     case  1: return 0; break;
  178.     case  2: return 1; break;
  179.     case  5: return 2; break;
  180.     case 10: return 3; break;
  181.     default: return 4; break;
  182.     }
  183. }
  184.  
  185. static void ClearLog(void)
  186. {
  187.     Err err;
  188.     UInt numRecords;
  189.     
  190.     numRecords = DmNumRecords(myDB);
  191.     while(--numRecords) {
  192.     err = DmRemoveRecord(myDB, numRecords);
  193.     ErrNonFatalDisplayIf(err, "DmRemoveRecord failed");
  194. /*
  195.     if (err)
  196.         break;
  197. */
  198.     }
  199. }
  200.  
  201. static Boolean MainFormHandleEvent (EventPtr e)
  202. {
  203.     Boolean handled = false;
  204.     FormPtr frm;
  205.     Char tmpChar1[10], tmpChar2[10];
  206.     
  207.     CALLBACK_PROLOGUE
  208.  
  209.     switch (e->eType) {
  210.     case frmUpdateEvent:
  211.     CtlEraseControl(GetObjectPtr(e->data.frmUpdate.updateCode));
  212.     if (e->data.frmUpdate.updateCode == lList) {
  213.         LstSetSelection(GetObjectPtr(lList), findBaudSelectionByValue(rec0val.baudRate));
  214.         CtlSetLabel(GetObjectPtr(bList), StrIToA(tmpChar1, rec0val.baudRate));
  215.     } else { /* e->data.frmUpdate.updateCode == lTime */
  216.         LstSetSelection(GetObjectPtr(lTime), findTimeSelectionByValue(rec0val.time));
  217.         CtlSetLabel(GetObjectPtr(bTime), StrIToA(tmpChar2, rec0val.time));
  218.     }
  219.     CtlDrawControl(GetObjectPtr(e->data.frmUpdate.updateCode));
  220.     handled = true;
  221.     break;
  222.     
  223.     case frmOpenEvent:
  224.     frm = FrmGetActiveForm();
  225.     
  226.     LstSetSelection(GetObjectPtr(lList), findBaudSelectionByValue(rec0val.baudRate));
  227.     LstSetSelection(GetObjectPtr(lTime), findTimeSelectionByValue(rec0val.time));
  228.     
  229.     CtlSetLabel(GetObjectPtr(bList), StrIToA(tmpChar1, rec0val.baudRate));
  230.     CtlSetLabel(GetObjectPtr(bTime), StrIToA(tmpChar2, rec0val.time));
  231.     
  232.     FrmDrawForm(frm);
  233.     handled = true;
  234.     break;
  235.  
  236.     case menuEvent:
  237.     MenuEraseStatus(NULL);
  238.     switch(e->data.menu.itemID) {
  239. /*
  240.     case mAbout:
  241.         FrmAlert(AboutAlert);
  242.         break;
  243. */
  244.     case mViewLog:
  245.         FrmPopupForm(ViewLogForm);
  246.         break;
  247.  
  248.     case mClearLog:
  249.         if (FrmAlert(ClearLogAlert) == 0)
  250.         ClearLog();
  251.         break;
  252.     }
  253.  
  254.         handled = true;
  255.     break;
  256.  
  257.     case ctlSelectEvent:
  258.     switch(e->data.ctlSelect.controlID) {
  259.         case bStart:
  260.         if (running) {
  261.             CtlSetLabel(GetObjectPtr(bStart), "Start");
  262.             CtlSetEnabled(GetObjectPtr(cLog), true);
  263.             CtlSetEnabled(GetObjectPtr(bList), true);
  264.             CtlSetEnabled(GetObjectPtr(bTime), true);
  265.             running = false;
  266.         }
  267.         else { /* not runing */
  268.             CtlSetEnabled(GetObjectPtr(bTime), false);
  269.             CtlSetEnabled(GetObjectPtr(bList), false);
  270.             CtlSetEnabled(GetObjectPtr(cLog), false);
  271.             CtlSetLabel(GetObjectPtr(bStart), "Stop");
  272.             running = true;
  273.             doitall();
  274.         }
  275.         handled = true;
  276.         break;
  277.         case cLog:
  278.         logIt = CtlGetValue(GetObjectPtr(cLog));
  279.         break;
  280.     }
  281.     break;
  282.  
  283.     case popSelectEvent:
  284.         aktList = e->data.popSelect.listID;
  285.  
  286.     if (e->data.popSelect.selection == 4) {
  287.         FrmPopupForm(enterValueForm);
  288.         handled = true;
  289.     } else {
  290.         CharPtr tmpList = LstGetSelectionText(GetObjectPtr(aktList),
  291.                               LstGetSelection(GetObjectPtr(aktList)));
  292.         
  293.         if (aktList == lList) {
  294.         rec0val.baudRate = StrAToI(tmpList);
  295.         } else { /* aktList == lTime */
  296.         rec0val.time = StrAToI(tmpList);
  297.         }
  298.     }
  299.     break;
  300.  
  301.     case nilEvent:
  302.     if (running) {
  303.         handled = doitall();
  304.     }
  305.     break;
  306.  
  307.     default:
  308.         break;
  309.     }
  310.  
  311.     CALLBACK_EPILOGUE
  312.  
  313.     return handled;
  314. }
  315.  
  316. static Boolean enterValueFormHandleEvent(EventPtr e)
  317. {
  318.     Boolean handled = false;
  319.     const FormPtr frm = FrmGetActiveForm();
  320.     
  321.     CALLBACK_PROLOGUE
  322.     
  323.     switch (e->eType) {
  324.     case frmOpenEvent: {
  325.     FieldPtr fld = GetObjectPtr(fenterValue);
  326.     Char tmpText[10];
  327.     
  328.     if (aktList == lList) {
  329.         StrIToA(tmpText, rec0val.baudRate);
  330.     } else { /* aktList == lTime */
  331.         StrIToA(tmpText, rec0val.time);
  332.     }
  333.     
  334.     FldInsert(fld, tmpText, StrLen(tmpText));
  335.     FrmDrawForm(frm);
  336.     FrmSetFocus(frm, FrmGetObjectIndex(frm, fenterValue));
  337.     FldSetInsertionPoint(fld, FldGetTextLength(fld));
  338.     break;
  339.     }
  340.  
  341.     case menuEvent:
  342.     MenuEraseStatus(NULL);
  343.     
  344.     switch (e->data.menu.itemID) {
  345.     }
  346.     
  347.     handled = true;
  348.     break;
  349.     
  350.     case ctlSelectEvent:
  351.     switch (e->data.ctlSelect.controlID) {
  352.     case bOK: {
  353.         FieldPtr fld = GetObjectPtr(fenterValue);
  354.         Handle textH;
  355.         CharPtr textP;
  356.         Int tmpVal;
  357.         
  358.         textH = FldGetTextHandle(fld);
  359.         if (textH) {
  360.         textP = MemHandleLock((VoidHand)(textH));
  361.         tmpVal = StrAToI(textP);
  362.         MemHandleUnlock((VoidHand)(textH));
  363.         if (aktList == lList) {
  364.             rec0val.baudRate = tmpVal;
  365.         } else { /* aktList == lTime */
  366.             rec0val.time = (Char) tmpVal;
  367.         }
  368.         }
  369.         FrmUpdateForm(MainForm, aktList);
  370.         FrmReturnToForm(MainForm);
  371.         handled = true;
  372.         break;
  373.     }
  374.     case bCancel:
  375.         FrmReturnToForm(MainForm);
  376.         handled = true;
  377.         break;
  378.     }
  379.     break;
  380.     
  381.     default:
  382.     break;
  383.     }
  384.     
  385.     CALLBACK_EPILOGUE
  386.     
  387.     return handled;
  388. }
  389.  
  390. #if 1  /* NEW TABLE CODE */ /* HIER DREHEN */
  391. static Boolean SeekRecord(UIntPtr indexP, Int offset, Int direction)
  392. {
  393.     DmSeekRecordInCategory(myDB, indexP, offset, direction, dmAllCategories);
  394.     if (DmGetLastErr())
  395.     return false;
  396.     return true;
  397. }
  398.  
  399. static Word ViewLogNumberOfRows(TablePtr table)
  400. {
  401.     Word rows;
  402.     Word rowsInTable;
  403.     Word tableHeight;
  404.     /* FontID currFont; */
  405.     RectangleType r;
  406.     
  407.     rowsInTable = TblGetNumberOfRows(table);
  408.     
  409.     TblGetBounds(table, &r);
  410.     tableHeight = r.extent.y;
  411.     
  412.     /* currFont = FntSetFont(ListFont); */
  413.     rows = tableHeight / FntLineHeight();
  414.     /* FntSetFont(currFont); */
  415.     
  416.     if (rows <= rowsInTable)
  417.     return rows;
  418.     else
  419.     return rowsInTable;
  420. }
  421.  
  422. static void ViewLogUpdateScrollers(FormPtr frm, Word bottomRecord)
  423. {
  424.     Word pos;
  425.     Word rows;
  426.     Word maxValue;
  427.     
  428.     rows = ViewLogNumberOfRows(GetObjectPtr(tLog));
  429.     if (/* numRecords */ nextRec > rows) {
  430.     pos = DmPositionInCategory(myDB, TopVisibleRecord, dmAllCategories);
  431.     maxValue = /* numRecords */ nextRec - rows;
  432.     } else {
  433.     pos = 1;
  434.     maxValue = 1;
  435.     }
  436.     
  437.     SclSetScrollBar(GetObjectPtr(sLog), pos, 1, maxValue, rows);
  438.  
  439. }
  440.  
  441. static void ViewLogLoadTable(FormPtr frm)
  442. {
  443.     Word row;
  444.     Word recordNum;
  445.     Word lineHeight;
  446.     Word dataHeight;
  447.     Word tableHeight;
  448.     Word lastRecordNum = 0;  /* shut up GCC */
  449.     Word numRows;
  450.     ULong uniqueID;
  451.     /* FontID currfont; */
  452.     TablePtr table;
  453.     VoidHand recordH;
  454.     RectangleType r;
  455.     
  456.     ErrNonFatalDisplayIf(TopVisibleRecord == 0, "TopVisibleRecord == 0");
  457.  
  458.     table = GetObjectPtr(tLog);
  459.  
  460.     TblGetBounds(table, &r);
  461.     tableHeight = r.extent.y;
  462.  
  463.     /* currFont = FntSetFont(ListFont); */
  464.     lineHeight = FntLineHeight();
  465.     /* FntSetFont(currFont) */
  466.     
  467.     dataHeight = 0;
  468.     
  469.     recordNum = TopVisibleRecord;
  470.     
  471.     numRows = TblGetNumberOfRows(table);
  472.     for (row = 0; row < numRows; row++) {
  473.     recordH = DmQueryNextInCategory(myDB, &recordNum, dmAllCategories);
  474.     
  475.     if (recordH && (tableHeight >= dataHeight + lineHeight)) {
  476.         TblSetRowID(table, row, recordNum);
  477.         TblSetItemStyle(table, row, 0, customTableItem);
  478.         /* TblSetItemFont(table, row, 0, ListFont); */
  479.         TblSetRowHeight(table, row, lineHeight);
  480.         
  481.         DmRecordInfo(myDB, recordNum, NULL, &uniqueID, NULL);
  482.         if ((TblGetRowData(table, row) != uniqueID) || ( ! TblRowUsable(table, row))) {
  483.         TblSetRowUsable(table, row, true);
  484.         
  485.         TblSetRowData(table, row, uniqueID);
  486.         
  487.         TblMarkRowInvalid(table, row);
  488.         }
  489.         
  490.         lastRecordNum = recordNum;
  491.         if (row+1 < numRows)
  492.         recordNum++;
  493.         
  494.         dataHeight += lineHeight;
  495.     } else
  496.         TblSetRowUsable(table, row, false);
  497.     }
  498.     
  499.     ViewLogUpdateScrollers(frm, lastRecordNum);
  500. }
  501.  
  502. static void ViewLogScroll(Short linesToScroll)
  503. {
  504.     Int i;
  505.     Word rows;
  506.     Word lastRow;
  507.     Word scrollAmount;
  508.     UInt newTopVisibleRecord;
  509.     TablePtr table;
  510.     RectangleType scrollR;
  511.     RectangleType vacated;
  512.     DirectionType direction;
  513.     
  514.     table = GetObjectPtr(tLog);
  515.     CurrentRecord = noRecordSelected;
  516.     
  517.     newTopVisibleRecord = TopVisibleRecord;
  518.     
  519.     if (linesToScroll > 0)
  520.     SeekRecord(&newTopVisibleRecord, linesToScroll, dmSeekForward);
  521.     else if (linesToScroll < 0)
  522.     SeekRecord(&newTopVisibleRecord, -linesToScroll, dmSeekBackward);
  523.     
  524.     ErrFatalDisplayIf(TopVisibleRecord == newTopVisibleRecord, "Invalid scroll value");
  525.     
  526.     TopVisibleRecord = newTopVisibleRecord;
  527.     
  528.     rows = ViewLogNumberOfRows(table);
  529.     if (((linesToScroll > 0) && (linesToScroll < rows)) ||
  530.         ((linesToScroll < 0) && (-linesToScroll < rows))) {
  531.     scrollAmount = 0;
  532.     
  533.     if (linesToScroll > 0) {
  534.         lastRow = TblGetLastUsableRow(table) - 1;
  535.         for (i = 0; i < linesToScroll; i++) {
  536.         scrollAmount += TblGetRowHeight(table, lastRow);
  537.         TblRemoveRow(table, 0);
  538.         }
  539.         direction = up;
  540.     } else {
  541.         for (i = 0; i < -linesToScroll; i++) {
  542.         scrollAmount += TblGetRowHeight(table, 0);
  543.         TblInsertRow(table, 0);
  544.         }
  545.         direction = down;
  546.     }
  547.     
  548.     TblGetBounds(table, &scrollR);
  549.     WinScrollRectangle(&scrollR, direction, scrollAmount, &vacated);
  550.     WinEraseRectangle(&vacated, 0);
  551.     }
  552.     ViewLogLoadTable(FrmGetActiveForm());
  553.     TblRedrawTable(table);
  554. }
  555.  
  556. static void DrawRecordData(CharPtr data, short x,short y, short width)
  557. {
  558. #if 0
  559.     Int titleLen;
  560.     Word charsToDraw;
  561.     short titleWidth;
  562.     CharPtr ptr;
  563.     Boolean stringFit;
  564.     
  565.     ptr = StrChr(data, linefeedChr);
  566.     if (ptr)
  567.     charsToDraw = (Word) (ptr - data);
  568.     else
  569.     charsToDraw = StrLen(data);
  570.     
  571.     titleWidth = width;
  572.     titleLen = charsToDraw;
  573.     FntCharsInWidth(data, &titleWidth, &titleLen, &stringFit);
  574.     
  575.     if (stringFit)
  576.     WinDrawChars(data, titleLen, x, y);
  577.     else {
  578.     width -= FntCharWidth('.') * 3;
  579.     while (titleWidth > width           ||
  580.            data[titleLen - 1] == ' ' ||
  581.            data[titleLen - 1] == tabChr)
  582.         titleWidth -= FntCharWidth(data[--titleLen]);
  583.     WinDrawChars(data, titleLen, x, y);
  584.     x += titleWidth;
  585.     WinDrawChars("...", 3, x, y);
  586.     }
  587. #else
  588.     Char line[34];
  589.     recT tmpRecord;
  590.     DateTimeType dt;
  591.  
  592.     MemMove(&tmpRecord, data, sizeof(tmpRecord));
  593.  
  594.     TimSecondsToDateTime(tmpRecord.when, &dt);
  595.     DateToAscii(dt.month, dt.day, dt.year, dfDMYWithDots, line);
  596.     StrCat(line, " ");
  597.     TimeToAscii(dt.hour, dt.minute,        tfColon24h, (line + StrLen(line)));
  598.     StrCat(line, ":");
  599.     StrIToA((line + StrLen(line)), dt.second);
  600.     if (dt.second < 10)
  601.     StrCat(line, "0");
  602.  
  603.     StrCat(line, " ");
  604.  
  605.     StrNCopy((line + StrLen(line)), tmpRecord.display, 14);
  606.     
  607.     WinDrawChars(line, StrLen(line), x, y);
  608. #endif
  609.     
  610. }
  611.  
  612. static void ViewLogDrawRecord(VoidPtr table, Word row, Word column, RectanglePtr bounds)
  613. {
  614.     Word len;
  615.     Word recordNum;
  616.     VoidHand recordH;
  617.     short x,y;
  618.     CharPtr recordP;
  619.     Word pos;
  620.     char posStr[6];
  621.     
  622.     recordNum = TblGetRowID(table, row);
  623.     
  624.     recordH = DmQueryRecord(myDB, recordNum); /* read only */
  625.     recordP = MemHandleLock(recordH);
  626.     
  627.     x = bounds->topLeft.x + 1;
  628.     y = bounds->topLeft.y;
  629.     
  630.     /* FntSetFont(ListFont); */
  631.     
  632.     pos = DmPositionInCategory(myDB, recordNum, dmAllCategories);
  633.     StrIToA(posStr, pos);
  634.     len = StrLen(posStr);
  635.     posStr[len++] = '.';
  636.     posStr[len] = '\0';
  637.     
  638.     if (len < 3)
  639.     x += FntCharWidth('1');
  640.  
  641.     WinDrawChars(posStr, len, x, y);
  642.     
  643.     x += FntCharsWidth(posStr, len) + 4;
  644.     
  645.     DrawRecordData(recordP, x, y, bounds->extent.x - x);
  646.  
  647.     MemHandleUnlock(recordH);
  648. }
  649.  
  650. static void ViewLogInit(FormPtr frm)
  651. {
  652.     TablePtr table;
  653.     Word recordNum;
  654.     Word rowsInTable;
  655.     
  656.     table = FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, tLog));
  657.     rowsInTable = ViewLogNumberOfRows(table);
  658.     
  659.     if (CurrentRecord != noRecordSelected) {
  660.     if (TopVisibleRecord > CurrentRecord)
  661.         TopVisibleRecord = CurrentRecord;
  662.     else {
  663.         recordNum = TopVisibleRecord;
  664.         DmSeekRecordInCategory(myDB, &recordNum, rowsInTable-1, dmSeekForward, dmAllCategories);
  665.         if (recordNum < CurrentRecord)
  666.         TopVisibleRecord = CurrentRecord;
  667.     }
  668.     }
  669.     
  670.     if (/* numRecords */ nextRec) {
  671.     recordNum = dmMaxRecordIndex;
  672.     DmSeekRecordInCategory(myDB, &recordNum, rowsInTable-1, dmSeekBackward, dmAllCategories);
  673.     TopVisibleRecord = min(TopVisibleRecord, recordNum);
  674.     if (!TopVisibleRecord)
  675.         TopVisibleRecord++;
  676.     } else
  677.     TopVisibleRecord = 1;
  678.  
  679.     ViewLogLoadTable(frm);
  680.  
  681.     
  682.     TblSetCustomDrawProcedure(table, 0, ViewLogDrawRecord);
  683.     TblSetColumnUsable(table, 0, true);
  684. }
  685. #else
  686. static void ViewLogInit(FormPtr frm)
  687. {
  688.     TablePtr table;
  689.     Word rowsInTable;
  690.     Word row;
  691.     Word rows;
  692.     Word visibleRows;
  693.     RectangleType r;
  694.     Word tableHeight;
  695.     VoidHand RecHandle;
  696.     Ptr RecPointer;
  697.     VoidPtr recPtr;
  698.     recT tmpRecord;
  699.     DateTimeType dt;
  700.     
  701.     table = GetObjectPtr(tLog);
  702.     rowsInTable = TblGetNumberOfRows(table);
  703.     
  704.     for (row = 0; row < rowsInTable; row++) {
  705.         TblSetItemStyle(table, row, 0, labelTableItem);
  706.         TblSetItemStyle(table, row, 1, labelTableItem);
  707.         TblSetRowUsable(table, row, false);
  708.     }
  709.     
  710.     TblSetColumnUsable(table, 0, true);
  711.     TblSetColumnUsable(table, 1, true);
  712.     /* TblSetColumnSpacing(table, 0, 20); */
  713.     
  714.     /* TblSetCustomDrawProcedure(table, column, function); */
  715.     
  716.     TblGetBounds(table, &r);
  717.     tableHeight = r.extent.y;
  718.     rows = tableHeight / FntLineHeight();
  719.     
  720.     if (rows <= rowsInTable)
  721.         visibleRows = rows;
  722.     else
  723.         visibleRows = rowsInTable;
  724.  
  725. #if 0
  726.     if (DmNumRecords(myDB)-1 < visibleRows)
  727.         visibleRows = DmNumRecords(myDB)-1;
  728. #else
  729.     if (nextRec - 1 < visibleRows)
  730.         visibleRows = nextRec - 1;
  731. #endif
  732.  
  733.     for (row = 0; row < visibleRows; row++) {
  734.         TblSetRowUsable(table, row, true);
  735.         TblMarkRowInvalid(table, row);
  736.         /* TblSetRowID(table, row, ID); */
  737.         /* TblSetItemInt(table, row, 0, -1); */
  738.         RecHandle = DmQueryRecord(myDB, row+1);
  739.         RecPointer = MemHandleLock(RecHandle);
  740.         MemMove(&tmpRecord, RecPointer, sizeof(tmpRecord));
  741.         MemPtrUnlock(RecPointer);
  742.         DmReleaseRecord(myDB, row+1, false);
  743.         
  744.         recPtr = MemPtrNew(14);
  745.         StrNCopy(recPtr, tmpRecord.display, 14);
  746.         TblSetItemPtr(table, row, 1, recPtr);
  747.         
  748.         recPtr = MemPtrNew(20);
  749.         TimSecondsToDateTime(tmpRecord.when, &dt);
  750.         DateToAscii(dt.month, dt.day, dt.year, dfDMYWithDots, recPtr);
  751.         StrCat(recPtr, " ");
  752.         TimeToAscii(dt.hour, dt.minute,        tfColon24h, (recPtr + StrLen(recPtr)));
  753.         StrCat(recPtr, ":");
  754.         StrIToA((recPtr + StrLen(recPtr)), dt.second);
  755.         if (dt.second < 10)
  756.         StrCat(recPtr, "0");
  757.         TblSetItemPtr(table, row, 0, recPtr);
  758.  
  759.     }
  760.     TblHasScrollBar(table, true);
  761.     SclSetScrollBar(GetObjectPtr(sLog), 1, 1, nextRec, 1);
  762. }
  763. #endif
  764.  
  765. static Boolean ViewLogFormHandleEvent(EventPtr e)
  766. {
  767.     Boolean handled = false;
  768.     const FormPtr frm = FrmGetActiveForm();
  769.     
  770.     CALLBACK_PROLOGUE
  771.     
  772.     switch (e->eType) {
  773.     case frmOpenEvent:
  774.     ViewLogInit(frm);
  775.     
  776.     FrmDrawForm(frm);
  777.     break;
  778.  
  779.     case menuEvent:
  780.     MenuEraseStatus(NULL);
  781.     
  782.     switch (e->data.menu.itemID) {
  783.     }
  784.     
  785.     handled = true;
  786.     break;
  787.     
  788.     case ctlSelectEvent:
  789.     switch (e->data.ctlSelect.controlID) {
  790.     case bOK: {
  791.         FrmReturnToForm(MainForm);
  792.         handled = true;
  793.         break;
  794.     }
  795.     }
  796.     break;
  797.     
  798.     case sclRepeatEvent:
  799.     ViewLogScroll(e->data.sclRepeat.newValue - e->data.sclRepeat.value);
  800.     break;
  801.  
  802.     case tblEnterEvent:
  803.     /* DisplayDetails(e); */
  804.     break;
  805.     
  806.     case tblSelectEvent:
  807. #if 0
  808.     CurrentRecord = TblGetRowID(e->data.tblSelect.pTable, e->data.tblSelect.row);
  809.     EditScrollPosition = 0;
  810.     FrmGotoForm(EditForm);
  811.     handled = true;
  812. #endif
  813.     break;
  814.  
  815.     default:
  816.     break;
  817.     }
  818.     
  819.     CALLBACK_EPILOGUE
  820.     
  821.     return handled;
  822. }
  823.  
  824. static Boolean ApplicationHandleEvent(EventPtr e)
  825. {
  826.     FormPtr frm;
  827.     Word    formId;
  828.     Boolean handled = false;
  829.  
  830.     if (e->eType == frmLoadEvent) {
  831.     formId = e->data.frmLoad.formID;
  832.     frm = FrmInitForm(formId);
  833.     FrmSetActiveForm(frm);
  834.  
  835.     switch(formId) {
  836.     case MainForm:
  837.         FrmSetEventHandler(frm, MainFormHandleEvent);
  838.         break;
  839.     case enterValueForm:
  840.         FrmSetEventHandler(frm, enterValueFormHandleEvent);
  841.         break;
  842.     case ViewLogForm:
  843.         FrmSetEventHandler(frm, ViewLogFormHandleEvent);
  844.         break;
  845.     }
  846.     handled = true;
  847.     }
  848.  
  849.     return handled;
  850. }
  851.  
  852. Int OpenDatabase(void)
  853. {
  854.     UInt index = 0;
  855.     VoidHand RecHandle;
  856.     Ptr RecPointer;
  857. #if 0
  858.     LocalID dbID;
  859.     UInt cardNo;
  860. #endif
  861.     
  862.     myDB = DmOpenDatabaseByTypeCreator(DBTYPE, APPID, dmModeReadWrite);
  863.     
  864.     if (!myDB) { /* doen't exist -> create it */
  865.     if (DmCreateDatabase(0, dbName, APPID, DBTYPE, false))
  866.         return 1;
  867.     myDB = DmOpenDatabaseByTypeCreator(DBTYPE, APPID, dmModeReadWrite);
  868.     ErrFatalDisplayIf(!myDB, "Couldn't create db.");
  869.     RecHandle = DmNewRecord(myDB, &index, sizeof(rec0val));
  870.     RecPointer = MemHandleLock(RecHandle);
  871.     DmWrite(RecPointer, 0, &rec0val, sizeof(rec0val));
  872.     MemPtrUnlock(RecPointer);
  873.     DmReleaseRecord(myDB, index, true);
  874.     }
  875.     
  876. #if 0
  877.     DmOpenDatabaseInfo(myDB, &dbID, NULL, NULL, &cardNo, NULL);
  878. #endif
  879.     
  880.     nextRec = DmNumRecords(myDB);
  881.     
  882.     /* load initial values */
  883.     
  884.     RecHandle = DmQueryRecord(myDB, index); /* read only */
  885.     RecPointer = MemHandleLock(RecHandle);
  886.     MemMove(&rec0val, RecPointer, sizeof(rec0val));
  887.     MemPtrUnlock(RecPointer);
  888.     DmReleaseRecord(myDB, index, false);
  889.     
  890.     return 0;
  891. }
  892.  
  893. void CloseDatabase(void)
  894. {
  895.     UInt index = 0;
  896.     VoidHand RecHandle;
  897.     Ptr RecPointer;
  898.     
  899.     /* save initial values */
  900.     
  901.     RecHandle = DmGetRecord(myDB, index); /* read write */
  902.     RecPointer = MemHandleLock(RecHandle);
  903.     DmWrite(RecPointer, 0, &rec0val, sizeof(rec0val));
  904.     MemPtrUnlock(RecPointer);
  905.     DmReleaseRecord(myDB, index, true);
  906.     
  907.     DmCloseDatabase(myDB);
  908. }
  909.  
  910. /* Get preferences, open (or create) app database */
  911. static Word StartApplication(void)
  912. {
  913.     Int retval;
  914.     
  915.     retval = OpenDatabase();
  916.  
  917.     if (retval)
  918.     return retval;
  919.  
  920.     FrmGotoForm(MainForm);
  921.     return 0;
  922. }
  923.  
  924. /* Save preferences, close forms, close app database */
  925. static void StopApplication(void)
  926. {
  927.     if (running)
  928.     SerClose(refNum);
  929.     CloseDatabase();
  930.     FrmSaveAllForms();
  931.     FrmCloseAllForms();
  932. }
  933.  
  934. static long GetWaitTime(void)
  935. {
  936.     if (!running)
  937.     return evtWaitForever;
  938.     else
  939.     return rec0val.time * sysTicksPerSecond;
  940. }
  941.  
  942. /* The main event loop */
  943. static void EventLoop(void)
  944. {
  945.     Word err;
  946.     EventType e;
  947.  
  948.     do {
  949.     EvtGetEvent(&e, GetWaitTime());
  950.     if (! SysHandleEvent (&e))
  951.         if (running || (! MenuHandleEvent (NULL, &e, &err)))
  952.         if (! ApplicationHandleEvent (&e))
  953.             FrmDispatchEvent (&e);
  954.     } while (e.eType != appStopEvent);
  955. }
  956.  
  957. /* Main entry point; it is unlikely you will need to change this except to
  958.    handle other launch command codes */
  959. DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
  960. {
  961.     Word err;
  962.  
  963.     if (cmd == sysAppLaunchCmdNormalLaunch) {
  964.  
  965.     err = StartApplication();
  966.     if (err) return err;
  967.  
  968.     EventLoop();
  969.     StopApplication();
  970.  
  971.     } else {
  972.     return sysErrParamErr;
  973.     }
  974.  
  975.     return 0;
  976. }
  977.