/***********************************************************************
 *
 * TITLE:
 *	dialog.c
 *
 * AUTHOR:
 *	Kevin J. Miller
 *
 * DESCRIPTION:
 *	Generic creation functions for dialog boxes.
 *
 *				CHANGE HISTORY
 *
 * $Log: dialog.c,v $
 * Revision 1.19  1994/11/21  23:05:21  maxwell
 * Fixed bug in DialogToggleSet analogous to the one in DialogRadioSet.
 *
 * Revision 1.18  1994/10/01  00:50:00  maxwell
 * Fixed two minor bugs in DialogRadioSet: one prevented setting any but
 * the first button (!), the other could cause multiple buttons to be set.
 *
 * Revision 1.17  1994/09/09  22:04:34  chester
 * Add DialogList routines.
 * Unmap Pushbuttons for NULL callbacks in DialogStdButtons.
 * Add MotifStringToAscii for converting XmStrings to ASCII.
 *
 * Revision 1.16  1994/08/16  16:14:59  cassie
 * fixed DialogDurationSet routine to work for all resolutions
 *
 * Revision 1.15  1994/06/29  20:25:23  ana
 * added include file Xm/LabelG.h
 *
 * Revision 1.14  1994/06/21  00:44:09  kevin
 * added Toggle functions
 *
 * Revision 1.13  1994/06/21  00:34:15  kevin
 * added Duration functions
 *
 * Revision 1.12  1994/06/17  21:41:37  kevin
 * fixed parent of label in DialogCreateSpecial()
 *
 * Revision 1.11  1994/06/17  03:51:17  kevin
 * fixed default value for radio box
 *
 * Revision 1.10  1994/06/16  03:04:12  kevin
 * added: second size on DialogTextCreate
 * added: DialogLabelCreate, DialogButtonCreate, DialogSeparatorCreate,
 *        DialogSpecialCreate, DialogChangeLabel
 *
 * Revision 1.9  1994/06/14  22:41:27  kevin
 * minor width fix
 *
 * Revision 1.8  1994/06/14  22:32:59  kevin
 * added int and float function to Text
 *
 * Revision 1.7  1994/06/10  14:26:56  ana
 * added a label widget to DialogText structure
 *
 * Revision 1.6  1994/06/06  23:26:12  clm
 * added RadioBox options
 *
 * Revision 1.5  1994/05/31  22:57:55  kevin
 * fixed Pixmap menus
 *
 * Revision 1.4  1994/05/26  23:23:43  kevin
 * added NULL value array
 *
 * Revision 1.3  1994/05/26  21:32:23  kevin
 * added array and Pixmaps to Option Menu
 *
 * Revision 1.2  1994/05/26  21:08:52  kevin
 * added date functions
 *
 * Revision 1.1  1994/05/18  18:17:38  kevin
 * Initial revision
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *	DialogInit
 *	DialogAddRow
 *	DialogNextWidth
 *	DialogTextCreate
 *	DialogTextCreateMenu
 *	DialogTextSet
 *	DialogTextGet
 *	DialogTextSetInt
 *	DialogTextGetInt
 *	DialogTextSetDouble
 *	DialogTextGetDouble
 *	DialogListCreate
 *	DialogListGetItems
 *	DialogListGetSelectItems
 *	DialogListSetItems
 *	DialogListSetSelectItems
 *	DialogListSelectItems
 *	DialogListSelectItem
 *	DialogListAddItems
 *	DialogListDeleteItems
 *	DialogOptionCreate
 *	DialogOptionSet
 *	DialogOptionGet
 *	DialogTimeCreate
 *	DialogTimeSet
 *	DialogTimeGet
 *	DialogDateCreate
 *	DialogDateSet
 *	DialogDateGet
 *	DialogDurationCreate
 *	DialogDurationSet
 *	DialogDurationGet
 *	DialogRadioCreate
 *	DialogRadioSet
 *	DialogRadioGet
 *      DialogToggleCreate
 *      DialogToggleDestroy
 *      DialogToggleFlip
 *      DialogToggleGet
 *      DialogToggleSet
 *	DialogLabelCreate
 *	DialogButtonCreate
 *	DialogSeparatorCreate
 *	DialogSpecialCreate
 *	DialogStdButtons
 *	DialogManage
 *	DialogFlagSet
 *
 * GLOBALS:
 *	none
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] = 
    "$Id: dialog.c,v 1.19 1994/11/21 23:05:21 maxwell OEL $";
#endif

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/List.h>
#include <Xm/Text.h>
#include <Xm/Separator.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/ToggleB.h>

#include "utc.h"
#include "dialog.h"
#include "shellmgmt.h"

static char *MotifStringToAscii(XmString);

#define MAX_DIALOG_DEPTH 4

static XtAppContext app;		/* for event loop */
static Widget rowCol;			/* current row column widget */
static Widget rowForm;			/* container for this row */
static int rowFormIndex;		/* current column number */
static int rowFormNumber;		/* maximum column number */
static int rowFormWidth;		/* width in columns of next entry */
static int flag[MAX_DIALOG_DEPTH];	/* array of flags */
static int depth = -1;			/* current dialog depth */

/***********************************************************************
 *
 * FUNCTION:
 *	DialogInit
 *
 * INPUTS:
 *	parent		- (Widget) parent object for this dialog
 *	text		- (char *) label for dialog
 *	name		- (char *) resource name for dialog
 *	cancelCB	- (XtCallbackProc) callback procedure for Cancel
 *	cancelData	- (XtPointer) client data for Cancel
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	curDialog	- (Widget) new dialog
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Create a new dialog shell.
 */

Widget
DialogInit(Widget parent, char *text, char *name, XtCallbackProc cancelCB,
    XtPointer cancelData)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    Widget dialog;

    app= XtWidgetToApplicationContext(parent);

    tmpstr = XmStringCreateSimple(text);
    n = 0;
    XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
    XtSetArg(args[n], XmNdialogTitle, tmpstr); n++;
    XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); n++;
    XtSetArg(args[n], XmNnoResize, True); n++;
    XtSetArg(args[n], XmNautoUnmanage, False); n++;
    dialog = XmCreateBulletinBoardDialog(parent, name, args, n);
    XmStringFree(tmpstr);
    ShellAddClose(dialog, cancelCB, cancelData);

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmVERTICAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_CENTER);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    rowCol = XmCreateRowColumn(dialog, "rowCol", args, n);
    XtManageChild(rowCol);

    return dialog;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogAddRow
 *
 * INPUTS:
 *	num		- (int) number of columns to set aside
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) container for this row
 *	rowFormIndex	- (int) current column number, set to 0
 *	rowFormNumber	- (int) maximum column number, set to num
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Insert a form in the current position to allow multiple
 *	entry widgets on a single line.
 */

void
DialogAddRow(int num)
{
    Arg args[1];
    Cardinal n;

    n = 0;
    XtSetArg(args[n], XmNfractionBase, num);  n++;
    rowForm = XmCreateForm(rowCol, "rowForm", args, n);
    XtManageChild(rowForm);

    rowFormIndex = 0;
    rowFormNumber = num;
    rowFormWidth = 1;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogNextWidth
 *
 * INPUTS:
 *	num		- (int) number of columns to set aside
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Set the width in columns of the next entry.
 */

void
DialogNextWidth(int num)
{
    rowFormWidth = num;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextCreate
 *
 * INPUTS:
 *	label		- (char *) label for text widget
 *	width		- (int) width of widget in characters
 *	maxcols		- (int) maximum number of saved columns
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogText *) structure defining this menu
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a text dialog entry.
 */

DialogText *
DialogTextCreate(char *label, int width, int maxcols)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogText *entry;

    entry = XtNew(DialogText);

    if (maxcols < width) maxcols = width;
    entry->maxcols = maxcols;

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateRowColumn(rowCol, "textRC", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateRowColumn(rowForm, "textRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, width); n++;
    XtSetArg(args[n], XmNmaxLength, maxcols); n++;
    entry->text = XmCreateText(entry->parent, "text", args, n);
    XtManageChild(entry->text);

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextSet
 *
 * INPUTS:
 *	entry		- (DialogText *) text structure
 *	val		- (char *) new value for text
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Set the value of a dialog text widget.  If the input string
 *	is longer than the legal limit, it is clipped.
 */

void
DialogTextSet(DialogText *entry, char *val)
{
    int len;		/* length of string */
    char c;		/* temporary character */

    len = strlen(val);
    if (len > entry->maxcols) {
	len = entry->maxcols;
	c = val[len];
	val[len] = '\0';
	XmTextSetString(entry->text, val);
	val[len] = c;
    } else {
	XmTextSetString(entry->text, val);
    }
    XmTextSetInsertionPosition(entry->text, len);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextGet
 *
 * INPUTS:
 *	entry		- (DialogText *) text structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (char *) new value for text
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog text widget.
 */

char *
DialogTextGet(DialogText *entry)
{
    char *val;

    val = XmTextGetString(entry->text);

    return val;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextSetInt
 *
 * INPUTS:
 *	entry		- (DialogText *) text structure
 *	val		- (int) new value for text
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Set the value of a dialog text widget to an integer.
 */

void
DialogTextSetInt(DialogText *entry, int val)
{
    char buf[32];	/* text buffer */
    int len;		/* length of string */

    (void)sprintf(buf, "%d", val);
    len = strlen(buf);
    XmTextSetString(entry->text, buf);
    XmTextSetInsertionPosition(entry->text, len);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextGetInt
 *
 * INPUTS:
 *	entry		- (DialogText *) text structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (int) new value for integer
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog text widget as an integer.
 */

int
DialogTextGetInt(DialogText *entry)
{
    char *txt;
    int val;

    txt = XmTextGetString(entry->text);
    val = atoi(txt);
    XtFree(txt);

    return val;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextSetDouble
 *
 * INPUTS:
 *	entry		- (DialogText *) text structure
 *	val		- (double) new value for text
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Set the value of a dialog text widget to an double.
 */

void
DialogTextSetDouble(DialogText *entry, double val)
{
    char buf[32];	/* text buffer */
    int len;		/* length of string */

    (void)sprintf(buf, "%G", val);
    len = strlen(buf);
    XmTextSetString(entry->text, buf);
    XmTextSetInsertionPosition(entry->text, len);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTextGetDouble
 *
 * INPUTS:
 *	entry		- (DialogText *) text structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (double) new value for double
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog text widget as an double.
 */

double
DialogTextGetDouble(DialogText *entry)
{
    char *txt;
    double val;

    txt = XmTextGetString(entry->text);
    val = atof(txt);
    XtFree(txt);

    return val;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListCreate
 *
 * INPUTS:
 *	label		- (char *) label for text widget
 *	visible		- (int) number of visible items
 *	selectType	- (unsigned char) selection type
 *	selectCB	- (XtCallbackProc) selection callback
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogList *) structure defining this menu
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a text dialog entry.
 */

DialogList *
DialogListCreate(char *label, int visible, unsigned char selectType,
                 XtCallbackProc selectCB)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogList *entry;

    entry = XtNew(DialogList);

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmVERTICAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateRowColumn(rowCol, "listRC", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateRowColumn(rowForm, "textRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); n++;
    XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++;
    XtSetArg(args[n], XmNvisibleItemCount, visible); n++;
    XtSetArg(args[n], XmNselectionPolicy, selectType); n++;
    entry->list = XmCreateScrolledList(entry->parent, "list", args, n);
    XtManageChild(entry->list);

    if (selectCB != NULL) {
        switch (selectType) {
        case XmSINGLE_SELECT:
            XtAddCallback(entry->list, XmNsingleSelectionCallback,
                          selectCB, NULL);
            break;
        case XmBROWSE_SELECT:
            XtAddCallback(entry->list, XmNbrowseSelectionCallback,
                          selectCB, NULL);
            break;
        case XmMULTIPLE_SELECT:
            XtAddCallback(entry->list, XmNmultipleSelectionCallback,
                          selectCB, NULL);
            break;
        case XmEXTENDED_SELECT:
            XtAddCallback(entry->list, XmNextendedSelectionCallback,
                          selectCB, NULL);
            break;
        }
    }
    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListSetItems
 *
 * INPUTS:
 *	entry		- (DialogList *) list structure
 *	items		- (char **) array of ascii strings
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 */

void
DialogListSetItems(DialogList *entry, char **items)
{
    Cardinal n;
    Arg args[5];
    XmStringTable itemList;
    int i, numItems;

    numItems = XtNumber(items);
    itemList = (XmStringTable)XtMalloc(numItems * sizeof(XmString *));
    for (i = 0; i < numItems; i++) {
        itemList[i] = XmStringCreateSimple(items[i]);
    }

    n = 0;
    XtSetArg(args[n], XmNitems, itemList); n++;
    XtSetArg(args[n], XmNitemCount, numItems); n++;
    XtSetValues(entry->list, args, n);

    for (i = 0; i < numItems; i++) {
        XmStringFree(itemList[i]);
    }
    XtFree((char *)itemList);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListSelectItems
 *
 * INPUTS:
 *	entry		- (DialogList *) list structure
 *	items		- (char **) array of ascii strings
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 */

void
DialogListSelectItems(DialogList *entry, char **items)
{
    Cardinal n;
    Arg args[5];
    XmStringTable itemList;
    int i, numItems;

    numItems = XtNumber(items);
    itemList = (XmStringTable)XtMalloc(numItems * sizeof(XmString *));
    for (i = 0; i < numItems; i++) {
        itemList[i] = XmStringCreateSimple(items[i]);
    }

    n = 0;
    XtSetArg(args[n], XmNselectedItems, itemList); n++;
    XtSetArg(args[n], XmNselectedItemCount, numItems); n++;
    XtSetValues(entry->list, args, n);

    for (i = 0; i < numItems; i++) {
        XmStringFree(itemList[i]);
    }
    XtFree((char *)itemList);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListDeselectItems
 *
 * INPUTS:
 *	entry		- (DialogList *) list structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 */

void
DialogListDeselectItems(DialogList *entry)
{
    XmListDeselectAllItems(entry->list);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListGetItems
 *
 * INPUTS:
 *	entry		- (DialogList *) text structure
 *	items		- (char **) list of items
 *	numItems	- (int *) number of list items
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (char *) new value for text
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog text widget.
 */

void
DialogListGetItems(DialogList *entry, char **items[], int *numItems)
{
    Cardinal n;
    Arg args[5];
    XmStringTable itemList;
    char **textList;
    int i, num;

    n = 0;
    XtSetArg(args[n], XmNitems, &itemList); n++;
    XtSetArg(args[n], XmNitemCount, &num); n++;
    XtGetValues(entry->list, args, n);

    textList = (char **)XtMalloc(num * sizeof(char *));
    for (i = 0; i < num; i++) {
        textList[i] = XtNewString(MotifStringToAscii(itemList[i]));
    }

    (*items) = textList;
    (*numItems) = num;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListGetSelectItems
 *
 * INPUTS:
 *	entry		- (DialogList *) text structure
 *	items		- (char **) list of selected items
 *	numItems	- (int *) number of list selecteditems
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (char *) new value for text
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog text widget.
 */

void
DialogListGetSelectItems(DialogList *entry, char **items[], int *numItems)
{
    Cardinal n;
    Arg args[5];
    XmStringTable itemList;
    char **textList;
    int i, num;

    n = 0;
    XtSetArg(args[n], XmNselectedItems, &itemList); n++;
    XtSetArg(args[n], XmNselectedItemCount, &num); n++;
    XtGetValues(entry->list, args, n);

    textList = (char **)XtMalloc(num * sizeof(char *));
    for (i = 0; i < num; i++) {
        textList[i] = XtNewString(MotifStringToAscii(itemList[i]));
    }

    (*items) = textList;
    (*numItems) = num;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListAddItem
 *
 * INPUTS:
 *	entry		- (DialogList *) text structure
 *	item		- (char *) item to add
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Add an item to the list widget
 */

void
DialogListAddItem(DialogList *entry, char *item)
{
    XmString addItem;

    addItem = XmStringCreateSimple(item);
    XmListAddItemUnselected(entry->list, addItem, 0);
    XmListSetBottomPos(entry->list, 0);
    XmStringFree(addItem);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListDeleteItem
 *
 * INPUTS:
 *	entry		- (DialogList *) text structure
 *	item		- (char *) item to delete
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Delete an item from the list widget
 */

void
DialogListDeleteItem(DialogList *entry, char *item)
{
    XmString deleteItem;

    deleteItem = XmStringCreateSimple(item);
    XmListDeleteItem(entry->list, deleteItem);
    XmStringFree(deleteItem);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogListDeleteList
 *
 * INPUTS:
 *	entry		- (DialogList *) text structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Delete the entire list from the list widget
 */

void
DialogListDeleteList(DialogList *entry)
{
    XmListDeleteAllItems(entry->list);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogOptionCreate
 *
 * INPUTS:
 *	label		- (char *) label for option menu
 *	num		- (int) number of menu entries
 *	initial		- (int) initial value for option menu
 *	callback	- (XtCallbackProc) callback procedure or NULL
 *	type		- (enum DialogOptionType) type of remaining args
 *
 *	The remining arguments can be:
 *
 *	    alternating labels (char *) and values (int)
 *	    an array of labels (char *[]) and an array of values (int [])
 *	    alternating pixmap (Pixmap) and values (int)
 *	    an array of pixmap (Pixmap []) and an array of values (int [])
 *
 *	In addition, the array of values (int []) may be set to NULL, if
 *	a trivial { 0, 1, 2, 3, ... } value translation is desired.
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogOption *) structure defining this menu
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	This function creates and manages an option menu on a dialog.
 */

DialogOption *
DialogOptionCreate(char *label, int num, int initial, XtCallbackProc callback,
    enum DialogOptionType type, ...)
{
    va_list ap;			/* variable function argument list */
    Cardinal n;			/* standard count of Xt arguments */
    Arg args[20];		/* standard  Xt argument list */
    DialogOption *entry;	/* returned structure */
    int i;			/* local index */
    Pixmap pix;			/* temporary pixmap */
    char *text;			/* temporary text string */
    Pixmap *pixarray;		/* pixmap array */
    char **txtarray;		/* text string array */
    int *valarray;		/* array of values */
    XmString tmpstr;		/* temporary Motif string */
    int val;			/* initial value index */

    va_start(ap, type);

    entry = XtNew(DialogOption);
    entry->button = (Widget *)XtMalloc(num * sizeof(Widget));
    entry->value = (int *)XtMalloc(num * sizeof(int));
    entry->num = num;

    n = 0;
    if (rowForm == NULL) {
	entry->menu = XmCreatePulldownMenu(rowCol, "menu", args, n);
    } else {
	entry->menu = XmCreatePulldownMenu(rowForm, "menu", args, n);
    }

    val = 0;

    switch (type) {
    case DIALOG_OPT_STR_VA:

	for (i = 0; i < num; ++i) {
    
	    text = va_arg(ap, char *);
	    entry->value[i] = va_arg(ap, int);
    
	    if (entry->value[i] == initial) {
		val = i;
	    }
    
	    tmpstr = XmStringCreateSimple(text);
	    n = 0;
	    XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
	    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	    entry->button[i] = XmCreatePushButtonGadget(entry->menu, "button",
		args, n);
	    XmStringFree(tmpstr);
	    if (callback != NULL) {
		XtAddCallback(entry->button[i], XmNactivateCallback, callback,
		    (XtPointer)(entry->value[i]));
	    }
	}
	break;

    case DIALOG_OPT_STR_ARY:

	txtarray = va_arg(ap, char **);
	valarray = va_arg(ap, int *);

	for (i = 0; i < num; ++i) {
	    
	    text = txtarray[i];
	    entry->value[i] = (valarray == NULL) ? i : valarray[i];

	    if (entry->value[i] == initial) {
		val = i;
	    }
    
	    tmpstr = XmStringCreateSimple(text);
	    n = 0;
	    XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
	    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	    entry->button[i] = XmCreatePushButtonGadget(entry->menu, "button",
		args, n);
	    XmStringFree(tmpstr);
	    if (callback != NULL) {
		XtAddCallback(entry->button[i], XmNactivateCallback, callback,
		    (XtPointer)(entry->value[i]));
	    }
	}
	break;

    case DIALOG_OPT_PIX_VA:

	for (i = 0; i < num; ++i) {
    
	    pix = va_arg(ap, Pixmap);
	    entry->value[i] = va_arg(ap, int);
    
	    if (entry->value[i] == initial) {
		val = i;
	    }
    
	    n = 0;
	    XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
	    XtSetArg(args[n], XmNlabelPixmap, pix); n++;
	    entry->button[i] = XmCreatePushButtonGadget(entry->menu, "button",
		args, n);
	    if (callback != NULL) {
		XtAddCallback(entry->button[i], XmNactivateCallback, callback,
		    (XtPointer)(entry->value[i]));
	    }
	}
	break;

    case DIALOG_OPT_PIX_ARY:

	pixarray = va_arg(ap, Pixmap *);
	valarray = va_arg(ap, int *);

	for (i = 0; i < num; ++i) {
    
	    pix = pixarray[i];
	    entry->value[i] = (valarray == NULL) ? i : valarray[i];
    
	    if (entry->value[i] == initial) {
		val = i;
	    }
    
	    n = 0;
	    XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
	    XtSetArg(args[n], XmNlabelPixmap, pix); n++;
	    entry->button[i] = XmCreatePushButtonGadget(entry->menu, "button",
		args, n);
	    if (callback != NULL) {
		XtAddCallback(entry->button[i], XmNactivateCallback, callback,
		    (XtPointer)(entry->value[i]));
	    }
	}
	break;

    }
    XtManageChildren(entry->button, (Cardinal)num);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    XtSetArg(args[n], XmNsubMenuId, entry->menu); n++;
    XtSetArg(args[n], XmNmenuHistory, entry->button[val]); n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateOptionMenu(rowCol, "option", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateOptionMenu(rowForm, "option", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XmStringFree(tmpstr);

    XtManageChild(entry->parent);

    entry->label = XmOptionLabelGadget(entry->parent);

    va_end(ap);

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogOptionSet
 *
 * INPUTS:
 *	entry		- (DialogOption *) option menu structure
 *	val		- (int) new value for option menu
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Set the value of an option menu in a simple manner.
 */

void
DialogOptionSet(DialogOption *entry, int val)
{
    Cardinal n;			/* standard count of Xt arguments */
    Arg args[1];		/* standard  Xt argument list */
    int i;			/* local index */

    for (i = 0; i < entry->num; ++i) {
	if (entry->value[i] == val) {
	    n = 0;
	    XtSetArg(args[n], XmNmenuHistory, entry->button[i]); n++;
	    XtSetValues(entry->parent, args, n);
	    break;
	}
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogOptionGet
 *
 * INPUTS:
 *	entry		- (DialogOption *) option menu structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (int) current value of option menu
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of an option menu in a simple manner.
 */

int
DialogOptionGet(DialogOption *entry)
{
    Cardinal n;			/* standard count of Xt arguments */
    Arg args[1];		/* standard  Xt argument list */
    Widget w;			/* returned button */
    int i;			/* local index */
    int val;			/* value to return */

    n = 0;
    XtSetArg(args[n], XmNmenuHistory, &w); n++;
    XtGetValues(entry->parent, args, n);

    val = -1;
    for (i = 0; i < entry->num; ++i) {
	if (entry->button[i] == w) {
	    val = entry->value[i];
	    break;
	}
    }

    return val;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTimeCreate
 *
 * INPUTS:
 *	label		- (char *) label for time widget
 *	resol		- (int) resolution of time widget
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogTime *) time structure
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a time entry box of the specified resolution.
 */

DialogTime *
DialogTimeCreate(char *label, int resol)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogTime *entry;
    Widget tmpwgt;

    entry = XtNew(DialogTime);

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateRowColumn(rowCol, "textRC", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateRowColumn(rowForm, "textRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 4); n++;
    XtSetArg(args[n], XmNmaxLength, 4); n++;
    entry->year = XmCreateText(entry->parent, "year", args, n);
    XtManageChild(entry->year);

    tmpstr = XmStringCreateSimple("-");
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 3); n++;
    XtSetArg(args[n], XmNmaxLength, 3); n++;
    entry->day = XmCreateText(entry->parent, "day", args, n);
    XtManageChild(entry->day);

    if (resol == UTC_DAYS) {
	entry->hour = NULL;
	entry->minute = NULL;
	entry->second = NULL;
	return entry;
    }

    tmpstr = XmStringCreateSimple("T");
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 2); n++;
    XtSetArg(args[n], XmNmaxLength, 2); n++;
    entry->hour = XmCreateText(entry->parent, "hour", args, n);
    XtManageChild(entry->hour);

    if (resol == UTC_HOURS) {
	entry->minute = NULL;
	entry->second = NULL;
	return entry;
    }

    tmpstr = XmStringCreateSimple(":");
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 2); n++;
    XtSetArg(args[n], XmNmaxLength, 2); n++;
    entry->minute = XmCreateText(entry->parent, "minute", args, n);
    XtManageChild(entry->minute);

    if (resol == UTC_MINUTES) {
	entry->second = NULL;
	return entry;
    }

    tmpstr = XmStringCreateSimple(":");
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 2); n++;
    XtSetArg(args[n], XmNmaxLength, 2); n++;
    entry->second = XmCreateText(entry->parent, "second", args, n);
    XtManageChild(entry->second);

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTimeSet
 *
 * INPUTS:
 *	entry		- (DialogTime *) text structure
 *	val		- (utc_val) new value for time
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Set the value of a dialog time widget.
 */

void
DialogTimeSet(DialogTime *entry, utc_val val)
{
    char text[UTC_TEXT_LENGTH];

    getx_utc(text, val);

    text[4] = '\0';
    XmTextSetString(entry->year, text);

    text[8] = '\0';
    XmTextSetString(entry->day, text + 5);

    if (entry->hour != NULL) {
	text[11] = '\0';
	XmTextSetString(entry->hour, text + 9);

	if (entry->minute != NULL) {
	    text[14] = '\0';
	    XmTextSetString(entry->minute, text + 12);

	    if (entry->second != NULL) {
		text[17] = '\0';
		XmTextSetString(entry->second, text + 15);
	    }
	}
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogTimeGet
 *
 * INPUTS:
 *	entry		- (DialogTime *) text structure
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (utc_val) new value for time
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog time widget.
 */

utc_val
DialogTimeGet(DialogTime *entry)
{
    char text[UTC_TEXT_LENGTH];
    char *ptr;
    utc_val val;

    /*
     * extract year
     */
    ptr = XmTextGetString(entry->year);
    if (strlen(ptr) != 4) {
	XtFree(ptr);
	return UTC_INVALID;
    }
    strcpy(text, ptr);
    XtFree(ptr);

    /*
     * extract day
     */
    ptr = XmTextGetString(entry->day);
    if (strlen(ptr) != 3) {
	XtFree(ptr);
	return UTC_INVALID;
    }
    text[4] = '-';
    strcpy(text + 5, ptr);
    XtFree(ptr);

    /*
     * extract hour
     */
    if (entry->hour != NULL) {
	ptr = XmTextGetString(entry->hour);
	if (strlen(ptr) != 2) {
	    XtFree(ptr);
	    return UTC_INVALID;
	}
	text[8] = 'T';
	strcpy(text + 9, ptr);
	XtFree(ptr);

	/*
	 * extract minute
	 */
	if (entry->minute != NULL) {
	    ptr = XmTextGetString(entry->minute);
	    if (strlen(ptr) != 2) {
		XtFree(ptr);
		return UTC_INVALID;
	    }
	    text[11] = ':';
	    strcpy(text + 12, ptr);

	    /*
	     * extract second
	     */
	    if (entry->second != NULL) {
		ptr = XmTextGetString(entry->second);
		if (strlen(ptr) != 2) {
		    XtFree(ptr);
		    return UTC_INVALID;
		}
		text[14] = ':';
		strcpy(text + 15, ptr);
	    }
	}
    }

    val = setx_utc(text);

    return val;
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogDateCreate
 *
 * INPUTS:
 *      label           - (char *) label for date widget
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *	entry		- (DialogDate *) date structure
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create the widgets for a Date object
 */

DialogDate *
DialogDateCreate(char *label)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogDate *entry;
    Widget tmpwgt;

    entry = XtNew(DialogDate);

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL) {
        entry->parent = XmCreateRowColumn(rowCol, "dateRC", args, n);
    } else {
        XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
        XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
        XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
        XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
        XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
        XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
        entry->parent = XmCreateRowColumn(rowForm, "dateRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
            rowForm = NULL;
            rowFormIndex = 0;
            rowFormNumber = 0;
        }
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 2); n++;
    XtSetArg(args[n], XmNmaxLength, 2); n++;
    entry->month = XmCreateText(entry->parent, "month", args, n);
    XtManageChild(entry->month);

    tmpstr = XmStringCreateSimple("/");
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 2); n++;
    XtSetArg(args[n], XmNmaxLength, 2); n++;
    entry->day = XmCreateText(entry->parent, "day", args, n);
    XtManageChild(entry->day);

    tmpstr = XmStringCreateSimple("/");
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNcolumns, 4); n++;
    XtSetArg(args[n], XmNmaxLength, 4); n++;
    entry->year = XmCreateText(entry->parent, "year", args, n);
    XtManageChild(entry->year);

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogDateSet
 *
 * INPUTS:
 *      entry           - (DialogDate *) date structure
 *	val		- (utc_val) current date
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Set the values of the dialog date widgets.
 */

void
DialogDateSet(DialogDate *entry, utc_val val)
{
    int month, day, year;
    char buf[5];

    get_mdy(&month, &day, &year, val);

    sprintf(buf, "%02d", month);
    XmTextSetString(entry->month, buf);
    XmTextSetInsertionPosition(entry->month, 2);
    sprintf(buf, "%02d", day);
    XmTextSetString(entry->day, buf);
    XmTextSetInsertionPosition(entry->day, 2);
    sprintf(buf, "%04d", year);
    XmTextSetString(entry->year, buf);
    XmTextSetInsertionPosition(entry->year, 4);
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogDateGet
 *
 * INPUTS:
 *      entry           - (DialogDate *) date structure
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *	utc_val		- utc value for month/day/year values
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Get the values of the dialog date widgets and compute the
 *	corresponding utc value.
 */

utc_val
DialogDateGet(DialogDate *entry)
{
    int month, day, year;
    utc_val val;
    char *text;

    /*
     * get all text values
     */
    text = (char *)XmTextGetString(entry->month);
    month = atoi(text);
    XtFree(text);
    text = (char *)XmTextGetString(entry->year);
    year = atoi(text);
    XtFree(text);
    text = (char *)XmTextGetString(entry->day);
    day = atoi(text);
    XtFree(text);

    val = set_mdy(month, day, year);

    return val;
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogRadioCreate
 *
 * INPUTS:
 *      label           - (char *) label for option menu
 *      num             - (int) number of menu entries
 *      initial         - (int) initial value for option menu
 *      callback        - (XtCallbackProc) callback procedure or NULL
 *	type		- (enum DialogOptionType) type of input
 *
 *      The remining arguments can be:
 *
 *          alternating labels (char *) and values (int)
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      entry           - (DialogRadio *) structure defining this menu
 *
 * EXTERNALLY READ:
 *      rowCol          - (Widget) parent for full row
 *      rowForm         - (Widget) parent for partial row
 *      rowFormIndex    - (int) index for partial row
 *      rowFormNumber   - (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *      rowForm         - (Widget) parent for partial row
 *      rowFormIndex    - (int) index for partial row
 *      rowFormNumber   - (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *      This function creates and manages an radio box on a dialog.
 */

DialogRadio *
DialogRadioCreate(char *label, int num, int initial, XtCallbackProc callback, 
    enum DialogRadioType type, ...)
{
    va_list ap;                 /* variable function argument list */
    Cardinal n;                 /* standard count of Xt arguments */
    Arg args[20];               /* standard  Xt argument list */
    DialogRadio *entry;		/* returned structure */
    int i;                      /* local index */
    char *text;                 /* temporary text string */
    char **txtarray;            /* text string array */
    int *valarray;              /* array of values */
    XmString tmpstr;            /* temporary Motif string */
    Widget tmpwgt;		/* temporary label widget */

    va_start(ap, type);

    entry = XtNew(DialogRadio);
    entry->button = (Widget *)XtMalloc(num * sizeof(Widget));
    entry->value = (int *)XtMalloc(num * sizeof(int));
    entry->num = num;

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL) {
        entry->parent = XmCreateRowColumn(rowCol, "radioRC", args, n);
    } else {
        XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
        XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
        XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
        XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
        XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
        XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
        entry->parent = XmCreateRowColumn(rowForm, "radioRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
            rowForm = NULL;
            rowFormIndex = 0;
            rowFormNumber = 0;
        }
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabelGadget(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
    tmpwgt = XmCreateRadioBox(entry->parent, "radio", args, n);
		
    switch (type) {
    case DIALOG_RAD_STR_VA:

	for (i = 0; i < num; ++i) {

            text = va_arg(ap, char *);
	    entry->value[i] = va_arg(ap, int);

            tmpstr = XmStringCreateSimple(text);
            n = 0;
            XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	    XtSetArg(args[n], XmNset, (entry->value[i] == initial)); n++;
            entry->button[i] = XmCreateToggleButton(tmpwgt, "button", 
		args, n);
	    XmStringFree(tmpstr);
	    if (callback != NULL) {
        	XtAddCallback(entry->button[i], XmNvalueChangedCallback, 
		    callback, (XtPointer)(entry->value[i]));
	    }
	}
	break;

    case DIALOG_RAD_STR_ARY:

	txtarray = va_arg(ap, char **);
        valarray = va_arg(ap, int *);

        for (i = 0; i < num; ++i) {

            text = txtarray[i];
            entry->value[i] = (valarray == NULL) ? i : valarray[i];

            tmpstr = XmStringCreateSimple(text);
            n = 0;
            XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
            XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	    XtSetArg(args[n], XmNset, (entry->value[i] == initial)); n++;
            entry->button[i] = XmCreateToggleButton(tmpwgt, "button",
		args, n);
	    XmStringFree(tmpstr);
            if (callback != NULL) {
                XtAddCallback(entry->button[i], XmNvalueChangedCallback,
		    callback, (XtPointer)(entry->value[i]));
            }
        }
        break;
    }

    XtManageChildren(entry->button, (Cardinal)num);
    XtManageChild(tmpwgt);

    va_end(ap);

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogRadioSet
 *
 * INPUTS:
 *      entry           - (DialogRadio *) radio box structure
 *      val             - (int) new value for radio box toggle button
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Set the value of an radio box in a simple manner.
 */

void
DialogRadioSet(DialogRadio *entry, int val)
{
    int i;

    for (i = 0; i < entry->num; ++i) {
	if (entry->value[i] == val) {
	    XmToggleButtonSetState(entry->button[i], True, True);
	    break;
	}
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogRadioGet
 *
 * INPUTS:
 *      entry           - (DialogRadio *) radio box structure
 *	item		- (int)	toggle button index
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      val             - (int) current value of radio box
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Get the value of an radio box toggle button in a simple manner.
 */

int
DialogRadioGet(DialogRadio *entry)
{
    int val;                    /* value of toggle button */
    int i;

    val = -1;
    for (i = 0; i < entry->num; ++i) {
	val = (int)XmToggleButtonGetState(entry->button[i]);
	if (val == 1) {
	    break;
	}
    }
  
    return entry->value[i];
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogToggleCreate
 *
 * INPUTS:
 *      label           - (char *) label for group
 *      num             - (int) number of toggle buttons
 *      callback        - (XtCallbackProc) callback procedure or NULL
 *	type		- (enum DialogToggleType) type of input
 *
 *      If type is DIALOG_TOG_STR_VA, then the remaining arguments should be
 *      triples of the form
 *          char * label, int key, int initialSetting
 *
 *      If type is DIALOG_TOG_STR_ARY, then the remaining arguments should be
 *          char ** labelArray, int * keyArray, int * initialArray
 *
 *      Also, in the latter case, keyArray may be set to NULL to have the
 *      effect of { 0, 1, 2, 3, ... } and initialArray may be set to NULL to
 *      have the effect of { 0, 0, 0, 0, ... }.
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      entry           - (DialogToggle *) structure defining this button
 *
 * EXTERNALLY READ:
 *      rowCol          - (Widget) parent for full row
 *      rowForm         - (Widget) parent for partial row
 *      rowFormIndex    - (int) index for partial row
 *      rowFormNumber   - (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *      rowForm         - (Widget) parent for partial row
 *      rowFormIndex    - (int) index for partial row
 *      rowFormNumber   - (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *      This function creates and manages a toggle button on a dialog.
 *      It borrows heavily from the DialogRadio routines.
 */

DialogToggle *
DialogToggleCreate(char *label, int num, XtCallbackProc callback, 
    enum DialogToggleType type, ...)
{
    va_list ap;                 /* variable function argument list */
    Cardinal n;                 /* standard count of Xt arguments */
    Arg args[20];               /* standard  Xt argument list */
    DialogToggle *entry;	/* returned structure */
    int i;                      /* local index */
    int state;                  /* state of current toggle (a temporary) */
    char *text;                 /* temporary text string */
    char **txtArray;            /* text string array */
    int *keyArray;              /* array of keys */
    int *initialArray;		/* array of initial states */
    XmString tmpstr;            /* temporary Motif string */

    va_start(ap, type);

    entry = XtNew(DialogToggle);
    entry->button = (Widget *)XtMalloc(num * sizeof(Widget));
    entry->keys = (int *)XtMalloc(num * sizeof(int));
    entry->num = num;

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL)  {
        entry->parent = XmCreateRowColumn(rowCol, "dialogRC", args, n);
    }  else  {
        XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
        XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
        XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
        XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
        XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
        XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
        entry->parent = XmCreateRowColumn(rowForm, "dialogRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber)  {
            rowForm = NULL;
            rowFormIndex = 0;
            rowFormNumber = 0;
        }
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabelGadget(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    n = 0;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
		
    switch (type)  {
    case DIALOG_TOG_STR_VA:

	for (i = 0; i < num; ++i)  {
            text = va_arg(ap, char *);
	    entry->keys[i] = va_arg(ap, int);
	    state = va_arg(ap, int);

            tmpstr = XmStringCreateSimple(text);
            n = 0;
            XtSetArg(args[n], XmNlabelString, tmpstr); n++;
            entry->button[i] = XmCreateToggleButton(entry->parent, "button",
		args, n);
	    XmStringFree(tmpstr);

	    XmToggleButtonSetState(entry->button[i], state, False);

	    if (callback != NULL)  {
        	XtAddCallback(entry->button[i], XmNvalueChangedCallback, 
		    callback, (XtPointer)(entry->keys[i]));
	    }
	}
	break;

    case DIALOG_TOG_STR_ARY:

	txtArray = va_arg(ap, char **);
        keyArray = va_arg(ap, int *);
	initialArray = va_arg(ap, int *);

	for (i = 0; i < num; ++i)  {
	    text = txtArray[i];
	    entry->keys[i] = (keyArray == NULL)  ?  i  :  keyArray[i];
	    state = (initialArray == NULL)  ?  0  :  initialArray[i];

	    tmpstr = XmStringCreateSimple(text);
	    n = 0;
	    XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
	    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	    entry->button[i] = XmCreateToggleButton(entry->parent, "button",
		args, n);
	    XmStringFree(tmpstr);

	    XmToggleButtonSetState(entry->button[i], state, False);

	    if (callback != NULL)  {
		XtAddCallback(entry->button[i], XmNvalueChangedCallback,
		    callback, (XtPointer)(entry->keys[i]));
	    }
	}
	break;
    }

    XtManageChildren(entry->button, (Cardinal) num);

    va_end(ap);

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogToggleDestroy
 *
 * INPUTS:
 *      entry           - (DialogToggle *) toggle structure
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Free up the memory used by a DialogToggle structure.
 */

void
DialogToggleDestroy(DialogToggle * entry)
{
    XtFree((char *) (entry->keys));
    XtFree((char *) entry);
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogToggleSet
 *
 * INPUTS:
 *      entry           - (DialogToggle *) toggle structure
 *      whichKey        - (int) identifies button to be set
 *      newSetting      - (int) new setting for toggle button (True/False).
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Directly set the state of a toggle button.
 */

void
DialogToggleSet(DialogToggle * entry, int whichKey, int newSetting)
{
    int i;

    for (i = 0; i < entry->num; ++i)  {
	if (entry->keys[i] == whichKey)  {
	    XmToggleButtonSetState(entry->button[i], newSetting, True);
	    break;
	}
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogToggleGet
 *
 * INPUTS:
 *      entry           - (DialogToggle *) toggle button structure
 *      whichKey        - (int) key identifying toggle
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      (boolean)       - (int) state of matching toggle, or -1 if invalid key.
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Get the state of a toggle button.
 */

int
DialogToggleGet(DialogToggle * entry, int whichKey)
{
    int i;

    for (i = 0; i < entry->num; ++i)  {
	if (entry->keys[i] == whichKey)
	    return XmToggleButtonGetState(entry->button[i]);
    }

    return -1;     /* Not found */
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogToggleFlip
 *
 * INPUTS:
 *      entry           - (DialogToggle *) toggle button structure
 *      whichKey        - (int) key identifying toggle to flip
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      Invert the state of a toggle button.
 */

void
DialogToggleFlip(DialogToggle * entry, int whichKey)
{
    DialogToggleSet(entry, whichKey, !DialogToggleGet(entry, whichKey));
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogLabelCreate
 *
 * INPUTS:
 *	text		- (char *) label text
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogEntry *) a entry for a Label Widget
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a Label widget.
 */

DialogEntry *
DialogLabelCreate(char *text)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogEntry *entry;

    entry = XtNew(DialogEntry);

    tmpstr = XmStringCreateSimple(text);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateLabel(rowCol, "label", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateLabel(rowForm, "label", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);
    XmStringFree(tmpstr);

    entry->label = entry->parent;

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogButtonCreate
 *
 * INPUTS:
 *	text		- (char *) label text
 *	callback	- (XtCallbackProc) callback procedure or NULL
 *	client		- (XtPointer) client data
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogEntry *) a entry for a Button Widget
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a Push Button Widget.
 */

DialogEntry *
DialogButtonCreate(char *text, XtCallbackProc callback, XtPointer client)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogEntry *entry;

    entry = XtNew(DialogEntry);

    tmpstr = XmStringCreateSimple(text);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
    if (rowForm == NULL) {
	entry->parent = XmCreatePushButton(rowCol, "button", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreatePushButton(rowForm, "button", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtAddCallback(entry->parent, XmNactivateCallback, callback, client);
    XtManageChild(entry->parent);
    XmStringFree(tmpstr);

    entry->label = entry->parent;

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogSeparatorCreate
 *
 * INPUTS:
 *	type		- (int) type of this Separator
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogEntry *) a entry for a Separator
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a Separator widget.
 */

DialogEntry *
DialogSeparatorCreate(int type)
{
    Arg args[15];
    Cardinal n;
    DialogEntry *entry;

    entry = XtNew(DialogEntry);

    n = 0;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNseparatorType, type);  n++;
    XtSetArg(args[n], XmNheight, 16);  n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateSeparator(rowCol, "separator", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateSeparator(rowForm, "separator", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);

    entry->label = NULL;

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogSpecialCreate
 *
 * INPUTS:
 *	label		- (char) label text or NULL
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogEntry *) a entry for a container
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a Horizontal row column widget to be used as a container
 *	for any items that the user wishes to add to the dialog.
 */

DialogEntry *
DialogSpecialCreate(char *label)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogEntry *entry;

    entry = XtNew(DialogEntry);

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateRowColumn(rowCol, "specialRC", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateRowColumn(rowForm, "specialRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);

    if (label != NULL) {
	tmpstr = XmStringCreateSimple(label);
	n = 0;
	XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	entry->label = XmCreateLabel(entry->parent, "label", args, n);
	XtManageChild(entry->label);
	XmStringFree(tmpstr);
    } else {
	entry->label = NULL;
    }

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogStdButtons
 *
 * INPUTS:
 *	parent		- (Widget) parent of this form
 *	okCB		- (XtCallbackProc) callback procedure for OK
 *	okData		- (XtPointer) client data for OK
 *	cancelCB	- (XtCallbackProc) callback procedure for Cancel
 *	cancelData	- (XtPointer) client data for Cancel
 *	helpCB		- (XtCallbackProc) callback procedure for Help
 *	helpData	- (XtPointer) client data for Help
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Create three buttons (OK, Cancel, and Help) with callbacks and
 *	client data for display in a dialog.
 */

void
DialogStdButtons(XtCallbackProc okCB, XtPointer okData, XtCallbackProc cancelCB,
    XtPointer cancelData, XtCallbackProc helpCB, XtPointer helpData)
{
    Cardinal n;
    Arg args[15];
    Widget buttonForm;
    Widget tmpwgt;
    XmString tmpstr;

    n = 0;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
    XtSetArg(args[n], XmNseparatorType, XmDOUBLE_LINE); n++;
    XtSetArg(args[n], XmNheight, 16); n++;
    tmpwgt = XmCreateSeparator(rowCol, "separator", args, n);
    XtManageChild(tmpwgt);

    n = 0;
    XtSetArg(args[n], XmNfractionBase, 100); n++;
    buttonForm = XmCreateForm(rowCol, "buttonForm", args, n);
    XtManageChild(buttonForm);

    n = 0;
    tmpstr = XmStringCreateSimple("OK");
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
    XtSetArg(args[n], XmNleftPosition, 0); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
    XtSetArg(args[n], XmNrightPosition, 30); n++;
    if (okCB == NULL) {
        XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
    }
    tmpwgt = XmCreatePushButton(buttonForm, "okButton", args, n);
    XtAddCallback(tmpwgt, XmNactivateCallback, okCB, okData);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    tmpstr = XmStringCreateSimple("Cancel");
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
    XtSetArg(args[n], XmNleftPosition, 35); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
    XtSetArg(args[n], XmNrightPosition, 65); n++;
    if (cancelCB == NULL) {
        XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
    }
    tmpwgt = XmCreatePushButton(buttonForm, "cancelButton", args, n);
    XtAddCallback(tmpwgt, XmNactivateCallback, cancelCB, cancelData);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);

    n = 0;
    tmpstr = XmStringCreateSimple("Help");
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
    XtSetArg(args[n], XmNleftPosition, 70); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
    XtSetArg(args[n], XmNrightPosition, 100); n++;
    if (helpCB == NULL) {
        XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
    }
    tmpwgt = XmCreatePushButton(buttonForm, "helpButton", args, n);
    XtAddCallback(tmpwgt, XmNactivateCallback, helpCB, helpData);
    XtManageChild(tmpwgt);
    XmStringFree(tmpstr);
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogManage
 *
 * INPUTS:
 *	dialog		- (Widget) dialog to manage
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 */

int
DialogManage(Widget dialog)
{
    XEvent event;			/* event structure for loop */

    if (depth == MAX_DIALOG_DEPTH - 1) {
	return DIALOG_ERROR;
    }

    flag[++depth] = DIALOG_ERROR;
    ShellModalManage(dialog);

    do {
	XtAppNextEvent(app, &event);
	XtDispatchEvent(&event);
    } while(flag[depth] & DIALOG_ERROR);

    ShellModalUnmanage(dialog);

    return flag[depth--];
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogFlagSet
 *
 * INPUTS:
 *	val		- (int) flag value
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	depth		- (static int) current dialog depth
 *
 * EXTERNALLY MODIFIED:
 *	flag		- (static int[]) current flag
 *
 * DESCRIPTION:
 *	Set the current dialog flag to the given value.
 */

void
DialogFlagSet(int val)
{
    flag[depth] = val;
}

/***********************************************************************
 *
 * FUNCTION:
 *      DialogChangeLabel
 *
 * INPUTS:
 *	entry		- (DialogEntry *) any dialog structure
 *	text		- (char *) new label text
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *	Change the label text for any DialogEntry.
 */

void
DialogChangeLabel(DialogEntry *entry, char *text)
{
    Arg args[2];
    Cardinal n;
    XmString tmpstr;

    if (entry->label != NULL) {
	tmpstr = XmStringCreateSimple(text);
	n = 0;
	XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	XtSetValues(entry->label, args, n);
	XmStringFree(tmpstr);
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogDurationCreate
 *
 * INPUTS:
 *	label		- (char *) label for time span widget
 *	resol1		- (int) resolution of time span widget
 *	resol2		- (int) resolution of time span widget
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	entry		- (DialogDuration *) time span structure
 *
 * EXTERNALLY READ:
 *	rowCol		- (Widget) parent for full row
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * EXTERNALLY MODIFIED:
 *	rowForm		- (Widget) parent for partial row
 *	rowFormIndex	- (int) index for partial row
 *	rowFormNumber	- (int) maximum index for partial row
 *	rowFormWidth	- (int) width in columns of next entry
 *
 * DESCRIPTION:
 *	Create a time span entry box of the specified
 *	beginning and ending resolutions.
 */

DialogDuration *
DialogDurationCreate(char *label, int resol1, int resol2)
{
    Arg args[15];
    Cardinal n;
    XmString tmpstr;
    DialogDuration *entry;
    Widget tmpwgt;

    entry = XtNew(DialogDuration);

    n = 0;
    XtSetArg(args[n], XmNnumColumns, 1);  n++;
    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);  n++;
    XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);  n++;
    XtSetArg(args[n], XmNmarginWidth, 0);  n++;
    XtSetArg(args[n], XmNmarginHeight, 0);  n++;
    XtSetArg(args[n], XmNspacing, 0);  n++;
    if (rowForm == NULL) {
	entry->parent = XmCreateRowColumn(rowCol, "textRC", args, n);
    } else {
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNleftPosition, rowFormIndex);  n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);  n++;
	XtSetArg(args[n], XmNrightPosition, rowFormIndex + rowFormWidth);  n++;
	entry->parent = XmCreateRowColumn(rowForm, "textRC", args, n);

	rowFormIndex += rowFormWidth;
	rowFormWidth = 1;

	if (rowFormIndex >= rowFormNumber) {
	    rowForm = NULL;
	    rowFormIndex = 0;
	    rowFormNumber = 0;
	}
    }
    XtManageChild(entry->parent);

    tmpstr = XmStringCreateSimple(label);
    n = 0;
    XtSetArg(args[n], XmNlabelString, tmpstr); n++;
    entry->label = XmCreateLabel(entry->parent, "label", args, n);
    XtManageChild(entry->label);
    XmStringFree(tmpstr);

    /*
     * Determine the starting resolution.
     */
    if (resol1 == UTC_DAYS) {
	n = 0;
	XtSetArg(args[n], XmNcolumns, 3); n++;
	XtSetArg(args[n], XmNmaxLength, 3); n++;
	entry->day = XmCreateText(entry->parent, "day", args, n);
	XtManageChild(entry->day);

	if (resol2 == UTC_DAYS) {
	    entry->hour = NULL;
	    entry->minute = NULL;
	    entry->second = NULL;
	    return entry;
	}
    } else {
	entry->day = NULL;
    }

    if (resol1 > UTC_HOURS) {
	tmpstr = XmStringCreateSimple(" ");
	n = 0;
	XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
	XtManageChild(tmpwgt);
	XmStringFree(tmpstr);
    }

    if (resol1 >= UTC_HOURS) {
	n = 0;
	XtSetArg(args[n], XmNcolumns, 2); n++;
	XtSetArg(args[n], XmNmaxLength, 2); n++;
	entry->hour = XmCreateText(entry->parent, "hour", args, n);
	XtManageChild(entry->hour);

	if (resol2 == UTC_HOURS) {
		entry->minute = NULL;
		entry->second = NULL;
		return entry;
	}
    } else {
	entry->hour = NULL;
    }

    if (resol1 > UTC_MINUTES) {
	tmpstr = XmStringCreateSimple(":");
	n = 0;
	XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
	XtManageChild(tmpwgt);
	XmStringFree(tmpstr);
    }

    if (resol1 >= UTC_MINUTES) {
	n = 0;
	XtSetArg(args[n], XmNcolumns, 2); n++;
	XtSetArg(args[n], XmNmaxLength, 2); n++;
	entry->minute = XmCreateText(entry->parent, "minute", args, n);
	XtManageChild(entry->minute);

	if (resol2 == UTC_MINUTES) {
		entry->second = NULL;
		return entry;
	}
    } else {
	entry->minute = NULL;
    }

    if (resol1 > UTC_SECONDS) {
	tmpstr = XmStringCreateSimple(":");
	n = 0;
	XtSetArg(args[n], XmNlabelString, tmpstr); n++;
	tmpwgt = XmCreateLabel(entry->parent, "label", args, n);
	XtManageChild(tmpwgt);
	XmStringFree(tmpstr);

    }

    if (resol1 >= UTC_SECONDS) {
	n = 0;
	XtSetArg(args[n], XmNcolumns, 2); n++;
	XtSetArg(args[n], XmNmaxLength, 2); n++;
	entry->second = XmCreateText(entry->parent, "second", args, n);
	XtManageChild(entry->second);
    } else {
	entry->second = NULL;	/* this should be an error */
    }

    return entry;
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogDurationSet
 *
 * INPUTS:
 *	entry		- (DialogDuration *) time span struct
 *	val		- (int) new value for time
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Set the value of a dialog time span widget.
 */

void
DialogDurationSet(DialogDuration *entry, int val)
{
    char text[10];
    int tval;

    tval = val % 60;
    val /= 60;
    if (entry->second != NULL) {
	sprintf(text, "%02d", tval);
	XmTextSetString(entry->second, text);
	XmTextSetInsertionPosition(entry->second, 2);

	tval = val % 60;
	val /= 60;

	if (entry->minute != NULL) {
	    sprintf(text, "%02d", tval);
	    XmTextSetString(entry->minute, text);
	    XmTextSetInsertionPosition(entry->minute, 2);
	}

	tval = val % 60;
        val /= 60;

	if (entry->hour != NULL) {
	    sprintf(text, "%02d", tval);
            XmTextSetString(entry->hour, text);
            XmTextSetInsertionPosition(entry->hour, 2);
        }

	tval = val % 60;
        val /= 60;

        if (entry->day != NULL) {
            sprintf(text, "%02d", tval);
            XmTextSetString(entry->day, text);
            XmTextSetInsertionPosition(entry->day, 2);
        }
    } else if (entry->minute != NULL) {
	sprintf(text, "%02d", tval);
	XmTextSetString(entry->minute, text);
	XmTextSetInsertionPosition(entry->minute, 2);

	tval = val % 60;
        val /= 60;

	if (entry->hour != NULL) {
	    sprintf(text, "%02d", tval);
            XmTextSetString(entry->hour, text);
            XmTextSetInsertionPosition(entry->hour, 2);
        }

	tval = val % 60;
        val /= 60;

        if (entry->day != NULL) {
            sprintf(text, "%02d", tval);
            XmTextSetString(entry->day, text);
            XmTextSetInsertionPosition(entry->day, 2);
        }
    } else if (entry->hour != NULL) {
	sprintf(text, "%02d", tval);
        XmTextSetString(entry->hour, text);
        XmTextSetInsertionPosition(entry->hour, 2);

	tval = val % 60;
        val /= 60;

        if (entry->day != NULL) {
            sprintf(text, "%02d", tval);
            XmTextSetString(entry->day, text);
            XmTextSetInsertionPosition(entry->day, 2);
        }
    } else if (entry->hour != NULL) {
	sprintf(text, "%03d", tval);
	XmTextSetString(entry->day, text);
	XmTextSetInsertionPosition(entry->day, 2);
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	DialogDurationGet
 *
 * INPUTS:
 *	entry		- (DialogDuration *) time span struct
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	val		- (int) new value for time
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	Get the value of a dialog time span widget.
 */

int
DialogDurationGet(DialogDuration *entry)
{
    char *ptr;
    int val;

    val = 0;
    /*
     * extract day
     */
    if (entry->day != NULL) {
	ptr = XmTextGetString(entry->day);
	val += (int)(UTC_ONE_DAY * atoi(ptr));
	XtFree(ptr);
    }

    /*
     * extract hour
     */
    if (entry->hour != NULL) {
	ptr = XmTextGetString(entry->hour);
	val += (int)(UTC_ONE_HOUR * atoi(ptr));
	XtFree(ptr);
    }

    /*
     * extract minute
     */
    if (entry->minute != NULL) {
	ptr = XmTextGetString(entry->minute);
	val += (int)(UTC_ONE_MINUTE * atoi(ptr));
	XtFree(ptr);
    }

    /*
     * extract second
     */
    if (entry->second != NULL) {
	ptr = XmTextGetString(entry->second);
	val += (int)(UTC_ONE_SECOND * atoi(ptr));
	XtFree(ptr);
    }

    return val;
}

/******************************************************************************
 *
 * FUNCTION:
 *    MotifStringToAscii
 *
 * INPUT:
 *    item        - Motif list string
 *
 * OUTPUT:
 *    NONE
 *
 * RETURNS:
 *    asciiString   - ascii text string
 *
 * DESCRIPTION:
 *    This function converts a string from the List widget into a ascii text
 * string.
 *
 */

static char *
MotifStringToAscii(XmString item)
{
    XmStringContext context;
    XmStringCharSet charset;
    XmStringDirection dir;
    Boolean sep;
    static char *ascii;

    XmStringInitContext(&context, item);
    XmStringGetNextSegment(context, &ascii, &charset, &dir, &sep);
    XmStringFreeContext(context);
    return ascii;
}
