/* init_widgets.c
 * Create the widgets that will be the managed children of the application
 * shell.  Inform the Form Widget of the relative positions of these widgets,
 * and it computes the layout.  The default translation table for the Dialog
 * box is not used - another (see below) is constructed and used instead.
 *
 * Peter Webb, Summer 1990.
 */

/* X include files */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>

/* Widget include files */

#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/AsciiText.h>

/* Standard include files */

#include <stdio.h>

/* Conversion routine definitions */

#include "window.h"   
#include "types.h"      /* Package-wide type definitions */
#include "error.h"      /* Error codes */
#include "extern.h"     /* External routines and global variables */
#include "reformat.h"   /* Package-wide contants */

/* Global variables */

Widget MsgOut = NULL;

/* The dialog box widget translation table contains references to external
 * functions.  The translation manager must be notified of these functions.
 * This table maps the names in the translation table to external function
 * names, and is registered with the translation manager during
 * initialization.
 */

#define NUM_ACTIONS 1
static XtActionsRec actionTable[] = {
  {"dialog-new-string", DialogNewString},
};

/* The dialog box widgets contain an AsciiTextWidget child that interacts
 * with the user.  The default action bindings provide too much functionality.
 * This translation table replaces them.  Essentially, most of the emacs-style
 * editing capabilities have been removed, and the text area has been limited
 * to a single line.
 */

static char *dialogActions = 
"<Key>Delete:         delete-previous-character()\n\
 <Ctrl>H:             delete-previous-character()\n\
 <Ctrl>D:             delete-next-character()\n\
 <Key>BackSpace:      delete-previous-character()\n\
 <Key>Right:          forward-character()\n\
 <Key>Left:           backward-character()\n\
 <Key>Linefeed:       dialog-new-string()\n\
 <Key>Return:         dialog-new-string()\n\
 <Key>:               insert-char()\n\
 <Btn1Down>:          select-start()\n\
 <Btn1Motion>:        extend-adjust()\n\
 <Btn1Up>:            extend-end(PRIMARY, CUT_BUFFER0)\n\
 <Btn2Down>:          insert-selection(PRIMARY, CUT_BUFFER0)\n\
 <Btn3Down>:          extend-start()\n\
 <Btn3Motion>:        extend-adjust()\n\
 <Btn3Up>:            extend-end(PRIMARY, CUT_BUFFER0)\n\
";
static XtTranslations dialogTable;

/* Translation table for the toggle widgets in the help window. Taken from
 * pg. 45 in the Athena Widget manual (R4).  Implements a strict one-of-many
 * protocol for the widgets in a radio group.  Exactly one will be active
 * at all times.
 */

static char *toggleActions =
"<EnterWindow>:   highlight(Always)\n\
 <LeaveWindow>:   unhighlight()\n\
 <Btn1Down>,<Btn1Up>:  set() notify()\n\
";
static XtTranslations toggleTable;

/* List of input file types. Must be NULL-terminated. Order is not important.
 * This list is constructed from the FileTypeMap global variable.
 */

static char *inputTypes[NUM_TYPES+1];

/* For widget creation */

static Arg argList[MAX_ARGS];
static int argNum = 0;

/* Dimension box pointer */

static Widget dimForm, dimWidth, dimHeight;

/* Return the dimensions */

long GetDimWidth()
{
  long num;
  String value, ptr;
  
  value = XawDialogGetValueString(XtNameToWidget(dimForm, DIM_WIDTH));

  num = (long)strtol(value, (char **)&ptr, 10);
  if (*ptr != NULL)
    {
      err_msg(GetWidth, NotAnInteger);
      return 0;
    }
  else return (num);
}

long GetDimHeight()
{
  long num;
  String value, ptr;
  
  value = XawDialogGetValueString(XtNameToWidget(dimForm, DIM_HEIGHT));

  num = (long)strtol(value, (char **)&ptr, 10);
  if (*ptr != NULL)
    {
      err_msg(GetHeight, NotAnInteger);
      return 0;
    }
  else return (num);
}


/* Map or ummap the dimension */

void MapDimensionBox(map)
     int map;
{
  
  argNum = 0;

  if (map)
    {
      XtSetArg(argList[argNum], XtNmappedWhenManaged, True); argNum++;
    }
  else
    {
      XtSetArg(argList[argNum], XtNmappedWhenManaged, False); argNum++;
    }

  XtSetValues(dimForm, argList, argNum);
}    

/* Customize the dialog box widget */

static void InitDialog(widget, boxWidth, boxHeight, len)
  Widget widget;
  Dimension boxWidth, boxHeight;
  int len;
{
  Widget value, label, hbar;
  int spacing;
  Dimension width, border_width, char_width;
  XawTextPosition display_pos;
  XFontStruct *font;

/* Set the width of the text and label field of the given dialog box widget */

  value = XtNameToWidget(widget, "value");
  label = XtNameToWidget(widget, "label");

  argNum = 0;
  XtSetArg(argList[argNum], XtNhorizDistance, &spacing); argNum++;
  XtSetArg(argList[argNum], XtNborderWidth, &border_width); argNum++;
  XtSetArg(argList[argNum], XtNfont, &font); argNum++;
  XtGetValues(value, argList, argNum);

  width = boxWidth-spacing*2-border_width*2; 

  argNum = 0;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNwidth, width); argNum++;
  XtSetValues(value, argList, argNum);
  XtSetValues(label, argList, 1);

/* Inform the value widget of its new translation table.  Also, allow the
 * value widget to scroll horizontally.
 * Set the left and right edges of the text field so that they remain a fixed
 * distance from the left and right edges of the dialog box.  This should
 * prevent the text field from changing size until the dialog box is resized.
 */

  char_width = font->max_bounds.rbearing - font->min_bounds.lbearing;
  display_pos = len - ((width/char_width)-1);
  if (display_pos < 0) display_pos = 0;

  argNum = 0;
  XtSetArg(argList[argNum], XtNinsertPosition, len); argNum++;
  XtSetArg(argList[argNum], XtNdisplayPosition, display_pos); argNum++;
  XtSetArg(argList[argNum], XtNresizable, False); argNum++;
  XtSetArg(argList[argNum], XtNright, XtChainRight); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNtranslations, dialogTable); argNum++;
  XtSetValues(value, argList, argNum);

/* Add a new event handler that understands when to scroll the text in the
 * window.
 */

  XtAddEventHandler(value, KeyPressMask, False, ScrollDialogText, width);

}

/* Create a form widget that contains a scrollable text widget.  This text
 * widget will be used to display the help file.
 */

static Widget InitHelpPopup(box_width, box_height, font_info, app_shell)
  Dimension box_width, box_height;
  XFontStruct *font_info;
  Widget app_shell;
{
  Widget popup, text, toggle, search, label, form, quit, w, button;
  Dimension pageWidth, pageHeight;

/* Compute the size of a "page".  PAGE_WIDTH chars by PAGE_HEIGHT lines.
 * Add on a little space for the vertical scrollbar.
 */

  pageWidth = (PAGE_WIDTH+2) *
    (font_info->max_bounds.rbearing - font_info->min_bounds.lbearing);
  pageHeight = PAGE_HEIGHT *
    (font_info->ascent + font_info->descent + VERT_SEP);

/* Create the popup shell */

  argNum = 0;
  popup = XtCreatePopupShell(HELP_TITLE, topLevelShellWidgetClass,
			     app_shell, argList, argNum);

/* Create the form */

  argNum = 0;
  XtSetArg(argList[argNum], XtNx, 0); argNum++;
  XtSetArg(argList[argNum], XtNy, 0); argNum++;
  XtSetArg(argList[argNum], XtNdefaultDistance, INNER_BORDER); argNum++;

  form = XtCreateManagedWidget(HELP_FORM, formWidgetClass, popup,
			     argList, argNum);

/* The text is scrollable in both directions and READ-ONLY */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, pageWidth); argNum++;
  XtSetArg(argList[argNum], XtNheight, pageHeight); argNum++;
  XtSetArg(argList[argNum], XtNeditType, XawtextRead); argNum++;
  XtSetArg(argList[argNum], XtNtype, XawAsciiFile); argNum++;
  XtSetArg(argList[argNum], XtNstring, HelpFile); argNum++;
  XtSetArg(argList[argNum], XtNscrollVertical, XawtextScrollAlways); argNum++;
  XtSetArg(argList[argNum], XtNscrollHorizontal,
	   XawtextScrollWhenNeeded); argNum++;

  text = XtCreateManagedWidget(HELP_TEXT, asciiTextWidgetClass, form,
			       argList, argNum);

/* It is possible to search through the documentation for a string entered
 * by the user.  Create a dialog box for the search string.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, text); argNum++;
  XtSetArg(argList[argNum], XtNlabel, SEARCH_LBL); argNum++;
  XtSetArg(argList[argNum], XtNvalue, ""); argNum++;

  search = XtCreateManagedWidget(SEARCH_BOX, dialogWidgetClass, form,
				 argList, argNum);

  label = XtNameToWidget(search, "label");

/* Create a new button (search) for the dialog box */

  argNum = 0;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNresizable, True); argNum++;
  XtSetArg(argList[argNum], XtNlabel, SEARCH_BTN_TXT); argNum++;
  XtSetArg(argList[argNum], XtNhorizDistance, INNER_BORDER); argNum++;

  button = XtCreateManagedWidget(SEARCH_BTN, commandWidgetClass, search,
				 argList, argNum);
  XtAddCallback(button, XtNcallback, HelpSearchCallBack, NULL);

/* Put the button above the value field, to the right of the label */

  w = XtNameToWidget(search, "value");

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, button); argNum++;
  XtSetValues(w, argList, argNum);

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, NULL); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, label); argNum++;
  XtSetValues(button, argList, argNum);

/* Initialize the dialog box */

  InitDialog(search, box_width, box_height, 0);

/* Create the label for the toggle widget */

  argNum = 0;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNresizable, True); argNum++;
  XtSetArg(argList[argNum], XtNwidth, box_width); argNum++;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNlabel, TOGGLE_LBL_TXT); argNum++;
  XtSetArg(argList[argNum], XtNjustify, XtJustifyCenter); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, search); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, text); argNum++;

  label = XtCreateManagedWidget(TOGGLE_LBL, labelWidgetClass, form,
				argList, argNum);

/* Create the toggle widget, which allows the user to select the search
 * direction.  The default direction is forward.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNtranslations, toggleTable); argNum++;
  XtSetArg(argList[argNum], XtNradioData, Forward); argNum++;
  XtSetArg(argList[argNum], XtNstate, True); argNum++;
  XtSetArg(argList[argNum], XtNwidth, box_width); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, search); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, label); argNum++;
  XtSetArg(argList[argNum], XtNlabel, FORWARD); argNum++;

  toggle = XtCreateManagedWidget(FOR_TOGGLE, toggleWidgetClass, form,
				 argList, argNum);
  XtAddCallback(toggle, XtNcallback, HelpToggleCallBack, (XtPointer)Backward);

  argNum = 0;
  XtSetArg(argList[argNum], XtNtranslations, toggleTable); argNum++;
  XtSetArg(argList[argNum], XtNradioData, Backward); argNum++;
  XtSetArg(argList[argNum], XtNradioGroup, toggle); argNum++;
  XtSetArg(argList[argNum], XtNwidth, box_width); argNum++;
  XtSetArg(argList[argNum], XtNvertDistance, 0); argNum++;  
  XtSetArg(argList[argNum], XtNfromHoriz, search); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, toggle); argNum++;
  XtSetArg(argList[argNum], XtNlabel, BACKWARD); argNum++;

  toggle = XtCreateManagedWidget(BACK_TOGGLE, toggleWidgetClass, form,
				 argList, argNum);
  XtAddCallback(toggle, XtNcallback, HelpToggleCallBack, (XtPointer)Forward);

/* Create the quit button, which will un-pop (sigh...) the help shell */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, box_width); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, text); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, label); argNum++;
  XtSetArg(argList[argNum], XtNlabel, "Quit"); argNum++;

  quit = XtCreateManagedWidget(HELP_QUIT, commandWidgetClass, form,
			     argList, argNum);
  XtAddCallback(quit, XtNcallback, HelpQuitCallBack, popup);

/* Realize the popup shell, so that initial popup will be swift */

  XtRealizeWidget(popup);

  return(popup);
}

/* Initialize and position the widgets */

void InitWidgets(context, dialog_tbl, app_shell, size_hints, font_info,
		 input_files, input_dir, output_dir)
  XtAppContext context;
  XtTranslations dialog_tbl;
  Widget app_shell;
  XSizeHints size_hints;
  XFontStruct *font_info;
  char *input_files;
  char *input_dir, *output_dir;
{ 
  int i, digit_width;
  Widget in_dir, out_dir, out_file, view, w, w1, form, value,
    label, list, in_file, in_type_view, text, toggle;
  Widget help_popup;
  int sizeList[NUM_CHILDREN][2];
  Dimension parentWidth, parentHeight, pageWidth, pageHeight;
  Dimension boxWidth, boxHeight, width, box_size;
  XrmValue xrm_value;
  int offset, spacing;
  char *str_type[ST_SIZE];           /* Strings describing resource types */

/* Calculate Widget sizes */

  parentWidth = size_hints.width;
  parentHeight = size_hints.height;
  boxWidth = parentWidth/2 - (INNER_BORDER * 2);
  boxHeight = (font_info->ascent + font_info->descent + VERT_SEP * 2);

/* Parse the translation table for the toggle buttons.  This table implements
 * a strict "one-of-many" rule for the toggles.  One button is always 
 * activated.
 */

  toggleTable = XtParseTranslationTable(toggleActions);

/* Parse the dialog box translation table */

  dialogTable = XtParseTranslationTable(dialogActions);

/* Register the new actions with the translation manager. */

  XtAppAddActions(context, actionTable, NUM_ACTIONS);

/* Width of sub-widgets */

  width =  parentWidth/2 - (INNER_BORDER*2);

/* Construct the input type list. */

   for (i=0; i<NUM_TYPES; i++)
     inputTypes[i] = FileTypeMap[i].str;
   inputTypes[i] = NULL;

/* Create the top-level Form widget that contains the more interesting widgets.
 * The Form is the size of the entire application window.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNx, 0); argNum++;
  XtSetArg(argList[argNum], XtNy, 0); argNum++;
  XtSetArg(argList[argNum], XtNwidth, parentWidth); argNum++;
  XtSetArg(argList[argNum], XtNheight, parentHeight); argNum++; 
  XtSetArg(argList[argNum], XtNdefaultDistance, INNER_BORDER); argNum++;

  form = XtCreateManagedWidget(TOP_FORM, formWidgetClass, app_shell,
			       argList, argNum);

/* Application Label */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, width*2+INNER_BORDER); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++; 
  XtSetArg(argList[argNum], XtNlabel, VERSION); argNum++;
  XtSetArg(argList[argNum], XtNjustify, XtJustifyCenter); argNum++;

  label = XtCreateManagedWidget(APP_LBL, labelWidgetClass, form,
				argList, argNum);

/* A message window spanning the width of the application appears at the top
 * of the form.  A NULL translation table prevents users from typing in this
 * window.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, width*2+INNER_BORDER); argNum++;
  XtSetArg(argList[argNum], XtNtranslations, NULL); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, label); argNum++;
  XtSetArg(argList[argNum], XtNvertDistance, 0); argNum++;
  XtSetArg(argList[argNum], XtNeditType, XawtextRead); argNum++;
  XtSetArg(argList[argNum], XtNdisplayCaret, False); argNum++;
  XtSetArg(argList[argNum], XtNtype, XawAsciiString); argNum++;
  XtSetArg(argList[argNum], XtNstring, WELCOME); argNum++;
  XtSetArg(argList[argNum], XtNinsertPosition, strlen(WELCOME)); argNum++;
  XtSetArg(argList[argNum], XtNscrollVertical, XawtextScrollAlways); argNum++;
  XtSetArg(argList[argNum], XtNscrollHorizontal,
	   XawtextScrollWhenNeeded); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight*4); argNum++; 

  MsgOut = XtCreateManagedWidget(MSG_BOX, asciiTextWidgetClass, form,
				 argList, argNum);

/* The dialog box for the input directory. Horizontally center the dialog box 
 * in the left half of the form.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNlabel, INPUT_DIR); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, MsgOut); argNum++;
  XtSetArg(argList[argNum], XtNvalue, input_dir); argNum++;

  in_dir = XtCreateManagedWidget(FROM_BOX, dialogWidgetClass, form,
				 argList, argNum);

  InitDialog(in_dir, boxWidth, boxHeight, strlen(input_dir));

/* The label for the viewport.  This is a read-only widget.  The text is
 * centered within the widget.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, width); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++; 
  XtSetArg(argList[argNum], XtNlabel, INPUT_FILES); argNum++;
  XtSetArg(argList[argNum], XtNjustify, XtJustifyCenter); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, in_dir); argNum++;

  label = XtCreateManagedWidget(VIEW_LBL, labelWidgetClass, form,
				argList, argNum);

/* Create the viewport that displays the files in the current directory.  
 * Force it to always display scrollbars.  Center it.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, width); argNum++;
  XtSetArg(argList[argNum], XtNallowHoriz, True); argNum++;
  XtSetArg(argList[argNum], XtNallowVert, True); argNum++;
  XtSetArg(argList[argNum], XtNforceBars, True); argNum++;
  XtSetArg(argList[argNum], XtNheight,
	   parentHeight-5*INNER_BORDER-10*boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, label); argNum++;
  XtSetArg(argList[argNum], XtNvertDistance, 0); argNum++;

  view = XtCreateManagedWidget(VIEWPORT, viewportWidgetClass, form,
			       argList, argNum);

/* The dialog box for the output directory.  Center the box in the right
 * half of the form.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, MsgOut); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNlabel, OUTPUT_DIR); argNum++;
  XtSetArg(argList[argNum], XtNvalue, output_dir); argNum++;

  out_dir = XtCreateManagedWidget(TO_BOX, dialogWidgetClass, form,
				  argList, argNum);

  InitDialog(out_dir, boxWidth, boxHeight, strlen(output_dir));

/* The dialog box for the input file name */

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, out_dir); argNum++;
  XtSetArg(argList[argNum], XtNlabel, INPUT_FILE); argNum++;
  XtSetArg(argList[argNum], XtNvalue, ""); argNum++;

  in_file = XtCreateManagedWidget(IN_FILE, dialogWidgetClass, form,
				  argList, argNum);

  InitDialog(in_file, boxWidth, boxHeight, 0);

/* The viewport is responsible for scrolling a list widget.  Don't put a
 * border around this widget, otherwise it will look too ugly.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNlist, input_files); argNum++; 
  XtSetArg(argList[argNum], XtNdefaultColumns, 1); argNum++;
  XtSetArg(argList[argNum], XtNforceColumns, True); argNum++;

  list = XtCreateManagedWidget(VIEW_LST, listWidgetClass, view,
			       argList, argNum);

  XtAddCallback(list, XtNcallback, FileListCallBack, in_file);

/* The label for the input file type viewport.  This is a read-only widget. 
 * The text is centered within the widget.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, width); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNlabel, INPUT_TYPE); argNum++;
  XtSetArg(argList[argNum], XtNjustify, XtJustifyCenter); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, view); argNum++;

  label = XtCreateManagedWidget(IN_TYPE_LBL, labelWidgetClass, form,
				argList, argNum);

/* Create the viewport that displays the possible types of the input files in 
 * the current directory.  Force it to always display scrollbars.  Center it.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, width); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight*2+INNER_BORDER); argNum++;
  XtSetArg(argList[argNum], XtNallowHoriz, True); argNum++;
  XtSetArg(argList[argNum], XtNallowVert, True); argNum++;
  XtSetArg(argList[argNum], XtNforceBars, True); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, label); argNum++;
  XtSetArg(argList[argNum], XtNvertDistance, 0); argNum++;

  in_type_view = XtCreateManagedWidget(IN_TYPE_PORT, viewportWidgetClass, form,
				       argList, argNum);

/* The input file type widget.  A scrollable list widget. */

  argNum = 0;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNlist, inputTypes); argNum++; 

  list = XtCreateManagedWidget(IN_TYPE_LST, listWidgetClass, in_type_view,
			       argList, argNum);

  XtAddCallback(list, XtNcallback, FileTypeCallBack, FALSE);

/* The dialog box for the output file name */

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, in_file); argNum++;
  XtSetArg(argList[argNum], XtNlabel, OUTPUT_FILE); argNum++;
  XtSetArg(argList[argNum], XtNvalue, "file.hdf"); argNum++;

  out_file = XtCreateManagedWidget(OUT_FILE, dialogWidgetClass, form,
				   argList, argNum);

/* Get a pointer to the text field */

  text = XtNameToWidget(out_file, "value");

/* The label for the compress HDF toggle.  This is a read-only widget. 
 * The text is left-justified within the widget.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNresizable, True); argNum++;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNlabel, COMPRESS_LBL_TXT); argNum++;
  XtSetArg(argList[argNum], XtNjustify, XtJustifyLeft); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, text); argNum++;

  label = XtCreateManagedWidget(COMPRESS_LBL, labelWidgetClass, out_file,
				argList, argNum);

/* Create the toggle widget, which allows the user to select between compressed
 * and uncompressed storage for HDF files.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNdefaultDistance, &spacing); argNum++;
  XtGetValues(out_file, argList, argNum);

  width = XTextWidth(font_info, COMPRESS_LBL_TXT, strlen(COMPRESS_LBL_TXT)) +
    XTextWidth(font_info, "Yes", 3) + XTextWidth(font_info, "No", 2) +
    spacing*7 + BORDER_WIDTH*2 ;

  argNum = 0;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNresizable, True); argNum++;
  XtSetArg(argList[argNum], XtNtranslations, toggleTable); argNum++;
  XtSetArg(argList[argNum], XtNradioData, TRUE); argNum++;
  XtSetArg(argList[argNum], XtNstate, True); argNum++;
/*  XtSetArg(argList[argNum], XtNhorizDistance, boxWidth-width); argNum++; */
  XtSetArg(argList[argNum], XtNfromHoriz, label); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, text); argNum++;
  XtSetArg(argList[argNum], XtNlabel, "No"); argNum++;

  toggle = XtCreateManagedWidget(COMP_NO_TOGGLE, toggleWidgetClass, out_file,
				 argList, argNum);

  XtAddCallback(toggle, XtNcallback, CompressYesNoCallBack, (XtPointer)FALSE);

  argNum = 0;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++; 
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++; 
  XtSetArg(argList[argNum], XtNresizable, True); argNum++;
  XtSetArg(argList[argNum], XtNtranslations, toggleTable); argNum++;
  XtSetArg(argList[argNum], XtNradioData, False); argNum++;
  XtSetArg(argList[argNum], XtNradioGroup, toggle); argNum++;
  XtSetArg(argList[argNum], XtNhorizDistance, 0); argNum++;  
  XtSetArg(argList[argNum], XtNfromHoriz, toggle); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, text); argNum++;
  XtSetArg(argList[argNum], XtNlabel, "Yes"); argNum++;

  toggle = XtCreateManagedWidget(COMP_YES_TOGGLE, toggleWidgetClass, out_file,
				 argList, argNum);
  XtAddCallback(toggle, XtNcallback, CompressYesNoCallBack, (XtPointer)TRUE);

  InitDialog(out_file, boxWidth, boxHeight, 8);

/* Create the dimension dialog box, which is not mapped until needed.  For
 * example, the raw data type needs it to specify the size of the image
 * being read. First create the form that will contain the two dialog boxes.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNmappedWhenManaged, False); argNum++;
/*  XtSetArg(argList[argNum], XtNwidth, boxWidth-(spacing*2)); argNum++; 
  XtSetArg(argList[argNum], XtNheight, boxHeight*3); argNum++; */
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, out_file); argNum++;

  dimForm = XtCreateManagedWidget(DIM_FORM, formWidgetClass, form,
				  argList, argNum);

  argNum = 0;
  XtSetArg(argList[argNum], XtNdefaultDistance, &spacing); argNum++;
  XtGetValues(dimForm, argList, argNum);

/* Create a label for the form */

  argNum = 0;
/*  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
*/  XtSetArg(argList[argNum], XtNresizable, True); argNum++;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNwidth, boxWidth-(spacing*2)); argNum++;
  XtSetArg(argList[argNum], XtNlabel, DIM_BOX_LBL); argNum++;
  XtSetArg(argList[argNum], XtNjustify, XtJustifyCenter); argNum++;

  label = XtCreateManagedWidget(DIM_LABEL, labelWidgetClass, dimForm,
				argList, argNum);

/* OK, create the width dialog box */

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, label); argNum++;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNlabel, WIDTH_LBL); argNum++;
  XtSetArg(argList[argNum], XtNvalue, "0"); argNum++;

  dimWidth = XtCreateManagedWidget(DIM_WIDTH, dialogWidgetClass, dimForm,
				    argList, argNum);

/* Move the value field so that it is to the right of the label field instead
 * of below it.  Set it to a good height too.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNdefaultDistance, &spacing); argNum++;
  XtGetValues(dimWidth, argList, argNum);

  label = XtNameToWidget(dimWidth, "label");
  text = XtNameToWidget(dimWidth, "value");

  digit_width = XTextWidth(font_info, "X", 1);

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, NULL); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, label); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNwidth, digit_width * 5); argNum++;
  XtSetArg(argList[argNum], XtNinsertPosition, 1); argNum++;
  XtSetArg(argList[argNum], XtNresizable, False); argNum++;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNtranslations, dialogTable); argNum++;
  XtSetValues(text, argList, argNum);

  XtAddEventHandler(text, KeyPressMask, False, ScrollDialogText,
		    digit_width * 5);

  argNum = 0;
  XtSetArg(argList[argNum], XtNhorizDistance, spacing + digit_width); argNum++;
  XtSetArg(argList[argNum], XtNresizable, False); argNum++;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetValues(label, argList, argNum);

/* Now the height dialog box */

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, dimWidth); argNum++;
  XtSetArg(argList[argNum], XtNborderWidth, 0); argNum++;
  XtSetArg(argList[argNum], XtNlabel, HEIGHT_LBL); argNum++;
  XtSetArg(argList[argNum], XtNvalue, "0"); argNum++;

  dimHeight = XtCreateManagedWidget(DIM_HEIGHT, dialogWidgetClass, dimForm,
				     argList, argNum);

/* Move the value field so that it is to the right of the label field instead
 * of below it.
 */

  label = XtNameToWidget(dimHeight, "label");
  text = XtNameToWidget(dimHeight, "value");

  argNum = 0;
  XtSetArg(argList[argNum], XtNfromVert, NULL); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, label); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNwidth, digit_width * 5); argNum++;
  XtSetArg(argList[argNum], XtNinsertPosition, 1); argNum++;
  XtSetArg(argList[argNum], XtNresizable, False); argNum++;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNtranslations, dialogTable); argNum++;
  XtSetValues(text, argList, argNum);

  XtAddEventHandler(text, KeyPressMask, False, ScrollDialogText,
		    digit_width * 5);

  argNum = 0;
  XtSetArg(argList[argNum], XtNresizable, False); argNum++;
  XtSetArg(argList[argNum], XtNright, XtChainLeft); argNum++;
  XtSetArg(argList[argNum], XtNleft, XtChainLeft); argNum++;
  XtSetValues(label, argList, argNum);

/* Now create the convert and help buttons */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, boxWidth); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, dimForm); argNum++;
  XtSetArg(argList[argNum], XtNlabel, "Convert"); argNum++;

  w = XtCreateManagedWidget(CVT_BTTN, commandWidgetClass, form,
			    argList, argNum);
  XtAddCallback(w, XtNcallback, ConvertCallBack, NULL);

/* The help button is bound to a popup shell that contains a scrollable 
 * text widget.  The contents of the help file are displayed in that text
 * widget. Create the help popup widget tree. 
 */

  help_popup = InitHelpPopup(boxWidth, boxHeight, font_info, app_shell);

/* The help button.  Note that the client data passed to the call back is the
 * pointer to the popup shell.  The callback procedure relies on this remaining
 * true.  The other alternative would have been to make the help popup shell
 * a global variable.
 */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, boxWidth); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, w); argNum++;
  XtSetArg(argList[argNum], XtNlabel, "Help Me!"); argNum++;

  w = XtCreateManagedWidget(HLP_BTTN, commandWidgetClass, form,
			    argList, argNum);
  XtAddCallback(w, XtNcallback, HelpCallBack, help_popup);

/* And the quit button */

  argNum = 0;
  XtSetArg(argList[argNum], XtNwidth, boxWidth); argNum++;
  XtSetArg(argList[argNum], XtNheight, boxHeight); argNum++;
  XtSetArg(argList[argNum], XtNfromHoriz, view); argNum++;
  XtSetArg(argList[argNum], XtNfromVert, w); argNum++;
  XtSetArg(argList[argNum], XtNlabel, "Quit"); argNum++;

  w = XtCreateManagedWidget(QUIT_BTTN, commandWidgetClass, form,
			     argList, argNum);
  XtAddCallback(w, XtNcallback, QuitCallBack, context);

/* Realize the widget tree, so that all widgets are allocated visual space. */

  XtRealizeWidget(app_shell);
}


