/*
    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:	loadcase.c						*
 *									*
 * Description:	This file contains the public and private function and	*
 *		type definitions for the loadcase 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/List.h>
# include <X11/Xaw/Viewport.h>
# include <X11/Xaw/MenuButton.h>
# include <X11/Xaw/Repeater.h>
# include <X11/Xaw/SimpleMenu.h>
# include <X11/Xaw/SmeBSB.h>
# include "Layout.h"
# include "LoadCase.h"
# include "TabGroup.h"
# include "util.h"
# include "objects.h"
# include "post.h"
# include "problem.h"
# include "allocate.h"
# include "error.h"

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


struct loadcase_dialog {
    Widget         shell;	   /* topLevelShell  <specified>	*/
    Widget         layout;	   /*	Layout  layout		   	*/
    Widget         name;	   /*	     AsciiText  name   	   	*/
    Widget         node [4];	   /*	     AsciiText  node{i}	   	*/
    Widget         element [4];	   /*	     AsciiText  element{i} 	*/
    Widget   	   force [4];	   /*	     AsciiText  force{i}	*/
    Widget   	   load [4];	   /*	     AsciiText  load{i}		*/
    Widget         force_button;   /*	     MenuButton  force_button   */
    Widget         force_menu;     /*	       SimpleMenu  force_menu	*/
    Widget         load_button;    /*	     MenuButton  load_button    */
    Widget         load_menu;      /*	       SimpleMenu  load_menu  	*/
    Widget         node_up;	   /*	     Command  node_up	   	*/
    Widget         node_down;	   /*	     Command  node_down	   	*/
    Widget	   element_up;	   /*	     Command  element_up   	*/
    Widget	   element_down;   /*	     Command  element_down 	*/
    Widget         viewport;	   /*	     Viewport viewport	   	*/
    Widget         list;	   /*	       List     list	   	*/
    Widget         help;	   /*	     MenuButton  help	   	*/
    Widget         accept;	   /*	     Command  accept	   	*/
    Widget         dismiss;	   /*	     Command  dismiss	   	*/
    Widget         delete;	   /*	     Command  delete	   	*/
    Widget         new;		   /*	     Command  new	   	*/
    Widget         copy;	   /*	     Command  copy	   	*/
    String	  *loadcases;
    LoadCase	   active;
    Boolean        new_copy;
    Tree           tree;
    unsigned	   node_base;
    unsigned	   element_base;
    String	   force_assignments [100];
    unsigned	   node_assignments [100];
    String	   load_assignments [100];
    unsigned       element_assignments [100];
    unsigned       num_forces;
    unsigned       num_loads;
};

static String labels [ ] = {
    "Name:", "node", "element"
};

static String names [ ] = {
    "nameLabel", "nodeLabel", "elementLabel"
};

static LoadCaseDialog  dialog;
static Cardinal	       num_loadcases;
static int	       list_index;


/* Bitmaps */

#define up_width 12
#define up_height 12
static char up_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xf0, 0x00, 0xf8, 0x01,
   0xfc, 0x03, 0xfe, 0x07, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

#define down_width 12
#define down_height 12
static char down_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0xfe, 0x07, 0xfc, 0x03,
   0xf8, 0x01, 0xf0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static Pixmap up_bitmap;
static Pixmap down_bitmap;


/* Resources */

static Pixel highlight;

static String dummy_list [ ] = {
    NULL
};

static String layout_string = 
"vertical { \
     horizontal { \
 	4 \
 	vertical { \
	    4 \
 	    horizontal { \
 		nameLabel \
 		4 \
 		name <+inf -100% *> \
 	    } \
 	    4 \
 	    viewport <+inf * +inf> \
 	    4 \
 	} \
 	12 \
	separator1 <* +inf -100%> \
        12 \
        vertical { \
            4 \
            horizontal { \
               ((width node1 - width nodeLabel) / 2) \
               nodeLabel \
               ((width node1 - width nodeLabel) / 2) \
	       16 \
               ((width force1 - width force_button) / 2) \
               force_button <+inf -100% *> \
               ((width force1 - width force_button) / 2) \
            } \
            4 \
            horizontal { \
               node1 \
               16 \
               force1 <+inf -100% *> \
            } \
            4 \
            horizontal { \
               node2 \
               16 \
               force2 <+inf -100% *> \
            } \
            4 \
            horizontal { \
               node3 \
               16 \
               force3 <+inf -100% *> \
            } \
            4 \
            horizontal { \
               node4 \
               16 \
               force4 <+inf -100% *> \
            } \
            8 \
            horizontal { \
               node_down \
               4 \
               node_up \
            } \
            4 \
        } \
        12 \
	separator3 <* +inf -100%> \
        12 \
        vertical { \
            4 \
            horizontal { \
               ((width element1 - width elementLabel) / 2) \
               elementLabel \
               ((width element1 - width elementLabel) / 2) \
	       16 \
               ((width load1 - width load_button) / 2) \
               load_button <+inf -100% *> \
               ((width load1 - width load_button) / 2) \
            } \
            4 \
            horizontal { \
               element1 \
               16 \
               load1 <+inf -100% *> \
            } \
            4 \
            horizontal { \
               element2 \
               16 \
               load2 <+inf -100% *> \
            } \
            4 \
            horizontal { \
               element3 \
               16 \
               load3 <+inf -100% *> \
            } \
            4 \
            horizontal { \
               element4 \
               16 \
               load4 <+inf -100% *> \
            } \
            8 \
            horizontal { \
               element_down \
               4 \
               element_up \
            } \
            4 \
        } \
        12 \
     } \
     separator2 <+inf -100% *> \
     4 \
     horizontal { \
 	4 \
 	help \
 	4 <+inf -100%> \
 	accept \
 	4 <+inf -100%> \
 	dismiss \
 	4 <+inf -100%> \
 	delete \
 	4 <+inf -100%> \
 	new \
 	4 <+inf -100%> \
 	copy \
 	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 viewport_args [ ] = {
    {XtNallowVert,   (XtArgVal) True},
    {XtNforceBars,   (XtArgVal) True},
    {XtNborderWidth, (XtArgVal) 0},
};

static Arg list_args [ ] = {
    {XtNdefaultColumns, (XtArgVal) 1},
    {XtNforceColumns,   (XtArgVal) 1},
    {XtNresize,		(XtArgVal) True},
    {XtNlist,		(XtArgVal) dummy_list},
};

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

static Arg name_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 repeater_args [ ] = {
    {XtNbitmap, (XtArgVal) NULL},
};


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


/* Translation tables */

static String text_table =
"<Key>Return: LoadCaseDialogAction(accept)\n\
 <Key>Escape: LoadCaseDialogAction(dismiss)\n\
 Ctrl<Key>d:  LoadCaseDialogAction(delete)\n\
 Ctrl<Key>c:  LoadCaseDialogAction(copy)\n\
 Ctrl<Key>n:  LoadCaseDialogAction(new)\n\
 Ctrl<Key>h:  LoadCaseDialogAction(help)\n\
 <Btn1Down>:  SetFocus() select-start()";

static XtTranslations text_translations;


static String button_table =
"<Key>Return: LoadCaseDialogAction(accept)\n\
 <Key>Escape: LoadCaseDialogAction(dismiss)\n\
 Ctrl<Key>d:  LoadCaseDialogAction(delete)\n\
 Ctrl<Key>c:  LoadCaseDialogAction(copy)\n\
 Ctrl<Key>n:  LoadCaseDialogAction(new)\n\
 Ctrl<Key>h:  LoadCaseDialogAction(help)\n\
 <BtnDown>:   PostMenu()\n\
 <Key>space:  PostMenu()";

static XtTranslations button_translations;


static String repeater_table =
"<Key>Return:  LoadCaseDialogAction(accept)\n\
 <Key>Escape:  LoadCaseDialogAction(dismiss)\n\
 Ctrl<Key>d:   LoadCaseDialogAction(delete)\n\
 Ctrl<Key>c:   LoadCaseDialogAction(copy)\n\
 Ctrl<Key>n:   LoadCaseDialogAction(new)\n\
 Ctrl<Key>h:   LoadCaseDialogAction(help)\n\
 <Key>space:   AutoRepeat(off) set()\n\
 <KeyUp>space: AutoRepeat(saved) notify() unset()";

static XtTranslations repeater_translations;


static String command_table =
"<Key>Return:  LoadCaseDialogAction(accept)\n\
 <Key>Escape:  LoadCaseDialogAction(dismiss)\n\
 Ctrl<Key>d:   LoadCaseDialogAction(delete)\n\
 Ctrl<Key>c:   LoadCaseDialogAction(copy)\n\
 Ctrl<Key>n:   LoadCaseDialogAction(new)\n\
 Ctrl<Key>h:   LoadCaseDialogAction(help)\n\
 <Key>space:   AutoRepeat(off) set()\n\
 <KeyUp>space: AutoRepeat(saved) notify() unset()";

static XtTranslations command_translations;


static String viewport_table =
"<Key>Return: LoadCaseDialogAction(accept)\n\
 <Key>Escape: LoadCaseDialogAction(dismiss)\n\
 Ctrl<Key>d:  LoadCaseDialogAction(delete)\n\
 Ctrl<Key>c:  LoadCaseDialogAction(copy)\n\
 Ctrl<Key>n:  LoadCaseDialogAction(new)\n\
 Ctrl<Key>h:  LoadCaseDialogAction(help)\n\
 <Btn1Down>:  SetFocus()";

static XtTranslations viewport_translations;


static String help_table =
"<Key>Return: LoadCaseDialogAction(accept)\n\
 <Key>Escape: LoadCaseDialogAction(dismiss)\n\
 Ctrl<Key>d:  LoadCaseDialogAction(delete)\n\
 Ctrl<Key>c:  LoadCaseDialogAction(copy)\n\
 Ctrl<Key>n:  LoadCaseDialogAction(new)\n\
 Ctrl<Key>h:  LoadCaseDialogAction(help)\n\
 <Key>space:  PostMenu()";

static XtTranslations help_translations;


/* Help message. */

static String help_message ="";


/************************************************************************
 * Function:	AppendLoadCaseName					*
 *									*
 * Description:	Appends the loadcase name to the array of names.  The	*
 *		index of the active loadcase is also set.		*
 ************************************************************************/

static int AppendLoadCaseName (item)
    Item item;
{
    if (dialog -> active == (LoadCase) item)
	list_index = num_loadcases;

    dialog -> loadcases [num_loadcases ++] = ((LoadCase) item) -> name;
    return 0;
}

/************************************************************************
 * 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.dismiss");
    else
	w = XtNameToWidget (XtParent (w), params [0]);

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


/************************************************************************
 * Function:	ScrollNode	
 *	
 * Description:	 
 ************************************************************************/

static void ScrollNode (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    Arg		    args [1];
    LoadCaseDialog  loadcased;
    unsigned	    current [4];
    unsigned	    count;
    String	    value;
    char	    buffer [10];
    unsigned	    node;
    unsigned	    i;
    unsigned	    base;
    int     	    dir;

    loadcased = (LoadCaseDialog) client_data;

    base = loadcased -> node_base;

   	/*
	 * figure out which entries have numbers in them
	 */

    XtSetArg (args [0], XtNstring,  &value);
    
    count = 0;
    for (i = 0 ; i < 4 ; i++) {
       XtGetValues (loadcased -> node [i], args, 1);
       node = atoi (value);
       if (node != 0) 
          current [count++] = node;
    }

	/*
	 * if necessary (and allowed) actually do the shift
	 */

    if (w == loadcased -> node_up && count == 4) 
       dir = 1;
    else if (w == loadcased -> node_down && base > 0) 
       dir = -1;
    else
       return;

    fprintf (stderr,"base = %d\n", base);
    fprintf (stderr,"count = %d\n", count);
    fprintf (stderr,"num_forces = %d\n", loadcased -> num_forces);

    if (base + count > loadcased -> num_forces) 
       loadcased -> num_forces = base + count;
    else if (base + count < loadcased -> num_forces && base + count > 0)
       loadcased -> num_forces = base + count;

	/*	
 	 * make a record of everything displayed before we shift anything 
	 * off screen (up shift)
         */

    if (dir == 1) {
       for (i = 0 ; i < count ; i++) {
          loadcased -> node_assignments [base + i] = current [i];
          XtGetValues (loadcased -> force [i], args, 1);
          loadcased -> force_assignments [base + i] = XtNewString (value);
          fprintf (stderr,"force %d = %s\n", base + i, loadcased -> force_assignments [base + i]);
       }
    }

    base = base + dir;
       
	/*
	 * update the nodes that are actually displayed
	 */

    for (i = 0 ; i < 4 ; i++) {
       if (base + i < loadcased -> num_forces) {
          sprintf (buffer,"%d", loadcased -> node_assignments [base + i]);
          SetTextString (loadcased -> node [i], buffer);
          SetTextString (loadcased -> force [i], loadcased -> force_assignments [base + i]);
       }
       else {
	  buffer [0] = 0;
          SetTextString (loadcased -> node [i], buffer);
          SetTextString (loadcased -> force [i], "");
       }

    } 

    loadcased -> node_base = base;

    return;
}

/************************************************************************
 * Function:	ScrollElement	
 *	
 * Description:	 
 ************************************************************************/

static void ScrollElement (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    Arg		    args [1];
    LoadCaseDialog  loadcased;
    unsigned	    current [4];
    unsigned	    count;
    String	    value;
    char	    buffer [10];
    unsigned	    element;
    unsigned	    i;
    unsigned	    base;
    int     	    dir;

    loadcased = (LoadCaseDialog) client_data;

    base = loadcased -> element_base;

   	/*
	 * figure out which entries have numbers in them
	 */

    XtSetArg (args [0], XtNstring,  &value);
    
    count = 0;
    for (i = 0 ; i < 4 ; i++) {
       XtGetValues (loadcased -> element [i], args, 1);
       element = atoi (value);
       if (element != 0) 
          current [count++] = element;
    }

	/*
	 * if necessary (and allowed) actually do the shift
	 */

    if (w == loadcased -> element_up && count == 4) 
       dir = 1;
    else if (w == loadcased -> element_down && base > 0) 
       dir = -1;
    else
       return;

    fprintf (stderr,"base = %d\n", base);
    fprintf (stderr,"count = %d\n", count);
    fprintf (stderr,"num_loads = %d\n", loadcased -> num_loads);

    if (base + count > loadcased -> num_loads) 
       loadcased -> num_loads = base + count;
    else if (base + count < loadcased -> num_loads && base + count > 0)
       loadcased -> num_loads = base + count;

	/*	
 	 * make a record of everything displayed before we shift anything 
	 * off screen (up shift)
         */

    if (dir == 1) {
       for (i = 0 ; i < count ; i++) {
          loadcased -> element_assignments [base + i] = current [i];
          XtGetValues (loadcased -> load [i], args, 1);
          loadcased -> load_assignments [base + i] = XtNewString (value);
          fprintf (stderr,"load %d = %s\n", base + i, loadcased -> load_assignments [base + i]);
       }
    }

    base = base + dir;
       
	/*
	 * update the elements that are actually displayed
	 */

    for (i = 0 ; i < 4 ; i++) {
       if (base + i < loadcased -> num_loads) {
          sprintf (buffer,"%d", loadcased -> element_assignments [base + i]);
          SetTextString (loadcased -> element [i], buffer);
          SetTextString (loadcased -> load [i], loadcased -> load_assignments [base + i]);
       }
       else {
	  buffer [0] = 0;
          SetTextString (loadcased -> element [i], buffer);
          SetTextString (loadcased -> load [i], "");
       }

    } 

    loadcased -> element_base = base;

    return;
}

/************************************************************************
 * Function:	ChangeForceAssignment	
 *	
 * Description:	 
 ************************************************************************/

static void ChangeForceAssignment (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    LoadCaseDialog  loadcased;
    Widget	    current_force;
    int		    i;


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

    loadcased = (LoadCaseDialog) client_data;

    current_force = GetFocus (loadcased -> name);

    for (i = 0 ; i < 4 ; i++) 
       if (current_force == loadcased -> force [i])
          break;

    if (i == 4)
       return;

    if (!strcmp (XtName (w), "- none -"))
        SetTextString (current_force, "");
    else
        SetTextString (current_force, GetLabelString (w));
}


/************************************************************************
 * Function:	ChangeLoadAssignment	
 *	
 * Description:	 
 ************************************************************************/

static void ChangeLoadAssignment (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    LoadCaseDialog  loadcased;
    Widget          current_load;
    int             i;


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

    loadcased = (LoadCaseDialog) client_data;

    current_load = GetFocus (loadcased -> name);

    for (i = 0 ; i < 4 ; i++) 
       if (current_load == loadcased -> load [i])
          break;

    if (i == 4)
       return;

    if (!strcmp (XtName (w), "- none -"))
        SetTextString (current_load, "");
    else
        SetTextString (current_load, GetLabelString (w));
}


/************************************************************************
 * Function:	Change							*
 *									*
 * Description:	Changes the displayed values to either the currently	*
 *		selected loadcase if the widget is not null, or the 	*
 *		active loadcase if the widget is null.  The newly 	*
 *		displayed loadcase is made the active loadcase and 	*
 *		any new/copy operation is canceled.			*
 ************************************************************************/

static void Change (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    char		 buffer [10];
    unsigned		 i;
    LoadCase		 active;
    struct loadcase	 dummy;
    LoadCaseDialog	 loadcased;
    XawListReturnStruct	*info;


    loadcased = (LoadCaseDialog) client_data;


    /* Retrieve the active loadcase from the tree if selected. */

    if (w != NULL) {
	info = (XawListReturnStruct *) call_data;
	if (info -> list_index == XAW_LIST_NONE)
	    return;

	dummy.name = info -> string;
	loadcased -> active = (LoadCase) TreeSearch (loadcased -> tree, &dummy);
    }

    active = loadcased -> active;
    loadcased -> new_copy = False;


    /* Update all of the entries. */

    SetTextString (loadcased -> name, active -> name);
    
    loadcased -> node_base    = 0;
    loadcased -> element_base = 0;
    loadcased -> num_forces = active -> numforces;
    loadcased -> num_loads = active -> numloads;
    
    for (i = 1 ; i <= active -> numforces ; i++) {
        if (i <= 4) {
           sprintf (buffer, "%d", active -> nodes [i] -> number);
           SetTextString (loadcased -> node [i-1], buffer);
           SetTextString (loadcased -> force [i-1], active -> forces [i] -> name);
        }

        loadcased -> node_assignments [i - 1] = active -> nodes [i] -> number;
        loadcased -> force_assignments [i - 1] = XtNewString (active -> forces [i] -> name);
    }

    for (i = 1 ; i <= active -> numloads ; i++) {
        if (i <= 4) {
           sprintf (buffer, "%d", active -> elements [i] -> number);
           SetTextString (loadcased -> element [i-1], buffer);
           SetTextString (loadcased -> load [i-1], active -> loads [i] -> name);
        }

        loadcased -> element_assignments [i - 1] = active -> elements [i] -> number;
        loadcased -> load_assignments [i - 1] = XtNewString (active -> loads [i] -> name);
    }
}


/************************************************************************
 * Function:	Accept							*
 *									*
 * Description:	Accepts changes made to the current loadcase.		*
 *		If the name is empty or a duplicate name is given then	*
 *		an error is reported.  Otherwise, a new loadcase is	*
 *		created if a new/copy operation is in effect.  The	*
 *		loadcase is then redisplayed to correct any invalid	*
 *		entries.						*
 ************************************************************************/

static void Accept (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    struct loadcase     old;
    struct loadcase     dummy;
    LoadCase	        found;
    LoadCase	        active;
    Boolean	        duplicate;
    LoadCaseDialog      loadcased;
    struct node		n;
    struct element	e;
    struct force	f;
    struct distributed  l;
    unsigned		i;


    loadcased = (LoadCaseDialog) client_data;


    /* Retrieve the name of the loadcase. */

    dummy.name = GetTextString (loadcased -> name);
    found = (LoadCase) TreeSearch (loadcased -> tree, &dummy);
    duplicate = found && (found != loadcased -> active || loadcased -> new_copy);


    /* Check for a duplicate name. */

    if (!dummy.name [0] || duplicate) {
	XBell (XtDisplay (loadcased -> name), 0);
	SetFocus (loadcased -> name);
	if (!loadcased -> new_copy)
	    SetTextString (loadcased -> name, loadcased -> active -> name);
	else
	    SetTextString (loadcased -> name, "");

    } else {


	/* Create a new loadcase or new name as needed. */

	if (loadcased -> new_copy)
	    loadcased -> active = CreateLoadCase (XtNewString (dummy.name));
	else if (strcmp (loadcased -> active -> name, dummy.name)) {
            old.name = loadcased -> active -> name;
            TreeDelete (loadcased -> tree, &old);
            XtFree (loadcased -> active -> name);
            loadcased -> active -> name = XtNewString (dummy.name);
            TreeInsert (loadcased -> tree, loadcased -> active);
	}

	active = loadcased -> active;

	/*
	 * fill out the actual components of the active load case here
	 */


        if (loadcased -> num_forces) {
           active -> numforces = loadcased -> num_forces;

           ZeroOffset (active -> nodes);   Deallocate (active -> nodes);
           ZeroOffset (active -> forces);  Deallocate (active -> forces);
           active -> nodes = Allocate(Node, loadcased -> num_forces);
           active -> forces = Allocate(Force, loadcased -> num_forces);
           UnitOffset (active -> nodes);
           UnitOffset (active -> forces);

           for (i = 1 ; i <= active -> numforces ; i++) {
              n.number = loadcased -> node_assignments [i-1];                
              active -> nodes [i] = (Node) TreeSearch (problem.node_tree, &n);
              if (active -> nodes [i] == NULL) {
                 error ("node %d is not defined", n.number);
                 return;
              }

              f.name = loadcased -> force_assignments [i-1];
              active -> forces [i] = (Force) TreeSearch (problem.force_tree, &f);
              if (active -> forces [i] == NULL) {
                 error ("force %s is not defined", f.name);
                 return;
              }
           }
        }

        if (loadcased -> num_loads) {
           active -> numloads = loadcased -> num_loads;

           ZeroOffset (active -> elements);   Deallocate (active -> elements);
           ZeroOffset (active -> loads);  Deallocate (active -> loads);
           active -> elements = Allocate(Element, loadcased -> num_loads);
           active -> loads = Allocate(Distributed, loadcased -> num_loads);
           UnitOffset (active -> elements);
           UnitOffset (active -> loads);

           for (i = 1 ; i <= active -> numloads ; i++) {
              e.number = loadcased -> element_assignments [i-1];                
              active -> elements [i] = (Element) TreeSearch (problem.element_tree, &e);
              if (active -> elements [i] == NULL) {
                 error ("element %d is not defined", e.number);
                 return;
              }

              l.name = loadcased -> load_assignments [i-1];
              active -> loads [i] = (Distributed) TreeSearch (problem.distributed_tree, &l);
              if (active -> loads [i] == NULL) {
                 error ("distributed load %s is not defined", l.name);
                 return;
              }
           }
        }

	if (loadcased -> new_copy)
	    TreeInsert (loadcased -> tree, loadcased -> active);

	LoadCaseDialogUpdate (loadcased, loadcased -> tree, NULL, NULL);
    }
}


/************************************************************************
 * Function:	Dismiss							*
 *									*
 * Description:	Pops down the dialog box.				*
 ************************************************************************/

static void Dismiss (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    LoadCaseDialog loadcased;


    loadcased = (LoadCaseDialog) client_data;
    XtPopdown (loadcased -> shell);
}


/************************************************************************
 * Function:	Delete							*
 *									*
 * Description:	Deletes the active loadcase if a new/copy operation is 	*
 *		not in effect.  The dialog is then updated.		*
 ************************************************************************/

static void Delete (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    LoadCaseDialog	    loadcased;


    loadcased = (LoadCaseDialog) client_data;

    if (!loadcased -> new_copy) {
	TreeDelete (loadcased -> tree, loadcased -> active);
	DestroyLoadCase (loadcased -> active);
	loadcased -> active = NULL;
    }

    LoadCaseDialogUpdate (loadcased, loadcased -> tree, NULL, NULL);
}


/************************************************************************
 * Function:	Copy							*
 *									*
 * Description:	Clears the name entry only and sets the flag indicating	*
 *		that a new/copy operation is in effect.			*
 ************************************************************************/

static void Copy (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    LoadCaseDialog loadcased;


    loadcased = (LoadCaseDialog) client_data;

    loadcased -> new_copy = True;
    SetFocus (loadcased -> name);
    XawListUnhighlight (loadcased -> list);
    SetTextString (loadcased -> name, "");
}


/************************************************************************
 * Function:	New							*
 *									*
 * Description:	Clears all entries in the loadcase dialog and sets the	*
 *		flag indicating that a new/copy operation is in effect.	*
 ************************************************************************/

static void New (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    LoadCaseDialog loadcased;
    unsigned       i;


    loadcased = (LoadCaseDialog) client_data;

    Copy (NULL, client_data, NULL);
    for (i = 0 ; i < 4 ; i++) {
       SetTextString (loadcased -> node [i] , "");
       SetTextString (loadcased -> element [i], "");
    }

    loadcased -> num_forces = 0;
    loadcased -> num_loads = 0;
    loadcased -> node_base = 0;
    loadcased -> element_base = 0;
}


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

LoadCaseDialog LoadCaseDialogCreate (parent, name, title)
    Widget	   parent;
    String	   name;
    String	   title;
{
    Window		window;
    Cardinal		i;
    char		buffer [128];
    Arg			args [2];
    Widget		group [28];
    LoadCaseDialog	loadcased;
    Dimension		width;
    Position		x;
    static XtAppContext	app_context = NULL;
    static XtActionsRec	actions [ ] = {{"LoadCaseDialogAction", 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);
	viewport_translations = XtParseTranslationTable (viewport_table);
	help_translations     = XtParseTranslationTable (help_table);
	repeater_translations = XtParseTranslationTable (repeater_table);
	button_translations   = XtParseTranslationTable (button_table);

        window = RootWindowOfScreen (XtScreen (parent));

        up_bitmap = XCreateBitmapFromData (XtDisplay (parent), window,
                    up_bits, up_width, up_height);

        down_bitmap = XCreateBitmapFromData (XtDisplay (parent), window,
                      down_bits, down_width, down_height);
    }


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

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

    loadcased = XtNew (struct loadcase_dialog);

    loadcased -> loadcases = NULL;

    loadcased -> active   = NULL;

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

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

    loadcased -> viewport = XtCreateManagedWidget ("viewport",
			 viewportWidgetClass, loadcased -> layout,
			 viewport_args, XtNumber (viewport_args));

    loadcased -> list     = XtCreateManagedWidget ("list",
			 listWidgetClass, loadcased -> viewport,
			 list_args, XtNumber (list_args));

    loadcased -> name     = XtCreateManagedWidget ("name",
			 asciiTextWidgetClass, loadcased -> layout,
			 name_args, XtNumber (name_args));

    for (i = 0 ; i < 4 ; i++) {
       sprintf (buffer,"node%d", i+1);
       loadcased -> node [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, loadcased -> layout,
			 number_args, XtNumber (number_args));

       sprintf (buffer,"element%d", i+1);
       loadcased -> element [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, loadcased -> layout,
			 number_args, XtNumber (number_args));

       sprintf (buffer,"force%d", i+1);
       loadcased -> force [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, loadcased -> layout,
			 name_args, XtNumber (name_args));

       sprintf (buffer,"load%d", i+1);
       loadcased -> load [i] = XtCreateManagedWidget (XtNewString (buffer),
			 asciiTextWidgetClass, loadcased -> layout,
			 name_args, XtNumber (name_args));
    }

    loadcased -> force_menu = XtCreateManagedWidget ("force_menu",
			 simpleMenuWidgetClass, loadcased -> layout,
			 NULL, 0);

    XtSetArg (button_args [0], XtNlabel,    "forces");
    XtSetArg (button_args [1], XtNmenuName, "force_menu");

    loadcased -> force_button = XtCreateManagedWidget ("force_button",
			 menuButtonWidgetClass, loadcased -> layout,
			 button_args, XtNumber (button_args));

    loadcased -> load_menu = XtCreateManagedWidget ("load_menu",
			 simpleMenuWidgetClass, loadcased -> layout,
			 NULL, 0);

    XtSetArg (button_args [0], XtNlabel,    "loads");
    XtSetArg (button_args [1], XtNmenuName, "load_menu");

    loadcased -> load_button = XtCreateManagedWidget ("load_button",
			 menuButtonWidgetClass, loadcased -> layout,
			 button_args, XtNumber (button_args));

    XtCreateManagedWidget ("- none -", smeBSBObjectClass,
                           loadcased -> force_menu, NULL, 0);

    XtCreateManagedWidget ("- none -", smeBSBObjectClass,
                           loadcased -> load_menu, NULL, 0);

    AddPostMenuActions (loadcased -> force_menu);
    AddPostMenuActions (loadcased -> load_menu);

    repeater_args [0].value = (XtArgVal) down_bitmap;

    loadcased -> node_down = XtCreateManagedWidget ("node_down",
                          repeaterWidgetClass, loadcased -> layout,
                          repeater_args, XtNumber (repeater_args));

    loadcased -> element_down = XtCreateManagedWidget ("element_down",
                          repeaterWidgetClass, loadcased -> layout,
                          repeater_args, XtNumber (repeater_args));

    repeater_args [0].value = (XtArgVal) up_bitmap;

    loadcased -> node_up = XtCreateManagedWidget ("node_up",
                          repeaterWidgetClass, loadcased -> layout,
                          repeater_args, XtNumber (repeater_args));

    loadcased -> element_up = XtCreateManagedWidget ("element_up",
                          repeaterWidgetClass, loadcased -> layout,
                          repeater_args, XtNumber (repeater_args));

    loadcased -> accept   = XtCreateManagedWidget ("accept",
			 commandWidgetClass, loadcased -> layout,
			 NULL, 0);

    loadcased -> dismiss  = XtCreateManagedWidget ("dismiss",
			 commandWidgetClass, loadcased -> layout,
			 NULL, 0);

    loadcased -> delete   = XtCreateManagedWidget ("delete",
			 commandWidgetClass, loadcased -> layout,
			 NULL, 0);

    loadcased -> new      = XtCreateManagedWidget ("new",
			 commandWidgetClass, loadcased -> layout,
			 NULL, 0);

    loadcased -> copy     = XtCreateManagedWidget ("copy",
			 commandWidgetClass, loadcased -> layout,
			 NULL, 0);

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

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


    XtCreateManagedWidget ("separator1", coreWidgetClass,
			loadcased -> layout, core_args, XtNumber (core_args));
    XtCreateManagedWidget ("separator2", coreWidgetClass,
			loadcased -> layout, core_args, XtNumber (core_args));
    XtCreateManagedWidget ("separator3", coreWidgetClass,
			loadcased -> layout, core_args, XtNumber (core_args));



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

    i = 0;
    group [i++]  = loadcased -> name;
    group [i++]  = loadcased -> viewport;
    group [i++]  = loadcased -> node[0];
    group [i++]  = loadcased -> force[0];
    group [i++]  = loadcased -> node[1];
    group [i++]  = loadcased -> force[1];
    group [i++]  = loadcased -> node[2];
    group [i++]  = loadcased -> force[2];
    group [i++]  = loadcased -> node[3];
    group [i++]  = loadcased -> force[3];
    group [i++]  = loadcased -> node_down;
    group [i++]  = loadcased -> node_up;
    group [i++]  = loadcased -> element[0];
    group [i++]  = loadcased -> load[0];
    group [i++]  = loadcased -> element[1];
    group [i++]  = loadcased -> load[1];
    group [i++]  = loadcased -> element[2];
    group [i++]  = loadcased -> load[2];
    group [i++]  = loadcased -> element[3];
    group [i++]  = loadcased -> load[3];
    group [i++]  = loadcased -> element_down;
    group [i++]  = loadcased -> element_up;
    group [i++]  = loadcased -> help;
    group [i++]  = loadcased -> accept;
    group [i++] = loadcased -> dismiss;
    group [i++] = loadcased -> delete;
    group [i++] = loadcased -> new;
    group [i++] = loadcased -> copy;

    XtGetValues (loadcased -> layout, color_args, XtNumber (color_args));
    CreateTabGroup (loadcased -> shell, group, XtNumber (group), highlight, True);
    XtRealizeWidget (loadcased -> shell);
    SetFocus (loadcased -> name);

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


    /* Add the translations to each widget. */

    AddDeleteWindowProtocol   (loadcased -> shell, "LoadCaseDialogAction()");
    ListAddCursorTranslations (loadcased -> viewport);

    XtOverrideTranslations (loadcased -> name,	   text_translations);

    XtOverrideTranslations (loadcased -> node[0],    text_translations);
    XtOverrideTranslations (loadcased -> node[1],    text_translations);
    XtOverrideTranslations (loadcased -> node[2],    text_translations);
    XtOverrideTranslations (loadcased -> node[3],    text_translations);
    XtOverrideTranslations (loadcased -> force[0],    text_translations);
    XtOverrideTranslations (loadcased -> force[1],    text_translations);
    XtOverrideTranslations (loadcased -> force[2],    text_translations);
    XtOverrideTranslations (loadcased -> force[3],    text_translations);
    XtOverrideTranslations (loadcased -> element[0], text_translations);
    XtOverrideTranslations (loadcased -> element[1], text_translations);
    XtOverrideTranslations (loadcased -> element[2], text_translations);
    XtOverrideTranslations (loadcased -> element[3], text_translations);
    XtOverrideTranslations (loadcased -> load[0], text_translations);
    XtOverrideTranslations (loadcased -> load[1], text_translations);
    XtOverrideTranslations (loadcased -> load[2], text_translations);
    XtOverrideTranslations (loadcased -> load[3], text_translations);

    XtOverrideTranslations (loadcased -> force_button, button_translations);
    XtOverrideTranslations (loadcased -> load_button, button_translations);

    XtOverrideTranslations (loadcased -> element_up,   repeater_translations);
    XtOverrideTranslations (loadcased -> element_down, repeater_translations);
    XtOverrideTranslations (loadcased -> node_up,      repeater_translations);
    XtOverrideTranslations (loadcased -> node_down,    repeater_translations);

    XtOverrideTranslations (loadcased -> accept,    command_translations);
    XtOverrideTranslations (loadcased -> dismiss,   command_translations);
    XtOverrideTranslations (loadcased -> delete,    command_translations);
    XtOverrideTranslations (loadcased -> new,	    command_translations);
    XtOverrideTranslations (loadcased -> copy,	    command_translations);
    XtOverrideTranslations (loadcased -> viewport,  viewport_translations);
    XtOverrideTranslations (loadcased -> help,	    help_translations);


    /* Add the necessary callbacks. */

    XtAddCallback (loadcased -> list,    XtNcallback, Change,  (XtPointer) loadcased);
    XtAddCallback (loadcased -> accept,  XtNcallback, Accept,  (XtPointer) loadcased);
    XtAddCallback (loadcased -> dismiss, XtNcallback, Dismiss, (XtPointer) loadcased);
    XtAddCallback (loadcased -> delete,  XtNcallback, Delete,  (XtPointer) loadcased);
    XtAddCallback (loadcased -> new,     XtNcallback, New,     (XtPointer) loadcased);
    XtAddCallback (loadcased -> copy,    XtNcallback, Copy,    (XtPointer) loadcased);
    XtAddCallback (loadcased -> node_up,      XtNcallback, ScrollNode,    (XtPointer) loadcased);
    XtAddCallback (loadcased -> node_down,    XtNcallback, ScrollNode,    (XtPointer) loadcased);
    XtAddCallback (loadcased -> element_up,   XtNcallback, ScrollElement, (XtPointer) loadcased);
    XtAddCallback (loadcased -> element_down, XtNcallback, ScrollElement, (XtPointer) loadcased);
    XtAddCallback (loadcased -> force_menu, XtNpopdownCallback, ChangeForceAssignment, (XtPointer) loadcased); 
    XtAddCallback (loadcased -> load_menu,  XtNpopdownCallback, ChangeLoadAssignment, (XtPointer) loadcased); 

    loadcased -> node_base = 0;
    loadcased -> element_base = 0;
    loadcased -> num_forces = 0;
    loadcased -> num_loads = 0;

    return loadcased;
}


/************************************************************************
 * Function:	LoadCaseDialogPopup					*
 *									*
 * Description:	Pops up the specified loadcase dialog.			*
 ************************************************************************/

void LoadCaseDialogPopup (loadcased)
    LoadCaseDialog loadcased;
{
    XtPopup (loadcased -> shell, XtGrabNone);
}


/************************************************************************
 * Function:	LoadCaseDialogActive					*
 *									*
 * Description:	Returns the currently active loadcase.			*
 ************************************************************************/

LoadCase LoadCaseDialogActive (loadcased)
    LoadCaseDialog loadcased;
{
    return loadcased -> active;
}


/************************************************************************
 * Function:	LoadCaseDialogDisplay					*
 *									*
 * Description:	Displays a specified loadcase.				*
 ************************************************************************/

void LoadCaseDialogDisplay (loadcased, loadcase)
    LoadCaseDialog loadcased;
    LoadCase	loadcase;
{
    loadcased -> active = loadcase;
    LoadCaseDialogUpdate (loadcased, loadcased -> tree, NULL, NULL);
}

/* Menu creation variables */

static Cardinal         child_number;
static WidgetList       children;
static Dimension        max_width;
static XtWidgetGeometry preferred;

/************************************************************************
 * Function:    SetForceEntry                                           *
 *                                                                      *
 * Description: Sets the label of the next menu entry to the name of    *
 *              the specified force.                                    *
 ************************************************************************/

static int SetForceEntry (item)
    Item item;
{
    SetLabelString (children [child_number], ((Force) item) -> name);

    XtQueryGeometry (children [child_number ++], NULL, &preferred);
    if (preferred.width > max_width)
        max_width = preferred.width;

    return 0;
}

/************************************************************************
 * Function:    SetLoadEntry                                            *
 *                                                                      *
 * Description: Sets the label of the next menu entry to the name of    *
 *              the specified load.                                     *
 ************************************************************************/

static int SetLoadEntry (item)
    Item item;
{
    SetLabelString (children [child_number], ((Distributed) item) -> name);

    XtQueryGeometry (children [child_number ++], NULL, &preferred);
    if (preferred.width > max_width)
        max_width = preferred.width;

    return 0;
}

/************************************************************************
 * Function:	LoadCaseDialogUpdate					*
 *									*
 * Description:	Updates the given loadcase dialog with the specified	*
 *		tree.  If no active loadcase exists, the first loadcase *
 *		is made active.  If no active loadcase still exists 	*
 *		then a new operation is performed.  Otherwise a change	*
 *		operation is performed to display the active values.	*
 ************************************************************************/

void LoadCaseDialogUpdate (loadcased, tree, force_tree, load_tree)
    LoadCaseDialog loadcased;
    Tree	tree;
    Tree	force_tree;
    Tree	load_tree;
{
    char	buffer [32];
    Arg		args [2];
    Cardinal 	nbytes;
    Cardinal	num_forces;
    Cardinal	num_loads;
    Cardinal	num_children;
    Cardinal	i;
    Cardinal	overflow;


    /* Determine a new active loadcase if necessary. */

    if (tree == NULL)
	tree = loadcased -> tree;

    if (loadcased -> active == NULL || tree != loadcased -> tree)
	loadcased -> active = (LoadCase) TreeMinimum (tree);


    /* Construct the array of loadcase names. */

    num_loadcases = 0;
    list_index = -1;
    dialog = loadcased;
    loadcased -> tree = tree;
    loadcased -> new_copy = False;

    nbytes = (TreeSize (loadcased -> tree) + 1) * sizeof (String);
    loadcased -> loadcases = (String *) XtRealloc ((char *) loadcased -> loadcases, nbytes);

    TreeSetIterator (loadcased -> tree, AppendLoadCaseName);
    TreeIterate (loadcased -> tree);
    loadcased -> loadcases [num_loadcases] = NULL;


    /* Update the list widget. */

    XawListChange (loadcased -> list, loadcased -> loadcases, 0, 0, True);

    if (list_index >= 0)
	XawListHighlight (loadcased -> list, list_index);


    /* Update the force menu */

   
    if (force_tree != NULL) {
       XtSetArg (args [0], XtNchildren,    &children);
       XtSetArg (args [1], XtNnumChildren, &num_children);
       XtGetValues (loadcased -> force_menu, args, 2);

       num_forces = TreeSize (force_tree) + 1;

       for (i = num_children; i < num_forces; i ++) {
           sprintf (buffer, "force_entry%d", i);
           XtCreateManagedWidget (XtNewString (buffer), smeBSBObjectClass,
                                  loadcased -> force_menu, NULL, 0);
       }

       if (num_children > num_forces) {
           overflow = num_children - num_forces;
           XtUnmanageChildren (children + num_forces, overflow);
       }

       XtSetArg (args [0], XtNchildren,    &children);
       XtSetArg (args [1], XtNnumChildren, &num_children);
       XtGetValues (loadcased -> force_menu, args, 2);

       XtQueryGeometry (children [0], NULL, &preferred);
       max_width = preferred.width;

       child_number = 1;
       TreeSetIterator (force_tree, SetForceEntry);
       TreeIterate (force_tree);

       XtSetArg (args [0], XtNwidth, max_width);
       XtSetValues (loadcased -> force_menu, args, 1);
    }


    /* Update the load menu */

   
    if (load_tree != NULL) {
       XtSetArg (args [0], XtNchildren,    &children);
       XtSetArg (args [1], XtNnumChildren, &num_children);
       XtGetValues (loadcased -> load_menu, args, 2);

       num_loads = TreeSize (load_tree) + 1;

       for (i = num_children; i < num_loads; i ++) {
           sprintf (buffer, "load_entry%d", i);
           XtCreateManagedWidget (XtNewString (buffer), smeBSBObjectClass,
                                  loadcased -> load_menu, NULL, 0);
       }

       if (num_children > num_loads) {
           overflow = num_children - num_loads;
           XtUnmanageChildren (children + num_loads, overflow);
       }

       XtSetArg (args [0], XtNchildren,    &children);
       XtSetArg (args [1], XtNnumChildren, &num_children);
       XtGetValues (loadcased -> load_menu, args, 2);

       XtQueryGeometry (children [0], NULL, &preferred);
       max_width = preferred.width;
   
       child_number = 1;
       TreeSetIterator (load_tree, SetLoadEntry);
       TreeIterate (load_tree);
   
       XtSetArg (args [0], XtNwidth, max_width);
       XtSetValues (loadcased -> load_menu, args, 1);
    }

    /* Update the text entries. */

    if (loadcased -> active == NULL)
	New (NULL, (XtPointer) loadcased, NULL);
    else
	Change (NULL, (XtPointer) loadcased, NULL);
}


syntax highlighted by Code2HTML, v. 0.9.1