1818 lines
57 KiB
C
1818 lines
57 KiB
C
/*
|
|
DAYS.C
|
|
|
|
Written by DavidW
|
|
Started on 4/12/91
|
|
*/
|
|
|
|
#include <p_std.h> /* basic Psion header file */
|
|
#include <p_file.h> /* defines E_FILE_ error values, etc */
|
|
#include <p_dbf.h> /* defines DbfXXX functions */
|
|
#include <p_date.h> /* defines date and time functions */
|
|
#include <p_config.h> /* defines E_CONFIG struct */
|
|
#include <epoc.h> /* general Epoc definitions */
|
|
#include <wlib.h> /* defines al Window Server library functions */
|
|
#include <hwif.h> /* defines all Hwif library functions */
|
|
|
|
GLREF_D UWORD DatLocked; /* non-zero when application "busy" */
|
|
GLREF_D TEXT *DatUsedPathNamePtr; /* full path name of current file */
|
|
|
|
LOCAL_D TEXT *cmds[]=
|
|
{ /* the commands in the menu bar */
|
|
"nNew",
|
|
"oOpen",
|
|
"mMerge",
|
|
"aSave as",
|
|
"kCompress",
|
|
"xExit",
|
|
"iInsert text",
|
|
"cCopy text",
|
|
"vEvaluate",
|
|
"hShow symbols",
|
|
"sSave",
|
|
"rRevert",
|
|
"eEnter anniversary",
|
|
"dDelete anniversary",
|
|
"uChange date",
|
|
"fFind",
|
|
"gFind next",
|
|
"bFind back",
|
|
"tFind date",
|
|
"jJump to",
|
|
"lList view",
|
|
"wWander through",
|
|
"pPrint",
|
|
"yPrint setup",
|
|
NULL
|
|
};
|
|
|
|
#define FILE_ITEMS 6 /* how many items in each menu */
|
|
#define EDIT_ITEMS 6
|
|
#define CHANGE_ITEMS 3
|
|
#define SEARCH_ITEMS 5
|
|
#define SPECIAL_ITEMS 4
|
|
|
|
#define ITEMS_BEFORE_FILE 0
|
|
#define ITEMS_BEFORE_EDIT FILE_ITEMS
|
|
#define ITEMS_BEFORE_CHANGE (ITEMS_BEFORE_EDIT+EDIT_ITEMS)
|
|
#define ITEMS_BEFORE_SEARCH (ITEMS_BEFORE_CHANGE+CHANGE_ITEMS)
|
|
#define ITEMS_BEFORE_SPECIAL (ITEMS_BEFORE_SEARCH+SEARCH_ITEMS)
|
|
|
|
#define LIST_ITEM ITEMS_BEFORE_SPECIAL
|
|
#define SYMBOLS_ITEM ITEMS_BEFORE_EDIT+3
|
|
|
|
LOCAL_D H_MENU_DATA mdata[]=
|
|
{ /* the menus in the menu bar */
|
|
"File",FILE_ITEMS,
|
|
"Edit",EDIT_ITEMS,
|
|
"Change",CHANGE_ITEMS,
|
|
"Search",SEARCH_ITEMS,
|
|
"Special",SPECIAL_ITEMS,
|
|
NULL
|
|
};
|
|
|
|
GLDEF_D TEXT ** _cmds=(&cmds[0]); /* Hwif code expects this */
|
|
GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]); /* Hwif code expects this */
|
|
|
|
LOCAL_D UINT MainWid; /* ID of main window */
|
|
|
|
LOCAL_D struct
|
|
{ /* format of data at start of Days DBF file */
|
|
UWORD dataStart;
|
|
UWORD needVersion;
|
|
UWORD firHeader;
|
|
UBYTE fir[3];
|
|
} ModelHeader=
|
|
{
|
|
DbfHeaderLength,
|
|
0x100f, /* DBF code version number required */
|
|
(DbfRecordTypeFir<<12)|3, /* 3 fields defined */
|
|
{
|
|
DbfFieldTypeWord, /* word field ("DayInYear") */
|
|
DbfFieldTypeString, /* string field ("name") */
|
|
DbfFieldTypeString /* string field ("notes") */
|
|
}
|
|
};
|
|
|
|
LOCAL_D TEXT filename[P_FNAMESIZE]; /* for current filename */
|
|
LOCAL_D VOID *dH; /* handle for DbfXXX services */
|
|
LOCAL_D UBYTE dBuf[512]; /* buffer used by DbfXXX services */
|
|
LOCAL_D UWORD dOff; /* current offset into dBuf[] */
|
|
|
|
typedef struct
|
|
{ /* structure of INDex ENTry */
|
|
UWORD diy; /* no of Day In Year */
|
|
UWORD no; /* no of record in file (secondary key) */
|
|
} INDENT;
|
|
|
|
LOCAL_D INDENT index[500]; /* cope with up to 500 entries */
|
|
LOCAL_D WORD count; /* how many entries */
|
|
LOCAL_D WORD where; /* current entry */
|
|
|
|
LOCAL_D WORD top; /* entry at top of screen (list view) */
|
|
LOCAL_D UWORD ViewList=FALSE; /* TRUE if in list view */
|
|
|
|
LOCAL_D VOID *edit[3]; /* the three editors */
|
|
LOCAL_D UWORD show_statwin=TRUE; /* whether Status Window is showing */
|
|
LOCAL_D UWORD ScreenWidth; /* width of main display area */
|
|
LOCAL_D INT emph=0; /* which editor is emphasised */
|
|
|
|
LOCAL_D UWORD lastbflags=W_BORD_CORNER_4; /* state of border flags */
|
|
|
|
LOCAL_D UWORD ShowSymbols=FALSE; /* whether editors display symbols */
|
|
|
|
LOCAL_D WORD currdiy; /* Day In Year of current entry */
|
|
LOCAL_D WORD origdiy; /* currdiy before operation started */
|
|
LOCAL_D WORD dummdiy; /* DIY of dummy entry (placeholder for real one) */
|
|
|
|
LOCAL_D WORD DummyEntry=FALSE; /* whether dummy entry in place */
|
|
LOCAL_D WORD lastchanged=FALSE; /* last state of "changed" flag */
|
|
|
|
LOCAL_D UBYTE daysim[]={31,29,31,30,31,30,31,31,30,31,30,31};
|
|
|
|
LOCAL_D TEXT find[20]={0}; /* the current find string */
|
|
LOCAL_D UWORD findtype=1; /* which type of find is being done */
|
|
|
|
LOCAL_D UWORD PrintNamesOnly=1; /* whether only to print names */
|
|
LOCAL_D UWORD PrintRec; /* which record is being printed */
|
|
LOCAL_D UWORD PrintState; /* which part of the record is being printed */
|
|
LOCAL_D UBYTE *PrintBuf; /* the text being printed */
|
|
LOCAL_D WORD PrintLen; /* length of text being printed */
|
|
LOCAL_D WORD PrintIndent; /* indent before text being printed */
|
|
LOCAL_D TEXT PrintDate[40]; /* text of date of entry being printed */
|
|
|
|
LOCAL_D UWORD tly[]={0,17,35}; /* top left y-positions of three editors */
|
|
LOCAL_D UWORD bry[]={15,32,80}; /* bottom right y-positions of editors */
|
|
|
|
|
|
LOCAL_C VOID DrawBorder(INT i)
|
|
{ /* draw border round i-th editor and emphasise */
|
|
P_RECT rect; /* appropriate rectangle */
|
|
|
|
rect.tl.x=0;
|
|
rect.br.x=ScreenWidth;
|
|
if (!i)
|
|
rect.br.x-=54;
|
|
else if (i==1)
|
|
rect.br.x-=10;
|
|
rect.tl.y=tly[i];
|
|
rect.br.y=bry[i];
|
|
gBorderRect(&rect, /* should border be emphasised? */
|
|
W_BORD_CORNER_4|W_BORD_SHADOW_S|(i==emph? W_BORD_SHADOW_ON: 0));
|
|
hEBEmphasise(edit[i],i==emph); /* emphasise or de-emphasise editor */
|
|
}
|
|
|
|
LOCAL_C VOID DrawWhereAndCount(VOID)
|
|
{ /* draw the text "n/m" */
|
|
TEXT buf[10];
|
|
P_RECT box; /* where to draw the text */
|
|
|
|
p_atos(&buf[0],"%d/%d",where+1,count); /* construct text to display */
|
|
box.tl.x=ScreenWidth-54;
|
|
box.tl.y=2;
|
|
box.br.x=ScreenWidth;
|
|
box.br.y=12;
|
|
gPrintBoxText(&box,8,G_TEXT_ALIGN_CENTRE,0,buf,p_slen(buf));
|
|
}
|
|
|
|
LOCAL_C INT CheckIfChanged(VOID)
|
|
{ /* return TRUE if current entry has been changed */
|
|
if (ViewList)
|
|
return(0);
|
|
return(origdiy!=currdiy
|
|
|| hEBSenseChanged(edit[1]) || hEBSenseChanged(edit[2]));
|
|
}
|
|
|
|
LOCAL_C INT FindMonNo(INT *pdiy)
|
|
{ /* find month number corresponding to day-in-year */
|
|
INT monno;
|
|
|
|
monno=0;
|
|
while (*pdiy>=daysim[monno])
|
|
(*pdiy)-=daysim[monno++];
|
|
return(monno);
|
|
}
|
|
|
|
LOCAL_C VOID DiyToBuf(INT diy,TEXT *pb)
|
|
{ /* get full textual representation of day in year */
|
|
E_CONFIG cfg; /* current system defaults */
|
|
TEXT mon[32]; /* name of month */
|
|
TEXT suff[31][3]; /* numerical suffices */
|
|
|
|
p_nmmon(&mon[0],FindMonNo(&diy));
|
|
p_getsuffixes(&suff[0][0]);
|
|
p_getctd(&cfg);
|
|
if (cfg.dateType==E_DATE_EUROPE)
|
|
p_atos(pb,"%u%s %s",diy+1,&suff[diy][0],&mon[0]);
|
|
else
|
|
p_atos(pb,"%s %u%s",&mon[0],diy+1,&suff[diy][0]);
|
|
}
|
|
|
|
LOCAL_C VOID DiyToShortBuf(INT diy,TEXT *pb)
|
|
{ /* get short textual representation of day in year */
|
|
INT mon;
|
|
E_CONFIG cfg; /* to find date separator */
|
|
INT first; /* either day number or month number */
|
|
INT second; /* the other */
|
|
|
|
mon=FindMonNo(&diy)+1;
|
|
diy++;
|
|
p_getctd(&cfg);
|
|
if (cfg.dateType==E_DATE_EUROPE)
|
|
{
|
|
first=diy;
|
|
second=mon;
|
|
}
|
|
else
|
|
{
|
|
first=mon;
|
|
second=diy;
|
|
}
|
|
p_atos(pb,"%u%c%u",first,cfg.dateSeparator,second);
|
|
}
|
|
|
|
LOCAL_C INT SetDateText(INT diy)
|
|
{ /* set date text into the date "editor" */
|
|
TEXT date[40];
|
|
|
|
DiyToBuf(diy,&date[0]);
|
|
return(hEBSetText(edit[0],&date[0],p_slen(&date[0])));
|
|
}
|
|
|
|
LOCAL_C VOID ClearChangedFlags(VOID)
|
|
{ /* acknowledge that changes have been absorbed */
|
|
origdiy=currdiy;
|
|
hEBClearChanged(edit[1]);
|
|
hEBClearChanged(edit[2]);
|
|
}
|
|
|
|
LOCAL_C VOID ZeroBufferStart(VOID)
|
|
{ /* put dummy entry at start of dBuf[] */
|
|
*(UWORD *)(&dBuf[2])=dummdiy;
|
|
*(UWORD *)(&dBuf[4])=0;
|
|
dOff=0;
|
|
DbfTrash(dH);
|
|
}
|
|
|
|
LOCAL_C VOID Check(INT val)
|
|
{ /* terminate application on file error */
|
|
TEXT buf[64];
|
|
|
|
if (val<0 && val!=E_FILE_EOF)
|
|
{
|
|
uForceToFront(); /* come into foreground */
|
|
DatLocked=TRUE;
|
|
p_errs(&buf[0],val); /* get error string */
|
|
wsAlertW(WS_ALERT_CLIENT,&buf[0],"Terminating application",0);
|
|
p_exit(0); /* exit cleanly */
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID SeekTo(UINT current)
|
|
{ /* read the specified record into dBuf[] */
|
|
Check(DbfAbsRead(dH,current,&dOff));
|
|
}
|
|
|
|
LOCAL_C INT LoadBuffer(INT j)
|
|
{ /* read the specified record (maybe dummy) into dBuf[] */
|
|
INT no;
|
|
|
|
if (j>=count)
|
|
return(-1); /* no such record */
|
|
no=index[j].no;
|
|
if (DummyEntry && no==count-1)
|
|
ZeroBufferStart(); /* record in process of being added */
|
|
else
|
|
SeekTo(no); /* real record */
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C VOID LoadEditors(VOID)
|
|
{ /* load editors in preparation to edit current entry */
|
|
UBYTE *psrc; /* points into dBuf[] */
|
|
INT len; /* length of text field */
|
|
|
|
LoadBuffer(where); /* read current record into dBuf[] */
|
|
psrc=(&dBuf[dOff+2]); /* position psrc to start of record */
|
|
ClearChangedFlags(); /* no changes made yet */
|
|
DrawWhereAndCount(); /* display new "n/m" text */
|
|
origdiy=currdiy=(*(UWORD *)psrc); /* read the Day In Year */
|
|
if (SetDateText(currdiy)) /* set text of date "editor" */
|
|
return;
|
|
psrc+=2; /* increment to first text field */
|
|
len=(*psrc); /* length of first text field */
|
|
if (hEBSetText(edit[1],(TEXT *)psrc+1,len))
|
|
return;
|
|
psrc+=len+1; /* increment to second text field */
|
|
hEBSetText(edit[2],(TEXT *)psrc+1,*psrc);
|
|
}
|
|
|
|
LOCAL_C INT AddMonthChoiceList(UWORD *pmonno)
|
|
{ /* add choice list of all month names to current dialog */
|
|
H_DI_CHOICE ch;
|
|
TEXT mon[32]; /* for name of current month */
|
|
INT i;
|
|
|
|
if (uBeginDCL(&ch))
|
|
return(-1);
|
|
for (i=0; i<12; i++)
|
|
{ /* for each month */
|
|
p_nmmon(&mon[0],i); /* look up month name */
|
|
if (uGrowDCL(&ch,&mon[0])) /* try to add next entry */
|
|
return(-1);
|
|
}
|
|
return(uAddDCL("Month",pmonno,&ch));
|
|
}
|
|
|
|
LOCAL_C INT FindDiy(INT monno,INT dayinm)
|
|
{ /* find DayInYear for given day in given month */
|
|
while (monno)
|
|
dayinm+=daysim[--monno];
|
|
return(dayinm);
|
|
}
|
|
|
|
LOCAL_C VOID IndexDelete(VOID)
|
|
{ /* delete an item from the index */
|
|
UWORD deleted; /* the record number of item deleted */
|
|
UWORD i;
|
|
INDENT *pindent;
|
|
UWORD tomove;
|
|
|
|
deleted=index[where].no;
|
|
count--; /* decrement total count number */
|
|
tomove=count-where; /* how many index entries to move to close gap */
|
|
p_bcpy(&index[where],&index[where+1],tomove*sizeof(INDENT));
|
|
pindent=(&index[0]); /* to scan through all index entries */
|
|
i=count;
|
|
while (i--)
|
|
{
|
|
if (pindent->no>deleted)
|
|
(pindent->no)--; /* since this record number now one less */
|
|
pindent++;
|
|
}
|
|
}
|
|
|
|
LOCAL_C UWORD FindKey(VOID)
|
|
{ /* read the DayInYear of the current entry */
|
|
return(*(UWORD *)(&dBuf[dOff+2]));
|
|
}
|
|
|
|
LOCAL_C INT compare(INDENT *p1,INDENT *p2)
|
|
{ /* find which of two entries is first in order */
|
|
UWORD diff;
|
|
|
|
diff=p1->diy-p2->diy;
|
|
return(diff? diff: p1->no-p2->no);
|
|
}
|
|
|
|
LOCAL_C INT cmp(INT r,VOID *pindent)
|
|
{ /* routine expected by p_bsrch */
|
|
return(compare(pindent,&index[r]));
|
|
}
|
|
|
|
LOCAL_C INT LocateByDate(INDENT *pent)
|
|
{ /* locate index position matching (or nearest after) given entry */
|
|
INT dir; /* direction to nearest hit (as given by p_bsrch) */
|
|
INT mid; /* nearest hit (as given by p_bsrch) */
|
|
|
|
if (!count)
|
|
mid=0;
|
|
else
|
|
{
|
|
dir=p_bsrch(count,cmp,&mid,pent);
|
|
if (dir>0)
|
|
mid++;
|
|
}
|
|
return(mid);
|
|
}
|
|
|
|
LOCAL_C VOID IndexAppend()
|
|
{ /* add index entry for new record at end of file */
|
|
INT mid;
|
|
UWORD tomove;
|
|
INDENT new;
|
|
|
|
new.no=count; /* new record added at end of file */
|
|
new.diy=currdiy;
|
|
mid=LocateByDate(&new); /* find where to insert index entry */
|
|
tomove=count-mid; /* how many entries to move down */
|
|
count++; /* increment total count of records */
|
|
p_bcpy(&index[mid+1],&index[mid],tomove*sizeof(INDENT));
|
|
index[mid]=new; /* write in the new entry */
|
|
where=mid; /* this entry is now current */
|
|
}
|
|
|
|
LOCAL_C VOID IndexUpdate(VOID)
|
|
{ /* update index entry for record updated */
|
|
IndexDelete(); /* delete the old entry... */
|
|
IndexAppend(); /* ...and construct a new one */
|
|
}
|
|
|
|
LOCAL_C INT Try(INT ret,TEXT *msg)
|
|
{ /* in case of file error, give user chance to retry */
|
|
TEXT buf[64];
|
|
|
|
if (ret>=0)
|
|
return(0); /* no error */
|
|
uForceToFront(); /* come to foreground */
|
|
DatLocked=TRUE; /* mark application as "busy" */
|
|
p_errs(&buf[0],ret);
|
|
if (wsAlertW(WS_ALERT_CLIENT,msg,&buf[0],"Continue","Exit",0))
|
|
p_exit(0); /* user is willing to exit application */
|
|
DatLocked=FALSE;
|
|
return(-1);
|
|
}
|
|
|
|
LOCAL_C VOID SeekToCurrent(VOID)
|
|
{ /* read the current record into dBuf[] */
|
|
SeekTo(index[where].no);
|
|
}
|
|
|
|
LOCAL_C INT DoUpdate(INT len)
|
|
{ /* user has finished updating record */
|
|
INT state;
|
|
|
|
if (DummyEntry)
|
|
{ /* was editing dummy record - so append real one */
|
|
if (Try(DbfAppend(dH,len),"Failed to save changes"))
|
|
return(-1);
|
|
DummyEntry=FALSE;
|
|
}
|
|
else
|
|
{
|
|
SeekToCurrent(); /* find the record to update */
|
|
state=DbfStateDisabled; /* instant update */
|
|
if (Try(DbfUpdate(&state,dH,len),"Failed to save changes"))
|
|
return(-1);
|
|
}
|
|
IndexUpdate(); /* update the corresponding index entry */
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C VOID EditEmphasise(INT flag)
|
|
{ /* pass emphasis or de-emphasis message to current editor */
|
|
if (!ViewList)
|
|
hEBEmphasise(edit[emph],flag);
|
|
} /* else no editors */
|
|
|
|
LOCAL_C INT RunDialog(VOID)
|
|
{ /* layer round dialog code to handle cursor flashing */
|
|
INT ret;
|
|
|
|
EditEmphasise(FALSE); /* remove any flashing cursor */
|
|
ret=uRunDialog(); /* run the dialog */
|
|
EditEmphasise(TRUE); /* reinstate any flashing cursor */
|
|
return(ret);
|
|
}
|
|
|
|
LOCAL_C INT Confirm(TEXT *pb)
|
|
{ /* present a "No/Yes" dialog */
|
|
if (uOpenDialog(pb)) /* title text supplied by caller */
|
|
return(-1);
|
|
if (uAddButtonList("No",-'n',"Yes",'y',NULL))
|
|
return(-1);
|
|
return(RunDialog()!='y'); /* return TRUE iff user answered Yes */
|
|
}
|
|
|
|
LOCAL_C INT SizeRecord(VOID)
|
|
{ /* return the length of first text field in current record */
|
|
return(*(UWORD *)&dBuf[dOff+4]);
|
|
}
|
|
|
|
LOCAL_C VOID AddDummyEntry()
|
|
{ /* add index position for record in process of being defined */
|
|
DummyEntry=TRUE;
|
|
dummdiy=currdiy;
|
|
IndexAppend();
|
|
}
|
|
|
|
LOCAL_C INT CalculateBflags(VOID)
|
|
{ /* find whether scroll arrows should be displayed on border */
|
|
INT bflags;
|
|
|
|
if (top) /* check if more records off top of screen */
|
|
bflags=W_BORD_CORNER_4|W_BORD_TOP_ON;
|
|
else
|
|
bflags=W_BORD_CORNER_4|W_BORD_TOP_OFF;
|
|
if (top+8<count) /* check if more records off bottom of screen */
|
|
bflags|=W_BORD_BOT_ON;
|
|
else
|
|
bflags|=W_BORD_BOT_OFF;
|
|
return(bflags);
|
|
}
|
|
|
|
LOCAL_C VOID LoadYs(P_RECT *pbox,INT y)
|
|
{ /* load top and bottom y-values for given screen line */
|
|
pbox->tl.y=4+y*9;
|
|
pbox->br.y=pbox->tl.y+9;
|
|
}
|
|
|
|
LOCAL_C VOID LineToScreen(INT y,INT x1,INT x2,INT align,TEXT *pb,INT tlen)
|
|
{ /* utility layer around gPrintBoxText */
|
|
P_RECT box;
|
|
|
|
box.tl.x=x1;
|
|
box.br.x=x2;
|
|
LoadYs(&box,y);
|
|
gPrintBoxText(&box,8,align,0,pb,tlen);
|
|
}
|
|
|
|
LOCAL_C VOID ClrLine(INT y)
|
|
{ /* clear a line on the screen */
|
|
P_RECT box;
|
|
|
|
box.tl.x=4;
|
|
box.br.x=ScreenWidth-4;
|
|
LoadYs(&box,y);
|
|
gClrRect(&box,G_TRMODE_CLR);
|
|
}
|
|
|
|
LOCAL_C VOID SetBold(INT flag)
|
|
{ /* prepare to print in bold (or in non-bold) */
|
|
G_GC gc;
|
|
|
|
gc.font=WS_FONT_BASE+flag;
|
|
gSetGC(0,G_GC_MASK_FONT,&gc);
|
|
}
|
|
|
|
LOCAL_C VOID GetCursorBox(INT i,P_RECT *pbox)
|
|
{ /* get rectangle to draw cursor for specified entry */
|
|
pbox->tl.x=4;
|
|
pbox->br.x=10;
|
|
LoadYs(pbox,i);
|
|
}
|
|
|
|
LOCAL_C VOID DrawCursor(INT i,INT on)
|
|
{ /* draw (or clear) cursor alongside given entry */
|
|
P_RECT box;
|
|
|
|
GetCursorBox(i,&box);
|
|
gPrintBoxText(&box,8,G_TEXT_ALIGN_LEFT,0,"\034",on);
|
|
}
|
|
|
|
LOCAL_C VOID DrawLine(INT i)
|
|
{ /* display a given entry on a line on screen */
|
|
INT entno;
|
|
UBYTE *psrc; /* pointer into dBuf[] */
|
|
TEXT date[6]; /* for short textual representation of date */
|
|
|
|
entno=i+top; /* offset by no of entry at screen top */
|
|
if (LoadBuffer(entno))
|
|
{ /* no such entry */
|
|
ClrLine(i);
|
|
return;
|
|
}
|
|
psrc=(&dBuf[dOff+2]); /* point to start of record */
|
|
DiyToShortBuf(*(UWORD *)psrc,&date[0]); /* get short date text */
|
|
DrawCursor(i,entno==where); /* draw or clear cursor */
|
|
SetBold(TRUE); /* draw date in bold */
|
|
LineToScreen(i,14,49,G_TEXT_ALIGN_RIGHT,&date[0],p_slen(&date[0]));
|
|
psrc+=2; /* position to first text field */
|
|
SetBold(FALSE); /* print remainder in non-bold */
|
|
LineToScreen(i,54,ScreenWidth-4,G_TEXT_ALIGN_LEFT,(TEXT *)psrc+1,*psrc);
|
|
}
|
|
|
|
LOCAL_C VOID ListDisplay(VOID)
|
|
{ /* redraw all visible entries (in list view) */
|
|
INT i;
|
|
|
|
for (i=0; i<8; i++)
|
|
DrawLine(i);
|
|
}
|
|
|
|
LOCAL_C VOID WholeListDisplay(VOID)
|
|
{ /* re-display whole screen (in list view) */
|
|
if (top+8>count)
|
|
top=count-8; /* wasted spaced at end of display */
|
|
if (top<0)
|
|
top=0;
|
|
if (where<top)
|
|
top=where; /* ensure current record on screen */
|
|
else if (where>top+7)
|
|
top=where-7;
|
|
lastbflags=CalculateBflags();
|
|
gBorder(lastbflags); /* draw border */
|
|
ListDisplay(); /* draw the entries themselves */
|
|
}
|
|
|
|
LOCAL_C INT LookFor(UBYTE *pb)
|
|
{ /* look for find text in given text field */
|
|
return(p_bsubi((TEXT *)pb+1,*pb,&find[1],find[0]));
|
|
}
|
|
|
|
LOCAL_C VOID RotateTo(INT newemph)
|
|
{ /* change which editor is emphasised */
|
|
INT oldemph;
|
|
|
|
if (newemph!=emph)
|
|
{
|
|
oldemph=emph;
|
|
emph=newemph;
|
|
DrawBorder(oldemph); /* clear former emphasis */
|
|
DrawBorder(newemph); /* apply new emphasis */
|
|
}
|
|
}
|
|
|
|
LOCAL_C INT SaveChanges(VOID)
|
|
{ /* save changes made to current record */
|
|
INT len1; /* length of first text field */
|
|
INT len2; /* length of second text field */
|
|
UBYTE *pb; /* pointer into dBuf[] */
|
|
TEXT *psrc; /* pointer into editor's text */
|
|
|
|
pb=(&dBuf[2]); /* start at beginning of dBuf[] */
|
|
*(UWORD *)pb=currdiy; /* fill in word DIY field */
|
|
pb+=2; /* position to first text field */
|
|
psrc=hEBSenseText(edit[1]); /* sense text in editor */
|
|
len1=p_slen(psrc);
|
|
*pb++=len1; /* record the length of the text */
|
|
pb=p_bcpy(pb,psrc,len1); /* record the text itself */
|
|
psrc=hEBSenseText(edit[2]); /* sense text in next editor */
|
|
len2=p_slen(psrc);
|
|
*pb++=len2; /* record the length of the text */
|
|
p_bcpy(pb,psrc,len2); /* record the text itself */
|
|
dOff=0;
|
|
if (DoUpdate(len1+len2+4)) /* give length of record being added */
|
|
return(-1);
|
|
ClearChangedFlags(); /* acknowledge editors are no longer "changed" */
|
|
DrawWhereAndCount(); /* position in index may be different now */
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C INT SaveIfChanged(VOID)
|
|
{ /* save changes made, if any */
|
|
if (!CheckIfChanged())
|
|
return(0);
|
|
return(SaveChanges());
|
|
}
|
|
|
|
LOCAL_C VOID CompressFile(VOID)
|
|
{ /* user has requested file be compressed */
|
|
UINT state;
|
|
|
|
if (!hIsDbfCompressible(dH))
|
|
wInfoMsg("Cannot compress on Flash");
|
|
else
|
|
{
|
|
state=DbfStateDisabled;
|
|
Check(DbfCompress(&state,dH));
|
|
wInfoMsg("File compressed");
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID ChangeName(TEXT *newname)
|
|
{ /* name of file being edited has changed */
|
|
p_scpy(&filename[0],newname); /* copy to own buffer */
|
|
hSetUpStatusNames(&filename[0]); /* inform system of the change */
|
|
wsUpdate(WS_UPDATE_NAME); /* force status window update */
|
|
}
|
|
|
|
LOCAL_C INT ordf(INT r1,INT r2,VOID *junk)
|
|
{ /* ordering function required by p_qsort() */
|
|
return(compare(&index[r1],&index[r2]));
|
|
}
|
|
|
|
LOCAL_C VOID excf(INT r1,INT r2,VOID *junk)
|
|
{ /* exchange function required by p_qsort() */
|
|
p_bswap(&index[r1],&index[r2],sizeof(INDENT));
|
|
}
|
|
|
|
LOCAL_C VOID BuildIndex(VOID)
|
|
{ /* build index for current file */
|
|
INDENT *pindent;
|
|
UWORD no;
|
|
|
|
no=0;
|
|
count=DbfCount(dH);
|
|
pindent=(&index[0]); /* to pass through whole index */
|
|
while (no<count)
|
|
{
|
|
SeekTo(no); /* position to given record in file */
|
|
pindent->diy=FindKey(); /* extract its DayInYear value */
|
|
pindent->no=no++; /* record secondary key */
|
|
pindent++;
|
|
}
|
|
p_qsort(no,ordf,excf,NULL); /* sort the index */
|
|
}
|
|
|
|
LOCAL_C VOID DoScroll(INT dely)
|
|
{ /* scroll part of the screen display vertically */
|
|
P_POINT offset; /* offset to scroll by */
|
|
P_RECT src; /* source region for the scroll */
|
|
|
|
offset.x=0;
|
|
offset.y=dely*9; /* each line is 9 pixels high */
|
|
src.tl.x=4;
|
|
src.br.x=ScreenWidth-4;
|
|
if (dely>0)
|
|
{ /* scrolling down - so omit display bottom from source */
|
|
src.tl.y=4;
|
|
src.br.y=4+(8-dely)*9;
|
|
}
|
|
else
|
|
{ /* scrolling up - so omit display top from source */
|
|
src.tl.y=4-dely*9;
|
|
src.br.y=4+8*9;
|
|
}
|
|
wScrollRect(MainWid,&src,&offset);
|
|
}
|
|
|
|
LOCAL_C VOID MakeHighlight(INT newcent)
|
|
{ /* move the cursor to the specified new value */
|
|
INT toscroll;
|
|
|
|
if (newcent==where)
|
|
return; /* cursor already there */
|
|
DrawCursor(where-top,FALSE); /* remove old cursor */
|
|
toscroll=top-newcent;
|
|
if (toscroll>0)
|
|
{ /* new cursor position off top of screen */
|
|
top-=toscroll;
|
|
if (toscroll<8)
|
|
DoScroll(toscroll);
|
|
else
|
|
toscroll=8; /* toscroll now gives number of lines to redraw */
|
|
while (toscroll)
|
|
DrawLine(--toscroll); /* draw lines not handled by scroll */
|
|
}
|
|
else
|
|
{
|
|
toscroll=-7-toscroll;
|
|
if (toscroll>0) /* new cursor position off bottom of screen */
|
|
{
|
|
top+=toscroll;
|
|
if (toscroll<8)
|
|
DoScroll(-toscroll);
|
|
else
|
|
toscroll=8;
|
|
while (toscroll)
|
|
DrawLine(8-toscroll--);/* draw lines not handled by scroll */
|
|
}
|
|
}
|
|
where=newcent;
|
|
DrawCursor(where-top,TRUE); /* draw cursor in new position */
|
|
}
|
|
|
|
LOCAL_C VOID NewWhere(UWORD new)
|
|
{ /* there is a new current record */
|
|
if (ViewList)
|
|
MakeHighlight(new); /* scroll if need be */
|
|
else
|
|
{ /* editors view - so change all editor contents */
|
|
where=new;
|
|
LoadEditors();
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID WholeDisplay(VOID)
|
|
{ /* the whole screen needs redrawn */
|
|
if (ViewList)
|
|
WholeListDisplay();
|
|
else
|
|
LoadEditors();
|
|
}
|
|
|
|
LOCAL_C VOID DisplayStart(VOID)
|
|
{ /* a new file needs loading and displaying */
|
|
BuildIndex();
|
|
if (!count)
|
|
AddDummyEntry();
|
|
where=0;
|
|
WholeDisplay();
|
|
}
|
|
|
|
LOCAL_C VOID ChangeOverTo(VOID *newdH,TEXT *newname)
|
|
{ /* change the file being edited */
|
|
DbfClose(dH);
|
|
dH=newdH; /* (new file is already successfully opened) */
|
|
ChangeName(newname);
|
|
DisplayStart();
|
|
}
|
|
|
|
LOCAL_C INT doOpen(VOID **pdH,TEXT *pb,INT flags,DbfHeader *pHead)
|
|
{ /* utility layer over DbfOpen */
|
|
INT state;
|
|
|
|
state=DbfStateDisabled;
|
|
p_scpy((TEXT *)&pHead->fileType[0],"OPLDatabaseFile");
|
|
return(uErrorValue(DbfOpen(&state,pdH,pb,flags,pHead,&dBuf[0],512,1)));
|
|
}
|
|
|
|
LOCAL_C INT TryOpenDbf(TEXT *pb,VOID **pdH)
|
|
{ /* save any current changes, and try to open named file */
|
|
DbfHeader Header;
|
|
|
|
if (SaveIfChanged())
|
|
return(-1);
|
|
return(doOpen(pdH,pb,P_FOPEN|P_FUPDATE|P_FRANDOM,&Header));
|
|
}
|
|
|
|
LOCAL_C VOID SetupFilename(TEXT *pb)
|
|
{ /* initialise text for editor from current filename */
|
|
p_bcpy(pb+1,DatUsedPathNamePtr,*pb=p_slen(DatUsedPathNamePtr));
|
|
}
|
|
|
|
LOCAL_C VOID OpenDbf(VOID)
|
|
{ /* user wants to open another file */
|
|
H_DI_FSEL open;
|
|
TEXT openbuf[P_FNAMESIZE+2];
|
|
VOID *newdH; /* open new file before closing old */
|
|
|
|
SetupFilename(open.fname=(&openbuf[0])); /* seed filename */
|
|
open.flags=H_FILE_PICK_SELECTOR|H_FILE_RESTRICT_LIST|H_FILE_SET_DEFEXT;
|
|
FOREVER
|
|
{ /* loop until success or user cancels */
|
|
if (uOpenDialog("Open anniversary file"))
|
|
break;
|
|
if (uAddDialogItem(H_DIALOG_FSEL,"File:",&open))
|
|
break;
|
|
if (RunDialog()<=0)
|
|
break;
|
|
openbuf[1+openbuf[0]]=0; /* convert from lbc to zts */
|
|
if (!TryOpenDbf(&openbuf[1],&newdH))
|
|
{ /* new file opened successfully */
|
|
ChangeOverTo(newdH,&openbuf[1]);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCAL_C INT TryNewDbf(TEXT *pb,VOID **pdH)
|
|
{ /* save any changes, and try to create new named file */
|
|
DbfHeader Header; /* values defined at top of this file */
|
|
|
|
if (SaveIfChanged())
|
|
return(-1);
|
|
hEnsurePath(pb); /* check the directory exists */
|
|
Header.createVersion=DbfVersion();
|
|
p_bcpy(&Header.dataStart,&ModelHeader,sizeof(ModelHeader));
|
|
return(doOpen(pdH,pb,P_FREPLACE|P_FUPDATE|P_FRANDOM,&Header));
|
|
}
|
|
|
|
LOCAL_C VOID NewDbf(VOID)
|
|
{ /* user wants to create a new file */
|
|
H_DI_FSEL new;
|
|
TEXT newbuf[P_FNAMESIZE+2];
|
|
VOID *newdH; /* create new file before closing old */
|
|
|
|
SetupFilename(new.fname=(&newbuf[0])); /* seed filename */
|
|
new.flags=H_FILE_NEW_EDITOR|H_FILE_SET_DEFEXT;
|
|
FOREVER
|
|
{ /* loop until success or user cancels */
|
|
if (uOpenDialog("New anniversary file"))
|
|
break;
|
|
if (uAddDialogItem(H_DIALOG_FSEL,"File:",&new))
|
|
break;
|
|
if (RunDialog()<=0)
|
|
break;
|
|
newbuf[1+newbuf[0]]=0; /* convert from lbc to zts */
|
|
if (!TryNewDbf(&newbuf[1],&newdH))
|
|
{ /* new file created successfully */
|
|
ChangeOverTo(newdH,&newbuf[1]);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCAL_C INT DoMerge(TEXT *pb,INT flags,INT dir)
|
|
{ /* common code for Merge and SaveAs */
|
|
UINT state;
|
|
|
|
state=DbfStateDisabled;
|
|
return(uErrorValue(DbfCopyFile(&state,dH,pb,flags,1,dir)));
|
|
}
|
|
|
|
LOCAL_C VOID MergeDbf(VOID)
|
|
{ /* user wants to merge two files */
|
|
H_DI_FSEL merge;
|
|
TEXT mergebuf[P_FNAMESIZE+2];
|
|
|
|
if (SaveIfChanged()) /* save any changes first */
|
|
return;
|
|
SetupFilename(merge.fname=(&mergebuf[0])); /* seed filename */
|
|
merge.flags=H_FILE_PICK_SELECTOR|H_FILE_RESTRICT_LIST|H_FILE_SET_DEFEXT;
|
|
FOREVER
|
|
{
|
|
if (uOpenDialog("Merge anniversary file"))
|
|
break;
|
|
if (uAddDialogItem(H_DIALOG_FSEL,"File:",&merge))
|
|
break;
|
|
if (RunDialog()<=0)
|
|
break;
|
|
mergebuf[1+mergebuf[0]]=0; /* convert lbc to zts */
|
|
if (!DoMerge(&mergebuf[1],P_FOPEN,DbfCopyToHandle))
|
|
{ /* merging handled by Dbf services */
|
|
wInfoMsg("File merged");
|
|
DisplayStart();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID DoSave(TEXT *pb,INT usenew)
|
|
{ /* Save to new filename and optionally use new file */
|
|
VOID *newdH; /* use separate Dbf handle */
|
|
INT i;
|
|
INT len;
|
|
|
|
if (TryNewDbf(pb,&newdH)) /* start by creating the new file */
|
|
return;
|
|
DbfTrash(dH); /* NB dBuf[] shared between two handles */
|
|
for (i=0; i<count; i++)
|
|
{ /* for all records in existing file */
|
|
LoadBuffer(i); /* load the record in dBuf[] */
|
|
len=DbfCopyDown(dH,dOff); /* prepare to write to new file */
|
|
Try(DbfAppend(newdH,len),"Failed to copy an entry");
|
|
}
|
|
DbfClose(newdH); /* close new file */
|
|
if (usenew)
|
|
{ /* switch to using new file */
|
|
DbfClose(dH);
|
|
ChangeName(pb);
|
|
while (TryOpenDbf(pb,&dH))
|
|
;
|
|
DisplayStart();
|
|
}
|
|
wInfoMsg("Saved");
|
|
}
|
|
|
|
LOCAL_C VOID SaveDbfAs(VOID)
|
|
{ /* user wants to SaveAs */
|
|
H_DI_FSEL save;
|
|
TEXT savebuf[P_FNAMESIZE+2];
|
|
UWORD usenew;
|
|
|
|
if (uOpenDialog("Save as"))
|
|
return;
|
|
SetupFilename(save.fname=(&savebuf[0])); /* seed filename */
|
|
save.flags=H_FILE_NEW_EDITOR|H_FILE_SET_DEFEXT;
|
|
if (uAddDialogItem(H_DIALOG_FSEL,"File:",&save))
|
|
return;
|
|
usenew=1;
|
|
if (uAddChoiceList("Use new file",&usenew,"No","Yes",NULL))
|
|
return;
|
|
if (RunDialog()>0)
|
|
{
|
|
savebuf[1+savebuf[0]]=0;
|
|
DoSave(&savebuf[1],usenew==2);
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID SetSymbolsState(VOID)
|
|
{ /* Set the "show symbols" state of the editors */
|
|
hEBShowSymbols(edit[2],ShowSymbols);
|
|
}
|
|
|
|
LOCAL_C VOID ToggleShowSymbols(VOID)
|
|
{ /* toggle the "show symbols" state of the editors */
|
|
ShowSymbols^=TRUE;
|
|
if (!ViewList)
|
|
SetSymbolsState();
|
|
cmds[SYMBOLS_ITEM]=(ShowSymbols? "hHide symbols": "hShow symbols");
|
|
}
|
|
|
|
LOCAL_C VOID ExitApplication(VOID)
|
|
{ /* user wants to exit */
|
|
if (!SaveIfChanged())
|
|
p_exit(0);
|
|
}
|
|
|
|
LOCAL_C INT DateDialog(TEXT *title,INT *pdiy)
|
|
{ /* present a date dialog with given title (common code) */
|
|
UWORD monno; /* month number in year */
|
|
INT dayinm; /* day number in month */
|
|
LONG ldayinm; /* dayinm as a LONG */
|
|
H_DI_NUMBER num;
|
|
|
|
dayinm=(*pdiy);
|
|
monno=FindMonNo(&dayinm)+1; /* crack the given DayInYear */
|
|
ldayinm=dayinm+1;
|
|
num.value=(&ldayinm);
|
|
num.low=1;
|
|
num.high=31; /* this limit is generally correct */
|
|
FOREVER
|
|
{
|
|
if (uOpenDialog(title))
|
|
return(-1);
|
|
if (AddMonthChoiceList(&monno))
|
|
return(-1);
|
|
if (uAddDialogItem(H_DIALOG_NUMBER,"Day in month",&num))
|
|
return(-1);
|
|
if (RunDialog()<=0)
|
|
return(-1);
|
|
dayinm=(INT)ldayinm-1;
|
|
if (dayinm<daysim[monno-1])
|
|
break;
|
|
wInfoMsg("Illegal date");
|
|
}
|
|
*pdiy=FindDiy(monno-1,dayinm); /* reconstitute DayInYear */
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C INT doEditDate(TEXT *title)
|
|
{ /* let user edit date, then set corresponding text */
|
|
INT diy;
|
|
|
|
diy=currdiy;
|
|
if (DateDialog(title,&diy))
|
|
return(-1);
|
|
if (!SetDateText(diy)) /* set text into date "editor" */
|
|
currdiy=diy;
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C INT CreateEditors(VOID)
|
|
{ /* create all three editors */
|
|
H_EDIT_BOX heb;
|
|
|
|
heb.win=MainWid; /* editors lodge on main window */
|
|
heb.maxchars=40;
|
|
heb.vulen=ScreenWidth-12-32-54;
|
|
heb.pos.x=5+32;
|
|
heb.pos.y=2;
|
|
edit[0]=hEBOpen(0,&heb); /* date "editor" */
|
|
if (!edit[0])
|
|
return(-1);
|
|
hEBSetCWidth(edit[0],0); /* hide any cursor display in date editor */
|
|
heb.maxchars=21;
|
|
heb.vulen=ScreenWidth-12-32-10;
|
|
heb.pos.x=5+32;
|
|
heb.pos.y=19;
|
|
edit[1]=hEBOpen(0,&heb); /* name editor */
|
|
if (!edit[1])
|
|
return(-1);
|
|
heb.maxchars=255;
|
|
heb.vulen=ScreenWidth-12;
|
|
heb.vislines=4;
|
|
heb.pos.x=5;
|
|
heb.pos.y=36;
|
|
edit[2]=hEBOpen(H_EDIT_BOX_VISLINES| /* notes editor */
|
|
H_EDIT_BOX_LEFT_CURSOR|H_EDIT_BOX_CLIPBOARD,&heb);
|
|
if (!edit[2])
|
|
return(-1);
|
|
if (ShowSymbols)
|
|
SetSymbolsState(); /* adjust show symbols state */
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C VOID CloseEditors(VOID)
|
|
{ /* close all three editors */
|
|
INT i;
|
|
|
|
for (i=0; i<3; i++)
|
|
{
|
|
if (edit[i])
|
|
{
|
|
hEBClose(edit[i]);
|
|
edit[i]=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID ClearWholeWindow(VOID)
|
|
{ /* clear the entire screen */
|
|
P_RECT whole;
|
|
|
|
whole.tl.x=whole.tl.y=0;
|
|
whole.br.x=240;
|
|
whole.br.y=80;
|
|
gClrRect(&whole,G_TRMODE_CLR);
|
|
}
|
|
|
|
LOCAL_C VOID SetStyle(INT style)
|
|
{ /* set the style of the current graphics context */
|
|
G_GC gc;
|
|
|
|
gc.style=style;
|
|
gSetGC(0,G_GC_MASK_STYLE,&gc);
|
|
}
|
|
|
|
LOCAL_C VOID DisplayPrompts(VOID)
|
|
{ /* display the prompts of the editors */
|
|
SetStyle(G_STY_ITALIC); /* use italics */
|
|
gPrintText(5,2+8,"Date:",5);
|
|
gPrintText(5,19+8,"Name:",5);
|
|
SetStyle(0); /* clear italics */
|
|
}
|
|
|
|
LOCAL_C VOID DrawFramework(VOID)
|
|
{ /* draw the "framework" of the current display */
|
|
INT i;
|
|
|
|
for (i=0; i<3; i++)
|
|
DrawBorder(i);
|
|
DisplayPrompts();
|
|
DrawWhereAndCount();
|
|
}
|
|
|
|
LOCAL_C INT ToggleListMode(VOID)
|
|
{ /* change between list view and editors view */
|
|
if (ViewList)
|
|
{ /* change over to editors view */
|
|
if (CreateEditors())
|
|
{ /* failed to create all editors */
|
|
CloseEditors(); /* clean up */
|
|
return(-1);
|
|
}
|
|
ClearWholeWindow();
|
|
DrawFramework();
|
|
LoadEditors();
|
|
}
|
|
else
|
|
{ /* change over to list view */
|
|
if (SaveIfChanged())
|
|
return(-1);
|
|
CloseEditors();
|
|
ClearWholeWindow();
|
|
WholeListDisplay();
|
|
}
|
|
ViewList^=TRUE;
|
|
cmds[LIST_ITEM]=(ViewList? "lNotes view": "lList view");
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C INT CheckNotListMode(VOID)
|
|
{ /* ensure in editors mode */
|
|
if (!ViewList)
|
|
return(0);
|
|
return(ToggleListMode());
|
|
}
|
|
|
|
LOCAL_C VOID EnterAnniversary(VOID)
|
|
{ /* user wants to enter an anniversary */
|
|
if (CheckNotListMode())
|
|
return; /* failed to create editors */
|
|
if (SaveIfChanged())
|
|
return; /* failed to save changes */
|
|
if (doEditDate("Enter anniversary"))
|
|
return; /* user cancelled or no memory for dialog */
|
|
AddDummyEntry();
|
|
LoadEditors();
|
|
RotateTo(1); /* emphasise the name editor */
|
|
}
|
|
|
|
LOCAL_C INT CheckEditing(VOID)
|
|
{ /* some menu commands are only allowed in notes window */
|
|
if (ViewList || emph!=2)
|
|
{
|
|
wInfoMsg("Only available in notes window");
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C INT ComplainIfChanged(VOID)
|
|
{ /* complain if there have been no changes */
|
|
if (!CheckIfChanged())
|
|
{
|
|
wInfoMsg("Not changed");
|
|
return(0);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
LOCAL_C VOID SaveAnniversary(VOID)
|
|
{ /* user wants to save any changes made */
|
|
if (!ComplainIfChanged())
|
|
return; /* no changes made */
|
|
if (!SaveChanges())
|
|
wInfoMsg("Anniversary saved");
|
|
}
|
|
|
|
LOCAL_C VOID UndoEditing(VOID)
|
|
{ /* user wants to "revert to saved" for current record */
|
|
if (!ComplainIfChanged())
|
|
return;
|
|
if (Confirm("Undo editing"))
|
|
return; /* user failed to confirm loss of changes */
|
|
LoadEditors();
|
|
ClearChangedFlags();
|
|
}
|
|
|
|
LOCAL_C VOID ChangeDate(VOID)
|
|
{ /* user wants to change an anniversary date */
|
|
if (CheckNotListMode())
|
|
return;
|
|
RotateTo(0); /* emphasise date window */
|
|
doEditDate("Change date of anniversary");
|
|
}
|
|
|
|
LOCAL_C VOID WanderThrough(VOID)
|
|
{ /* provide help for user to "wander through" anniversaries */
|
|
if (SaveIfChanged())
|
|
return;
|
|
if (ViewList)
|
|
wInfoMsg("Use \030 and \031 to view all anniversaries");
|
|
else
|
|
{
|
|
RotateTo(0); /* compiler will share code here */
|
|
wInfoMsg("Use \032 and \033 to view all anniversaries");
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID PrintSetupDialog(VOID)
|
|
{ /* run the print setup dialog suite */
|
|
EditEmphasise(FALSE); /* remove any existing flashing cursor */
|
|
hPrintSetupDialog();
|
|
EditEmphasise(TRUE); /* reinstate any flashing cursor */
|
|
}
|
|
|
|
LOCAL_C INT DoFind(INT try,INT dir,INT k)
|
|
{ /* look for string in given direction, in next k records */
|
|
UBYTE *pb; /* for text of record */
|
|
INT off; /* offset into field where found */
|
|
INT newemph; /* which editor to emphasise */
|
|
|
|
FOREVER
|
|
{ /* for up to k records */
|
|
if (!k--)
|
|
return(-1); /* not found */
|
|
try+=dir;
|
|
if (try>=count)
|
|
try=0; /* handle wrap round forwards */
|
|
else if (try<0)
|
|
try=count-1; /* handle wrap round backwards */
|
|
SeekTo(index[try].no); /* load text of specified record */
|
|
pb=(&dBuf[dOff+4]); /* position to name field */
|
|
if (findtype&1)
|
|
{ /* if searching in name field */
|
|
newemph=1;
|
|
off=LookFor(pb);
|
|
if (off>=0)
|
|
break; /* found */
|
|
}
|
|
pb+=(*pb)+1; /* position to notes field */
|
|
if (findtype&2)
|
|
{ /* if searching in notes field */
|
|
newemph=2;
|
|
off=LookFor(pb);
|
|
if (off>=0)
|
|
break; /* found */
|
|
}
|
|
}
|
|
if (ViewList)
|
|
{
|
|
if (newemph==1)
|
|
{ /* can position to name field in list view... */
|
|
MakeHighlight(try);
|
|
return(0);
|
|
}
|
|
if (ToggleListMode()) /* ...but not to notes field */
|
|
return(0);
|
|
}
|
|
NewWhere(try); /* load editors with relevant record */
|
|
hEBSetSelect(edit[newemph],off,off+find[0]); /* highlight match */
|
|
RotateTo(newemph); /* emphasise correct editor */
|
|
return(0);
|
|
}
|
|
|
|
LOCAL_C VOID FindAnniversary(VOID)
|
|
{ /* user wants to Find */
|
|
H_DI_EDIT edfind;
|
|
|
|
if (SaveIfChanged())
|
|
return; /* failed to save changes */
|
|
edfind.str=(&find[0]); /* seed with previous find string */
|
|
edfind.len=19;
|
|
FOREVER
|
|
{
|
|
if (uOpenDialog("Find text"))
|
|
return;
|
|
if (uAddDialogItem(H_DIALOG_EDIT,"Text",&edfind))
|
|
return;
|
|
if (uAddChoiceList("Search",&findtype,"Just names",
|
|
"Just notes","Names and notes",NULL))
|
|
return;
|
|
if (RunDialog()<=0)
|
|
return;
|
|
if (!DoFind(count,+1,count))
|
|
return; /* match found */
|
|
wInfoMsg("Not found");
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID FindAgain(INT dir)
|
|
{ /* user wants to Find Again */
|
|
if (SaveIfChanged())
|
|
return;
|
|
if (DoFind(where,dir,count-1))
|
|
wInfoMsg("No more found");
|
|
}
|
|
|
|
LOCAL_C VOID JumpTo(VOID)
|
|
{ /* user wants to jump to record by index number */
|
|
LONG curr;
|
|
H_DI_NUMBER num;
|
|
INT new;
|
|
|
|
if (SaveIfChanged())
|
|
return; /* failed to save changes */
|
|
if (uOpenDialog(NULL)) /* this dialog has no title */
|
|
return;
|
|
curr=where+1; /* seed with current value */
|
|
num.value=(&curr);
|
|
num.low=1;
|
|
num.high=count;
|
|
if (uAddDialogItem(H_DIALOG_NUMBER,"Jump to record",&num))
|
|
return;
|
|
if (RunDialog()<=0)
|
|
return;
|
|
new=(UINT)(curr-1);
|
|
NewWhere(new);
|
|
}
|
|
|
|
LOCAL_C INT Today(VOID)
|
|
{ /* return DayInYear for today */
|
|
P_DAYSEC ds;
|
|
P_DATE dt;
|
|
ULONG now;
|
|
|
|
now=p_date();
|
|
p_sttods(&now,&ds);
|
|
p_dstodt(&ds,&dt);
|
|
return(FindDiy(dt.month,dt.day));
|
|
}
|
|
|
|
LOCAL_C VOID FindDate(VOID)
|
|
{ /* user wants to find record on given date */
|
|
INT diy;
|
|
INT mid;
|
|
INDENT ent;
|
|
|
|
diy=Today(); /* seed with today */
|
|
if (DateDialog("Find date",&diy))
|
|
return; /* user cancelled or out of memory */
|
|
ent.diy=diy;
|
|
ent.no=0;
|
|
mid=LocateByDate(&ent);
|
|
if (mid>=count)
|
|
mid=count-1;
|
|
NewWhere(mid);
|
|
}
|
|
|
|
LOCAL_C INT PrintLine(H_PRINT *pr)
|
|
{ /* call-back function to print line of data */
|
|
INT ind;
|
|
|
|
switch (PrintState++)
|
|
{
|
|
case 0: /* reached only at very beginning: set up print indent */
|
|
PrintIndent=hPrintSenseBufWidth(" ",1)*4;
|
|
hPrintSetSI(PrintIndent); /* indent for word-wrapped lines */
|
|
PrintState++;
|
|
case 1: /* print date */
|
|
LoadBuffer(PrintRec); /* load record into dBuf[] */
|
|
PrintBuf=(&dBuf[dOff+2]); /* position to DayInYear field */
|
|
DiyToBuf(*(UWORD *)PrintBuf,&PrintDate[0]);
|
|
PrintBuf+=2; /* position to name text field */
|
|
pr->buf=(&PrintDate[0]); /* print text version of date */
|
|
pr->blen=p_slen(&PrintDate[0]);
|
|
pr->style|=H_PRINT_STY_BOLD; /* print in bold */
|
|
break;
|
|
case 2: /* print name */
|
|
pr->blen=(*PrintBuf++);
|
|
pr->buf=(TEXT *)PrintBuf;
|
|
PrintBuf+=pr->blen; /* position to notes text field */
|
|
PrintLen=(*PrintBuf++); /* how many characters in note */
|
|
break;
|
|
default: /* print (next section of) notes */
|
|
if (PrintNamesOnly==1)
|
|
{ /* if NOT only printing names */
|
|
pr->buf=(TEXT *)PrintBuf;
|
|
pr->indent=PrintIndent;
|
|
ind=p_bloc(PrintBuf,PrintLen,'\n'); /* search for '\n' */
|
|
if (ind<0)
|
|
{ /* all (remaining) text is one "paragraph" */
|
|
pr->blen=PrintLen; /* print it all */
|
|
PrintLen=0; /* none left */
|
|
}
|
|
else
|
|
{
|
|
pr->blen=ind; /* print rest of "paragraph" */
|
|
PrintLen-=ind+1; /* still some of note left to print */
|
|
PrintBuf+=ind+1; /* position to next "paragraph" */
|
|
}
|
|
if (pr->blen || PrintLen)
|
|
break; /* not finished note yet */
|
|
}
|
|
pr->blen=0; /* print blank line */
|
|
PrintState=1; /* ready for date of next record */
|
|
return(++PrintRec!=count); /* return FALSE if finished */
|
|
}
|
|
pr->flags|=H_PRINT_KEEP; /* keep record together, if possible */
|
|
return(TRUE); /* still more to print */
|
|
}
|
|
|
|
LOCAL_C VOID PrintAnniversaries(VOID)
|
|
{ /* user wants to Print */
|
|
if (SaveIfChanged())
|
|
return; /* failed to save changes */
|
|
if (uOpenDialog("Print"))
|
|
return;
|
|
if (uAddChoiceList("Names only",&PrintNamesOnly,"No","Yes",0))
|
|
return;
|
|
if (RunDialog()<=0)
|
|
return;
|
|
PrintRec=0; /* initialise print state variables */
|
|
PrintState=0;
|
|
hPrint(PrintLine); /* specify call-back function */
|
|
}
|
|
|
|
LOCAL_C VOID DeleteAnniversary(VOID)
|
|
{ /* user wants to delete anniversary */
|
|
INT state;
|
|
|
|
if (count==1 && !SizeRecord())
|
|
{
|
|
wInfoMsg("Nothing to delete");
|
|
return;
|
|
}
|
|
if (Confirm("Delete this anniversary"))
|
|
return; /* user failed to confirm */
|
|
SeekToCurrent(); /* load current entry into dBuf[] */
|
|
state=DbfStateDisabled;
|
|
Check(DbfEraseRead(&state,dH,&dOff));
|
|
IndexDelete(); /* remove current entry from index too */
|
|
if (!count)
|
|
AddDummyEntry(); /* don't leave index completely empty */
|
|
if (where==count)
|
|
where=count-1;
|
|
WholeDisplay();
|
|
}
|
|
|
|
LOCAL_C VOID ManageCommand(INT index)
|
|
{ /* switch on command index to appropriate function */
|
|
switch (index)
|
|
{
|
|
case ITEMS_BEFORE_FILE:
|
|
NewDbf();
|
|
break;
|
|
case ITEMS_BEFORE_FILE+1:
|
|
OpenDbf();
|
|
break;
|
|
case ITEMS_BEFORE_FILE+2:
|
|
MergeDbf();
|
|
break;
|
|
case ITEMS_BEFORE_FILE+3:
|
|
SaveDbfAs();
|
|
break;
|
|
case ITEMS_BEFORE_FILE+4:
|
|
CompressFile();
|
|
break;
|
|
case ITEMS_BEFORE_FILE+5:
|
|
ExitApplication();
|
|
break;
|
|
case ITEMS_BEFORE_EDIT:
|
|
if (!CheckEditing())
|
|
{ /* insert text - handled by editor */
|
|
if (hEBPaste(edit[2])>0)
|
|
wInfoMsg("No text to insert");
|
|
}
|
|
break;
|
|
case ITEMS_BEFORE_EDIT+1:
|
|
if (!CheckEditing())
|
|
{ /* copy text - handled by editor */
|
|
if (hEBCopy(edit[2])>0)
|
|
wInfoMsg("No text to copy");
|
|
else
|
|
wInfoMsg("Text copied");
|
|
}
|
|
break;
|
|
case ITEMS_BEFORE_EDIT+2:
|
|
if (!CheckEditing())
|
|
hEBEvaluate(edit[2]); /* evaluate - handled by editor */
|
|
break;
|
|
case ITEMS_BEFORE_EDIT+3:
|
|
ToggleShowSymbols();
|
|
break;
|
|
case ITEMS_BEFORE_EDIT+4:
|
|
SaveAnniversary();
|
|
break;
|
|
case ITEMS_BEFORE_EDIT+5:
|
|
UndoEditing();
|
|
break;
|
|
case ITEMS_BEFORE_CHANGE:
|
|
EnterAnniversary();
|
|
break;
|
|
case ITEMS_BEFORE_CHANGE+1:
|
|
DeleteAnniversary();
|
|
break;
|
|
case ITEMS_BEFORE_CHANGE+2:
|
|
ChangeDate();
|
|
break;
|
|
case ITEMS_BEFORE_SEARCH:
|
|
FindAnniversary();
|
|
break;
|
|
case ITEMS_BEFORE_SEARCH+1:
|
|
FindAgain(+1);
|
|
break;
|
|
case ITEMS_BEFORE_SEARCH+2:
|
|
FindAgain(-1); /* this is "Find Backwards" */
|
|
break;
|
|
case ITEMS_BEFORE_SEARCH+3:
|
|
FindDate();
|
|
break;
|
|
case ITEMS_BEFORE_SEARCH+4:
|
|
JumpTo();
|
|
break;
|
|
case ITEMS_BEFORE_SPECIAL:
|
|
ToggleListMode();
|
|
break;
|
|
case ITEMS_BEFORE_SPECIAL+1:
|
|
WanderThrough();
|
|
break;
|
|
case ITEMS_BEFORE_SPECIAL+2:
|
|
PrintAnniversaries();
|
|
break;
|
|
case ITEMS_BEFORE_SPECIAL+3:
|
|
PrintSetupDialog();
|
|
}
|
|
}
|
|
|
|
LOCAL_C INT ObeySystemCommand(INT cmd,TEXT *pb,VOID **pdH)
|
|
{ /* respond to SwitchFiles command from System Screen */
|
|
return((cmd=='O'? TryOpenDbf: TryNewDbf)(pb,pdH));
|
|
}
|
|
|
|
LOCAL_C VOID ProcessSystemCommand(VOID)
|
|
{ /* respond to message from System Screen */
|
|
TEXT buf[P_FNAMESIZE+2];
|
|
VOID *newdH;
|
|
|
|
wGetCommand((UBYTE *)&buf[0]);
|
|
if (buf[0]=='X')
|
|
ExitApplication();
|
|
if (!ObeySystemCommand(buf[0],&buf[1],&newdH))
|
|
ChangeOverTo(newdH,&buf[1]);
|
|
}
|
|
|
|
LOCAL_C VOID TryExecuteCommand(INT keycode)
|
|
{ /* try to find command to execute matching accelerator passed */
|
|
keycode=uLocateCommand(keycode); /* look up accelerator table */
|
|
if (keycode>=0) /* found - keycode converted to index */
|
|
ManageCommand(keycode);
|
|
}
|
|
|
|
LOCAL_C VOID RotateFocus(INT shifted)
|
|
{ /* respond to TAB key */
|
|
INT newemph;
|
|
|
|
if (ViewList)
|
|
ToggleListMode();
|
|
else
|
|
{
|
|
newemph=emph;
|
|
if (shifted)
|
|
{ /* go backwards for SHIFT TAB */
|
|
if (!newemph--)
|
|
newemph=2;
|
|
}
|
|
else if (++newemph==3)
|
|
newemph=0;
|
|
RotateTo(newemph);
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID MoveTo(INT newwhere)
|
|
{ /* move to given record (works in either list or editors view */
|
|
if (SaveIfChanged())
|
|
return;
|
|
if (newwhere<0)
|
|
newwhere=count-1;
|
|
else if (newwhere>=count)
|
|
newwhere=0;
|
|
NewWhere(newwhere);
|
|
}
|
|
|
|
LOCAL_C INT ResizeWidth(UWORD width)
|
|
{ /* try to change the width of the main display region */
|
|
INT ret;
|
|
W_WINDATA wd;
|
|
|
|
wd.extent.tl.x=wd.extent.tl.y=0;
|
|
wd.extent.width=width;
|
|
wd.extent.height=80;
|
|
wSetWindow(MainWid,W_WIN_EXTENT,&wd);
|
|
ret=uErrorValue(wCheckPoint()); /* check whether successful */
|
|
if (!ret)
|
|
ScreenWidth=width;
|
|
return(ret);
|
|
}
|
|
|
|
LOCAL_C VOID ToggleStatusWindow(VOID)
|
|
{ /* attempt to toggle the visibility of the status window */
|
|
if (show_statwin)
|
|
{ /* status window is currently showing */
|
|
if (ResizeWidth(240))
|
|
return;
|
|
wsDisable(); /* remove status window */
|
|
}
|
|
else
|
|
{ /* status window not currently showing */
|
|
if (ResizeWidth(189))
|
|
return;
|
|
wsEnable(); /* display status window */
|
|
}
|
|
show_statwin^=TRUE;
|
|
ClearWholeWindow();
|
|
if (ViewList)
|
|
{
|
|
gBorder(lastbflags);
|
|
ListDisplay();
|
|
}
|
|
else
|
|
{
|
|
lastchanged=FALSE;
|
|
DrawFramework();
|
|
hEBChangeWidth(edit[0],ScreenWidth-12-32-54);
|
|
hEBChangeWidth(edit[1],ScreenWidth-12-32-10);
|
|
hEBChangeWidth(edit[2],ScreenWidth-12); /* change editor widths */
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID UpdateDateDisplays(VOID)
|
|
{ /* system time format defaults may have changed */
|
|
if (ViewList)
|
|
ListDisplay();
|
|
else
|
|
SetDateText(currdiy);
|
|
}
|
|
|
|
LOCAL_C VOID KeyToEditors(WMSG_KEY *pkey)
|
|
{ /* pass key to emphasised editor */
|
|
if (!emph)
|
|
{ /* emphasis on date "editor" */
|
|
switch (pkey->keycode)
|
|
{
|
|
case W_KEY_LEFT:
|
|
MoveTo(pkey->modifiers&W_PSION_MODIFIER? 0: where-1);
|
|
break;
|
|
case W_KEY_RIGHT:
|
|
MoveTo(pkey->modifiers&W_PSION_MODIFIER? count-1: where+1);
|
|
break;
|
|
case W_KEY_RETURN:
|
|
ChangeDate();
|
|
}
|
|
return;
|
|
}
|
|
if (pkey->keycode==W_KEY_RETURN && emph!=2)
|
|
return;
|
|
hEBHandleKey(edit[emph],pkey->keycode,pkey->modifiers);
|
|
}
|
|
|
|
LOCAL_C VOID ScrollPageBy(INT delta)
|
|
{ /* implementation of PgUp / PgDn */
|
|
if (delta<(-7))
|
|
delta=(-7);
|
|
else if (delta>7)
|
|
delta=7;
|
|
top+=delta;
|
|
where+=delta;
|
|
ListDisplay();
|
|
}
|
|
|
|
LOCAL_C VOID KeyToList(WMSG_KEY *pkey)
|
|
{ /* key handling routine for list view */
|
|
switch (pkey->keycode)
|
|
{
|
|
case W_KEY_UP:
|
|
if (where)
|
|
MakeHighlight(where-1);
|
|
break;
|
|
case W_KEY_DOWN:
|
|
if (where<count-1)
|
|
MakeHighlight(where+1);
|
|
break;
|
|
case W_KEY_PAGE_UP:
|
|
if (pkey->modifiers&W_CTRL_MODIFIER)
|
|
MakeHighlight(0);
|
|
else if (!top)
|
|
MakeHighlight(0);
|
|
else
|
|
ScrollPageBy(-top);
|
|
break;
|
|
case W_KEY_PAGE_DOWN:
|
|
if (pkey->modifiers&W_CTRL_MODIFIER)
|
|
MakeHighlight(count-1);
|
|
else if (top+8>=count)
|
|
MakeHighlight(count-1);
|
|
else
|
|
ScrollPageBy(count-top-8);
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID CheckEmbellishments(VOID)
|
|
{ /* called regularly (once every event) */
|
|
INT bflags;
|
|
INT changed;
|
|
P_RECT box; /* rectangle to draw "changed" asterisk in */
|
|
|
|
if (ViewList)
|
|
{ /* see if scroll arrows in border need changing */
|
|
bflags=CalculateBflags();
|
|
if (bflags!=lastbflags)
|
|
gBorder(lastbflags=bflags);
|
|
}
|
|
else
|
|
{ /* see if "changed" asterisk after name editor needs changing */
|
|
changed=CheckIfChanged();
|
|
if (changed==lastchanged)
|
|
return;
|
|
lastchanged=changed;
|
|
box.tl.x=ScreenWidth-10;
|
|
box.tl.y=19;
|
|
box.br.x=ScreenWidth;
|
|
box.br.y=29;
|
|
gPrintBoxText(&box,8,G_TEXT_ALIGN_CENTRE,0,"*",changed);
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID MainLoop(VOID)
|
|
{ /* central event processing loop */
|
|
INT ret;
|
|
WMSG_KEY key;
|
|
|
|
FOREVER
|
|
{
|
|
CheckEmbellishments(); /* check display up-to-date */
|
|
uGetKey(&key);
|
|
if (key.keycode&W_EVENT_KEY)
|
|
{
|
|
switch (key.keycode)
|
|
{
|
|
case CONS_EVENT_FOREGROUND:
|
|
UpdateDateDisplays();
|
|
break;
|
|
case CONS_EVENT_COMMAND:
|
|
ProcessSystemCommand();
|
|
}
|
|
}
|
|
else if (key.keycode&W_SPECIAL_KEY) /* Psion key pressed */
|
|
TryExecuteCommand(key.keycode&(~W_SPECIAL_KEY));
|
|
else
|
|
{
|
|
switch (key.keycode)
|
|
{
|
|
case W_KEY_MENU:
|
|
if (key.modifiers&W_CTRL_MODIFIER)
|
|
ToggleStatusWindow();
|
|
else
|
|
{ /* display menu bar */
|
|
ret=uPresentMenus();
|
|
if (ret>0)
|
|
TryExecuteCommand(ret);
|
|
}
|
|
break;
|
|
case W_KEY_MODE: /* if assigned app button pressed */
|
|
ToggleListMode();
|
|
break;
|
|
case W_KEY_TAB:
|
|
RotateFocus(key.modifiers&W_SHIFT_MODIFIER);
|
|
break;
|
|
default:
|
|
(ViewList? KeyToList: KeyToEditors)(&key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCAL_C VOID SmallScreen(VOID)
|
|
{ /* attempt to make room for status window */
|
|
if (ResizeWidth(189))
|
|
p_exit(0);
|
|
}
|
|
|
|
LOCAL_C VOID CreateGC(VOID)
|
|
{ /* attempt to create default graphics context on main window */
|
|
INT hgc; /* graphics context handle (if successful) */
|
|
|
|
hgc=gCreateGC0(MainWid);
|
|
if (hgc<0)
|
|
p_exit(hgc);
|
|
}
|
|
|
|
LOCAL_C VOID SpecificInit(VOID)
|
|
{ /* application initialisation specific to Days */
|
|
INT command;
|
|
|
|
uEscape(FALSE); /* disable Psion-Esc */
|
|
MainWid=uFindMainWid(); /* find id of main display window */
|
|
CreateGC(); /* create default graphics context */
|
|
SmallScreen(); /* make room for status window */
|
|
wsEnable(); /* display status window */
|
|
CreateEditors(); /* start in editor mode */
|
|
command=hCrackCommandLine(); /* analyse command line */
|
|
if (ObeySystemCommand(command,DatUsedPathNamePtr,&dH))
|
|
p_exit(0);
|
|
DrawFramework();
|
|
DisplayStart();
|
|
}
|
|
|
|
GLDEF_C VOID main(VOID)
|
|
{ /* the main() for all Hwif programs */
|
|
uCommonInit(); /* initialisation common to all Hwif programs */
|
|
SpecificInit(); /* initialisation specific to Days */
|
|
MainLoop(); /* the central event processing loop */
|
|
}
|