/* {(rm mdllib.o ; cc -DUNIX -c -s -n -O -Wc,-Nd4000 -Wc,-Ns4000 -Wc,-Nt50000 -DSYSV -DNLS16 -Dhp9000s300 -o mdllib.o mdllib.c)& } */
/**---------------------------------------------------------------------
***	
***	file:		mdl.c
***
***	project:	Menu Description Language
***                     General purpose Menu generator.
***
***			(c) 1990 Rainer Kowallik
***
***-------------------------------------------------------------------*/


/*  include files  */
#include <stdio.h>
#include <setjmp.h>

#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/Shell.h>
#include <Xm/Xm.h>
#include <Xm/BulletinB.h>
#include <Xm/CascadeB.h>
#include <Xm/Frame.h>
#include <Xm/Label.h>
#include <Xm/MainW.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
#include <Xm/ScrollBar.h>
#include <Xm/ScrolledW.h>
#include <Xm/ToggleBG.h>
#include <Xm/Scale.h>
#include <Xm/SelectioB.h>


#define	PUSH         1
#define	TOGGLE       2
#define	SCALEX       3
#define SCALEY       4
#define	DIALOG       5
#define	MENU         6
#define	NEW_MENU     7
#define	FILE_SELECT  8
#define	BOARD	     9
#define BULLETIN    10
#define	SELECTION   11
#define	MESSAGE     12
#define	RADIO       13
#define	ROWCOL      14
#define	SCALEX11    15
#define SCALEY11    16
#define STRING      17
#define INTEGER     18
#define FLOAT       19


/*  functions defined in this program  */
/* void main(); */
void activateCB(); /* Callback for the PushButton */


/*  global variables  */

Display		*display	= NULL; /*  dsplay		*/
XtAppContext	app_context     = NULL; /*  Application Context */
Widget		app_shell	= NULL;	/*  shell widget	*/
Widget		main_window	= NULL;	/*  MainWindow		*/
Widget		menu_bar	= NULL;	/*  MenuBar		*/
Widget		menu_pane	= NULL;	/*  MenuPane		*/
Widget		cascade		= NULL;	/*  CascadeButton	*/
Widget		frame		= NULL;	/*  Frame		*/
Widget		swindow		= NULL;	/*  ScrolledWindow	*/
Widget		row_column	= NULL;	/*  RowColumn		*/
Widget		button		= NULL;	/*  PushButtonGadget	*/
Widget		hsb		= NULL;
Widget 		vsb		= NULL;	/*  ScrollBars		*/
Widget		radio		= NULL;	/*  Radio button Widget */
Widget		dialog_box	= NULL;

int     last_gadgetid = 0;
int 	fn_number = 0;
void    (*fn_command[160])();
int     *var_value[160];
int     var_funct[160];
Widget 	Wstring[160];
int	string_var[160];
int 	string_ptr = 0;
Widget 	Wtoggle[160];
int	toggle_var[160];
int 	toggle_ptr = 0;
Widget	Wscale[160];
int	scale_var[160];
int	scale_ptr = 0;
int	selector[160];
int	selector_ptr = 0;
int	acc_x = 0;        /* accumulated x  */
int	acc_y = 0;        /* accumulated y  */
int	bas_y = 5;        /* base scale for y-increment */
char	menu_name[80];			/* store menu bar name */
char	return_string[80];		/* string returned from dialog box */
char	resource[80];
jmp_buf	ugly;

/* -------------------------------------------------------------
   The following variables and functions are declared for AMIGA
   compatibility. They should get more usefull in future releases
   ------------------------------------------------------------- */

int    propdwn;
int    menu_line;
int    menu_column;
int    top_slider;
int    scale_var0[160];
int    scale_var1[160];
int    fin_flg;               /* tells the MainLoop to termitate */

read_dir(s1,s2)
char *s1, *s2;
{
   return(0);
}

/* -------------------------------------------------------------- 
    Create default application windows and widgets
   -------------------------------------------------------------- */
Widget CreateApplication (parent) 
Widget		parent;		/*  parent widget	*/
{
Arg		args[10];	/*  arg list		*/
register int	n;		/*  arg count		*/


	/*	Create MainWindow.
	*/
	n = 0;
	main_window = XmCreateMainWindow (parent, "main1", args, n);
	XtManageChild (main_window);

	/*	Create MenuBar in MainWindow.
	*/
	n = 0;
	menu_bar = XmCreateMenuBar (main_window, "menu_bar", args, n); 
	XtManageChild (menu_bar);

	/*	Create Frame MainWindow and ScrolledWindow in Frame.
	*/
	n = 0;
	XtSetArg (args[n], XmNmarginWidth, 2);  n++;
	XtSetArg (args[n], XmNmarginHeight, 2);  n++;
	XtSetArg (args[n], XmNshadowThickness, 1);  n++;
	XtSetArg (args[n], XmNshadowType, XmSHADOW_OUT);  n++;
	frame = XmCreateFrame (main_window, "frame", args, n);
	XtManageChild (frame);

	n = 0;
	XtSetArg (args[n], XmNscrollBarDisplayPolicy, XmAS_NEEDED);  n++;
	XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC);  n++;
	swindow = XmCreateScrolledWindow (frame, "swindow", args, n);
	XtManageChild (swindow);

	n = 0;
	XtSetArg (args[n], XmNpacking, XmPACK_NONE);  n++;
	XtSetArg (args[n], XmNorientation, XmVERTICAL);  n++; 
	row_column = XmCreateRowColumn (swindow, "row_column", args, n);
	XtManageChild (row_column);

	/*	Set MainWindow areas and add tab groups
	*/
	XmMainWindowSetAreas (main_window, menu_bar, NULL, NULL, NULL,
			frame);
	n = 0;
	XtSetArg (args[n], XmNhorizontalScrollBar, &hsb);  n++;
	XtSetArg (args[n], XmNverticalScrollBar, &vsb);  n++;
	XtGetValues (main_window, args, n);
	if (hsb) XmAddTabGroup (hsb);
	if (vsb) XmAddTabGroup (vsb);
	XmAddTabGroup (row_column);
	return(main_window);
}


/* -------------------------------------------------------------
 	Dialog Box Creation Functions:
		Help(char message[]);
		FileSelect(char dir[]);
		StringBox(char title[]);
   ------------------------------------------------------------- */
/*-------------------------------------------------------------
**	CreateHelp		- create help window
*/
Widget	CreateHelp (message) 
	char message[];
{
	Widget		knopf;
	Widget		message_box;	/*  Message Dialog 	*/
	Arg		args[20];	/*  arg list		*/
	register int	n;		/*  arg count           */
	XmString	title_string = NULL;
	XmString	message_string = NULL;
	XmString	knopf_string = NULL;


	message_string = XmStringCreateLtoR (message, XmSTRING_DEFAULT_CHARSET);
	knopf_string = XmStringCreateLtoR ("Close", XmSTRING_DEFAULT_CHARSET);
	title_string = XmStringCreateLtoR ("Message:", XmSTRING_DEFAULT_CHARSET);

	/*	Create MessageBox dialog.
	*/
	n = 0;
	XtSetArg (args[n], XmNdialogTitle, title_string);  n++;
	XtSetArg (args[n], XmNokLabelString, knopf_string);  n++;
	XtSetArg (args[n], XmNmessageString, message_string);  n++;
	message_box = XmCreateMessageDialog (main_window, "helpbox", args, n);

	knopf = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
	XtUnmanageChild (knopf);
	knopf = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
	XtUnmanageChild (knopf);


	/*	Free strings and return MessageBox.
	*/
	if (title_string) XtFree (title_string);
	if (message_string) XtFree (message_string);
	if (knopf_string) XtFree (knopf_string);
	return (message_box);
}

Help(message)
char message[];
{
Widget w;
w = CreateHelp(message);
XtManageChild(w);
}

/*-------------------------------------------------------------
**	CreateStringBox		- create string input window
*/
Widget	CreateStringBox (title) 
	char title[];
{
	Widget		knopf;
	Arg		args[20];	/*  arg list		*/
	register int	n;		/*  arg count		*/

	XmString	title_string = NULL;


	title_string = XmStringCreateLtoR (title, XmSTRING_DEFAULT_CHARSET);

	/*	Create MessageBox dialog.
	*/
	n = 0;
	XtSetArg (args[n], XmNdialogTitle, title_string);  n++;
	dialog_box = (Widget) XmCreatePromptDialog (main_window, "stringbox", args, n);

	XtAddCallback (dialog_box, XmNokCallback,activateCB, -1);

	/*	Free strings and return MessageBox.
	*/
	if (title_string) XtFree (title_string);
	return (dialog_box);
}

/* TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK

   Since Xwindows only works from within the XtMainloop (building boxes,
   watching mouse actions ...) it seemd to be impossible to write
   JUST a function, which returns anything from a box, and then continues
   with the program. The only way around this is a very dirty trick:
   we store the address of our function with setjmp before giving controll
   to XtMainloop, and after processing in our callback routine, longjmp
   goes back to were we started.

   TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK TRICK */

StringBox(message,rtstr)
char message[],rtstr[];
{
Widget w;
w = CreateStringBox(message);
if(setjmp(ugly)==0) {
   XtManageChild(w);
   XtAppMainLoop (app_context);
} else {
   strcpy(rtstr,return_string);
}
}

/*-------------------------------------------------------------
**	CreateFileSelect	- create file selection window
*/
Widget	CreateFileSelect (dir) 
	char dir[];
{
	Widget		knopf;
	Arg		args[10];	/*  arg list		*/
	register int	n;		/*  arg count		*/

	XmString	title_string = NULL;


	title_string = XmStringCreateLtoR (dir, XmSTRING_DEFAULT_CHARSET);

	/*	Create MessageBox dialog.
	*/
	n = 0;
	XtSetArg (args[n], XmNdialogTitle, title_string);  n++;
	dialog_box = (Widget) XmCreateFileSelectionDialog (main_window,
			 "fsel_box", args, n);

	XtAddCallback (dialog_box, XmNokCallback,activateCB, -1);

	knopf = (Widget) XmFileSelectionBoxGetChild (dialog_box, XmDIALOG_HELP_BUTTON);
	XtUnmanageChild (knopf);


	/*	Free strings and return MessageBox.
	*/
	if (title_string) XtFree (title_string);
	return (dialog_box);
}

FileSelect(message,rtstr)
char message[],rtstr[];
{
Widget w;
w = CreateFileSelect(message);
if(setjmp(ugly)==0) {
   XtManageChild(w);
   XtAppMainLoop (app_context);
} else {
   strcpy(rtstr,return_string);
}
}

/* -------------------------------------------------------------------

   look for altered variables and assotiated gadgets, Update Gadgets
   (Writes back altered wariables to Gadgets)

   ------------------------------------------------------------------- */

UpdateGadgets()            /* NEW! */
{
int	n,m,i;

/* first set all toggle buttons */
   for(n=0;n<toggle_ptr;n++) {
      m=toggle_var[n];
      i = *var_value[m];
      XmToggleButtonGadgetSetState(Wtoggle[n],i);
   }
      
/* now set all sliders */
   for(n=0;n<scale_ptr;n++) {
      m=scale_var[n];
      i = *var_value[m];
      XmScaleSetValue(Wscale[n],i);
   }

/* now set all strings */
   for(n=0;n<string_ptr;n++) {
      m=string_var[n];
      XmTextSetString(Wstring[n],var_value[m]);
   }
}


/* -------------------------------------------------------------
    add an item to the menu list
   ------------------------------------------------------------- */
add_item(x,y,type,text,p1,p2)
int x,y,type,p1,p2;
char text[];
{
int i,m;
Widget button;
Widget knopf;
XmString label_string;
Arg	args[10]; /*  arg list		*/
register int n;	/*  arg count		*/
char s1[80];
XmString item[80];

   var_funct[fn_number] = type;

/* check, if position has to be adjusted */
   if(x != -1) acc_x = x;
   if(y != -1) acc_y = y;

/* do string parsing for SELECTION box */
   extract_str(s1,text,0,',');
	label_string = 
           XmStringCreateLtoR(s1, XmSTRING_DEFAULT_CHARSET);
	n = 0;
	XtSetArg (args[n], XmNlabelString, label_string);  n++;
   i=1; m=1;
   while(m>0) {
      m = extract_str(s1,text,i,',');
      if(strlen(s1)==0) break;
      item[i-1] = XmStringCreateLtoR(s1,XmSTRING_DEFAULT_CHARSET);
      i++;
   }
   item[i-1] = NULL;

/* set position */
	XtSetArg (args[n], XmNx,acc_x); n++;
	XtSetArg (args[n], XmNy,acc_y); n++;

   switch(type) {

   case PUSH:
	XtSetArg (args[n], XmNlabelType, XmSTRING);  n++; 
	button = XmCreatePushButtonGadget(row_column,text , args, n);
	XtAddCallback (button, XmNactivateCallback, 
          activateCB, (caddr_t)fn_number);
	acc_y = acc_y + (8 * bas_y);
	break;

   case TOGGLE:
	if(radio==NULL) radio = row_column;
	button = XmCreateToggleButtonGadget(radio,text , args, n);
	toggle_var[toggle_ptr] = fn_number;
	Wtoggle[toggle_ptr++] = button;
	acc_y = acc_y + (5 * bas_y);
	break;

   case SCALEX:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
	XtSetArg (args[n], XmNorientation, XmHORIZONTAL);  n++;
	XtSetArg (args[n], XmNshowValue, True);  n++;
	XtSetArg (args[n], XmNminimum,p1);  n++;
	XtSetArg (args[n], XmNmaximum,p2);  n++;
	button = XmCreateScale(row_column,text , args, n);
	scale_var[scale_ptr] = fn_number;
	Wscale[scale_ptr++] = button;
	acc_y = acc_y + (15 * bas_y);
	break;

   case SCALEY:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
	XtSetArg (args[n], XmNorientation, XmVERTICAL);  n++;
	XtSetArg (args[n], XmNshowValue, True);  n++;
	XtSetArg (args[n], XmNminimum,p1);  n++;
	XtSetArg (args[n], XmNmaximum,p2);  n++;
	button = XmCreateScale(row_column,text , args, n);
	scale_var[scale_ptr] = fn_number;
	Wscale[scale_ptr++] = button;
	acc_y = acc_y + (30 * bas_y);
	break;

   case SCALEY11:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
	XtSetArg (args[n], XmNorientation, XmVERTICAL);  n++;
	XtSetArg (args[n], XmNshowValue, True);  n++;
	XtSetArg (args[n], XmNminimum,p1);  n++;
	XtSetArg (args[n], XmNmaximum,p2);  n++;
	XtSetArg (args[n], XmNheight,(p2-p1));  n++;
	button = XmCreateScale(row_column,text , args, n);
	scale_var[scale_ptr] = fn_number;
	Wscale[scale_ptr++] = button;
	acc_y = acc_y + (30 * bas_y);
	break;

   case SCALEX11:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
	XtSetArg (args[n], XmNorientation, XmHORIZONTAL);  n++;
	XtSetArg (args[n], XmNshowValue, True);  n++;
	XtSetArg (args[n], XmNminimum,p1);  n++;
	XtSetArg (args[n], XmNmaximum,p2);  n++;
	XtSetArg (args[n], XmNwidth,(p2-p1));  n++;
	button = XmCreateScale(row_column,text , args, n);
	scale_var[scale_ptr] = fn_number;
	Wscale[scale_ptr++] = button;
	acc_y = acc_y + (15 * bas_y);
	break;

   case SELECTION:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
	XtSetArg (args[n], XmNlistLabelString, label_string);  n++;
	XtSetArg (args[n], XmNminimizeButtons,True);  n++;
	XtSetArg (args[n], XmNlistItemCount,i-1);  n++;
	XtSetArg (args[n], XmNlistItems,item); n++;
	button = XmCreateSelectionBox(row_column,text , args, n);
	knopf = XmMessageBoxGetChild (button, XmDIALOG_CANCEL_BUTTON);
	XtUnmanageChild (knopf); /* get rid of unneeded buttons */
	XtAddCallback (button, XmNokCallback, 
          activateCB, (caddr_t)fn_number);
	selector[selector_ptr++] = fn_number;
	acc_y = acc_y + (75 * bas_y);
	break;

   case RADIO:
	radio = (Widget) XmCreateRadioBox(row_column,text, args, n);
	XtManageChild (radio);
	return(0);
	break;

   case FILE_SELECT:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
	XtSetArg (args[n], XmNlistLabelString, label_string);  n++;
	button = (Widget) XmCreateFileSelectionBox(row_column,text , args, n);
	knopf = (Widget) XmFileSelectionBoxGetChild (button, XmDIALOG_CANCEL_BUTTON);
	XtUnmanageChild (knopf); /* get rid of unneeded buttons */
	knopf = (Widget) XmFileSelectionBoxGetChild (button, XmDIALOG_HELP_BUTTON);
	XtUnmanageChild (knopf);
	XtAddCallback (button, XmNokCallback, 
          activateCB, (caddr_t)fn_number);
	selector[selector_ptr++] = fn_number;
	acc_y = acc_y + (90 * bas_y);
	break;

   case STRING:
	XtSetArg (args[n], XmNtitleString, label_string);  n++;
        XtSetArg (args[n], XmNeditable, True); n++;
        XtSetArg (args[n], XmNeditMode, XmSINGLE_LINE_EDIT); n++;
        XtSetArg (args[n], XmNscrollVertical, False); n++;
        XtSetArg (args[n], XmNscrollHorizontal, False); n++;
	button = (Widget) XmCreateScrolledText(row_column,text , args, n);
	XtAddCallback (button, XmNactivateCallback, 
          activateCB, (caddr_t)fn_number);
	string_var[string_ptr] = fn_number;
	Wstring[string_ptr++] = button;
	acc_y = acc_y + (15 * bas_y);
	break;

   case MENU:
	button = XmCreatePushButton (menu_pane, label_string, args, n);
	XtAddCallback (button, XmNactivateCallback, 
 		activateCB, (caddr_t)fn_number);
	break;

   case NEW_MENU:
	n = 0;
	label_string = 
           XmStringCreateLtoR(menu_name, XmSTRING_DEFAULT_CHARSET);
	XtSetArg (args[n], XmNlabelString, label_string);  n++;
	XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
	XtSetArg(args[n], XmNlabelString,
		label_string);
	cascade = XmCreateCascadeButton (menu_bar,label_string,args,n);
	XtManageChild (cascade);
	n = 0;
	menu_pane = XmCreatePulldownMenu (menu_bar, "menu_pane", args, n);
	strcpy(menu_name,text);
	return(0);
	break;
   default:
	return(0);
	break;
   }
   
/*  start managing button */
	  XtManageChild(button);
}


/*-------------------------------------------------------------
**	activateCB - callback for button
*/
void activateCB (w, client_data, call_data) 
Widget	w;		/*  widget id		*/
caddr_t	client_data;	/*  data from application   */
caddr_t	call_data;	/*  data from widget class  */
{
int	fn;
int	n,m,i;
char	*cbstr;
char	rtstr[80];

/* first read all toggle buttons */
   for(n=0;n<toggle_ptr;n++) {
      i=XmToggleButtonGadgetGetState(Wtoggle[n]);
      m=toggle_var[n];
      *var_value[m] = i;
   }
      
/* now read all sliders */
   for(n=0;n<scale_ptr;n++) {
      XmScaleGetValue(Wscale[n],&i);
      m=scale_var[n];
      *var_value[m] = i;
   }

/* now read all strings */
   for(n=0;n<string_ptr;n++) {
      m=string_var[n];
      cbstr = (char *) XmTextGetString(Wstring[n]);
      strcpy(var_value[m],cbstr);
      XtFree(cbstr);
   }


   fn = (int) client_data;
   last_gadgetid = fn;

/* process callback from dialog box */
   if(fn<0) {
          {
             XmSelectionBoxCallbackStruct *scb =
                (XmSelectionBoxCallbackStruct *) call_data;
             XmStringGetLtoR(scb->value, XmSTRING_DEFAULT_CHARSET, &cbstr);
          }
          strcpy(return_string,cbstr);
	  XtUnmanageChild(dialog_box);
          longjmp(ugly,1);
   }



/* if call from selection box, the catch string */
   for(n=0;n<selector_ptr;n++) {
      if(selector[n] == fn) {
          {
             XmSelectionBoxCallbackStruct *scb =
                (XmSelectionBoxCallbackStruct *) call_data;
             XmStringGetLtoR(scb->value, XmSTRING_DEFAULT_CHARSET, &cbstr);
             strcpy(var_value[fn],cbstr);
          }
      }
   }
   (*fn_command[fn])();
   UpdateGadgets();
}


dummy()
{
return(0);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      Dummy functions for amiga compatibility
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

Refresh1Gadget(i)
int i;
{
   return;
}


DrawAllPropBorders(i)
int i;
{
   return;
}

set_new_pointer()
{
   return;
}

set_old_pointer()
{
   return;
}

RequestYesNo(s)
char *s;
{
   return(0);
}

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

   S T R I N G H A N D L I N G

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

/* --------------------------------------------------
   reurns in s1 s2 from nth occurence of c up to c
   -------------------------------------------------- */

extract_str(s1,s2,n,c)
char s1[],s2[],c;
int n;
{
int m,i,l;
char c1;

   m=0; l=strlen(s2);
   i = 0;
   if(n > 0) {
      for(i=0;i<l;i++) {
          c1=s2[i];
          if(c1 == c) m++;
          if(m == n) break;
      }
      s1[0] = 0;
      if(c1 != c) return(-1);
      i++;
   }
   m=0;
   while(i<l) {
      c1 = s2[i++];
      if(c1 == c) break;
      s1[m++] = c1;
   }
   s1[m] = 0;
   if(strlen(s1)==0) return(-1);
   return(1);
}

