/*
 * as_menuh.c:  procedures for creating menus recursively
 */

/*
 * Copyright 1991 - 1994,  Andrzej Stochniol, London, UK
 *
 * ASEDIT text editor, both binary and source (hereafter, Software) is
 * copyrighted by Andrzej Stochniol (hereafter, AS) and ownership remains
 * with AS.
 *
 * AS grants you (hereafter, Licensee) a license to use the Software
 * for academic, research and internal business purposes only, without a
 * fee.  Licensee may distribute the binary and source code (if released)
 * to third parties provided that the copyright notice and this statement
 * appears on all copies and that no charge is associated with such copies.
 *
 * Licensee may make derivative works.  However, if Licensee distributes
 * any derivative work based on or derived from the Software, then
 * Licensee will:
 * (1) notify AS regarding its distribution of the derivative work, and
 * (2) clearly notify users that such derivative work is a modified version
 *      and not the original ASEDIT distributed by AS.
 *
 * Any Licensee wishing to make commercial use of the Software should
 * contact AS to negotiate an appropriate license for such commercial use.
 * Commercial use includes:
 * (1) integration of all or part of the source code into a product for sale
 *     or license by or on behalf of Licensee to third parties, or 
 * (2) distribution of the binary code or source code to third parties that
 *     need it to utilize a commercial product sold or licensed by or on 
 *     behalf of Licensee.
 *
 * A. STOCHNIOL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS
 * SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
 * IMPLIED WARRANTY.  IN NO EVENT SHALL A. STOCHNIOL BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * 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 PERFORMANCE OF THIS SOFTWARE.
 *
 * By using or copying this Software, Licensee agrees to abide by the
 * copyright law and all other applicable laws, and the terms of this
 * license.
 * AS shall have the right to terminate this license immediately by
 * written notice upon Licensee's breach of, or non-compliance with, any
 * of its terms.  Licensee may be held legally responsible for any
 * copyright infringement that is caused or encouraged by Licensee's
 * failure to abide by the terms of this license.
 *
 *
 * 	Andrzej Stochniol	(A.Stochniol@ic.ac.uk)
 * 	30 Hatch Road
 * 	London SW16 4PN
 * 	UK
 */


#include <stdio.h>		/* for fprintf and stderr definition ... */
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Separator.h>
#include <Xm/PushB.h>
#include <Xm/CascadeB.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/ToggleB.h>

#include "asedit.h"

#ifdef _NO_PROTO
XtPointer mk_asdat(/*   int client_data   */);
#else  /* _NO_PROTO */
XtPointer mk_asdat(int client_data);
#endif


#ifdef _NO_PROTO
void as_create_menuh(title, menu, menulist, nitems, charset)
char *title;
Widget menu;
as_menuh_struct *menulist;
int nitems;
XmStringCharSet charset;
#else  /* _NO_PROTO */
void as_create_menuh(char *title, Widget menu, as_menuh_struct *menulist, int nitems,
		XmStringCharSet charset)
#endif
{
  Arg        wargs[10];
  int        i, n=0;
  WidgetList buttons;
  int        separators = 0;
  char	     pull_down_name[40];	/* to construct _PD strings... (note before 1.3 we had _PullDown) */


  /* Allocate a widget list to hold all button widgets. */
  buttons = (WidgetList) XtMalloc(nitems * sizeof(Widget));

  /* If a title is given, create Label and Separator widgets. */
  if(title)
  {
    n = 0;
    XtCreateManagedWidget(title, xmLabelWidgetClass, menu, wargs, n);

    n = 0;
    XtCreateManagedWidget("separator", xmSeparatorWidgetClass, menu, wargs, n);
  }

  /* Create an entry for each item in the menu. */
  for(i=0; i<nitems; i++)
  {
   if(menulist[i].name == NULL)	  /* A NULL name represents a separator.*/
   {
     n = 0;
     XtCreateManagedWidget("separator", xmSeparatorWidgetClass, menu, wargs, n);
     separators++; 		/* Count how many entries aren't buttons */
   }

   /* If there is a name and a callback, create a "normal"
    * menu entry and register the callback function.
    */
   else if(menulist[i].func)
   {
     n=0;
     if(menulist[i].mnemonic) { XtSetArg(wargs[n],XmNmnemonic,menulist[i].mnemonic); n++; }

     if(menulist[i].acceleratorText)
     {
	 XtSetArg(wargs[n], XmNacceleratorText,
		 XmStringCreateLtoR(menulist[i].acceleratorText, charset)); n++;
     }

     if(menulist[i].accelerator) { XtSetArg(wargs[n], XmNaccelerator,
					menulist[i].accelerator); n++; }

     if (menulist[i].name[0] == '<' || menulist[i].name[0] == '>' ||
	 menulist[i].name[0] == '[' || menulist[i].name[0] == ']')    /* otpion/toggle button */
     {
	/* A toggle button (one of many) is diamond-shaped. */
	if (menulist[i].name[0] == '<' || menulist[i].name[0] == '>')
	{
	    XtSetArg(wargs[n], XmNindicatorType, XmONE_OF_MANY); n++;
	}
	/* set the on state (for '>' and ']') */
	if (menulist[i].name[0] == '>' || menulist[i].name[0] == ']')
	{
	    XtSetArg (wargs[n], XmNset, True);  n++;
	}


	/* ignore the first character of the label */
	buttons[i-separators] = XmCreateToggleButton (menu,(String)&(menulist[i].name[1]),
				      wargs, n);
	XtAddCallback(buttons[i-separators], XmNvalueChangedCallback ,
			   menulist[i].func, mk_asdat(menulist[i].data) );

     }
     else /* regular button */
     {
	buttons[i-separators] = XmCreatePushButton (menu, menulist[i].name,
				      wargs, n);
	XtAddCallback(buttons[i-separators], XmNactivateCallback,
		   menulist[i].func, mk_asdat(menulist[i].data) );
     }

     if( menulist[i].helpCB )
	XtAddCallback(buttons[i-separators], XmNhelpCallback,
		   menulist[i].helpCB, mk_asdat(menulist[i].data) );

   }
   /*
    * If there is a name, but no callback function, the entry
    * must be a label, unless there is a submenu.
    */
   else if(!menulist[i].sub_menu)
   {
     n = 0;
     buttons[i-separators] = XtCreateWidget(menulist[i].name,
					   xmLabelWidgetClass,
					   menu, wargs, n);
   }
   /*
    * If we got here, the entry must be a submenu (except when the name 
    * starts with ".").
    * Create a pulldown menu pane and an XmCascadeButton widget. 
    * If the name starts with a "." create option menu.
    * Then attach the menu pane and make a recursive call
    * to create the entries in the submenu.
    */
   else
   {
    Widget sub_menu;

    /*  old (the name of the pull down menu was never set if sub_menu_title
	was not	specified, which is the usual situation)
	    sub_menu =XmCreatePulldownMenu(menu,
				   menulist[i].sub_menu_title,
				   NULL, 0);
    ***OLD  (before 14.10.1992)  */

    /* first construct a name for the pull down widget (practically menu shell widget) */

    if(menulist[i].name[0] != '.') strcpy(pull_down_name, menulist[i].name);
    else strcpy(pull_down_name, menulist[i].name+1);
    strcat(pull_down_name,"_PD");

    sub_menu =XmCreatePulldownMenu(menu,
				   pull_down_name,
				   NULL, 0);

    n=0;
    XtSetArg(wargs[n], XmNsubMenuId, sub_menu); n++;
    if(menulist[i].mnemonic) { XtSetArg(wargs[n],XmNmnemonic,menulist[i].mnemonic); n++; }

    if(menulist[i].acceleratorText)
    {
	 XtSetArg(wargs[n], XmNacceleratorText,
		 XmStringCreateLtoR(menulist[i].acceleratorText, charset)); n++;
    }

    if(menulist[i].accelerator) { XtSetArg(wargs[n], XmNaccelerator,
					menulist[i].accelerator); n++; }

    if(menulist[i].name[0] != '.') buttons[i-separators] = XmCreateCascadeButton (menu,
				 menulist[i].name, wargs, n);
    else buttons[i-separators] = XmCreateOptionMenu (menu,
				 menulist[i].name+1, wargs, n);

    /* install a help callback if specified */
     if( menulist[i].helpCB )
	XtAddCallback(buttons[i-separators], XmNhelpCallback,
		   menulist[i].helpCB, mk_asdat(menulist[i].data) );



    as_create_menuh(menulist[i].sub_menu_title,
			  sub_menu, menulist[i].sub_menu,
			  menulist[i].n_sub_items, charset);
   }
   /* put the address of a created button widget into menulist[i]  */
   if(menulist[i].name != NULL)
   { 	/* O.K., otherwise a separator element has been created .... */
	menulist[i].w = buttons[i-separators];
   }

  }


  /*
   * Manage all button widgets. Menu panes are not managed.
   */
  XtManageChildren(buttons, nitems - separators);

} /* as_create_menuh */





#ifdef _NO_PROTO
void as_create_popup_menu(title, menu, menulist, nitems, charset)
char *title;
Widget menu;
as_menuh_struct *menulist;
int nitems;
XmStringCharSet charset;
#else  /* _NO_PROTO */
void as_create_popup_menu(char *title, Widget menu, as_menuh_struct *menulist, int nitems,
		XmStringCharSet charset)
#endif
{
  Arg        wargs[10];
  int        i, n=0;
  WidgetList buttons;
  int        separators = 0;
  char	     popup_name[40];	/* to construct ..._Popup strings */
  Widget     popup;
  char	     *def_error =  "\nError: %s is not allowed in the popup menu top structure! Popup No. %d not created!";


  /* first check the validity of the data structure */
  if(title)	fprintf(stderr, "\nWarning: title not needed in the popup menus top structure!");



  /* Allocate a widget list to hold all popup widgets (usually there is only one). */
  buttons = (WidgetList) XtMalloc(nitems * sizeof(Widget));

  /* Create an entry for each item in the popup list menu. */
  for(i=0; i<nitems; i++)
  {

   if(menulist[i].name == NULL)   /* A NULL name represents a separator. - NOT allowed here! */
   {
	fprintf(stderr, def_error, "separator" , i);
   }
   else if(menulist[i].func)	  /* normal pulldown menu entries - NOT allowed here! */
   {
	fprintf(stderr, def_error, "normal pulldown entry" , i);
   }
   else if(!menulist[i].sub_menu) /* label - NOT allowed here! */
   {
	fprintf(stderr, def_error, "label" , i);
   }
   else
   {
   	/*
    	* If we got here, the entry must be a submenu (except when the name 
    	* starts with ".", but we don't expect the former here anyway).
    	* Create popup menu.
    	* Then  make a recursive call to create the entries in the popup submenu.
    	*/

    	/* first construct a name for the popu menu (practically menu shell widget) */
    	strcpy(popup_name, menulist[i].name);
    	strcat(popup_name,"_Popup");

    	popup = XmCreatePopupMenu(menu,
				   popup_name,
				   NULL, 0);
	menulist[i].w = popup;

    	as_create_menuh(menulist[i].sub_menu_title,
			  popup, menulist[i].sub_menu,
			  menulist[i].n_sub_items, charset);

    }

  }

} /* as_create_popup_menu */


