 /*
  * Khoros: $Id: menu.c,v 1.4 1992/03/20 22:43:23 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: menu.c,v 1.4 1992/03/20 22:43:23 dkhoros Exp $";
#endif

 /*
  * $Log: menu.c,v $
 * Revision 1.4  1992/03/20  22:43:23  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "cantata.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>								<<<<
   >>>>	    file name:  menu.c					<<<<
   >>>>								<<<<
   >>>>   description:						<<<<
   >>>>								<<<<
   >>>>      routines:  xvl_init_menus()			<<<<
   >>>>			xvl_build_menu()			<<<<
   >>>>								<<<<
   >>>>			xvl_main_menu_cb()			<<<<
   >>>>			xvl_glyph_menu_cb()			<<<<
   >>>>			xvl_clipboard_menu_cb()			<<<<
   >>>>			xvl_procedure_menu_cb()			<<<<
   >>>>								<<<<
   >>>>			xvl_transport_menu()			<<<<
   >>>>			xvl_distribute_menu()			<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
* Routine Name:  xvl_init_menus
*
*      Purpose:  This routine is used to read in the database used
*		 for the menu forms associated with each workspace.
*		 We do this to avoid re-reading the database in
*		 for each workspace, which can take a lot of time
*		 as well as memory.
*
*        Input:
*
*   Written By:  Mark Young
*
*************************************************************/


int xvl_init_menus(display)

Display *display;
{
	char	*filename, *value;
	int	xvl_error_handler(), xvl_io_error_handler();
	XtErrorHandler xvl_xt_error_handler(), xvl_xt_warning_handler();


	/*
	 *  Set the main and clipboard workspace to be NULL so that if we
	 *  get interrupted during our initialization we don't try to
	 *  delete them.
	 */
        main_workspace  = NULL;
        clipboard = NULL;

        /*
         *  Add error handlers.  First trap SIGINT using so we can cleanup the
         *  temporary files before exiting.  We also need to add an X error
         *  handler, so that we can recover from certain X protocol errors.
         */
        xve_init();
        XVF_EXPRESSION = true;
	khoros_phantomd_pid = 0;

        (void) signal(SIGINT, xvl_error_signal);
        (void) signal(SIGQUIT, xvl_error_signal);
        (void) signal(SIGHUP, xvl_error_signal);
        (void) signal(SIGTERM, xvl_error_signal);
        (void) signal(SIGBUS, xvl_error_signal);
        (void) signal(SIGSEGV, xvl_error_signal);
        xvf_add_signal(SIGCHLD);

        XSetErrorHandler(xvl_error_handler);
        XSetIOErrorHandler(xvl_io_error_handler);
        XtSetErrorHandler(xvl_xt_error_handler);
        XtSetWarningHandler(xvl_xt_warning_handler);

	/*
	 *  Initialize the workspace resources and as well as the
	 *  glyph pixmaps.
	 */
	xvl_load_wresource(&wresource);
	xvl_create_pixmaps(display);

        /*
         * set the name of the khoros main menu
         */
        if ((cantata->form_flag == True) && (cantata->form != NULL))
           filename = xvf_strcpy(cantata->form);
        else
        {
           if (((value = XGetDefault(display, "cantata", "Form")) != NULL) ||
	       ((value = XGetDefault(display, "cantata", "form")) != NULL))
	   {
              filename = xvf_strcpy(value);
	   }
           else
              filename = xvf_strcpy("KHOROS_HOME/repos/cantata/cantata.form");
        }
	if ((main_menu = xvl_build_menu(filename, xvl_main_menu_cb)) == NULL)
	   return(False);

        /*
         * set the name of the khoros sub-procedure menu
         */
        if (((value = XGetDefault(display, "cantata", "ProcedureForm")) !=
		NULL) || ((value = XGetDefault(display, "cantata",
		"procedure_form")) != NULL))
	{
	   if ((procedure_menu = xvl_build_menu(value, xvl_main_menu_cb)) ==
			NULL)
	      procedure_menu = main_menu;
	}
        else
	   procedure_menu = main_menu;


        /*
         * set the name of the khoros clipboard menu
         */
        if (((value = XGetDefault(display, "cantata", "ClipboardForm")) !=
		NULL) || ((value = XGetDefault(display, "cantata",
		"clipboard_form")) != NULL))
	{
	   if ((clipboard_menu = xvl_build_menu(value,
			xvl_clipboard_menu_cb)) == NULL)
	   {
	      filename = xvf_strcpy("KHOROS_HOME/repos/cantata/clipboard.form");
	      if ((clipboard_menu = xvl_build_menu(filename,
			xvl_clipboard_menu_cb)) == NULL)
	      {
	         clipboard_menu = NULL;
	      }
	   }
	}
        else
	{
	   filename = xvf_strcpy("KHOROS_HOME/repos/cantata/clipboard.form");
	   if ((clipboard_menu = xvl_build_menu(filename,
			xvl_clipboard_menu_cb))
			== NULL)
	   {
	      clipboard_menu = NULL;
	   }
	}

        /*
         *  Create the workspace and some of the widgets that are used
         *  by cantata.  The xvl_create_workspace() creates the workspace
         *  where the glyhs will be located.  The xvl_create_routine()
         *  creates the accelerated cantata commands list.  This allows the
         *  user to create glyphs by command rather than going thru the
         *  form tree.  The xvip_create_pixmaps() routines creates the
         *  different pixmaps (buttons) located on the glyphs.
         */ 
        main_workspace = (Workspace *) XtCalloc(1, sizeof(Workspace));
        if (!xvl_create_workspace(main_menu, NULL, main_workspace))
        {
           return(False);
        }
        main_workspace->parent = NULL;

	xvl_set_attributes(main_workspace);
        xvl_create_routine(main_workspace->menuform);
        xvf_change_active(main_workspace->menuform, True);

	if (clipboard_menu != NULL)
	{
           clipboard = (Workspace *) XtCalloc(1, sizeof(Workspace));
           if (!xvl_create_workspace(clipboard_menu, "Copy/Paste Workspace",
			clipboard))
           {
              return(False);
           }
           clipboard->parent = NULL;
           clipboard->menuform->glyph_state    = True;
           clipboard->menuform->glyph_toplevel = NULL;
	}
	xvl_set_attributes(clipboard);
	return(True);
}



/************************************************************
*
* Routine Name: xvl_build_menu
*
*      Purpose: This routine is used to build a menu structure
*		that is suitable to be used for a toplevel menu.
*
*        Input: filename -  the filename in which to  read
*			    user interface from.
*		routine  -  the callback routine be used
*
*       Output: returns the newly created menu structure or NULL
*		upon failure
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


Menu *xvl_build_menu(filename, routine)

char	*filename;
void	(*routine)();
{
	Menu	*menu;
	FILE	*file;
	char	*fullpath, temp[MaxLength];


	fullpath = vfullpath(filename, NULL, NULL); 
	if (!(file = fopen(fullpath, "r")))
        {
           sprintf(temp, "Unable to open '%s' to read database", fullpath);
           xvf_error_wait(temp, "xvl_init_database", NULL);
           return(NULL);
        }
	free(fullpath);

	menu = (Menu *) XtCalloc(1, sizeof(Menu));
	menu->routine = routine;
	if ((menu->db = xvf_read_database(file, &menu->num, &menu->size))==NULL)
	{
	   XtFree(menu);
	   menu = NULL;
	}
	fclose(file);
	return(menu);
}



/************************************************************
*
* Routine Name:  xvl_main_menu_cb
*
*      Purpose:  This routine is used to process the user requests
*		 from a workspace form.
*
*        Input:  form     - the form being processed
*		 subform  - the subform of that form
*		 clientData - the workspace being processed.
*
*
*   Written By: Mark Young
*
*************************************************************/


void xvl_main_menu_cb(form, subform, clientData)

xvf_form     *form;
xvf_sub_form *subform;
char	     *clientData;
{
	Glyph	  *glyph;
	Line_Info lineinfo;
	Workspace *workspace = (Workspace *) clientData;


	if (workspace == NULL)
	   return;

	/* main_form chosen because this is the callback for the main form */
	if (subform != NULL)
	{
	   subform->subform_sel = false;
	   subform->selected    = false;

           if (subform->type == PsuedoSubForm)
	   {
	      workspace->modified = True;
	      xvl_master_button(workspace, subform);
	   }
	   else if (subform->subform_name != NULL)
	   {
	      if ((strcmp(subform->subform_name,"environment") == 0 ||
		   strcmp(subform->subform_name,"attributes") == 0 ||
		   strcmp(subform->subform_name,"directory") == 0) &&
		         subform->type == SubFormButton)
	      {
	         workspace->modified = True;
                 xvl_set_environment(workspace, form, subform);
              }
	      else if (strcmp(subform->subform_name,"variables") == 0 &&
		         subform->type == SubFormButton)
	      {
		 xvl_eval_variables(workspace, form, subform);
	      }
	      else
	      {
	         if (subform->glyph_type == SIMPLE || subform->glyph_type==NONE)
		    subform->quit = False;
	         else
		 {
	            workspace->modified = True;
	            xvl_update_glyph((Glyph *) subform->glyph_info);
		 }
	      }
	   }
	}
	else
	{
	   if (form->quit == True) 
	   {
	      if (workspace->parent == NULL)
	         xvl_quit_workspace(workspace);
	      else
	      {
		 form->form_sel = false;
		 form->quit     = false;
		 glyph = workspace->parent;
		 workspace = glyph->workspace;

	         xvl_clear_workspace(workspace->undo_workspace);
	         xvl_cut_connections(glyph, NULL);
	         xvl_move_glyph(glyph, workspace->undo_workspace, True);
	         xvl_update_undo(workspace);
	      }
	      return;
	   }
	   else if ((subform = xvf_search_sel_master_action(form)) != NULL)
	   {
	      workspace->modified = True;
	      xvf_clear_line_info(&lineinfo);
	      xvl_parse_line(form->db, subform->button_index, &lineinfo);

	      if (lineinfo.variable != NULL)
	      {
		 if (strcmp(lineinfo.variable,"redraw") == 0)
		 {
		    XClearWindow(display, XtWindow(workspace->draw));
		    xvl_redraw_connections(workspace);
		 }
		 else if (strcmp(lineinfo.variable,"accelerate") == 0)
		 {
		    xvf_reverse_colors(subform->button);
		    xvl_routine(workspace, form);
		    xvf_reverse_colors(subform->button);
		 }
		 else if (strcmp(lineinfo.variable,"reset") == 0)
		    xvl_reset_workspace(workspace);
		 else if (strcmp(lineinfo.variable,"check") == 0)
		    xvl_check_workspace(workspace);
		 else if (strcmp(lineinfo.variable,"auto_run") == 0 ||
			  strcmp(lineinfo.variable,"stop_auto_run") == 0)
		    xvl_autorun(workspace);
		 else if (strcmp(lineinfo.variable,"paste") == 0)
		    xvl_paste_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"copy") == 0)
		    xvl_copy_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"duplicate") == 0)
		    xvl_duplicate_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"cut") == 0)
		    xvl_cut_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"save") == 0)
		    xvl_save_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"procedure") == 0)
		    xvl_procedure_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"select") == 0)
		    xvl_select_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"unselect") == 0)
		    xvl_unselect_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"raise") == 0)
		    xvl_raise_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"lower") == 0)
		    xvl_lower_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"delete") == 0)
		    xvl_delete_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"distribute") == 0)
		    xvl_distribute_glyphs(workspace);
		 else if (strcmp(lineinfo.variable,"undo") == 0)
		    xvl_undo_delete(workspace);
		 else if (strcmp(lineinfo.variable,"info") == 0)
		    xvl_workspace_info(workspace);
		 else if (strcmp(lineinfo.variable,"show_clipboard") == 0)
		    xvl_show_clipboard();
                 else if (strcmp(lineinfo.variable, "savefiles") == 0)
		    (void) xvl_save_temp_files(workspace);
	         else if (strcmp(lineinfo.variable,"clear") == 0)
	         {
	             if (xvf_warn_wait("Warning, this option will delete all \
current information from the workspace.\n\nSelect CLEAR if you wish to \
continue.\n\nSelect CANCEL if you wish to return to the current workspace.",
			 "CLEAR Workspace - Warning", "CLEAR", "CANCEL") == 1)
		    {
		       if (workspace->undo_workspace != NULL)
		       {
			  xvl_clear_workspace(workspace->undo_workspace);
			  xvl_update_undo(workspace);
		       }
	               xvl_clear_workspace(workspace);
		    }
	         }
	      }
	      subform->selected = false;
	   }
	   else if (form->glyph_state == true)
	   {
	      if (form->glyph_type == PROCEDURE)
	         xvl_update_glyph((Glyph *) form->glyph_info);
	   }
	}

	/*
	 * acknowledge that form's selection has been properly dealt with
	 */
	form->form_sel = false; 
}



/************************************************************
*
* Routine Name:  xvl_procedure_menu_cb
*
*      Purpose:  This routine is used to process the user requests
*		 from the procedure workspace form.
*
*        Input:  form     - the form being processed
*		 subform  - the subform of that form
*		 clientData - the workspace being processed.
*
*
*   Written By: Mark Young
*
*************************************************************/


void xvl_procedure_menu_cb(form, subform, clientData)

xvf_form     *form;
xvf_sub_form *subform;
char	     *clientData;
{
}



/************************************************************
*
* Routine Name:  xvl_glyph_menu_cb
*
*      Purpose:  This routine is used to process the user requests
*		 from the glyph workspaces.
*
*        Input:  form     - the form being processed
*		 subform  - the subform of that form
*		 clientData - the workspace being processed.
*
*
*   Written By: Mark Young
*
*************************************************************/


void xvl_glyph_menu_cb(form, subform, clientData)

xvf_form     *form;
xvf_sub_form *subform;
char	     *clientData;
{
	Glyph	  *glyph;
	Workspace *workspace = (Workspace *) clientData;


	if (workspace == NULL || subform == NULL)
	   return;

	workspace->modified = True;
	subform->subform_sel = False;
	subform->selected    = False;
	glyph = (Glyph *) subform->glyph_info;
	if (subform->quit == True)
	{
	   subform->quit = False;
	   if (subform->glyph_type != SIMPLE && subform->glyph_type != NONE)
	   {
	      xvl_clear_workspace(workspace->undo_workspace);
	      xvl_cut_connections(glyph, NULL);
	      xvl_move_glyph(glyph, workspace->undo_workspace, True);
	      xvl_update_undo(workspace);
	   }
	}
	else if (subform->glyph_state == true)
	{
	   if (subform->glyph_type == SIMPLE || subform->glyph_type == NONE)
	      subform->quit = False;
	   else
	      xvl_update_glyph(glyph);
	}
	else
	   xvl_update_glyph(glyph);
}



/************************************************************
*
* Routine Name:  xvl_clipboard_menu_cb
*
*      Purpose:  This routine is used to process the user requests
*		 from the clipboard workspace form.
*
*        Input:  form     - the form being processed
*		 subform  - the subform of that form
*		 clientData - the workspace being processed.
*
*
*   Written By: Mark Young
*
*************************************************************/


void xvl_clipboard_menu_cb(form, subform, clientData)

xvf_form     *form;
xvf_sub_form *subform;
char	     *clientData;
{
	Workspace *workspace = (Workspace *) clientData;

	Line_Info    lineinfo;


	if (workspace == NULL || workspace != clipboard)
	   return;

	if ((subform = xvf_search_sel_master_action(form)) != NULL)
	{
	   workspace->modified = True;
	   xvf_clear_line_info(&lineinfo);
	   xvl_parse_line(form->db, subform->button_index, &lineinfo);

	   if (strcmp(lineinfo.variable,"delete") == 0)
	      xvl_delete_glyphs(workspace);
	   else if (strcmp(lineinfo.variable,"save") == 0)
	      xvl_save_glyphs(workspace);
	   else if (strcmp(lineinfo.variable,"procedure") == 0)
	      xvl_procedure_glyphs(workspace);
	   else if (strcmp(lineinfo.variable,"select") == 0)
	      xvl_select_glyphs(workspace);
	   else if (strcmp(lineinfo.variable,"unselect") == 0)
	      xvl_unselect_glyphs(workspace);

	   subform->selected = false;
	}
	else if (form->glyph_state == true)
	{
	   if (form->glyph_type == PROCEDURE)
	      xvl_map_glyph((Glyph *) form->glyph_info);
	   xvl_update_all_clipboard(main_workspace);
	}

	/*
	 * acknowledge that form's selection has been properly dealt with
	 */
	form->form_sel = false; 
}



/************************************************************
*
* Routine Name:  xvl_transport_menu
*
*      Purpose:  This routine is used to prompt the user for the
*		 desired transport to be used between an input
*		 and output node.
*
*        Input:  label		- the label to be used with the list widget
*		 selections     - other menu choices beside the standard
*				  transports
*		 num_selections - the number of selections
*
*
*   Written By: Mark Young
*
*************************************************************/


char  *xvl_transport_menu(workspace, label, prompt, selections, num_selections)

Workspace *workspace;
char	*label;
char	*prompt;
char	**selections;
int	num_selections;
{
	XawListReturnStruct *choice;
	char	**transports, **list;
	int	num_transports, num_list;


	transports = ktransport_list(True, True, True,
				workspace->stream_execution, &num_transports);
	if (transports != NULL && selections != NULL)
	{
	   num_list = num_selections + num_transports;
	   list = vmergelist(selections, transports, num_selections,
			num_transports, False);
	}
	else if (selections != NULL)
	{
	   list = selections;
	   num_list = num_selections;
	}
	else if (transports != NULL)
	{
	   list = transports;
	   num_list = num_transports;
	}
	else return(NULL);

	choice = xvf_run_list_wait(list, num_list, 1, prompt, label, 0, False);

	if (transports != list && selections != list) free(list);
	if (transports != NULL) free(transports);

	if (choice != NULL)
	   return(choice->string);
	else
	   return(NULL);
}



/************************************************************
*
* Routine Name:  xvl_distribute_menu
*
*      Purpose:  This routine is used to prompt the user for the
*		 desired machine in which to execute a glyph on.
*
*        Input:  label		- the label to be used with the list widget
*		 prompt		- the prompt to be used with the list widget
*		 selections     - other menu choices beside the current
*				  machines
*		 num_selections - the number of selections
*
*
*   Written By: Mark Young
*
*************************************************************/


char *xvl_distribute_menu(label, prompt, selections, num_selections)

char	*label;
char	*prompt;
char	**selections;
int	num_selections;
{
	char	**machines, **list;
	XawListReturnStruct *choice;
	int	num_machines, num_list;


	machines = xvl_remote_machines(&num_machines);
	if (machines != NULL && selections != NULL)
	{
	   num_list = num_selections + num_machines;
	   list = vmergelist(selections, machines, num_selections,
			num_machines, False);
	}
	else if (selections != NULL)
	{
	   list = selections;
	   num_list = num_selections;
	}
	else if (machines != NULL)
	{
	   list = machines;
	   num_list = num_machines;
	}
	else return(NULL);

	choice = xvf_run_list_wait(list, num_list, 1, prompt, label, 0, True);

	if (machines != list && selections != list) free(list);
	if (machines != NULL) free(machines);

	if (choice != NULL)
	   return(choice->string);
	else
	   return(NULL);
}
