/******************************************************************************
*
* NSSDC/CDF Windowing widgets.
*
* Version 1.3b, 13-Nov-97, Hughes STX.
*
* Modification history:
*
* V1.0 19-Nov-93, J Love Original version.
* V1.0a 22-Feb-94, J Love Spelling lesson.
* V1.0b 28-Mar-94, J Love Solaris using GNU C compiler.
* V1.1 13-Dec-94, J Love CDF V2.5.
* V1.1a 23-Jan-95, J Love Primary/alternate "current" item movement
* keys for ItemWindow.
* V1.1b 7-Mar-95, J Love Added FieldWindow.
* V1.2 11-Apr-95, J Love POSIX/CDFexport.
* V1.2a 10-May-95, J Love More CDFexport.
* V1.2b 13-Jun-95, J Love catchrX. Linux.
* V1.2c 30-Aug-95, J Love CDFexport-related changes. Moved online help
* widget to this file. FSI key definitions.
* V1.2d 18-Sep-95, J Love Macintosh event handling.
* V1.3 26-Aug-96, J Love CDF V2.6.
* V1.3a 31-Mar-97, J Love Allowed fields in a FieldWindow to be longer
* than their on-screen width.
* V1.3b 13-Nov-97, J Love Windows NT/Visual C++.
* V1.4 11-Jul-05, M Liu Added MingW port for PC.
*
******************************************************************************/
#include "widgets.h"
/******************************************************************************
* Local macros.
******************************************************************************/
#define MAX_PCT_LEN 5
#define DIFF(a,b) BOO((a < b),(b - a),(a - b))
/******************************************************************************
* Local function prototypes.
******************************************************************************/
static void CalcItemDirections PROTOARGs((
int nItems, int NiLines, int *iLineNs, int *iCols, int *iLens,
int *iDownTo, int *iUpTo, int *iLeftTo, int *iRightTo
));
static void DownArrow PROTOARGs((
int *iLineNs, int *iDownTo, int iRowT, int iRowB, Logical iScroll,
int *iRowN, int *itemN
));
static void UpArrow PROTOARGs((
int NiLines, int *iLineNs, int *iUpTo, int iRowT, int iRowB, Logical iScroll,
int *iRowN, int *itemN
));
static void NextScreen PROTOARGs((
int NiRows, int NiLines, int *iLineNs, int *iDownTo, int iRowB, int iRowT,
Logical iScroll, int *itemN, int *iRowN
));
static void PrevScreen PROTOARGs((
int NiRows, int *iLineNs, int *iUpTo, int iRowT, Logical iScroll, int *iRowN,
int *itemN
));
static void UpdatePctString PROTOARGs((WINDOWid, int, int, int, int, int));
static void DrawSection PROTOARGs((
WINDOWid, int, int, int, int, char **, int
));
static void DrawField PROTOARGs((struct FieldWindowStruct *FW));
static void DrawFieldsSection PROTOARGs((struct FieldWindowStruct *FW));
static int IWtopRowLineN PROTOARGs((struct ItemWindowStruct *IW));
static int FWtopRowLineN PROTOARGs((struct FieldWindowStruct *FW));
static void DrawEditSection PROTOARGs((struct EditWindowStruct *EW));
static void SetEditCursor PROTOARGs((struct EditWindowStruct *EW));
/******************************************************************************
* ItemWindow.
*
* Header section.
* Items section (scrollable).
* Trailer section.
*
******************************************************************************/
#if defined(STDARG)
int ItemWindow (int opT, ...)
#else
int ItemWindow (va_alist)
va_dcl
#endif
{
int op; /* Operation to perform (eg. create new menu,
delete menu, etc. */
struct ItemWindowStruct *IW; /* Menu configuration. */
va_list ap;
/***************************************************************************
* Start variable-length argument list scanning.
***************************************************************************/
#if defined(STDARG)
va_start (ap, opT);
op = opT;
#else
VA_START (ap);
op = va_arg (ap, int);
#endif
IW = va_arg (ap, struct ItemWindowStruct *);
/***************************************************************************
* Perform desired operation. Some operations wait for user input (by
* falling through the `switch' statement).
***************************************************************************/
switch (op) {
/*************************************************************************
* Check for new/modified menu.
*************************************************************************/
case NEWiw:
case UPDATEiw: {
int nSections; /* Number of sections on window. */
int nHorizLines; /* Number of horizontal lines needed. At
most 2 horizontal lines will be needed
to separate the 3 sections. */
int horizRows[2]; /* Rows at which to draw the horizontal
lines. */
int horizLineN; /* Horizontal line number. */
int xRow; /* Used when determining starting rows for
the various sections. */
Logical highlightItem = FALSE; /* If TRUE, hightlight the
current item. */
/***********************************************************************
* Get remaining arguments.
***********************************************************************/
IW->itemN = va_arg (ap, int); /* Initial item number (if any
items exist). */
va_end (ap);
/***********************************************************************
* Calculate positions.
***********************************************************************/
if (op == NEWiw) {
IW->nColS = IW->nColsTotal - 2;
nSections = 0;
nHorizLines = 0;
/********************************************************************\
| Start at row 1 (row 0 is top border line).
\********************************************************************/
xRow = 1;
if (IW->NhLines > 0) {
nSections++;
IW->hRowT = xRow;
IW->hRowB = IW->hRowT + IW->NhLines - 1;
xRow += IW->NhLines + 1;
}
if (IW->NiRows > 0) {
nSections++;
IW->iRowT = xRow;
IW->iRowB = IW->iRowT + IW->NiRows - 1;
xRow += IW->NiRows + 1;
if (nSections > 1) horizRows[nHorizLines++] = IW->iRowT - 1;
}
else
return FALSE; /* An item section must exist. */
if (IW->NtLines > 0) {
nSections++;
IW->tRowT = xRow;
IW->tRowB = IW->tRowT + IW->NtLines - 1;
xRow += IW->NtLines + 1;
if (nSections > 1) horizRows[nHorizLines++] = IW->tRowT - 1;
}
IW->nRowsTotal = xRow;
}
/***********************************************************************
* Turn off cursor.
***********************************************************************/
set_cursor_mode (CURSORoff);
/***********************************************************************
* Create window?
***********************************************************************/
begin_pasteboard_update ();
if (op == NEWiw) {
create_virtual_display (IW->nRowsTotal, IW->nColsTotal, &(IW->wid),
BORDER, NORMAL);
paste_virtual_display (IW->wid, IW->ULrow, IW->ULcol);
}
/***********************************************************************
* If specified, write label to window. If this is an update operation,
* first overwrite the existing label.
***********************************************************************/
if (op == UPDATEiw) draw_horizontal_line (IW->wid, 0, 1, IW->nColS,
NORMAL, FALSE);
if (IW->label != NULL) {
int len = (int) strlen(IW->label);
if (len <= IW->nColS) {
int nRemainChars = IW->nColS - len;
int nCharsBefore = nRemainChars / 2;
put_chars (IW->wid, IW->label, len, 0, nCharsBefore + 1, FALSE,
REVERSE1);
}
}
/***********************************************************************
* If necessary, draw horizontal lines on window.
***********************************************************************/
if (op == NEWiw) {
for (horizLineN = 0; horizLineN < nHorizLines; horizLineN++) {
draw_horizontal_line (IW->wid, horizRows[horizLineN], 0,
IW->nColsTotal-1, NORMAL, TRUE);
}
}
/***********************************************************************
* If specified, write header section to window. If an update operation,
* it is assumed that the number of lines has not changed.
***********************************************************************/
if (IW->NhLines > 0) DrawSection (IW->wid, IW->hRowT, IW->hRowB, 0,
IW->NhLines, IW->hLines, IW->nColS);
/***********************************************************************
* Write items section to window and `highlight' current item. The
* current item is set to zero initially for a new menu (if items exist,
* otherwise it is set to -1). The item section may contain lines but
* no items. If an update operation, note that the number of lines may
* have changed.
***********************************************************************/
if (op == UPDATEiw) {
if (IW->iUpTo != NULL) cdf_FreeMemory (IW->iUpTo,
FatalError);
if (IW->iDownTo != NULL) cdf_FreeMemory (IW->iDownTo,
FatalError);
if (IW->iLeftTo != NULL) cdf_FreeMemory (IW->iLeftTo,
FatalError);
if (IW->iRightTo != NULL) cdf_FreeMemory (IW->iRightTo,
FatalError);
}
IW->iUpTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
FatalError);
IW->iDownTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
FatalError);
IW->iLeftTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
FatalError);
IW->iRightTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
FatalError);
if (IW->NiLines > 0) {
/*******************************************************************
* One or more lines in the item section.
*******************************************************************/
if (IW->nItems > 0) {
/*****************************************************************
* One or more items in the item section.
*****************************************************************/
CalcItemDirections (IW->nItems, IW->NiLines, IW->iLineNs,
IW->iCols, IW->iLens, IW->iDownTo, IW->iUpTo,
IW->iLeftTo, IW->iRightTo);
if (IW->NiLines > IW->NiRows)
IW->iScroll = TRUE;
else
IW->iScroll = FALSE;
/*******************************************************************
* Determine row number for current item. If this is an UPDATEiw
* operation, try to keep the row number the same as it was (or as
* close as possible).
*******************************************************************/
if (op == NEWiw)
IW->iRowN = MinInt (IW->iRowT +
IW->iLineNs[IW->itemN], IW->iRowB);
else
if (IW->iScroll) {
int nLinesFromTop = IW->iLineNs[IW->itemN];
int nRowsFromTop = IW->iRowN - IW->iRowT;
if (nLinesFromTop < nRowsFromTop)
IW->iRowN -= nRowsFromTop - nLinesFromTop;
else {
int nLinesFromBot = (IW->NiLines-1) - IW->iLineNs[IW->itemN];
int nRowsFromBot = IW->iRowB - IW->iRowN;
if (nLinesFromBot < nRowsFromBot)
IW->iRowN += nRowsFromBot - nLinesFromBot;
}
}
else
IW->iRowN = IW->iRowT + IW->iLineNs[IW->itemN];
DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
IW->NiLines, IW->iLines, IW->nColS);
highlightItem = TRUE;
}
else {
/*****************************************************************
* No items in the item section (but there are some lines). Just
* redraw lines.
*****************************************************************/
IW->iRowN = IW->iRowT;
DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
IW->NiLines, IW->iLines, IW->nColS);
}
}
else {
/*******************************************************************
* No lines in the item section. Erase lines in case there had
* previously been lines.
*******************************************************************/
IW->iRowN = IW->iRowT;
erase_display (IW->wid, IW->iRowT, 1, IW->iRowB, IW->nColS);
}
/*********************************************************************
* Setup/display initial percentage indicator.
*********************************************************************/
if (IW->iPct) {
int lineNt = IWtopRowLineN (IW);
if (op == NEWiw) {
IW->iPctRowN = IW->iRowB + 1;
IW->iPctColN = IW->nColsTotal - 7;
}
UpdatePctString (IW->wid, IW->NiLines, IW->NiRows, lineNt,
IW->iPctRowN, IW->iPctColN);
}
/***********************************************************************
* If specified, write trailer section to window. If an update
* operation, it is assumed that the number of lines has not changed.
***********************************************************************/
if (IW->NtLines > 0) DrawSection (IW->wid, IW->tRowT, IW->tRowB, 0,
IW->NtLines, IW->tLines, IW->nColS);
/***********************************************************************
* Update screen and then highlight the current item (if there is one).
* The current item is highlighted after the screen is updated for those
* situations where the cursor could not be turned off. Highlighting
* the current item last will put the (possible blinking) cursor after
* the current item which isn't as distracting as when the cursor is at
* the end of the last line of the trailer section.
***********************************************************************/
end_pasteboard_update ();
if (highlightItem) change_rendition (IW->wid, IW->iRowN,
IW->iCols[IW->itemN] + 1, 1,
IW->iLens[IW->itemN], REVERSE2);
return TRUE;
}
/*************************************************************************
* Check for a beep request.
*************************************************************************/
case BEEPiw:
ring_bell ();
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be deleted.
*************************************************************************/
case DELETEiw:
if (IW->iUpTo != NULL) cdf_FreeMemory (IW->iUpTo, FatalError);
if (IW->iDownTo != NULL) cdf_FreeMemory (IW->iDownTo, FatalError);
if (IW->iLeftTo != NULL) cdf_FreeMemory (IW->iLeftTo, FatalError);
if (IW->iRightTo != NULL) cdf_FreeMemory (IW->iRightTo, FatalError);
delete_virtual_display (IW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be erased (but remain in existence).
*************************************************************************/
case UNDISPLAYiw:
unpaste_virtual_display (IW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be redisplayed (but don't wait for input - a call
* with `op = READiw' should be made next).
*************************************************************************/
case REDISPLAYiw:
set_cursor_mode (CURSORoff);
paste_virtual_display (IW->wid, IW->ULrow, IW->ULcol);
va_end (ap);
return TRUE;
/*************************************************************************
* Get next input. The cursor is positioned and turned off first. The
* cursor is positioned for those cases where the cursor cannot be turned
* off. A (possibly) blinking cursor at the end of the highlighted item
* is less distracting than where it might be.
*************************************************************************/
case READiw:
for (;;) {
if (IW->nItems > 0) {
set_cursor_abs (IW->wid, IW->iRowN,
IW->iCols[IW->itemN] + IW->iLens[IW->itemN] + 1);
}
set_cursor_mode (CURSORoff);
read_input (
#if defined(CURSESui)
IW->wid,
#endif
&(IW->key), PASSTHRUri, TRUE);
/********************************************************************
* Check for an exit key. If no exit keys were specified, any key
* causes an exit.
********************************************************************/
if (IW->exitChars[0] == NUL) {
va_end (ap);
return TRUE;
}
else {
int charN;
for (charN = 0; IW->exitChars[charN] != NUL; charN++)
if (IW->key == IW->exitChars[charN]) {
va_end (ap);
return TRUE;
}
}
/********************************************************************
* Check for next-screen key.
********************************************************************/
if (IW->key == IW->NSkey) {
begin_pasteboard_update ();
if (IW->nItems > 0) {
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], NORMAL);
NextScreen (IW->NiRows, IW->NiLines, IW->iLineNs, IW->iDownTo,
IW->iRowB, IW->iRowT, IW->iScroll, &(IW->itemN),
&(IW->iRowN));
DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
IW->NiLines, IW->iLines, IW->nColS);
if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
IWtopRowLineN(IW), IW->iPctRowN,
IW->iPctColN);
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], REVERSE2);
}
else
ring_bell ();
end_pasteboard_update ();
continue;
}
/********************************************************************
* Check for prev-screen key.
********************************************************************/
if (IW->key == IW->PSkey) {
begin_pasteboard_update ();
if (IW->nItems > 0) {
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], NORMAL);
PrevScreen (IW->NiRows, IW->iLineNs, IW->iUpTo, IW->iRowT,
IW->iScroll, &(IW->iRowN), &(IW->itemN));
DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
IW->NiLines, IW->iLines, IW->nColS);
if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
IWtopRowLineN(IW), IW->iPctRowN,
IW->iPctColN);
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], REVERSE2);
}
else
ring_bell ();
end_pasteboard_update ();
continue;
}
/********************************************************************
* Check for down arrow key.
********************************************************************/
if (IW->key == IW_DOWN || IW->key == IW_DOWNx) {
begin_pasteboard_update ();
if (IW->nItems > 0) {
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], NORMAL);
DownArrow (IW->iLineNs, IW->iDownTo, IW->iRowT, IW->iRowB,
IW->iScroll, &(IW->iRowN), &(IW->itemN));
DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
IW->NiLines, IW->iLines, IW->nColS);
if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
IWtopRowLineN(IW), IW->iPctRowN,
IW->iPctColN);
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], REVERSE2);
}
else
ring_bell ();
end_pasteboard_update ();
continue;
}
/********************************************************************
* Check for up arrow key.
********************************************************************/
if (IW->key == IW_UP || IW->key == IW_UPx) {
begin_pasteboard_update ();
if (IW->nItems > 0) {
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], NORMAL);
UpArrow (IW->NiLines, IW->iLineNs, IW->iUpTo, IW->iRowT,
IW->iRowB, IW->iScroll, &(IW->iRowN), &(IW->itemN));
DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
IW->NiLines, IW->iLines, IW->nColS);
if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
IWtopRowLineN(IW), IW->iPctRowN,
IW->iPctColN);
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], REVERSE2);
}
else
ring_bell ();
end_pasteboard_update ();
continue;
}
/********************************************************************
* Check for left arrow key.
********************************************************************/
if (IW->key == IW_LEFT || IW->key == IW_LEFTx) {
begin_pasteboard_update ();
if (IW->nItems > 0) {
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], NORMAL);
IW->itemN = IW->iLeftTo[IW->itemN];
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], REVERSE2);
}
else
ring_bell ();
end_pasteboard_update ();
continue;
}
/********************************************************************
* Check for right arrow key.
********************************************************************/
if (IW->key == IW_RIGHT || IW->key == IW_RIGHTx) {
begin_pasteboard_update ();
if (IW->nItems > 0) {
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], NORMAL);
IW->itemN = IW->iRightTo[IW->itemN];
change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
1, IW->iLens[IW->itemN], REVERSE2);
}
else
ring_bell ();
end_pasteboard_update ();
continue;
}
/********************************************************************
* Check for the `refresh' key.
********************************************************************/
if (IW->key == IW->refreshChar) {
repaint_screen ();
continue;
}
/********************************************************************
* Illegal key, ring the bell.
********************************************************************/
ring_bell ();
}
}
va_end (ap);
return FALSE; /* Illegal operation. */
}
/******************************************************************************
* PromptWindow.
******************************************************************************/
#if defined(STDARG)
int PromptWindow (int opT, ...)
#else
int PromptWindow (va_alist)
va_dcl
#endif
{
int op; /* Operation to perform (eg. create new
prompt window, delete window, etc.). */
struct PromptWindowStruct *PW;
/* Prompt window configuration. */
va_list ap;
/***************************************************************************
* Start variable-length argument list scanning.
***************************************************************************/
#if defined(STDARG)
va_start (ap, opT);
op = opT;
#else
VA_START (ap);
op = va_arg (ap, int);
#endif
PW = va_arg (ap, struct PromptWindowStruct *);
/***************************************************************************
* Perform desired operation. Some operations wait for user input (by
* falling through the `switch' statement).
***************************************************************************/
switch (op) {
/*************************************************************************
* Check for new menu or menu to be reset.
*************************************************************************/
case NEWpw:
case RESETpw: {
/***********************************************************************
* Get remaining arguments.
***********************************************************************/
PW->curChar = va_arg (ap, int);
PW->insertMode = va_arg (ap, Logical);
va_end (ap);
/***********************************************************************
* Calculate positions.
***********************************************************************/
if (op == NEWpw) {
PW->nColS = PW->nColsTotal - 2;
PW->nRowsTotal = (PW->NhLines > 0 ? 1 + PW->NhLines : 0) +
3 +
(PW->NtLines > 0 ? PW->NtLines + 1 : 0);
PW->NvCols = PW->nColsTotal - 6;
PW->vRow = (PW->NhLines > 0 ? PW->NhLines + 2 : 1);
PW->vLcol = 3;
PW->vRcol = PW->vLcol + PW->NvCols - 1;
PW->mLcol = 1;
PW->mRcol = PW->nColsTotal - 2;
if (PW->NhLines > 0) {
PW->hRowT = 1;
PW->hRowB = PW->hRowT + PW->NhLines - 1;
}
if (PW->NtLines > 0) {
PW->tRowT = (PW->NhLines > 0 ? 1 + PW->NhLines : 0) + 3;
PW->tRowB = PW->tRowT + PW->NtLines - 1;
}
}
/***********************************************************************
* Create window?
***********************************************************************/
begin_pasteboard_update ();
if (op == NEWpw) {
create_virtual_display (PW->nRowsTotal, PW->nColsTotal, &(PW->wid),
BORDER, NORMAL);
paste_virtual_display (PW->wid, PW->ULrow, PW->ULcol);
}
/***********************************************************************
* If specified, write label to window.
***********************************************************************/
if (PW->label != NULL) {
int len = (int) strlen(PW->label);
if (len <= PW->nColS) {
int nRemainChars = PW->nColS - len;
int nCharsBefore = nRemainChars / 2;
put_chars (PW->wid, PW->label, len, 0, nCharsBefore + 1, FALSE,
REVERSE1);
}
}
/***********************************************************************
* Draw necessary horizontal and vertical lines.
***********************************************************************/
if (op == NEWpw) {
if (PW->NhLines > 0) draw_horizontal_line (PW->wid, PW->vRow-1, 0,
PW->nColsTotal-1, NORMAL,
TRUE);
if (PW->NtLines > 0) draw_horizontal_line (PW->wid, PW->vRow+1, 0,
PW->nColsTotal-1, NORMAL,
TRUE);
draw_vertical_line (PW->wid, PW->vRow - 1, PW->vRow + 1,
PW->vLcol - 1, NORMAL, TRUE);
draw_vertical_line (PW->wid, PW->vRow - 1, PW->vRow + 1,
PW->vRcol + 1, NORMAL, TRUE);
}
/***********************************************************************
* If specified, draw header.
***********************************************************************/
if (PW->NhLines > 0) DrawSection (PW->wid, PW->hRowT, PW->hRowB, 0,
PW->NhLines, PW->hLines, PW->nColS);
/***********************************************************************
* Draw initial value (if one exists) and place cursor. If a RESETpw
* operation, first erase existing value.
***********************************************************************/
if (op == RESETpw) {
put_chars (PW->wid, " ", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
erase_display (PW->wid, PW->vRow, PW->vLcol, PW->vRow, PW->vRcol);
put_chars (PW->wid, " ", 1, PW->vRow, PW->mRcol, FALSE, NORMAL);
}
PW->curLen = (int) strlen (PW->value);
if (PW->curChar < PW->NvCols) {
if (PW->curLen > PW->NvCols) {
put_chars (PW->wid, PW->value, PW->NvCols, PW->vRow, PW->vLcol,
FALSE, NORMAL);
put_chars (PW->wid, ">", 1, PW->vRow, PW->mRcol, FALSE, NORMAL);
}
else
put_chars (PW->wid, PW->value, PW->curLen, PW->vRow, PW->vLcol,
FALSE, NORMAL);
PW->curCol = PW->vLcol + PW->curChar;
}
else {
put_chars (PW->wid, "<", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
if (PW->curChar < PW->curLen) {
put_chars (PW->wid, &(PW->value[PW->curChar - PW->NvCols + 1]),
PW->NvCols, PW->vRow, PW->vLcol, FALSE, NORMAL);
if (PW->curChar != PW->curLen - 1) put_chars (PW->wid, ">", 1,
PW->vRow, PW->mRcol,
FALSE, NORMAL);
}
else
put_chars (PW->wid, &(PW->value[PW->curChar - PW->NvCols + 1]),
PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE, NORMAL);
PW->curCol = PW->vRcol;
}
/***********************************************************************
* If specified, draw trailer.
***********************************************************************/
if (PW->NtLines > 0) DrawSection (PW->wid, PW->tRowT, PW->tRowB, 0,
PW->NtLines, PW->tLines, PW->nColS);
/***********************************************************************
* Update screen.
***********************************************************************/
end_pasteboard_update ();
/***********************************************************************
* Position cursor (which must occur after the pasteboard batching is
* ended).
***********************************************************************/
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
set_cursor_mode (CURSORon);
return TRUE;
}
/*************************************************************************
* Check for a beep request.
*************************************************************************/
case BEEPpw:
ring_bell ();
va_end (ap);
return TRUE;
/*************************************************************************
* Check if window should be erased (but remain in existence).
*************************************************************************/
case UNDISPLAYpw:
unpaste_virtual_display (PW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Check if window should be redisplayed (don't wait for input - a call
* with `op = READpw' should be made next).
*************************************************************************/
case REDISPLAYpw:
paste_virtual_display (PW->wid, PW->ULrow, PW->ULcol);
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
set_cursor_mode (CURSORon);
va_end (ap);
return TRUE;
/*************************************************************************
* Check if window should be deleted.
*************************************************************************/
case DELETEpw:
delete_virtual_display (PW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Read keystrokes until `exit' key entered.
*************************************************************************/
case READpw: {
int colsToEnd; /* Number of columns from cursor to the right-
most column of the value field (including
the cursor position). */
int offRight; /* Number of characters to the right of the
last column in the value field (the right
`more' indicator should be ON). This can
be zero or negative. */
int offLeft; /* Number of characters to the left of the
first column in the value field (the left
`more' indicator should be ON). This can
be zero or negative. */
int charsToEnd; /* Number of characters from the cursor to the
end of the value (including at the cursor
position). */
int leftColChar; /* Character number at left column of value
field. */
int rightColChar; /* Character number at right column of value
field. */
int charN; /* Character number. */
/***********************************************************************
* Set cursor mode/position.
***********************************************************************/
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
set_cursor_mode (CURSORon);
/***********************************************************************
* Read/process keys until an `exit' key...
***********************************************************************/
for (;;) {
read_input (
#if defined(CURSESui)
PW->wid,
#endif
&(PW->key), PASSTHRUri, TRUE);
/********************************************************************
* Check for an `exit' key.
********************************************************************/
for (charN = 0; PW->exitChars[charN] != NUL; charN++) {
if (PW->key == PW->exitChars[charN]) {
va_end (ap);
return TRUE;
}
}
/********************************************************************
* Check for left arrow.
********************************************************************/
if (PW->key == KB_LEFTARROW) {
begin_pasteboard_update ();
if (PW->curCol > PW->vLcol) {
PW->curChar--;
PW->curCol--;
}
else
if (PW->curChar > 0) {
PW->curChar--;
charsToEnd = PW->curLen - PW->curChar;
put_chars (PW->wid, &(PW->value[PW->curChar]),
MINIMUM(charsToEnd,PW->NvCols), PW->vRow, PW->vLcol,
FALSE, NORMAL);
if (PW->curChar == 0) put_chars (PW->wid, " ", 1, PW->vRow,
PW->mLcol, FALSE, NORMAL);
offRight = charsToEnd - PW->NvCols;
if (offRight == 1) put_chars (PW->wid, ">", 1, PW->vRow,
PW->mRcol, FALSE, NORMAL);
}
else
ring_bell ();
end_pasteboard_update ();
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
continue;
}
/********************************************************************
* Check for right arrow.
********************************************************************/
if (PW->key == KB_RIGHTARROW) {
begin_pasteboard_update ();
if (PW->curCol < PW->vRcol) {
if (PW->curChar < PW->curLen) {
PW->curChar++;
PW->curCol++;
}
else
ring_bell ();
}
else
if (PW->curChar < PW->curLen) {
PW->curChar++;
leftColChar = PW->curChar - PW->NvCols + 1;
if (PW->curChar == PW->curLen) {
put_chars (PW->wid, &(PW->value[leftColChar]),
PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE,
NORMAL);
put_chars (PW->wid, " ", 1, PW->vRow, PW->vRcol, FALSE,
NORMAL);
}
else
put_chars (PW->wid, &(PW->value[leftColChar]), PW->NvCols,
PW->vRow, PW->vLcol, FALSE, NORMAL);
put_chars (PW->wid, "<", 1, PW->vRow, PW->mLcol, FALSE,
NORMAL);
charsToEnd = PW->curLen - PW->curChar;
colsToEnd = PW->vRcol - PW->curCol + 1;
offRight = charsToEnd - colsToEnd;
if (offRight == 0) put_chars (PW->wid, " ", 1, PW->vRow,
PW->mRcol, FALSE, NORMAL);
}
else
ring_bell ();
end_pasteboard_update ();
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
continue;
}
/********************************************************************
* Check for delete key.
********************************************************************/
if (PW->key == KB_DELETE) {
begin_pasteboard_update ();
if (PW->curCol == PW->vLcol) {
if (PW->curChar > 0) {
charsToEnd = PW->curLen - PW->curChar;
memmove (&PW->value[PW->curChar-1], &PW->value[PW->curChar],
charsToEnd + 1);
PW->curChar--;
PW->curLen--;
if (PW->curChar == 0) put_chars (PW->wid, " ", 1, PW->vRow,
PW->mLcol, FALSE, NORMAL);
}
else
ring_bell ();
}
else {
charsToEnd = PW->curLen - PW->curChar;
colsToEnd = PW->vRcol - PW->curCol + 1;
offRight = charsToEnd - colsToEnd;
if (offRight > 0) {
memmove (&(PW->value[PW->curChar-1]),
&(PW->value[PW->curChar]), charsToEnd + 1);
PW->curChar--;
PW->curCol--;
PW->curLen--;
colsToEnd++;
put_chars (PW->wid, &(PW->value[PW->curChar]), colsToEnd,
PW->vRow, PW->curCol, FALSE, NORMAL);
offRight--;
if (offRight == 0) put_chars (PW->wid, " ", 1, PW->vRow,
PW->mRcol, FALSE, NORMAL);
}
else
if (charsToEnd > 0) {
memmove (&(PW->value[PW->curChar-1]),
&(PW->value[PW->curChar]), charsToEnd + 1);
PW->curChar--;
PW->curCol--;
PW->curLen--;
put_chars (PW->wid, &(PW->value[PW->curChar]), charsToEnd,
PW->vRow, PW->curCol, FALSE, NORMAL);
put_chars (PW->wid, " ", 1, PW->vRow,
PW->curCol + charsToEnd, FALSE, NORMAL);
}
else {
PW->curChar--;
PW->value[PW->curChar] = NUL;
PW->curLen--;
PW->curCol--;
put_chars (PW->wid, " ", 1, PW->vRow, PW->curCol, FALSE,
NORMAL);
}
}
end_pasteboard_update ();
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
continue;
}
/********************************************************************
* Check for the `refresh' key.
********************************************************************/
if (PW->key == PW->refreshChar) {
repaint_screen ();
continue;
}
/********************************************************************
* Check for the SOL key. If the current length of the value is
* greater than the number of available columns, the right `more'
* indicator is drawn (even though it may already be drawn).
********************************************************************/
if (PW->key == PW->SOLchar) {
begin_pasteboard_update ();
leftColChar = PW->curChar - (PW->curCol - PW->vLcol);
if (leftColChar > 0) {
put_chars (PW->wid, " ", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
put_chars (PW->wid, PW->value, PW->NvCols, PW->vRow, PW->vLcol,
FALSE, NORMAL);
if (PW->curLen > PW->NvCols) put_chars (PW->wid, ">", 1,
PW->vRow, PW->mRcol,
FALSE, NORMAL);
}
PW->curCol = PW->vLcol;
PW->curChar = 0;
end_pasteboard_update ();
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
continue;
}
/********************************************************************
* Check for the EOL key. The `right column character' is used to
* determine if moving the cursor to the end of the value will cause
* characters to be off the left end of the value field. The left
* and right `more' indicators are updated regardless of how they may
* have already been.
********************************************************************/
if (PW->key == PW->EOLchar) {
begin_pasteboard_update ();
rightColChar = PW->curChar + (PW->vRcol - PW->curCol);
if (rightColChar < PW->curLen) {
put_chars (PW->wid, "<", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
put_chars (PW->wid, &(PW->value[PW->curLen - PW->NvCols + 1]),
PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE, NORMAL);
put_chars (PW->wid, " ", 1, PW->vRow, PW->vRcol, FALSE, NORMAL);
put_chars (PW->wid, " ", 1, PW->vRow, PW->mRcol, FALSE, NORMAL);
}
PW->curCol = MinInt (PW->vLcol + PW->curLen, PW->vRcol);
PW->curChar = PW->curLen;
end_pasteboard_update ();
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
continue;
}
/********************************************************************
* Check for the toggle insert/overstrike mode key.
********************************************************************/
if (PW->key == PW->TOGGLEchar) {
PW->insertMode = (PW->insertMode ? FALSE : TRUE);
continue;
}
/********************************************************************
* Check for a printable character to insert/overstrike.
********************************************************************/
if (Printable(PW->key)) {
begin_pasteboard_update ();
charsToEnd = PW->curLen - PW->curChar;
colsToEnd = PW->vRcol - PW->curCol + 1;
if (charsToEnd == 0) {
/****************************************************************
* The cursor is at the end of the value.
****************************************************************/
if (PW->curLen < PW->maxChars) {
catchrX (PW->value, PW->key, PW->maxChars);
PW->curLen++;
PW->curChar++;
if (colsToEnd > 1) {
put_chars (PW->wid, &(PW->value[PW->curChar-1]), 1, PW->vRow,
PW->curCol, FALSE, NORMAL);
PW->curCol++;
}
else {
leftColChar = PW->curChar - PW->NvCols + 1;
put_chars (PW->wid, &(PW->value[leftColChar]), PW->NvCols-1,
PW->vRow, PW->vLcol, FALSE, NORMAL);
offLeft = PW->curLen - PW->NvCols + 1;
if (offLeft == 1) put_chars (PW->wid, "<", 1, PW->vRow,
PW->mLcol, FALSE, NORMAL);
}
}
else
ring_bell ();
}
else {
/****************************************************************
* The cursor is somewhere in the middle of the value.
****************************************************************/
if (!PW->insertMode ||
(PW->insertMode && PW->curLen < PW->maxChars)) {
if (PW->insertMode) {
/************************************************************
* Insert mode.
************************************************************/
memmove (&(PW->value[PW->curChar+1]),
&(PW->value[PW->curChar]), charsToEnd + 1);
PW->value[PW->curChar] = PW->key;
PW->curLen++;
if (colsToEnd > 1) {
/**********************************************************
* The cursor is not in the last column of the value field.
**********************************************************/
put_chars (PW->wid, &(PW->value[PW->curChar]),
MINIMUM(colsToEnd,charsToEnd + 1),
PW->vRow, PW->curCol, FALSE, NORMAL);
PW->curChar++;
PW->curCol++;
charsToEnd = PW->curLen - PW->curChar;
colsToEnd = PW->vRcol - PW->curCol + 1;
offRight = charsToEnd - colsToEnd;
if (offRight == 1) put_chars (PW->wid, ">", 1, PW->vRow,
PW->mRcol, FALSE, NORMAL);
}
else {
/**********************************************************
* The cursor is in the last column of the value field.
**********************************************************/
PW->curChar++;
leftColChar = PW->curChar - PW->NvCols + 1;
put_chars (PW->wid, &(PW->value[leftColChar]), PW->NvCols,
PW->vRow, PW->vLcol, FALSE, NORMAL);
if (leftColChar == 1) put_chars (PW->wid, "<", 1, PW->vRow,
PW->mLcol, FALSE, NORMAL);
}
}
else {
/************************************************************
* Overstrike mode.
************************************************************/
PW->value[PW->curChar] = PW->key;
if (colsToEnd > 1) {
/**********************************************************
* The cursor is not in the last column of the value field.
**********************************************************/
put_chars (PW->wid, &(PW->value[PW->curChar]), 1, PW->vRow,
PW->curCol, FALSE, NORMAL);
PW->curChar++;
PW->curCol++;
}
else {
/**********************************************************
* The cursor is in the last column of the value field.
**********************************************************/
offRight = charsToEnd - 1;
if (offRight > 0) {
/********************************************************
* One or more character off the right end.
********************************************************/
PW->curChar++;
leftColChar = PW->curChar - PW->NvCols + 1;
put_chars (PW->wid, &(PW->value[leftColChar]),
PW->NvCols, PW->vRow, PW->vLcol, FALSE,
NORMAL);
if (leftColChar == 1) put_chars (PW->wid, "<", 1,
PW->vRow, PW->mLcol,
FALSE, NORMAL);
offRight--;
if (offRight == 0) put_chars (PW->wid, " ", 1, PW->vRow,
PW->mRcol, FALSE, NORMAL);
}
else {
/********************************************************
* Cursor is on the last character.
********************************************************/
PW->curChar++;
leftColChar = PW->curChar - PW->NvCols + 1;
put_chars (PW->wid, &(PW->value[leftColChar]),
PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE,
NORMAL);
put_chars (PW->wid, " ", 1, PW->vRow, PW->vRcol, FALSE,
NORMAL);
if (leftColChar == 1) put_chars (PW->wid, "<", 1,
PW->vRow, PW->mLcol,
FALSE, NORMAL);
}
}
}
}
else
ring_bell ();
}
end_pasteboard_update ();
set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
continue;
}
/********************************************************************
* None of the above, illegal character.
********************************************************************/
ring_bell ();
}
}
}
va_end (ap);
return FALSE; /* Illegal operation. */
}
/******************************************************************************
* EditWindow.
******************************************************************************/
#if defined(STDARG)
int EditWindow (int opT, ...)
#else
int EditWindow (va_alist)
va_dcl
#endif
{
int op; /* Operation to perform (eg. create new
edit window, delete window, etc.). */
struct EditWindowStruct *EW; /* Edit window configuration. */
va_list ap;
/***************************************************************************
* Start variable-length argument list scanning.
***************************************************************************/
#if defined(STDARG)
va_start (ap, opT);
op = opT;
#else
VA_START (ap);
op = va_arg (ap, int);
#endif
EW = va_arg (ap, struct EditWindowStruct *);
/***************************************************************************
* Perform desired operation. Some operations wait for user input (by
* falling through the `switch' statement).
***************************************************************************/
switch (op) {
/*************************************************************************
* Check for new menu.
*************************************************************************/
case NEWew:
case UPDATEew: {
/***********************************************************************
* Get remaining arguments.
***********************************************************************/
EW->insertMode = va_arg (ap, Logical);
va_end (ap);
/***********************************************************************
* Create window?
***********************************************************************/
begin_pasteboard_update ();
if (op == NEWew) {
EW->nRowsTotal = BOO(EW->NhLines > 0,1,0) + EW->NhLines +
BOO(EW->NeRows > 0,1,0) + EW->NeRows +
BOO(EW->NtLines > 0,1,0) + EW->NtLines + 1;
create_virtual_display (EW->nRowsTotal, EW->nColsTotal, &(EW->wid),
BORDER, NORMAL);
paste_virtual_display (EW->wid, EW->ULrow, EW->ULcol);
EW->nColS = EW->nColsTotal - 2;
}
/***********************************************************************
* If specified, write label to window. If this is an update operation,
* first overwrite the existing label.
***********************************************************************/
if (op == UPDATEew) draw_horizontal_line (EW->wid, 0, 1, EW->nColS,
NORMAL, FALSE);
if (EW->label != NULL) {
int len = (int) strlen(EW->label);
if (len <= EW->nColS) {
int nRemainChars = EW->nColS - len;
int nCharsBefore = nRemainChars / 2;
put_chars (EW->wid, EW->label, len, 0, nCharsBefore + 1, FALSE,
REVERSE1);
}
}
/***********************************************************************
* If necessary, calculate positions and draw horizontal lines on window.
***********************************************************************/
if (op == NEWew) {
int nSections = 0; /* Number of sections in the window. */
int xRow = 1; /* Start at row 1 (row 0 is top border line). */
if (EW->NhLines > 0) {
nSections++;
EW->hRowT = xRow;
EW->hRowB = EW->hRowT + EW->NhLines - 1;
xRow += EW->NhLines + 1;
}
if (EW->NeRows > 0) {
nSections++;
EW->eRowT = xRow;
EW->eRowB = EW->eRowT + EW->NeRows - 1;
xRow += EW->NeRows + 1;
if (nSections > 1) draw_horizontal_line (EW->wid, EW->eRowT - 1, 0,
EW->nColsTotal - 1, NORMAL,
TRUE);
}
if (EW->NtLines > 0) {
nSections++;
EW->tRowT = xRow;
EW->tRowB = EW->tRowT + EW->NtLines - 1;
xRow += EW->NtLines + 1;
if (nSections > 1) draw_horizontal_line (EW->wid, EW->tRowT - 1, 0,
EW->nColsTotal - 1, NORMAL,
TRUE);
}
}
/***********************************************************************
* If specified, write header section to window. If an update operation,
* it is assumed that the number of lines has not changed.
***********************************************************************/
if (EW->NhLines > 0) DrawSection (EW->wid, EW->hRowT, EW->hRowB, 0,
EW->NhLines, EW->hLines, EW->nColS);
/***********************************************************************
* Write edit section to window. If an update operation, note that the
* text may have changed (to more or less lines) but not the number of
* rows.
***********************************************************************/
EW->nChars = (int) strlen(EW->eText);
EW->xChars = EW->nChars;
EW->cursorRow = EW->eRowT;
EW->cursorCol = 1;
EW->firstChar = 0;
EW->cursorChar = 0;
DrawEditSection (EW);
/*********************************************************************
* Setup/display initial percentage indicator.
*********************************************************************/
if (EW->ePct) {
if (op == NEWew) {
EW->ePctRowN = EW->eRowB + 1;
EW->ePctColN = EW->nColsTotal - 7;
}
UpdatePctString (EW->wid, EW->nChars + 1, 1, EW->cursorChar,
EW->ePctRowN, EW->ePctColN);
}
/***********************************************************************
* If specified, write trailer section to window. If an update
* operation, it is assumed that the number of lines has not changed.
***********************************************************************/
if (EW->NtLines > 0) DrawSection (EW->wid, EW->tRowT, EW->tRowB, 0,
EW->NtLines, EW->tLines, EW->nColS);
/***********************************************************************
* Update screen.
***********************************************************************/
end_pasteboard_update ();
/***********************************************************************
* Position cursor (which must occur after the pasteboard batching is
* ended).
***********************************************************************/
set_cursor_abs (EW->wid, EW->cursorRow, EW->cursorCol);
set_cursor_mode (CURSORon);
return TRUE;
}
/*************************************************************************
* Check for a beep request.
*************************************************************************/
case BEEPew:
ring_bell ();
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be deleted.
*************************************************************************/
case DELETEew:
delete_virtual_display (EW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Get next input (exit key).
*************************************************************************/
case READew: {
int length, i, count;
set_cursor_abs (EW->wid, EW->cursorRow, EW->cursorCol);
set_cursor_mode (CURSORon);
for (;;) {
read_input (
#if defined(CURSESui)
EW->wid,
#endif
&(EW->key), PASSTHRUri, TRUE);
/********************************************************************
* Check for an exit key. If no exit keys were specified, any key
* causes an exit.
********************************************************************/
if (EW->exitChars[0] == NUL) {
va_end (ap);
return TRUE;
}
else {
int charN;
for (charN = 0; EW->exitChars[charN] != NUL; charN++) {
if (EW->key == EW->exitChars[charN]) {
va_end (ap);
return TRUE;
}
}
}
/********************************************************************
* Check for start-of-line key.
********************************************************************/
if (EW->key == EW->SOLkey) {
ring_bell ();
continue;
}
/********************************************************************
* Check for end-of-line key.
********************************************************************/
if (EW->key == EW->EOLkey) {
ring_bell ();
continue;
}
/********************************************************************
* Check for start-of-text key.
********************************************************************/
if (EW->key == EW->SOTkey) {
ring_bell ();
continue;
}
/********************************************************************
* Check for end-of-text key.
********************************************************************/
if (EW->key == EW->EOTkey) {
ring_bell ();
continue;
}
/********************************************************************
* Check for next-word key.
********************************************************************/
if (EW->key == EW->NWkey) {
ring_bell ();
continue;
}
/********************************************************************
* Check for delete-line key.
********************************************************************/
if (EW->key == EW->DLkey) {
if (EW->readOnly)
ring_bell ();
else {
ring_bell ();
}
continue;
}
/********************************************************************
* Check for next-screen key.
********************************************************************/
if (EW->key == EW->NSkey) {
if (EW->eText[EW->cursorChar] == NUL)
ring_bell ();
else {
int count; /* Number of lines that cursor is moved down. */
/****************************************************************
* Move the cursor to the beginning of the line.
****************************************************************/
while (EW->cursorChar > 0) {
if (EW->eText[EW->cursorChar-1] == Nl) break;
EW->cursorChar--;
}
/****************************************************************
* Move the cursor down the number of rows displayed (or less).
****************************************************************/
for (count = 0;
EW->eText[EW->cursorChar] != NUL;
EW->cursorChar++) {
if (EW->eText[EW->cursorChar] == Nl) {
count++;
if (count == EW->NeRows) {
EW->cursorChar++;
break;
}
}
}
/****************************************************************
* Move the `first character displayed' down the same number of
* rows (if necessary).
****************************************************************/
if (EW->cursorRow + count > EW->eRowB) {
int count1; /* Number of lines after the first displayed. */
int charN;
for (count1 = 0, charN = EW->firstChar;
EW->eText[charN] != NUL; charN++) {
if (EW->eText[charN] == Nl) count1++;
}
count1 -= (EW->NeRows - 1);
count1 = MINIMUM(count1,count);
while (count1 > 0) {
if (EW->eText[EW->firstChar] == Nl) count1--;
EW->firstChar++;
}
DrawEditSection (EW);
}
/****************************************************************
* Update the percentage and cursor position.
****************************************************************/
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for prev-screen key.
********************************************************************/
if (EW->key == EW->PSkey) {
if (EW->cursorChar == 0)
ring_bell ();
else {
int count; /* Number of lines that cursor is moved up. */
/****************************************************************
* Move the cursor to the beginning of the line.
****************************************************************/
while (EW->cursorChar > 0) {
if (EW->eText[EW->cursorChar-1] == Nl) break;
EW->cursorChar--;
}
/****************************************************************
* Move the cursor up the number of rows displayed (or less).
****************************************************************/
for (count = 0; EW->cursorChar > 0; EW->cursorChar--) {
if (EW->eText[EW->cursorChar] == Nl) {
count++;
if (count == EW->NeRows) {
if (EW->cursorChar > 0) {
EW->cursorChar--;
while (EW->cursorChar > 0) {
if (EW->eText[EW->cursorChar-1] == Nl) break;
EW->cursorChar--;
}
}
break;
}
}
}
/****************************************************************
* Move the `first character displayed' up the same number of
* rows (if necessary).
****************************************************************/
if (EW->cursorRow - count < EW->eRowT) {
while (EW->firstChar > 0) {
if (EW->eText[EW->firstChar] == Nl) {
count--;
if (count == 0) {
if (EW->firstChar > 0) {
EW->firstChar--;
while (EW->firstChar > 0) {
if (EW->eText[EW->firstChar-1] == Nl) break;
EW->firstChar--;
}
}
break;
}
}
EW->firstChar--;
}
DrawEditSection (EW);
}
/****************************************************************
* Update the percentage and cursor position.
****************************************************************/
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for down arrow key.
********************************************************************/
if (EW->key == KB_DOWNARROW) {
char *nextNL = strchr (&(EW->eText[EW->cursorChar]), Nl);
if (nextNL == NULL)
ring_bell ();
else {
int toNL = (int) (nextNL - &(EW->eText[EW->cursorChar]));
EW->cursorChar += (toNL + 1);
for (i = 1; i < EW->cursorCol; i++) {
if (EW->eText[EW->cursorChar] == Nl) break;
if (EW->eText[EW->cursorChar] == NUL) break;
EW->cursorChar++;
}
if (EW->cursorRow == EW->eRowB) {
while (EW->eText[EW->firstChar] != Nl) EW->firstChar++;
EW->firstChar++;
DrawEditSection (EW);
}
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for up arrow key.
********************************************************************/
if (EW->key == KB_UPARROW) {
if (EW->firstChar == 0 && EW->cursorRow == EW->eRowT)
ring_bell ();
else {
/****************************************************************
* If the cursor is on the top line then scroll up one line.
****************************************************************/
if (EW->cursorRow == EW->eRowT) {
for (EW->firstChar--; EW->firstChar > 0; EW->firstChar--) {
if (EW->eText[EW->firstChar-1] == Nl) break;
}
DrawEditSection (EW);
}
/****************************************************************
* Set the cursor character as follows...
* 1. Move backward to the newline character of the preceeding
* line while counting the number of characters moved.
* 2. Move backward to the first character of the preceeding
* line.
* 3. Move forward to position the cursor character at the same
* column or at the newline character (which ever occurs
* first).
****************************************************************/
for (count = 1, EW->cursorChar--;
EW->eText[EW->cursorChar] != Nl;
EW->cursorChar--) count++;
while (EW->cursorChar > 0) {
if (EW->eText[EW->cursorChar-1] == Nl) break;
EW->cursorChar--;
}
for (i = 1; i < count; i++) {
if (EW->eText[EW->cursorChar] == Nl) break;
EW->cursorChar++;
}
/****************************************************************
* Update the percentage and cursor position.
****************************************************************/
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for left arrow key.
********************************************************************/
if (EW->key == KB_LEFTARROW) {
if (EW->cursorChar == 0)
ring_bell ();
else {
if (EW->cursorChar == EW->firstChar) {
for (EW->firstChar--; EW->firstChar > 0; EW->firstChar--) {
if (EW->eText[EW->firstChar-1] == Nl) break;
}
DrawEditSection (EW);
}
EW->cursorChar--;
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for right arrow key.
********************************************************************/
if (EW->key == KB_RIGHTARROW) {
if (EW->eText[EW->cursorChar] == NUL)
ring_bell ();
else {
if (EW->cursorRow == EW->eRowB &&
EW->eText[EW->cursorChar] == Nl) {
while (EW->eText[EW->firstChar] != Nl) EW->firstChar++;
EW->firstChar++;
DrawEditSection (EW);
}
EW->cursorChar++;
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for the RETURN key.
********************************************************************/
if (EW->key == KB_RETURN) {
if (EW->readOnly)
ring_bell ();
else {
if (EW->nChars == EW->xChars) {
EW->xChars += EW->nColS;
EW->eText = cdf_ReallocateMemory (EW->eText,
(size_t) (EW->xChars + 1),
FatalError);
}
length = (int) strlen (&(EW->eText[EW->cursorChar]));
memmove (&(EW->eText[EW->cursorChar+1]),
&(EW->eText[EW->cursorChar]), (size_t) (length + 1));
EW->eText[EW->cursorChar] = Nl;
EW->nChars++;
EW->cursorChar++;
if (EW->cursorRow == EW->eRowB) {
while (EW->eText[EW->firstChar] != Nl) EW->firstChar++;
EW->firstChar++;
}
DrawEditSection (EW);
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Check for the DELETE key.
********************************************************************/
if (EW->key == KB_DELETE) {
if (EW->readOnly)
ring_bell ();
else {
if (EW->cursorChar == 0)
ring_bell ();
else {
length = (int) strlen (&(EW->eText[EW->cursorChar]));
memmove (&(EW->eText[EW->cursorChar-1]),
&(EW->eText[EW->cursorChar]), (size_t) (length + 1));
EW->nChars--;
if (EW->cursorChar == EW->firstChar) {
for (EW->firstChar--; EW->firstChar > 0; EW->firstChar--) {
if (EW->eText[EW->firstChar-1] == Nl) break;
}
}
EW->cursorChar--;
DrawEditSection (EW);
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
}
continue;
}
/********************************************************************
* Check for the toggle insert/overstrike mode key.
********************************************************************/
if (EW->key == EW->TOGGLEkey) {
if (EW->readOnly)
ring_bell ();
else
EW->insertMode = BOO(EW->insertMode,FALSE,TRUE);
continue;
}
/********************************************************************
* Check for the `refresh' key.
********************************************************************/
if (EW->key == EW->REFRESHkey) {
repaint_screen ();
continue;
}
/********************************************************************
* Check for a printable character.
********************************************************************/
if (Printable(EW->key)) {
if (EW->readOnly)
ring_bell ();
else {
if (EW->insertMode ||
EW->eText[EW->cursorChar] == Nl || /* If over- */
EW->eText[EW->cursorChar] == NUL) { /* strike mode. */
if (EW->nChars == EW->xChars) {
EW->xChars += EW->nColS;
EW->eText = cdf_ReallocateMemory (EW->eText,
(size_t) (EW->xChars + 1),
FatalError);
}
length = (int) strlen (&(EW->eText[EW->cursorChar]));
memmove (&(EW->eText[EW->cursorChar+1]),
&(EW->eText[EW->cursorChar]), (size_t) (length + 1));
EW->eText[EW->cursorChar] = (char) EW->key;
EW->nChars++;
}
else
EW->eText[EW->cursorChar] = (char) EW->key;
DrawEditSection (EW);
if (EW->cursorCol < EW->nColS) EW->cursorChar++;
if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
EW->cursorChar, EW->ePctRowN,
EW->ePctColN);
SetEditCursor (EW);
}
continue;
}
/********************************************************************
* Illegal key, ring the bell.
********************************************************************/
ring_bell ();
}
}
}
va_end (ap);
return FALSE; /* Illegal operation. */
}
/******************************************************************************
* DrawEditSection.
******************************************************************************/
static void DrawEditSection (EW)
struct EditWindowStruct *EW;
{
char *charPtr = &(EW->eText[EW->firstChar]);
int rowN = EW->eRowT, length;
for (;;) {
char *nextNL = strchr (charPtr, Nl);
if (nextNL == NULL) {
length = (int) strlen (charPtr);
if (length > 0) {
put_chars (EW->wid, charPtr, MINIMUM(length,EW->nColS), rowN, 1,
FALSE, NORMAL);
if (length < EW->nColS) erase_display (EW->wid, rowN, length + 1,
rowN, EW->nColS);
rowN++;
}
break;
}
length = (int) (nextNL - charPtr);
put_chars (EW->wid, charPtr, MINIMUM(length,EW->nColS), rowN, 1, FALSE,
NORMAL);
if (length < EW->nColS) erase_display (EW->wid, rowN, length + 1,
rowN, EW->nColS);
rowN++;
if (rowN > EW->eRowB) break;
charPtr = nextNL + 1;
}
if (rowN <= EW->eRowB) erase_display (EW->wid, rowN, 1,
EW->eRowB, EW->nColS);
return;
}
/******************************************************************************
* SetEditCursor.
******************************************************************************/
static void SetEditCursor (EW)
struct EditWindowStruct *EW;
{
int charN;
EW->cursorRow = EW->eRowT;
EW->cursorCol = 0;
for (charN = EW->firstChar; charN <= EW->cursorChar; charN++) {
EW->cursorCol++;
if (EW->eText[charN] == Nl && charN < EW->cursorChar) {
EW->cursorCol = 0;
EW->cursorRow++;
}
}
set_cursor_abs (EW->wid, EW->cursorRow, EW->cursorCol);
return;
}
/******************************************************************************
* FieldWindow.
*
* Header section (optional).
* Fields section (scrollable) containing one or more fields.
* Trailer section (optional).
*
******************************************************************************/
#if defined(STDARG)
int FieldWindow (int opT, ...)
#else
int FieldWindow (va_alist)
va_dcl
#endif
{
int op; /* Operation to perform (eg. create new menu). */
struct FieldWindowStruct *FW;
/* Menu configuration. */
va_list ap;
/***************************************************************************
* Start variable-length argument list scanning.
***************************************************************************/
#if defined(STDARG)
va_start (ap, opT);
op = opT;
#else
VA_START (ap);
op = va_arg (ap, int);
#endif
FW = va_arg (ap, struct FieldWindowStruct *);
/***************************************************************************
* Perform desired operation. Some operations wait for user input (by
* falling through the `switch' statement).
***************************************************************************/
switch (op) {
/*************************************************************************
* Check for new/modified menu.
*************************************************************************/
case NEWfw:
case UPDATEfw: {
int nSections; /* Number of sections on window. */
int nHorizLines; /* Number of horizontal lines needed. At
most 2 horizontal lines will be needed
to separate the 3 sections. */
int horizRows[2]; /* Rows at which to draw the horizontal
lines. */
int horizLineN; /* Horizontal line number. */
int xRow; /* Used when determining starting rows for
the various sections. */
/***********************************************************************
* Get remaining arguments.
***********************************************************************/
FW->fieldN = va_arg (ap, int);
FW->insert = va_arg (ap, Logical);
va_end (ap);
/***********************************************************************
* Validate menu.
***********************************************************************/
if (FW->NfRows < 1) return FALSE;
/***********************************************************************
* Turn on cursor.
***********************************************************************/
set_cursor_mode (CURSORon);
/***********************************************************************
* Calculate positions.
***********************************************************************/
if (op == NEWfw) {
FW->nColS = FW->nColsTotal - 2;
nSections = 0;
nHorizLines = 0;
/*********************************************************************
* Start at row 1 (row 0 is top border line).
*********************************************************************/
xRow = 1;
if (FW->NhLines > 0) {
nSections++;
FW->hRowT = xRow;
FW->hRowB = FW->hRowT + FW->NhLines - 1;
xRow += FW->NhLines + 1;
}
nSections++;
FW->fRowT = xRow;
FW->fRowB = FW->fRowT + FW->NfRows - 1;
xRow += FW->NfRows + 1;
if (nSections > 1) horizRows[nHorizLines++] = FW->fRowT - 1;
if (FW->NtLines > 0) {
nSections++;
FW->tRowT = xRow;
FW->tRowB = FW->tRowT + FW->NtLines - 1;
xRow += FW->NtLines + 1;
if (nSections > 1) horizRows[nHorizLines++] = FW->tRowT - 1;
}
FW->nRowsTotal = xRow;
}
/***********************************************************************
* Create window?
***********************************************************************/
begin_pasteboard_update ();
if (op == NEWfw) {
create_virtual_display (FW->nRowsTotal, FW->nColsTotal, &(FW->wid),
BORDER, NORMAL);
paste_virtual_display (FW->wid, FW->ULrow, FW->ULcol);
}
/***********************************************************************
* If specified, write label to window. If this is an update operation,
* first overwrite the existing label.
***********************************************************************/
if (op == UPDATEfw) draw_horizontal_line (FW->wid, 0, 1, FW->nColS,
NORMAL, FALSE);
if (FW->label != NULL) {
int len = (int) strlen(FW->label);
if (len <= FW->nColS) {
int nRemainChars = FW->nColS - len;
int nCharsBefore = nRemainChars / 2;
put_chars (FW->wid, FW->label, len, 0, nCharsBefore + 1, FALSE,
REVERSE1);
}
}
/***********************************************************************
* If necessary, draw horizontal lines on window.
***********************************************************************/
if (op == NEWfw) {
for (horizLineN = 0; horizLineN < nHorizLines; horizLineN++) {
draw_horizontal_line (FW->wid, horizRows[horizLineN], 0,
FW->nColsTotal-1, NORMAL, TRUE);
}
}
/***********************************************************************
* If specified, write header section to window. If an update operation,
* it is assumed that the number of lines has not changed.
***********************************************************************/
if (FW->NhLines > 0) DrawSection (FW->wid, FW->hRowT, FW->hRowB, 0,
FW->NhLines, FW->hLines, FW->nColS);
/***********************************************************************
* Write fields section to window. If an update operation, note that
* the number of lines may have changed.
***********************************************************************/
if (op == UPDATEfw) {
if (FW->fUpTo != NULL) cdf_FreeMemory (FW->fUpTo, FatalError);
if (FW->fDownTo != NULL) cdf_FreeMemory (FW->fDownTo, FatalError);
if (FW->fLeftTo != NULL) cdf_FreeMemory (FW->fLeftTo, FatalError);
if (FW->fRightTo != NULL) cdf_FreeMemory (FW->fRightTo, FatalError);
}
if (FW->nFields > 0) {
size_t nBytes = FW->nFields * sizeof(int);
FW->fUpTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
FW->fDownTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
FW->fLeftTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
FW->fRightTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
CalcItemDirections (FW->nFields, FW->NfLines, FW->fLineNs, FW->fCols,
FW->fLens, FW->fDownTo, FW->fUpTo, FW->fLeftTo,
FW->fRightTo);
}
else {
FW->fUpTo = NULL;
FW->fDownTo = NULL;
FW->fLeftTo = NULL;
FW->fRightTo = NULL;
}
if (FW->NfLines > FW->NfRows)
FW->fScroll = TRUE;
else
FW->fScroll = FALSE;
/***********************************************************************
* Determine row number for current field. If this is an UPDATEfw
* operation, try to keep the row number the same as it was (or as
* close as possible).
***********************************************************************/
if (FW->nFields > 0) {
if (op == NEWfw)
FW->fRowN = MinInt (FW->fRowT + FW->fLineNs[FW->fieldN], FW->fRowB);
else {
if (FW->fScroll) {
int nLinesFromTop = FW->fLineNs[FW->fieldN];
int nRowsFromTop = FW->fRowN - FW->fRowT;
if (nLinesFromTop < nRowsFromTop)
FW->fRowN -= nRowsFromTop - nLinesFromTop;
else {
int nLinesFromBot = (FW->NfLines-1) - FW->fLineNs[FW->fieldN];
int nRowsFromBot = FW->fRowB - FW->fRowN;
if (nLinesFromBot < nRowsFromBot)
FW->fRowN += nRowsFromBot - nLinesFromBot;
}
}
else
FW->fRowN = FW->fRowT + FW->fLineNs[FW->fieldN];
}
}
else
FW->fRowN = FW->fRowT;
/*********************************************************************
* Draw fields section.
*********************************************************************/
DrawFieldsSection (FW);
/*********************************************************************
* Setup/display initial percentage indicator.
*********************************************************************/
if (FW->fPct) {
int lineNt = FWtopRowLineN (FW);
if (op == NEWfw) {
FW->fPctRowN = FW->fRowB + 1;
FW->fPctColN = FW->nColsTotal - 7;
}
UpdatePctString (FW->wid, FW->NfLines, FW->NfRows, lineNt,
FW->fPctRowN, FW->fPctColN);
}
/***********************************************************************
* If specified, write trailer section to window. If an update
* operation, it is assumed that the number of lines has not changed.
***********************************************************************/
if (FW->NtLines > 0) DrawSection (FW->wid, FW->tRowT, FW->tRowB, 0,
FW->NtLines, FW->tLines, FW->nColS);
/***********************************************************************
* Update screen and place the cursor in the current field.
***********************************************************************/
end_pasteboard_update ();
FW->charN = 0;
FW->leftCharN = 0;
if (FW->nFields > 0) {
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
}
return TRUE;
}
/*************************************************************************
* Check for a beep request.
*************************************************************************/
case BEEPfw:
ring_bell ();
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be deleted.
*************************************************************************/
case DELETEfw:
if (FW->fUpTo != NULL) cdf_FreeMemory (FW->fUpTo, FatalError);
if (FW->fDownTo != NULL) cdf_FreeMemory (FW->fDownTo, FatalError);
if (FW->fLeftTo != NULL) cdf_FreeMemory (FW->fLeftTo, FatalError);
if (FW->fRightTo != NULL) cdf_FreeMemory (FW->fRightTo, FatalError);
delete_virtual_display (FW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be erased (but remain in existence).
*************************************************************************/
case UNDISPLAYfw:
unpaste_virtual_display (FW->wid);
va_end (ap);
return TRUE;
/*************************************************************************
* Check if menu should be redisplayed (but don't wait for input - a call
* with `op = READfw' should be made next).
*************************************************************************/
case REDISPLAYfw:
set_cursor_mode (CURSORon);
paste_virtual_display (FW->wid, FW->ULrow, FW->ULcol);
va_end (ap);
return TRUE;
/*************************************************************************
* Get next input. The cursor is positioned first in case it had been
* moved.
*************************************************************************/
case READfw: {
int colN;
if (FW->nFields < 1) return FALSE;
set_cursor_mode (CURSORon);
colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN) + 1;
set_cursor_abs (FW->wid, FW->fRowN, colN);
for (;;) {
read_input (
#if defined(CURSESui)
FW->wid,
#endif
&(FW->key), PASSTHRUri, TRUE);
/********************************************************************
* Check for an exit key. If no exit keys were specified, any key
* causes an exit.
********************************************************************/
if (FW->exitChars[0] == NUL) {
va_end (ap);
return TRUE;
}
else {
int charN;
for (charN = 0; FW->exitChars[charN] != NUL; charN++)
if (FW->key == FW->exitChars[charN]) {
va_end (ap);
return TRUE;
}
}
/********************************************************************
* Check for next-screen key.
********************************************************************/
if (FW->key == FW->NSkey) {
begin_pasteboard_update ();
NextScreen (FW->NfRows, FW->NfLines, FW->fLineNs, FW->fDownTo,
FW->fRowB, FW->fRowT, FW->fScroll, &(FW->fieldN),
&(FW->fRowN));
DrawFieldsSection (FW);
if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
FWtopRowLineN(FW), FW->fPctRowN,
FW->fPctColN);
end_pasteboard_update ();
FW->charN = 0;
FW->leftCharN = 0;
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
continue;
}
/********************************************************************
* Check for prev-screen key.
********************************************************************/
if (FW->key == FW->PSkey) {
begin_pasteboard_update ();
PrevScreen (FW->NfRows, FW->fLineNs, FW->fUpTo, FW->fRowT,
FW->fScroll, &(FW->fRowN), &(FW->fieldN));
DrawFieldsSection (FW);
if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
FWtopRowLineN(FW), FW->fPctRowN,
FW->fPctColN);
end_pasteboard_update ();
FW->charN = 0;
FW->leftCharN = 0;
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
continue;
}
/********************************************************************
* Check for down field key.
********************************************************************/
if (FW->key == FW_DOWN_FIELD || FW->key == FW_DOWN_FIELDx) {
begin_pasteboard_update ();
DownArrow (FW->fLineNs, FW->fDownTo, FW->fRowT, FW->fRowB,
FW->fScroll, &(FW->fRowN), &(FW->fieldN));
DrawFieldsSection (FW);
if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
FWtopRowLineN(FW), FW->fPctRowN,
FW->fPctColN);
end_pasteboard_update ();
FW->charN = 0;
FW->leftCharN = 0;
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
continue;
}
/********************************************************************
* Check for up field key.
********************************************************************/
if (FW->key == FW_UP_FIELD || FW->key == FW_UP_FIELDx) {
begin_pasteboard_update ();
UpArrow (FW->NfLines, FW->fLineNs, FW->fUpTo, FW->fRowT,
FW->fRowB, FW->fScroll, &(FW->fRowN), &(FW->fieldN));
DrawFieldsSection (FW);
if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
FWtopRowLineN(FW), FW->fPctRowN,
FW->fPctColN);
end_pasteboard_update ();
FW->charN = 0;
FW->leftCharN = 0;
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
continue;
}
/********************************************************************
* Check for left field key.
********************************************************************/
if (FW->key == FW_LEFT_FIELD || FW->key == FW_LEFT_FIELDx) {
FW->fieldN = FW->fLeftTo[FW->fieldN];
FW->charN = 0;
FW->leftCharN = 0;
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
continue;
}
/********************************************************************
* Check for right field key.
********************************************************************/
if (FW->key == FW_RIGHT_FIELD || FW->key == FW_RIGHT_FIELDx) {
FW->fieldN = FW->fRightTo[FW->fieldN];
FW->charN = 0;
FW->leftCharN = 0;
set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
continue;
}
/********************************************************************
* Check for left character key.
********************************************************************/
if (FW->key == FW_LEFT_CHAR || FW->key == FW_LEFT_CHARx) {
if (FW->charN > 0) {
int colN, len; char *ptr;
if (FW->charN == FW->leftCharN) {
FW->leftCharN--;
ptr = &(FW->fields[FW->fieldN][FW->leftCharN]);
len = (int) strlen(ptr);
put_chars (FW->wid, ptr, MINIMUM(len,FW->fLens[FW->fieldN]),
FW->fRowN, FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
}
FW->charN--;
colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN);
set_cursor_abs (FW->wid, FW->fRowN, colN + 1);
}
else
ring_bell ();
continue;
}
/********************************************************************
* Check for right character key.
********************************************************************/
if (FW->key == FW_RIGHT_CHAR || FW->key == FW_RIGHT_CHARx) {
int fieldLen = (int) strlen(FW->fields[FW->fieldN]);
if (FW->charN < fieldLen) {
int colN, cursorPos = FW->charN - FW->leftCharN + 1;
if (cursorPos == FW->fLens[FW->fieldN]) {
char *ptr = &(FW->fields[FW->fieldN][FW->leftCharN+1]);
if (FW->charN == fieldLen - 1) {
int count = FW->fLens[FW->fieldN] - 1;
put_chars (FW->wid, ptr, count, FW->fRowN,
FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
colN = FW->fCols[FW->fieldN] + count;
put_chars (FW->wid, " ", 1, FW->fRowN, colN + 1,
FALSE, NORMAL);
}
else {
put_chars (FW->wid, ptr, FW->fLens[FW->fieldN], FW->fRowN,
FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
}
FW->leftCharN++;
}
FW->charN++;
colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN);
set_cursor_abs (FW->wid, FW->fRowN, colN + 1);
}
else
ring_bell ();
continue;
}
/********************************************************************
* Check for delete key.
********************************************************************/
if (FW->key == KB_DELETE) {
if (FW->charN > 0) {
if (FW->charN == FW->leftCharN) {
char *ptr = &(FW->fields[FW->fieldN][FW->charN]);
memmove (ptr - 1, ptr, strlen(ptr) + 1);
FW->charN--;
FW->leftCharN--;
}
else {
char *ptr;
ptr = &(FW->fields[FW->fieldN][FW->charN]);
memmove (ptr - 1, ptr, strlen(ptr) + 1);
FW->charN--;
DrawField (FW);
}
}
else
ring_bell ();
continue;
}
/********************************************************************
* Check for the `refresh' key.
********************************************************************/
if (FW->key == FW->refreshChar) {
repaint_screen ();
continue;
}
/********************************************************************
* Check for the toggle insert/overstrike key.
********************************************************************/
if (FW->key == FW->toggleKey) {
FW->insert = BOO(FW->insert,FALSE,TRUE);
continue;
}
/********************************************************************
* Character to insert/overstrike.
********************************************************************/
if (Printable(FW->key)) {
if (FW->insert) {
int len = (int) strlen(FW->fields[FW->fieldN]);
if (len < FW->fMaxs[FW->fieldN]) {
char *ptr = &(FW->fields[FW->fieldN][FW->charN]);
int len = (int) strlen(ptr);
memmove (ptr + 1, ptr, len + 1);
*ptr = (char) FW->key;
if (FW->charN - FW->leftCharN == FW->fLens[FW->fieldN] - 1) {
FW->leftCharN++;
}
FW->charN++;
DrawField (FW);
}
else
ring_bell ();
}
else {
if (FW->charN < FW->fMaxs[FW->fieldN]) {
int len = (int) strlen(FW->fields[FW->fieldN]);
char *ptr = &(FW->fields[FW->fieldN][FW->charN]);
*ptr = (char) FW->key;
if (FW->charN == len) *(ptr+1) = NUL;
if (FW->charN - FW->leftCharN == FW->fLens[FW->fieldN] - 1) {
FW->leftCharN++;
}
FW->charN++;
DrawField (FW);
}
else
ring_bell ();
}
continue;
}
/********************************************************************
* Illegal key, ring the bell.
********************************************************************/
ring_bell ();
}
}
}
va_end (ap);
return FALSE; /* Illegal operation. */
}
/******************************************************************************
* DrawField.
******************************************************************************/
static void DrawField (FW)
struct FieldWindowStruct *FW;
{
char *ptr = &(FW->fields[FW->fieldN][FW->leftCharN]);
int i, colN, len = (int) strlen(ptr);
put_chars (FW->wid, ptr, MINIMUM(len,FW->fLens[FW->fieldN]),
FW->fRowN, FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
for (i = len; i < FW->fLens[FW->fieldN]; i++) {
put_chars (FW->wid, " ", 1, FW->fRowN,
FW->fCols[FW->fieldN] + i + 1, FALSE, NORMAL);
}
colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN);
set_cursor_abs (FW->wid, FW->fRowN, colN + 1);
return;
}
/******************************************************************************
* DrawFieldsSection.
******************************************************************************/
static void DrawFieldsSection (FW)
struct FieldWindowStruct *FW; /* Pointer to FieldWindow structure. */
{
size_t len; int i, rowN, lineN, fieldN; char line[SCREEN_WIDTH+1];
for (rowN = FW->fRowT, lineN = FWtopRowLineN(FW);
rowN <= FW->fRowB && lineN < FW->NfLines; rowN++, lineN++) {
strcpyX (line, FW->fLines[lineN], SCREEN_WIDTH);
for (fieldN = 0; fieldN < FW->nFields; fieldN++) {
if (FW->fLineNs[fieldN] == lineN) {
len = (int) strlen(FW->fields[fieldN]);
for (i = 0; i < FW->fLens[fieldN]; i++) {
if (i < (int) len)
line[FW->fCols[fieldN]+i] = FW->fields[fieldN][i];
else
line[FW->fCols[fieldN]+i] = ' ';
}
}
}
len = (int) strlen(line);
put_chars (FW->wid, line, MINIMUM(FW->nColS,(int)len), rowN, 1,
FALSE, NORMAL);
if ((int)len < FW->nColS)
erase_display (FW->wid, rowN, (int)len + 1, rowN, FW->nColS);
}
if (rowN <= FW->fRowB) erase_display (FW->wid, rowN, 1, FW->fRowB, FW->nColS);
return;
}
/******************************************************************************
* CalcItemDirections.
******************************************************************************/
static void CalcItemDirections (nItems, NiLines, iLineNs, iCols, iLens,
iDownTo, iUpTo, iLeftTo, iRightTo)
int nItems;
int NiLines;
int *iLineNs;
int *iCols;
int *iLens;
int *iDownTo;
int *iUpTo;
int *iLeftTo;
int *iRightTo;
{
int *center, i;
/***************************************************************************
* Allocate and calculate center point for each item.
***************************************************************************/
center = (int *) cdf_AllocateMemory (nItems * sizeof(int),
FatalError);
for (i = 0; i < nItems; i++) {
center[i] = iCols[i] + (iLens[i] / 2);
}
/***************************************************************************
* Calculate directions for each item.
***************************************************************************/
for (i = 0; i < nItems; i++) {
/************************************************************************
* Calculate down direction.
************************************************************************/
iDownTo[i] = i;
if (NiLines > 1 && nItems > 1) {
int toLineN, mostOff, j;
int fromLineN = iLineNs[i];
for (j = (i+1) % nItems, toLineN = -1; j != i; j = (j+1) % nItems) {
int lineNt = iLineNs[j];
if (lineNt != fromLineN)
if (toLineN == -1) {
iDownTo[i] = j;
toLineN = lineNt;
mostOff = DIFF(center[i],center[j]);
}
else
if (lineNt == toLineN) {
int offBy = DIFF(center[i],center[j]);
if (offBy < mostOff) {
iDownTo[i] = j;
mostOff = offBy;
}
}
else
break; /* No more items on `toLineN'. */
}
}
/************************************************************************
* Calculate up direction.
************************************************************************/
iUpTo[i] = i;
if (NiLines > 1 && nItems > 1) {
int toLineN, mostOff, j;
int fromLineN = iLineNs[i];
for (j = (i == 0 ? nItems-1 : i-1), toLineN = -1;
j != i; j = (j == 0 ? nItems-1 : j-1)) {
int lineNt = iLineNs[j];
if (lineNt != fromLineN)
if (toLineN == -1) {
iUpTo[i] = j;
toLineN = lineNt;
mostOff = DIFF(center[i],center[j]);
}
else
if (lineNt == toLineN) {
int offBy = DIFF(center[i],center[j]);
if (offBy < mostOff) {
iUpTo[i] = j;
mostOff = offBy;
}
}
else
break; /* No more items on `toLineN'. */
}
}
/************************************************************************
* Calculate left direction. First check for the nearest item to the
* left. If none found, check for the farthest item to the right (if
* none found, going left stays at the same item).
************************************************************************/
iLeftTo[i] = i;
if (nItems > 1) {
int toLeftLineN = (i > 0 ? iLineNs[i-1] : -1), j;
if (toLeftLineN == iLineNs[i])
iLeftTo[i] = i - 1;
else
for (j = i+1; j < nItems; j++)
if (iLineNs[j] == iLineNs[i])
iLeftTo[i] = j;
else
break;
}
/************************************************************************
* Calculate right direction. First check for the nearest item to the
* right. If none found, check for the farthest item to the left (if
* none found, going right stays at the same item).
************************************************************************/
iRightTo[i] = i;
if (nItems > 1) {
int toRightLineN = (i < nItems-1 ? iLineNs[i+1] : -1), j;
if (toRightLineN == iLineNs[i])
iRightTo[i] = i + 1;
else
for (j = i-1; j >= 0; j--)
if (iLineNs[j] == iLineNs[i])
iRightTo[i] = j;
else
break;
}
}
cdf_FreeMemory (center, FatalError);
return;
}
/******************************************************************************
* UpdatePctString.
******************************************************************************/
static void UpdatePctString (wid, nLines, nRows, topRowLineN, rowN, colN)
WINDOWid wid;
int nLines;
int nRows;
int topRowLineN;
int rowN;
int colN;
{
char pct[MAX_PCT_LEN+1];
if (nLines <= nRows)
strcpyX (pct, " All ", MAX_PCT_LEN);
else
if (topRowLineN == 0)
strcpyX (pct, " Top ", MAX_PCT_LEN);
else
if (topRowLineN == nLines - nRows)
strcpyX (pct, " End ", MAX_PCT_LEN);
else {
sprintf (pct, "%3d%% ", (int)
((100.0 * (((float) topRowLineN) / (nLines - nRows))) + 0.5));
}
put_chars (wid, pct, (int) strlen(pct), rowN, colN, FALSE, NORMAL);
return;
}
/******************************************************************************
* DrawSection.
******************************************************************************/
static void DrawSection (wid, rowT, rowB, topRowLineN, nLines, lineS, nColS)
WINDOWid wid;
int rowT; /* Top row number. */
int rowB; /* Bottom row number. */
int topRowLineN; /* Line number to be displayed in top row. */
int nLines; /* Number of lines (may be greater than the number of
available rows). */
char **lineS; /* Lines to be displayed. Capital `S' because of the
IBM RS6000. */
int nColS; /* Number of available columns (first character of a
line is displayed in column one [1]). */
{
size_t len;
int rowN, lineN;
for (rowN = rowT, lineN = topRowLineN;
rowN <= rowB && lineN < nLines; rowN++, lineN++) {
len = strlen(lineS[lineN]);
put_chars (wid, lineS[lineN], MINIMUM(nColS,(int)len), rowN, 1,
FALSE, NORMAL);
if ((int)len < nColS)
erase_display (wid, rowN, (int)len + 1, rowN, nColS);
}
if (rowN <= rowB) erase_display (wid, rowN, 1, rowB, nColS);
return;
}
/******************************************************************************
* NextScreen.
******************************************************************************/
static void NextScreen (NiRows, NiLines, iLineNs, iDownTo, iRowB, iRowT,
iScroll, itemN, iRowN)
int NiRows;
int NiLines;
int *iLineNs;
int *iDownTo;
int iRowB;
int iRowT;
Logical iScroll;
int *itemN;
int *iRowN;
{
int oldLineN = iLineNs[*itemN];
int maxLineN = MinInt (oldLineN + NiRows, NiLines - 1);
for (;;) {
int itemNt = iDownTo[*itemN];
int lineNt = iLineNs[itemNt];
if (lineNt <= maxLineN && lineNt > oldLineN)
*itemN = itemNt;
else
break;
}
if (iScroll) {
int linesToEnd = (NiLines - 1) - iLineNs[*itemN];
if (*iRowN + linesToEnd < iRowB) *iRowN = iRowB - linesToEnd;
}
else
*iRowN = iRowT + iLineNs[*itemN];
return;
}
/******************************************************************************
* PrevScreen.
******************************************************************************/
static void PrevScreen (NiRows, iLineNs, iUpTo, iRowT, iScroll, iRowN, itemN)
int NiRows;
int *iLineNs;
int *iUpTo;
int iRowT;
Logical iScroll;
int *iRowN;
int *itemN;
{
int oldLineN = iLineNs[*itemN];
int minLineN = MaxInt (oldLineN - NiRows, 0);
for (;;) {
int itemNt = iUpTo[*itemN];
int lineNt = iLineNs[itemNt];
if (lineNt >= minLineN && lineNt < oldLineN)
*itemN = itemNt;
else
break;
}
if (iScroll) {
int linesToBeg = iLineNs[*itemN];
if (*iRowN - linesToBeg > iRowT) *iRowN = iRowT + linesToBeg;
}
else
*iRowN = iRowT + iLineNs[*itemN];
return;
}
/******************************************************************************
* DownArrow.
******************************************************************************/
static void DownArrow (iLineNs, iDownTo, iRowT, iRowB, iScroll, iRowN, itemN)
int *iLineNs;
int *iDownTo;
int iRowT;
int iRowB;
Logical iScroll;
int *iRowN;
int *itemN;
{
int oldLineN = iLineNs[*itemN];
*itemN = iDownTo[*itemN];
if (iScroll) {
int nLinesDown = iLineNs[*itemN] - oldLineN;
if (nLinesDown < 0)
*iRowN = iRowT + iLineNs[*itemN];
else
*iRowN = MINIMUM (*iRowN + nLinesDown, iRowB);
}
else
*iRowN = iRowT + iLineNs[*itemN];
return;
}
/******************************************************************************
* UpArrow.
******************************************************************************/
static void UpArrow (NiLines, iLineNs, iUpTo, iRowT, iRowB, iScroll, iRowN,
itemN)
int NiLines;
int *iLineNs;
int *iUpTo;
int iRowT;
int iRowB;
Logical iScroll;
int *iRowN;
int *itemN;
{
int oldLineN = iLineNs[*itemN];
*itemN = iUpTo[*itemN];
if (iScroll) {
int nLinesUp = oldLineN - iLineNs[*itemN];
if (nLinesUp < 0) {
int nLinesFromBot = (NiLines - 1) - iLineNs[*itemN];
*iRowN = iRowB - nLinesFromBot;
}
else
*iRowN = MaxInt (*iRowN - nLinesUp, iRowT);
}
else
*iRowN = iRowT + iLineNs[*itemN];
return;
}
/******************************************************************************
* IWtopRowLineN.
******************************************************************************/
static int IWtopRowLineN (IW)
struct ItemWindowStruct *IW;
{
return BOO(IW->nItems > 0,
IW->iLineNs[IW->itemN] - (IW->iRowN - IW->iRowT), 0);
}
/******************************************************************************
* FWtopRowLineN.
******************************************************************************/
static int FWtopRowLineN (FW)
struct FieldWindowStruct *FW;
{
return BOO(FW->nFields > 0,
FW->fLineNs[FW->fieldN] - (FW->fRowN - FW->fRowT), 0);
}
/******************************************************************************
* AllocIW.
******************************************************************************/
void AllocIW (IW, nItems, NiLines, iLineNchars, fatalFnc)
struct ItemWindowStruct *IW;
int nItems;
int NiLines;
int iLineNchars;
void (*fatalFnc) PROTOARGs((char *msg));
{
IW->nItems = nItems;
if (IW->nItems > 0) {
IW->iLineNs = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
fatalFnc);
IW->iCols = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
fatalFnc);
IW->iLens = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
fatalFnc);
}
IW->NiLines = NiLines;
if (IW->NiLines > 0) {
int lineN, i;
IW->iLines = (char **) cdf_AllocateMemory (IW->NiLines * sizeof(char *),
fatalFnc);
for (lineN = 0; lineN < IW->NiLines; lineN++) {
IW->iLines[lineN] = (char *) cdf_AllocateMemory (iLineNchars+1,
fatalFnc);
for (i = 0; i < iLineNchars; i++) IW->iLines[lineN][i] = ' ';
IW->iLines[lineN][iLineNchars] = NUL;
}
}
return;
}
/******************************************************************************
* AllocFW.
******************************************************************************/
void AllocFW (FW, nFields, NfLines, fLineNchars, fatalFnc)
struct FieldWindowStruct *FW;
int nFields;
int NfLines;
int fLineNchars;
void (*fatalFnc) PROTOARGs((char *msg));
{
FW->nFields = nFields;
if (FW->nFields > 0) {
FW->fLineNs = (int *) cdf_AllocateMemory (FW->nFields * sizeof(int),
fatalFnc);
FW->fCols = (int *) cdf_AllocateMemory (FW->nFields * sizeof(int),
fatalFnc);
FW->fLens = (int *) cdf_AllocateMemory (FW->nFields * sizeof(int),
fatalFnc);
}
FW->NfLines = NfLines;
if (FW->NfLines > 0) {
int lineN, i;
FW->fLines = (char **) cdf_AllocateMemory (FW->NfLines * sizeof(char *),
fatalFnc);
for (lineN = 0; lineN < FW->NfLines; lineN++) {
FW->fLines[lineN] = (char *) cdf_AllocateMemory (fLineNchars+1,
fatalFnc);
for (i = 0; i < fLineNchars; i++) FW->fLines[lineN][i] = ' ';
FW->fLines[lineN][fLineNchars] = NUL;
}
}
return;
}
/******************************************************************************
* FreeIW.
******************************************************************************/
void FreeIW (IW, fatalFnc)
struct ItemWindowStruct *IW;
void (*fatalFnc) PROTOARGs((char *msg));
{
if (IW->NiLines > 0) {
int lineN;
for (lineN = IW->NiLines - 1; lineN >= 0; lineN--) {
cdf_FreeMemory (IW->iLines[lineN], fatalFnc);
}
cdf_FreeMemory (IW->iLines, fatalFnc);
}
if (IW->nItems > 0) {
cdf_FreeMemory (IW->iLens, fatalFnc);
cdf_FreeMemory (IW->iCols, fatalFnc);
cdf_FreeMemory (IW->iLineNs, fatalFnc);
}
IW->NiLines = 0;
IW->nItems = 0;
IW->iLines = NULL;
IW->iLineNs = NULL;
IW->iCols = NULL;
IW->iLens = NULL;
return;
}
/******************************************************************************
* FreeFW.
******************************************************************************/
void FreeFW (FW, fatalFnc)
struct FieldWindowStruct *FW;
void (*fatalFnc) PROTOARGs((char *msg));
{
if (FW->NfLines > 0) {
int lineN;
for (lineN = FW->NfLines - 1; lineN >= 0; lineN--) {
cdf_FreeMemory (FW->fLines[lineN], fatalFnc);
}
cdf_FreeMemory (FW->fLines, fatalFnc);
}
if (FW->nFields > 0) {
cdf_FreeMemory (FW->fLens, fatalFnc);
cdf_FreeMemory (FW->fCols, fatalFnc);
cdf_FreeMemory (FW->fLineNs, fatalFnc);
}
FW->NfLines = 0;
FW->nFields = 0;
FW->fLines = NULL;
FW->fLineNs = NULL;
FW->fCols = NULL;
FW->fLens = NULL;
return;
}
/******************************************************************************
* OnlineHelpWindow.
******************************************************************************/
Logical OnlineHelpWindow (ilhFile, helpId)
char *ilhFile;
int helpId;
{
AOSs1A (header, BLANKs78)
AOSs1B (trailer,
"Exit: ________ NextScreen: ________ PrevScreen: ________")
static char errorLines[] = "Online help not available.\n";
static int exitChars[] = { EXITkey_FSI, NUL };
static char label[] = { BLANKs78 };
static Logical first = TRUE;
static struct EditWindowStruct EW = {
label, 0, 0, SCREEN_WIDTH, 1, header, NULL, 18, 1, trailer, TRUE, TRUE,
exitChars, REFRESHkey_FSI, NUL, NUL, NUL, NUL, NSkey_FSI, PSkey_FSI, NUL,
NUL, NUL
};
/****************************************************************************
* Encode label and key definitions the first time.
****************************************************************************/
if (first) {
sprintf (EW.label, " %s Online Help ", pgmName);
EncodeKeyDefinitions (1, EW.tLines, EXITkey_FSI, NSkey_FSI, PSkey_FSI);
first = FALSE;
}
/****************************************************************************
* Load online help.
****************************************************************************/
if (!LoadOnlineHelp(ilhFile,helpId,EW.hLines[0],&EW.eText)) {
cdf_FreeMemory (EW.eText, FatalError);
strcpyX (EW.hLines[0], "Error!", 0);
EW.eText = errorLines;
EditWindow (NEWew, &EW, TRUE);
EditWindow (READew, &EW);
EditWindow (DELETEew, &EW);
return FALSE;
}
/****************************************************************************
* Display help window/wait for exit key.
****************************************************************************/
EditWindow (NEWew, &EW, TRUE);
EditWindow (READew, &EW);
EditWindow (DELETEew, &EW);
/****************************************************************************
* Cleanup and return.
****************************************************************************/
cdf_FreeMemory (EW.eText, FatalError);
return TRUE;
}
/******************************************************************************
* LoadOnlineHelp.
* You'll notice that the buffers used to hold lines of online help are
* allocated as (SCREEN_WIDTH-2)+1+1. This is for the number of characters,
* the newline (as returned by `fgets'), and the terminating NUL character.
* When `fgets' is called, the number of characters to read is specified as
* (SCREEN_WIDTH-2)+1+1. This is for the actual characters plus the newline
* plus one more since `fgets' subtracts one from this value and uses that as
* the maximum number of characters to read (which includes the newline).
******************************************************************************/
Logical LoadOnlineHelp (ilhFile, helpId, header, eText)
char *ilhFile;
int helpId;
char *header;
char **eText;
{
FILE *fp; int i; size_t length;
char beginStr[15+1], line[(SCREEN_WIDTH-2)+1+1], helpIdStr[15+1];
enum { ITEMw, PROMPTw, EDITw } windowType;
int nBlanks;
int nestLevel = 0; /* Depth into `#ifos's. */
int osMask = 0; /* When 0, display line. Note that bit 0 is not used
(eg. nesting depth of 1 uses bit 1, etc.). */
#if defined(vms)
static char thisOS[] = "vms";
#endif
#if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
defined(posixSHELL)
static char thisOS[] = "unix";
#endif
#if defined(dos) || defined(__CYGWIN__) || defined(__MINGW32__)
static char thisOS[] = "dos";
#endif
#if defined(mac)
static char thisOS[] = "mac";
#endif
#if defined(win32)
static char thisOS[] = "win";
#endif
/****************************************************************************
* Initialize.
****************************************************************************/
*eText = cdf_AllocateMemory ((size_t) 1, FatalError);
MakeNUL (*eText);
/****************************************************************************
* Open help file.
****************************************************************************/
fp = OnlineHelpFP (ilhFile, NULL);
if (fp == NULL) return FALSE;
/****************************************************************************
* Read through help file looking for proper help section.
****************************************************************************/
sprintf (beginStr, "#section %d", helpId);
while (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) != NULL) {
/**************************************************************************
* Strip trailing newline character and check to see if the help section
* has been found.
**************************************************************************/
line[strlen(line)-1] = NUL;
if (!strcmp(line,beginStr)) {
/************************************************************************
* Determine window type.
************************************************************************/
if (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) == NULL) {
fclose (fp);
return FALSE;
}
line[strlen(line)-1] = NUL;
if (!strcmp(line,"#item"))
windowType = ITEMw;
else
if (!strcmp(line,"#prompt"))
windowType = PROMPTw;
else
if (!strcmp(line,"#edit"))
windowType = EDITw;
else {
fclose (fp);
return FALSE;
}
/************************************************************************
* Build header.
************************************************************************/
if (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) == NULL) {
fclose (fp);
return FALSE;
}
line[strlen(line)-1] = NUL;
if (strncmp(line,"#title ",7) != 0) {
fclose (fp);
return FALSE;
}
strcpyX (header, "Help for ", 0);
strcatX (header, &line[7], 0);
sprintf (helpIdStr, "[%d%c]", helpId,
(windowType == ITEMw ? 'i' :
(windowType == PROMPTw ? 'p' :
(windowType == EDITw ? 'e' : '?'))));
nBlanks = (SCREEN_WIDTH-2) - strlen(header) - strlen(helpIdStr);
CatNcharacters (header, nBlanks, (int) ' ');
strcatX (header, helpIdStr, 0);
/************************************************************************
* Read and save lines until "#endsection" is found.
************************************************************************/
while (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) != NULL) {
line[strlen(line)-1] = NUL;
/**********************************************************************
* Check if at end of this section of help. If so, delete trailing
* newline characters, encode key definitions based on window type,
* close help file, and return.
**********************************************************************/
if (!strcmp(line,"#endsection")) {
if (nestLevel != 0) {
fclose (fp);
return FALSE;
}
length = strlen (*eText);
if (length > 0) {
for (i = length - 1; i >= 0; i--) {
if ((*eText)[i] != Nl) break;
(*eText)[i] = NUL;
}
}
switch (windowType) {
case ITEMw:
EncodeKeyDefinitions (1, eText, NSkey_FSI, PSkey_FSI);
break;
case PROMPTw:
EncodeKeyDefinitions (1, eText, SOLkey_FSI, EOLkey_FSI,
INSERTorOVERkey_FSI);
break;
case EDITw:
EncodeKeyDefinitions (1, eText, NSkey_FSI, PSkey_FSI);
break;
}
fclose (fp);
return TRUE;
}
/**********************************************************************
* Not at end yet. Check if an operating system directive. If not,
* include the line if all of the bits in the operating system mask
* are clear.
**********************************************************************/
if (line[0] == '#') {
/********************************************************************
* Check for an `#ifos' directive. If this operating system is not
* specified, then set the bit in the operating system mask for this
* nesting level.
********************************************************************/
if (!strncmp(line,"#ifos",5)) {
nestLevel++;
if (strstr(line,thisOS) == NULL) SETBIT (osMask, nestLevel);
continue;
}
/********************************************************************
* Check for an `#else' directive. Simply flip the bit in the
* operating system mask for this nesting level.
********************************************************************/
if (!strcmp(line,"#else")) {
if (nestLevel < 1) {
fclose (fp);
return FALSE;
}
FLPBIT (osMask, nestLevel);
continue;
}
/********************************************************************
* Check for an `#endos' directive. Clear the bit in the operating
* system mask for this nesting level and decrement the nesting level.
********************************************************************/
if (!strcmp(line,"#endos")) {
if (nestLevel < 1) {
fclose (fp);
return FALSE;
}
CLRBIT (osMask, nestLevel);
nestLevel--;
continue;
}
/********************************************************************
* An unknown directive has been encountered.
********************************************************************/
fclose (fp);
return FALSE;
}
else {
if (osMask == 0) {
size_t length, newLength;
#if defined(dos)
int tabCount, i;
#endif
length = strlen (line);
#if defined(dos)
for (tabCount = 0, i = 0; i < length; i++) {
if (line[i] == Ht) tabCount++;
}
length += (7 * tabCount);
#endif
newLength = strlen(*eText) + (length + 1) + 1;
*eText = cdf_ReallocateMemory (*eText, newLength,
FatalError);
#if defined(dos)
for (i = 0; i < tabCount; i++) {
strcatX (*eText, " ", 0);
}
strcatX (*eText, &line[i], 0);
#else
strcatX (*eText, line, 0);
#endif
strcatX (*eText, "\n", 0);
}
}
}
/************************************************************************
* `#endsection' not found - error return.
************************************************************************/
fclose (fp);
return FALSE;
}
}
/****************************************************************************
* `#section x' not found - error return.
****************************************************************************/
fclose (fp);
return FALSE;
}
/******************************************************************************
* InfoWindow.
******************************************************************************/
void InfoWindow (message1, message2, message3, center, beep, wait)
char *message1; /* This message line must exist. */
char *message2; /* This message line is optional (NULL if absent). */
char *message3; /* This message line is optional (NULL if absent).
If `message2' is NULL, this must also be NULL. */
Logical center; /* TRUE if window should be in center of screen. */
Logical beep; /* TRUE if window should beep after being displayed. */
int wait; /* 0: Read a key before deleting window.
>0: Wait `wait' seconds and then delete window. */
{
static int exitChars[] = { NUL };
static char eText[INFOtextMAX+1];
static char ackLabel[] = " Enter any key to acknowledge. ";
static struct EditWindowStruct EW = {
NULL, 0, 0, 0, 0, NULL, eText, 0, 0, NULL, FALSE, TRUE, exitChars,
REFRESHkey_FSI, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
};
EW.label = BOO(wait > 0,NULL,ackLabel);
if (center) {
EW.nColsTotal = BOO(EW.label == NULL,0,(int)(strlen(EW.label) + 4));
EW.nColsTotal = MaxInt (EW.nColsTotal, (int) (strlen(message1) + 2));
strcpyX (EW.eText, message1, INFOtextMAX);
strcatX (EW.eText, "\n", INFOtextMAX);
EW.ULrow = (SCREEN_HEIGHT - 3) / 2;
EW.NeRows = 1;
if (message2 != NULL) {
EW.nColsTotal = MaxInt (EW.nColsTotal, (int) (strlen(message2) + 2));
strcatX (EW.eText, message2, INFOtextMAX);
strcatX (EW.eText, "\n", INFOtextMAX);
EW.ULrow = (SCREEN_HEIGHT - 4) / 2;
EW.NeRows = 2;
}
if (message3 != NULL) {
EW.nColsTotal = MaxInt (EW.nColsTotal, (int) (strlen(message3) + 2));
strcatX (EW.eText, message3, INFOtextMAX);
strcatX (EW.eText, "\n", INFOtextMAX);
EW.ULrow = (SCREEN_HEIGHT - 5) / 2;
EW.NeRows = 3;
}
EW.ULcol = (SCREEN_WIDTH - EW.nColsTotal) / 2;
}
else {
strcpyX (EW.eText, message1, INFOtextMAX);
strcatX (EW.eText, "\n", INFOtextMAX);
EW.ULrow = SCREEN_HEIGHT - 3;
EW.NeRows = 1;
if (message2 != NULL) {
strcatX (EW.eText, message2, INFOtextMAX);
strcatX (EW.eText, "\n", INFOtextMAX);
EW.ULrow = SCREEN_HEIGHT - 4;
EW.NeRows = 2;
}
if (message3 != NULL) {
strcatX (EW.eText, message3, INFOtextMAX);
strcatX (EW.eText, "\n", INFOtextMAX);
EW.ULrow = SCREEN_HEIGHT - 5;
EW.NeRows = 3;
}
EW.nColsTotal = SCREEN_WIDTH;
EW.ULcol = 0;
}
EditWindow (NEWew, &EW, TRUE);
if (beep) EditWindow (BEEPew, &EW);
if (wait > 0)
zzzzz ((double) wait);
else
EditWindow (READew, &EW);
EditWindow (DELETEew, &EW);
return;
}
syntax highlighted by Code2HTML, v. 0.9.1