/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (c) 1995-1999.  The Regents of the University of California.  All     */
/*   rights reserved.                                                      */
/*                                                                         */
/*   This work was produced at the University of California, Lawrence      */
/*   Livermore National Laboratory (UC LLNL) under contract no.            */
/*   W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy     */
/*   (DOE) and The Regents of the University of California (University)    */
/*   for the operation of UC LLNL.  Copyright is reserved to the           */
/*   University for purposes of controlled dissemination,                  */
/*   commercialization through formal licensing, or other disposition      */
/*   under terms of Contract 48; DOE policies, regulations and orders;     */
/*   and U.S. statutes.  The rights of the Federal Government are          */
/*   reserved under Contract 48 subject to the restrictions agreed upon    */
/*   by the DOE and University.                                            */
/*                                                                         */
/*                                                                         */
/*                              DISCLAIMER                                 */
/*                                                                         */
/*   This software was prepared as an account of work sponsored by an      */
/*   agency of the United States Government.  Neither the United States    */
/*   Government nor the University of California nor any of their          */
/*   employees, makes any warranty, express or implied, or assumes any     */
/*   liability or responsibility for the accuracy, completeness, or        */
/*   usefulness of any information, apparatus, product, or process         */
/*   disclosed, or represents that its specific commercial products,       */
/*   process, or service by trade name, trademark, manufacturer, or        */
/*   otherwise, does not necessarily constitute or imply its               */
/*   endorsement, recommendation, or favoring by the United States         */
/*   Government or the University of California. The views and opinions    */
/*   of the authors expressed herein do not necessarily state or reflect   */
/*   those of the United States Government or the University of            */
/*   California, and shall not be used for advertising or product          */
/*   endorsement purposes.                                                 */
/*                                                                         */
/*   Permission to use, copy, modify and distribute this software and its  */
/*   documentation for any non-commercial purpose, without fee, is         */
/*   hereby granted, provided that the above copyright notice and this     */
/*   permission notice appear in all copies of the software and            */
/*   supporting documentation, and that all UC LLNL identification in      */
/*   the user interface remain unchanged.  The title to copyright LLNL     */
/*   XDIR shall at all times remain with The Regents of the University     */
/*   of California and users agree to preserve same. Users seeking the     */
/*   right to make derivative works with LLNL XDIR for commercial          */
/*   purposes may obtain a license from the Lawrence Livermore National    */
/*   Laboratory's Technology Transfer Office, P.O. Box 808, L-795,         */
/*   Livermore, CA 94550.                                                  */
/*                                                                         */
/***************************************************************************/
/***************************************************************************/

#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/ScrolledW.h>
#include <Xm/Separator.h>
#include <Xm/RowColumn.h>
#include <Xm/ToggleBG.h>
#include <Xm/ToggleB.h>
#include <Xm/Frame.h>
#include <Xm/Label.h>
#include <Xm/TextF.h>
#include <Xm/Form.h>
#include <Xm/Scale.h>
#include "gprefs.h"
#include "gprefsmsg.h"

extern int need_to_save_prefs;
extern Display *display;
extern int screen;
extern Window root_window;
extern int depth;
extern int nprefs;

static String prefsTranslations =
	"<Btn1Down>:  Help()";

static int gprefs_visible = False;
static int initialized_gprefs = False;

static struct {
	Widget w_shell;
	Widget w_form;
	Widget w_optionMenu;
	Widget w_scrolledWindow;
	Widget w_rowColumn;
	Widget w_separator;
	Widget w_actionArea;
	Widget w_okButton;
	Widget w_applyButton;
	Widget w_cancelButton;
	Widget w_helpButton;
} gpref;

extern struct prefs_struct prefs[];
extern Widget w_toplev;
extern struct pref_category_st pref_categories[];
extern int npref_categories;

void cb_gprefs_item_help();
void cb_gprefs_help();
void cb_gprefs_ok();
void cb_gprefs_apply();
void cb_gprefs_cancel();
void cb_gprefs_change_category();
void create_gprefs_window();
void display_current_gprefs();
void gprefs_display_category();


/*
 * cb_general_preferences - Callback to pop up General Preferences dialog.
 */
void
cb_general_preferences(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
    /* Clear error flag */
    raise_okflag();

	create_gprefs_window();

	/* Pop up preferences window */
	display_current_gprefs();
	XtPopup(gpref.w_shell, XtGrabNone);
	add_dialog_to_list(gpref.w_shell);
	traverse_to_widget(gpref.w_okButton);
	XMapRaised(display, XtWindow(gpref.w_shell));
	gprefs_visible = True;
}


/*
 * create_gprefs_window - Create General Preferences window.
 */
void
create_gprefs_window()
{
	int i;
	int j;
	char *label;
	XmString string;
	Widget w_form;
	Widget w_label;
	Widget w_radioBoxFrame;
	Widget w_radioBox;
	int len;
	int x;
	int y;
	struct choice_st *c_st;
	struct number_st *n_st;
	XtTranslations translations;
	Dimension form_width;
	int toggle_offset;
	Dimension sw_width;
	Dimension menu_width;
	Widget w_pulldown;
	Widget widget;
	Arg args[4];
	Pixmap gprefsmsg1_pixmap;
	Pixmap gprefsmsg2_pixmap;
	Pixmap gprefsmsg3_pixmap;
	Pixel fg;
	Pixel bg;
	Widget w_msg1;
	Widget w_msg2;
	Widget w_msg3;

    /* Create dialog only once */
    if (initialized_gprefs)
        return;
    initialized_gprefs = True;

	/* Create toplevel shell for directory window */
	gpref.w_shell = XtVaCreatePopupShell("prefs", topLevelShellWidgetClass,
		w_toplev, NULL);

    /* Attach custom icon */
	attach_wm_icon(gpref.w_shell);
		
	/* Create form */
	gpref.w_form = XtVaCreateWidget("form", xmFormWidgetClass, gpref.w_shell,
		NULL);

	/* Add callback for the WM_DELETE_WINDOW protocol */
	add_wm_delete_window_cb(gpref.w_shell, cb_gprefs_cancel, NULL, True);

	/* Create form for action area */
    gpref.w_actionArea = XtVaCreateWidget(
        "actionArea",
        xmFormWidgetClass,
        gpref.w_form,
		XmNmarginHeight,		10,
		XmNbottomAttachment,	XmATTACH_FORM,
		XmNleftAttachment,		XmATTACH_FORM,
		XmNrightAttachment,		XmATTACH_FORM,
        NULL
    );

	/* Create OK pushbutton */
    gpref.w_okButton = XtVaCreateManagedWidget(
        "okButton",
        xmPushButtonWidgetClass,
        gpref.w_actionArea,
		XmNdefaultButtonShadowThickness,	1,
		XmNmarginHeight,					4,
		XmNtopAttachment,					XmATTACH_FORM,
        XmNbottomAttachment,    			XmATTACH_FORM,
        XmNleftAttachment,      			XmATTACH_POSITION,
        XmNleftPosition,        			5,
        XmNrightAttachment,     			XmATTACH_POSITION,
        XmNrightPosition,       			20,
        NULL
    );
    XtAddCallback(gpref.w_okButton, XmNactivateCallback, cb_gprefs_ok,
        (XtPointer)NULL);
	XtVaSetValues(gpref.w_form, XmNdefaultButton, gpref.w_okButton, NULL);

	/* Create Apply pushbutton */
    gpref.w_applyButton = XtVaCreateManagedWidget(
        "applyButton",
        xmPushButtonWidgetClass,
        gpref.w_actionArea,
		XmNdefaultButtonShadowThickness,	1,
		XmNmarginHeight,					4,
		XmNtopAttachment,					XmATTACH_FORM,
        XmNbottomAttachment,    			XmATTACH_FORM,
        XmNleftAttachment,      			XmATTACH_POSITION,
        XmNleftPosition,        			30,
        XmNrightAttachment,     			XmATTACH_POSITION,
        XmNrightPosition,       			45,
        NULL
    );
    XtAddCallback(gpref.w_applyButton, XmNactivateCallback, cb_gprefs_apply,
        (XtPointer)NULL);

	/* Create Cancel pushbutton */
    gpref.w_cancelButton = XtVaCreateManagedWidget(
        "cancelButton",
        xmPushButtonWidgetClass,
        gpref.w_actionArea,
		XmNdefaultButtonShadowThickness,	1,
		XmNmarginHeight,					4,
		XmNtopAttachment,					XmATTACH_FORM,
        XmNbottomAttachment,    			XmATTACH_FORM,
        XmNleftAttachment,      			XmATTACH_POSITION,
        XmNleftPosition,        			55,
        XmNrightAttachment,     			XmATTACH_POSITION,
        XmNrightPosition,       			70,
        NULL
    );
    XtAddCallback(gpref.w_cancelButton, XmNactivateCallback, cb_gprefs_cancel,
        (XtPointer)NULL);

	/* Create Help pushbutton */
    gpref.w_helpButton = XtVaCreateManagedWidget(
        "helpButton",
        xmPushButtonWidgetClass,
        gpref.w_actionArea,
		XmNdefaultButtonShadowThickness,	1,
		XmNmarginHeight,					4,
		XmNtopAttachment,					XmATTACH_FORM,
        XmNbottomAttachment,    			XmATTACH_FORM,
        XmNleftAttachment,      			XmATTACH_POSITION,
        XmNleftPosition,        			80,
        XmNrightAttachment,     			XmATTACH_POSITION,
        XmNrightPosition,       			95,
        NULL
    );
    XtAddCallback(gpref.w_helpButton, XmNactivateCallback, cb_gprefs_help,
        (XtPointer)NULL);

	XtManageChild(gpref.w_actionArea);

    /* Create separator */
    gpref.w_separator = XtVaCreateManagedWidget(
        "separator",
        xmSeparatorWidgetClass,
        gpref.w_form,
        XmNbottomAttachment,    XmATTACH_WIDGET,
        XmNbottomWidget,        gpref.w_actionArea,
        XmNleftAttachment,      XmATTACH_FORM,
        XmNrightAttachment,     XmATTACH_FORM,
        NULL
    );

	/* Concatenate three pixmaps to form a message */
	XtVaGetValues(gpref.w_form, XmNbackground, &bg, XmNforeground, &fg, NULL);
	gprefsmsg1_pixmap = XCreatePixmapFromBitmapData(display, root_window,
		(char *)gprefsmsg1_bits, gprefsmsg1_width, gprefsmsg1_height, fg, bg,
		depth);
	gprefsmsg2_pixmap = XCreatePixmapFromBitmapData(display, root_window,
		(char *)gprefsmsg2_bits, gprefsmsg2_width, gprefsmsg2_height, fg, bg,
		depth);
	gprefsmsg3_pixmap = XCreatePixmapFromBitmapData(display, root_window,
		(char *)gprefsmsg3_bits, gprefsmsg3_width, gprefsmsg3_height, fg, bg,
		depth);
	w_msg1 = XtVaCreateManagedWidget(
		"msg1",
		xmLabelWidgetClass,
		gpref.w_form,
		XmNlabelType,			XmPIXMAP,
		XmNlabelPixmap,			gprefsmsg1_pixmap,
		XmNmarginHeight,		0,
		XmNmarginWidth,			0,
		XmNbottomAttachment,	XmATTACH_WIDGET,
		XmNbottomWidget,		gpref.w_separator,
		XmNbottomOffset,		8,
		XmNleftAttachment,		XmATTACH_FORM,
		XmNleftOffset,			90,
		NULL
	);
	w_msg2 = XtVaCreateManagedWidget(
		"msg2",
		xmLabelWidgetClass,
		gpref.w_form,
		XmNlabelType,			XmPIXMAP,
		XmNlabelPixmap,			gprefsmsg2_pixmap,
		XmNmarginHeight,		0,
		XmNmarginWidth,			0,
		XmNbottomAttachment,	XmATTACH_WIDGET,
		XmNbottomWidget,		gpref.w_separator,
		XmNbottomOffset,		8,
		XmNleftAttachment,		XmATTACH_WIDGET,
		XmNleftWidget,			w_msg1,
		NULL
	);
	w_msg3 = XtVaCreateManagedWidget(
		"msg3",
		xmLabelWidgetClass,
		gpref.w_form,
		XmNlabelType,			XmPIXMAP,
		XmNlabelPixmap,			gprefsmsg3_pixmap,
		XmNmarginHeight,		0,
		XmNmarginWidth,			0,
		XmNbottomAttachment,	XmATTACH_WIDGET,
		XmNbottomWidget,		gpref.w_separator,
		XmNbottomOffset,		8,
		XmNleftAttachment,		XmATTACH_WIDGET,
		XmNleftWidget,			w_msg2,
		NULL
	);
	

	/* Create option menu to hold categories */
	w_pulldown = XmCreatePulldownMenu(gpref.w_form, "prefOptionMenu",
		NULL, 0);
	for (i=0; i<npref_categories; i++) {
		string = XmStringCreateSimple(pref_categories[i].menu_label);
		widget = XtVaCreateManagedWidget(
			"prefOptionMenuItem",
			xmPushButtonGadgetClass,
			w_pulldown,
			XmNlabelString,	string,
			NULL
		);
		XmStringFree(string);
		XtAddCallback(widget, XmNactivateCallback, cb_gprefs_change_category,
			(XtPointer)i);
	}
	i=0;
	XtSetArg(args[i], XmNsubMenuId, w_pulldown); i++;
	string = XmStringCreateSimple("");
	XtSetArg(args[i], XmNlabelString, string); i++;
	XtSetArg(args[i], XmNtopAttachment, XmATTACH_FORM); i++;
	XtSetArg(args[i], XmNtopOffset, 13); i++;
	gpref.w_optionMenu = XmCreateOptionMenu(gpref.w_form, "optionMenu", args,i);
	XmStringFree(string);
	XtManageChild(gpref.w_optionMenu);

	/* Create scrolled window to hold preferences */
	gpref.w_scrolledWindow = XtVaCreateManagedWidget(
		"scrolledWindow",
		xmScrolledWindowWidgetClass,
		gpref.w_form,
		XmNscrollingPolicy,			XmAUTOMATIC,
		XmNscrollBarDisplayPolicy,	XmSTATIC,
		XmNtopAttachment,			XmATTACH_WIDGET,
		XmNtopWidget,				gpref.w_optionMenu,
		XmNtopOffset,				10,
		XmNbottomAttachment,		XmATTACH_WIDGET,
		XmNbottomWidget,			w_msg1,
		XmNbottomOffset,			6,
		XmNleftAttachment,			XmATTACH_FORM,
		XmNleftOffset,				10,
		XmNrightAttachment,			XmATTACH_FORM,
		XmNrightOffset,				10,
		NULL
	);

	/* Calcuate some component dimensions based on scrolled window size */
	XtVaGetValues(gpref.w_scrolledWindow, XmNwidth, &sw_width, NULL);
	form_width = sw_width-41;
	toggle_offset = (int)(.46*(.56*form_width-7));

	/* Hokey hack to center option menu */
	widget = XmOptionButtonGadget(gpref.w_optionMenu);
	XtVaGetValues(widget, XmNwidth, &menu_width, NULL);
	XtVaSetValues(gpref.w_optionMenu,
		XmNrightAttachment,		XmATTACH_FORM,
		XmNrightOffset,			((int)(sw_width-menu_width-22))/2,
		NULL
	);

	/* Create rowcolumn widget to hold preferences */
	gpref.w_rowColumn = XtVaCreateWidget(
		"rowColumn",
		xmRowColumnWidgetClass,
		gpref.w_scrolledWindow,
		NULL
	);

	/* Layout widgets for individual preferences */
	for (i=0; i<nprefs; i++) {
		prefs[i].w_frame = XtVaCreateWidget("frame", xmFrameWidgetClass,
			gpref.w_rowColumn, NULL);
		w_form = XtVaCreateWidget("form",
			xmFormWidgetClass,
			prefs[i].w_frame,
			XmNwidth,	form_width,
			NULL
		);
		len = strlen(prefs[i].file_label);
		label = XtNewString(prefs[i].file_label);
		for (j=0; j<len; j++)
			if (label[j] == '_')
				label[j] = ' ';
		string = XmStringCreateSimple(label);
		XtFree(label);
		w_label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, w_form,
			XmNlabelString,			string,
			XmNtopAttachment,		XmATTACH_FORM,
			XmNbottomAttachment,	XmATTACH_FORM,
			XmNleftAttachment,		XmATTACH_FORM,
			XmNleftOffset,			6,
			NULL
		);
		XmStringFree(string);
		translations = XtParseTranslationTable(prefsTranslations);
		XtOverrideTranslations(w_label, translations);
		XtAddCallback(w_label, XmNhelpCallback, cb_gprefs_item_help,
			(XtPointer)i);
		switch (prefs[i].type) {
		case TEXT:
			prefs[i].widget = XtVaCreateManagedWidget(
				"textField",
				xmTextFieldWidgetClass,
				w_form,
				XmNtopAttachment,		XmATTACH_FORM,
				XmNbottomAttachment,	XmATTACH_FORM,
				XmNrightAttachment,		XmATTACH_FORM,
				XmNleftAttachment,		XmATTACH_POSITION,
				XmNleftPosition,		44,
				XmNtopOffset,			6,
				XmNbottomOffset,		6,
				XmNrightOffset,			6,
				NULL
			);
			break;
		case CHOICE:
			w_radioBoxFrame = XtVaCreateWidget(
				"radioBoxFrame",
				xmFrameWidgetClass,
				w_form,
				XmNtopAttachment,		XmATTACH_FORM,
				XmNbottomAttachment,	XmATTACH_FORM,
				XmNleftAttachment,		XmATTACH_POSITION,
				XmNleftPosition,		44,
				XmNrightAttachment,		XmATTACH_FORM,
				XmNtopOffset,			8,
				XmNbottomOffset,		8,
				XmNrightOffset,			8,
				NULL
			);
			w_radioBox = XtVaCreateWidget(
				"radioBox",
				xmRowColumnWidgetClass,
				w_radioBoxFrame,
				XmNisHomogeneous,	True,
				XmNentryClass,		xmToggleButtonGadgetClass,
				XmNpacking,			XmPACK_NONE,
				XmNradioBehavior,	True,
				NULL
			);
			c_st = prefs[i].part.choice;
			for (j=0; j<c_st->nchoices; j++) {
				string = XmStringCreateSimple(c_st->choices[j].label);
				if (j%2 == 0) 
					x = 0;
				else
					x = toggle_offset;
				y = 20*(j/2);
				c_st->choices[j].widget = XtVaCreateManagedWidget(
					"",
					xmToggleButtonGadgetClass,
					w_radioBox,
					XmNlabelString,		string,
					XmNmarginHeight,	0,
					XmNx,				x,
					XmNy,				y,
					NULL
				);
				XmStringFree(string);
			}
			XtManageChild(w_radioBox);
			XtManageChild(w_radioBoxFrame);
			break;
		case NUMBER:
			n_st = prefs[i].part.number;
			prefs[i].widget = XtVaCreateManagedWidget(
				"scale",
				xmScaleWidgetClass,
				w_form,
                XmNtopAttachment,       XmATTACH_FORM,
                XmNbottomAttachment,    XmATTACH_FORM,
                XmNrightAttachment,     XmATTACH_FORM,
				XmNleftAttachment,		XmATTACH_POSITION,
				XmNleftPosition,		44,
                XmNtopOffset,           6,
                XmNbottomOffset,        6,
                XmNrightOffset,         6,
		        XmNshowValue,           True,
		        XmNorientation,         XmHORIZONTAL,
				XmNminimum,				n_st->min,
				XmNmaximum,				n_st->max,
				NULL
			);
			break;
		default:
			fatal_error("Bug in create_gprefs_window()");
		}
		XtManageChild(w_form);
	}

	/* Make preferences in first category visible */
	gprefs_display_category(0);

	XtManageChild(gpref.w_rowColumn);
	XtManageChild(gpref.w_scrolledWindow);
	XtManageChild(gpref.w_form);
}


/*
 * display_current_gprefs - Update the genenal preferences display with
 *                          current values.
 */
void
display_current_gprefs()
{
	int i;
	int j;
	struct choice_st *c_st;

	for (i=0; i<nprefs; i++)
		switch (prefs[i].type) {
		case TEXT:
			XmTextFieldSetString(prefs[i].widget, *prefs[i].part.text->value);
			break;
		case CHOICE:
			c_st = prefs[i].part.choice;
			for (j=0; j<c_st->nchoices; j++)
				if (*c_st->value == c_st->choices[j].value) {
					XmToggleButtonSetState(
						c_st->choices[j].widget,
						True,
						True
					);
					break;
				}
			if (j == c_st->nchoices)
				fatal_error(
					"Bug in display_current_gprefs() - Contact programmer");
			break;
		case NUMBER:
			XmScaleSetValue(prefs[i].widget, *prefs[i].part.number->value);
			break;
		default:
			fatal_error("Bug in display_current_gprefs()");
		}
}


/*
 * apply - Set current preferences to displayed values.
 */
void
apply()
{
	int i;
	int j;
	struct choice_st *c_st;

	need_to_save_prefs = True;

	for (i=0; i<nprefs; i++)
		switch (prefs[i].type) {
		case TEXT:
			XtFree(*prefs[i].part.text->value);
			*prefs[i].part.text->value = XmTextFieldGetString(prefs[i].widget);
			break;
		case CHOICE:
			c_st = prefs[i].part.choice;
			for (j=0; j<c_st->nchoices; j++)
				if (XmToggleButtonGetState(c_st->choices[j].widget))
					break;
			if (j<c_st->nchoices)
				*c_st->value = c_st->choices[j].value;
			else
				fatal_error("Bug in apply().  Contact programmer.\n");
			break;
		case NUMBER:
			XmScaleGetValue(prefs[i].widget, prefs[i].part.number->value);
			break;
		default:
			fatal_error("Bug in apply().  Contact programmer.\n");
		}

		/* Sortability of caches might have changed */
		update_all_goto_menus();
}


/*
 * cb_gprefs_ok - Callback that applies current general preferences and then
 *                closes General Preferences dialog.
 */
void
cb_gprefs_ok(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	apply();
	XtUnmapWidget(gpref.w_shell);
	gprefs_visible = False;
}


/*
 * cb_gprefs_apply - Callback that applies current general preferences.
 */
void
cb_gprefs_apply(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	apply();
}


/*
 * cb_gprefs_cancel - Callback that restores old general preferences and then
 *                    closes General Preferences dialog.
 */
void
cb_gprefs_cancel(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	display_current_gprefs();
	XtUnmapWidget(gpref.w_shell);
	gprefs_visible = False;
}


/*
 * iconify_gprefs_window - Iconify general preferences window.
 */
void
iconify_gprefs_window()
{
	if (gprefs_visible)
		XIconifyWindow(display, XtWindow(gpref.w_shell), screen);
}


/*
 * deiconify_gprefs_window - Iconify general preferences window.
 */
void
deiconify_gprefs_window()
{
	if (gprefs_visible)
		XMapWindow(display, XtWindow(gpref.w_shell));
}


/*
 * cb_gprefs_change_category - Callback that changes the category of general
 *                             preferences presented to the user.
 */
void
cb_gprefs_change_category(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	int indx = (int)client_data;

	XtVaSetValues(gpref.w_rowColumn, XmNresizeWidth, False, NULL);
	gprefs_display_category(indx);
}


/*
 * gprefs_display_category - Display the category of general preferences
 *                           pointed to by pref_categories[cindx].
 */
void
gprefs_display_category(cindx)
int cindx;
{
	int i;

	/* Manage only those widgets containing indicated preference info */
	XtUnmanageChild(gpref.w_rowColumn);
	for (i=0; i<nprefs; i++) {
		XtUnmanageChild(prefs[i].w_frame);
	}
	XtManageChild(gpref.w_rowColumn);
	for (i=0; i<pref_categories[cindx].nprefs; i++)
		XtManageChild(prefs[pref_categories[cindx].prefs[i].indx].w_frame);
}



syntax highlighted by Code2HTML, v. 0.9.1