      /********************************************************/
      /*                   Widget-Builder               (1)   */
      /* This program was written by Brian R. Gardner, 1988.  */
      /* It was created as a visual, easy to use, technique   */
      /* for rapid proto-typing of user interfaces. It allows */
      /* its user to design the layout of an X-window based   */
      /* user interface, complete with sub-windows, buttons,  */
      /* labels, and other "widgets". This program will also  */
      /* serve as a programmer's aid by writing out to a file */
      /* the source code required to re-generate the created  */
      /* visual user interface. The code generated is usually */
      /* substantial, reflecting immense savings in the time  */
      /* neccessary to program using X-windows.               */
      /*    Note that this program is only a simple test      */
      /* version. It was the author's first introduction to   */
      /* the Athena environment, as well as X-windows and the */
      /*  X-Toolkit. It was written in 2 weeks.               */
      /*    This was written under the roof of Project Athena */
      /* at Massachusetts Institute of Technology, by         */
      /* Brian Gardner (DEC), and hence reasonably available. */
      /* Read that as "FREE"         :-)                      */
      /* with the usual friendly restrictions.                */
      /********************************************************/

     /************************************************************/
     /* Copyright 1988, Massachusetts Institute of Technology.   */
     /* See X(1) for a full statement of rights and permissions. */
     /************************************************************/

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>  /* include all the intrinsic headers */
                            /* includes XToolkit defenitions     */
#include <X11/IntrinsicP.h> /* ditto */
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h> /* allows cursor change when window is entered */
#include <X11/VPaned.h>     /* include vPaned widget class header files */
#include <X11/Box.h>        /* include box widget class header files */
#include <X11/Dialog.h>     /* include dialog widget class header files */
#include <X11/Composite.h>  /* include composite widget class header files */
#include <X11/Scroll.h>  /* include scrollbar widget class header files */
#include <X11/Command.h>    /* include command widget class header files */
#include <X11/Text.h>       /* include text widget class header files */
#include <X11/Form.h>       /* not only includes the Form widget defs */
                            /* but also the constraint defs           */
#include <X11/Label.h>      /* header if I want to use a Label widget later */
#include <X11/StringDefs.h> /* string definitions for things like "XtNwidth" */

#include <X11/Xresource.h>
#include <X11/Shell.h>
#include <X11/AsciiText.h>  /* for asciiStringWidgetClass widgets */

#define MAX_DOCUMENTATION_LINE_LENGTH 65
#define WBFONTWIDTH 8
#define WBFONTHEIGHT 10 

/* Useful global variables */
/* ----------------------- */

extern struct widgetusage widgetsUsed; /* flags what types of widgets in use */
Widget WBMarkedShell;                  /* most recent popup edit shell */
Widget WBMarkedWidget;                 /* widget marked for editing    */
static char WBMarkedWidgetType[50];    /* marked widget's type         */
static char WBMarkedWidgetOption[150];    /* resource to change on widget */

static Widget userArea;
static Widget documentation_line_widget; /* used to display useful msgs */
static char documentation_string[MAX_DOCUMENTATION_LINE_LENGTH + 1];
static int WBgensymValue = 0;
Widget filename_widget[2];  /* dialog widget to get filename to save C code */
static int filename_not_done = TRUE;   /* used by dialogbox to get filename */

Display *the_display;                     /* the display for this run */
XEvent the_event;                         /* used for XSendEvent()    */
Cursor the_cursor;                        /* Cursor used to point     */
XFontStruct *timesRoman12, *timesBold12;  /* font structures needed   */
XFontStruct *timesRoman14, *timesBold14;  /* font structures needed   */
XFontStruct *fixedFont;

static Arg arg_list[30];

static Arg widget_builder_label_arg_list[] = {
  /* Label related instance variables, about appearance */
  { XtNborderWidth, (XtArgVal) 1},
  { XtNjustify, (XtArgVal) XtJustifyCenter},
  { XtNlabel, (XtArgVal)
     "                          Widget Builder                         "},
  { XtNresizable, TRUE},
  { XtNleft, (XtArgVal) XtChainLeft},
  { XtNtop, (XtArgVal) XtChainTop},
  { XtNright, (XtArgVal) XtChainRight},
  { XtNwidth, (XtArgVal) 400},
  { NULL, NULL}
 };

static Arg userArea_arg_list[] = {
  /* Form related instance variables, about appearance */
  { XtNborderWidth, (XtArgVal) 1},      /* normal */
  { XtNdefaultDistance, (XtArgVal) 4},  /* normal */
/*  { XtNheight, (XtArgVal) 300},
  { XtNwidth, (XtArgVal) 400}, */
  { XtNx, (XtArgVal) NULL},
  { XtNy, (XtArgVal) NULL},
  { XtNresizable, TRUE},
  { NULL, NULL}
 };

static Arg box_args[] = {
  { XtNhSpace, (XtArgVal)0},
  { XtNvSpace, (XtArgVal)0},
  { XtNminWidth,  (XtArgVal) 400},
  { XtNminHeight,  (XtArgVal) 300},
  { XtNresizable, TRUE},
  { XtNallowShellResize, TRUE},
  { NULL, NULL}
 };

static Arg widget_builder_doc_arg_list[] = {
  /* Label related instance variables, about appearance */
  { XtNborderWidth, (XtArgVal) 1},
  { XtNjustify, (XtArgVal) XtJustifyCenter},
  { XtNresizable, TRUE},
  { XtNleft, (XtArgVal) XtChainLeft},
  { XtNright, (XtArgVal) XtChainRight},
  { XtNbottom, (XtArgVal) XtChainBottom},
  { XtNwidth, (XtArgVal) 400},
  { NULL, NULL}
 };

/* Include file for saving the C code necessary to regenerate all widgets */
/* ---------------------------------------------------------------------- */
#include "wbsaveccode.c"
#include "button_menu.c"

/* Basic Function Options */
/*----------------------- */

#define WBAddCommandButton   "Add Command Button        "
#define WBAddLabel           "Add Label                 "
#define WBAddBlankLine       "Add a Blank Line          "
#define WBAddKeyedMailField  "Add Keyed Mail Field      "
#define WBAddBlankMailField  "Add Blank Mail Field      "
#define WBResizeWorkingArea  "Resize Working Area       "
#define WBSaveAsCCode        "Save as C code into a file"
#define WBSaveAsCCodeOp      "Save as C code (Optimized)"
#define WBQuit               "          Quit            "

static String widget_builder_options[] = {
    WBAddCommandButton,
    WBAddLabel,
    WBAddBlankLine,
    WBAddKeyedMailField,
/*    WBAddBlankMailField,
      WBResizeWorkingArea, */
    WBQuit,
    NULL
    };

/*  WBSaveAsCCode and WBSaveAsCCodeOp options are added to above in main() */

/* Command Button Widget Options */
/* ----------------------------- */
#define WBDestroyButtonWidget  "   Destroy Button Widget   "

struct button_widget_struct {
    char *label;
    int   height;
    int   width;
    int   borderWidth;
    };

/* Initialization Values for a Command Button Widget */
static Arg button_arg_list[] = {
  /* Command Button related instance variables, about appearance */
  { XtNfont, NULL},
  { XtNborderWidth, (XtArgVal) 1},
  { XtNjustify, (XtArgVal) XtJustifyCenter},
  { XtNresizable, TRUE},
  { XtNlabel, (XtArgVal) "Unlabelled Button"},
  { NULL, NULL}
 };

/* Label Widget Options */
/* -------------------- */
#define WBDestroyLabelWidget   "     Destroy Label Widget   "

/* Initialization Values for a Label Widget */
static Arg label_arg_list[] = {
  /* Form related instance variables, about placement */
  { XtNvertDistance, (XtArgVal) 4},
  { XtNhorizDistance, (XtArgVal) 4},
  { XtNtop, (XtArgVal) XtRubber},
  { XtNleft, (XtArgVal) XtChainLeft},
  { XtNright, (XtArgVal) XtChainRight},
  { XtNbottom, (XtArgVal) XtRubber},
  { XtNresizable, (XtArgVal) TRUE},
  { XtNfromHoriz, NULL},  
  { XtNfromVert, NULL},
  /* Label related instance variables, about appearance */
  { XtNborderWidth, (XtArgVal) 0},
  { XtNjustify, (XtArgVal) XtJustifyCenter},
  { XtNlabel, (XtArgVal) "Null Label"},
  { NULL, NULL}
 };

/* Blank Line Widget Options */
/* ------------------------- */
#define WBDestroyBlankLineWidget  "  Destroy Blank Line Widget "

/* Initialization Values for a Blank Line Widget */
static Arg blank_line_arg_list[] = {
  /* Form related instance variables, about placement */
  { XtNvertDistance, (XtArgVal) 4},
  { XtNhorizDistance, (XtArgVal) 4},
  { XtNtop, (XtArgVal) XtRubber},
  { XtNleft, (XtArgVal) XtChainLeft},
  { XtNright, (XtArgVal) XtChainRight},
  { XtNbottom, (XtArgVal) XtRubber},
  { XtNresizable, (XtArgVal) TRUE},
  { XtNfromHoriz, NULL},  
  { XtNfromVert, NULL},
  /* Label related instance variables, about appearance */
  { XtNborderWidth, (XtArgVal) 0},
  { XtNjustify, (XtArgVal) XtJustifyCenter},
  { XtNlabel, (XtArgVal) "                                                "},
  { NULL, NULL}
 };

/****************************************************************/

char *gensym()
 {
   char *str;
   int places;
   float n;

   /* Generate a unique symbol (string) for internal Widget Builder use */
   /* ----------------------------------------------------------------- */
   n = WBgensymValue + 1;
   for (places = 1; n > 1; places++)
     n = n / 10.0;
   /* Generate a unique widget name */
   str = (char *) calloc((strlen("WBwidget") + places + 2), 1);
   sprintf(str, "WBwidget%d", WBgensymValue++);
   return(str);

 };       /* end of gensym() */

/****************************************************************/

void documentation_line(msg)
     char *msg;
 { 
   extern Widget documentation_line_widget;
   int i;

   /* Display a line of documentation at the bottom */
   /* of the Widget Builder window                  */
   /* --------------------------------------------- */
   strcpy(documentation_string, msg);
   for (i = strlen(msg); i < MAX_DOCUMENTATION_LINE_LENGTH; i++)
     documentation_string[i] = ' ';
   documentation_string[MAX_DOCUMENTATION_LINE_LENGTH] = '\0';
   XtSetArg(arg_list[0], XtNlabel, documentation_string);
   XtSetValues(documentation_line_widget, arg_list, 1);

 };         /* end of documentation_line() */

/****************************************************************/

Widget make_edit_menu(parent_widget, grandparent_widget, options, type)
     Widget parent_widget;
     Widget grandparent_widget;
     char *options[];       /* the list of options for the popup menu */
     char type[];           /* "button", "scrollbar", etc.            */
 {
   Widget edit_shell;  /* the Override Shell that holds button editor */
   Widget edit_menu;   /* the background box for button editor menu   */
   Widget widget;
   Widget menu_label;
   char *shell_name;       /* a unique shell name for this popup menu */
   char *str;
   int i;

   /* Create the popup edit menu for a widget */
   /* ---------------------------------------------- */
   shell_name = (char *) gensym();
   edit_shell = XtCreatePopupShell(shell_name,
			  overrideShellWidgetClass,
			  grandparent_widget,
			  NULL, 0);
   edit_menu = 
	   XtCreateManagedWidget((char *) gensym(),
		       boxWidgetClass,
   		       edit_shell,
		       NULL, 0);
   /* Force edit_menu to popdown when button is let up */
   /* XtAugmentTranslations(edit_shell, */
   XtOverrideTranslations(edit_shell, 
			 XtParseTranslationTable(
			  "<Btn1Down>,<Btn1Up>:MenuPopdown()"));

   /* Link new popup edit menu to parent_widget */
   /* ----------------------------------------- */
   /* alloc space for translation table string  */
   str = (char *) calloc((strlen(shell_name) + strlen(type) 
	        + strlen("<Btn1Down>: MarkWidget(\"\") MenuPopup(\"\")")
/* 		+ strlen(" pushshell(\"\")") + 10 */
		+ 1 + 10) , 1);  
   /* make translation table string */
   sprintf(str,
	   "<Btn1Down>: MarkWidget(\"%s\",\"%d\") MenuPopup(\"%s\")",
	   type, (int) edit_shell, shell_name);    
   XtOverrideTranslations(parent_widget, 
   /* XtAugmentTranslations(parent_widget, */
			  XtParseTranslationTable(str));

   /* Place a sensible Label ontop of the popup edit menu */
   /* ------------------------------------------------------ */
   str = (char *) calloc((strlen(type) + 20), 1);
   sprintf(str, "   %s options   ", type);
   arg_list[0].name = XtNlabel;
   arg_list[0].value = (XtArgVal) str;
   menu_label = XtCreateManagedWidget((char *) gensym(),
			       labelWidgetClass, edit_menu,
			       arg_list, 1);
   inverseVideo(menu_label);    /* Highlight the label */

/*			       widget_builder_label_arg_list,
			       XtNumber(widget_builder_label_arg_list)); 
   XtSetValues(menu_label, arg_list, 3); */

   for (i=0; options[i] != NULL; i++)
     {
       /* add an option to popup menu */
       /* --------------------------- */
       arg_list[0].name = XtNlabel;         /* label for the option button */
       arg_list[0].value = (XtArgVal) options[i]; 

       /* Create the Option Button */
       widget =
	   XtCreateManagedWidget((char *) gensym(),
		       commandWidgetClass,
   		       edit_menu,
		       arg_list, 1);

       /* make the button widget editable via a popup menu button editor */
       str = (char *) calloc((strlen(options[i]) + 28), 1);
       sprintf(str,
         "<Btn1Down>: EditWidget(\"%s\")", options[i]);
       /* XtAugmentTranslations(widget, */
       XtOverrideTranslations(widget, 
			      XtParseTranslationTable(str));
     };

   return(edit_menu);
 };         /* end of make_edit_menu() */

/****************************************************************/

Widget make_editable_mail_field(parent_widget)
     Widget parent_widget;
     {
       Widget mail_widget;
       Widget keyWidget;
       Widget valueWidget;
       char *key_string;
       char *val_string;
       int val_string_length;
       Widget make_editable_label();

       /* Create a Mail-Field widget */
       /* -------------------------- */
       arg_list[0].name = XtNborderWidth;
       arg_list[0].value = (XtArgVal) 1;
       arg_list[1].name = XtNleft;
       arg_list[1].value = (XtArgVal) XtChainLeft;
       arg_list[2].name = XtNright;
       arg_list[2].value = (XtArgVal) XtChainRight;
       arg_list[3].name = XtNwidth;
       arg_list[3].value = (XtArgVal) 400;
       arg_list[4].name = XtNwidth;
       arg_list[4].value = (XtArgVal) 20;
       arg_list[5].name = XtNresizable;
       arg_list[5].value = (XtArgVal) TRUE;
       mail_widget = XtCreateWidget((char *) gensym(),
			       formWidgetClass, 
			       parent_widget,
			       arg_list, 6);
       /* Add this widget to database, before creating any children */
       add_widget_node(mail_widget, parent_widget, "form");

       /* Create the Keyword field  as a label widget */
       /* ------------------------------------------- */
       keyWidget = make_editable_label(mail_widget);

       /* Create input Value field as an AsciiText widget */
       /* ----------------------------------------------- */
       val_string_length = 70;
       val_string = (char *) calloc((val_string_length + 1), 1);
       XtSetArg(arg_list[0], XtNeditType, XttextEdit);
       XtSetArg(arg_list[1], XtNstring, val_string);
       XtSetArg(arg_list[2], XtNfromHoriz, keyWidget);
       XtSetArg(arg_list[3], XtNlength, (val_string_length * WBFONTWIDTH));
       XtSetArg(arg_list[4], XtNtextOptions, 
		resizeHeight | resizeWidth); /* | editable); */
       XtSetArg(arg_list[5], XtNresizable, TRUE);
       valueWidget = XtCreateManagedWidget((char *) gensym(),
			       asciiStringWidgetClass, mail_widget,
			       arg_list, 6);

       /* Now allow the new widget to become managed (and realized) */
       XtManageChild(mail_widget);

       /* Add these widgets to the linked list of created widgets */
       /* ------------------------------------------------------- */
       (add_widget_node(valueWidget, mail_widget, "ascii text"))->string
	    = val_string;
       widgetsUsed.keyedMailField = TRUE;
       widgetsUsed.label = TRUE;
       widgetsUsed.text = TRUE;
       widgetsUsed.asciiText = TRUE;
       widgetsUsed.form = TRUE;

       return(mail_widget);

     };      /* end of make_editable_mail_field() */

/****************************************************************/

void edit_key_field(widget, event)
     Widget widget;
     XEvent *event;
 {
   char *str;
   int str_length;

   str_length = strlen(WBMarkedWidgetOption) + 1;
   str = (char *) calloc(str_length, 1);
   strcpy(str, WBMarkedWidgetOption);
   arg_list[0].name = XtNlabel;
   arg_list[0].value = (XtArgVal) str;
/*   arg_list[1].name = XtNlength;
   arg_list[1].value = (XtArgVal) str_length;  * WBFONTWIDTH; */
   XtSetValues(WBMarkedWidget, arg_list, 1);

 };           /* end of edit_key_field() */

/****************************************************************/

void edit_button(widget, event)
     Widget widget;
     XEvent *event;
 {
   char *str;
   WidgetNode *widget_node;

   /* Alter attributes of a button widget */
   /* ----------------------------------- */
   if (strcmp(WBMarkedWidgetOption, XtNlabel) == 0)     /* Change Label */
     { 
       str = (char *) calloc(11, 1);
       strcpy(str, "New Label");
       arg_list[0].name = XtNlabel;
       arg_list[0].value = (XtArgVal) str;
       XtSetValues(WBMarkedWidget, arg_list, 1);
     }
   else if (strcmp(WBMarkedWidgetOption,
		   XtNheight) == 0)                    /* Change Height */
     {
/*       arg_list[0].name = XtNheight;
       arg_list[0].value = (XtArgVal) 10;
       XtSetValues(WBMarkedWidget, arg_list, 1); */
     }
   else if (strcmp(WBMarkedWidgetOption,
		   XtNwidth) == 0)                     /* Change Width */
     {
/*       arg_list[0].name = XtNwidth;
       arg_list[0].value = (XtArgVal) 10;
       XtSetValues(WBMarkedWidget, arg_list, 1); */
     }
   else if (strcmp(WBMarkedWidgetOption,
		   XtNfont) == 0)                       /* Change Font   */
     {
       XtSetArg(arg_list[0], XtNfont, timesBold12);
       XtSetValues(WBMarkedWidget, arg_list, 1);
       widget_node = find_widgets_node(WBMarkedWidget);
       widget_node->font = "times-bold12";
       widget_node->font_struct = timesBold12;
     }
   else if (strcmp(WBMarkedWidgetOption,
		   XtNborderWidth) == 0)                /* Change Border */
     {
       arg_list[0].name = XtNborderWidth;
       arg_list[0].value = (XtArgVal) 10;
       XtSetValues(WBMarkedWidget, arg_list, 1);
     }
   else if (strcmp(WBMarkedWidgetOption,
		   WBDestroyButtonWidget) == 0)         /* Destroy Widget */
     {
       XtDestroyWidget(WBMarkedWidget);
     }
   else                                                 /* Ignore Others */
     ;

 };       /* end of edit_button() */

/****************************************************************/

void make_saveCcode_button(parent_widget, option, index)
     Widget parent_widget;
     char *option;
     int index;
 {
   Widget widget, edit_menu, edit_shell;
   Widget filename_button;
   String null_edit_options[1];
   char  *str, *shell_name;

   null_edit_options[0] = NULL;

   /* Create the WBSaveAsCCode(op) button widget */
   /* -------------------------------------- */
   XtSetArg(arg_list[0], XtNlabel, option);
   widget = XtCreateWidget(option,
                   commandWidgetClass,
   	           parent_widget, arg_list, 1);

   /* make the button widget editable via a popup menu button editor */
   /* this must be done before the new widget is realized (managed)  */
   /*--------------------------------------------------------------- */
   shell_name = (char *) gensym();
   edit_shell = XtCreatePopupShell(shell_name,
			  overrideShellWidgetClass,
			  parent_widget,
			  NULL, 0);
   edit_menu = 
	   XtCreateManagedWidget((char *) gensym(),
		       boxWidgetClass,
   		       edit_shell,
		       NULL, 0); 

   /* Force edit_menu to popdown when button is let up */
   XtOverrideTranslations(edit_shell, 
            XtParseTranslationTable(
		"<Btn1Up>: \n\
                 <Btn1Up>,<Btn1Down>,<Btn1Up>:MenuPopdown() WBPopdown()"));

   /* Link new popup edit menu to widget */
   /* ----------------------------------------- */
   /* alloc space for translation table string  */
   str = (char *) calloc((strlen(shell_name) + strlen("Widget Builder") 
	        + strlen("<Btn1Down>: MarkWidget(\"\") MenuPopup(\"\")")
		+ 1 + 10) , 1); 
   /* make translation table string */
   sprintf(str,
	   "<Btn1Down>: MarkWidget(\"%s\",\"%d\") MenuPopup(\"%s\")",
	   "Widget Builder", (int) edit_shell, shell_name);    
   XtOverrideTranslations(widget, 
			  XtParseTranslationTable(str));


   /* Now allow the new widget to become managed (and realized) */
   XtManageChild(widget);

   /* Create the dialog box which will get the filename for C code saving */
   XtSetArg(arg_list[0], XtNlabel, 
            "Enter Filename (full path) for output:");
   XtSetArg(arg_list[1], XtNvalue, "");
   XtSetArg(arg_list[2], XtNwidth, 100);

   filename_widget[index] = XtCreateManagedWidget("Enter Filename:",
				   dialogWidgetClass,
				   edit_menu, arg_list, 3);
   filename_button = XtCreateManagedWidget("Ready", commandWidgetClass,
		  filename_widget[index],
		  arg_list, 0);

   /* make the button widget editable via a popup menu button editor */
   str = (char *) calloc(((strlen(option) * 2) + 38), 1);
   sprintf(str, "<Btn1Down>: GotFilename(\"%s\") EditWidget(\"%s\")",
	   option, option);
   XtOverrideTranslations(filename_button,
			  XtParseTranslationTable(str));

     };       /* end of make_saveCcode_button()  */

/****************************************************************/

void make_saveCcode_buttons(parent_widget)
     Widget parent_widget;
 {
   make_saveCcode_button(parent_widget, WBSaveAsCCode, 0);
   make_saveCcode_button(parent_widget, WBSaveAsCCodeOp, 1);
 };          /* end of make_saveCcode_buttons()  */

/****************************************************************/

Widget make_editable_button(parent_widget)
     Widget parent_widget;
     {
       char *widget_name;
       Widget widget;

       /* Create a button widget */
       /* ---------------------- */
       widget_name = (char *) gensym();
       XtSetArg(button_arg_list[0], 
		 XtNfont, timesRoman12);
       widget = XtCreateWidget(widget_name,
		       commandWidgetClass,
   		       parent_widget, 
		       button_arg_list, XtNumber(button_arg_list));

       /* Set the cursor to made editable widgets stand-out */
       /* ------------------------------------------------- */
       XtSetArg(arg_list[0], XtNcursor, the_cursor);
       XtSetValues(widget, arg_list, 1);

       /* Add this widget to the linked list of created widgets */
       /* ----------------------------------------------------- */
       add_widget_node(widget, parent_widget, "button");
       widgetsUsed.button = TRUE;

       /* make the button widget editable via a popup menu button editor */
       /* this must be done before the new widget is realized (managed)  */
       /*--------------------------------------------------------------- */
       create_button_menu(create_empty_popupmenu(widget,
						 parent_widget, "button"),
			  widget);

       /* Now allow the new widget to become managed (and realized) */
       XtManageChild(widget);

       return(widget);

     };        /* end of  make_editable_button() */

/****************************************************************/

Widget make_editable_label(parent_widget)
     Widget parent_widget;
     {
       char *widget_name;
       Widget widget;

       /* Create a button widget */
       /* ---------------------- */
       widget_name = (char *) gensym();
       widget = XtCreateWidget(widget_name,
		       labelWidgetClass,
   		       parent_widget,
		       label_arg_list, XtNumber(label_arg_list));

       /* Set the cursor to made editable widgets stand-out */
       /* ------------------------------------------------- */
       XtSetArg(arg_list[0], XtNcursor, the_cursor);
       XtSetValues(widget, arg_list, 1);

       /* Add this widget to the linked list of created widgets */
       /* ----------------------------------------------------- */
       add_widget_node(widget, parent_widget, "label");
       widgetsUsed.label = TRUE;

       /* make the button widget editable via a popup menu button editor */
       /* this must be done before the new widget is realized (managed)  */
       /*--------------------------------------------------------------- */
       create_label_menu(create_empty_popupmenu(widget,
						 parent_widget, "label"),
			  widget);

       /* Now allow the new widget to become managed (and realized) */
       XtManageChild(widget);

       return(widget);

     };

/****************************************************************/

Widget make_editable_blank_line(parent_widget)
     Widget parent_widget;
     {
       char *widget_name;
       Widget widget;

       /* Create a button widget */
       /* ---------------------- */
       widget_name = (char *) gensym();
       widget = XtCreateWidget(widget_name,
		       labelWidgetClass,
   		       parent_widget,
		       blank_line_arg_list,
		       XtNumber(blank_line_arg_list));

       /* Set the cursor to made editable widgets stand-out */
       /* ------------------------------------------------- */
       XtSetArg(arg_list[0], XtNcursor, the_cursor);
       XtSetValues(widget, arg_list, 1);

       /* Add this widget to the linked list of created widgets */
       /* ----------------------------------------------------- */
       add_widget_node(widget, parent_widget, "blank line");
       widgetsUsed.blankLine = TRUE;

       /* make the button widget editable via a popup menu button editor */
       /* this must be done before the new widget is realized (managed)  */
       /*--------------------------------------------------------------- */
       create_blank_line_menu(create_empty_popupmenu(widget,
						 parent_widget, "blank line"),
			  widget);

       /* Now allow the new widget to become managed (and realized) */
       /* --------------------------------------------------------- */
       XtManageChild(widget);

       return(widget);

     };

/****************************************************************/

void edit_wb(widget, event)
     Widget widget;
     XEvent *event;
 {
   FILE *outfile, *fopen();
  
   printf(" DEBUG: >> Entering edit_wb()\n");    /* DEBUG */
   if (strcmp(WBMarkedWidgetOption,
	      WBAddCommandButton) == 0)     /* Add a Command Button */
       make_editable_button(userArea);
   else if (strcmp(WBMarkedWidgetOption,
		   WBAddLabel) == 0)        /* Add a Label Widget */
       make_editable_label(userArea);
   else if (strcmp(WBMarkedWidgetOption,
		   WBAddBlankLine) == 0)    /* Add a Blank Line Widget */
       make_editable_blank_line(userArea);
   else if (strcmp(WBMarkedWidgetOption,
	         WBAddKeyedMailField) == 0) /* Add a Keyed Mail Field */
       make_editable_mail_field(userArea);
   else if (strcmp(WBMarkedWidgetOption,
	         WBAddBlankMailField) == 0) /* Add a Blank Mail Field */
     ;
   else if (strcmp(WBMarkedWidgetOption,
	         WBResizeWorkingArea) == 0) /* Resize the User Area */
     ;
   else if (strcmp(WBMarkedWidgetOption,
		   "Ready") == 0)           /* User Entered Filename */
       filename_not_done = FALSE;   /* used by dialogbox to get filename */
   else if ((strcmp(WBMarkedWidgetOption,
		   WBSaveAsCCode) == 0)     /* Save as C code to file   */
	    OR
	    (strcmp(WBMarkedWidgetOption,
		    WBSaveAsCCodeOp) == 0)) /* Save as C code Optimized */
     {
       /* Set the optimizing flag for the routines that the write code */
       if (strcmp(WBMarkedWidgetOption,
		  WBSaveAsCCodeOp) == 0)
	 not_optimizing = FALSE;
       else
	 not_optimizing = TRUE;

       /* Open file and write out a C program that re-generates userArea */
       printf(" DEBUG: --   In edit_wb(): filename=\"%s\"\n",    /* DEBUG */
	      XtDialogGetValueString(                            /* DEBUG */
	       filename_widget[(not_optimizing == TRUE) ? 0 : 1])); /* DEBUG */

       if ((outfile = fopen(XtDialogGetValueString(
                            filename_widget[(not_optimizing == TRUE) ? 0 : 1]),
			   "w"))
	   == NULL)
         {
	   documentation_line("Error in filename. File not Saved.");
           XBell(the_display, 1); /* beep console just above base volume */
         }
       else
         {
	   write_headers(outfile);
           write_widgets(outfile);
	   write_main(outfile);
	   fclose(outfile);
	   documentation_line("C code successfully saved to file.");
	 };
     }
   else if (strcmp(WBMarkedWidgetOption,
		   WBQuit) == 0)            /* Exit Widget Builder Program */
     exit(0);
   else
    ;                                       /* Ignore Others */

   printf(" DEBUG: << Exiting edit_wb()\n");    /* DEBUG */

 };          /* end of edit_wb() */

/****************************************************************/

void GotFilename(widget, event, widget_option, num_strings)
     Widget widget;
     XEvent *event;
     String *widget_option;      /* array of 1 string, like "Ready" */
     Cardinal num_strings; /* number of strings in widget_option array */
 {
   printf(" DEBUG printf: Entering GotFilename()\n");
   filename_not_done = FALSE;   /* used by dialogbox to get filename */
   printf(" DEBUG printf: Entering GotFilename()\n");
 };        /* end of GotFilename()  */
/****************************************************************/

void WBPopdown(widget, event, widget_option, num_strings)
     Widget widget;
     XEvent *event;
     String *widget_option;      /* array of 1 string, like "Ready" */
     Cardinal num_strings; /* number of strings in widget_option array */
 {
   printf(" DEBUG printf: Entering WBPopdown()\n");
   XtPopdown(WBMarkedShell);
   printf(" DEBUG printf: Entering WBPopdown()\n");
 };        /* end of GotFilename()  */

/****************************************************************/

void MarkWidget(widget, event, myWidgetType, num_myWidgetTypes)
     Widget widget;
     XEvent *event;
     String *myWidgetType;       /* array of strings, like "button", etc    */
     Cardinal num_myWidgetTypes; /* number of strings in myWidgetType array */
 {
   XButtonEvent *buttonevent;
   Position rootx, rooty;
   int widget_ID;

   /* Store info in Global vars, for EditWidget to access on Popdown */
   /* -------------------------------------------------------------- */
   WBMarkedWidget = widget;                        /* set widget */
   strcpy(WBMarkedWidgetType, myWidgetType[0]);    /* set type   */

   /* Store x,y of future popup menu */
   /* ------------------------------ */
   buttonevent = (XButtonEvent *) event;
   XtTranslateCoords(widget, buttonevent->x, buttonevent->y,
		     &rootx, &rooty);

   /* Change the position of the popup about to reveal itself */
   /* ------------------------------------------------------- */
   sscanf(myWidgetType[1], "%d", &widget_ID);
   WBMarkedShell = (Widget) widget_ID;
   XtMoveWidget(WBMarkedShell, rootx, rooty);

 };         /* end of MarkWidget() */

/****************************************************************/

void EditWidget(widget, event, widget_option, num_myWidgetTypes)
     Widget widget;
     XEvent *event;
     String *widget_option;    /* array of 1 resource string, like XtNwidth */
     Cardinal num_myWidgetTypes; /* number of strings in myWidgetType array */
 {
   /* Store more info in a Global var, for edit_button to access */
   /* ---------------------------------------------------------- */
   strcpy(WBMarkedWidgetOption, widget_option[0]); /* set option */

   if (strcmp(WBMarkedWidgetType,"button") == 0)     /* button */
     edit_button(widget, event);
   else if (strcmp(WBMarkedWidgetType,
		   "Widget Builder") == 0)     /* Basic Functions */
       edit_wb(widget, event);
   else if (strcmp(WBMarkedWidgetType,
		   "key field") == 0)          /* Mail Field Keyword */
     edit_key_field(widget, event);
   else
     ;
 };         /* end of EditWidget() */

/****************************************************************/

 inverseVideo(widget)
     Widget widget;
 {
   Pixel foreground;
   Pixel background;
   Arg arg_list[2];

   /* Swap the Pixel coloring of the foreground and background */
   /* -------------------------------------------------------- */
   arg_list[0].name = XtNforeground;
   arg_list[0].value = (XtArgVal) &foreground;
   arg_list[1].name = XtNbackground;
   arg_list[1].value = (XtArgVal) &background;
   XtGetValues(widget, arg_list, 2);
   arg_list[0].name = XtNforeground;
   arg_list[0].value = (XtArgVal) background;
   arg_list[1].name = XtNbackground;
   arg_list[1].value = (XtArgVal) foreground;
   XtSetValues(widget, arg_list, 2);
 };        /* end of inverseVideo() */

/****************************************************************/

  /* Widget Action related globals */
  /* ----------------------------- */
XtActionsRec action_list[] = {
  {"EditWidget",    EditWidget},
  {"MarkWidget",    MarkWidget},
  {"GotFilename",   GotFilename},
  {"WBPopdown",     WBPopdown},
  { NULL, NULL}
  };

static int num_actions = 4;

/****************************************************************/
/****************************************************************/

main(argc, argv)
     int argc;
     char *argv[];
 { 
   Widget shell;
   Widget WBform;
   Widget box_label;          /* label for the Widget Builder main box */

   /* Set up new widget actions */
   /* ------------------------- */
   XtAddActions(action_list, num_actions);

   /* Initialize a toplevel root shell widget */
   /* --------------------------------------- */
   shell = XtInitialize(argv[0],
		       "Widget-Builder",
		       NULL, 0,
			&argc, argv);
   XtSetValues(shell, box_args, XtNumber(box_args));

   /* Load in necessary fonts */
   /* ----------------------- */
   the_display = XtDisplay(shell);     /* first get the display */
   timesRoman12 = XLoadQueryFont(the_display, "times-roman12");
   timesBold12 = XLoadQueryFont(the_display, "times-bold12");
   timesRoman14 = XLoadQueryFont(the_display, "times-roman14");
   timesBold14 = XLoadQueryFont(the_display, "times-bold14");
   fixedFont = XLoadQueryFont(the_display, "fixed");


   /* Set the cursor to make editable things easily visible */
   /* ----------------------------------------------------- */
   the_cursor = XCreateFontCursor(the_display, XC_hand2);

   /* Create main (background) widget for the Widget Builder */
   /* ------------------------------------------------------ */
   WBform = XtCreateManagedWidget("Widget Builder form",
			       boxWidgetClass, shell,
			       box_args, XtNumber(box_args));
   box_label = XtCreateManagedWidget("Widget Builder", 
			       labelWidgetClass, WBform,
			       widget_builder_label_arg_list,
			       XtNumber(widget_builder_label_arg_list));
   XtSetArg(arg_list[0], XtNcursor, the_cursor);
   XtSetValues(box_label, arg_list, 1);
   inverseVideo(box_label);    /* Highlight the Widget Builder label */

   /* Create user's work area */
   /* ----------------------- */
   userArea = XtCreateManagedWidget("WB User Area", boxWidgetClass, WBform,
			       userArea_arg_list,
			       XtNumber(userArea_arg_list));

   /* Place a widget a bottom of form to serve as a */
   /* display for useful documentation              */
   /* --------------------------------------------- */
   documentation_line_widget = XtCreateManagedWidget("Widget Builder", 
			       labelWidgetClass, WBform,
			       widget_builder_doc_arg_list,
			       XtNumber(widget_builder_doc_arg_list));
   documentation_line(
      " Mouse-L: Edit Widget.           Title-Bar: Add/Delete Widgets.  ");
   /* Highlight the Widget Builder label */
   inverseVideo(documentation_line_widget);    

   /* Position documentation line at bottom */
   /* ------------------------------------- */
   XtSetArg(arg_list[0], XtNfromVert, box_label);
   XtSetArg(arg_list[1], XtNvertDistance, 0);
   XtSetValues(userArea, arg_list, 2);
   XtSetArg(arg_list[0], XtNfromVert, userArea);
   XtSetArg(arg_list[1], XtNvertDistance, 0);
   XtSetValues(documentation_line_widget, arg_list, 2);

   /* Set up defaults for later. Used when saving C code to file. */
   /* Useful as an optimization hack.                             */
   /* ----------------------------------------------------------- */
   load_widget_defaults_from(userArea);
   not_optimizing = FALSE;

   /* Set flags for types of widgets used, applications shell & user area */
   widgetsUsed.shell = TRUE;
   widgetsUsed.box  = TRUE;

   /* Attach Basic Functions popup menu to the box_label */
   make_saveCcode_buttons(make_edit_menu(box_label, WBform, 
     		          widget_builder_options, "Widget Builder"));

   XtRealizeWidget(shell);

   XtMainLoop();

 };        /* end of main() */
