      /********************************************************/
      /*                   Widget-Builder               (3)   */
      /* 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 "wb_include.h"
#include "wbnodeP.h"

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

char *dupl_string(str)
     char *str;
 { char *new_str;
   int len;

   len = strlen(str);
   new_str = (char *) XtCalloc((Cardinal) ( 1 + len),
			       (Cardinal) sizeof(char));
   strcpy(new_str, str);
   new_str[len] = '\0';

   return(new_str);

 };        /* end of dupl_string()  */

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

/****************************************************************/
/*    Instance Variable access functions for a Widget-Node.     */
/****************************************************************/

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

void WN_set_type(node, type)
     WidgetNode *node;
     char *type;
 { if (node->type != NULL)
     XtFree((char *) node->type);
   node->type = dupl_string(type);  
 };

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

char *WN_get_type(node)
     WidgetNode *node;
 { 
   return(node->type);
 };

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

void WN_set_mmm_id(node, id)
     WidgetNode *node;
     int id;
  {
   /* Set the widget's mmm ID, used when being written to a mail file */
   node->mmm_id = id;

  };        /* end of WN_set_mmm_id()  */

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

int WN_get_mmm_id(node)
     WidgetNode *node;
  {
   /* Get the widget's mmm ID, used when being written to a mail file */
   return(node->mmm_id);

  };        /* end of WN_get_mmm_id()  */

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

void WN_set_parent_mmm_id(node, id)
     WidgetNode *node;
     int id;
  {
   /* Set widget's parent mmm ID, used when being written to a mail file */
   node->parent_mmm_id = id;

  };        /* end of WN_set_parent_mmm_id()  */

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

int WN_get_parent_mmm_id(node)
     WidgetNode *node;
  {
   /* Get widget's parent mmm ID, used when being written to a mail file */
   return(node->parent_mmm_id);

  };        /* end of WN_get_parent_mmm_id()  */

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

void WN_set_id_name(node, id_name)
     WidgetNode *node;
     char  *id_name;
  {
   /* Set widget's ID name, WB internal unique name */
   node->id_name = id_name;

  };        /* end of WN_set_id_name()  */

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

char *WN_get_id_name(node)
     WidgetNode *node;
  {
   /* Get widget's ID name, WB internal unique name */
   return(node->id_name);

  };        /* end of WN_set_id_name()  */
/****************************************************************/

void WN_edit_states_create(node)
     WidgetNode *node;
 {
  if (node->edit_states == NULL)
    { node->edit_states = (struct menu_state *)
	          XtCalloc((Cardinal) 1, (Cardinal) sizeof(struct menu_state));
      (node->edit_states)->varName = NULL;
      (node->edit_states)->varName_string = NULL;
      (node->edit_states)->name = NULL;
      (node->edit_states)->name_string = NULL;
      (node->edit_states)->label = NULL;
      (node->edit_states)->label_string = NULL;
      (node->edit_states)->callback = NULL;
      (node->edit_states)->callback_string = NULL;
      (node->edit_states)->font = NULL;
      (node->edit_states)->justify = NULL;
      (node->edit_states)->inverseVideo = NULL;
      (node->edit_states)->inverseVideo_string = NULL;
      (node->edit_states)->borderWidth = NULL;
      (node->edit_states)->videomode = NULL;
    };
 };

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

struct menu_state *WN_get_edit_states(node)
     WidgetNode *node;
 {
  return(node->edit_states);
  };

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

void WN_set_varName(node, varname)
     WidgetNode *node;
     char  *varname;
  {
   /* Set widget's varname, used for generating C code */
   if (node->varName != NULL)
     { strcpy(node->varName, varname);
       node->varName[strlen(varname)] = '\0';
     }
   else
     { /* the struct used to keep track of this node's pop-up edit menu   */
       WN_edit_states_create(node);
       node->varName = (char *)
		       XtCalloc((Cardinal) (MIN_ASCII_STRING_LENGTH + 2),
				(Cardinal) sizeof(char));
       (node->edit_states)->varName_string = node->varName;
       strcpy(node->varName, varname);
       node->varName[strlen(varname)] = '\0';
     };
  };        /* end of WN_set_varName()  */

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

char *WN_get_varName(node)
     WidgetNode *node;
  {
   /* Get widget's varname, used for generating C code */
   return(node->varName);

  };        /* end of WN_get_varName()  */

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

void WN_set_name(node, name)
     WidgetNode *node;
     char  *name;
  {
   /* Set widget's varname, used by X */
   if (node->name != NULL)
     { strcpy(node->name, name);
       node->name[strlen(name)] = '\0';
     }
   else
     { /* the struct used to keep track of this node's pop-up edit menu   */
       WN_edit_states_create(node);
       node->name = (char *)
		       XtCalloc((Cardinal) (MIN_ASCII_STRING_LENGTH + 2),
				(Cardinal) sizeof(char));
       (node->edit_states)->name_string = node->name;
       strcpy(node->name, name);
       node->name[strlen(name)] = '\0';
     };
  };        /* end of WN_set_name()  */

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

char *WN_get_name(node)
     WidgetNode *node;
  {
   /* Get widget's name, used by X */
   return(node->name);

  };        /* end of WN_get_name()  */

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

void WN_set_callback(node, callback_string)
     WidgetNode *node;
     char  *callback_string;
  {
   /* Set widget's callback, used for generating C code */
   if (node->callback != NULL)
     { strcpy(node->callback, callback_string);
       node->callback[strlen(callback_string)] = '\0';
     }
   else
     { /* the struct used to keep track of this node's pop-up edit menu   */
       WN_edit_states_create(node);
       node->callback = (char *)
		       XtCalloc((Cardinal) (MIN_ASCII_STRING_LENGTH + 2),
				(Cardinal) sizeof(char));
       (node->edit_states)->callback_string = node->callback;
       strcpy(node->callback, callback_string);
       node->callback[strlen(callback_string)] = '\0';
     };
  };        /* end of WN_set_callback()  */

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

char *WN_get_callback(node)
     WidgetNode *node;
  {
   /* Get widget's callback name, used for generating C code */
   return(node->callback);

  };        /* end of WN_get_callback()  */

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

void WN_set_font(node, font_string)
     WidgetNode *node;
     char *font_string;
 { if (node->font != NULL)
     XtFree((char *) node->font);

   /* set the string name of the font */
   node->font = dupl_string(font_string);

   /* set the struct of the font used this widget's label      */
   node->font_struct = fontstruct(font_string);

   /* actually alter the font of the widget */
   XtSetArg(arg_list[0], XtNfont,
			    (XtArgVal) node->font_struct);
   XtSetValues(node->widget, arg_list, 1);

 };

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

char *WN_get_font(node)
     WidgetNode *node;
 { 
   return(node->font);
 };

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

Widget WN_get_widget(node)
     WidgetNode *node;
 { 
   return(node->widget);
 };

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

void WN_set_string(node, text_string)
     WidgetNode *node;
     char  *text_string;
  {
   /* Set widget's string, used by ascii-text widgets */
   if (node->string != NULL)
     { strcpy(node->string, text_string);
       node->string[strlen(text_string)] = '\0';
     }
   else
     { node->string = (char *)
		       XtCalloc((Cardinal) (MIN_ASCII_STRING_LENGTH + 2),
				(Cardinal) sizeof(char));
       strcpy(node->string, text_string);
       node->string[strlen(text_string)] = '\0';
       XtSetArg(arg_list[0], XtNstring, (XtArgVal) (node->string));
       XtSetValues(node->widget, arg_list, 1);
     };
  };        /* end of WN_set_string()  */

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

char *WN_get_string(node)
     WidgetNode *node;
  {
   /* Get widget's string, used by asciitext widgets */
   return(node->string);

  };        /* end of WN_get_string()  */

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

void WN_set_label(node, label_string)
     WidgetNode *node;
     char  *label_string;
  {
   /* Set widget's label */

      /* the struct used to keep track of this node's pop-up edit menu   */
       WN_edit_states_create(node);
       if ((node->edit_states)->label_string == NULL)
         (node->edit_states)->label_string = (char *)
		       XtCalloc((Cardinal) (MIN_ASCII_STRING_LENGTH + 2),
				(Cardinal) sizeof(char));
       strcpy((node->edit_states)->label_string, label_string);
       ((node->edit_states)->label_string)[strlen(label_string)] = '\0';
       XtSetArg(arg_list[0], XtNlabel, (XtArgVal) 
			    ((node->edit_states)->label_string));
       XtSetValues(node->widget, arg_list, 1);

  };        /* end of WN_set_label()  */

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

char *WN_get_label(node)
     WidgetNode *node;
  {
   /* Get widget's label text */
   return((node->edit_states)->label_string);

  };        /* end of WN_get_label()  */

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





/****************************************************************/
/*     Methods for a Widget-Node object.                        */
/****************************************************************/

WidgetNode *find_widgets_node(widget, starting_node)
     Widget widget;
     WidgetNode *starting_node;
 {
    WidgetNode *current_node, *wn;

    /* Locate the widget node in linked list for the search widget */
    /* ----------------------------------------------------------- */
    for (current_node = starting_node;
	 (current_node != NULL) && (current_node->widget != widget);
	 current_node = current_node->next)
      if ((wn = find_widgets_node(widget, current_node->first_child))
	  != NULL)
	return(wn);

    return(current_node);
  };         /* end of find_widgets_node() */

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

WidgetNode *get_widgetnode_by_mmm_id(mmm_id, starting_node)
     int mmm_id;
     WidgetNode *starting_node;
 {
    WidgetNode *current_node, *wn;

    /* Locate the widget node in linked list for the search widget */
    /* ----------------------------------------------------------- */
    for (current_node = starting_node;
	 (current_node != NULL) && (current_node->mmm_id != mmm_id);
	 current_node = current_node->next)
      if ((wn = get_widgetnode_by_mmm_id(mmm_id, current_node->first_child))
	  != NULL)
	return(wn);

    return(current_node);
  };         /* end of get_widgetnode_by_mmm_id() */

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

WidgetNode *add_widget_node(widget, parent_widget, type, prstr_func)
     Widget widget;
     Widget parent_widget;
     char *type;
     VOID_FUNCPTR prstr_func;
 {
   WidgetNode *new_node;
   char *tempstr;
   extern char *genname();

   /* allocate space for the new node */
   new_node = (WidgetNode *) XtCalloc((Cardinal) 1,
				      (Cardinal) sizeof(WidgetNode));

   /* first, set edit_states pointer to NULL, so other stuff will work right */
   new_node->edit_states = NULL;

   /* second, set pointer to actual widget, so other stuff will work right */
   new_node->widget = widget;

   /*  the widget's ID when being written to a mail file    */
   new_node->mmm_id = -1;   /* will be reset later, anyway */

   /* unique name of widget for X, often genname'ed         */
   tempstr = genname();
   new_node->name = NULL;
   WN_set_name(new_node, tempstr);

   /* name of variable widget is assigned to in saved code */
   new_node->varName = NULL;
   WN_set_varName(new_node, tempstr);

   XtFree((char *) tempstr);

   /* type of widget (e.g.: "button", "label", etc.)       */
   new_node->type = NULL;
   WN_set_type(new_node, type);

   /* pointer to the widget's parent widget                */
   new_node->parent = parent_widget;

   /* pointer to the widget's popup child widget           */
   new_node->popup = NULL;

   /* name of callback function for widget (written later) */
   new_node->callback = NULL;

   /* use for holding ptr to Ascii Text widget's XtNstring */
   new_node->string = NULL;
   if (strcmp(type, "ascii text") == 0)
     WN_set_string(new_node, " ");
   if (strcmp(type, "asciitext") == 0)
     WN_set_string(new_node, " ");

   /* the name of the font used for  label of this widget  */
   new_node->font = NULL;
   WN_set_font(new_node, "times-roman12");

   /* The pointer to the function which prints a string of properties */
   new_node->prstr_func = (VOID_FUNCPTR) prstr_func;

   /* pointer to next widget node in linked list           */
   new_node->next = NULL;

   /* Set the pointer to the parent's widget node          */
   new_node->parent_node = find_widgets_node(parent_widget, HeadWidgetList);

   /* Link new node into linked list of child widget nodes */
   if (parent_widget == userArea)
     { /* add node to the top level list */
       if (HeadWidgetList == NULL)
	 {
	   HeadWidgetList = new_node;
	   TailWidgetList = new_node;
	 }
       else
	 {
	   TailWidgetList->next = new_node;
	   TailWidgetList = new_node;
	 };
     }
   else if (new_node->parent_node != NULL)
     { /* add node to a parents children list */
       if ((new_node->parent_node)->first_child == NULL)
	 {
	   (new_node->parent_node)->first_child = new_node;
	   (new_node->parent_node)->last_child = new_node;
	 }
       else
	 {
	   ((new_node->parent_node)->last_child)->next = new_node;
	   (new_node->parent_node)->last_child = new_node;
	 };
     }
   else
     { return(NULL);   /* can not add the node, nothing to add it to */
     };

   return(new_node);

 };             /* end of add_widget_node() */

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

void traverse_widgets_nodes(starting_node, func, arg)
     WidgetNode   *starting_node;
     VOID_FUNCPTR  func;
     VOIDP         arg;
  {
     WidgetNode *current_node, *wn;

     /* Traverse linked tree, performing "func" on each widget node */
     for(current_node = starting_node;
	 current_node != NULL;
	 current_node = current_node->next)
       { 
	 if (func != NULL)
	   (func)(arg, current_node);

	 traverse_widgets_nodes(current_node->first_child,
				func, arg);
       };
   };         /* end of traverse_widgets_nodes()  */

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

void WNdestroy(node, flag)     /* just destroys one node */
     WidgetNode   *node;       
     int           flag;         /* flags if widget is to be destroyed, too */
   {
     
     if (node != NULL)
       { /* Destroy widget if necessary */
	 if (flag && (node->widget != NULL))
	   XtDestroyWidget(node->widget);

	 /* free original struct */
	 XtFree((char *) node);
       };
   };         /* end of WNdestroy()  */

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

void WNdestroy_tree(starting_node, flag)
     WidgetNode   *starting_node;       
     int           flag;         /* flags if widget is to be destroyed, too */
  {
     WidgetNode *current_node, *next_node;

     if (starting_node != NULL)
       {
	 /* Traverse linked tree, to first free all the children */
	 for(current_node = starting_node->first_child;
	     current_node != NULL;
	     current_node = next_node)
	   { 
	     next_node = current_node->next;
	     current_node->next = NULL;
	     WNdestroy_tree(current_node, FALSE);
	   };
	 
	 /* Now free the top starting_node */
	 starting_node->first_child = NULL;
	 starting_node->next = NULL;
	 WNdestroy(starting_node, flag);     /* just destroys one node */
       }; 
   };        /* end of WNdestroy_tree()  */

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

void WNdestroy_all(flag)
     int           flag;
   { extern WidgetNode *HeadWidgetList;
     WidgetNode *current_node, *next_node;

     if (HeadWidgetList != NULL)
       { 
	 /* Traverse linked tree, to first free all the children */
	 /* ---------------------------------------------------- */
	 for(current_node = HeadWidgetList->next;
	     current_node != NULL;
	     current_node = next_node)
	   { 
	     next_node = current_node->next;
	     WNdestroy_tree(current_node, flag);
	   };

	 HeadWidgetList->next = NULL;
	 WNdestroy_tree(HeadWidgetList, flag);  /* destroy all known nodes */
	 HeadWidgetList = NULL;    /* erase pointer to dead structure */
       };
   };         /* end of WNdestroy_all()  */

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

int WNhas_mmm_parent(widgetnode)
     WidgetNode *widgetnode;
 {
   return(widgetnode->parent_mmm_id >= 0);
 };           /* end of WNhas_mmm_parent()  */

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

