/************************************************************************
 *	TITLE:			GEMLIB.C				*
 *	PROJECT:		JAGUAR					*
 *	FUNCTION:		GEM like Library			*
 *	PROGRAMMER:		Cary Gee, Hans-Martin Krober		*
 *	DATE:			1/95					*
 *									*
 *              COPYRIGHT 1993,1994 Atari U.S. Corporation              *
 *          UNATHORIZED REPRODUCTION, ADAPTATION, DISTRIBUTION,         *
 *          PERFORMANCE OR DISPLAY OF THIS COMPUTER PROGRAM OR          *
 *        THE ASSOCIATED AUDIOVISUAL WORK IS STRICTLY PROHIBITED.       *
 *                            ALL RIGHTS RESERVED.                      *
 *									*
 ************************************************************************/

#include <stdarg.h>
#include "portab.h"
#include "glib.h"
#include "gemlib.h"
#include "joypad.h"
#include "alloc.h"
#include "slibc.h"

WORD            parser(VOID);

/*
 * 
 * ===========================================================================
 * INTERNAL PROTOTYPES
 */

/*
 * Object Library
 */

VOID            ob_draw(OBJECT * tree, WORD obj, WORD depth);
WORD            ob_varargs(OBJECT *,...);
WORD            alpha_char2ix(BYTE *, BYTE *, BYTE *);
WORD            get_par(OBJECT * tree, WORD obj);
VOID
everyobj(OBJECT * tree, WORD this, WORD last,
	 WORD startx, WORD starty, WORD maxdep);
VOID            just_draw(OBJECT * tree, WORD obj, WORD sx, WORD sy);
VOID            draw_alphaslider(SLALPHINFO *, OBJECT *, WORD, WORD, WORD);
VOID            draw_fltslider(SLFLTINFO *, OBJECT *, WORD, WORD, WORD);
VOID            draw_intslider(SLINTINFO *, OBJECT *, WORD, WORD, WORD);
VOID            draw_txtslider(SLTXTINFO *, OBJECT *, WORD, WORD, WORD);
VOID            draw_list(OBJECT *, WORD, WORD);
VOID            show_list(OBJECT *, WORD, WORD);
VOID            dn_list(OBJECT *, WORD);
VOID            up_list(OBJECT *, WORD);

BYTE
ob_sst(OBJECT * tree, WORD obj, LONG * pspec, WORD * pstate,
       WORD * ptype, WORD * pflags, GRECT * pt, WORD * pth);
VOID
gr_crack(UWORD color, WORD * pbc, WORD * ptc, WORD * pip,
	 WORD * pic, WORD * pmd);
VOID            ob_setxywh(OBJECT * tree, WORD obj, GRECT * rect);


/*
 * Graphics Text Library
 */

VOID            gsx_tblt(WORD, WORD, WORD, BYTE *);
WORD            gr_just(WORD, BYTE *, WORD, WORD, GRECT *);
VOID            gr_gtext(WORD, BYTE *, GRECT *, WORD);
VOID            gsx_tcalc(BYTE *, WORD *, WORD *, WORD *);
VOID            gtext_attr(WORD, WORD, WORD, WORD);

/*
 * Etc
 */
VOID            _do_nothing(VOID);

/*
 * 
 * ===========================================================================
 * DEFINES
 */

#define ADJ3DPIX	3
#define ADJOUTLPIX	3
#define ADJSHADPIX	SHADOW
#define LLOWD(x) 	((UWORD)(x))
#define LLOBT(x) 	((BYTE)(x))
#define LBYTE2(x) 	(*((x)+1))
#define LBYTE3(x) 	(*(x))
#define LWGET(x) 	((WORD) *((WORD *)(x)))
#define TED_THICKNESS	22
#define LHIBT(x) 	((BYTE)(x >> 8))
#define	XADJ3DPIX	2

/*
 * 
 * ===========================================================================
 * EXTERNALS
 */

EXTERN LONG     _levels;
EXTERN LONG     _edges;
EXTERN VOID     _readpad(VOID);

EXTERN WORD    *v_bas_ad;

EXTERN VOID     voices_off(VOID);

/*
 * 
 * ===========================================================================
 * GLOBALS
 */

WORD            _ap_id;

WORD            gl_wchar;
WORD            gl_hchar;


LONG            sl_table[] = {	/* Ramping values for slider code */
	0L,
	1L,
	10L,
	100L,
	1000L,
	10000L,
	100000L,
	1000000L,
	10000000L,
	100000000L,
	1000000000L
};

EXTERN BYTE     MenuBuffer[];

/*
 * 
 * ===========================================================================
 * APPLICATION LIBRARY
 */

WORD
appl_init(VOID)
{
	_ap_id = 1;
	gl_wchar = 8;
	gl_hchar = 8;

	_timeleft_middle = 0L;
	_timeleft_count = 0L;
	_slider_ti = 10L;
	_alphaslider_kidx = 0L;
	_alphaslider_oldkey = -2L;
	_joypad_timer = 0L;
	_joypad_speed = 10L;


	return _ap_id;
}

VOID
appl_exit(VOID)
{

}

/*
 * 
 * ===========================================================================
 * OBJECT LIBRARY
 */


/*
 * Lookup a string in a table for an ALPHA SLIDER
 */

WORD
alpha_char2ix(str, ix, tab)
	REG BYTE       *str, *ix, *tab;	/* string, indexes into table, table */
{
	REG WORD        i;
	REG BYTE       *t;
	WORD            err;

	err = 0;
	for (; *str; str++) {
		for (i = 0, t = tab; *t; t++, i++) {
			if (*t == *str) {
				*ix++ = i;
				break;
			}
		}
		if (!*t) {
			*ix++ = 0;
			err = -1;
		}
	}
	return err;
}

/*
 * Add an extended object to an object tree. Pretty powerful!
 */
WORD
objc_xadd(OBJECT * tree,...)
{
	va_list         ap;
	REG OBJECT     *op;
	XOBJECT        *xobp;
	REG UWORD       parent;
	REG UWORD       child;
	UWORD           lastkid;
	UWORD           type;
	WORD            ret;

	va_start(ap, tree);

	/*
	 * insert object into tree
	 */

	parent = (WORD) va_arg(ap, WORD);
	child = (WORD) va_arg(ap, WORD);
	type = (WORD) va_arg(ap, WORD);

	if (child == NIL)	/* what do you want?  */
		return -1;
	if (parent == NIL) {
		if (child != ROOT)
			return -1;
		tree[ROOT].ob_next = NIL;	/* make it root */
		tree[ROOT].ob_head = NIL;
		tree[ROOT].ob_tail = NIL;
	} else {
		tree[child].ob_next = parent;	/* ok, we're a child */
		lastkid = tree[parent].ob_tail;	/* but where are the toys? */
		if (lastkid == NIL)
			tree[parent].ob_head = child;
		else
			tree[lastkid].ob_next = child;

		tree[parent].ob_tail = child;
	}
	/*
	 * now set up the standard object parameters
	 */
	op = &tree[child];

	op->ob_type = type;
	op->ob_head = (WORD) va_arg(ap, WORD);
	op->ob_tail = (WORD) va_arg(ap, WORD);
	op->ob_x = (WORD) va_arg(ap, WORD);
	op->ob_y = (WORD) va_arg(ap, WORD);
	op->ob_width = (WORD) va_arg(ap, WORD);
	op->ob_height = (WORD) va_arg(ap, WORD);
	op->ob_flags = (WORD) va_arg(ap, WORD);
	op->ob_state = (WORD) va_arg(ap, WORD);
#if 0
	if (parent == 0)
		op->ob_flags |= LASTOB;
#endif
	/*
	 * set up extended parameters & initalize them (now it gets serious)
	 */
	switch (type) {
	case G_XTEXT:
	case G_XBOXTEXT:
		if ((op->ob_spec = (void *) malloc(sizeof(BOXTXTINFO))) == NULL) {
			return -2;
		}
		xobp = &((BOXTXTINFO *) op->ob_spec)->ex_ob;
		((BOXTXTINFO *) op->ob_spec)->bx_text = " ";
		((BOXTXTINFO *) op->ob_spec)->bx_bgcolor = LWHITE;
		((BOXTXTINFO *) op->ob_spec)->bx_txtcolor = BLACK;
		((BOXTXTINFO *) op->ob_spec)->bx_fontid = FNT_MEDIUM;
		((BOXTXTINFO *) op->ob_spec)->bx_align = TE_CNTR;
		break;
	case G_XBUTTON:
		if ((op->ob_spec = (void *) malloc(sizeof(BTTNINFO))) == NULL) {
			return -2;
		}
		xobp = &((BTTNINFO *) op->ob_spec)->ex_ob;
		((BTTNINFO *) op->ob_spec)->bt_text = " ";
		((BTTNINFO *) op->ob_spec)->bt_bgcolor = LWHITE;
		((BTTNINFO *) op->ob_spec)->bt_txtcolor = BLACK;
		((BTTNINFO *) op->ob_spec)->bt_fontid = FNT_MEDIUM;
		((BTTNINFO *) op->ob_spec)->bt_smchar = '0';
		((BTTNINFO *) op->ob_spec)->bt_callbk = NULL;
		((BTTNINFO *) op->ob_spec)->bt_data = NULL;
		break;
	case G_XBAR:
		if ((op->ob_spec = (void *) malloc(sizeof(BARINFO))) == NULL) {
			return -2;
		}
		xobp = &((BARINFO *) op->ob_spec)->ex_ob;
		((BARINFO *) op->ob_spec)->ba_callbk = NULL;
		((BARINFO *) op->ob_spec)->ba_data = NULL;
		((BARINFO *) op->ob_spec)->ba_curr = NIL;
		((BARINFO *) op->ob_spec)->ba_rcurr = NIL;
		((BARINFO *) op->ob_spec)->ba_first = 0;
		((BARINFO *) op->ob_spec)->ba_num = 0;
		break;
	case G_XALPHSLIDER:
		if ((op->ob_spec = (void *) malloc(sizeof(SLALPHINFO))) == NULL) {
			return -2;
		}
		xobp = &((SLALPHINFO *) op->ob_spec)->ex_ob;
		((SLALPHINFO *) op->ob_spec)->slname[0] = '\0';
		((SLALPHINFO *) op->ob_spec)->sliderx = 0;
		((SLALPHINFO *) op->ob_spec)->slidery = 0;
		((SLALPHINFO *) op->ob_spec)->mainstr = " ";
		((SLALPHINFO *) op->ob_spec)->extstr = " ";
		((SLALPHINFO *) op->ob_spec)->mainspaces = 1;
		((SLALPHINFO *) op->ob_spec)->extspaces = 1;
		((SLALPHINFO *) op->ob_spec)->table = "abcd";
		((SLALPHINFO *) op->ob_spec)->fontid = FNT_MEDIUM;
		((SLALPHINFO *) op->ob_spec)->charwidth = FNT_MWIDTH;
		((SLALPHINFO *) op->ob_spec)->charheight = FNT_MHEIGHT;
		((SLALPHINFO *) op->ob_spec)->cursor_index = 0;
		((SLALPHINFO *) op->ob_spec)->extflag = 1;
		((SLALPHINFO *) op->ob_spec)->data = NULL;
		((SLALPHINFO *) op->ob_spec)->callbk = NULL;
		break;
	case G_XFLTSLIDER:
		if ((op->ob_spec = (void *) malloc(sizeof(SLFLTINFO))) == NULL) {
			return -2;
		}
		xobp = &((SLFLTINFO *) op->ob_spec)->ex_ob;
		((SLFLTINFO *) op->ob_spec)->slname[0] = '\0';
		((SLFLTINFO *) op->ob_spec)->sliderx = 0;
		((SLFLTINFO *) op->ob_spec)->slidery = 0;
		((SLFLTINFO *) op->ob_spec)->intval = 0L;
		((SLFLTINFO *) op->ob_spec)->fracval = 0L;
		((SLFLTINFO *) op->ob_spec)->intspaces = 5;
		((SLFLTINFO *) op->ob_spec)->fracspaces = 5;
		((SLFLTINFO *) op->ob_spec)->maxint = 65535;
		((SLFLTINFO *) op->ob_spec)->maxfrac = 65535;
		((SLFLTINFO *) op->ob_spec)->fontid = FNT_MEDIUM;
		((SLFLTINFO *) op->ob_spec)->charwidth = FNT_MWIDTH;
		((SLFLTINFO *) op->ob_spec)->charheight = FNT_MHEIGHT;
		((SLFLTINFO *) op->ob_spec)->cursor_index = 0;
		((SLFLTINFO *) op->ob_spec)->shiftcount = 4;
		((SLFLTINFO *) op->ob_spec)->data = NULL;
		((SLFLTINFO *) op->ob_spec)->callbk = NULL;
		break;
	case G_XINTSLIDER:
		if ((op->ob_spec = (void *) malloc(sizeof(SLINTINFO))) == NULL) {
			return -2;
		}
		xobp = &((SLINTINFO *) op->ob_spec)->ex_ob;
		((SLINTINFO *) op->ob_spec)->slname[0] = '\0';
		((SLINTINFO *) op->ob_spec)->sliderx = 0;
		((SLINTINFO *) op->ob_spec)->slidery = 0;
		((SLINTINFO *) op->ob_spec)->intval = 0L;
		((SLINTINFO *) op->ob_spec)->intspaces = 5;
		((SLINTINFO *) op->ob_spec)->maxint = 65535;
		((SLINTINFO *) op->ob_spec)->fontid = FNT_MEDIUM;
		((SLINTINFO *) op->ob_spec)->charwidth = FNT_MWIDTH;
		((SLINTINFO *) op->ob_spec)->charheight = FNT_MHEIGHT;
		((SLINTINFO *) op->ob_spec)->cursor_index = 0;
		((SLINTINFO *) op->ob_spec)->changesign = 0;
		((SLINTINFO *) op->ob_spec)->signextend = 0;
		((SLINTINFO *) op->ob_spec)->data = NULL;
		((SLINTINFO *) op->ob_spec)->callbk = NULL;
		break;
	case G_XTXTSLIDER:
		if ((op->ob_spec = (void *) malloc(sizeof(SLTXTINFO))) == NULL) {
			return -2;
		}
		xobp = &((SLTXTINFO *) op->ob_spec)->ex_ob;
		((SLTXTINFO *) op->ob_spec)->slname[0] = '\0';
		((SLTXTINFO *) op->ob_spec)->sliderx = 0;
		((SLTXTINFO *) op->ob_spec)->slidery = 0;
		((SLTXTINFO *) op->ob_spec)->table = NULL;
		((SLTXTINFO *) op->ob_spec)->maxitems = 0;
		((SLTXTINFO *) op->ob_spec)->maxlength = 0;
		((SLTXTINFO *) op->ob_spec)->fontid = FNT_MEDIUM;
		((SLTXTINFO *) op->ob_spec)->charwidth = FNT_MWIDTH;
		((SLTXTINFO *) op->ob_spec)->charheight = FNT_MHEIGHT;
		((SLTXTINFO *) op->ob_spec)->index = 0;
		((SLTXTINFO *) op->ob_spec)->data = NULL;
		((SLTXTINFO *) op->ob_spec)->callbk = NULL;
		break;
	case G_XLIST:
		if ((op->ob_spec = (void *) malloc(sizeof(LISTINFO))) == NULL) {
			return -2;
		}
		xobp = &((LISTINFO *) op->ob_spec)->ex_ob;
		((LISTINFO *) op->ob_spec)->callbk = NULL;
		((LISTINFO *) op->ob_spec)->data = NULL;
		((LISTINFO *) op->ob_spec)->name[0] = '\0';
		((LISTINFO *) op->ob_spec)->index = 0;
		((LISTINFO *) op->ob_spec)->maxitems = 0;
		((LISTINFO *) op->ob_spec)->visitems = 0;
		((LISTINFO *) op->ob_spec)->ncols = 1;
		((LISTINFO *) op->ob_spec)->titles[0][0] = '\0';
		((LISTINFO *) op->ob_spec)->cx[0] = 0;
		((LISTINFO *) op->ob_spec)->fontid = FNT_SMALL;
		((LISTINFO *) op->ob_spec)->charwidth = FNT_SWIDTH;
		((LISTINFO *) op->ob_spec)->charheight = FNT_SHEIGHT;

		break;
	default:
		op->ob_spec = (VOID *) LWHITE;	/* set fill color to grey */
		xobp = NULL;
	}
	/*
	 * reset joypad movement parameters
	 */
	if (xobp != NULL) {
		xobp->ob_up = -1;
		xobp->ob_down = -1;
		xobp->ob_left = -1;
		xobp->ob_right = -1;
	}
	ret = ob_varargs(tree, parent, child, type, xobp, ap);

	va_end(ap);
	return ret;
}				/* objc_xadd */


WORD
ob_varargs(OBJECT * tree,...)
{
	va_list         ap;
	REG OBJECT     *op;
	XOBJECT        *xobp;
	REG UWORD       child;
	UWORD           type;
	UWORD           arg;
	UWORD           parent;
	UWORD           where;
	ULONG           lvalue;
	UWORD           i, d;
	UWORD           tix;	/* title index; */
	UWORD           lflag = FALSE;
	UWORD           uflag = FALSE;
	UWORD           nocol = TRUE;
	BYTE           *s, *t;

	va_start(ap, tree);

	/*
	 * insert object into tree
	 */
	parent = (WORD) va_arg(ap, WORD);
	child = (WORD) va_arg(ap, WORD);
	type = (WORD) va_arg(ap, WORD);
	xobp = (XOBJECT *) va_arg(ap, XOBJECT *);
	ap = (VOID *) va_arg(ap, VOID *);
	tix = 0;
	op = &tree[child];



	/*
	 * parse variable paramters
	 */
	while ((arg = va_arg(ap, WORD)) != 0) {
		switch (arg) {
			/*
			 * Old Object Parameters
			 */
		case T_OB_SPEC:
			d = (WORD) va_arg(ap, WORD);
			switch (d) {
			case T_OBSPEC_FILLCOLOR:
				lvalue = (ULONG) op->ob_spec;
				lvalue &= ~0x0fL;
				lvalue |= (ULONG) (((WORD) va_arg(ap, WORD)) & 0x0f);
				op->ob_spec = (VOID *) lvalue;
				break;
			}
			break;
			/*
			 * Extended Object Parameters
			 */
		case T_OB_UP:
			xobp->ob_up = (WORD) va_arg(ap, WORD);
			break;
		case T_OB_DOWN:
			xobp->ob_down = (WORD) va_arg(ap, WORD);
			break;
		case T_OB_LEFT:
			xobp->ob_left = (WORD) va_arg(ap, WORD);
			break;
		case T_OB_RIGHT:
			xobp->ob_right = (WORD) va_arg(ap, WORD);
			break;
		case T_OB_LATTACH:
			where = (WORD) va_arg(ap, WORD);
			d = (WORD) va_arg(ap, WORD);
			lflag = TRUE;
			if (where == parent) {
				d += ((tree[child].ob_flags & IS3DOBJ) ? 2 : 0);
				tree[child].ob_x = d;
			} else {
				d += ((tree[child].ob_flags & IS3DOBJ) ? 4 : 0);
				tree[child].ob_x = tree[where].ob_x +
					tree[where].ob_width + d;
			}
			break;
		case T_OB_RATTACH:
			where = (WORD) va_arg(ap, WORD);
			d = (WORD) va_arg(ap, WORD);
			if (where == parent) {
				if (lflag) {
					d += ((tree[child].ob_flags & IS3DOBJ) ?
					      2 : 0);
					tree[child].ob_width =
						tree[parent].ob_width -
						tree[child].ob_x - d;
				} else {
					d += ((tree[child].ob_flags & IS3DOBJ) ?
					      4 : 0);
					tree[child].ob_x =
						tree[parent].ob_width -
						tree[child].ob_width - d;
				}
			} else {
				if (lflag) {
					d += ((tree[child].ob_flags & IS3DOBJ) ? 2 : 0);
					tree[child].ob_width =
						tree[where].ob_x -
						tree[child].ob_x - d;
				} else {
					d += ((tree[child].ob_flags & IS3DOBJ) ? 4 : 0);
					tree[child].ob_x = tree[where].ob_x -
						tree[child].ob_width - d;
				}
			}
			break;
		case T_OB_UATTACH:
			where = (WORD) va_arg(ap, WORD);
			d = (WORD) va_arg(ap, WORD);

			uflag = TRUE;
			if (where == parent) {
				d += ((tree[child].ob_flags & IS3DOBJ) ? 2 : 0);
				tree[child].ob_y = d;
			} else {
				d += ((tree[child].ob_flags & IS3DOBJ) ? 4 : 0);
				tree[child].ob_y = tree[where].ob_y +
					tree[where].ob_height + d;
			}
			break;
		case T_OB_DATTACH:
			where = (WORD) va_arg(ap, WORD);
			d = (WORD) va_arg(ap, WORD);
			if (where == parent) {
				if (uflag) {
					d += ((tree[child].ob_flags & IS3DOBJ) ?
					      2 : 0);
					tree[child].ob_height =
						tree[parent].ob_height -
						tree[child].ob_height - d;
				} else {
					d += ((tree[child].ob_flags & IS3DOBJ) ?
					      4 : 0);
					tree[child].ob_y =
						tree[parent].ob_height -
						tree[child].ob_height - d;
				}
			} else {
				if (uflag) {
					d += ((tree[child].ob_flags & IS3DOBJ) ? 2 : 0);
					tree[child].ob_height =
						tree[where].ob_y -
						tree[child].ob_y - d;
				} else {
					d += ((tree[child].ob_flags & IS3DOBJ) ? 4 : 0);
					tree[child].ob_y = tree[where].ob_y -
						tree[child].ob_height - d;
				}
			}
			break;
			/*
			 * XBOXTXT
			 */
		case T_BX_TEXT:
			s = (BYTE *) va_arg(ap, BYTE *);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			((BOXTXTINFO *) op->ob_spec)->bx_text = t;
			/* we do this because we have problems */
			/* accessing bytes from the ROMulator  */
			break;
		case T_BX_BGCOLOR:
			((BOXTXTINFO *) op->ob_spec)->bx_bgcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BX_TXTCOLOR:
			((BOXTXTINFO *) op->ob_spec)->bx_txtcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BX_FONTID:
			((BOXTXTINFO *) op->ob_spec)->bx_fontid =
				(BYTE) va_arg(ap, WORD);
			break;
		case T_BX_ALIGN:
			((BOXTXTINFO *) op->ob_spec)->bx_align =
				(BYTE) va_arg(ap, WORD);
			break;
			/*
			 * XBUTTON
			 */
		case T_BT_TEXT:
			s = (BYTE *) va_arg(ap, BYTE *);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			((BTTNINFO *) op->ob_spec)->bt_text = t;
			/* we do this because we have problems */
			/* accessing bytes from the ROMulator  */
			break;
		case T_BT_BGCOLOR:
			((BTTNINFO *) op->ob_spec)->bt_bgcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BT_TXTCOLOR:
			((BTTNINFO *) op->ob_spec)->bt_txtcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BT_FONTID:
			((BTTNINFO *) op->ob_spec)->bt_fontid =
				(BYTE) va_arg(ap, WORD);
			break;
		case T_BT_SMCHAR:
			((BTTNINFO *) op->ob_spec)->bt_smchar =
				(BYTE) va_arg(ap, WORD);
			break;
		case T_BT_CALLBK:
			((BTTNINFO *) op->ob_spec)->bt_callbk =
				(LONG(*) (OBJECT *, WORD, WORD, WORD, ULONG)) va_arg(ap, LFCTP);
			break;

			/*
			 * XBUTTON BAR
			 */
		case T_BA_NUM:
			((BARINFO *) op->ob_spec)->ba_num =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BA_CURR:
			((BARINFO *) op->ob_spec)->ba_curr =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BA_RCURR:
			((BARINFO *) op->ob_spec)->ba_rcurr =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BA_FIRST:
			((BARINFO *) op->ob_spec)->ba_first =
				(WORD) va_arg(ap, WORD);
			break;
			/*
			 * FLOAT SLIDER
			 */
		case T_FLT_SLNAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = ((SLFLTINFO *) op->ob_spec)->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;
		case T_FLT_INTVAL:
			((SLFLTINFO *) op->ob_spec)->intval =
				(LONG) va_arg(ap, LONG);
			break;
		case T_FLT_FRACVAL:
			((SLFLTINFO *) op->ob_spec)->fracval =
				(LONG) va_arg(ap, LONG);
			break;
		case T_FLT_INTSPACES:
			((SLFLTINFO *) op->ob_spec)->intspaces =
				(WORD) va_arg(ap, WORD);
			break;
		case T_FLT_FRACSPACES:
			((SLFLTINFO *) op->ob_spec)->fracspaces =
				(WORD) va_arg(ap, WORD);
			break;
		case T_FLT_MAXINT:
			((SLFLTINFO *) op->ob_spec)->maxint =
				(LONG) va_arg(ap, LONG);
			break;
		case T_FLT_MAXFRAC:
			((SLFLTINFO *) op->ob_spec)->maxfrac =
				(LONG) va_arg(ap, LONG);
			break;
		case T_FLT_FONTID:
			d = ((SLFLTINFO *) op->ob_spec)->fontid =
				(WORD) va_arg(ap, WORD);
			switch (d) {
			case FNT_SMALL:
				((SLFLTINFO *) op->ob_spec)->charwidth =
					FNT_SWIDTH;
				((SLFLTINFO *) op->ob_spec)->charheight =
					FNT_SHEIGHT;
				break;
			case FNT_MEDIUM:
				((SLFLTINFO *) op->ob_spec)->charwidth =
					FNT_MWIDTH;
				((SLFLTINFO *) op->ob_spec)->charheight =
					FNT_MHEIGHT;
				break;
			case FNT_BIG:
				((SLFLTINFO *) op->ob_spec)->charwidth =
					FNT_BWIDTH;
				((SLFLTINFO *) op->ob_spec)->charheight =
					FNT_BHEIGHT;
				break;
			}
			break;
		case T_FLT_CU_INDEX:
			((SLFLTINFO *) op->ob_spec)->cursor_index =
				(WORD) va_arg(ap, WORD);
			break;
		case T_FLT_SHIFTCNT:
			((SLFLTINFO *) op->ob_spec)->shiftcount =
				(WORD) va_arg(ap, WORD);
			break;
		case T_FLT_DATA:
			break;
		case T_FLT_CALLBK:
			break;

			/*
			 * ALPHA SLIDER
			 */
		case T_ALPH_SLNAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = ((SLALPHINFO *) op->ob_spec)->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;
		case T_ALPH_MAINSTR:
			s = (BYTE *) va_arg(ap, BYTE *);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			((SLALPHINFO *) op->ob_spec)->mainstr = t;
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			((SLALPHINFO *) op->ob_spec)->mainix = t;
			break;
		case T_ALPH_EXTSTR:
			s = (BYTE *) va_arg(ap, BYTE *);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			((SLALPHINFO *) op->ob_spec)->extstr = t;
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			((SLALPHINFO *) op->ob_spec)->extix = t;
			break;
		case T_ALPH_MAINSPACES:
			((SLALPHINFO *) op->ob_spec)->mainspaces =
				(WORD) va_arg(ap, WORD);
			break;
		case T_ALPH_EXTSPACES:
			((SLALPHINFO *) op->ob_spec)->extspaces =
				(WORD) va_arg(ap, WORD);
			break;
		case T_ALPH_TABLE:
			((SLALPHINFO *) op->ob_spec)->table =
				(BYTE *) va_arg(ap, BYTE *);
			break;
		case T_ALPH_FONTID:
			d = ((SLFLTINFO *) op->ob_spec)->fontid =
				(WORD) va_arg(ap, WORD);
			switch (d) {
			case FNT_SMALL:
				((SLALPHINFO *) op->ob_spec)->charwidth =
					FNT_SWIDTH;
				((SLALPHINFO *) op->ob_spec)->charheight =
					FNT_SHEIGHT;
				break;
			case FNT_MEDIUM:
				((SLALPHINFO *) op->ob_spec)->charwidth =
					FNT_MWIDTH;
				((SLALPHINFO *) op->ob_spec)->charheight =
					FNT_MHEIGHT;
				break;
			case FNT_BIG:
				((SLALPHINFO *) op->ob_spec)->charwidth =
					FNT_BWIDTH;
				((SLALPHINFO *) op->ob_spec)->charheight =
					FNT_BHEIGHT;
				break;
			}
			break;
		case T_ALPH_CU_INDEX:
			((SLALPHINFO *) op->ob_spec)->cursor_index =
				(WORD) va_arg(ap, WORD);
			break;
		case T_ALPH_EXTFLAG:
			((SLALPHINFO *) op->ob_spec)->extflag =
				(WORD) va_arg(ap, WORD);
			break;
		case T_ALPH_DATA:
			break;
		case T_ALPH_CALLBK:
			break;
			/*
			 * INT SLIDER
			 */
		case T_INT_SLNAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = ((SLINTINFO *) op->ob_spec)->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;
		case T_INT_INTVAL:
			((SLINTINFO *) op->ob_spec)->intval =
				(LONG) va_arg(ap, LONG);
			break;
		case T_INT_INTSPACES:
			((SLINTINFO *) op->ob_spec)->intspaces =
				(WORD) va_arg(ap, WORD);
			break;
		case T_INT_MAXINT:
			((SLINTINFO *) op->ob_spec)->maxint =
				(LONG) va_arg(ap, LONG);
			break;
		case T_INT_FONTID:
			d = ((SLINTINFO *) op->ob_spec)->fontid =
				(WORD) va_arg(ap, WORD);
			switch (d) {
			case FNT_SMALL:
				((SLINTINFO *) op->ob_spec)->charwidth =
					FNT_SWIDTH;
				((SLINTINFO *) op->ob_spec)->charheight =
					FNT_SHEIGHT;
				break;
			case FNT_MEDIUM:
				((SLINTINFO *) op->ob_spec)->charwidth =
					FNT_MWIDTH;
				((SLINTINFO *) op->ob_spec)->charheight =
					FNT_MHEIGHT;
				break;
			case FNT_BIG:
				((SLINTINFO *) op->ob_spec)->charwidth =
					FNT_BWIDTH;
				((SLINTINFO *) op->ob_spec)->charheight =
					FNT_BHEIGHT;
				break;
			}
			break;
		case T_INT_CU_INDEX:
			((SLINTINFO *) op->ob_spec)->cursor_index =
				(WORD) va_arg(ap, WORD);
			break;
		case T_INT_DATA:
			break;
		case T_INT_CALLBK:
			break;
			/*
			 * TXT SLIDER
			 */
		case T_TXT_SLNAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = ((SLTXTINFO *) op->ob_spec)->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;
		case T_TXT_TABLE:
			((SLTXTINFO *) op->ob_spec)->table =
				(BYTE **) va_arg(ap, BYTE **);
			break;
		case T_TXT_MAXITEMS:
			((SLTXTINFO *) op->ob_spec)->maxitems =
				(WORD) va_arg(ap, WORD);
			break;
		case T_TXT_MAXLEN:
			((SLTXTINFO *) op->ob_spec)->maxlength =
				(WORD) va_arg(ap, WORD);
			break;
		case T_TXT_FONTID:
			d = ((SLTXTINFO *) op->ob_spec)->fontid =
				(WORD) va_arg(ap, WORD);
			switch (d) {
			case FNT_SMALL:
				((SLTXTINFO *) op->ob_spec)->charwidth =
					FNT_SWIDTH;
				((SLTXTINFO *) op->ob_spec)->charheight =
					FNT_SHEIGHT;
				break;
			case FNT_MEDIUM:
				((SLTXTINFO *) op->ob_spec)->charwidth =
					FNT_MWIDTH;
				((SLTXTINFO *) op->ob_spec)->charheight =
					FNT_MHEIGHT;
				break;
			case FNT_BIG:
				((SLTXTINFO *) op->ob_spec)->charwidth =
					FNT_BWIDTH;
				((SLTXTINFO *) op->ob_spec)->charheight =
					FNT_BHEIGHT;
				break;
			}
			break;
		case T_TXT_DATA:
			break;
		case T_TXT_CALLBK:
			((SLTXTINFO *) op->ob_spec)->callbk =
				(LONG(*) (OBJECT *, WORD, SLTXTINFO *))
				va_arg(ap, LFCTP);
			break;
			/*
			 * XLIST
			 */
		case T_LST_NAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = ((LISTINFO *) op->ob_spec)->name;
			strncpy(t, s, 30);
			t[31] = '\0';
			break;
		case T_LST_TITLES:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = ((LISTINFO *) op->ob_spec)->titles[tix++];
			strncpy(t, s, 30);
			t[31] = '\0';
			break;
		case T_LST_INDEX:
			((LISTINFO *) op->ob_spec)->index =
				(WORD) va_arg(ap, WORD);
			break;
		case T_LST_MAXITEMS:
			((LISTINFO *) op->ob_spec)->maxitems =
				(WORD) va_arg(ap, WORD);
			break;
		case T_LST_VISITEMS:
			((LISTINFO *) op->ob_spec)->visitems =
				(WORD) va_arg(ap, WORD);
			break;
		case T_LST_NCOLS:
			((LISTINFO *) op->ob_spec)->ncols =
				(WORD) va_arg(ap, WORD);
			nocol = FALSE;
			break;
		case T_LST_CX:
			((LISTINFO *) op->ob_spec)->cx[0] =
				(WORD) va_arg(ap, WORD);
			break;
		case T_LST_CY:
			((LISTINFO *) op->ob_spec)->cy =
				(WORD) va_arg(ap, WORD);
			break;
		case T_LST_CALLBK:
			((LISTINFO *) op->ob_spec)->callbk =
				(LONG(*) (OBJECT *, WORD, LISTINFO *))
				va_arg(ap, LFCTP);
			break;
		case T_LST_FONTID:
			d = ((LISTINFO *) op->ob_spec)->fontid =
				(WORD) va_arg(ap, WORD);
			switch (d) {
			case FNT_SMALL:
				((LISTINFO *) op->ob_spec)->charwidth =
					FNT_SWIDTH;
				((LISTINFO *) op->ob_spec)->charheight =
					FNT_SHEIGHT;
				break;
			case FNT_MEDIUM:
				((LISTINFO *) op->ob_spec)->charwidth =
					FNT_MWIDTH;
				((LISTINFO *) op->ob_spec)->charheight =
					FNT_MHEIGHT;
				break;
			case FNT_BIG:
				((LISTINFO *) op->ob_spec)->charwidth =
					FNT_BWIDTH;
				((LISTINFO *) op->ob_spec)->charheight =
					FNT_BHEIGHT;
				break;
			}
		}		/* switch  */
	}			/* while */

	va_end(ap);

	switch (type) {
	case G_XFLTSLIDER:
		op->ob_width = (((SLFLTINFO *) op->ob_spec)->intspaces +
			      ((SLFLTINFO *) op->ob_spec)->fracspaces + 5) *
			((SLFLTINFO *) op->ob_spec)->charwidth;
		op->ob_height = 4 * ((SLFLTINFO *) op->ob_spec)->charheight;
		break;
	case G_XTXTSLIDER:
		op->ob_width =
			(((SLTXTINFO *) op->ob_spec)->maxlength + 5) *
			((SLTXTINFO *) op->ob_spec)->charwidth;
		op->ob_height = 4 * ((SLTXTINFO *) op->ob_spec)->charheight;
		break;
	case G_XALPHSLIDER:
		op->ob_width = (((SLALPHINFO *) op->ob_spec)->mainspaces +
			      ((SLALPHINFO *) op->ob_spec)->extspaces + 5) *
			((SLALPHINFO *) op->ob_spec)->charwidth;
		op->ob_height = 4 * ((SLALPHINFO *) op->ob_spec)->charheight;

		s = ((SLALPHINFO *) op->ob_spec)->table;
		for (i = 0; *s; s++)
			i++;
		((SLALPHINFO *) op->ob_spec)->tabitems = i;

		alpha_char2ix(((SLALPHINFO *) op->ob_spec)->mainstr,
			      ((SLALPHINFO *) op->ob_spec)->mainix,
			      ((SLALPHINFO *) op->ob_spec)->table);
		alpha_char2ix(((SLALPHINFO *) op->ob_spec)->extstr,
			      ((SLALPHINFO *) op->ob_spec)->extix,
			      ((SLALPHINFO *) op->ob_spec)->table);

		break;
	case G_XLIST:
		if (nocol)
			((LISTINFO *) op->ob_spec)->ncols = tix;
		d = ((LISTINFO *) op->ob_spec)->ncols;
		d = (d > tix) ? tix : d;

		for (i = 1; i < d; i++) {
			((LISTINFO *) op->ob_spec)->cx[i] =
				((LISTINFO *) op->ob_spec)->cx[i - 1] + (
									 (1 + strlen(((LISTINFO *) op->ob_spec)->titles[i - 1])) *
				     ((LISTINFO *) op->ob_spec)->charwidth);
		}
		((LISTINFO *) op->ob_spec)->cy = 24;
		((LISTINFO *) op->ob_spec)->visitems = (op->ob_height -
					   ((LISTINFO *) op->ob_spec)->cy) /
			(((LISTINFO *) op->ob_spec)->charheight + 2);
		if ((((LISTINFO *) op->ob_spec)->visitems % 2) != 0) {
			((LISTINFO *) op->ob_spec)->visitems -= 1;
		}
		break;

	}
	return 0;
}
/*
 * */
WORD
objc_xupdate(OBJECT * tree,...)
{
	va_list         ap;
	REG OBJECT     *op;
	XOBJECT        *xobp;
	REG UWORD       child;
	UWORD           type;
	WORD            ret;

	va_start(ap, tree);

	/*
	 * insert object into tree
	 */

	child = (WORD) va_arg(ap, WORD);
	if (child == NIL)	/* what do you want? */
		return -1;

	type = tree[child].ob_type;
	op = &tree[child];

	/*
	 * set up extended parameters
	 */
	switch (type) {
	case G_XTEXT:
	case G_XBOXTEXT:
		xobp = &((BOXTXTINFO *) op->ob_spec)->ex_ob;
		break;
	case G_XBUTTON:
		xobp = &((BTTNINFO *) op->ob_spec)->ex_ob;
		break;
	case G_XBAR:
		xobp = &((BARINFO *) op->ob_spec)->ex_ob;
		break;
	case G_XFLTSLIDER:
		xobp = &((SLFLTINFO *) op->ob_spec)->ex_ob;
		break;
	case G_XINTSLIDER:
		xobp = &((SLINTINFO *) op->ob_spec)->ex_ob;
		break;
	case G_XTXTSLIDER:
		xobp = &((SLTXTINFO *) op->ob_spec)->ex_ob;
		break;
	case G_XLIST:
		xobp = &((LISTINFO *) op->ob_spec)->ex_ob;
		break;
	}

	ret = ob_varargs(tree, 0, child, type, xobp, ap);
	va_end(ap);
	return ret;
}


/*
 * */
WORD
objc_xget(OBJECT * tree,...)
{
	va_list         ap;
	REG OBJECT     *op;
	XOBJECT        *xobp;
	REG UWORD       child;
	UWORD           type;
	UWORD           arg;
	UWORD           i, d;
	UWORD           tix;	/* title index; */
	LONG           *lp;

	va_start(ap, tree);

	/*
	 * insert object into tree
	 */


	child = (WORD) va_arg(ap, WORD);
	if (child == NIL)	/* what do you want? */
		return -1;

	type = tree[child].ob_type;
	tix = 0;
	op = &tree[child];


	/*
	 * parse variable paramters
	 */
	while ((arg = va_arg(ap, WORD)) != 0) {
		switch (arg) {
			/*
			 * INT SLIDER
			 */
		case T_INT_INTVAL:
			lp = va_arg(ap, LONG *);
			*lp = ((SLINTINFO *) op->ob_spec)->intval;
			break;

		}		/* switch */
	}			/* while */

	va_end(ap);
	return 0;
}


/*
 * Object draw routine that walk the tree and draws the appropriate objects.
 * Sets clipping TOO!
 */
VOID
objc_draw(OBJECT * tree, WORD obj, WORD depth,
	  WORD x, WORD y, WORD w, WORD h)
{				/* Clipping rectangle */
	/* Handle clip here */
	/* OK..clip is set um, here!!! */
	/* vs_clip(etc....); */

	ob_draw(tree, obj, depth);
}



/*
 * Object draw routine that walks the tree and draws the appropriate objects
 */
VOID
ob_draw(OBJECT * tree, WORD obj, WORD depth)
{
	WORD            last, pobj;
	WORD            sx, sy;

	last = ((obj == ROOT) ? NIL : ObNext(obj));
	pobj = get_par(tree, obj);

	if (pobj != NIL)
		objc_offset(tree, pobj, &sx, &sy);
	else
		sx = sy = 0;

	everyobj(tree, obj, last, sx, sy, depth);
}


/*
 * Routine that will find the parent of a given object.  The idea is to walk
 * to the end of our siblings and return to our parent.  If object is the
 * root, then return NIL as parent.
 */
WORD
get_par(OBJECT * tree, WORD obj)
{
	REG WORD        pobj;

	pobj = obj;

	if (obj == ROOT)
		return (NIL);

	do {
		obj = pobj;
		pobj = ObNext(obj);

	} while (ObTail(pobj) != obj);

	return pobj;
}




/*
 * Routine to find the x,y offset of a particular object relative to the
 * physical screen.  This involves accumulating the offsets of all the
 * objects parents up to and including the root
 */
VOID
objc_offset(OBJECT * tree, WORD obj, WORD * pxoff, WORD * pyoff)
{
	if (obj == NIL)
		return;
	*pxoff = *pyoff = 0;
	do {
		*pxoff += ObX(obj);
		*pyoff += ObY(obj);
		obj = get_par(tree, obj);
	} while (obj != NIL);
}




/*
 * Non-recursive tree traversal
 */
VOID
everyobj(OBJECT * tree, WORD this, WORD last,
	 WORD startx, WORD starty, WORD maxdep)
{
	WORD            tmp1;
	WORD            depth;
	WORD            x[8], y[8];

	x[0] = startx;
	y[0] = starty;

	depth = 1;

child:
	if (this == last)
		return;

	x[depth] = x[depth - 1] + ObX(this);
	y[depth] = y[depth - 1] + ObY(this);
	just_draw(tree, this, x[depth], y[depth]);

	tmp1 = ObHead(this);


	if (tmp1 != NIL) {
		if ((!(ObFlags(this) & HIDETREE)) && (depth <= maxdep)) {
			depth++;
			this = tmp1;
			goto child;
		}
	}
sibling:
	tmp1 = ObNext(this);
	if ((tmp1 == last) || (this == ROOT))
		return;

	if (ObTail(tmp1) != this) {
		this = tmp1;
		goto child;
	}
	depth--;
	this = tmp1;
	goto sibling;
}

/*
 * This one does the real object drawing work
 */

VOID
just_draw(OBJECT * tree, WORD obj, WORD sx, WORD sy)
{
	UWORD           type;
	UWORD           state;
	UWORD           flag;
	UWORD           fillcolor;
	OBJECT         *curtree;
	GRECT           pt;

	curtree = (OBJECT *) & tree[obj];
	type = ObType(obj);
	state = ObState(obj);
	flag = ObFlags(obj);

	if (flag & HIDETREE)
		return;

	vsf_color(LWHITE);

	fillcolor = (UWORD) ((ULONG) tree[obj].ob_spec & 0x0f);

	switch (type) {
	case G_BOX:
	case G_XBAR:
		if (tree[obj].ob_flags & IS3DOBJ) {
			if (tree[obj].ob_state & SELECTED)
				v_Ibar3d(sx, sy, ObW(obj), ObH(obj));
			else
				v_bar3d(sx, sy, ObW(obj), ObH(obj));
		} else {
			vsf_color(fillcolor);
			v_bar(sx, sy, ObW(obj), ObH(obj));
		}
		break;
	case G_STRING:
		pt.g_x = sx;
		pt.g_y = sy;
		pt.g_w = tree[obj].ob_width;
		pt.g_h = tree[obj].ob_height;

		gtext_attr(1, 0x0001, 0, 1);
		gr_gtext(TE_LEFT, (BYTE *) tree[obj].ob_spec, &pt, 0);
		break;

	case G_XBUTTON:
		{
			BTTNINFO       *bttn = (BTTNINFO *) tree[obj].ob_spec;

			if (tree[obj].ob_state & SELECTED)
				v_Ibar3d(sx, sy, ObW(obj), ObH(obj));
			else
				v_bar3d(sx, sy, ObW(obj), ObH(obj));
			pt.g_x = sx;
			pt.g_y = sy;
			pt.g_w = tree[obj].ob_width;
			pt.g_h = tree[obj].ob_height;

			if (bttn != NULL) {
				gtext_attr(bttn->bt_fontid, bttn->bt_txtcolor, 0, 1);
				gr_gtext(TE_CNTR, bttn->bt_text, &pt, 0);

				vst_font(FNT_SMALL);	/* set font type */
				pt.g_x = sx + pt.g_w - 7;
				pt.g_y = sy + 1;

				v_bltchr(pt.g_x, pt.g_y, bttn->bt_smchar);
			}
		}
		break;

	case G_XBOXTEXT:
		{
			BOXTXTINFO     *box = (BOXTXTINFO *) tree[obj].ob_spec;

			if (tree[obj].ob_flags & IS3DOBJ) {
				if (tree[obj].ob_state & SELECTED)
					v_Ibar3d(sx, sy, ObW(obj), ObH(obj));
				else
					v_bar3d(sx, sy, ObW(obj), ObH(obj));
			} else
				v_bar3d(sx, sy, ObW(obj), ObH(obj));

			pt.g_x = sx;
			pt.g_y = sy;
			pt.g_w = tree[obj].ob_width;
			pt.g_h = tree[obj].ob_height;

			gtext_attr(box->bx_fontid, box->bx_txtcolor, 0, 1);
			gr_gtext(box->bx_align, box->bx_text, &pt, 0);

		}
		break;

	case G_XTEXT:
		{
			BOXTXTINFO     *box = (BOXTXTINFO *) tree[obj].ob_spec;

			pt.g_x = sx;
			pt.g_y = sy;
			pt.g_w = tree[obj].ob_width;
			pt.g_h = tree[obj].ob_height;

			gtext_attr(box->bx_fontid, box->bx_txtcolor, 0, 1);
			gr_gtext(box->bx_align, box->bx_text, &pt, 0);

		}
		break;
#if 1
	case G_XALPHSLIDER:
		draw_alphaslider((SLALPHINFO *) curtree->ob_spec, tree, obj, sx, sy);
		break;
	case G_XFLTSLIDER:
		draw_fltslider((SLFLTINFO *) curtree->ob_spec, tree, obj, sx, sy);
		break;

	case G_XTXTSLIDER:
		draw_txtslider((SLTXTINFO *) curtree->ob_spec, tree, obj, sx, sy);
		break;

	case G_XINTSLIDER:
		draw_intslider((SLINTINFO *) curtree->ob_spec, tree, obj, sx, sy);
		break;
	case G_XLIST:
		draw_list(&tree[obj], sx, sy);
		show_list(&tree[obj], sx, sy);
		break;
#endif
	case G_XBOXCHAR:
		if (tree[obj].ob_state & SELECTED)
			v_Ibar3d(sx, sy, ObW(obj), ObH(obj));
		else
			v_bar3d(sx, sy, ObW(obj), ObH(obj));

		pt.g_x = sx;
		pt.g_y = sy;
		pt.g_w = tree[obj].ob_width;
		pt.g_h = tree[obj].ob_height;

		gtext_attr(1, 0x0001, 0, 1);
		gr_gtext(TE_CNTR, (BYTE *) tree[obj].ob_spec, &pt, 0);
		break;
	default:
		break;
	}			/* switch */
}				/* just_draw */


/*
 * Draw a alpha numeric slider
 */
VOID
draw_alphaslider(slinfo, tree, obj, sx, sy)
	SLALPHINFO     *slinfo;
	OBJECT         *tree;
	WORD            obj;
	WORD            sx, sy;
{
	WORD            slwidth, slheight;
	WORD            boxx, boxy;
	WORD            intx, fracx, texty;
	WORD            titlex;

	vst_bgcolor(LWHITE);

	slinfo->sliderx = sx;
	slinfo->slidery = sy;

	slwidth = (slinfo->mainspaces + slinfo->extspaces + 5) *
		slinfo->charwidth;
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);
	intx = boxx + 2 * slinfo->charwidth;
	fracx = intx + (slinfo->mainspaces * slinfo->charwidth) +
		slinfo->charwidth;
	texty = boxy + (slinfo->charheight / 2);

	v_bar3d(boxx, slinfo->slidery, slwidth, 4 * slinfo->charheight);


	v_bar3d(boxx, boxy, slinfo->charwidth, slheight);
	v_bar3d(boxx + (2 * slinfo->charwidth), boxy,
		slwidth - (4 * slinfo->charwidth),
		slheight);
	v_bar3d(boxx + slwidth - slinfo->charwidth,
		boxy,
		slinfo->charwidth,
		slheight);


	titlex = (boxx + (slwidth / 2)) -
		(((strlen(slinfo->slname)) * 6) / 2);	/* assume 6x6 font */

	vst_color(LGREEN);
	vst_font(FNT_SMALL);
	vst_wrmode(1);

	v_gtext(titlex, slinfo->slidery + 1, slinfo->slname);

	vst_color(BLACK);
	vst_font(slinfo->fontid);
	vst_wrmode(0);


	v_bltchr(slinfo->sliderx, texty, 2);
	v_bltchr(slinfo->sliderx + slwidth - slinfo->charwidth, texty, 1);

	v_gtext(intx, texty, slinfo->mainstr);
	if (slinfo->extflag) {
		v_gtext(fracx - slinfo->charwidth, texty, ".");
		v_gtext(fracx, texty, slinfo->extstr);
	}
}

/*
 * Draw a floating point number slider
 */
VOID
draw_fltslider(slinfo, tree, obj, sx, sy)
	SLFLTINFO      *slinfo;
	OBJECT         *tree;
	WORD            obj;
	WORD            sx, sy;
{
	WORD            slwidth, slheight;
	BYTE            intstr[10];
	BYTE            fracstr[10];
	WORD            boxx, boxy;
	WORD            intx, fracx, texty;
	WORD            titlex;

	vst_bgcolor(LWHITE);

	slinfo->sliderx = sx;
	slinfo->slidery = sy;

	slwidth = (slinfo->intspaces + slinfo->fracspaces + 5) *
		slinfo->charwidth;
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);
	intx = boxx + 2 * slinfo->charwidth;
	fracx = intx + (slinfo->intspaces * slinfo->charwidth) +
		slinfo->charwidth;
	texty = boxy + (slinfo->charheight / 2);

	v_bar3d(boxx, slinfo->slidery, slwidth, 4 * slinfo->charheight);


	v_bar3d(boxx, boxy, slinfo->charwidth, slheight);
	v_bar3d(boxx + (2 * slinfo->charwidth), boxy,
		slwidth - (4 * slinfo->charwidth),
		slheight);
	v_bar3d(boxx + slwidth - slinfo->charwidth,
		boxy,
		slinfo->charwidth,
		slheight);


	titlex = (boxx + (slwidth / 2)) -
		(((strlen(slinfo->slname)) * 6) / 2);	/* assume 6x6 font */

	vst_color(LGREEN);
	vst_font(FNT_SMALL);
	vst_wrmode(1);

	v_gtext(titlex, slinfo->slidery + 1, slinfo->slname);

	vst_color(BLACK);
	vst_font(slinfo->fontid);
	vst_wrmode(0);

	ltoa(slinfo->intval, slinfo->intspaces, intstr);
	ltoa(slinfo->fracval, slinfo->fracspaces, fracstr);

	v_bltchr(slinfo->sliderx, texty, 2);
	v_bltchr(slinfo->sliderx + slwidth - slinfo->charwidth, texty, 1);

	v_gtext(intx, texty, intstr);
	v_gtext(fracx - slinfo->charwidth, texty, ":");
	v_gtext(fracx, texty, fracstr);
}



/*
 * Draw an integer number slider
 */

VOID
draw_intslider(slinfo, tree, obj, sx, sy)
	SLINTINFO      *slinfo;
	OBJECT         *tree;
	WORD            obj;
	WORD            sx, sy;
{
	WORD            slwidth, slheight;
	BYTE            intstr[15];
	WORD            boxx, boxy;
	WORD            intx, texty;
	WORD            titlex;

	vst_bgcolor(LWHITE);

	slinfo->sliderx = sx;	/* tree[obj].ob_x; */
	slinfo->slidery = sy;	/* tree[obj].ob_y; */

	slwidth = (slinfo->intspaces + 5) * slinfo->charwidth;
	/* slwidth = slinfo->slwidth; */
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);
	/* intx = boxx + 2 * slinfo->charwidth; */
	intx = (boxx + (slwidth / 2)) -
		((slinfo->intspaces * slinfo->charwidth) / 2);
	texty = boxy + (slinfo->charheight / 2);

	v_bar3d(boxx, slinfo->slidery, slwidth, 4 * slinfo->charheight);

	v_bar3d(boxx, boxy, slinfo->charwidth, slheight);
	v_bar3d(intx, boxy, slinfo->intspaces * slinfo->charwidth, slheight);
	v_bar3d(boxx + slwidth - slinfo->charwidth, boxy,
		slinfo->charwidth, slheight);

	titlex = boxx + (slwidth / 2) -
		((strlen(slinfo->slname) * 6) / 2);	/* assume 6x6 font */

	vst_color(LGREEN);
	vst_font(FNT_SMALL);
	vst_wrmode(1);

	v_gtext(titlex, slinfo->slidery + 1, slinfo->slname);

	vst_color(BLACK);

	vst_font(slinfo->fontid);
	vst_wrmode(0);

	if (slinfo->signextend)
		ltoa(slinfo->intval, (WORD) slinfo->intspaces, intstr);
	else
		ltoa(slinfo->intval, (WORD) slinfo->intspaces, intstr);

	v_bltchr(slinfo->sliderx, texty, 2);
	v_bltchr(slinfo->sliderx + slwidth - slinfo->charwidth, texty, 1);

	v_gtext(intx, texty, intstr);
}

/*
 * Draw Text Slider
 */
VOID
draw_txtslider(slinfo, tree, obj, sx, sy)
	SLTXTINFO      *slinfo;
	OBJECT         *tree;
	WORD            obj;
	WORD            sx, sy;
{
	WORD            slwidth, slheight;
	WORD            boxx, boxy;
	WORD            xpos, ypos;
	WORD            titlex;

	vst_bgcolor(LWHITE);

	slinfo->sliderx = sx;	/* tree[obj].ob_x; */
	slinfo->slidery = sy;	/* tree[obj].ob_y; */

	slwidth = (slinfo->maxlength + 5) * slinfo->charwidth;
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);

	/* xpos = boxx + 2 * slinfo->charwidth; */
	xpos = (boxx + (slwidth / 2)) -
		((slinfo->maxlength * slinfo->charwidth) / 2);
	ypos = boxy + (slinfo->charheight / 2);

	v_bar3d(boxx, slinfo->slidery, slwidth, 4 * slinfo->charheight);

	v_bar3d(boxx, boxy, slinfo->charwidth, slheight);
	v_bar3d(boxx + (2 * slinfo->charwidth), boxy,
		slwidth - (4 * slinfo->charwidth),
		slheight);
	v_bar3d(boxx + slwidth - slinfo->charwidth,
		boxy,
		slinfo->charwidth,
		slheight);

	titlex = (boxx + (slwidth / 2)) -
		((strlen(slinfo->slname) * 6) / 2);	/* assume 6x6 font */
	vst_color(LGREEN);
	vst_font(FNT_SMALL);
	vst_wrmode(1);

	v_gtext(titlex, slinfo->slidery + 1, slinfo->slname);

	vst_color(BLACK);
	vst_font(slinfo->fontid);
	vst_wrmode(0);

	v_bltchr(slinfo->sliderx, ypos, 2);
	v_bltchr(slinfo->sliderx + slwidth - slinfo->charwidth, ypos, 1);

	v_gtext(xpos, ypos, (BYTE *) (slinfo->table[slinfo->index]));
}

/*
 * draw list object
 */
VOID
draw_list(obj, sx, sy)
	OBJECT         *obj;
	WORD            sx, sy;
{
	WORD            x, y, w, h;
	GRECT           pt;
	REG LISTINFO   *li = ((LISTINFO *) (obj->ob_spec));
	REG WORD        i, n;

	/* Main Box	 */
	vsf_color(LWHITE);
	v_bar3d(sx, sy, obj->ob_width, obj->ob_height);


	/* Scroll Bar 	 */
	vst_color(WHITE);
	sx += 2;
	sy += 2;
	x = sx + obj->ob_width - 12;
	y = sy + 12;
	v_bar3d(x, y, 10, obj->ob_height - 14);
	vst_font(FNT_MEDIUM);
	v_bltchr(x + 1, y, '\001');
	v_bltchr(x + 1, y + obj->ob_height - 12 - 10, '\002');


	/* Name Box	 */
	v_bar3d(sx - 2, sy - 2, obj->ob_width, 10);
	pt.g_x = sx - 2;
	pt.g_y = sy - 2;
	pt.g_w = obj->ob_width;
	pt.g_h = 10;
	gtext_attr(1, 0x0001, 0, 1);
	gr_gtext(TE_CNTR, (BYTE *) li->name, &pt, 0);

	vst_color(LGREEN);
	vst_font(li->fontid);

	/* Columns: Boxes + Titels	 */
	n = li->ncols;
	x = sx - 2 + li->cx[0];
	y = sy + 12;
	h = obj->ob_height - 14;
	for (i = 0; i < (n - 1); i++) {
		x = sx - 2 + li->cx[i];
		w = li->cx[i + 1] - li->cx[i] - 2;
		v_bar3d(x, y, w, h);
		v_gtext(x + 1, y + 2, li->titles[i]);
	}
	x = sx - 2 + li->cx[i];
	w = obj->ob_width - li->cx[i] - 14;
	v_bar3d(x, y, w, h);
	v_gtext(x + 1, y + 2, li->titles[i]);

}


VOID
show_list(obj, sx, sy)
	OBJECT         *obj;
	WORD            sx, sy;
{
	REG LISTINFO   *list = (LISTINFO *) obj->ob_spec;
	REG BYTE      **data = (BYTE **) list->data;
	REG WORD        i, j, l;
	WORD            n;
	WORD            current;
	WORD            x, y, dy;
	WORD            ix;

	current = list->index;
	if ((list->maxitems <= 0) || (current < 0))
		return;

	vst_color(BLACK);
	vst_font(list->fontid);

	dy = list->charheight + 2;

	y = sy + list->cy;
	x = sx;
	n = list->visitems / 2;
	i = current - n;
	i = (i < 0) ? 0 : i;
	l = i + list->visitems;
	l = (l > (list->maxitems - 1)) ? (list->maxitems - 1) : l;

	if ((current - i) < n) {
		for (j = 0; j < (n - (current - i)); j++)
			y += dy;
		if ((l - i + j) > list->visitems)
			l = list->visitems + i - j;
	}
	n = list->ncols;
	ix = list->ncols * i;
	for (; i <= l; i++, y += dy) {
		if (i == current) {
			vst_color(BLUE);
			list->cly = y;
		}
		for (j = 0; j < n; j++) {
			x = sx + list->cx[j];
			v_gtext(x + 2, y, data[ix++]);
		}
		if (i == current) {
			vst_color(BLACK);
		}
	}
}
#if 0
{
	REG T_WAVEINFO *wi = *pwi;
	REG WORD        i, l, j;
	WORD            current = wi->current;
	BYTE            buf[32];
	BYTE            buf1[32];
	BYTE            buf2[32];
	BYTE            buf3[32];
	WORD            index;
	BYTE            nr[8];
	LONG            f;

	if ((wi->end == -1) || (wi->current == -1))
		return;



	TxtSFont(0);
	TxtSColor(0x001f);

	ltoa((LONG) wi->current, 2, nr);
	STxtBlt(wi->x + 2, wi->y + 3, nr);

	TxtSColor(0x0001);
	sy = wi->sy_row;
	i = current - 4;
	i = (i < 0) ? 0 : i;
	l = i + 9;
	l = (l > wi->end) ? wi->end : l;

	buf[0] = ' ';
	buf1[0] = ' ';
	buf2[0] = ' ';
	buf3[0] = ' ';
	wbp = &wi->wavebuf[wi->index[i]];

#if 0				/* NOT working */
	if (((j = (l - i)) < 9)) {
		WORD            k;

		k = (9 - j) >> 1;
		for (j = 0; j < k; j++)
			sy += 8;
	}
#else				/* SEEMS to work */
	if ((current - i) < 4) {
		for (j = 0; j < (4 - (current - i)); j++)
			sy += 8;
		/*
		 * if (l > j) l -= j;
		 */
		if ((l - i + j) > 9)
			l = 9 + i - j;
	}
#endif
	for (; i <= l; i++, sy += 8) {
		if (i == current) {
			TxtSColor(0x001f);
		}
		STxtBlt(wi->sx_col1 + 6, sy,
			wtable[index = FindWave((ULONG) wbp->sample)]);

		ltoa(wbp->time, 5, &buf[1]);
		STxtBlt(wi->sx_col2, sy, buf);

		f = wbp->fade_v >> 14L;
		ltoa(f, 6, &buf1[1]);
		STxtBlt(wi->sx_col3, sy, buf1);

		f = wbp->fade_v & 0x3fffL;
		ltoa(f, 5, &buf2[1]);
		buf2[0] = ':';
		STxtBlt(wi->sx_col3 + 42, sy, buf2);
		/* buf2[0] = ' '; */

		ltoa(-(wbp->fade_l), 4, &buf3[1]);	/* CS 11/17/93 */
		STxtBlt(wi->sx_col4, sy, buf3);

		if (i == current) {
			TxtSColor(0x0001);
			wi->c_y = sy;
			wi->c_wave = index;
			strcpy(wi->c_time, buf);
			strcpy(wi->c_fd_vi, buf1);
			strcpy(wi->c_fd_vf, buf2);
			strcpy(wi->c_fd_l, buf3);
		}
		if ((wbp = wbp->next) == (T_WAVEBUF *) - 1L)
			break;
	}
}

#endif

VOID
ob_setxywh(OBJECT * tree, WORD obj, GRECT * rect)
{
	ObRect(obj) = *(GRECT *) & rect->g_x;
}

/*
 * Draw an outline green box around an object
 */
VOID
objc_outline(tree, curr, prev)
	OBJECT         *tree;
	WORD            curr;	/* object to be selected */
	WORD            prev;	/* object to be deselcted */
{
	WORD            x, y;

	if (prev != NIL) {
		vsl_color(LWHITE);
		objc_offset(tree, prev, &x, &y);
		v_outline(x - 1, y - 1,
			  tree[prev].ob_width + 2, tree[prev].ob_height + 2);
	}
	if (curr != NIL) {
		vsl_color(GREEN);
		objc_offset(tree, curr, &x, &y);
		v_outline(x - 1, y - 1,
			  tree[curr].ob_width + 2, tree[curr].ob_height + 2);
	}
}


/*
 * Centers rd within rs
 */
VOID
rc_center(GRECT * rs, GRECT * rd)
{
	rd->g_x = ((rs->g_w - rd->g_w) / 2) + rs->g_x;
	rd->g_y = ((rs->g_h - rd->g_h) / 2) + rs->g_y;
}

/*
 * Set a GRECT
 */
VOID
r_set(GRECT * rect, WORD x, WORD y, WORD w, WORD h)
{
	rect->g_x = x;
	rect->g_y = y;
	rect->g_w = w;
	rect->g_h = h;
}


/*
 * Copy src xywh block to dest xywh block.
 */
VOID
rc_copy(psxywh, pdxywh)
	register WORD  *psxywh;
	register WORD  *pdxywh;
{
	*pdxywh++ = *psxywh++;
	*pdxywh++ = *psxywh++;
	*pdxywh++ = *psxywh++;
	*pdxywh = *psxywh;
}

/*
 * 
 * ===========================================================================
 * GRAPHICS TEXT LIBRARY
 */

/*
 * Routine to adjust the x,y starting point of a text string to account for
 * its justification.  The number of characters in the string is also
 * returned.
 */
WORD
gr_just(just, ptext, w, h, pt)
	WORD            just;
	BYTE           *ptext;
	REG WORD        w, h;
	REG GRECT      *pt;
{
	WORD            numchs;
	/* figure out the	 */
	/* width of the text	 */
	/* string in pixels	 */
	gsx_tcalc(ptext, &pt->g_w, &pt->g_h, &numchs);

	h -= pt->g_h;
	if (h > 0)		/* check height		 */
		pt->g_y += ((h + 1) / 2);

	w -= pt->g_w;
	if (w > 0) {
		switch (just) {
		case TE_CNTR:	/* center text in	 */
			/* rectangle		 */
			pt->g_x += (w + 1) / 2;
			break;
		case TE_RIGHT:	/* right justify	 */
			pt->g_x += w;
			break;
		}		/* switch */
	}
	return numchs;
}


/*
 * Routine to draw a string of graphic text.
 */
VOID
gr_gtext(just, ptext, pt, tmode)
	WORD            just;
	BYTE           *ptext;
	GRECT          *pt;
	WORD            tmode;
{
	WORD            numchs;
	GRECT           t;
	/* figure out where &	 */
	/* how to put out	 */
	rc_copy((WORD *) pt, (WORD *) & t);
	numchs = gr_just(just, ptext, t.g_w, t.g_h, &t);
	if (numchs > 0)
		gsx_tblt(t.g_x, t.g_y, numchs, (BYTE *) ptext);

}

/*
 * Calculate where to put the text
 */

VOID
gsx_tcalc(ptext, ptextw, ptexth, pnumchs)
	BYTE           *ptext;
	REG WORD       *ptextw;
	WORD           *ptexth;
	REG WORD       *pnumchs;
{
	WORD            wc;
	WORD            hc;

	wc = gl_wchar;
	hc = gl_hchar;

	*pnumchs = strlen((BYTE *) ptext);
	/* figure out the min width of  text	 */

	*ptextw = MIN(*ptextw, *pnumchs * wc);
	/* figure out the min height of text	 */
	*ptexth = MIN(*ptexth, hc);

	/* if the height and width are big enough to put	 */
	if (*ptexth / hc) {	/* the text then do it			 */
		*pnumchs = MIN(*pnumchs, *ptextw / wc);
	} else
		*pnumchs = 0;

}				/* gsx_tcalc */

/*
 * Blit a text string
 */
VOID
gsx_tblt(x, y, tb_nc, str)
	REG WORD        x, y;
	WORD            tb_nc;
	BYTE           *str;
{
	BYTE            space;

	space = str[tb_nc];
	str[tb_nc] = '\0';

	v_gtext(x, y, str);
	str[tb_nc] = space;
}

/*
 * Set graphics text attributes
 */
VOID
gtext_attr(fontid, txtcolor, bgcolor, wrmode)
	WORD            fontid;
	WORD            txtcolor;
	WORD            bgcolor;
	WORD            wrmode;
{
	vst_font(fontid);
	vst_color(txtcolor);
	vst_bgcolor(bgcolor);
	vst_wrmode(wrmode);

	switch (fontid) {
	case FNT_SMALL:
		gl_wchar = 6;
		gl_hchar = 6;
		break;
	case FNT_MEDIUM:
		gl_wchar = 8;
		gl_hchar = 8;
		break;
	case FNT_BIG:
		gl_wchar = 8;
		gl_hchar = 16;
		break;
	}
}


/*
 * ==========================================================================
 * FORM LIBRARY
 */

/*
 * Handle a form
 */

WORD
form_xdo(tree, first)
	REG OBJECT     *tree;
	WORD            first;
{
	LOCAL WORD      curr;
	LOCAL WORD      new_curr;
	LOCAL WORD      type;
	LOCAL ULONG     levels, edges;
	LOCAL LONG      i;
	LOCAL LONG      x;
	XOBJECT        *xobp;



	curr = first;
	new_curr = NIL;

	if (first != NIL) {
		type = tree[curr].ob_type;
		if (tree[curr].ob_flags & JOYPAD) {
			xobp = &((CMMNXOBJ *) tree[curr].ob_spec)->ex_ob;
		}
		objc_outline(tree, curr, NIL);
	}
	for (;;) {
		evnt_joypad(LEVELS | EDGES, &levels, &edges);

		if (levels & FIRE_B) {
			if (edges & JOY_UP) {
				new_curr = xobp->ob_up;
			} else if (edges & JOY_DOWN) {
				new_curr = xobp->ob_down;
			} else if (edges & JOY_LEFT) {
				new_curr = xobp->ob_left;
			} else if (edges & JOY_RIGHT) {
				new_curr = xobp->ob_right;
			}
			if ((new_curr != NIL) && (new_curr != curr)) {
				type = tree[new_curr].ob_type;
				if (tree[new_curr].ob_flags & JOYPAD) {
					xobp =
						&((CMMNXOBJ *) tree[new_curr].ob_spec)->ex_ob;
				}
				objc_outline(tree, new_curr, curr);
				curr = new_curr;
			}
		} else {
			switch (type) {
			case G_XBAR:
				if ((((BARINFO *) tree[curr].ob_spec)->ba_callbk) != NULL)
					x = (LONG) ((BARINFO *) tree[curr].ob_spec)->ba_callbk(tree, curr, edges);
				else
					x = (LONG) frm_bttnbar(tree, curr, edges);
				break;
			case G_XFLTSLIDER:
				frm_fltslider(tree, curr,
					   (SLFLTINFO *) tree[curr].ob_spec,
					      levels, edges);
			case G_XINTSLIDER:
				frm_intslider(tree, curr,
					   (SLINTINFO *) tree[curr].ob_spec,
					      levels, edges);
				break;
			case G_XTXTSLIDER:
				frm_txtslider(tree, curr,
					   (SLTXTINFO *) tree[curr].ob_spec,
					      levels, edges);
				break;
			case G_XALPHSLIDER:
				frm_alphslider(tree, curr,
					  (SLALPHINFO *) tree[curr].ob_spec,
					       levels, edges);
				break;
			case G_XLIST:
				frm_list(tree, curr, levels, edges);
				break;
			}
		}
#if 0
		if (!(levels & FIRE_B) && (type == G_XLIST))
			for (i = 0; i < 5000; i++);
		else
			for (i = 0; i < 10000; i++);
#endif
		if (x == -1L)
			break;

	}
	return 0;
}

LONG
frm_bttnbar(tree, curr, k)
	REG OBJECT     *tree;
	REG WORD        curr;
	REG ULONG       k;
{
	BARINFO        *bap;
	WORD            n;
	LONG            x;
	WORD            found;
	REG WORD        i;

	bap = (BARINFO *) tree[curr].ob_spec;

	if (k & KEY_0)
		n = 0;
	else if (k & KEY_1)
		n = 1;
	else if (k & KEY_2)
		n = 2;
	else if (k & KEY_3)
		n = 3;
	else if (k & KEY_4)
		n = 4;
	else if (k & KEY_5)
		n = 5;
	else if (k & KEY_6)
		n = 6;
	else if (k & KEY_7)
		n = 7;
	else if (k & KEY_8)
		n = 8;
	else if (k & KEY_9)
		n = 9;

	if ((n < bap->ba_first) || (n >= (bap->ba_first + bap->ba_num))) {
		return 0L;
	}
	found = NIL;
	for (i = tree[curr].ob_head; 1; i = tree[i].ob_next) {
		if (tree[i].ob_type == G_XBUTTON) {
			if ((((BTTNINFO *) tree[i].ob_spec)->bt_smchar - '0') == n) {
				found = i;
				break;
			}
		}
		if (i == tree[curr].ob_tail)
			break;
	}
	if (found == NIL)
		return NIL;
	if (tree[found].ob_flags & RBUTTON) {
		if ((bap->ba_rcurr != NIL) &&
		    (found != bap->ba_rcurr) &&
		    (tree[bap->ba_rcurr].ob_flags & RBUTTON)) {
			Deselect(bap->ba_rcurr);
			ob_draw(tree, bap->ba_rcurr, MAXDEPTH);
		}
		bap->ba_rcurr = found;
	}
	Select(found);
	ob_draw(tree, found, MAXDEPTH);

	if ((((BTTNINFO *) tree[found].ob_spec)->bt_callbk) != NULL) {
		i = -10;
		x = (LONG) ((BTTNINFO *) tree[found].ob_spec)->bt_callbk(tree, curr,
							       found, n, k);
	}
	if (tree[found].ob_flags & ABUTTON) {
		if (i != -10)
			for (i = 0; i < 5000; i++);
		Deselect(found);
		ob_draw(tree, found, MAXDEPTH);

	}
	bap->ba_curr = found;

	return x;
}

/*
 * Handle floating pt slider
 */
VOID
frm_fltslider(tree, obj, slinfo, levels, edges)
	OBJECT         *tree;
	WORD            obj;
	SLFLTINFO      *slinfo;
	LONG            levels;
	LONG            edges;
{
	WORD            slwidth, slheight;
	BYTE            intstr[10];
	BYTE            fracstr[10];
	WORD            boxx, boxy;
	WORD            intx, fracx, texty;
	WORD            tblindex, index, maxindex;
	WORD            modify_int;
	LONG            temp;
	BYTE            ch;
	LONG            keyval;
	WORD            flag = FALSE;
	LONG            pts[4];
	LONG(*fctp) (OBJECT *, WORD, SLFLTINFO *);

	vst_bgcolor(LWHITE);
	vst_color(BLACK);

	vst_font(slinfo->fontid);
	vst_wrmode(0);

	slwidth = (slinfo->intspaces + slinfo->fracspaces + 5) *
		slinfo->charwidth;
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);
	intx = boxx + 2 * slinfo->charwidth;
	fracx = intx + (slinfo->intspaces * slinfo->charwidth) +
		slinfo->charwidth;
	texty = boxy + (slinfo->charheight / 2);

	maxindex = slinfo->intspaces + slinfo->fracspaces - 1;
	index = slinfo->cursor_index;
	if (index < slinfo->intspaces) {
		modify_int = 1;
		tblindex = slinfo->intspaces - index;
	} else {
		index -= slinfo->intspaces;
		modify_int = 0;
		tblindex = slinfo->fracspaces - index;
	}

	if ((edges & JOY_UP) || (levels & JOY_UP)) {
		if (modify_int) {
			if ((slinfo->intval + sl_table[tblindex]) < slinfo->maxint)
				slinfo->intval += sl_table[tblindex];
			else
				slinfo->intval = slinfo->maxint;
		} else {
			if ((slinfo->fracval + sl_table[tblindex]) < slinfo->maxfrac)
				slinfo->fracval += sl_table[tblindex];
			else
				slinfo->fracval = slinfo->maxfrac;
		}
		flag = TRUE;
	}
	if ((edges & JOY_DOWN) || (levels & JOY_DOWN)) {
		if (modify_int) {
			if (slinfo->intval - sl_table[tblindex] >= 0L)
				slinfo->intval -= sl_table[tblindex];
			else
				slinfo->intval = 0L;
		} else {
			if (slinfo->fracval - sl_table[tblindex] >= 0L)
				slinfo->fracval -= sl_table[tblindex];
			else
				slinfo->fracval = 0L;
		}
		flag = TRUE;
	}
	keyval = -1L;
	if (edges & KEY_0) {
		keyval = 0L;
	} else if (edges & KEY_1) {
		keyval = 1L;
	} else if (edges & KEY_2) {
		keyval = 2L;
	} else if (edges & KEY_3) {
		keyval = 3L;
	} else if (edges & KEY_4) {
		keyval = 4L;
	} else if (edges & KEY_5) {
		keyval = 5L;
	} else if (edges & KEY_6) {
		keyval = 6L;
	} else if (edges & KEY_7) {
		keyval = 7L;
	} else if (edges & KEY_8) {
		keyval = 8L;
	} else if (edges & KEY_9) {
		keyval = 9L;
	}
	ltoa(slinfo->intval, slinfo->intspaces, intstr);
	ltoa(slinfo->fracval, slinfo->fracspaces, fracstr);

	if (keyval >= 0L) {
		if (modify_int) {
			ch = intstr[index];
			temp = (long) (ch - '0');
			temp *= sl_table[tblindex];
			slinfo->intval -= temp;
			temp = keyval * sl_table[tblindex];
			if ((slinfo->intval + temp) < slinfo->maxint)
				slinfo->intval += temp;
		} else {
			ch = fracstr[index];
			temp = (LONG) (ch - '0');
			temp *= sl_table[tblindex];
			slinfo->fracval -= temp;
			temp = keyval * sl_table[tblindex];
			if ((slinfo->fracval + temp) < slinfo->maxfrac)
				slinfo->fracval += temp;
		}
		flag = TRUE;
	}
	if ((edges & JOY_RIGHT) || (edges & JOY_LEFT) || (keyval >= 0)) {
		/* Erase old line prepare to move cursor */
		vsl_color(LWHITE);
		index = slinfo->cursor_index;
		if (index >= slinfo->intspaces)
			index++;/* Space for the . */
		pts[0] = intx + (slinfo->charwidth * index);
		pts[1] = texty + slinfo->charheight + 2;
		pts[2] = pts[0] + slinfo->charwidth;
		pts[3] = pts[1];
		v_line(pts);
		if ((edges & JOY_RIGHT) || (keyval >= 0)) {
			if (slinfo->cursor_index < maxindex)
				slinfo->cursor_index++;
			else
				slinfo->cursor_index = 0L;
		}
		if (edges & JOY_LEFT) {
			if (slinfo->cursor_index > 0)
				slinfo->cursor_index--;
			else
				slinfo->cursor_index = maxindex;
		}
	}
	/*
	 * Print the slider values
	 */
	ltoa(slinfo->intval, slinfo->intspaces, intstr);
	ltoa(slinfo->fracval, slinfo->fracspaces, fracstr);

	v_gtext(intx, texty, intstr);
	v_gtext(fracx - slinfo->charwidth, texty, ":");
	v_gtext(fracx, texty, fracstr);

	/*
	 * Redraw the cursor
	 */
	vsl_color(GREEN);
	index = slinfo->cursor_index;
	if (index >= slinfo->intspaces)
		index++;	/* Space for the . */
	pts[0] = intx + (slinfo->charwidth * index);
	pts[1] = texty + slinfo->charheight + 2;
	pts[2] = pts[0] + slinfo->charwidth;
	pts[3] = pts[1];
	v_line(pts);

	fctp = (LONG(*) (OBJECT *, WORD, SLFLTINFO *)) slinfo->callbk;
	if (fctp != NULL)
		(*fctp) (tree, obj, slinfo);
}


/*
 * Handle alpha slider
 */

VOID
frm_alphslider(tree, obj, slinfo, levels, edges)
	OBJECT         *tree;
	WORD            obj;
	SLALPHINFO     *slinfo;
	LONG            levels;
	LONG            edges;
{
	WORD            slwidth, slheight;
	WORD            boxx, boxy;
	WORD            intx, fracx, texty;
	WORD            tblindex, index, maxindex;
	WORD            modify_main;
	LONG            keyval = -1L;
	REG WORD        i;
	WORD            flag = FALSE;
	LONG            pts[4];
	LONG(*fctp) (OBJECT *, WORD, SLALPHINFO *);

	vst_bgcolor(LWHITE);
	vst_color(BLACK);

	vst_font(slinfo->fontid);
	vst_wrmode(0);

	slwidth = (slinfo->mainspaces + slinfo->extspaces + 5) *
		slinfo->charwidth;
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);
	intx = boxx + 2 * slinfo->charwidth;
	fracx = intx + (slinfo->mainspaces * slinfo->charwidth) +
		slinfo->charwidth;
	texty = boxy + (slinfo->charheight / 2);

	maxindex = slinfo->mainspaces + slinfo->extspaces - 1;
	index = slinfo->cursor_index;
	if (index < slinfo->mainspaces) {
		modify_main = 1;
		tblindex = slinfo->mainspaces - index;
	} else {
		index -= slinfo->mainspaces;
		modify_main = 0;
		tblindex = slinfo->extspaces - index;
	}

	if ((edges & JOY_UP) || (levels & JOY_UP)) {
		if (modify_main) {
			slinfo->mainix[index] += 1;
			if (slinfo->mainix[index] >= slinfo->tabitems)
				slinfo->mainix[index] = 0;
		} else {
			slinfo->extix[index] += 1;
			if (slinfo->extix[index] >= slinfo->tabitems)
				slinfo->extix[index] = 0;
		}
		flag = TRUE;
	}
	if ((edges & JOY_DOWN) || (levels & JOY_DOWN)) {
		if (modify_main) {
			slinfo->mainix[index] -= 1;
			if (slinfo->mainix[index] <= 0)
				slinfo->mainix[index] = slinfo->tabitems - 1;
		} else {
			slinfo->extix[index] -= 1;
			if (slinfo->extix[index] <= 0)
				slinfo->extix[index] = slinfo->tabitems - 1;
		}
		flag = TRUE;
	}
	if (edges & KEY_HASH) {
		if (modify_main) {
			for (i = index; i < 8; i++) {
				slinfo->mainstr[i] = ' ';
			}
			alpha_char2ix(slinfo->mainstr, slinfo->mainix,
				      slinfo->table);
		} else {
			for (i = index; i < 3; i++) {
				slinfo->extstr[i] = ' ';
			}
			alpha_char2ix(slinfo->extstr, slinfo->mainix,
				      slinfo->table);
		}
		flag = FALSE;
		keyval = '#';
	}
	if (flag) {
		if (modify_main)
			slinfo->mainstr[index] =
				slinfo->table[slinfo->mainix[index]];
		else
			slinfo->extstr[index] =
				slinfo->table[slinfo->extix[index]];
	}
	if ((edges & JOY_RIGHT) || (edges & JOY_LEFT) || (keyval >= 0)) {
		/* Erase old line prepare to move cursor */
		vsl_color(LWHITE);
		index = slinfo->cursor_index;
		if (index >= slinfo->mainspaces)
			index++;/* Space for the . */
		pts[0] = intx + (slinfo->charwidth * index);
		pts[1] = texty + slinfo->charheight + 2;
		pts[2] = pts[0] + slinfo->charwidth;
		pts[3] = pts[1];
		v_line(pts);
		if ((edges & JOY_RIGHT) || (keyval >= 0)) {
			if ((keyval == '#') && modify_main) {
				slinfo->cursor_index = 8L;
			} else if (slinfo->cursor_index < maxindex)
				slinfo->cursor_index++;
			else
				slinfo->cursor_index = 0L;
		}
		if (edges & JOY_LEFT) {
			if (slinfo->cursor_index > 0)
				slinfo->cursor_index--;
			else
				slinfo->cursor_index = maxindex;
		}
	}
	/*
	 * Print the slider values
	 */

	v_gtext(intx, texty, slinfo->mainstr);
	v_gtext(fracx - slinfo->charwidth, texty, ".");
	v_gtext(fracx, texty, slinfo->extstr);

	/*
	 * Redraw the cursor
	 */
	vsl_color(GREEN);
	index = slinfo->cursor_index;
	if (index >= slinfo->mainspaces)
		index++;	/* Space for the . */
	pts[0] = intx + (slinfo->charwidth * index);
	pts[1] = texty + slinfo->charheight + 2;
	pts[2] = pts[0] + slinfo->charwidth;
	pts[3] = pts[1];
	v_line(pts);

	fctp = (LONG(*) (OBJECT *, WORD, SLALPHINFO *)) slinfo->callbk;
	if (fctp != NULL)
		(*fctp) (tree, obj, slinfo);
}


/*
 * Handle integer slider
 */

VOID
frm_intslider(tree, obj, slinfo, levels, edges)
	OBJECT         *tree;
	WORD            obj;
	SLINTINFO      *slinfo;
	LONG            levels;
	LONG            edges;
{
	WORD            slwidth, slheight;
	BYTE            intstr[15];
	WORD            boxx, boxy;
	WORD            intx, texty;
	WORD            tblindex, index, maxindex;
	LONG            temp;
	LONG            intval;
	BYTE            ch;
	LONG            keyval;
	LONG            pts[4];
	WORD            flag = FALSE;
	LONG(*fctp) (OBJECT *, WORD, SLINTINFO *);

	vst_bgcolor(LWHITE);
	vst_color(BLACK);
	vst_font(slinfo->fontid);
	vst_wrmode(0);

	slwidth = (slinfo->intspaces + 5) * slinfo->charwidth;
	/* slwidth = slinfo->slwidth; */
	slheight = 2 * 8 /* slinfo->charheight */ ;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);

	intx = (boxx + (slwidth / 2)) - ((slinfo->intspaces *
					  slinfo->charwidth) / 2);
	/* intx = boxx + 2 * slinfo->charwidth; */

	texty = boxy + (slinfo->charheight / 2);

	maxindex = slinfo->intspaces - 1;
	index = slinfo->cursor_index;

	tblindex = slinfo->intspaces - index;

	if ((edges & JOY_UP) || (levels & JOY_UP)) {
		if (slinfo->signextend) {
			if (slinfo->intval + sl_table[tblindex] < slinfo->maxint)
				slinfo->intval += sl_table[tblindex];
			else
				slinfo->intval = slinfo->maxint;
		} else {
			if ((ULONG) slinfo->intval + (ULONG) sl_table[tblindex] <
			    (ULONG) slinfo->maxint)
				slinfo->intval += sl_table[tblindex];
			else
				slinfo->intval = slinfo->maxint;
		}
		flag = TRUE;
	}
	if ((edges & JOY_DOWN) || (levels & JOY_DOWN)) {
		if (slinfo->signextend) {
			intval = slinfo->intval;
			if ((slinfo->intval - sl_table[tblindex]) >=
			    (-slinfo->maxint))
				slinfo->intval -= sl_table[tblindex];
			else
				slinfo->intval = -slinfo->maxint;
		} else {
			if (slinfo->intval - sl_table[tblindex] >= 0)
				slinfo->intval -= sl_table[tblindex];
			else
				slinfo->intval = 0L;
		}
		flag = TRUE;
	}
	keyval = -1L;
	if (edges & KEY_0) {
		keyval = 0L;
	} else if (edges & KEY_1) {
		keyval = 1L;
	} else if (edges & KEY_2) {
		keyval = 2L;
	} else if (edges & KEY_3) {
		keyval = 3L;
	} else if (edges & KEY_4) {
		keyval = 4L;
	} else if (edges & KEY_5) {
		keyval = 5L;
	} else if (edges & KEY_6) {
		keyval = 6L;
	} else if (edges & KEY_7) {
		keyval = 7L;
	} else if (edges & KEY_8) {
		keyval = 8L;
	} else if (edges & KEY_9) {
		keyval = 9L;
	}
	if (slinfo->signextend)
		itoa(slinfo->intval, slinfo->intspaces, intstr);
	else
		ltoa(slinfo->intval, slinfo->intspaces, intstr);
	if (keyval >= 0L) {
		flag = TRUE;

		ch = intstr[index];
		temp = (long) (ch - '0');
		temp *= sl_table[tblindex];
		if (slinfo->signextend && ((short) slinfo->intval < 0))
			slinfo->intval += temp;
		else
			slinfo->intval -= temp;
		temp = keyval * sl_table[tblindex];
		if (slinfo->signextend && ((WORD) slinfo->intval < 0)) {
			if (slinfo->intval - temp > (-slinfo->maxint))
				slinfo->intval -= temp;
		} else if ((ULONG) slinfo->intval + (ULONG) sl_table[tblindex] <
			   (ULONG) slinfo->maxint)
			slinfo->intval += temp;
	}
	if ((edges & JOY_RIGHT) || (edges & JOY_LEFT) || (keyval >= 0)) {
		flag = TRUE;
		/* Erase old line prepare to move cursor */
		vsl_color(LWHITE);
		index = slinfo->cursor_index;

		pts[0] = intx + (slinfo->charwidth * index);
		pts[1] = texty + slinfo->charheight + 2;
		pts[2] = pts[0] + slinfo->charwidth;
		pts[3] = pts[1];
		v_line(pts);
		if ((edges & JOY_RIGHT) || (keyval >= 0)) {
			if (slinfo->cursor_index < maxindex)
				slinfo->cursor_index++;
			else
				slinfo->cursor_index = 0 + slinfo->signextend;
		}
		if (edges & JOY_LEFT) {
			if (slinfo->cursor_index > (0 + slinfo->signextend))
				slinfo->cursor_index--;
			else
				slinfo->cursor_index = maxindex;
		}
	}
	if (edges & KEY_STAR) {
		slinfo->intval = (long) (-(short) slinfo->intval);
	}
	/*** Print the slider values ****/

	if (slinfo->signextend)
		itoa((short) slinfo->intval, (int) slinfo->intspaces, intstr);
	else
		ltoa(slinfo->intval, (int) slinfo->intspaces, intstr);

	v_gtext(intx, texty, intstr);

	/*** Redraw the cursor ***/
	vsl_color(GREEN);

	index = slinfo->cursor_index;

	pts[0] = intx + (slinfo->charwidth * index);
	pts[1] = texty + slinfo->charheight + 2;
	pts[2] = pts[0] + slinfo->charwidth;
	pts[3] = pts[1];
	v_line(pts);


	fctp = (LONG(*) (OBJECT *, WORD, SLINTINFO *)) slinfo->callbk;
	if (fctp != NULL)
		(*fctp) (tree, obj, slinfo);
}

/*
 * Handle Text Slider
 */
#if 1
VOID
frm_txtslider(tree, obj, slinfo, levels, edges)
	OBJECT         *tree;
	WORD            obj;
	SLTXTINFO      *slinfo;
	LONG            levels;
	LONG            edges;
{
	WORD            slwidth, slheight;
	WORD            boxx, boxy;
	WORD            xpos, ypos;
	WORD            flag = FALSE;
	LONG(*fctp) (OBJECT *, WORD, SLTXTINFO *);

	vst_bgcolor(LWHITE);
	vst_color(BLACK);
	vst_font(slinfo->fontid);
	vst_wrmode(0);

	slwidth = (slinfo->maxlength + 5) * slinfo->charwidth;
	slheight = 2 * slinfo->charheight;
	boxx = slinfo->sliderx;
	boxy = slinfo->slidery + ((slinfo->charheight == 6) ?
			       slinfo->charheight + 3 : slinfo->charheight);
	/* xpos = boxx + 2 * slinfo->charwidth; */
	xpos = (boxx + (slwidth / 2)) -
		((slinfo->maxlength * slinfo->charwidth) / 2);
	ypos = boxy + (slinfo->charheight / 2);

	if ((edges & JOY_UP) || (levels & JOY_UP)) {
		if ((slinfo->index + 1) < slinfo->maxitems)
			slinfo->index++;
		else
			slinfo->index = 0L;
		flag = TRUE;
	}
	if ((edges & JOY_DOWN) || (levels & JOY_DOWN)) {
		if ((slinfo->index - 1) >= 0L)
			slinfo->index--;
		else
			slinfo->index = slinfo->maxitems - 1;
		flag = TRUE;
	}
	v_gtext(xpos, ypos, (BYTE *) (slinfo->table[slinfo->index]));

	if (flag) {
		fctp = (LONG(*) (OBJECT *, WORD, SLTXTINFO *)) slinfo->callbk;
		if (fctp != NULL)
			(*fctp) (tree, obj, slinfo);
	}
}
#endif


VOID
frm_list(tree, obj, levels, edges)
	OBJECT         *tree;
	WORD            obj;
	LONG            edges, levels;
{
	REG LISTINFO   *info = (LISTINFO *) tree[obj].ob_spec;



	if (((levels & JOY_UP) || (edges & JOY_UP)) && ((info->index - 1) >= 0)) {
		info->index = (info->index == 0) ? 0 : --(info->index);
		up_list(tree, obj);
	} else if (((levels & JOY_DOWN) || (edges & JOY_DOWN)) &&
		   ((info->index + 1) < info->maxitems)) {
		info->index = (info->index >= (info->maxitems - 1)) ?
			(info->maxitems - 1) : ++(info->index);
		dn_list(tree, obj);
	} else if (edges & FIRE_A) {
		(*info->callbk) (tree, obj, info);
		objc_outline(tree, obj, NIL);
	}
}

VOID
dn_list(tree, obj)
	OBJECT         *tree;
	WORD            obj;

{
	REG LISTINFO   *list = tree[obj].ob_spec;
	REG BYTE      **data = (BYTE **) list->data;
	REG WORD        i, j, l;
	WORD            n;
	WORD            sx, sy, x, y, w;
	WORD            ix;
	WORD            area[8];
	MFDB            src;
	MFDB            dst;
	WORD            dy;
	WORD            cy = list->cy;


	vst_font(list->fontid);
	vst_color(BLACK);

	/* ----- red2raw current line in black */
	objc_offset(tree, obj, &sx, &sy);

	y = list->cly;
	x = sx;
	dy = list->charheight + 2;
	n = list->ncols;
	ix = list->ncols * (list->index - 1);
	for (j = 0; j < n; j++) {
		x = sx + list->cx[j];
		v_gtext(x + 2, y, data[ix++]);
	}


	/* ----- do the blit */

	src.fd_addr = (LONG) v_bas_ad;
	src.fd_width = 0x4400L;
	src.fd_height = 200L;

	dst.fd_addr = (LONG) MenuBuffer;
	dst.fd_width = 0x4400L;
	dst.fd_height = 100L;

	area[0] = sx + 2;
	area[1] = sy + cy + dy;
	area[2] = tree[obj].ob_width - 14;
	area[3] = tree[obj].ob_height - cy - dy;

	area[4] = 0;
	area[5] = 0;
	area[6] = area[2];
	area[7] = area[3];

	vro_cpyfm(12, area, &src, &dst);

	area[0] = 0;
	area[1] = 0;
	area[2] = tree[obj].ob_width - 14;
	area[3] = tree[obj].ob_height - cy - dy;

	area[4] = sx + 2;
	area[5] = sy + cy;
	area[6] = area[2];
	area[7] = area[3];

	vro_cpyfm(12, area, &dst, &src);

	/* ----- redraw NEW current line in green */
	vst_color(BLUE);
	y = list->cly;
	x = sx;
	n = list->ncols;
	ix = list->ncols * list->index;
	for (j = 0; j < n; j++) {
		x = sx + list->cx[j];
		v_gtext(x + 2, y, data[ix++]);
	}
	vst_color(BLACK);

	/* ----- clear & redraw the last line */


	l = list->index + list->visitems / 2;
	l = (l > list->maxitems) ? list->maxitems : l;
	y = sy + list->cy + list->visitems * dy;
	x = sx - 2 + list->cx[0];
	vsf_color(LWHITE);
	for (i = 0; i < (n - 1); i++) {
		x = sx + list->cx[i];
		w = list->cx[i + 1] - list->cx[i] - 2;
		v_bar(x, y, w, dy);
	}
	x = sx + list->cx[i];
	if (n > 1)
		w = tree[obj].ob_width - list->cx[i] - 14;
	else
		w = tree[obj].ob_width - 14;
	v_bar(x, y, w, dy);

	if ((list->index + list->visitems / 2) < list->maxitems) {
		ix = l * n;
		for (j = 0; j < n; j++) {
			x = sx + list->cx[j];
			v_gtext(x + 2, y, data[ix++]);
		}
	}
}

VOID
up_list(tree, obj)
	OBJECT         *tree;
	WORD            obj;

{
	REG LISTINFO   *list = tree[obj].ob_spec;
	REG BYTE      **data = (BYTE **) list->data;
	REG WORD        i, j, l;
	WORD            n;
	WORD            sx, sy, x, y, w;
	WORD            ix;
	WORD            area[8];
	MFDB            src;
	MFDB            dst;
	WORD            dy;
	WORD            cy = list->cy;

	vst_font(list->fontid);
	vst_color(BLACK);

	/* ----- redraw current line in black */
	objc_offset(tree, obj, &sx, &sy);

	y = list->cly;
	x = sx;
	dy = list->charheight + 2;
	n = list->ncols;
	ix = list->ncols * (list->index + 1);
	for (j = 0; j < n; j++) {
		x = sx + list->cx[j];
		v_gtext(x + 2, y, data[ix++]);
	}


	/* ----- do the blit */

	src.fd_addr = (LONG) v_bas_ad;
	src.fd_width = 0x4400L;
	src.fd_height = 200L;

	dst.fd_addr = (LONG) MenuBuffer;
	dst.fd_width = 0x4400L;
	dst.fd_height = 100L;

	if (list->fontid == FNT_SMALL)
		j = 4;
	else
		j = 6;

	area[0] = sx + 2;
	area[1] = sy + cy;
	area[2] = tree[obj].ob_width - 14;
	area[3] = tree[obj].ob_height - cy - dy - j;

	area[4] = 0;
	area[5] = 0;
	area[6] = area[2];
	area[7] = area[3];

	vro_cpyfm(12, area, &src, &dst);

	area[0] = 0;
	area[1] = 0;
	area[2] = tree[obj].ob_width - 14;
	area[3] = tree[obj].ob_height - cy - dy - j;

	area[4] = sx + 2;
	area[5] = sy + cy + dy;
	area[6] = area[2];
	area[7] = area[3];

	vro_cpyfm(12, area, &dst, &src);

	/* ----- redraw NEW current line in green */
	vst_color(BLUE);
	y = list->cly;
	x = sx;
	n = list->ncols;
	ix = list->ncols * list->index;
	for (j = 0; j < n; j++) {
		x = sx + list->cx[j];
		v_gtext(x + 2, y, data[ix++]);
	}
	vst_color(BLACK);

	/* ----- clear & redraw the first line */

	l = list->index - list->visitems / 2;
	l = (l < 0) ? 0 : l;
	y = sy + list->cy;	/* + list->visitems * dy; */
	x = sx - 2 + list->cx[0];
	vsf_color(LWHITE);
	for (i = 0; i < (n - 1); i++) {
		x = sx + list->cx[i];
		w = list->cx[i + 1] - list->cx[i] - 2;
		v_bar(x, y, w, dy);
	}
	x = sx + list->cx[i];
	if (n > 1)
		w = tree[obj].ob_width - list->cx[i] - 14;
	else
		w = tree[obj].ob_width - 14;

	v_bar(x, y, w, dy);


	if ((list->index - list->visitems / 2) >= 0) {
		ix = l * n;
		for (j = 0; j < n; j++) {
			x = sx + list->cx[j];
			v_gtext(x + 2, y, data[ix++]);
		}
	}
}

/*
 * ==========================================================================
 * EVENT LIBRARY
 */

#define REPEATCODE 1024

ULONG
evnt_joypad(mask, levels, edges)
	WORD            mask;
	ULONG          *levels;
	ULONG          *edges;
{
	WORD            r, i;
	WORD            quit = 0;
	static LONG     timer = 0L;

	do {
		r = parser();
		_readpad();
		if ((_edges == PAUSE) || (_levels == PAUSE)) {
			voices_off();
			_edges = 0L;
			_levels = 0L;
		}
		if ((timer > REPEATCODE) && (mask & EDGES) && (_edges != 0L)) {
			*edges = _edges;
			_edges = 0L;
			timer = 0L;
			quit = 2;

		}
		if (((timer == 0L) || (timer > REPEATCODE)) &&
		    (mask & LEVELS) && (_levels != 0L)) {
			*levels = _levels;
			quit += 1;
			for (i = 0; i < 3400; i++)	/* don't go to fast */
				_do_nothing();
		}
		if (quit == 2) {
			*levels = _levels = 0L;

		}
		if (quit == 1) {
			*edges = _edges = 0L;
		}
		timer++;
	} while (!quit);
	return 0L;
}


VOID
_do_nothing(VOID)
{

}
