      /********************************************************/
      /*                   Widget-Builder               (2)   */
      /* 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 "editwidgetP.h"
#include "editwidget.h"

void done_button(widget, closure, call_data)
     Widget widget;
     caddr_t closure;
     caddr_t call_data;
 {
   struct marker_info *callback_info; /* callback info about what to change */
   WidgetNode *widget_node;           /* info about widget being changed    */
   char *val_string;                  /* string data from a menu widget     */
   char *set_string;                  /* new string data for edited widget  */

   callback_info = (struct marker_info *) closure;
   widget_node = callback_info->widget_node;

   /* If varName was edited, replace old string with copy of new one in menu */
   /* ---------------------------------------------------------------------- */
   val_string =  (callback_info->state)->varName_string;
   if (strcmp(val_string, (widget_node->varName)) != 0)  /* it was edited */
     { /* update variable name */
       widget_node->varName = val_string;
     };

   /* If name was edited, replace old string with copy of new one in menu */
   /* ------------------------------------------------------------------- */
   val_string =  (callback_info->state)->name_string;
   if (strcmp(val_string, (widget_node->name)) != 0)  /* it was edited */
     { /* update widget name */
       widget_node->name = val_string;
     };

   /* If label was edited, replace old string with copy of new one in menu */
   /* -------------------------------------------------------------------- */
   if ((strcmp(widget_node->type, "blank line") != 0)
       && (strcmp(widget_node->type, "video") != 0)
       && (strcmp(widget_node->type, "asciitext") != 0)
       && (strcmp(widget_node->type, "ascii text") != 0)
       && (strcmp(widget_node->type, "form") != 0))
     {     /* can't edit blank line */
       val_string =  (callback_info->state)->label_string;
       XtSetArg(arg_list[0], XtNlabel, &set_string);
       XtSetArg(arg_list[1], NULL, NULL);
       XtGetValues((callback_info->widget), arg_list, 1); /* old label */
       if ((val_string != NULL) && (set_string != NULL))
	 { if (strcmp(val_string, set_string) != 0)  /* it was edited */
	     { /* update label */
	       XtSetArg(arg_list[0], XtNlabel, val_string);
	       XtSetValues(widget_node->widget, arg_list, 1);
	     };
	 };
     };

   /* If callback function name was edited,           */
   /* replace old string with copy of new one in menu */
   /* ----------------------------------------------- */
   val_string =  (callback_info->state)->callback_string;
   if ((strcmp(val_string, (widget_node->callback)) != 0)  /* it was edited */
       && (strcmp(widget_node->type, "button") == 0))      /* uses callback */
     { /* update callback function name */
       widget_node->callback = val_string;
     };

   /* Pop Down the Menu */
   /* ----------------- */
   XtPopdown(WBMarkedShell);

 };      /* end of done_button() */

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

void WBbutton_handler(widget, closure, call_data)
     Widget widget;
     caddr_t closure;
     caddr_t call_data;
 {
   struct marker_info *callback_info;
   WidgetNode *widget_node;
   int i;
   Widget make_editable_button();
   Widget make_editable_label();
   Widget make_editable_video();
   Widget make_editable_asciitext();
   Widget make_editable_blank_line();
   Widget make_editable_form();
   Widget make_editable_mail_field();

   callback_info = (struct marker_info *) closure;
   widget_node = callback_info->widget_node;

   if (strcmp(callback_info->option, WBjustify) == 0)      /* re-justify     */
     {
       XtSetArg(arg_list[0], XtNjustify, 
	     ((strcmp(callback_info->value, "center") == 0) ? XtJustifyCenter
		  : ((strcmp(callback_info->value, "right") == 0)
		     ? XtJustifyRight : XtJustifyLeft)));
       XtSetValues(widget_node->widget, arg_list, 1); /* re-justify          */
       inverseVideo((callback_info->state)->justify); /* de-activate button  */
       (callback_info->state)->justify = widget;      /* set state           */
       inverseVideo(widget);                          /* activate new button */
     }
   else if (strcmp(callback_info->option, WBfont) == 0)    /* font change    */
     {
       widget_node->font = callback_info->value;
       XtSetArg(arg_list[0], XtNfont, fontstruct(callback_info->value));
       XtSetValues(widget_node->widget, arg_list, 1); /* re-set font         */
       inverseVideo((callback_info->state)->font);    /* de-activate button  */
       (callback_info->state)->font = widget;         /* set state           */
       inverseVideo(widget);                          /* activate new button */
     }
   else if (strcmp(callback_info->option,
		   WBborderwidth) == 0)                    /* border width   */
     {
       sscanf(callback_info->value, "%d", &i);        /* convert str to int  */
       XtSetArg(arg_list[0], XtNborderWidth, i);
       XtSetValues(widget_node->widget, arg_list, 1); /* set border width    */
       inverseVideo((callback_info->state)->borderWidth);  /* de-activate    */
       (callback_info->state)->borderWidth = widget;  /* set state           */
       inverseVideo(widget);                          /* activate new button */
     }
   else if ((strcmp(callback_info->option,
		   WBinverseVideo) == 0)                   /* inverse video  */
	    && (strcmp((callback_info->state)->inverseVideo_string,
		  callback_info->value) != 0))        /* & a change was made */
     {
       if (strcmp((callback_info->state)->inverseVideo_string,
		  "No") == 0)                         /* turn inverse off    */
	 (callback_info->state)->inverseVideo_string = "Yes";
       else                                           /* turn inverse on     */
	 (callback_info->state)->inverseVideo_string = "No";
       inverseVideo(widget_node->widget);             /* do actual flip work */
       inverseVideo((callback_info->state)->inverseVideo); /* de-activate    */
       (callback_info->state)->inverseVideo = widget; /* set state           */
       inverseVideo(widget);                          /* activate new button */
     }
   else if (strcmp(callback_info->option, "button") == 0)   /* add button    */
     { make_editable_button(widget_node->widget);
     }
   else if (strcmp(callback_info->option, "label") == 0)    /* add label     */
     { make_editable_label(widget_node->widget);
     }
   else if (strcmp(callback_info->option, "video") == 0)    /* add video     */
     { make_editable_video(widget_node->widget);
     }
   else if (strcmp(callback_info->option, "asciitext") == 0) /* + asciitext */
     { make_editable_asciitext(widget_node->widget);
     }
   else if (strcmp(callback_info->option, "blank line") == 0) 
     { make_editable_blank_line(widget_node->widget);      /* add blank line */
     }
   else if (strcmp(callback_info->option, "form") == 0)      /* add form     */
     { make_editable_form(widget_node->widget);
     }
   else if (strcmp(callback_info->option, "mail field") == 0)
     { make_editable_mail_field(widget_node->widget);      /* add mail field */
     }
   else if ((strcmp(callback_info->option,
		   "Still") == 0)                   /* Still video selected */
	    && ((callback_info->state)->videomode
		!= widget))                         /* & it wasn't already  */
     {
       XtSetVideoMode(widget_node->widget, XtVideoStill);
       inverseVideo((callback_info->state)->videomode);  /* old button off */
       inverseVideo(widget);                        /* activate new button */
       (callback_info->state)->videomode = widget;  /* set new state       */
     }
   else if ((strcmp(callback_info->option,
		   "Live") == 0)                   /* Still video selected */
	    && ((callback_info->state)->videomode
		!= widget))                         /* & it wasn't already  */
     {
       XtSetVideoMode(widget_node->widget, XtVideoLive);
       inverseVideo((callback_info->state)->videomode);  /* old button off */
       inverseVideo(widget);                        /* activate new button */
       (callback_info->state)->videomode = widget;  /* set new state       */
     }
   else if ((strcmp(callback_info->option,
		   "Scaled") == 0)                   /* Still video selected */
	    && ((callback_info->state)->videomode
		!= widget))                         /* & it wasn't already  */
     {
       XtSetVideoMode(widget_node->widget, XtVideoScaled);
       inverseVideo((callback_info->state)->videomode);  /* old button off */
       inverseVideo(widget);                        /* activate new button */
       (callback_info->state)->videomode = widget;  /* set new state       */
     };

 };      /* end of button_handler() */

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

Widget WBcreate_form(parent, above)
     Widget parent, above;
 {
   int i;
   Widget widget;

   /* Create Form Widget, whose parent is parent */
   i = 0;
   XtSetArg(arg_list[i], XtNborderWidth, 0); i++;
   /* Form related instance variables, about placement */
   XtSetArg(arg_list[i], XtNleft, XtChainLeft); i++;
   XtSetArg(arg_list[i], XtNright, XtChainRight); i++;
   XtSetArg(arg_list[i], XtNtop, XtRubber); i++;
   XtSetArg(arg_list[i], XtNbottom, XtRubber); i++;
   XtSetArg(arg_list[i], XtNresizable, TRUE); i++;
   XtSetArg(arg_list[i], XtNfromVert, above); i++;
   XtSetArg(arg_list[i], XtNfont, timesRoman12); i++;
   XtSetArg(arg_list[i], NULL, NULL);

   widget =
      XtCreateManagedWidget(gensym(),
               formWidgetClass,
               parent, arg_list, i);

   return(widget);
 };        /* end of WBcreate_form() */

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

Widget WBcreate_button(parent, left, func, markerWidgetNode, option, label)
     Widget parent, left;           /* menu form to add button to, & sibling */
     void func();                   /* callback function */
     WidgetNode *markerWidgetNode;  /* WidgetNode for widget being edited    */
     char *option, *label;          /* property to alter, and possible value */
 {
   int i;
   Widget widget;
   struct marker_info *callback_info;

   /* Create Button Widget, whose parent is parent */

   i = 0;
   XtSetArg(arg_list[i], XtNlabel, label); i++;
   XtSetArg(arg_list[i], XtNjustify, XtJustifyCenter); i++;
   /* Form related instance variables, about placement */
   XtSetArg(arg_list[i], XtNleft, XtRubber); i++;
   XtSetArg(arg_list[i], XtNright, XtRubber); i++;
   XtSetArg(arg_list[i], XtNtop, XtRubber); i++;
   XtSetArg(arg_list[i], XtNbottom, XtRubber); i++;
   XtSetArg(arg_list[i], XtNresizable, TRUE); i++;
   XtSetArg(arg_list[i], XtNfromHoriz, left); i++;
   XtSetArg(arg_list[i], XtNfont, timesRoman12); i++;
   XtSetArg(arg_list[i], NULL, NULL);

   widget =
      XtCreateManagedWidget(gensym(),
               commandWidgetClass,
               parent, arg_list, i);

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

   /* store info about widget being edited by this menu button */
   callback_info = (struct marker_info *)
                      XtCalloc(sizeof(struct marker_info),1);
   callback_info->widget = markerWidgetNode->widget;
   callback_info->widget_node = markerWidgetNode;
   callback_info->option = option;
   callback_info->value = label;
   callback_info->state = markerWidgetNode->edit_states;
   XtAddCallback(widget, XtNcallback, func,
		 (caddr_t) callback_info);
   return(widget);
 };        /* end of WBcreate_button() */

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

Widget WBcreate_label(parent, label)
     Widget parent;
     char *label;
 {
   int i;
   Widget widget;

   /* Create Label Widget, whose parent is parent */

   i = 0;
   XtSetArg(arg_list[i], XtNlabel, label); i++;
   XtSetArg(arg_list[i], XtNborderWidth, 0); i++;
   XtSetArg(arg_list[i], XtNjustify, XtJustifyCenter); i++;
   /* Form related instance variables, about placement */
   XtSetArg(arg_list[i], XtNleft, XtRubber); i++;
   XtSetArg(arg_list[i], XtNright, XtRubber); i++;
   XtSetArg(arg_list[i], XtNtop, XtRubber); i++;
   XtSetArg(arg_list[i], XtNbottom, XtRubber); i++;
   XtSetArg(arg_list[i], XtNresizable, TRUE); i++;
   XtSetArg(arg_list[i], XtNfont, timesRoman12); i++;
   XtSetArg(arg_list[i], NULL, NULL);

   widget =
      XtCreateManagedWidget(gensym(),
               labelWidgetClass,
               parent, arg_list, i);

   return(widget);
 };        /* end of WBcreate_label() */

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

Widget WBcreate_ascii_text(parent, left, default_string, state_string_ptr)
     Widget parent, left;
     char *default_string;
     char **state_string_ptr;
 {
   char *val_string;
   int i;
   Widget widget;

   /* Create Ascii Text Widget, whose parent is parent */

   i = 0;
   /* Form related instance variables, about placement */
   XtSetArg(arg_list[i], XtNleft, XtRubber); i++;
   XtSetArg(arg_list[i], XtNright, XtRubber); i++;
   XtSetArg(arg_list[i], XtNtop, XtRubber); i++;
   XtSetArg(arg_list[i], XtNbottom, XtRubber); i++;
   XtSetArg(arg_list[i], XtNresizable, TRUE); i++;
   XtSetArg(arg_list[i], XtNfromHoriz, left); i++;
   XtSetArg(arg_list[i], XtNfont, timesRoman12); i++;

   /* Create input Value field as an AsciiText widget */
   /* ----------------------------------------------- */
   if (MIN_ASCII_STRING_LENGTH >= strlen(default_string))
     val_string = (char *) calloc(MIN_ASCII_STRING_LENGTH + 1, 1);
   else
     val_string = (char *) calloc(strlen(default_string) + 1, 1);
   strcpy(val_string, default_string);
   *state_string_ptr = val_string;
   XtSetArg(arg_list[i], XtNstring, val_string); i++;
   XtSetArg(arg_list[i], XtNeditType, XttextEdit); i++;
   XtSetArg(arg_list[i], XtNlength, MIN_ASCII_STRING_BOXSIZE); i++;
/*   XtSetArg(arg_list[i], XtNmaxLength, MIN_ASCII_STRING_LENGTH); i++; */
   XtSetArg(arg_list[i], XtNtextOptions, resizeHeight | resizeWidth); i++;

   XtSetArg(arg_list[i], NULL, NULL);

   widget =
      XtCreateManagedWidget(gensym(),
               asciiStringWidgetClass,
               parent, arg_list, i);

   return(widget);
 };        /* end of WBcreate_ascii_text() */

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

void make_widget_popable(widget, wtype, edit_shell, shell_name)
     Widget widget;
     char *wtype;
     Widget edit_shell;  /* the Override Shell that holds button editor */
     char *shell_name;       /* a unique shell name for this popup menu */
 {
   char *str;

   /* Allocate space for translation table string */
   /* ------------------------------------------- */
   str = (char *)
          calloc((
           strlen("<Btn1Up>: MarkWidget(\"\") MyDebug() WBPopup(\"\") ")
           + strlen(shell_name) + strlen(wtype) + 1 + 100),
                  1);  

   /* Make translation table string */
   /* ----------------------------- */
   sprintf(str,
     "<Btn1Up>: MarkWidget(\"%s\",\"%d\") MyDebug() WBPopup(\"%s\")\n%c ",
	   wtype, (int) edit_shell, shell_name, '\0');    
   XtOverrideTranslations(widget, 
			  XtParseTranslationTable(str));
 };

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

Widget create_empty_popupmenu(parent, grandparent_widget, type)
     Widget parent, grandparent_widget;
     char *type;
 {
   Widget edit_shell;  /* the Override Shell that holds button editor */
   Widget edit_menu;   /* the background box for button editor menu   */
   Widget menu_label;
   char *shell_name;       /* a unique shell name for this popup menu */
   char *str;

   /* Create an empty 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);

   /* Link new popup edit menu to parent_widget */
   /* ----------------------------------------- */
   make_widget_popable(parent, type, edit_shell, shell_name);

   /* 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 */

   return(edit_menu);

  };         /* end of create_empty_popupmenu()  */

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