/*
 *
 *	xsupport.c
 *
 *	HNMS User Interface
 *	HNMS 2.0
 *
 *	February 1994
 *
 *	Leslie Schlecht
 *	Computer Sciences Corporation
 *	Numerical Aerodynamic Simulation Systems Division
 *	NASA Ames Research Center
 *
 *	Copyright (c) 1994 Leslie Schlecht
 *
 *	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 1, 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.
 *
 */

#include		<stdio.h>
#include		<string.h>
#include		<time.h>

#include		<X11/StringDefs.h>
#include		<X11/Intrinsic.h>
#include		<X11/Shell.h>
#include		<X11/Core.h>
#include		<Xm/Xm.h>
#include		<Xm/PushB.h>
#include		<Xm/CascadeB.h>
#include		<Xm/Form.h>
#include		<Xm/Text.h>
#include		<Xm/Label.h>
#include		<Xm/List.h>

#include		"defines.h"
#include		"externs.h"
#include		"colors.h"
#include		"xsupport.h"

#include		"bitmap/closebutton"
#include		"bitmap/helpbutton"
#include		"bitmap/morebutton"
#include		"bitmap/clearbutton"
#include		"bitmap/okbutton"
#include		"bitmap/statusbutton"
#include		"bitmap/viewsbutton"
#include		"bitmap/serverbutton"
#include		"bitmap/objectbutton"

static XtAppContext	hnms_app;
static Display		*hnms_dpy;
static Colormap		cmap;
static int		screen, depth;
static Window		root;
static GC		diag_gc, bm_gc, pm_gc;
static Font		diag_font[3];
static XFontStruct	*diag_fontinfo[3];

static int		bell_on=1;
static unsigned long	ci[N_COLORS];
static int		hnms_xoff=0, hnms_yoff=0;
static XrmDatabase	old=NULL;
static int		timer_interval=1000;
static void		(*timer)();
static Pixmap		pix[NUM_ICONS];
static int		currentproc=1, working=False, current_font=2;
static caddr_t		queue=NULL;
static int		qcount = 0;

typedef	struct		wpstruct {
	void		(*f)();
	int		k;
	caddr_t		a1, a2, a3, a4;
	int		id;
	} WPA;


/*
 *	Initialize the Xlib Interface.
 */
int
AllocateStatusColors(dpy)
Display	*dpy;
	{
	register	i;
	XColor		color;


	for (i=0; i<N_COLORS; i++) {
		color.red = colors[i][RED_COMPONENT];
		color.green = colors[i][GREEN_COMPONENT];
		color.blue = colors[i][BLUE_COMPONENT];
		if (!XAllocColor(hnms_dpy, cmap, &color)) {
			printf("Unable to allocate color %d (%d,%d,%d)\n",
				i, color.red, color.green,color.blue);
			ci[i] = 0;
			}
		else
			ci[i] = color.pixel;
		}
	return(1);
	}


/*
 *	Sound the bell if it is turned on.
 */
void
Beep(count)
int	count;
	{
	if (!bell_on) return;
	while (count) {
		XBell(hnms_dpy, 100);
		count --;
		}
	}


/*
 *	Timer for time-of-day clock and check for messages from server.
 */
void
ClockTick(w, id)
Widget		w;
XtIntervalId	id;
	{
	void	ClockTick();

	if (timer) (timer)();
	XtAppAddTimeOut(hnms_app, timer_interval, ClockTick, w);
	}

/*
 *	Are we on a color screen.
 */
int
ColorScreen(dpy)
Display	*dpy;
	{
	XVisualInfo	vinfo;

	if (depth < 8) {
		printf("Not enough color planes.\n");
		return(0);
		}
	if (!XMatchVisualInfo(dpy, screen, depth, PseudoColor, &vinfo)) {
		printf("Display is not color.\n");
		return(0);
		}
	return(1);
	}


/*
 *	Destroy the X application.
 */
void
DestroyX()
	{
	FreePixmap(pix[CLOSE_PIXMAP]);
	FreePixmap(pix[HELP_PIXMAP]);
	FreePixmap(pix[MORE_PIXMAP]);
	FreePixmap(pix[CLEAR_PIXMAP]);
	FreePixmap(pix[OK_PIXMAP]);
	FreePixmap(pix[VIEWS_PIXMAP]);
	FreePixmap(pix[OBJECT_PIXMAP]);
	FreePixmap(pix[SERVBLK_PIXMAP]);
	FreePixmap(pix[SERVRED_PIXMAP]);
	FreePixmap(pix[SERVGRE_PIXMAP]);
	FreePixmap(pix[STATBLK_PIXMAP]);
	FreePixmap(pix[STATRED_PIXMAP]);
	XtDestroyApplicationContext(hnms_app);
	}


/*
 *	Figure out actual window placement.
 */
void
FindShell(widg, a, event)
Widget	widg;
caddr_t	a;
XEvent	*event;
	{
	int	x, y;
	unsigned int	w, h, b, p;
	Window	r;
	static int	firsttime = 1;

	if (event->type == MapNotify)
		HideShowViewPanels(0);
	else if (event->type == ReparentNotify) {
		if (!firsttime) return;
		firsttime = 0;
		XGetGeometry(hnms_dpy, event->xreparent.parent, &r, &x, &y, &w,
			&h, &b, &p);
		if (b) {
			hnms_xoff = b;
			hnms_yoff = b;
			}
		else {
			hnms_xoff = x;
			hnms_yoff = y;
			}
		}
	}


/*
 *	Timer for flashing objects.
 */
void
FlashIt(w, id)
Widget		w;
XtIntervalId	id;
	{
	if (UpdateFlash())
		XtAppAddTimeOut(hnms_app, 500, FlashIt, w);
	}


/*
 *	Get the dimensions of a shell.
 */
void
GetShellDimensions(shell, xr, yr, wr, hr)
Widget	shell;
int	*xr, *yr, *wr, *hr;
	{
	Position	x, y;
	Dimension	w, h;
	int		xg, yg;
	unsigned int	wg, hg, bg, dg;
	Window		rg;

	XtVaGetValues(shell,
		XmNx, &x,
		XmNy, &y,
		XmNwidth, &w,
		XmNheight, &h,
		NULL);
	*xr = x;
	*yr = y;
	*wr = w;
	*hr = h;
#ifdef	sun
	XGetGeometry(hnms_dpy, XtWindow(shell), &rg, &xg, &yg, &wg, &hg, &bg,
		&dg);
	*yr = y-yg;
#endif
	}


/*
 *	Initialize the Xlib Interface.
 */
int
InitializeX(argc, argv, fallbacks, dpy)
int	argc;
char	*argv[];
char	*fallbacks[];
Display	**dpy;
	{
	XtToolkitInitialize();

	hnms_app = XtCreateApplicationContext();
	XtAppSetFallbackResources(hnms_app, fallbacks);

	hnms_dpy = XtOpenDisplay(hnms_app, NULL, argv[0], "Hnms", NULL, 0,
		&argc, argv);

	if (!hnms_dpy) return(0);
	*dpy = hnms_dpy;
	screen = DefaultScreen(hnms_dpy);
	cmap = DefaultColormap(hnms_dpy, screen);
	root = RootWindow(hnms_dpy, screen);
	depth = DefaultDepth(hnms_dpy, screen);
	diag_gc = XCreateGC(hnms_dpy, root, NULL, NULL);
	XSetState(hnms_dpy, diag_gc, ci[WHITE], ci[BLACK], GXcopy, AllPlanes);

	diag_font[2] = XLoadFont(hnms_dpy, "9x15");
	XSetFont(hnms_dpy, diag_gc, diag_font[2]);
	diag_fontinfo[2] = XQueryFont(hnms_dpy, XGContextFromGC(diag_gc));
	diag_font[1] = XLoadFont(hnms_dpy, "6x10");
	XSetFont(hnms_dpy, diag_gc, diag_font[1]);
	diag_fontinfo[1] = XQueryFont(hnms_dpy, XGContextFromGC(diag_gc));
	
	return(1);
	}

void
InitializePixmaps(dpy, fgcolor, bgcolor)
Display	*dpy;
Pixel	fgcolor, bgcolor;
	{
	pix[0] = 0;
	pix[CLOSE_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		closebutton_bits, closebutton_width, closebutton_height,
		fgcolor, bgcolor, depth);
	pix[HELP_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		helpbutton_bits, helpbutton_width, helpbutton_height,
		fgcolor, bgcolor, depth);
	pix[MORE_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		morebutton_bits, morebutton_width, morebutton_height,
		fgcolor, bgcolor, depth);
	pix[CLEAR_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		clearbutton_bits, clearbutton_width, clearbutton_height,
		fgcolor, bgcolor, depth);
	pix[OK_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		okbutton_bits, okbutton_width, okbutton_height,
		fgcolor, bgcolor, depth);
	pix[VIEWS_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		viewsbutton_bits, viewsbutton_width, viewsbutton_height,
		fgcolor, bgcolor, depth);
	pix[OBJECT_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		objectbutton_bits, objectbutton_width, objectbutton_height,
		fgcolor, bgcolor, depth);
	pix[SERVBLK_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		serverbutton_bits, serverbutton_width, serverbutton_height,
		ci[BLACK], bgcolor, depth);
	pix[SERVRED_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		serverbutton_bits, serverbutton_width, serverbutton_height,
		ci[RED], bgcolor, depth);
	pix[SERVGRE_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		serverbutton_bits, serverbutton_width, serverbutton_height,
		ci[GREEN], bgcolor, depth);
	pix[STATBLK_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		statusbutton_bits, statusbutton_width, statusbutton_height,
		ci[BLACK], bgcolor, depth);
	pix[STATRED_PIXMAP] = XCreatePixmapFromBitmapData(dpy, root,
		statusbutton_bits, statusbutton_width, statusbutton_height,
		ci[RED], bgcolor, depth);
	}

Pixmap
GetPixmap(i)
int	i;
	{
	return(pix[i]);
	}

/*
 *	Run a work proc.
 */
XtWorkProcId
LaunchProc(dummy)
caddr_t	dummy;
	{
	WPA	*a;
	caddr_t	n;

	n = queue;
	if (!NextEntry(&n, &a)) {
		working = False;
		return(True);
		}

	qcount --;
	SetQueueCount(qcount);
	if (a->id != currentproc) {
		RemoveEntry(&queue, a, free);
		return(False);
		}
	switch (a->k) {
	case 0:
		(a->f)();
		break;
	case 1:
		(a->f)(a->a1);
		break;
	case 2:
		(a->f)(a->a1, a->a2);
		break;
	case 3:
		(a->f)(a->a1, a->a2, a->a3);
		break;
	case 4:
		(a->f)(a->a1, a->a2, a->a3, a->a4);
		break;
	default:;
		}
	RemoveEntry(&queue, a, free);
	return(False);
	}


/*
 *	Use X main loop.
 */
void
MainLoop()
	{
	XtAppMainLoop(hnms_app);
	}


/*
 *	Make a top level shell.
 */
Widget
MakeShell(name, w, h)
char	*name;
	{
	Widget	s;

	s = XtVaAppCreateShell(name,
		"Hnms",
		topLevelShellWidgetClass,
		hnms_dpy,
		XmNkeyboardFocusPolicy, XmPOINTER,
		NULL);
	if (w)
		XtVaSetValues(s,
			XmNwidth, w,
			NULL);
	if (h)
		XtVaSetValues(s,
			XmNheight, h,
			NULL);
	return(s);
	}


/*
 *	Post a popup menu.
 */
void
PostPopupMenu(pb, popup, event)
Widget	pb;
Widget	popup;
XButtonPressedEvent	*event;
	{
	XmMenuPosition(popup, event);
	XtManageChild(popup);
	}


/*
 *	Raise a widget window to the front of the screen.
 */
void
RaiseWidget(widg)
Widget	widg;
	{
	XRaiseWindow(hnms_dpy, XtWindow(widg));
	}


/*
 *	Set the bell on and sound it.
 */
void
SetBeep(i)
int	i;
	{
	bell_on = i;
	Beep();
	}


/*
 *	Set shell dimensions.
 */
void
SetShellDimensions(shell, x, y, w, h)
Widget	shell;
int	x, y, w, h;
	{
	if (x >= 0 && y >= 0)
		XtVaSetValues(shell,
			XmNx, x,
			XmNy, y,
			NULL);
	if (w > 0 && h > 0)
		XtVaSetValues(shell,
			XmNwidth, w,
			XmNheight, h,
			NULL);
	}


/*
 *	Set shell location.
 */
void
SetShellLocation(shell, x, y, buf)
Widget	shell;
int	x, y;
char	*buf;
	{

	if (x >= 0 && y >= 0) {
		sprintf(buf, "+%d+%d", x, y);
		XtVaSetValues(shell,
			XmNgeometry, buf,
			NULL);
		}
	}


/*
 *	Set the procedure called by the timer.
 */
void
TimerProc(f, interval)
void	(*f)();
	{
	if (interval != 0) timer_interval = interval;
	timer = f;
	}


/*
 *	Set the foreground color of a widget.
 */
int
WidgetColor(w, i)
Widget	w;
int	i;
	{
	XtVaSetValues(w,
		XmNforeground, ci[i],
		NULL);
	}


/*
 *	Add a work proc.
 */
void
WorkProc(f, k, a1, a2, a3, a4)
void	(*f)();
int	k;
caddr_t	a1, a2, a3, a4;
	{
	WPA	*a;
	int	i;
	caddr_t	q;

	a = (WPA*)myalloc(NULL, 1, sizeof(WPA));
	a->f = f;
	a->k = k;
	a->a1 = a1;
	a->a2 = a2;
	a->a3 = a3;
	a->a4 = a4;
	a->id = currentproc;
	AddEntry(&(queue), a, NULL, 0);
	qcount ++;
	SetQueueCount(qcount);
	if (!working) {
		working = True;
		XtAppAddWorkProc(hnms_app, LaunchProc, NULL);
		}
	}


void
SetWorkProc()
	{
	currentproc ++;
	RemoveEntryList(queue, free);
	queue = NULL;
	qcount =0;
	SetQueueCount(qcount);
	}


/*
 *	Create a labeled list widget.
 */
Widget
labeled_list(name, parent, s)
char	*name, *s;
Widget	parent;
	{
	XmString	xs;
	Widget		l, widg;

	l = XtVaCreateManagedWidget("label",
		xmLabelWidgetClass,
		parent,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_NONE,
		XmNlabelString, (xs=X_STR(s)),
		NULL);
	XmStringFree(xs);
	widg = XmCreateScrolledList(parent, name, NULL, 0);
	XtVaSetValues(XtParent(widg),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, l,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	XtManageChild(widg);
	return(widg);
	}

/*
 *	Create a labeled text widget.
 */
Widget
labeled_text(name, parent, w, s)
char	*name, *s;
Widget	parent;
int	w;
	{
	XmString	xs;
	Widget		l, widg;

	l = XtVaCreateManagedWidget("label",
		xmLabelWidgetClass,
		parent,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_NONE,
		XmNlabelString, (xs=X_STR(s)),
		NULL);
	XmStringFree(xs);
	widg = XtVaCreateManagedWidget(name,
		xmTextWidgetClass,
		parent,
		XmNeditable, False,
		XmNcolumns, w,
		XmNcursorPositionVisible, False,
		XmNtopAttachment, XmATTACH_NONE,
		XmNrightAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, l,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNhighlightThickness, 0,
		XmNshadowThickness, 0,
		XmNresizeWidth, True,
		XmNresizable, True,
		NULL);
	return(widg);
	}

/*
 *	Create a pushbutton.
 */
Widget
pbutton(name, parent, s)
char	*name, *s;
Widget	parent;
	{
	XmString	xs;
	Widget		pb;

	pb = XtVaCreateManagedWidget(name,
		xmPushButtonWidgetClass,
		parent,
		XmNlabelString, (xs=X_STR(s)),
		NULL);
	XmStringFree(xs);
	return(pb);
	}

/*
 *	Create a cascade button.
 */
Widget
cbutton(name, parent, s, m)
char	*name, *s;
Widget	parent, m;
	{
	XmString	xs;
	Widget		cb;

	if (!m)
		cb = XtVaCreateManagedWidget(name,
			xmCascadeButtonWidgetClass,
			parent,
			XmNlabelString, (xs=X_STR(s)),
			NULL);
	else
		cb = XtVaCreateManagedWidget(name,
			xmCascadeButtonWidgetClass,
			parent,
			XmNlabelString, (xs=X_STR(s)),
			XmNsubMenuId, m,
			NULL);
	XmStringFree(xs);
	return(cb);
	}


void
TextGainFocus(widg, a1, a2)
Widget	widg;
caddr_t	a1, a2;
	{
	XmTextSetEditable(widg, True);
	}


void
TextLoseFocus(widg, a1, a2)
Widget	widg;
caddr_t	a1, a2;
	{
	XmTextSetEditable(widg, False);
	}

/*
 *	Get a color.
 */
int
GetColor(i)
	{
	return(ci[i]);
	}

/*
 *	Free a pixmap.
 */
void
FreePixmap(pm)
Pixmap	pm;
	{
	XFreePixmap(hnms_dpy, pm);
	}

/*
 *	Clear a bitmap.
 */
void
ClearBitmap(pm, width, height)
Pixmap	pm;
int	width, height;
	{
	XSetState(hnms_dpy, bm_gc, 0, 0, GXcopy, AllPlanes);
	XFillRectangle(hnms_dpy, pm, bm_gc, 0, 0, width, height);
	}


/*
 *	Draw into a bitmap.
 */
void
BitmapLines(pm, points, npoints)
Drawable	pm;
XPoint	points[];
int	npoints;
	{
	if (npoints == 0) return;
	XSetState(hnms_dpy, bm_gc, 1, 0, GXcopy, AllPlanes);
	XDrawLines(hnms_dpy, pm, bm_gc, points, npoints,
		CoordModeOrigin);
	}


/*
 *	Copy a pixmap to a window.
 */
void
CopyPixmap(da, pm, x, y, width, height)
Pixmap	pm;
Widget	da;
int	x, y, width, height;
	{
	XCopyArea(hnms_dpy, pm, XtWindow(da), diag_gc, 0, 0,
		(unsigned int)width, (unsigned int)height, x, y);
	}

/*
 *	Create a bitmap.
 */
Pixmap
CreateBitmap(w, h)
int	w, h;
	{
	Pixmap	p;

	p = XCreatePixmap(hnms_dpy, root,
		(unsigned int) w,
		(unsigned int) h,
		1);
	if (!bm_gc) {
		bm_gc = XCreateGC(hnms_dpy, p, 0, NULL);
		XSetState(hnms_dpy, bm_gc, 1, 0, GXcopy, AllPlanes);
		}
	ClearBitmap(p, w, h);
	return(p);
	}

/*
 *	Create a pixmap.
 */
Pixmap
CreatePixmap(w, h)
int	w, h;
	{
	Pixmap	p;

	p = XCreatePixmap(hnms_dpy, root,
		(unsigned int) w,
		(unsigned int) h,
		depth);
	if (!pm_gc) {
		pm_gc = XCreateGC(hnms_dpy, p, 0, NULL);
		XSetState(hnms_dpy, pm_gc, 1, 0, GXcopy, AllPlanes);
		}
	return(p);
	}


void
SetColor(i)
int	i;
	{
	XSetForeground(hnms_dpy, diag_gc, ci[i]);
	}


void
SetLineWidth(i)
unsigned int	i;
	{
	XSetLineAttributes(hnms_dpy, diag_gc, i, LineSolid, CapButt, JoinMiter);
	}


void
SetBackgroundColor(i)
int	i;
	{
	XSetBackground(hnms_dpy, diag_gc, ci[i]); 
	}


void
CopyBitmap(da, pm, width, height)
Pixmap	pm;
Widget	da;
int	width, height;
	{
	XCopyPlane(hnms_dpy, pm, XtWindow(da), diag_gc, 0, 0,
		(unsigned int)width, (unsigned int)height, 0, 0, 1);
	}


void
ClearXQ()
	{
	XSync(hnms_dpy, True);
	}


void
ClearWindow(w)
Widget	w;
	{
	XClearWindow(hnms_dpy, XtWindow(w));
	}

int
ScreenWidth()
	{
	return(DisplayWidth(hnms_dpy, screen));
	}

int
ScreenHeight()
	{
	return(DisplayHeight(hnms_dpy, screen));
	}


void
DrawArrowHead(da, x0, y0, x1, y1)
Widget	da;
float	x0, y0, x1, y1;
	{
	float	dx, dy, x2, y2, x3, y3;

	dx = (x1-x0)/2;
	dy = (y1-y0)/2;
	x2 = x0-dy;
	y2 = y0+dx;
	x3 = x0+dy;
	y3 = y0-dx;
	XDrawLine(hnms_dpy, XtWindow(da), diag_gc, (int)x1, (int)y1, (int)x2,
		(int)y2);
	XDrawLine(hnms_dpy, XtWindow(da), diag_gc, (int)x1, (int)y1, (int)x3,
		(int)y3);
	}


void
DrawCircle(da, x0, y0, r)
Widget	da;
float	x0, y0, r;
	{
	XDrawArc(hnms_dpy, XtWindow(da), diag_gc, (int)(x0-r), (int)(y0-r),
		(int)r*2, (int)r*2, 0, 23040);
	}


void
DrawArc(da, x0, y0, r)
Widget	da;
float	x0, y0, r;
	{
	XDrawArc(hnms_dpy, XtWindow(da), diag_gc, (int)(x0-r), (int)(y0-r),
		(int)r*2, (int)r*2, 17280, 17280);
	}


void
DrawDot(da, x0, y0, r)
Widget	da;
float	x0, y0, r;
	{
	XFillArc(hnms_dpy, XtWindow(da), diag_gc, (int)(x0-r), (int)(y0-r),
		(int)r*2, (int)r*2, 0, 23040);
	}


void
DrawLine(da, x0, y0, x1, y1)
Widget	da;
float	x0, y0, x1, y1;
	{
	XDrawLine(hnms_dpy, XtWindow(da), diag_gc, (int)x0, (int)y0, (int)x1,
		(int)y1);
	}


void
DrawBlock(da, x0, y0, r)
Widget	da;
float	x0, y0, r;
	{
	XFillRectangle(hnms_dpy, XtWindow(da), diag_gc, (int)(x0-r),
		(int)(y0-r), (unsigned int)(2*r), (unsigned int)(2*r));
	}


void
StrToList(str, list)
char	*str;
Widget	list;
	{
	char		*p;
	XmString	xs;

	if (!str) return;
	for (p=gettoken(str); p; p=gettoken(NULL)) {
		xs = X_STR(p);
		XmListAddItem(list, xs, 0);
		XmStringFree(xs);
		}
	XmListDeselectAllItems(list);
	}


int
FontAscent(i)
int	i;
	{
	return(diag_fontinfo[i]->ascent);
	}


void
SetFont(i)
int	i;
	{
	XSetFont(hnms_dpy, diag_gc, diag_font[i]);
	current_font = i;
	}


void
DrawAngledText(da, x0, y0, c, s, str, len)
Widget	da;
float	c, s;
char	*str;
float	x0, y0;
int	len;
	{
	float	x, y;
	int	w, l;
	register	i;
	char	*cp;

	if (s == 0.0) y0 += FontAscent(current_font)*0.5;
	if (c == 0.0) x0 -= TextWidth(current_font, "_", 1)*0.5;
	x = x0;
	y = y0;
	if ((c > 0.0) && (c <= 0.5)) {
		cp = str;
		for (i=0; i<len; i++) {
			l = i+1;
			w = FontAscent(current_font)*l;
			if (s > 0.0) {
				DrawText(da,x,y,cp,1);
				y = y0-w;
				w = w*c/s+0.5;
				x = x0+w;
				}
			else {
				y = y0+w;
				w = w*c/s+0.5;
				x = x0-w;
				DrawText(da,x,y,cp,1);
				}
			cp ++;
			}
		}
	else if ((c > 0.5) && (c <= 1.0)) {
		cp = str;
		for (i=0; i<len; i++) {
			l = i+1;
			DrawText(da, x, y, cp, 1);
			w = TextWidth(current_font, str, l);
			x = x0+w;
			w = w*s/c+0.5;
			y = y0-w;
			cp ++;
			}
		}
	else if ((c <= 0.0) && (c >= (-0.5))) {
		cp = &(str[len-1]);
		for (i=len; i>0; i--) {
			l = len-i+1;
			w = FontAscent(current_font)*l;
			if (s > 0.0) {
				DrawText(da,x,y,cp,1);
				y = y0-w;
				w = w*c/s+0.5;
				x = x0+w;
				}
			else {
				y = y0+w;
				w = w*c/s+0.5;
				x = x0-w;
				DrawText(da,x,y,cp,1);
				}
			cp --;
			}
		}
	else {
		cp = &(str[len-1]);
		for (i=len; i>0; i--) {
			l = len-i+1;
			w = TextWidth(current_font, str, l);
			x = x0-w;
			w = w*s/c+0.5;
			y = y0+w;
			DrawText(da, x, y, cp, 1);
			cp --;
			}
		}
	}

/*
 *	Draw text.
 */
void
DrawText(da, x, y, s, l)
Widget	da;
float	x, y;
int	l;
char	*s;
	{
	if (!l)
		XDrawString(hnms_dpy, XtWindow(da), diag_gc, (int)x, (int)y, s,
			strlen(s));
	else
		XDrawString(hnms_dpy, XtWindow(da), diag_gc, (int)x, (int)y, s,
			l);
	}

/*
 *	Get the extents of a text string.
 */
int
GetTextExtents(fi, str, nchars, w, h, a, d)
int	fi, nchars;
char	*str;
int	*w, *h, *a, *d;
	{
	int	direction;
	int	ascent, descent;
	XCharStruct	overall;

	XTextExtents(diag_fontinfo[fi], str, nchars, &direction, &ascent,
		&descent, &overall);
	*w = overall.width;
	*h = overall.descent+overall.ascent;
	*d = overall.descent;
	*a = overall.ascent;
	return(overall.width);
	}


/*
 *	Get the width of a text string.
 */
int
TextWidth(fi, str, nchars)
int	fi, nchars;
char	*str;
	{
	return(XTextWidth(diag_fontinfo[fi], str, nchars));
	}


void
WidgetPixmap(w, pixmap)
Widget	w;
int	pixmap;
	{
	XtVaSetValues(w,
		XmNlabelPixmap, pix[pixmap],
		NULL);
	}
