home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
linuxmafia.com 2016
/
linuxmafia.com.tar
/
linuxmafia.com
/
pub
/
palmos
/
timber-0.0beta.tar.gz
/
timber-0.0beta.tar
/
Timber
/
Timber.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-14
|
73KB
|
2,789 lines
/*
TIMBER - A logging program for numerical data with graphical views
FILE: Timber.c
VERSION: 0.0 BETA
DATE: 2000/01/14
AUTHOR: Jens R. Woinowski (jrw)
Timber is open source software under GNU GPL. Read LICENSE.txt.
*/
#ifdef __GNUC__
#include "Callbacks.h"
#endif
#define ERROR_CHECK_LEVEL 2
#include <Pilot.h>
#include <DataMgr.h>
#include <CharAttr.h>
#include <SysEvtMgr.h>
#include <Preferences.h>
#include <DateTime.h>
#include "TimberRsc.h"
// database types and variables:
// we use fixed comma with 4 digits fractional
#define MaxPrecisionMult 10000
#define MaxPrecision 4
#define UseMaxAndCut -1
// smoothing of year graph, how many past values are used:
#define SmoothNumber 5
// string length of weights
#define WeightSize 32
typedef ULong WeightType;
typedef WeightType *WeightPtr;
typedef struct {
DateType date;
WeightType weight;
} RecordType;
typedef RecordType *RecordPtr;
static DmOpenRef gTimberDB;
// application start:
static Err StartApplication(void);
static void InitTable(void);
// database routines:
static Err OpenOrCreateDB(DmOpenRef *dbP, ULong type, ULong creator,
ULong mode, UInt cardNo, char *name);
static Int DateCompareInDB(RecordPtr p1, RecordPtr p2, Int i,
SortRecordInfoPtr s1, SortRecordInfoPtr s2,
VoidHand appInfoH);
static Int DateCompare(DateType *p1, DateType *p2);
static Long FindRecord(DateType date, Boolean *isNewPtr);
static Err AddRecord(DateType date, WeightType weight,
Boolean ask, Long *newIndex);
static Err DeleteRecord(DateType date, Boolean ask, Boolean *deleted);
static Err ChangeRecord(DateType oldDate, DateType newDate,
WeightType oldWeight, WeightType newWeight,
Boolean ask,Long *newIndex);
static void MinMaxFind(void);
static void MinMaxBetween(DateType start, DateType end,
WeightType *minWeight, WeightType *maxWeight,
Boolean *emptyRange);
// weight to ascii and back:
static void WeightToAscii(CharPtr to, WeightType weight, Int precision);
static void AsciiToWeight(CharPtr from, WeightPtr weight);
// list drawing:
static void TimberListTableDrawItem(VoidPtr table, Word row, Word column,
RectanglePtr bounds);
static void UpdateListView(Boolean firstVisibleUpdate, Boolean triggerUpdate);
static void ScrollView(Int lines);
// graph drawing:
static void TimberGraphDraw(void);
static void CalcDrawYRanges(void);
static Int ScreenY(WeightType y);
static void DrawYScale(void);
static void CalcDrawXRanges(void);
static void CalcGoalCoordinates(void);
static Int ScreenX(Int day, Int month);
static void DrawXScale(void);
static void DrawMonthScale(void);
static void DrawQuarterOrYearScale(Int firstMonth);
static void DrawTheGraph(void);
static void DrawMonthGraph(void);
static void DrawQuarterOrYearGraph(void);
static void DrawSmoothYearGraph(void);
// Timber form handling:
static void TimberSetActiveView(Word view);
static void TimberDrawViewDate(FormPtr frm);
static void TimberChangeDate(FormPtr frm, Int byMonths);
static Boolean CommonKeyHandler(Word chr);
static Boolean TimberHandleMenuEvent(Word itemID);
// Timber custom dialogs:
static void ViewDateDialog(FormPtr frm);
static void DoNewWeightDialog(Long *newIndex);
static void NewWeightDialogDrawDate(void);
static void DoNewDateDialog(FormPtr frm);
static void DoEditWeightDialog(UInt index, Long *newIndex);
static void EditWeightDialogDrawDate(void);
static void DoPrefDialog(void);
static void DoGoalDialog();
static void GoalDialogDrawDates(void);
static void DoDeleteDialog(Boolean *updateView);
static void DeleteDialogDrawDate(void);
// helpful system shortcuts:
static Word GetObjectIdxFromActive(Word objectID);
static Word GetObjectIdxFromAny(Word FormID, Word objectID);
static VoidPtr GetObjectPtrFromActive(Word objectID);
static VoidPtr GetObjectPtrFromAny(Word formID, Word objectID);
// debugging:
static void DoDebugAlertInt(CharPtr s1,Long i);
static void DoDebugAlertInt2(CharPtr s1, Long i, Long j);
static void DoDebugAlert1(CharPtr s1);
static void DoDebugAlert2(CharPtr s1, CharPtr s2);
static void DoDebugAlert3(CharPtr s1, CharPtr s2, CharPtr s3);
static VoidHand TimberGetRecord(DmOpenRef dbR,UInt index);
static VoidHand TimberQueryRecord(DmOpenRef dbR,UInt index);
static VoidPtr TimberHandleLock(VoidHand h);
static Char gBuf1[128];
static Char gBuf2[128];
static Char gBuf3[128];
#define TimberListView 0
#define TimberMonthView 1
#define TimberQuarterView 2
#define TimberYearView 3
#define TimberSmoothView 4
#define datePrevMonth -1
#define dateNextMonth 1
#define kTimberCreator 'Tmbr'
#define kTimberPrefID 0x00
#define kTimberVersion 0x00
#define kTimberDBType 'Cust'
#define kTimberDBName "Timber-Tmbr"
static Boolean gTimberStart;
static Word gTimberView;
static Word gTimberGroup;
// preferences:
static DateFormatType gSysPrefDateFormat;
typedef struct {
Word ActiveView;
DateFormatType DateFormat;
DateFormatType LongDateFormat;
Byte ListPrecision;
Boolean RoundWeights;
Short DrawPrecision;
NumberFormatType NumberFormat;
Char ThousandSeparator;
Char DecimalSeparator;
Boolean ReplaceAsk;
Boolean DeleteAsk;
Int MonthScroll;
Boolean GlobalMinMax;
Boolean ShowGoal;
Boolean ShowAverage;
RecordType GoalStart;
RecordType GoalEnd;
} PrefType;
typedef PrefType *PrefPtr;
static PrefPtr gPrefPtr;
static PrefType gPrefDefault={TimberListView,0,0,1,true,
1,0,0,0,true,true,false,false,false,false,
{{0,0,0},0},{{0,0,0},0}};
static PrefType gSavedPrefs;
// viewed or chosen date:
static DateType gViewDate;
static DateType gChooseDate;
// drawing ranges:
static Long gDrawXRange;
static Long gDrawXMin;
static Long gDrawXMax;
static Int gScreenXMax=158;
static Int gScreenXRange;
static Int gScreenXOffset;
static Int gDrawMonthOffset;
static Int gDrawMonthDays[12];
static Boolean gDrawBigRange;
static WeightType gDrawYRange;
static WeightType gDrawYMin;
static WeightType gDrawYMax;
static Long gScreenYRange=115;
static Long gScreenYOffset=18;
static WeightType gDrawPrecision;
static WeightType gDrawPrecisionMult;
static WeightType gDrawPrecisionRound;
static DateType gDrawStartDate;
static DateType gDrawEndDate;
static Int gGoalStartX;
static Int gGoalStartY;
static Int gGoalEndX;
static Int gGoalEndY;
static Boolean gGoalOutOfBounds;
CustomPatternType AvgPattern={0xf0f0,0xf0f0,0xf0f0,0xf0f0};
CustomPatternType GoalPattern={0xeedd,0xbb77,0xeedd,0xbb77};
// visible records:
static Long gFirstVisibleRecord;
TablePtr gTimberListTablePtr;
static int gScrollPerButton;
static int gTableRows;
static WeightType gMaxWeight=0;
static WeightType gMinWeight=-1L; // cheating
static Boolean gCheckWeight=true;
//
// application start:
//
static Err StartApplication(void)
{
ULong seconds;
Err result;
Word prefSize;
Word appResult;
// start flag to check if in application startup process
gTimberStart=true;
// set view date to actual system date
seconds=TimGetSeconds();
DateSecondsToDate(seconds,&gViewDate);
// get preference(s)
prefSize=sizeof(PrefType);
appResult=PrefGetAppPreferences(kTimberCreator,kTimberPrefID,
&gSavedPrefs,&prefSize,true);
if(appResult!=noPreferenceFound) {// &&(appResult>=prefSize)){
gPrefPtr=&gSavedPrefs;
}
else {
gPrefPtr=&gPrefDefault;
}
gPrefPtr->DateFormat=PrefGetPreference(prefDateFormat);
gPrefPtr->LongDateFormat=PrefGetPreference(prefLongDateFormat);
gSysPrefDateFormat=PrefGetPreference(prefDateFormat);
gPrefPtr->NumberFormat=PrefGetPreference(prefNumberFormat);
LocGetNumberSeparators(gPrefPtr->NumberFormat,
&gPrefPtr->ThousandSeparator,&gPrefPtr->DecimalSeparator);
// set active view
TimberSetActiveView(gPrefPtr->ActiveView);
// open database
if(result=OpenOrCreateDB(&gTimberDB, kTimberDBType, kTimberCreator,
dmModeReadWrite, 0, kTimberDBName)){
FrmAlert(NoTimberDBAlert);
return result;
}
// debugging:
/*
{
RecordType record;
record.date.year=gViewDate.year;
for(record.date.month=1;record.date.month<13;record.date.month+=3)
for(record.date.day=1;record.date.day<29;record.date.day+=3)
AddRecord(record.date,
((UInt)SysRandom(0)+record.date.day+record.date.month)
*MaxPrecisionMult/100,false,NULL);
}
*/
// startup completed
gTimberStart=false;
return 0;
}
static void InitTable(void)
{
TablePtr table;
Int rows,i;
Int columns,j;
table=GetObjectPtrFromActive(TimberListTable);
gTimberListTablePtr=table;
rows=TblGetNumberOfRows(table);
columns=TimberListCols;
gTableRows=rows;
gScrollPerButton=rows;
for(i=0;i<rows;i++){
TblSetItemStyle(table,i,0,customTableItem);
TblSetRowUsable(table,i,false);
}
for(j=0;j<columns;j++)
TblSetColumnUsable(table,j,true);
TblSetCustomDrawProcedure(table,0,TimberListTableDrawItem);
}
static void StopApplication(void)
{
// save preferences
gPrefPtr->ActiveView=gTimberView;
PrefSetAppPreferences(kTimberCreator,kTimberPrefID,kTimberVersion,
gPrefPtr,sizeof(PrefType),true);
// closing the database
// DmResetRecordStates(gTimberDB); // should be no performance problem
DmCloseDatabase(gTimberDB);
}
//
// database routines:
//
static Err OpenOrCreateDB(DmOpenRef *dbP, ULong type, ULong creator,
ULong mode, UInt cardNo, char *name)
{
Err err;
*dbP = DmOpenDatabaseByTypeCreator(type, creator, mode);
err = DmGetLastErr();
if (! *dbP)
{
err = DmCreateDatabase(0, name, creator, type, false);
if (err)
return err;
*dbP = DmOpenDatabaseByTypeCreator(type, creator, mode);
if (! *dbP)
return DmGetLastErr();
}
return err;
}
static Int DateCompareInDB(RecordPtr p1, RecordPtr p2, Int i,
SortRecordInfoPtr s1, SortRecordInfoPtr s2,
VoidHand appInfoH)
{
Int result;
result=(Int)(p1->date.year)-(Int)(p2->date.year);
if(result==0){
result=(Int)(p1->date.month)-(Int)(p2->date.month);
if(result==0)
result=(Int)(p1->date.day)-(Int)(p2->date.day);
}
return result;
}
static Int DateCompare(DateType *p1, DateType *p2)
{
Int result;
result=(Int)(p1->year)-(Int)(p2->year);
if(result==0){
result=(Int)(p1->month)-(Int)(p2->month);
if(result==0)
result=(Int)(p1->day)-(Int)(p2->day);
}
return result;
}
static Long FindRecord(DateType date, Boolean *isNewPtr)
{
RecordType record;
Long index;
Boolean isNew=true;
FormPtr frm=FrmGetActiveForm();
Word frmID=FrmGetActiveFormID();
// show busy message
switch(frmID){
case TimberListForm:
FrmShowObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
break;
case TimberGraphForm:
FrmShowObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
break;
}
// find the record position
record.date.month=date.month;
record.date.day=date.day;
record.date.year=date.year;
index=(Long)DmFindSortPosition(gTimberDB,
&record,0,(DmComparF *)DateCompareInDB,0);
// check if the date is new
if ((index>0) && (index<=DmNumRecords(gTimberDB))){
VoidHand foundRecordH;
RecordPtr foundRecordP;
foundRecordH=TimberQueryRecord(gTimberDB,index-1);
foundRecordP=TimberHandleLock(foundRecordH);
isNew=DateCompare(&date,&(foundRecordP->date))!=0;
MemHandleUnlock(foundRecordH);
}
if(isNewPtr)
*isNewPtr=isNew;
// hide busy message
switch(frmID){
case TimberListForm:
FrmHideObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
break;
case TimberGraphForm:
FrmHideObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
break;
}
if(isNew)
return index;
else
return index-1;
}
static Err AddRecord(DateType date, WeightType weight,
Boolean ask, Long *newIndex)
{
RecordType newRecord;
UInt index;
Boolean isNew;
VoidHand newRecordH;
RecordPtr newRecordP;
Char dateStr[longDateStrLength+9];
Boolean checkWeight;
if(newIndex)
*newIndex=-1;
index=FindRecord(date,&isNew);
newRecord.date.month=date.month;
newRecord.date.day=date.day;
newRecord.date.year=date.year;
newRecord.weight=weight;
if (isNew) {
newRecordH=DmNewRecord(gTimberDB,&index,sizeof(RecordType));
if(newRecordH==NULL) {
FrmAlert(MemoryFullAlert);
return DmGetLastErr();
}
newRecordP=TimberHandleLock(newRecordH);
DmWrite(newRecordP,0,&newRecord,sizeof(RecordType));
MemHandleUnlock(newRecordH);
DmReleaseRecord(gTimberDB,index,true);
if(weight<gMinWeight)
gMinWeight=weight;
if(weight>gMaxWeight)
gMaxWeight=weight;
} else {
if (ask) {
DateToDOWDMFormat(date.month,
date.day,
date.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
if(FrmCustomAlert(ReplaceAlert,dateStr," "," ")!=StandardAlertOK)
return 0;
}
newRecordH=TimberGetRecord(gTimberDB,index);
newRecordP=TimberHandleLock(newRecordH);
checkWeight=(newRecordP->weight==gMinWeight)||
(newRecordP->weight==gMaxWeight);
DmWrite(newRecordP,0,&newRecord,sizeof(RecordType));
MemHandleUnlock(newRecordH);
DmReleaseRecord(gTimberDB,index,true);
if(checkWeight)
MinMaxFind();
else if(weight<gMinWeight)
gMinWeight=weight;
if(weight>gMaxWeight)
gMaxWeight=weight;
}
if(newIndex)
*newIndex=index;
return 0;
}
static Err DeleteRecord(DateType date, Boolean ask, Boolean *deleted)
{
UInt index;
Boolean isNew;
Char dateStr[longDateStrLength+9];
// the flag tells if after the procedure a record with that date exists
if(deleted)
*deleted=true;
// we try only to delete existing records
index=FindRecord(date,&isNew);
if (isNew)
return 0;
if(deleted)
*deleted=false;
// confirmation dialog
if (ask) {
DateToDOWDMFormat(date.month,
date.day,
date.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
if(FrmCustomAlert(DeleteAlert,dateStr," "," ")!=StandardAlertOK)
return 0;
}
// now, do it
DmRemoveRecord(gTimberDB,index);
MinMaxFind();
if(deleted)
*deleted=true;
return 0;
}
static Err ChangeRecord(DateType oldDate, DateType newDate,
WeightType oldWeight, WeightType newWeight,
Boolean ask, Long *newIndex)
{
RecordType newRecord;
Char oldDateStr[longDateStrLength+9];
Char newDateStr[longDateStrLength+9];
if(newIndex)
*newIndex=-1;
// no date change is like regular add
if (DateCompare(&oldDate,&newDate)==0)
return AddRecord(oldDate,newWeight,ask,newIndex);
// date change needs complcated dialog cases
if (ask) {
DateToDOWDMFormat(oldDate.month,
oldDate.day,
oldDate.year+firstYear,
gPrefPtr->DateFormat,
oldDateStr);
DateToDOWDMFormat(newDate.month,
newDate.day,
newDate.year+firstYear,
gPrefPtr->DateFormat,
newDateStr);
if(oldWeight==newWeight){
// simple move confirmation
if(FrmCustomAlert(MoveAlert,oldDateStr,newDateStr," ")
!=StandardAlertOK)
return 0;
} else {
// change value and move confirmation
if(FrmCustomAlert(ChangeAlert,oldDateStr,newDateStr," ")
!=StandardAlertOK)
return 0;
}
}
// and now, just do it:
DeleteRecord(oldDate,false,NULL);
return AddRecord(newDate,newWeight,ask,newIndex);
}
static void MinMaxFind(void)
{
UInt index,numRecords;
VoidHand recordH;
RecordPtr recordP;
WeightType weight;
FormPtr frm=FrmGetActiveForm();
Word frmID=FrmGetActiveFormID();
// show busy message
switch(frmID){
case TimberListForm:
FrmShowObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
break;
case TimberGraphForm:
FrmShowObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
break;
}
gMaxWeight=0;
gMinWeight=-1L; // cheating
numRecords=DmNumRecords(gTimberDB);
for(index=0;index<numRecords;index++){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
weight=recordP->weight;
MemHandleUnlock(recordH);
if(weight<gMinWeight)
gMinWeight=weight;
if(weight>gMaxWeight)
gMaxWeight=weight;
}
// hide busy message
switch(frmID){
case TimberListForm:
FrmHideObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
break;
case TimberGraphForm:
FrmHideObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
break;
}
}
static void MinMaxBetween(DateType start, DateType end,
WeightType *minWeight, WeightType *maxWeight,
Boolean *emptyRange)
{
Long index,first,last;
VoidHand recordH;
RecordPtr recordP;
WeightType weight;
FormPtr frm=FrmGetActiveForm();
Word frmID=FrmGetActiveFormID();
Boolean isNew;
// find the record range
*emptyRange=false;
first=FindRecord(start,&isNew);
if(first<0)
first=0;
last=FindRecord(end,&isNew);
if(isNew)
last--;
if(last<=first){
*emptyRange=true;
return;
}
if(gPrefPtr->GlobalMinMax)
return;
// show busy message
switch(frmID){
case TimberListForm:
FrmShowObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
break;
case TimberGraphForm:
FrmShowObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
break;
}
*maxWeight=0;
*minWeight=-1L; // cheating
for(index=first;index<=last;index++){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
weight=recordP->weight;
MemHandleUnlock(recordH);
if(weight<*minWeight)
*minWeight=weight;
if(weight>*maxWeight)
*maxWeight=weight;
}
if(*minWeight==-1L)
*minWeight=*maxWeight;
// hide busy message
switch(frmID){
case TimberListForm:
FrmHideObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
break;
case TimberGraphForm:
FrmHideObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
break;
}
}
//
// weight to ascii and back:
//
static void WeightToAscii(CharPtr to, WeightType weight, Int precision)
{
Int resultLen,i,p;
WeightType precisionMult;
Boolean useMaxAndCut=false;
if(precision==UseMaxAndCut){
useMaxAndCut=true;
precision=MaxPrecision;
}
for(precisionMult=1,p=precision;p;p--)
precisionMult*=10;
if(gPrefPtr->RoundWeights)
weight+=(5*(ULong)MaxPrecisionMult/10)/precisionMult;
if(weight<MaxPrecisionMult){
StrIToA(to,weight+MaxPrecisionMult);
to[0]='0';
} else
StrIToA(to,weight);
resultLen=StrLen(to)+precision-MaxPrecision;
to[resultLen+1]=0;
for(i=0,p=resultLen;i<precision;i++,p--)
to[p]=to[p-1];
if(precision)
to[p]=gPrefPtr->DecimalSeparator;
else
to[p]=0;
if(useMaxAndCut){
for(p=StrLen(to)-1;to[p]=='0';p--);
if(to[p]!=',')
p++;
to[p]=0;
}
StrLocalizeNumber(to,gPrefPtr->ThousandSeparator,gPrefPtr->DecimalSeparator);
}
static void AsciiToWeight(CharPtr from, WeightPtr weight)
{
ULong intPart,fracPart;
Int prec;
intPart=0;
fracPart=0;
while(*from&&(*from!=gPrefPtr->DecimalSeparator))
if(('0'<=*from)&&('9'>=*from)){
intPart=intPart*10+*from-'0';
from++;
} else
from++;
if(*from)
from++;
prec=0;
while((*from)&&(prec<MaxPrecision))
if(('0'<=*from)&&('9'>=*from)){
fracPart=fracPart*10+*from-'0';
from++;
prec++;
} else
from++;
while(prec++<MaxPrecision)
fracPart*=10;
*weight=intPart*MaxPrecisionMult+fracPart;
}
//
// list drawing:
//
static void TimberListTableDrawItem(VoidPtr table, Word row, Word column,
RectanglePtr bounds)
{
Char dateStr[longDateStrLength+9];
Char weightStr[33];
UInt numRecords;
UInt index;
Int drawX;
Int width;
Int charsToDraw;
VoidHand recordH;
RecordPtr recordP;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
WinEraseRectangle(bounds,0);
numRecords=DmNumRecords(gTimberDB);
// no drawing necessary
index=gFirstVisibleRecord+row;
if((index==-1)||(index==numRecords)){
StrCopy(dateStr,"");
StrCopy(weightStr,"- - - - - - - - - - - - - - - - - - - - - - - -");
} else {
// lock, get and convert data
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
DateToDOWDMFormat(recordP->date.month,
recordP->date.day,
recordP->date.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
WeightToAscii(weightStr,recordP->weight,gPrefPtr->ListPrecision);
MemHandleUnlock(recordH);
}
// draw date
charsToDraw=StrLen(dateStr);
width=FntCharsWidth(dateStr,charsToDraw);
drawX=bounds->topLeft.x+(Int)bounds->extent.x*3/5-width;
WinDrawChars(dateStr, charsToDraw, drawX, bounds->topLeft.y);
// draw weight
charsToDraw=StrLen(weightStr);
width=FntCharsWidth(weightStr,charsToDraw);
drawX=bounds->topLeft.x+bounds->extent.x-width;
WinDrawChars(weightStr, charsToDraw, drawX, bounds->topLeft.y);
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
}
static void UpdateListView(Boolean firstVisibleUpdate, Boolean triggerUpdate)
{
Long index;
VoidHand recordH;
RecordPtr recordP;
Long numRecords;
ScrollBarPtr scroll;
TablePtr table;
Int rows,i;
FormPtr frm;
// get table info
table=gTimberListTablePtr;
if(table==NULL)
return;
rows=TblGetNumberOfRows(table);
numRecords=DmNumRecords(gTimberDB);
// find first visible record
gViewDate.day=0;
if((!firstVisibleUpdate)||triggerUpdate){
if(gFirstVisibleRecord>=numRecords)
index=numRecords-1;
if(gFirstVisibleRecord>=0)
index=gFirstVisibleRecord;
else
index=0;
} else
index=FindRecord(gViewDate,NULL);
if((0<=index)&&(index<numRecords)){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
// update view date trigger
if(triggerUpdate) {
if(index<numRecords){
gViewDate.month=recordP->date.month;
gViewDate.year=recordP->date.year;
}
} else if(firstVisibleUpdate) {
if(index<numRecords){
// check if view is before first record
if(index==0){
if((gViewDate.year<recordP->date.year)||
((gViewDate.year=recordP->date.year)&&
(gViewDate.month<recordP->date.month)))
gFirstVisibleRecord=-1;
else
gFirstVisibleRecord=0;
} else
gFirstVisibleRecord=index;
} else
gFirstVisibleRecord=numRecords;
}
MemHandleUnlock(recordH);
}
// update scrollbar
scroll=GetObjectPtrFromAny(TimberListForm,TimberListScrollBar);
SclSetScrollBar(scroll,gFirstVisibleRecord+1,0,numRecords+1,rows);
// update usable
for(i=0;i<rows;i++)
TblSetRowUsable(table,i,
((i!=0)||(gFirstVisibleRecord>=-1))
&&(i+gFirstVisibleRecord<=numRecords));
TblMarkTableInvalid(table);
}
static void ScrollView(Int lines)
{
Long newFirst;
Long maxLast=DmNumRecords(gTimberDB);
newFirst=gFirstVisibleRecord+(Long)lines;
if(newFirst<-1)
newFirst=-1L;
if(newFirst>maxLast)
newFirst=maxLast;
gFirstVisibleRecord=newFirst;
UpdateListView(false,true);
}
//
// event handling:
//
static Boolean TimberListFormHandleEvent(EventPtr event)
{
Boolean handled;
FormPtr frm;
Word ctlID;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
handled = false;
frm=FrmGetActiveForm();
switch (event->eType) {
case ctlSelectEvent: // A control button was pressed and released.
ctlID=event->data.ctlSelect.controlID;
switch (ctlID) {
case TimberListMonthButton:
case TimberListQuarterButton:
case TimberListYearButton:
case TimberListSmoothButton:
TblUnhighlightSelection(gTimberListTablePtr);
TimberSetActiveView(ctlID-TimberListListButton);
handled = true;
break;
case TimberListDateTrigger:
TblUnhighlightSelection(gTimberListTablePtr);
ViewDateDialog(frm);
UpdateListView(true,true);
TblMarkTableInvalid(gTimberListTablePtr);
TblDrawTable(gTimberListTablePtr);
TimberDrawViewDate(frm);
handled = true;
break;
case TimberListNewButton:
{
TablePtr table=gTimberListTablePtr;
Long newIndex;
Long row;
Word selectRow,selectCol;
Boolean triggerUpdate,selected;
DoNewWeightDialog(&newIndex);
if(newIndex>=0) {
TblUnhighlightSelection(table);
if(newIndex<gFirstVisibleRecord){
row=0;
gFirstVisibleRecord=newIndex;
triggerUpdate=true;
}
else if(newIndex>=gFirstVisibleRecord+gTableRows){
row=gTableRows-1;
gFirstVisibleRecord=newIndex-(gTableRows-1);
triggerUpdate=true;
} else {
row=newIndex-gFirstVisibleRecord;
triggerUpdate=row==0;
}
UpdateListView(false,triggerUpdate);
if(triggerUpdate)
TimberDrawViewDate(frm);
TblMarkTableInvalid(gTimberListTablePtr);
TblDrawTable(gTimberListTablePtr);
TblSelectItem(table,row,0);
}
}
handled = true;
break;
case TimberListPrefButton:
DoPrefDialog();
TblMarkTableInvalid(gTimberListTablePtr);
TblDrawTable(gTimberListTablePtr);
handled=true;
break;
case TimberListGoalButton:
DoGoalDialog();
handled=true;
break;
}
break;
case ctlRepeatEvent:
{
Long saveFirstVisible=gFirstVisibleRecord;
switch (event->data.ctlRepeat.controlID){
case TimberListPrevButton:
TblUnhighlightSelection(gTimberListTablePtr);
TimberChangeDate(frm,datePrevMonth);
UpdateListView(true,false);
TimberDrawViewDate(frm);
if(saveFirstVisible!=gFirstVisibleRecord){
TblMarkTableInvalid(gTimberListTablePtr);
TblDrawTable(gTimberListTablePtr);
}
// handled stays false because then system unhighlights button
// if necessary!
break;
case TimberListNextButton:
TblUnhighlightSelection(gTimberListTablePtr);
TimberChangeDate(frm,dateNextMonth);
UpdateListView(true,false);
TimberDrawViewDate(frm);
if(saveFirstVisible!=gFirstVisibleRecord){
TblMarkTableInvalid(gTimberListTablePtr);
TblDrawTable(gTimberListTablePtr);
}
// handled stays false because then system unhighlights button
// if necessary!
break;
}
}
break;
case menuEvent:
handled=TimberHandleMenuEvent(event->data.menu.itemID);
break;
case keyDownEvent:
{
Long saveFirstVisible=gFirstVisibleRecord;
switch(event->data.keyDown.chr){
case pageUpChr:
TblUnhighlightSelection(gTimberListTablePtr);
if(gPrefPtr->MonthScroll){
TimberChangeDate(frm,datePrevMonth);
UpdateListView(true,false);
} else
ScrollView(-gScrollPerButton);
TimberDrawViewDate(frm);
if(saveFirstVisible!=gFirstVisibleRecord)
TblDrawTable(gTimberListTablePtr);
handled = true;
break;
case pageDownChr:
TblUnhighlightSelection(gTimberListTablePtr);
if(gPrefPtr->MonthScroll){
TimberChangeDate(frm,dateNextMonth);
UpdateListView(true,false);
} else
ScrollView(gScrollPerButton);
TimberDrawViewDate(frm);
if(saveFirstVisible!=gFirstVisibleRecord)
TblDrawTable(gTimberListTablePtr);
handled = true;
break;
}
}
break;
case tblEnterEvent:
{
TablePtr table=GetObjectPtrFromActive(event->data.tblEnter.tableID);
Long row=event->data.tblEnter.row;
Long index=row+gFirstVisibleRecord;
Long newIndex;
Boolean triggerUpdate;
TblUnhighlightSelection(table);
if((index>=0)&&(index<DmNumRecords(gTimberDB))){
TblSelectItem(table,row,0);
DoEditWeightDialog(index,&newIndex);
triggerUpdate=(index==newIndex)&&(row==0);
if(newIndex<0)
triggerUpdate=row==0;
else if(newIndex<gFirstVisibleRecord){
row=0;
gFirstVisibleRecord=newIndex;
triggerUpdate=true;
}
else if(newIndex>=gFirstVisibleRecord+gTableRows){
row=gTableRows-1;
gFirstVisibleRecord=newIndex-(gTableRows-1);
triggerUpdate=true;
} else
row=newIndex-gFirstVisibleRecord;
if(newIndex!=-1){
UpdateListView(false,triggerUpdate);
TblMarkTableInvalid(gTimberListTablePtr);
if(triggerUpdate)
TimberDrawViewDate(frm);
TblUnhighlightSelection(table);
TblDrawTable(gTimberListTablePtr);
TblSelectItem(table,row,0);
}
}
}
handled = true;
break;
case sclRepeatEvent:
TblUnhighlightSelection(gTimberListTablePtr);
ScrollView(event->data.sclRepeat.newValue-
event->data.sclRepeat.value);
TblDrawTable(gTimberListTablePtr);
TimberDrawViewDate(frm);
break;
case frmOpenEvent:
FrmSetControlGroupSelection(frm,
TimberListViewGroup,
TimberListListButton);
// initialize list view
InitTable();
UpdateListView(true,true);
FrmDrawForm(frm);
TimberDrawViewDate(frm);
if(gCheckWeight)
MinMaxFind();
gCheckWeight=false;
FrmHideObject(frm,GetObjectIdxFromActive(TimberListBusyLabel));
handled = true;
break;
}
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
return(handled);
}
static Boolean TimberGraphFormHandleEvent(EventPtr event)
{
Boolean handled;
FormPtr frm;
Word ctlID;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
handled = false;
frm=FrmGetActiveForm();
switch (event->eType) {
case ctlSelectEvent: // A control button was pressed and released.
switch (ctlID=event->data.ctlSelect.controlID) {
case TimberGraphListButton:
case TimberGraphMonthButton:
case TimberGraphQuarterButton:
case TimberGraphYearButton:
case TimberGraphSmoothButton:
TimberSetActiveView(ctlID-TimberGraphListButton);
handled = true;
break;
case TimberGraphDateTrigger:
ViewDateDialog(frm);
TimberDrawViewDate(frm);
TimberGraphDraw();
handled = true;
break;
case TimberGraphNewButton:
DoNewWeightDialog(NULL);
TimberGraphDraw();
handled = true;
break;
case TimberGraphPrefButton:
DoPrefDialog();
TimberGraphDraw();
handled=true;
break;
case TimberGraphGoalButton:
DoGoalDialog();
TimberGraphDraw();
handled=true;
break;
}
break;
case menuEvent:
handled=TimberHandleMenuEvent(event->data.menu.itemID);
break;
case keyDownEvent:
switch(event->data.keyDown.chr){
case pageUpChr:
TimberChangeDate(frm,datePrevMonth);
TimberGraphDraw();
handled = true;
break;
case pageDownChr:
TimberChangeDate(frm,dateNextMonth);
TimberGraphDraw();
handled = true;
break;
}
break;
case ctlRepeatEvent: // View Date change:
switch (event->data.ctlRepeat.controlID){
case TimberGraphPrevButton:
TimberChangeDate(frm,datePrevMonth);
TimberGraphDraw();
// handled stays false because then system unhighlights button
// if necessary!
break;
case TimberGraphNextButton:
TimberChangeDate(frm,dateNextMonth);
TimberGraphDraw();
// handled stays false because then system unhighlights button
// if necessary!
break;
}
break;
case frmOpenEvent:
FrmSetControlGroupSelection(frm,
TimberGraphViewGroup,
TimberGraphListButton+gTimberView);
FrmDrawForm(frm);
TimberDrawViewDate(frm);
if(gCheckWeight)
MinMaxFind();
gCheckWeight=false;
FrmHideObject(frm,GetObjectIdxFromActive(TimberGraphBusyLabel));
TimberGraphDraw();
handled = true;
break;
}
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
return(handled);
}
static Boolean TimberNewFormHandleEvent(EventPtr event)
{
Boolean handled;
FormPtr frm;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
handled = false;
frm=FrmGetActiveForm();
// Always keep focus in weight field:
FrmSetFocus(frm,GetObjectIdxFromActive(NewWeightField));
switch (event->eType) {
case ctlSelectEvent: // A control button was pressed and released.
switch (event->data.ctlSelect.controlID) {
case NewDateTrigger:
DoNewDateDialog(frm);
NewWeightDialogDrawDate();
break;
}
break;
case keyDownEvent:
handled=CommonKeyHandler(event->data.keyDown.chr);
break;
case frmOpenEvent:
FrmDrawForm(frm);
NewWeightDialogDrawDate();
handled = true;
break;
}
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
return(handled);
}
static Boolean TimberEditFormHandleEvent(EventPtr event)
{
Boolean handled;
FormPtr frm;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
handled = false;
frm=FrmGetActiveForm();
// Always keep focus in weight field:
FrmSetFocus(frm,GetObjectIdxFromActive(EditWeightField));
switch (event->eType) {
case ctlSelectEvent: // A control button was pressed and released.
switch (event->data.ctlSelect.controlID) {
case EditDateTrigger:
DoNewDateDialog(frm);
EditWeightDialogDrawDate();
break;
}
break;
case keyDownEvent:
handled=CommonKeyHandler(event->data.keyDown.chr);
break;
case frmOpenEvent:
FrmDrawForm(frm);
EditWeightDialogDrawDate();
handled = true;
break;
}
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
return(handled);
}
static Boolean TimberGoalFormHandleEvent(EventPtr event)
{
Boolean handled;
FormPtr frm;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
handled = false;
frm=FrmGetActiveForm();
switch (event->eType) {
case ctlSelectEvent: // A control button was pressed and released.
switch (event->data.ctlSelect.controlID) {
case GoalStartDateTrigger:
gChooseDate=gPrefPtr->GoalStart.date;
DoNewDateDialog(frm);
gPrefPtr->GoalStart.date=gChooseDate;
GoalDialogDrawDates();
handled=true;
break;
case GoalEndDateTrigger:
gChooseDate=gPrefPtr->GoalEnd.date;
DoNewDateDialog(frm);
gPrefPtr->GoalEnd.date=gChooseDate;
GoalDialogDrawDates();
handled=true;
break;
}
break;
case keyDownEvent:
handled=CommonKeyHandler(event->data.keyDown.chr);
break;
case frmOpenEvent:
FrmDrawForm(frm);
handled = true;
break;
}
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
return(handled);
}
static Boolean TimberDeleteFormHandleEvent(EventPtr event)
{
Boolean handled;
FormPtr frm;
#ifdef __GNUC__
CALLBACK_PROLOGUE
#endif
handled = false;
frm=FrmGetActiveForm();
switch (event->eType) {
case ctlSelectEvent: // A control button was pressed and released.
switch (event->data.ctlSelect.controlID) {
case EditDeleteDateTrigger:
DoNewDateDialog(frm);
DeleteDialogDrawDate();
break;
}
break;
case frmOpenEvent:
FrmDrawForm(frm);
DeleteDialogDrawDate();
handled = true;
break;
}
#ifdef __GNUC__
CALLBACK_EPILOGUE
#endif
return(handled);
}
static Boolean CommonKeyHandler(Word chr)
{
Boolean handled=true;
switch(chr){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case leftArrowChr:
case rightArrowChr:
case backspaceChr:
handled=false;
break;
}
if((chr>=0x100)||(chr==gPrefPtr->DecimalSeparator))
handled=false;
return handled;
}
static Boolean TimberHandleMenuEvent(Word itemID)
{
Boolean updateView=false;
Long newIndex;
Boolean handled=false;
TablePtr table=gTimberListTablePtr;
Long row;
Word selectRow,selectCol;
Boolean triggerUpdate=false;
Boolean visibleUpdate=true;
Boolean selected;
switch(itemID){
case EditAddItem:
DoNewWeightDialog(&newIndex);
updateView=newIndex>=0;
if(updateView) {
visibleUpdate=false;
if(newIndex<gFirstVisibleRecord){
row=0;
gFirstVisibleRecord=newIndex;
triggerUpdate=true;
}
else if(newIndex>=gFirstVisibleRecord+gTableRows){
row=gTableRows-1;
gFirstVisibleRecord=newIndex-(gTableRows-1);
triggerUpdate=true;
} else {
row=newIndex-gFirstVisibleRecord;
triggerUpdate=row==0;
}
}
handled=true;
break;
case EditDeleteItem:
DoDeleteDialog(&updateView);
handled=true;
break;
case OptionsGoalItem:
DoGoalDialog();
updateView=gTimberView!=TimberListView;
visibleUpdate=true;
triggerUpdate=false;
handled=true;
break;
case OptionsPrefItem:
DoPrefDialog();
updateView=true;
visibleUpdate=true;
triggerUpdate=false;
handled=true;
break;
case OptionsHelpItem:
FrmHelp(OptionsHelpString);
handled=true;
break;
case OptionsAboutGPLItem:
FrmHelp(AboutGPLString);
handled=true;
break;
case OptionsAboutItem:
FrmAlert(OptionsAboutAlert);
handled=true;
break;
}
if(updateView){
if(gTimberView==TimberListView){
UpdateListView(visibleUpdate,triggerUpdate);
TblUnhighlightSelection(table);
TblMarkTableInvalid(table);
TblDrawTable(table);
if(itemID==EditAddItem)
TblSelectItem(table,row,0);
}
else
TimberGraphDraw();
}
return handled;
}
static Boolean ApplicationHandleEvent(EventPtr event)
{
FormPtr frm;
Int formId;
Boolean handled = false;
if (event->eType == frmLoadEvent){
// Load the form resource specified in the event then activate the form.
formId = event->data.frmLoad.formID;
frm = FrmInitForm(formId);
FrmSetActiveForm(frm);
// Set the event handler for the form. The handler of the currently
// active form is called by FrmDispatchEvent each time it receives an event.
switch (formId){
case TimberListForm:
FrmSetEventHandler(frm, TimberListFormHandleEvent);
break;
case TimberGraphForm:
FrmSetEventHandler(frm, TimberGraphFormHandleEvent);
break;
case TimberNewForm:
FrmSetEventHandler(frm, TimberNewFormHandleEvent);
break;
case TimberEditForm:
FrmSetEventHandler(frm, TimberEditFormHandleEvent);
break;
case TimberGoalForm:
FrmSetEventHandler(frm, TimberGoalFormHandleEvent);
break;
}
handled = true;
}
return handled;
}
static void EventLoop(void)
{
EventType event;
Word error;
do {
EvtGetEvent(&event, evtWaitForever);
if (! SysHandleEvent(&event))
if (! MenuHandleEvent(0, &event, &error))
if (! ApplicationHandleEvent(&event))
FrmDispatchEvent(&event);
} while (event.eType != appStopEvent);
}
//
// program entry point
//
DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
{
Err err = 0;
if (cmd == sysAppLaunchCmdNormalLaunch){
if ((err = StartApplication()) == 0){
EventLoop();
StopApplication();
}
}
return err;
}
//
// graph drawing:
//
static void TimberGraphDraw(void)
{
RectangleType bounds;
RectangleType oldBounds;
bounds.topLeft.x=0;
bounds.topLeft.y=gScreenYOffset-3;
bounds.extent.x=160;
bounds.extent.y=gScreenYRange+14;
WinEraseRectangle(&bounds,0);
if(DmNumRecords(gTimberDB)<1)
return;
// Y before X is essential!
CalcDrawYRanges();
if((gPrefPtr->ShowGoal)&&(gPrefPtr->GoalStart.date.month))
CalcGoalCoordinates();
bounds.topLeft.x=gScreenXOffset;
bounds.topLeft.y=gScreenYOffset;
bounds.extent.x=gScreenXRange+1;
bounds.extent.y=gScreenYRange+1;
DrawYScale();
CalcDrawXRanges();
DrawXScale();
WinGetClip(&oldBounds);
DrawTheGraph();
WinSetPattern(GoalPattern);
bounds.extent.x=gScreenXRange+1;
// the +15 is necessary because the Palm UI Clipping has a bug:
// sometimes lines to be partially clipped do not appear at all
bounds.extent.y=gScreenYRange+1; // works on PalmV?
WinSetClip(&bounds);
if(!gGoalOutOfBounds
&&(gPrefPtr->ShowGoal)
&&(gPrefPtr->GoalStart.date.month)){
WinFillLine(gGoalStartX,gGoalStartY-1,gGoalEndX,gGoalEndY-1);
WinFillLine(gGoalStartX-1,gGoalStartY,gGoalEndX-1,gGoalEndY);
WinFillLine(gGoalStartX,gGoalStartY,gGoalEndX,gGoalEndY);
WinFillLine(gGoalStartX+1,gGoalStartY,gGoalEndX+1,gGoalEndY);
WinFillLine(gGoalStartX,gGoalStartY+1,gGoalEndX,gGoalEndY+1);
}
WinSetClip(&oldBounds);
}
static void CalcDrawYRanges(void)
{
Int p;
Int maxStrLen;
Char weightStr[30];
Int month,year;
DateType date;
WeightType minWeight,maxWeight;
Boolean emptyRange;
// calculate start and end date
gDrawEndDate.month=gViewDate.month;
gDrawEndDate.day=31;
gDrawEndDate.year=gViewDate.year;
switch(gTimberView){
case TimberMonthView:
month=gViewDate.month;
break;
case TimberQuarterView:
month=(gViewDate.month+21)%12+1;
break;
case TimberYearView:
case TimberSmoothView:
month=gViewDate.month%12+1;
break;
}
if(month>gViewDate.month)
year=gViewDate.year-1;
else
year=gViewDate.year;
if(year<0){
year=0;
month=1;
}
gDrawStartDate.month=month;
gDrawStartDate.day=1;
gDrawStartDate.year=year;
MinMaxBetween(gDrawStartDate,gDrawEndDate,&minWeight,&maxWeight,&emptyRange);
if(gPrefPtr->GlobalMinMax||emptyRange){
minWeight=gMinWeight;
maxWeight=gMaxWeight;
if(gPrefPtr->GoalStart.date.day){
if(minWeight>gPrefPtr->GoalStart.weight)
minWeight=gPrefPtr->GoalStart.weight;
if(minWeight>gPrefPtr->GoalEnd.weight)
minWeight=gPrefPtr->GoalEnd.weight;
if(maxWeight<gPrefPtr->GoalStart.weight)
maxWeight=gPrefPtr->GoalStart.weight;
if(maxWeight<gPrefPtr->GoalEnd.weight)
maxWeight=gPrefPtr->GoalEnd.weight;
}
}
// set and calculate precision values
if(gPrefPtr->DrawPrecision<0)
gDrawPrecision=gPrefPtr->ListPrecision;
else
gDrawPrecision=gPrefPtr->DrawPrecision;
p=gDrawPrecision;
gDrawPrecisionMult=1;
for(p;p;p--)
gDrawPrecisionMult*=10;
gDrawPrecisionRound=MaxPrecisionMult/gDrawPrecisionMult;
// vertical range values
gDrawYMin=(minWeight/gDrawPrecisionRound)*gDrawPrecisionRound;
gDrawYMax=(((maxWeight+gDrawPrecisionRound-1)/gDrawPrecisionRound)
*gDrawPrecisionRound);
if(gDrawYMax==gDrawYMin)
gDrawYMax+=gDrawPrecisionRound;
gDrawYRange=gDrawYMax-gDrawYMin;
gDrawBigRange=gDrawYRange>10000L*(Long)MaxPrecision;
if(gDrawBigRange)
gDrawYRange/=1000;
// horizontal offset
WeightToAscii(weightStr,gDrawYMax,gDrawPrecision);
maxStrLen=StrLen(weightStr);
gScreenXOffset=FntCharsWidth(weightStr,maxStrLen)+3;
gScreenXRange=gScreenXMax-gScreenXOffset;
}
static void CalcGoalCoordinates(void)
{
Long startDay,endDay,firstDay,lastDay,dayFirst,dayRange;
WeightType correctBig;
Long firstWeight,lastWeight;
WeightType weightDiff,weightRange;
Long correctDiff;
startDay=DateToDays(gPrefPtr->GoalStart.date);
endDay=DateToDays(gPrefPtr->GoalEnd.date);
firstDay=DateToDays(gDrawStartDate);
lastDay=DateToDays(gDrawEndDate);
dayRange=lastDay-firstDay;
dayFirst=firstDay;
gGoalOutOfBounds=(firstDay>=endDay)||(lastDay<=startDay)||(startDay>=endDay);
if(gGoalOutOfBounds)
return;
if(firstDay<startDay)
firstDay=startDay;
if(lastDay>endDay)
lastDay=endDay;
if(gPrefPtr->GoalEnd.weight>=gPrefPtr->GoalStart.weight)
weightRange=gPrefPtr->GoalEnd.weight-gPrefPtr->GoalStart.weight;
else
weightRange=gPrefPtr->GoalStart.weight-gPrefPtr->GoalEnd.weight;
if(weightRange>10000L*(Long)MaxPrecision)
correctBig=1000;
else
correctBig=1;
weightDiff=(Long)(gPrefPtr->GoalEnd.weight/correctBig)
-(Long)(gPrefPtr->GoalStart.weight/correctBig);
correctDiff=(Long)weightDiff;
firstWeight=(((((firstDay-startDay)*correctDiff)
/(endDay-startDay))*correctBig)
+gPrefPtr->GoalStart.weight);
lastWeight=(((((lastDay-startDay)*correctDiff)
/(endDay-startDay))*correctBig)
+gPrefPtr->GoalStart.weight);
gGoalStartY=ScreenY(firstWeight);
gGoalEndY=ScreenY(lastWeight);
gGoalStartX=gScreenXOffset+((firstDay-dayFirst)*gScreenXRange)/dayRange;
gGoalEndX=gScreenXOffset+((lastDay-dayFirst)*gScreenXRange)/dayRange;
}
static Int ScreenY(WeightType y)
{
Long yDiff,result;
if(y>=gDrawYMin)
yDiff=(Long)y-(Long)gDrawYMin;
else
yDiff=y;
// check, if a big range is used
if(gDrawBigRange)
result=(Long)(((yDiff/gDrawYRange)*gScreenYRange)/1000);
else
result=(Long)((yDiff*gScreenYRange)/gDrawYRange);
if(y<gDrawYMin){
if(gDrawBigRange)
result-=(Long)(((gDrawYMin/gDrawYRange)*gScreenYRange)/1000);
else
result-=(Long)((gDrawYMin*gScreenYRange)/gDrawYRange);
}
return (Long)gScreenYOffset+(Long)gScreenYRange-result;
}
static void DrawYScale(void)
{
Int i,stepCount;
WeightType range;
WeightType val;
WeightType lastVal;
WeightType step;
Char weightStr[30];
Int len,width;
Int y;
range=gDrawYMax-gDrawYMin;
step=range/5;
step=((step+gDrawPrecisionRound-1)/gDrawPrecisionRound)*gDrawPrecisionRound;
if(!step)
step=gDrawPrecisionRound;
stepCount=1+range/step;
while(((stepCount-1)*step<range)&&(stepCount<20))
stepCount++;
lastVal=-1;
for(i=0;i<stepCount;i++){
if(i==stepCount-1)
val=gDrawYMax;
else {
val=gDrawYMin+i*step+(5*gDrawPrecisionRound)/10;
val=(val/gDrawPrecisionRound)*gDrawPrecisionRound;
}
if(val!=lastVal){
lastVal=val;
WeightToAscii(weightStr,val,gDrawPrecision);
len=StrLen(weightStr);
width=FntCharsWidth(weightStr,len);
y=ScreenY(val);
WinDrawLine(gScreenXOffset-2,y,gScreenXOffset+2,y);
if((i==stepCount-1)||(y<=gScreenYOffset+5))
y=gScreenYOffset+4;
WinDrawChars(weightStr,len,(gScreenXOffset-3)-width,y-5);
}
}
WinDrawLine(gScreenXOffset,gScreenYOffset,
gScreenXOffset,gScreenYOffset+gScreenYRange);
}
static void CalcDrawXRanges(void)
{
Int trickster,month,realMonth,realYear,days;
trickster=-2;
switch(gTimberView){
case TimberMonthView:
gDrawXMax=DaysInMonth(gViewDate.month,gViewDate.year+firstYear);
gDrawMonthDays[gViewDate.month%12]=0;
gDrawXMin=1;
break;
case TimberYearView:
case TimberSmoothView:
trickster=-11; // this is a little tricky, no break!
case TimberQuarterView:
gDrawXMax=0;
for(month=trickster;trickster++<=0;month++){
realMonth=((int)gViewDate.month+month+23)%12+1;
if(realMonth>gViewDate.month)
realYear=gViewDate.year-1;
else
realYear=gViewDate.year;
gDrawMonthDays[realMonth%12]=gDrawXMax;
if(realYear>0){
gDrawXMax+=DaysInMonth(realMonth,realYear+firstYear);
}
}
gDrawXMin=1;
break;
}
gDrawXRange=gDrawXMax-gDrawXMin;
}
static Int ScreenX(Int day, Int month)
{
return
gScreenXOffset+
(gDrawMonthDays[month%12]+day-gDrawXMin)
*gScreenXRange
/gDrawXRange;
}
static void DrawXScale(void)
{
Int y;
switch(gTimberView){
case TimberMonthView:
DrawMonthScale();
break;
case TimberQuarterView:
DrawQuarterOrYearScale(-2);
break;
case TimberYearView:
case TimberSmoothView:
DrawQuarterOrYearScale(-11);
break;
}
y=gScreenYRange+gScreenYOffset;
WinDrawLine(gScreenXOffset,y,gScreenXOffset+gScreenXRange,y);
}
static void DrawMonthScale(void)
{
Int i,month,days;
Int x,y;
Char dayStr[5];
Int len,width;
y=gScreenYRange+gScreenYOffset;
month=gViewDate.month;
days=gDrawXMax;
for(i=1;i<days-1;i+=10){
x=ScreenX(i,month);
StrIToA(dayStr,i);
len=StrLen(dayStr);
width=FntCharsWidth(dayStr,len)/2;
WinDrawChars(dayStr,len,x-width,y+2);
WinDrawLine(x,y-2,x,y+2);
}
x=gScreenXRange+gScreenXOffset;
StrIToA(dayStr,days);
len=StrLen(dayStr);
width=FntCharsWidth(dayStr,len);
WinDrawChars(dayStr,len,2+x-width,y+2);
WinDrawLine(x,y-2,x,y+2);
}
static void DrawQuarterOrYearScale(Int firstMonth)
{
Char dateStr[longDateStrLength];
Int lastX,nextX,i,width,y,month,letters;
if(firstMonth==-2)
letters=3;
else
letters=1;
y=gScreenYRange+gScreenYOffset;
lastX=gScreenXOffset;
WinDrawLine(lastX,y-2,lastX,y+2);
for(i=firstMonth;i<=0;i++) {
month=((Int)gViewDate.month+i+23)%12+1;
if(i)
nextX=ScreenX(1,month+1);
else
nextX=gScreenXMax;
DateToAscii(month,1,firstYear,dfMYMed,dateStr);
width=FntCharsWidth(dateStr,letters)-2;
WinDrawChars(dateStr,letters,(nextX+lastX)/2-width/2,y);
WinDrawLine(nextX,y-2,nextX,y+2);
lastX=nextX;
}
}
static void DrawTheGraph(void)
{
Int y;
switch(gTimberView){
case TimberMonthView:
DrawMonthGraph();
break;
case TimberQuarterView:
DrawQuarterOrYearGraph();
break;
case TimberYearView:
DrawQuarterOrYearGraph();
break;
case TimberSmoothView:
DrawSmoothYearGraph();
break;
}
}
static void DrawMonthGraph(void)
{
Long index;
DateType date=gViewDate;
Int drawX,drawY,lastX,lastY,month;
VoidHand recordH;
RecordPtr recordP;
UInt numRecords=DmNumRecords(gTimberDB);
Long sum;
Int count=1;
date.day=1;
index=FindRecord(date,NULL);
if(index<0)
index=0;
if(index<numRecords){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
month=recordP->date.month;
if(month==gViewDate.month){
lastX=ScreenX(recordP->date.day,month);
lastY=ScreenY(recordP->weight);
if(gPrefPtr->ShowAverage)
sum=lastY;
MemHandleUnlock(recordH);
} else {
MemHandleUnlock(recordH);
return;
}
} else
return;
WinDrawLine(lastX-1,lastY-1,lastX+1,lastY-1);
WinDrawLine(lastX+1,lastY-1,lastX+1,lastY+1);
WinDrawLine(lastX+1,lastY+1,lastX-1,lastY+1);
WinDrawLine(lastX-1,lastY+1,lastX-1,lastY-1);
while(++index<numRecords){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
month=recordP->date.month;
if(month==gViewDate.month){
drawX=ScreenX(recordP->date.day,month);
drawY=ScreenY(recordP->weight);
if(gPrefPtr->ShowAverage){
sum+=drawY;
count++;
}
MemHandleUnlock(recordH);
} else {
MemHandleUnlock(recordH);
if(gPrefPtr->ShowAverage){
WinSetPattern(AvgPattern);
WinFillLine(gScreenXOffset,sum/count,
gScreenXOffset+gScreenXRange,sum/count);
}
return;
}
WinDrawLine(lastX,lastY,drawX,drawY);
lastX=drawX;
lastY=drawY;
WinDrawLine(lastX-1,lastY-1,lastX+1,lastY-1);
WinDrawLine(lastX+1,lastY-1,lastX+1,lastY+1);
WinDrawLine(lastX+1,lastY+1,lastX-1,lastY+1);
WinDrawLine(lastX-1,lastY+1,lastX-1,lastY-1);
}
if(gPrefPtr->ShowAverage){
WinSetPattern(AvgPattern);
WinFillLine(gScreenXOffset,sum/count,
gScreenXOffset+gScreenXRange,sum/count);
}
}
static void DrawQuarterOrYearGraph(void)
{
Long index;
DateType date=gViewDate;
Int drawX,drawY,lastX,lastY,month;
VoidHand recordH;
RecordPtr recordP;
UInt numRecords=DmNumRecords(gTimberDB);
Long sum;
Int count=1;
date.day=1;
index=FindRecord(gDrawStartDate,NULL);
if(index<0)
index=0;
if(index<numRecords){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
month=recordP->date.month;
if(DateCompare(&(recordP->date),&gDrawEndDate)<=0){
lastX=ScreenX(recordP->date.day,month);
lastY=ScreenY(recordP->weight);
if(gPrefPtr->ShowAverage)
sum=lastY;
MemHandleUnlock(recordH);
} else {
MemHandleUnlock(recordH);
return;
}
} else
return;
WinDrawLine(lastX-1,lastY-1,lastX+1,lastY-1);
WinDrawLine(lastX+1,lastY-1,lastX+1,lastY+1);
WinDrawLine(lastX+1,lastY+1,lastX-1,lastY+1);
WinDrawLine(lastX-1,lastY+1,lastX-1,lastY-1);
while(++index<numRecords){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
month=recordP->date.month;
if(DateCompare(&(recordP->date),&gDrawEndDate)<=0){
drawX=ScreenX(recordP->date.day,month);
drawY=ScreenY(recordP->weight);
if(gPrefPtr->ShowAverage){
sum+=drawY;
count++;
}
MemHandleUnlock(recordH);
} else {
if(gPrefPtr->ShowAverage){
WinSetPattern(AvgPattern);
WinFillLine(gScreenXOffset,sum/count,
gScreenXOffset+gScreenXRange,sum/count);
}
MemHandleUnlock(recordH);
return;
}
WinDrawLine(lastX,lastY,drawX,drawY);
lastX=drawX;
lastY=drawY;
WinDrawLine(lastX-1,lastY-1,lastX+1,lastY-1);
WinDrawLine(lastX+1,lastY-1,lastX+1,lastY+1);
WinDrawLine(lastX+1,lastY+1,lastX-1,lastY+1);
WinDrawLine(lastX-1,lastY+1,lastX-1,lastY-1);
}
if(gPrefPtr->ShowAverage){
WinSetPattern(AvgPattern);
WinFillLine(gScreenXOffset,sum/count,
gScreenXOffset+gScreenXRange,sum/count);
}
}
static void DrawSmoothYearGraph(void)
{
Long index;
Int i;
DateType date=gViewDate;
Long drawX,drawY,lastX,lastY,month;
VoidHand recordH;
RecordPtr recordP;
UInt numRecords=DmNumRecords(gTimberDB);
Int smoothPos=0;
Long smoothSave[SmoothNumber];
Long smoothSum;
Long sum;
Int count=1;
date.day=1;
index=FindRecord(gDrawStartDate,NULL);
if(index<0)
index=0;
if(index<numRecords){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
month=recordP->date.month;
if(DateCompare(&(recordP->date),&gDrawEndDate)<=0){
lastX=ScreenX(recordP->date.day,month);
lastY=ScreenY(recordP->weight);
if(gPrefPtr->ShowAverage)
sum=lastY;
MemHandleUnlock(recordH);
} else {
MemHandleUnlock(recordH);
return;
}
} else
return;
smoothSum=SmoothNumber*lastY;
for(i=0;i<SmoothNumber;i++)
smoothSave[i]=lastY;
while(++index<numRecords){
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
month=recordP->date.month;
if(DateCompare(&(recordP->date),&gDrawEndDate)<=0){
drawX=ScreenX(recordP->date.day,month);
drawY=ScreenY(recordP->weight);
if(gPrefPtr->ShowAverage){
sum+=drawY;
count++;
}
MemHandleUnlock(recordH);
} else {
MemHandleUnlock(recordH);
if(gPrefPtr->ShowAverage){
WinSetPattern(AvgPattern);
WinFillLine(gScreenXOffset,sum/count,
gScreenXOffset+gScreenXRange,sum/count);
}
return;
}
smoothSum=smoothSum+drawY-smoothSave[smoothPos];
smoothSave[smoothPos++]=drawY;
smoothPos=smoothPos%SmoothNumber;
drawY=smoothSum/SmoothNumber;
WinDrawLine(lastX,lastY,drawX,drawY);
lastX=drawX;
lastY=drawY;
}
if(gPrefPtr->ShowAverage){
WinSetPattern(AvgPattern);
WinFillLine(gScreenXOffset,sum/count,
gScreenXOffset+gScreenXRange,sum/count);
}
}
//
// Timber form handling:
//
static void TimberSetActiveView(Word view)
{
Word oldView=gTimberView;
FormPtr frm;
gTimberView=view;
if (view==TimberListView) {
gTimberGroup=TimberListViewGroup;
frm=FrmInitForm(TimberListForm);
FrmGotoForm(TimberListForm);
} else {
gTimberGroup=TimberGraphViewGroup;
frm=FrmInitForm(TimberGraphForm);
FrmGotoForm(TimberGraphForm);
FrmSetControlGroupSelection(frm,
TimberGraphViewGroup,
TimberGraphListButton+gTimberView);
}
}
static void TimberDrawViewDate(FormPtr frm)
{
Char dateStr[longDateStrLength];
Char printStr[longDateStrLength];
CharPtr dateP,printP;
RectangleType bounds;
Word charsToDraw;
Int titleWidth;
DateToAscii(gViewDate.month,
gViewDate.day,
gViewDate.year+firstYear,
dfMYMed,
dateStr);
// the format without apostrophe does not work!
for(dateP=dateStr,printP=printStr;*dateP!='\0';)
if(*dateP=='\'')
dateP++;
else
*printP++=*dateP++;
*printP++='\0';
if(gTimberView==TimberListView)
FrmGetObjectBounds(frm,
GetObjectIdxFromActive(TimberListDateTrigger),
&bounds);
else
FrmGetObjectBounds(frm,
GetObjectIdxFromActive(TimberGraphDateTrigger),
&bounds);
WinEraseRectangle(&bounds,0);
charsToDraw = StrLen(printStr);
titleWidth = FntCharsWidth (printStr, charsToDraw);
WinDrawChars (printStr,
charsToDraw,
(Int)bounds.topLeft.x+((Int)bounds.extent.x-titleWidth)/2,
bounds.topLeft.y);
}
static void TimberChangeDate(FormPtr frm, Int byMonths)
{
Int month,day,year;
month=(Int)gViewDate.month+byMonths%12;
year=(Int)gViewDate.year+(Int)firstYear+byMonths/12;
if ((year<firstYear)||((year==firstYear)&&(month<1))){
month=1;
year=firstYear;
} else if ((year>lastYear)||((year==lastYear)&&(month>12))){
month=12;
year=lastYear;
} else if(month<1){
month+=12;
year--;
} else if (month>12){
month-=12;
year++;
}
if((gViewDate.month!=month)||(gViewDate.year!=year-firstYear)){
gViewDate.month=month;
gViewDate.year=year-firstYear;
TimberDrawViewDate(frm);
}
}
//
// Timber custom dialogs:
//
static void ViewDateDialog(FormPtr frm)
{
SWord month,day,year;
CharPtr title;
title = TimberHandleLock(DmGetResource (strRsc, ChooseMonthTitle));
month=gViewDate.month;
day=gViewDate.day;
year=gViewDate.year+firstYear;
if (SelectDay (selectDayByMonth, &month, &day, &year, title)) {
gViewDate.month=month;
gViewDate.day=day;
gViewDate.year=year-firstYear;
}
MemHandleUnlock(DmGetResource (strRsc, ChooseMonthTitle));
}
static void DoNewWeightDialog(Long *newIndex)
{
ULong seconds;
Word hitButton;
FormPtr previousForm=FrmGetActiveForm();
FormPtr frm;
CharPtr weightStr;
WeightType weight;
if(newIndex)
*newIndex=-1;
// set dialog date to actual system date
seconds=TimGetSeconds();
DateSecondsToDate(seconds,&gChooseDate);
// and on we go
frm=FrmInitForm(TimberNewForm);
NewWeightDialogDrawDate();
FrmSetFocus(frm,GetObjectIdxFromAny(TimberNewForm,NewWeightField));
FrmSetEventHandler(frm, TimberNewFormHandleEvent);
hitButton=FrmDoDialog(frm);
if(hitButton==NewAddButton){
weightStr=FldGetTextPtr(GetObjectPtrFromAny(TimberNewForm,NewWeightField));
AsciiToWeight(weightStr,&weight);
AddRecord(gChooseDate,weight,gPrefPtr->ReplaceAsk,newIndex);
}
// done
if (previousForm)
FrmSetActiveForm(previousForm);
FrmDeleteForm(frm);
}
static void NewWeightDialogDrawDate()
{
CharPtr dateStr;
ControlPtr ctl;
ctl=GetObjectPtrFromAny(TimberNewForm,NewDateTrigger);
dateStr=CtlGetLabel(ctl);
DateToDOWDMFormat(gChooseDate.month,
gChooseDate.day,
gChooseDate.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
CtlSetLabel(ctl,dateStr);
}
static void DoNewDateDialog(FormPtr frm)
{
SWord month,day,year;
CharPtr title;
title = TimberHandleLock(DmGetResource (strRsc, ChooseDayTitle));
month=gChooseDate.month;
day=gChooseDate.day;
year=gChooseDate.year+firstYear;
if (SelectDay (selectDayByDay, &month, &day, &year, title)) {
gChooseDate.month=month;
gChooseDate.day=day;
gChooseDate.year=year-firstYear;
}
MemHandleUnlock(DmGetResource (strRsc, ChooseDayTitle));
}
static void DoEditWeightDialog(UInt index,Long *newIndex)
{
VoidHand recordH;
RecordPtr recordP;
Word hitButton;
FormPtr previousForm=FrmGetActiveForm();
FormPtr frm;
FieldPtr fld;
VoidHand weightH;
Word fldIndex;
DateType oldDate;
WeightType oldWeight;
CharPtr weightStr;
WeightType weight;
Boolean deleted;
*newIndex=-1;
// set dialog date to record date
recordH=TimberQueryRecord(gTimberDB,index);
recordP=TimberHandleLock(recordH);
gChooseDate=recordP->date;
oldDate=recordP->date;
oldWeight=recordP->weight;
MemHandleUnlock(recordH);
// set dialog weight to record weight
frm=FrmInitForm(TimberEditForm);
fld=FrmGetObjectPtr(frm,FrmGetObjectIndex(frm,EditWeightField));
weightH=MemHandleNew(WeightSize);
if(!weightH){
FrmAlert(MemoryFullAlert);
return;
}
weightStr=TimberHandleLock(weightH);
WeightToAscii(weightStr,oldWeight,UseMaxAndCut);
FldSetText(fld,weightH,0,WeightSize);
FldSetSelection(fld,0,StrLen(weightStr));
// and on we go
EditWeightDialogDrawDate();
fldIndex=GetObjectIdxFromAny(TimberEditForm,EditWeightField);
FrmSetFocus(frm,fldIndex);
FrmSetEventHandler(frm, TimberEditFormHandleEvent);
hitButton=FrmDoDialog(frm);
if(hitButton==EditOKButton){
AsciiToWeight(weightStr,&weight);
ChangeRecord(oldDate,gChooseDate,oldWeight,weight,gPrefPtr->ReplaceAsk,
newIndex);
} else if(hitButton==EditDeleteButton) {
DeleteRecord(oldDate,gPrefPtr->DeleteAsk,&deleted);
if(deleted)
*newIndex=-2;
}
// done
if (previousForm)
FrmSetActiveForm(previousForm);
MemHandleUnlock(weightH);
FrmDeleteForm(frm);
}
static void EditWeightDialogDrawDate()
{
CharPtr dateStr;
ControlPtr ctl;
ctl=GetObjectPtrFromAny(TimberEditForm,EditDateTrigger);
dateStr=CtlGetLabel(ctl);
DateToDOWDMFormat(gChooseDate.month,
gChooseDate.day,
gChooseDate.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
CtlSetLabel(ctl,dateStr);
}
static void DoPrefDialog(void)
{
FormPtr frm;
ListPtr listPrecisionList;
ListPtr drawPrecisionList;
ControlPtr listPrecisionLabel;
ControlPtr drawPrecisionLabel;
CharPtr listPrecisionStr;
CharPtr drawPrecisionStr;
ControlPtr globalMinMaxCheck;
ControlPtr showGoalCheck;
ControlPtr showAverageCheck;
ControlPtr monthScrollCheck;
ControlPtr replaceAskCheck;
ControlPtr deleteAskCheck;
Word hitButton;
// init pointers
frm=FrmInitForm(TimberPrefForm);
listPrecisionList=GetObjectPtrFromAny(TimberPrefForm,PrefListPrecisionList);
drawPrecisionList=GetObjectPtrFromAny(TimberPrefForm,PrefDrawPrecisionList);
listPrecisionLabel=GetObjectPtrFromAny(TimberPrefForm,
PrefListPrecisionTrigger);
drawPrecisionLabel=GetObjectPtrFromAny(TimberPrefForm,
PrefDrawPrecisionTrigger);
listPrecisionStr=CtlGetLabel(listPrecisionLabel);
drawPrecisionStr=CtlGetLabel(drawPrecisionLabel);
globalMinMaxCheck=GetObjectPtrFromAny(TimberPrefForm,PrefGlobalMinMaxCheck);
showGoalCheck=GetObjectPtrFromAny(TimberPrefForm,PrefShowGoalCheck);
showAverageCheck=GetObjectPtrFromAny(TimberPrefForm,PrefShowAverageCheck);
monthScrollCheck=GetObjectPtrFromAny(TimberPrefForm,PrefMonthScrollCheck);
replaceAskCheck=GetObjectPtrFromAny(TimberPrefForm,PrefReplaceAskCheck);
deleteAskCheck=GetObjectPtrFromAny(TimberPrefForm,PrefDeleteAskCheck);
// init values
LstSetSelection(listPrecisionList,gPrefPtr->ListPrecision);
LstSetSelection(drawPrecisionList,gPrefPtr->DrawPrecision);
listPrecisionStr[0]=gPrefPtr->ListPrecision+'0';
drawPrecisionStr[0]=gPrefPtr->DrawPrecision+'0';
CtlSetLabel(listPrecisionLabel,listPrecisionStr);
CtlSetLabel(drawPrecisionLabel,drawPrecisionStr);
CtlSetValue(globalMinMaxCheck,gPrefPtr->GlobalMinMax);
CtlSetValue(showGoalCheck,gPrefPtr->ShowGoal);
CtlSetValue(showAverageCheck,gPrefPtr->ShowAverage);
CtlSetValue(monthScrollCheck,gPrefPtr->MonthScroll);
CtlSetValue(replaceAskCheck,gPrefPtr->ReplaceAsk);
CtlSetValue(deleteAskCheck,gPrefPtr->DeleteAsk);
if(FrmDoDialog(frm)==PrefOKButton){
// retrieve new values
gPrefPtr->ListPrecision=LstGetSelection(listPrecisionList);
gPrefPtr->DrawPrecision=LstGetSelection(drawPrecisionList);
gPrefPtr->GlobalMinMax=CtlGetValue(globalMinMaxCheck);
gPrefPtr->ShowGoal=CtlGetValue(showGoalCheck);
gPrefPtr->ShowAverage=CtlGetValue(showAverageCheck);
gPrefPtr->MonthScroll=CtlGetValue(monthScrollCheck);
gPrefPtr->ReplaceAsk=CtlGetValue(replaceAskCheck);
gPrefPtr->DeleteAsk=CtlGetValue(deleteAskCheck);
}
FrmDeleteForm(frm);
}
static void DoGoalDialog()
{
Word hitButton;
FormPtr previousForm=FrmGetActiveForm();
FormPtr frm;
FieldPtr startFld,endFld;
VoidHand startWeightH,endWeightH;
Word startFldIndex,endFldIndex;
CharPtr startWeightStr,endWeightStr;
WeightType startWeight,endWeight;
RecordType oldStart, oldEnd;
/*
There are some seemingly unnecessary labels without contents in this
form. Without them, some of the necessary ones would not shuw up in
POSE.
I suspect this to be a bug either in pilrc or in the 3.0 debug rom.
*/
frm=FrmInitForm(TimberGoalForm);
// backup for cancel
oldStart=gPrefPtr->GoalStart;
oldEnd=gPrefPtr->GoalEnd;
// set start weight
startFld=FrmGetObjectPtr(frm,FrmGetObjectIndex(frm,GoalStartWeightField));
startWeightH=MemHandleNew(WeightSize);
if(!startWeightH){
FrmAlert(MemoryFullAlert);
return;
}
startWeightStr=TimberHandleLock(startWeightH);
WeightToAscii(startWeightStr,gPrefPtr->GoalStart.weight,UseMaxAndCut);
FldSetText(startFld,startWeightH,0,WeightSize);
// set end weight
endFld=FrmGetObjectPtr(frm,FrmGetObjectIndex(frm,GoalEndWeightField));
endWeightH=MemHandleNew(WeightSize);
if(!endWeightH){
FrmAlert(MemoryFullAlert);
return;
}
endWeightStr=TimberHandleLock(endWeightH);
WeightToAscii(endWeightStr,gPrefPtr->GoalEnd.weight,UseMaxAndCut);
FldSetText(endFld,endWeightH,0,WeightSize);
// and on we go
GoalDialogDrawDates();
FrmSetEventHandler(frm, TimberGoalFormHandleEvent);
hitButton=FrmDoDialog(frm);
if(hitButton==GoalOKButton){
// startWeightStr=FldGetTextPtr(GetObjectPtrFromAny(TimberGoalForm,
// GoalStartWeightField));
AsciiToWeight(startWeightStr,&gPrefPtr->GoalStart.weight);
//endWeightStr=FldGetTextPtr(GetObjectPtrFromAny(TimberGoalForm,
// GoalEndWeightField));
AsciiToWeight(endWeightStr,&gPrefPtr->GoalEnd.weight);
gPrefPtr->ShowGoal=true;
} else {
gPrefPtr->GoalStart=oldStart;
gPrefPtr->GoalEnd=oldEnd;
}
// done
if (previousForm)
FrmSetActiveForm(previousForm);
MemHandleUnlock(startWeightH);
MemHandleUnlock(endWeightH);
FrmDeleteForm(frm);
}
static void GoalDialogDrawDates(void)
{
CharPtr dateStr;
ControlPtr ctl;
// set start date
ctl=GetObjectPtrFromAny(TimberGoalForm,GoalStartDateTrigger);
dateStr=CtlGetLabel(ctl);
if(gPrefPtr->GoalStart.date.day==0){
gPrefPtr->GoalStart.date=gViewDate;
gPrefPtr->GoalStart.date.day=1;
}
DateToDOWDMFormat(gPrefPtr->GoalStart.date.month,
gPrefPtr->GoalStart.date.day,
gPrefPtr->GoalStart.date.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
CtlSetLabel(ctl,dateStr);
// set end date
ctl=GetObjectPtrFromAny(TimberGoalForm,GoalEndDateTrigger);
dateStr=CtlGetLabel(ctl);
if(gPrefPtr->GoalEnd.date.day==0){
gPrefPtr->GoalEnd.date=gViewDate;
gPrefPtr->GoalEnd.date.day=DaysInMonth(gViewDate.month,
gViewDate.year+firstYear);
}
DateToDOWDMFormat(gPrefPtr->GoalEnd.date.month,
gPrefPtr->GoalEnd.date.day,
gPrefPtr->GoalEnd.date.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
CtlSetLabel(ctl,dateStr);
}
static void DoDeleteDialog(Boolean *updateView)
{
ULong seconds;
Word hitButton;
FormPtr previousForm=FrmGetActiveForm();
FormPtr frm;
DateType oldDate;
WeightType oldWeight;
ControlPtr ctl;
Long index;
Boolean isNew;
if(updateView)
*updateView=false;
// set dialog date to actual system date
seconds=TimGetSeconds();
DateSecondsToDate(seconds,&gChooseDate);
// set dialog weight to record weight
frm=FrmInitForm(TimberDeleteForm);
// uncheck prior checkbox
ctl=FrmGetObjectPtr(frm,FrmGetObjectIndex(frm,EditDeletePriorCheck));
CtlSetValue(ctl,false);
// and on we go
DeleteDialogDrawDate();
FrmSetEventHandler(frm, TimberDeleteFormHandleEvent);
hitButton=FrmDoDialog(frm);
if(hitButton==EditDeleteOKButton){
if(CtlGetValue(ctl)){
index=FindRecord(gChooseDate,&isNew);
if(isNew)
index--;
if((index>=0)&&(index<DmNumRecords(gTimberDB))){
if(index==0){
if(isNew){
VoidHand recordH;
RecordPtr recordP;
recordH=TimberQueryRecord(gTimberDB,0);
recordP=TimberHandleLock(recordH);
gChooseDate=recordP->date;
MemHandleUnlock(recordH);
}
DeleteRecord(gChooseDate,gPrefPtr->DeleteAsk,updateView);
} else {
StrIToA(gBuf1,++index);
if(FrmCustomAlert(DeleteOldAlert,gBuf1," "," ")==0){
while(index--)
DmRemoveRecord(gTimberDB,0);
if(updateView)
*updateView=true;
}
}
}
} else
DeleteRecord(gChooseDate,gPrefPtr->DeleteAsk,updateView);
}
// done
if (previousForm)
FrmSetActiveForm(previousForm);
FrmDeleteForm(frm);
}
static void DeleteDialogDrawDate(void)
{
CharPtr dateStr;
ControlPtr ctl;
ctl=GetObjectPtrFromAny(TimberDeleteForm,EditDeleteDateTrigger);
dateStr=CtlGetLabel(ctl);
DateToDOWDMFormat(gChooseDate.month,
gChooseDate.day,
gChooseDate.year+firstYear,
gPrefPtr->DateFormat,
dateStr);
CtlSetLabel(ctl,dateStr);
}
//
// helpful system shortcuts:
//
static Word GetObjectIdxFromActive(Word objectID)
{
return FrmGetObjectIndex(FrmGetActiveForm(), objectID);
}
static Word GetObjectIdxFromAny(Word formID, Word objectID)
{
FormPtr form = FrmGetFormPtr(formID);
return FrmGetObjectIndex(form, objectID);
}
static VoidPtr GetObjectPtrFromActive(Word objectID)
{
FormPtr currentForm = FrmGetActiveForm();
return FrmGetObjectPtr(currentForm,
FrmGetObjectIndex(currentForm, objectID));
}
static VoidPtr GetObjectPtrFromAny(Word formID, Word objectID)
{
FormPtr form = FrmGetFormPtr(formID);
return FrmGetObjectPtr(form,
FrmGetObjectIndex(form,objectID));
}
//
// debugging:
//
static void DoDebugAlertInt(CharPtr s1, Long i)
{
StrIToA(gBuf1,i);
FrmCustomAlert(DebugAlert3,s1,gBuf1," ");
}
static void DoDebugAlertInt2(CharPtr s1, Long i, Long j)
{
StrIToA(gBuf1,i);
StrIToA(gBuf2,j);
FrmCustomAlert(DebugAlert3,s1,gBuf1,gBuf2);
}
static void DoDebugAlert1(CharPtr s1)
{
FrmCustomAlert(DebugAlert3,s1," "," ");
}
static void DoDebugAlert2(CharPtr s1, CharPtr s2)
{
FrmCustomAlert(DebugAlert3,s1,s2," ");
}
static void DoDebugAlert3(CharPtr s1, CharPtr s2, CharPtr s3)
{
FrmCustomAlert(DebugAlert3,s1,s2,s3);
}
static VoidHand TimberQueryRecord(DmOpenRef dbR,UInt index)
{
ErrFatalDisplayIf(index>=DmNumRecords(dbR),"Query tried index too high");
return DmQueryRecord(dbR,index);
}
static VoidHand TimberGetRecord(DmOpenRef dbR,UInt index)
{
ErrFatalDisplayIf(index>=DmNumRecords(dbR),"Get tried index too high");
return DmGetRecord(dbR,index);
}
static VoidPtr TimberHandleLock(VoidHand h)
{
VoidPtr r;
ErrFatalDisplayIf(!h,"Tried to lock NULL handle");
r=MemHandleLock(h);
ErrFatalDisplayIf(!r,"Tried to lock illegal handle");
return r;
}