/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:	grid.c							*
 *									*
 * Description:	This file contains the public and private function and	*
 *		type definitions for the grid generation control	*
 *		dialog box.						*
 ************************************************************************/

# include <stdio.h>
# include <X11/Intrinsic.h>
# include <X11/StringDefs.h>
# include <X11/Shell.h>
# include <X11/Xaw/AsciiText.h>
# include <X11/Xaw/Command.h>
# include <X11/Xaw/Label.h>
# include <X11/Xaw/MenuButton.h>
# include <X11/Xaw/SimpleMenu.h>
# include <X11/Xaw/SmeBSB.h>
# include "Layout.h"
# include "Grid.h"
# include "TabGroup.h"
# include "util.h"
# include "post.h"
# include "mesh.h"
# include "code.h"
# include "error.h"

# ifndef X_NOT_STDC_ENV
# include <stdlib.h>
# endif

# define WaitState 0
# define OkayState 1
# define CancelState 2

static String rule_names [] = {
   "linear",
   "cosinusoidal",
   "sinusoidal",
   "logarithmic",
   "reverse-logarithmic",
   "parabolic",
   "reverse-parabolic"
};

struct grid_dialog {
    Widget         shell;	   /* topLevelShell  <specified>	*/
    Widget         layout;	   /*	Layout  layout		   	*/
    Widget         start [3];	   /*	     AsciiText  start{i}   	*/
    Widget         end [3];	   /*	     AsciiText  end{i} 		*/
    Widget   	   number [3];	   /*	     AsciiText  number{i}	*/
    Widget   	   rule [3];	   /*	     AsciiText  rule{i}		*/
    Widget         rule_button;    /*	     MenuButton  rule_button    */
    Widget         rule_menu;      /*	       SimpleMenu  rule_menu	*/
    Widget         help;	   /*	     MenuButton  help	   	*/
    Widget         okay;	   /*	     Command  okay	   	*/
    Widget         cancel;	   /*	     Command  cancel	   	*/
    Grid	   gr;
    int		   status;
};

static String labels [ ] = {
    "x", "y", "z", "start", "end", "number" 
};

static String names [ ] = {
    "xLabel", "yLabel", "zLabel", "startLabel", "endLabel", "numberLabel" 
};


/* Resources */

static Pixel highlight;

static String layout_string = 
"vertical { \
     horizontal { \
        vertical { \
           8 \
           height startLabel \
           8 \
           ((height start1 - height xLabel) / 2) \
           xLabel \
           ((height start1 - height xLabel) / 2) \
           8 \
           ((height start2 - height yLabel) / 2) \
           yLabel \
           ((height start2 - height yLabel) / 2) \
           8 \
           ((height start3 - height zLabel) / 2) \
           zLabel \
           ((height start3 - height zLabel) / 2) \
           8 \
        } \
        8 \
        vertical { \
           8 \
           horizontal { \
              ((width start1 - width startLabel) / 2) \
              startLabel \
              ((width start1 - width startLabel) / 2) \
           } \
           8 \
           start1 \
           8 \
           start2 \
           8 \
           start3 \
           8 \
        } \
        8 \
        vertical { \
           8 \
           horizontal { \
              ((width end1 - width endLabel) / 2) \
              endLabel \
              ((width end1 - width endLabel) / 2) \
           } \
           8 \
           end1 \
           8 \
           end2 \
           8 \
           end3 \
           8 \
        } \
        8 \
        vertical { \
           8 \
           horizontal { \
              ((width number1 - width numberLabel) / 2) \
              numberLabel \
              ((width number1 - width numberLabel) / 2) \
           } \
           8 \
           number1 \
           8 \
           number2 \
           8 \
           number3 \
           8 \
        } \
        8 \
        vertical { \
           8 \
           ((height numberLabel - height rule_button) / 2) \
           horizontal { \
              ((width rule1 - width rule_button) / 2) \
              rule_button \
              ((width rule1 - width rule_button) / 2) \
           } \
           ((height numberLabel - height rule_button) / 2) \
           8 \
           rule1 \
           8 \
           rule2 \
           8 \
           rule3 \
           8 \
        } \
     } \
     4 \
     separator <+inf -100% *> \
     4 \
     horizontal { \
        4 \
        help \
        4 <+inf -100%> \
        okay \
        4 <+inf -100%> \
        cancel \
        4 \
     } \
     4 \
}";

static Arg color_args [ ] = {
    {XtNborderColor, (XtArgVal) &highlight},
};

static Arg shell_args [ ] = {
    {XtNtitle,    (XtArgVal) NULL},
    {XtNiconName, (XtArgVal) NULL},
};

static Arg layout_args [ ] = {
    {XtNlayout, (XtArgVal) NULL},
};

static Arg text_args [ ] = {
    {XtNeditType,    (XtArgVal) XawtextEdit},
    {XtNborderWidth, (XtArgVal) 0},
    {XtNpieceSize,   (XtArgVal) 32},
    {XtNcursorName,  (XtArgVal) "left_ptr"},
};

static Arg label_args [ ] = {
    {XtNlabel,       (XtArgVal) ""},
    {XtNborderWidth, (XtArgVal) 0},
};

static Arg core_args [ ] = {
    {XtNwidth,  (XtArgVal) 3},
    {XtNheight, (XtArgVal) 3},
};

static Arg button_args [ ] = {
    {XtNlabel,       (XtArgVal) ""},
    {XtNmenuName,    (XtArgVal) ""},
    {XtNborderWidth, (XtArgVal) 0},
};


/* Translation tables */

static String text_table =
"<Key>Return: GridDialogAction(okay)\n\
 <Key>Escape: GridDialogAction(cancel)\n\
 Ctrl<Key>h:  GridDialogAction(help)\n\
 <Btn1Down>:  SetFocus() select-start()";

static XtTranslations text_translations;


static String button_table =
"<Key>Return: GridDialogAction(okay)\n\
 <Key>Escape: GridDialogAction(cancel)\n\
 Ctrl<Key>h:  GridDialogAction(help)\n\
 <BtnDown>:   PostMenu()\n\
 <Key>space:  PostMenu()";

static XtTranslations button_translations;


static String command_table =
"<Key>Return:  GridDialogAction(okay)\n\
 <Key>Escape:  GridDialogAction(cancel)\n\
 Ctrl<Key>h:   GridDialogAction(help)\n\
 <Key>space:   AutoRepeat(off) set()\n\
 <KeyUp>space: AutoRepeat(saved) notify() unset()";

static XtTranslations command_translations;


static String help_table =
"<Key>Return: GridDialogAction(okay)\n\
 <Key>Escape: GridDialogAction(cancel)\n\
 Ctrl<Key>h:  GridDialogAction(help)\n\
 <Key>space:  PostMenu()";

static XtTranslations help_translations;


/* Help message. */

static String help_message ="\
Use this form to define the parameters for grids of line, quadrilateral, \
and brick elements.  The start and end coordinates define the two opposite \
corners of the grid to generate.  The number and rule entries define \
how many elements, and which spacing rule to use in generating the elements, \
wll be generated along each of the three axes.";


/************************************************************************
 * Function:	Action							*
 *									*
 * Description:	An action procedure which emulates pressing of the	*
 *		specified button.					*
 ************************************************************************/

static void Action (w, event, params, num_params)
    Widget    w;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
{
    if (XtClass (w) == topLevelShellWidgetClass)
	w = XtNameToWidget (w, "layout.cancel");
    else
	w = XtNameToWidget (XtParent (w), params [0]);

    if (!strcmp (XtName (w), "help"))
	XtCallActionProc (w, "PostMenu", event, NULL, 0);
    else
	XtCallCallbacks (w, XtNcallback, NULL);
}


/************************************************************************
 * Function:	ChangeRule
 *	
 * Description:	 
 ************************************************************************/

static void ChangeRule (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    GridDialog  gridd;
    Widget      current_rule;
    int	        i;


    if (!(w = XawSimpleMenuGetActiveEntry (w)))
        return;

    gridd = (GridDialog) client_data;

    current_rule = GetFocus (gridd -> start [0]);

    for (i = 0 ; i < 3 ; i++) 
       if (current_rule == gridd -> rule [i])
          break;

    if (i == 3)
       return;

    SetTextString (current_rule, GetLabelString (w));
}


/************************************************************************
 * Function:	Okay							*
 *									*
 * Description:								*
 ************************************************************************/

static void Okay (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    GridDialog   gridd;


    gridd = (GridDialog) client_data;
    gridd -> status = OkayState;
}


/************************************************************************
 * Function:	Cancel							*
 *									*
 * Description:	sets the cancel flag					*
 ************************************************************************/

static void Cancel (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    GridDialog gridd;

    gridd = (GridDialog) client_data;
    gridd -> status = CancelState;
}

static int MatchRuleName (name)
   String	name;
{
   int	i;

   if (strcmp(name, "") == 0)
      return 0;			/* default - linear rule */

   for (i = 0 ; i < XtNumber (rule_names) ; i++) 
      if (strcmp(rule_names [i], name) == 0)
         return i;

   return -1;
}

/************************************************************************
 * Function:	GridDialogSet						*
 *									*
 * Description:	fills the Grid structure based on the text fields	*
 ************************************************************************/

static int GridDialogSet (gridd)
    GridDialog	gridd;
{
    Arg		args [1];
    String	value;
    int		rule;

    XtSetArg (args [0], XtNstring, &value);

    XtGetValues (gridd -> start [0], args, 1); 
    gridd -> gr -> xs = exptod (value, NULL);

    XtGetValues (gridd -> start [1], args, 1); 
    gridd -> gr -> ys = exptod (value, NULL);

    XtGetValues (gridd -> start [2], args, 1); 
    gridd -> gr -> zs = exptod (value, NULL);

    XtGetValues (gridd -> end [0], args, 1); 
    gridd -> gr -> xe = exptod (value, NULL);

    XtGetValues (gridd -> end [1], args, 1); 
    gridd -> gr -> ye = exptod (value, NULL);

    XtGetValues (gridd -> end [2], args, 1); 
    gridd -> gr -> ze = exptod (value, NULL);

    XtGetValues (gridd -> number [0], args, 1); 
    gridd -> gr -> xnumber = exptod (value, NULL);

    XtGetValues (gridd -> number [1], args, 1); 
    gridd -> gr -> ynumber = exptod (value, NULL);

    XtGetValues (gridd -> number [2], args, 1); 
    gridd -> gr -> znumber = exptod (value, NULL);

    XtGetValues (gridd -> rule [0], args, 1); 
    rule = MatchRuleName (value);
    if (rule == -1) {
       error ("%s is an invalid rule name", value);
       return 1;
    }
    else
       gridd -> gr -> xrule = rule;
  
    XtGetValues (gridd -> rule [1], args, 1); 
    rule = MatchRuleName (value);
    if (rule == -1) {
       error ("%s is an invalid rule name", value);
       return 1;
    }
    else
       gridd -> gr -> yrule = rule;

    XtGetValues (gridd -> rule [2], args, 1); 
    rule = MatchRuleName (value);
    if (rule == -1) {
       error ("%s is an invalid rule name", value);
       return 1;
    }
    else
       gridd -> gr -> zrule = rule;

    return 0;
}

/************************************************************************
 * Function:	GridDialogCreate					*
 *									*
 * Description:	Creates a new grid dialog.  You would never want to	*
 *		have more than one of these but the interface is kept	*
 *		consistent with those of the other dialogs.		*
 ************************************************************************/

GridDialog GridDialogCreate (parent, name, title)
    Widget	   parent;
    String	   name;
    String	   title;
{
    Cardinal		i;
    char		buffer [128];
    Arg			args [2];
    Widget		group [15];
    GridDialog		gridd;
    Dimension		width;
    Position		x;
    static XtAppContext	app_context = NULL;
    static XtActionsRec	actions [ ] = {{"GridDialogAction", Action}};


    /* Perform one time initialization. */

    if (app_context == NULL) {
	app_context = XtWidgetToApplicationContext (parent);
	XtAppAddActions (app_context, actions, XtNumber (actions));
	AddAutoRepeatAction (app_context);

        layout_args [0].value = StringToLayout (parent, layout_string);

	text_translations     = XtParseTranslationTable (text_table);
	command_translations  = XtParseTranslationTable (command_table);
	help_translations     = XtParseTranslationTable (help_table);
	button_translations   = XtParseTranslationTable (button_table);
    }


    /* Create the grid dialog and its widgets. */

    XtSetArg (shell_args [0], XtNtitle, title);
    XtSetArg (shell_args [1], XtNiconName, title);

    gridd = XtNew (struct grid_dialog);
   
    gridd -> gr = XtNew (struct _grid);

    gridd -> shell    = XtCreatePopupShell (name,
			 topLevelShellWidgetClass, parent,
			 shell_args, XtNumber (shell_args));

    gridd -> layout   = XtCreateManagedWidget ("layout",
			 layoutWidgetClass, gridd -> shell,
			 layout_args, XtNumber (layout_args));

    for (i = 0 ; i < 3 ; i++) {
       sprintf (buffer,"start%d", i+1);
       gridd -> start [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, gridd -> layout,
			 text_args, XtNumber (text_args));

       sprintf (buffer,"end%d", i+1);
       gridd -> end [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, gridd -> layout,
			 text_args, XtNumber (text_args));

       sprintf (buffer,"number%d", i+1);
       gridd -> number [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, gridd -> layout,
			 text_args, XtNumber (text_args));

       sprintf (buffer,"rule%d", i+1);
       gridd -> rule [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, gridd -> layout,
			 text_args, XtNumber (text_args));

    }

    gridd -> rule_menu = XtCreateManagedWidget ("rule_menu",
			 simpleMenuWidgetClass, gridd -> layout,
			 NULL, 0);

    XtSetArg (button_args [0], XtNlabel,    "rule");
    XtSetArg (button_args [1], XtNmenuName, "rule_menu");

    gridd -> rule_button = XtCreateManagedWidget ("rule_button",
			 menuButtonWidgetClass, gridd -> layout,
			 button_args, XtNumber (button_args));

    for (i = 0 ; i < XtNumber (rule_names) ; i++)
       XtCreateManagedWidget (rule_names [i], smeBSBObjectClass,
                              gridd -> rule_menu, NULL, 0);

    AddPostMenuActions (gridd -> rule_menu);

    gridd -> okay   = XtCreateManagedWidget ("okay",
			 commandWidgetClass, gridd -> layout,
			 NULL, 0);

    gridd -> cancel  = XtCreateManagedWidget ("cancel",
			 commandWidgetClass, gridd -> layout,
			 NULL, 0);

    gridd -> help     = CreateHelpButton (gridd -> layout, "help");

    for (i = 0; i < XtNumber (labels); i ++) {
	label_args [0].value = (XtArgVal) labels [i];
	XtCreateManagedWidget (names [i], labelWidgetClass,
		gridd -> layout, label_args, XtNumber (label_args));
    }


    XtCreateManagedWidget ("separator", coreWidgetClass,
			gridd -> layout, core_args, XtNumber (core_args));



    /* Create a tab group for the grid dialog. */

    i = 0;
    group [i++]  = gridd -> start [0];
    group [i++]  = gridd -> start [1];
    group [i++]  = gridd -> start [2];
    group [i++]  = gridd -> end [0];
    group [i++]  = gridd -> end [1];
    group [i++]  = gridd -> end [2];
    group [i++]  = gridd -> number [0];
    group [i++]  = gridd -> number [1];
    group [i++]  = gridd -> number [2];
    group [i++]  = gridd -> rule [0];
    group [i++]  = gridd -> rule [1];
    group [i++]  = gridd -> rule [2];
    group [i++]  = gridd -> help;
    group [i++]  = gridd -> okay;
    group [i++] = gridd -> cancel;

    XtGetValues (gridd -> layout, color_args, XtNumber (color_args));
    CreateTabGroup (gridd -> shell, group, XtNumber (group), highlight, True);
    XtRealizeWidget (gridd -> shell);
    SetFocus (gridd -> start [0]);

    XtSetArg (args [0], XtNwidth, &width);
    XtGetValues (gridd -> layout, args, 1);
    XtSetArg (args [0], XtNx, &x);
    XtGetValues (gridd -> help, args, 1);
    UpdateHelpMessage (gridd -> help, help_message, width - 2 * x);


    /* Add the translations to each widget. */

    AddDeleteWindowProtocol   (gridd -> shell, "GridDialogAction()");

    for (i = 0 ; i < 3 ; i++) {
       XtOverrideTranslations (gridd -> start [i],  text_translations);
       XtOverrideTranslations (gridd -> end [i],    text_translations);
       XtOverrideTranslations (gridd -> number [i], text_translations);
       XtOverrideTranslations (gridd -> rule [i],   text_translations);
    }

    XtOverrideTranslations (gridd -> rule_button, button_translations);

    XtOverrideTranslations (gridd -> okay,    command_translations);
    XtOverrideTranslations (gridd -> cancel,   command_translations);
    XtOverrideTranslations (gridd -> help,	    help_translations);


    /* Add the necessary callbacks. */

    XtAddCallback (gridd -> okay,  XtNcallback, Okay,  (XtPointer) gridd);
    XtAddCallback (gridd -> cancel, XtNcallback, Cancel, (XtPointer) gridd);
    XtAddCallback (gridd -> rule_menu, XtNpopdownCallback, ChangeRule, (XtPointer) gridd); 

    return gridd;
}

/************************************************************************
 * Function:	GridDialogPopup						*
 *									*
 * Description:	Pops up the specified material dialog.			*
 ************************************************************************/

Grid GridDialogPopup (gridd)
    GridDialog gridd;
{
    XEvent	 event;
    XtAppContext app_context;
    
    app_context = XtWidgetToApplicationContext (gridd -> shell);

    XtPopup (gridd -> shell, XtGrabExclusive);
    gridd -> status = WaitState;

    while (gridd -> status == WaitState) {
       XtAppNextEvent (app_context, &event);
       XtDispatchEvent (&event);
    }

    XtPopdown (gridd -> shell);

    if (gridd -> status == CancelState)
       return NULL;
    else {
       if (!GridDialogSet (gridd))
          return gridd -> gr;
       else
          return GridDialogPopup (gridd);
    }
}


syntax highlighted by Code2HTML, v. 0.9.1