/*
 *  Copyright (c) 1994, Riley Rainey,  riley@netcon.com
 *
 *  Permission to use, copy, modify and distribute (without charge) this
 *  software, documentation, images, etc. is granted, provided that this 
 *  comment and the author's name is retained.
 *
 *  This software is provided by the author as is, and without any expressed
 *  or implied warranties, including, but not limited to, the implied
 *  warranties of merchantability and fitness for a particular purpose.  In no
 *  event shall the author be liable for any direct, indirect, incidental, or
 *  consequential damages arising in any way out of the use of this software.
 */

/*
 * LINKER_OPTIONS -lX11
 * LINKER_OPTIONS -lXt
 * LINKER_OPTIONS -lXm
 */

#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xos.h>
#include <X11/cursorfont.h>
#include <Xm/BulletinB.h>
#include <Xm/CascadeB.h>
#include <Xm/DrawingA.h>
#include <Xm/FileSB.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/LabelG.h>
#include <Xm/MainW.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/SelectioB.h>
#include <Xm/Separator.h>
#include <Xm/TextF.h>
#include <Xm/ToggleB.h>
#include <Xm/Xm.h>

#include "../util/memory.h"
#include "shared.h"
#include "dialog.h"
#include "CrExFormDlg.h"
#include "gutil1.h"
#include "io.h"
#include "actions.h"
#include "VWriteObject.h"
#include "VReadObject.h"
#include "xbm/curs_poly.xbm"
#include "xbm/curs_poly_mask.xbm"
#include "xbm/curs_marker.xbm"
#include "xbm/curs_marker_mask.xbm"


static char     grid_dash_list[2] = { 1, 4 };

static XmStringCharSet  charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;

/*
 *  fallback resources
 */

static String   fallback[] = {
	"*.Background:                  GhostWhite",
	"*buttons*highlightColor:       GhostWhite",

	"*.fontList:                    -*-helvetica-medium-r-*-*-*-140-*",
	"*.rulerFont:                   -*-courier-bold-r-*-*-*-140-*",
	"*XmTextField.fontList:         -*-courier-medium-r-*-*-*-140-*",
	"*XmPushButton.shadowThickness: 3",
	"*XmDrawingArea.traversalOn:    false",
	"*.menu_bar*Background:         #bbb",
	"*.menu_bar.spacing:            10",
	"*.top_frame.shadowType:        XmSHADOW_ETCHED_OUT",
	"*.bottom_frame.shadowType:     XmSHADOW_ETCHED_OUT",
	"*.twindow.background:          #d8d8d8",
	"*.twindow.foreground:          black",
	"*.bwindow.background:          #e1caac",
	"*.bwindow.foreground:          black",
	"*.main.form.height:            700",
	"*.main.form.width:             950",

	"*set_views.labelString: Set Views ...",
	"*mirror_xz.labelString: Mirror left/right",
	"*mirror_xz.acceleratorText:    Alt-L",
	"*mirror_xz.accelerator:        Meta<Key>l:",
	"*mirror_xz.mnemonic:           l",
	"*mirror_xy.labelString: Mirror top/bottom",
	"*mirror_xy.acceleratorText:    Alt-T",
	"*mirror_xy.accelerator:        Meta<Key>t:",
	"*mirror_xy.mnemonic:           t",
	"*mirror_yz.labelString: Mirror front/back",
	"*mirror_yz.acceleratorText:    Alt-F",
	"*mirror_yz.accelerator:        Meta<Key>f:",
	"*mirror_yz.mnemonic:           f",
	"*rescale.labelString: Rescale Object ...",
	"*rescale.mnemonic:             R",

	"*info.labelString: Aircraft Information ...",
	"*gear.labelString: Landing Gear ...",
	"*stability.labelString: Stability Derivatives ...",
	"*powerplant.labelString: Powerplant ...",

	"*rescale_dialog.dialogTitle: Rescale Object",

	"*open_d.dialogTitle:           Open a File",
	"*open_d.okLabelString:         Open",
	"*open_d.selectionLabelString:  Open which file?",
	"*open_d.autoUnmanage:          true",
	"*open_d*pattern:               *.gdf",

	"*save_as_d.dialogTitle:        Save Work",
	"*save_as_d.selectionLabelString:       File name:",
	"*save_as_d.okLabelString:      Save",
	"*save_as_d.*.fontList:         -*-helvetica-medium-r-*-*-*-120-*",

	"*gedit_format.labelString:     Gedit format",
	"*gedit_format.set:             true",
	"*v_format.labelString:         V format",
	"*rayshade_format.labelString:  ACM Inventory format",

	"*show_grid.visibleWhenOff:     true",
	"*show_ruler.visibleWhenOff:    true",

	"*coodinates*columns:           8",
	"*coodinates*sensitive:         false",

	"*new.labelString:              New",
	"*open.labelString:             Open ...",
	"*save.labelString:             Save",
	"*save_as.labelString:          Save As ...",
	"*exit.labelString:             Exit",

	"*new.acceleratorText:          Alt-N",
	"*new.accelerator:              Meta<Key>n:",
	"*new.mnemonic:                 N",
	"*open.acceleratorText:         Alt-O",
	"*open.accelerator:             Meta<Key>o:",
	"*open.mnemonic:                O",
	"*save.acceleratorText:         Alt-S",
	"*save.accelerator:             Meta<Key>s:",
	"*save.mnemonic:                S",
	"*save_as.mnemonic:             A",
	"*exit.acceleratorText:         Alt-E",
	"*exit.accelerator:             Meta<Key>e:",
	"*exit.mnemonic:                E",

	"*cut.labelString:              Cut",
	"*cut.acceleratorText:          Shift-Del",
	"*cut.accelerator:              Shift<Key>Delete:",
	"*cut.mnemonic:                 t",
	"*copy.labelString:             Copy",
	"*copy.acceleratorText:         Ctrl-Ins",
	"*copy.accelerator:             Ctrl<Key>Insert:",
	"*copy.mnemonic:                C",
	"*paste.labelString:            Paste",
	"*paste.acceleratorText:        Shift-Ins",
	"*paste.accelerator:            Shift<Key>Insert:",
	"*paste.mnemonic:               P",
	"*clear.labelString:            Clear",
	"*clear.mnemonic:               e",
	"*rotx.labelString:             Rotate 90 about X-Axis",
	
	"*info_dialog*XmLabelGadget.topOffset:          7",
	"*info_dialog*XmLabelGadget.rightOffset:        10",
	"*info_dialog*XmLabelGadget.leftOffset:         10",    
	"*info_dialog*XmTextField.rightOffset:          10",
	"*gear_dialog*XmLabelGadget.topOffset:          7",
	"*gear_dialog*XmLabelGadget.rightOffset:        10",
	"*gear_dialog*XmLabelGadget.leftOffset:         10",
	"*gear_dialog*XmTextField.rightOffset:          10",
	"*powerplant_dialog*XmLabelGadget.topOffset:    7",
	"*powerplant_dialog*XmLabelGadget.rightOffset:  10",
	"*powerplant_dialog*XmLabelGadget.leftOffset:   10",
	"*powerplant_dialog*XmTextField.rightOffset:    10",
	"*stability_dialog*XmLabelGadget.topOffset:     7",
	"*stability_dialog*XmLabelGadget.rightOffset:   10",
	"*stability_dialog*XmLabelGadget.leftOffset:    10",
	"*stability_dialog*XmTextField.rightOffset:     10",

	"*stability_dialog*Calculate.sensitive: false",
	"*info_dialog*Calculate.sensitive:      false",
	"*info_dialog*Calculate.sensitive:      false",

	NULL
	};

static XrmOptionDescRec options[] = {
	{"-controllerClass", "*controllerClass", XrmoptionSepArg, "is"},
	};

static XtResource resources[] = {
	{
		XtNselectionColor,
		XtCSelectionColor,
		XtRPixel,
		sizeof(Pixel),
		XtOffset(AppDataPtr, select_pixel),
		XtRString,
		(caddr_t) "firebrick"
	},
	{
		XtNgridColor,
		XtCGridColor,
		XtRPixel,
		sizeof(Pixel),
		XtOffset(AppDataPtr, grid_pixel),
		XtRString,
		(caddr_t) "black"
	},
	{
		XtNlineThickness,
		XtCLineThickness,
		XtRInt,
		sizeof(int),
		XtOffset(AppDataPtr, line_thickness),
		XtRImmediate,
		(caddr_t) 0
	},
	{
		XtNselectionThickness,
		XtCSelectionThickness,
		XtRInt,
		sizeof(int),
		XtOffset(AppDataPtr, selection_thickness),
		XtRImmediate,
		(caddr_t) 2
	},
	{
		XtNboxSize,
		XtCBoxSize,
		XtRInt,
		sizeof(int),
		XtOffset(AppDataPtr, box_size),
		XtRImmediate,
		(caddr_t) 5
	},
	{
		XtNpickSensitivity,
		XtCPickSensitivity,
		XtRInt,
		sizeof(int),
		XtOffset(AppDataPtr, pick_sensitivity),
		XtRImmediate,
		(caddr_t) 64
	},
	{
		XtNbuttonSize,
		XtCButtonSize,
		XtRInt,
		sizeof(int),
		XtOffset(AppDataPtr, button_size),
		XtRImmediate,
		(caddr_t) 32
	},
	{
		XtNcursorForeground,
		XtCCursorForeground,
		XtRPixel,
		sizeof(Pixel),
		XtOffset(AppDataPtr, cursor_foreground),
		XtRString,
		(caddr_t) "black"
	},
	{
		XtNcursorBackground,
		XtCCursorBackground,
		XtRPixel,
		sizeof(Pixel),
		XtOffset(AppDataPtr, cursor_background),
		XtRString,
		(caddr_t) "white"
	},
	{
		XtNshowGrid,
		XtCShowGrid,
		XmRBoolean,
		sizeof(Boolean),
		XtOffset(AppDataPtr, show_grid),
		XtRString,
		(caddr_t) "true"
	},
	{
		XtNshowRuler,
		XtCShowRuler,
		XmRBoolean,
		sizeof(Boolean),
		XtOffset(AppDataPtr, show_ruler),
		XtRString,
		(caddr_t) "false"
	},
	{
		XtNrulerFont,
		XtCFont,
		XtRFontStruct,
		sizeof(XFontStruct *),
		XtOffset(AppDataPtr, ruler_font),
		XtRString,
		(caddr_t) "fixed"
	}

	};

typedef struct {
	Boolean defined_in_this_version;
	Widget  widget;
	char    *name;
	char    *pixmap_file;
	} button_list_t;

button_list_t button_list[] = {
	{ True,         NULL, "point",          "xbm/cursor_%d.xbm" },
	{ False,        NULL, "hand",           "xbm/hand_%d.xbm" },
	{ True,         NULL, "polygon",        "xbm/polygon_%d.xbm" },
	{ True,         NULL, "circle",         "xbm/circle_%d.xbm" },
	{ True,         NULL, "origin",         "xbm/origin_%d.xbm" },
	{ True,         NULL, "zoom_out",       "xbm/zoom_out_%d.xbm" },
	{ True,         NULL, "zoom_in",        "xbm/zoom_in_%d.xbm" }
	};


#define MAX_ARGS        16
#define APP_CLASS       "Gedit"


static Widget   help_box;
//static Widget view_box = (Widget) NULL;


static void
ViewCB (w, client_data, call_data)
Widget  w;
caddr_t client_data;
caddr_t call_data;
{
	register XmToggleButtonCallbackStruct   *cbs =
		(XmToggleButtonCallbackStruct *) call_data;

	if (cbs->set == False)
		return;

	if (client_data == 0)
		desired_view = VIEW_LEFT_TOP;
	else
		desired_view = VIEW_FRONT_TOP;

}

static Widget
CreateHelp (parent) 
Widget          parent;
{

	Widget          button;
	Widget          message_box;
	Arg             args[MAX_ARGS];
	register int    n;

	static char     message[BUFSIZ];
	XmString        title_string = NULL;
	XmString        message_string = NULL;
	XmString        button_string = NULL;

	sprintf (message, "\
Gedit:  A Three Dimensional Object Editor\n\
\n\
Copyright (c) 1991  Riley Rainey\n\
\n\n");

	message_string = XmStringCreateLtoR (message, charset);
	button_string = XmStringCreateLtoR ("Continue", charset);
	title_string = XmStringCreateLtoR ("graphics editor help", charset);

	n = 0;
	XtSetArg (args[n], XmNdialogTitle, title_string);  n++;
	XtSetArg (args[n], XmNokLabelString, button_string);  n++;
	XtSetArg (args[n], XmNmessageString, message_string);  n++;
	message_box = XmCreateMessageDialog (parent, "help_box", args, n);

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

	if (title_string)
		XmStringFree (title_string);
	if (message_string)
		XmStringFree (message_string);
	if (button_string)
		XmStringFree (button_string);

	return (message_box);
}

static Widget
CreateViewsDialog (parent)
Widget parent;
{

	XmString string;
	static ActionAreaButton action_items[] = {
		{ "Ok",     MenuCB,     (XtPointer) MENU_SET_VIEWS_COMPLETE},
		{ "Cancel", MenuCB,     (XtPointer) MENU_SET_VIEWS_CANCEL},
		{ "Help",   NULL,       NULL    },
	};
	Widget  dialog, string_w, form, box;

	dialog = CreateExtendedFormDialog("dialog", parent, &form, action_items,
		XtNumber (action_items), 0); 

	string = XmStringCreateSimple("Select the desired views:");
	string_w = XtVaCreateManagedWidget("label", xmLabelGadgetClass, form,
		XmNlabelString,    string,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_FORM,
		NULL);
	XmStringFree(string);

	box = XmVaCreateSimpleRadioBox (form, "box", 0, ViewCB,
		XmVaRADIOBUTTON,
		XmStringCreateSimple("Left side / Top"), NULL, NULL, NULL,
		XmVaRADIOBUTTON,
		XmStringCreateSimple("Front / Top"), NULL, NULL, NULL,
		XmNleftAttachment,      XmATTACH_FORM,
		XmNrightAttachment,     XmATTACH_FORM,
		XmNtopAttachment,       XmATTACH_WIDGET,
		XmNtopWidget,           string_w,
		NULL);

	XtManageChild (box);
	XtManageChild (form);
	return dialog;

}

static Widget
CreateRescaleDialog (parent)
Widget parent;
{

	XmString string;
	static ActionAreaButton action_items[] = {
		{ "Apply",     MenuCB,  (XtPointer) MENU_RESCALE_APPLY},
		{ "Cancel", MenuCB,     (XtPointer) MENU_RESCALE_CANCEL},
		{ "Help",   NULL,       NULL    },
	};
	Widget  dialog, string_w, prompt, form;

	dialog = CreateExtendedFormDialog("rescale_dialog", parent, &form,
		action_items, XtNumber (action_items), 0); 

	string = XmStringCreateSimple("Current object dimensions:");
	string_w = XtVaCreateManagedWidget("label", xmLabelGadgetClass, form,
		XmNlabelString,    string,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_FORM,
		NULL);
	XmStringFree(string);

	extent_x = XtVaCreateManagedWidget("label_x", xmLabelGadgetClass, form,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_WIDGET,
		XmNtopWidget,      string_w,
		NULL);

	extent_y = XtVaCreateManagedWidget("label_y", xmLabelGadgetClass, form,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_WIDGET,
		XmNtopWidget,      extent_x,
		NULL);

	extent_z = XtVaCreateManagedWidget("label_z", xmLabelGadgetClass, form,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_WIDGET,
		XmNtopWidget,      extent_y,
		NULL);

	string = XmStringCreateSimple("Enter the object scaling factor:");
	prompt = XtVaCreateManagedWidget("label_z", xmLabelGadgetClass, form,
		XmNlabelString,    string,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_WIDGET,
		XmNtopWidget,      extent_z,
		NULL);
	XmStringFree(string);

	rescale_field = XtVaCreateManagedWidget("rescale_field",
		xmTextFieldWidgetClass, form,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment,  XmATTACH_WIDGET,
		XmNtopWidget,      prompt,
		XmNcolumns,        32,
		NULL);

	XtManageChild (form);
	return dialog;

}

static void
InitializeCursors()
{

	unsigned long   fg = 1, bg = 0;
	XColor          colors[2];
	Drawable        d;
	Display         *dpy;
	Pixmap          source, mask;
	Colormap        cmap;

	dpy = XtDisplay (twindow);
	d = RootWindow(dpy, DefaultScreen(dpy));

	XtVaGetValues (twindow,
		XmNcolormap,    &cmap,
		NULL);

	cursors[CURSOR_POINT] = XCreateFontCursor (dpy, XC_left_ptr);

	source = XCreatePixmapFromBitmapData (dpy, d, curs_poly_bits,
		curs_poly_width, curs_poly_height,
		fg, bg, 1);
	mask = XCreatePixmapFromBitmapData (dpy, d, curs_poly_mask_bits,
		curs_poly_width, curs_poly_height,
		fg, bg, 1);

	colors[0].pixel = app_data.cursor_foreground;
	colors[1].pixel = app_data.cursor_background;
	XQueryColors (dpy, cmap, colors, 2);

	cursors[CURSOR_POLY] = XCreatePixmapCursor (dpy, source,
		mask, &colors[0], &colors[1],
		curs_poly_x_hot, curs_poly_y_hot);
	XFreePixmap (dpy, source);
	XFreePixmap (dpy, mask);

	source = XCreatePixmapFromBitmapData (dpy, d, curs_marker_bits,
		curs_marker_width, curs_marker_height,
		fg, bg, 1);
	mask = XCreatePixmapFromBitmapData (dpy, d, curs_marker_mask_bits,
		curs_marker_width, curs_marker_height,
		fg, bg, 1);

	cursors[CURSOR_MARKER] = XCreatePixmapCursor (dpy, source,
		mask, &colors[0], &colors[1],
		curs_marker_x_hot, curs_marker_y_hot);
	XFreePixmap (dpy, source);
	XFreePixmap (dpy, mask);

	cursors[CURSOR_ORIGIN] = XCreateFontCursor (dpy, XC_crosshair);

}

static void
QuitCB (w, client_data, call_data)
Widget  w;
caddr_t client_data;
caddr_t call_data;
{

	exit (0);
}

static void
HelpCB (w, client_data, call_data)
Widget  w;
caddr_t client_data;
caddr_t call_data;
{

	XtManageChild (help_box);
}

static void
ButtonCB (w, client_data, call_data)
Widget  w;
caddr_t client_data;
caddr_t call_data;
{

	switch ( shared_PtrToInt(client_data) ) {

	case 0:
		edit_state = STATE_POINT;
		SetCursor (CURSOR_POINT);
		break;

	case 1:
		break;

	case 2:
		edit_state = STATE_POLYGON;
		SetCursor (CURSOR_POLY);
		break;

	case 3:
		edit_state = STATE_CIRCLE;
		SetCursor (CURSOR_CIRCLE);
		break;

	case 4:
		edit_state = STATE_MOVE_ORIGIN;
		SetCursor (CURSOR_ORIGIN);
		break;

	case 5:
		RescaleView(twindow, 1 / 1.2);
		XmProcessTraversal (button_list[0].widget, XmTRAVERSE_CURRENT);
		edit_state = STATE_POINT;
		SetCursor (CURSOR_POINT);
		break;

	case 6:
		RescaleView(twindow, 1.2);
		XmProcessTraversal (button_list[0].widget, XmTRAVERSE_CURRENT);
		edit_state = STATE_POINT;
		SetCursor (CURSOR_POINT);
		break;

	default:
		printf ("button %d\n", shared_PtrToInt(client_data));

	}
}

static void
FileCB (w, client_data, call_data)
Widget  w;
caddr_t client_data;
caddr_t call_data;
{
	register int    menu_id = shared_PtrToInt(client_data), i;
	register XmSelectionBoxCallbackStruct   *p =
		(XmSelectionBoxCallbackStruct *) call_data;
	char    *value;
	Boolean state;

	XmStringGetLtoR (p->value, charset, &value);

	switch (menu_id) {

	case MENU_OPEN:
		ReadGeditFile (value);
		break;

	case MENU_SAVE_AS:
		for (i=0; i < 3; ++i) {

			XtVaGetValues (save_formats[i],
				XmNset,         &state,
				NULL);

			if (state) {
				switch (i) {

				case 0:
					WriteGeditFile (value);
					break;
				case 1:
					WriteVFile (value);
					break;
				}

				break;
			}
		}
		break;
	}

	strcpy (filename, value);
	filename_valid = True;

	XtFree (value);
}

static void
AllocPixmap (w, width, height)
Widget  w;
Dimension       width, height;
{

	Pixel           bg;
	view_info_t     *p;
	Display         *d;
	int             depth;

	d = XtDisplay (w);

	XtVaGetValues (w,
		XmNbackground,  &bg,
		XmNuserData,    &p,
		XmNdepth,       &depth,
		NULL);

	if (p->flags & VI_PIXMAP_ALLOCATED)
		XFreePixmap (d, p->pixmap);

	p->pixmap = XCreatePixmap (d, RootWindow (d, DefaultScreen(d)),
		width, height, depth);

	XSetForeground (d, p->erase_gc, bg);
	XSetLineAttributes (d, p->erase_gc, app_data.selection_thickness,
		LineSolid, CapButt, JoinMiter);

	XFillRectangle (d, p->pixmap, p->erase_gc, 0, 0, width, height);

	p->width = width;
	p->height = height;
	p->flags |= VI_PIXMAP_ALLOCATED;
}


static void
WindowCB (w, client_data, call_data)
Widget  w;
caddr_t client_data;
caddr_t call_data;
{

	register XmDrawingAreaCallbackStruct    *q;
	view_info_t     *p;

	q = (XmDrawingAreaCallbackStruct *) call_data;

	XtVaGetValues (w,
		XmNuserData,    &p,
		NULL);

	switch (q->reason) {

	case XmCR_EXPOSE:
		if ((p->flags & VI_PIXMAP_ALLOCATED) == 0) {
			XtVaGetValues (w,
				XmNwidth,       &p->width,
				XmNheight,      &p->height,
				NULL);
			AllocPixmap (w, p->width, p->height);
		}
		XCopyArea (XtDisplay(w), p->pixmap, XtWindow(w),
			p->gc, 0, 0, p->width, p->height, 0, 0);
		break;

	case XmCR_RESIZE:
		XtVaGetValues (w,
			XmNwidth,       &p->width,
			XmNheight,      &p->height,
			NULL);
		AllocPixmap (w, p->width, p->height);
		p->origin_x = (p->width + 1) / 2;
		p->origin_y = (p->height + 1) / 2;
		DrawWidget (w, False);
		break;

	}

}


static char *markers[] = {
	"Pilot's Head Location",
	"Nose/Tail Gear Ground Contact Point",
	"Main Gear Ground Contact Point",
	"Tail Ground Contact Point",
	NULL
	};


static void
CreateMarkerList(Widget parent)
{

	register char   **p;
	register int    count = 0, i, n;
	XmString        string;
	Widget          item, menu, cascade;
	Arg             args[4];
	char            s[32];

	for (p=markers; *p; ++p) {
		++count;
	}

	marker_count = count;

	n = 0;
	menu = XmCreatePulldownMenu (parent, "marker_menu", args, n);

	marker_list = (marker_t *) XtMalloc (count * sizeof(marker_t));

	for (i=0; i<count; ++i) {
		marker_list[i].defined = False;
		marker_list[i].id = i;
		memory_strcpy(marker_list[i].name, sizeof(marker_list[i].name), markers[i]);
		string = XmStringCreateSimple(markers[i]);
		sprintf (s, "marker_%d", i);
		item = XtVaCreateWidget (s, xmPushButtonWidgetClass,
			menu,
			XmNlabelString, string,
			NULL);
		XtManageChild (item);
		XtAddCallback (item, XmNactivateCallback, MenuCB,
			(XtPointer) shared_IntToPtr(MENU_MARKER + i));
		XmStringFree (string);
	}

	XtManageChild (menu);

	n = 0;
	XtSetArg (args[n], XmNsubMenuId, menu);  n++;
	XtSetArg (args[n], XmNmnemonic, 'M');  n++;
	cascade = XmCreateCascadeButton (parent, "Markers", args, n);
	XtManageChild (cascade);

}



int main(int argc, char **argv)
{
	Widget          toplevel;
	Widget          main_window;
	Widget          menu_bar;
	Widget          menu_pane;
	Widget          button;
	Widget          cascade;
	Widget          top_frame, bottom_frame, main_form, row_col;
	Widget          row_col1, index_form;
	int             n, i;
	Arg             args[16];
	char            name[128];
	//XmString      label_string;
	XtAppContext    context;
	static int      tw = 1, bw = 2;
	Display         *display;
	Pixmap          pixmap;
	Pixel           fg, bg;
	XGCValues       gcv;
	XmString        string;

	toplevel = XtAppInitialize (&context, APP_CLASS, options,
		XtNumber(options), &argc, argv, fallback, NULL, 0);

	XtGetApplicationResources (toplevel, &app_data, resources,
		XtNumber(resources), NULL, 0);

	n = 0; 
	main_window = XmCreateMainWindow (toplevel, "main", args, n);
	XtManageChild (main_window);

	n = 0;
	menu_bar = XmCreateMenuBar (main_window, "menu_bar", args, n); 
	XtManageChild (menu_bar);

/*
 *  The File menu
 */

	n = 0;
	menu_pane = XmCreatePulldownMenu (menu_bar, "file_menu", args, n);

	n = 0;
	button = XmCreatePushButton (menu_pane, "new", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_NEW);

	n = 0;
	button = XmCreatePushButton (menu_pane, "open", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_OPEN); 
	//XmStringFree (string);

	n = 0;
	button = XmCreatePushButton (menu_pane, "save", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_SAVE);
	/* XmStringFree (string); */

	n = 0;
	button = XmCreatePushButton (menu_pane, "save_as", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_SAVE_AS);

	n = 0;
	button = XmCreatePushButton (menu_pane, "exit", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, QuitCB, NULL);

	n = 0;
	XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
	XtSetArg (args[n], XmNmnemonic, 'F');  n++;
	cascade = XmCreateCascadeButton (menu_bar, "File", args, n);
	XtManageChild (cascade);

/*
 *  The Edit menu
 */

	n = 0;
	menu_pane = XmCreatePulldownMenu (menu_bar, "edit_menu", args, n);

	n = 0;
	button = XmCreatePushButton (menu_pane, "cut", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_CUT);

	n = 0;
	button = XmCreatePushButton (menu_pane, "copy", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_COPY);

	n = 0;
	button = XmCreatePushButton (menu_pane, "paste", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_PASTE);

	n = 0;
	button = XmCreateSeparator (menu_pane, "separator1", args, n);
	XtManageChild (button);

	n = 0;
	button = XmCreatePushButton (menu_pane, "clear", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_CLEAR);

	n = 0;
	button = XmCreateSeparator (menu_pane, "separator2", args, n);
	XtManageChild (button);

	n = 0;
	button = XmCreatePushButton (menu_pane, "rotx", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_ROTATE_X);

	n = 0;
	button = XmCreatePushButton (menu_pane, "mirror_xz", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_MIRROR_XZ);

	n = 0;
	button = XmCreatePushButton (menu_pane, "mirror_xy", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_MIRROR_XY);

	n = 0;
	button = XmCreatePushButton (menu_pane, "mirror_yz", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_MIRROR_YZ);

	n = 0;
	button = XmCreateSeparator (menu_pane, "separator", args, n);
	XtManageChild (button);

	n = 0;
	button = XmCreatePushButton (menu_pane, "rescale", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_RESCALE);

	n = 0;
	XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
	XtSetArg (args[n], XmNmnemonic, 'E');  n++;
	cascade = XmCreateCascadeButton (menu_bar, "Edit", args, n);
	XtManageChild (cascade);

/*
 *  The Layout menu
 */

	n = 0;
	menu_pane = XmCreatePulldownMenu (menu_bar, "layout_menu", args, n);

	n = 0;
	string = XmStringCreateSimple ("Show Grid");
	XtSetArg (args[n], XmNlabelString, string);  n++;
	XtSetArg (args[n], XmNset, app_data.show_grid);  n++;
	XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY);  n++;
	XtSetArg (args[n], XmNradioBehavior, False);  n++;
	button = XmCreateToggleButton (menu_pane, "show_grid", args, n);
	XmStringFree (string);
	XtManageChild (button); 
	XtAddCallback (button, XmNvalueChangedCallback, MenuCB,
		(XtPointer) MENU_GRID);

	n = 0;
	string = XmStringCreateSimple ("Show Ruler");
	XtSetArg (args[n], XmNlabelString, string);  n++;
	XtSetArg (args[n], XmNset, app_data.show_ruler);  n++;
	XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY);  n++;
	XtSetArg (args[n], XmNradioBehavior, False);  n++;
	button = XmCreateToggleButton (menu_pane, "show_ruler", args, n);
	XmStringFree (string);
	XtManageChild (button); 
	XtAddCallback (button, XmNvalueChangedCallback, MenuCB,
		(XtPointer) MENU_RULER);

	n = 0;
	button = XmCreateSeparator (menu_pane, "separator", args, n);
	XtManageChild (button); 

	n = 0;
	button = XmCreatePushButton (menu_pane, "set_views", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_SET_VIEWS);

	n = 0;
	XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
	XtSetArg (args[n], XmNmnemonic, 'L');  n++;
	cascade = XmCreateCascadeButton (menu_bar, "Layout", args, n);
	XtManageChild (cascade);

	CreateMarkerList (menu_bar);

	n = 0;
	XtSetArg (args[n], XmNmnemonic, 'H');  n++;
	cascade = XmCreateCascadeButton (menu_bar, "Help", args, n);
	XtManageChild (cascade);
	XtAddCallback (cascade, XmNactivateCallback, HelpCB, NULL);

	n = 0;
	XtSetArg (args[n], XmNmenuHelpWidget, cascade);  n++;
	XtSetValues (menu_bar, args, n);

/*
 *  The Aircraft Performance menu
 */

	n = 0;
	menu_pane = XmCreatePulldownMenu (menu_bar, "perf_menu", args, n);

	n = 0;
	button = XmCreatePushButton (menu_pane, "info", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_INFO);
	
	n = 0;
	button = XmCreatePushButton (menu_pane, "gear", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_GEAR);

	n = 0;
	button = XmCreatePushButton (menu_pane, "stability", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_DERIV);

	n = 0;
	button = XmCreatePushButton (menu_pane, "powerplant", args, n);
	XtManageChild (button);
	XtAddCallback (button, XmNactivateCallback, MenuCB,
		(XtPointer) MENU_PWR);

	n = 0;
	XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
	XtSetArg (args[n], XmNmnemonic, 'P');  n++;
	cascade = XmCreateCascadeButton (menu_bar, "Performance", args, n);
	XtManageChild (cascade);

/*
 *  The main window hierarchy
 */

	main_form = XtVaCreateWidget ("form", xmFormWidgetClass,
		main_window,
		NULL);

	XtVaSetValues (main_window,
		XmNworkWindow,  main_form,
		NULL);

	index_form = XtVaCreateWidget ("index", xmFormWidgetClass,
		main_form,
		XmNleftAttachment,      XmATTACH_FORM,
		XmNtopAttachment,       XmATTACH_FORM,
		XmNbottomAttachment,    XmATTACH_FORM,
		NULL);

	row_col = XtVaCreateWidget ("buttons", xmRowColumnWidgetClass,
		index_form,
		XmNleftAttachment,      XmATTACH_FORM,
		XmNtopAttachment,       XmATTACH_FORM,
		NULL);

	XtVaGetValues (row_col,
		XmNforeground,  &fg,
		XmNbackground,  &bg,
		NULL);

	for (i=0; i < XtNumber(button_list); ++i) {

	    if (button_list[i].defined_in_this_version) {
	    
		sprintf (name, button_list[i].pixmap_file,
			app_data.button_size);

		pixmap = XmGetPixmap (XtScreen (row_col), name, fg, bg);

		button_list[i].widget = XtVaCreateManagedWidget (
			button_list[i].name, xmPushButtonWidgetClass, row_col,
			XmNlabelType,           XmPIXMAP,
			XmNlabelPixmap,         pixmap,
			XmNwidth,               64,
			XmNheight,              64,
			XmNshadowType,          XmSHADOW_ETCHED_OUT,
			NULL);

		XtAddCallback (button_list[i].widget,
			XmNactivateCallback, ButtonCB, (XtPointer) shared_IntToPtr(i));
	    }

	}

	XtManageChild (row_col);

	row_col1 = XtVaCreateWidget ("coordinates", xmRowColumnWidgetClass,
		index_form,
		XmNleftAttachment,      XmATTACH_FORM,
		XmNrightAttachment,     XmATTACH_FORM,
		XmNtopAttachment,       XmATTACH_WIDGET,
		XmNtopWidget,           row_col,
		XmNbottomAttachment,    XmATTACH_FORM,
		NULL);

	x_field = XtVaCreateManagedWidget("x",
		xmTextFieldWidgetClass, row_col1,
		XmNcolumns,        12,
		NULL);

	y_field = XtVaCreateManagedWidget("y",
		xmTextFieldWidgetClass, row_col1,
		XmNcolumns,        12,
		NULL);

	z_field = XtVaCreateManagedWidget("z",
		xmTextFieldWidgetClass, row_col1,
		XmNcolumns,        12,
		NULL);

	XtManageChild (row_col1);
	XtManageChild (index_form);

	top_frame = XtVaCreateManagedWidget ("top_frame", xmFrameWidgetClass,
		main_form,
		XmNtopAttachment,       XmATTACH_FORM,
		XmNleftAttachment,      XmATTACH_WIDGET,
		XmNleftWidget,          index_form,
		XmNrightAttachment,     XmATTACH_FORM,
		XmNbottomAttachment,    XmATTACH_POSITION,
		XmNbottomPosition,      50,
		NULL);

	twindow = XmCreateDrawingArea (top_frame, "twindow", args, n);

	XtAddCallback (twindow, XmNexposeCallback, WindowCB, (caddr_t) &tw);
	XtAddCallback (twindow, XmNinputCallback, WindowCB, (caddr_t) &tw);
	XtAddCallback (twindow, XmNresizeCallback, WindowCB, (caddr_t) &tw);

	XtManageChild (twindow);

	bottom_frame = XtVaCreateManagedWidget ("bottom_frame",
		xmFrameWidgetClass, main_form,
		XmNtopAttachment,       XmATTACH_WIDGET,
		XmNtopWidget,           top_frame,
		XmNleftAttachment,      XmATTACH_WIDGET,
		XmNleftWidget,          index_form,
		XmNrightAttachment,     XmATTACH_FORM,
		XmNbottomAttachment,    XmATTACH_FORM,
		NULL);

	n = 0;
	bwindow = XmCreateDrawingArea (bottom_frame, "bwindow", args, n);

	XtAddCallback (bwindow, XmNexposeCallback, WindowCB, (caddr_t) &bw);
	XtAddCallback (bwindow, XmNinputCallback, WindowCB, (caddr_t) &bw);
	XtAddCallback (bwindow, XmNresizeCallback, WindowCB, (caddr_t) &bw);

	XtManageChild (bwindow);
	XtManageChild (main_form);

	InitializeTranslations (context, twindow, bwindow);

/*
 *  File dialogs
 */

	n = 0;
	open_dialog = XmCreateFileSelectionDialog (toplevel, "open_d", args, n);
	XtAddCallback (open_dialog, XmNokCallback, FileCB, (XtPointer) MENU_OPEN);

	n = 0;
	save_as_dialog = XmCreatePromptDialog (toplevel, "save_as_d", args, n);
	XtAddCallback (save_as_dialog, XmNokCallback, FileCB, (XtPointer) MENU_SAVE_AS);

	n = 0;
	row_col = XmCreateRadioBox (save_as_dialog, "file_formats", args, n);
	XtManageChild (row_col);

	save_formats[0] = XtVaCreateManagedWidget ("gedit_format",
		xmToggleButtonWidgetClass, row_col,
		NULL);

	save_formats[1] = XtVaCreateManagedWidget ("v_format",
		xmToggleButtonWidgetClass, row_col,
		NULL);

	save_formats[2] = XtVaCreateManagedWidget ("rayshade_format",
		xmToggleButtonWidgetClass, row_col,
		NULL);

	set_views_dialog = CreateViewsDialog (toplevel);

	rescale_dialog = CreateRescaleDialog (toplevel);

	info_dialog = CreateInfoDialog(toplevel);
	
	gear_dialog = CreateGearDialog(toplevel);

	deriv_dialog = CreateDerivDialog(toplevel);

	powerplant_dialog = CreatePowerplantDialog(toplevel);

/*
 *  We logically cross-connect each of the two drawing areas with a data
 *  structure that is hung off each widget's userData field.
 */

	display = XtDisplay (twindow);
	t_info.flags = 0;
	t_info.other_view = &b_info;
	t_info.layout = VL_NXZ;
	t_info.other_widget = bwindow;
	t_info.other_window = XtWindow (bwindow);
	gcv.graphics_exposures = False;
	gcv.line_style = LineOnOffDash;
	gcv.font = app_data.ruler_font->fid;
	t_info.gc = XCreateGC (display,
		RootWindow(display, DefaultScreen(display)),
		GCGraphicsExposures | GCFont, &gcv);
	t_info.erase_gc = XCreateGC (display,
		RootWindow(display, DefaultScreen(display)),
		GCGraphicsExposures, &gcv);
	t_info.grid_gc = XCreateGC (display,
		RootWindow(display, DefaultScreen(display)),
		GCGraphicsExposures | GCLineStyle, &gcv);
	XSetDashes (display, t_info.grid_gc, 0, grid_dash_list, 2);

	XtVaSetValues (twindow,
		XmNuserData,    &t_info,
		NULL);

	display = XtDisplay (twindow);
	b_info.flags = 0;
	b_info.other_view = &t_info;
	b_info.layout = VL_NXNY;
	b_info.other_widget = twindow;
	b_info.other_window = XtWindow (twindow);
	b_info.gc = XCreateGC (display,
		RootWindow(display, DefaultScreen(display)),
		GCGraphicsExposures | GCFont, &gcv);
	b_info.erase_gc = XCreateGC (display,
		RootWindow(display, DefaultScreen(display)),
		GCGraphicsExposures, &gcv);
	b_info.grid_gc = XCreateGC (display,
		RootWindow(display, DefaultScreen(display)),
		GCGraphicsExposures | GCLineStyle, &gcv);
	XSetDashes (display, b_info.grid_gc, 0, grid_dash_list, 2);

	XtVaSetValues (bwindow,
		XmNuserData,    &b_info,
		NULL);

	help_box = CreateHelp (toplevel);

	edit_state = STATE_POINT;
	cur_polygon = (polygon_t *) NULL;
	polygon_max = 256;
	polygon_list = (polygon_t *) memory_allocate(polygon_max * sizeof (polygon_t), NULL);
	sel_polygon = unsel_polygon = clipboard_polygon = -1;
	drag_mode = False;

	for (i=0; i<polygon_max; ++i) {
		polygon_list[i].id = i;
		polygon_list[i].num_points = 0;
		polygon_list[i].next = -1;
	}

	polygon_count = 0;
	tmp_point_max = 128;
	tmp_point = (point_t *) memory_allocate(tmp_point_max * sizeof (point_t), NULL);

	pixel_scale = 0.125;
	app_data.box_offset = - app_data.box_size / 2;

	filename_valid = False;
	strcpy (filename, "Untitled");

	desired_view = VIEW_LEFT_TOP;

	XtRealizeWidget (toplevel);

	InitializeCursors ();
	SetCursor (CURSOR_POINT);

	XtAppMainLoop (context);
	
	memory_report();
	return 0;
}
