/************************************************************************
 *	TITLE:			GL_OBJC.C				*
 *	PROJECT:		JAGUAR					*
 *	FUNCTION:		GEM like Library			*
 *	PROGRAMMER:		Cary Gee, Hans-Martin Krober, Andreas Binner		*
 *	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(WORD, 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);


/*
 * ===========================================================================
 * 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[];
/*
 * ===========================================================================
 * 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_XTEXTEDIT:
		if ((op->ob_spec.textedit = (EDITINFO *) malloc(sizeof(EDITINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.textedit->ex_ob);
		op->ob_spec.textedit->data = " ";
		op->ob_spec.textedit->fontid = 0;
		op->ob_spec.textedit->cursor = 0;
		op->ob_spec.textedit->usage = 0;
		op->ob_spec.textedit->min = 0;
		op->ob_spec.textedit->max = 32767;
		op->ob_spec.textedit->value = 0;
		op->ob_spec.textedit->callbk = NULL;
		break;

	case G_XENVELOPE:
		if ((op->ob_spec.env = (ENVINFO *) malloc(sizeof(ENVINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		/* op->ob_width=256; */
		op->ob_spec.env->curr_point = 0;
		op->ob_spec.env->points = 4;
		op->ob_spec.env->locked = 0;
		op->ob_spec.env->ampl[0] = 0L;
		op->ob_spec.env->time[0] = 0L;
		op->ob_spec.env->ampl[1] = 30000L;
		op->ob_spec.env->time[1] = 1200L;
		op->ob_spec.env->ampl[2] = 20000L;
		op->ob_spec.env->time[2] = 2400L;
		op->ob_spec.env->ampl[3] = 0L;
		op->ob_spec.env->time[3] = 10000L;
		break;

	case G_XREALSLIDER:
		if ((op->ob_spec.slider = (SLIDEINFO *) malloc(sizeof(SLIDEINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.slider->curr = 0;
		op->ob_spec.slider->max = 255L;
		op->ob_spec.slider->min = 0L;
		op->ob_spec.slider->frac = 0;
		op->ob_spec.slider->flags = 0;
		op->ob_spec.slider->callbk = NULL;
		break;
	case G_XPOPUP:
		if ((op->ob_spec.popup = (POPUPINFO *) malloc(sizeof(POPUPINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.popup->index = 0;
		op->ob_spec.popup->type = 0;
		op->ob_spec.popup->fontid = FNT_MEDIUM;
		op->ob_spec.popup->data = NULL;
		op->ob_spec.popup->callbk = NULL;
		op->ob_spec.popup->action = NULL;
		op->ob_spec.popup->lock_str = FMSTR_POPUPLOCKED;
		break;

	case G_XTEXT:
	case G_XBOXTEXT:
		if ((op->ob_spec.boxtext = (BOXTXTINFO *) malloc(sizeof(BOXTXTINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.boxtext->bx_text = " ";
		op->ob_spec.boxtext->bx_bgcolor = LWHITE;
		op->ob_spec.boxtext->bx_txtcolor = BLACK;
		op->ob_spec.boxtext->bx_fontid = FNT_MEDIUM;
		op->ob_spec.boxtext->bx_align = TE_CNTR;
		break;
	case G_XBUTTON:
		if ((op->ob_spec.button = (BTTNINFO *) malloc(sizeof(BTTNINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.button->bt_text = " ";
		op->ob_spec.button->bt_bgcolor = LWHITE;
		op->ob_spec.button->bt_txtcolor = BLACK;
		op->ob_spec.button->bt_fontid = FNT_MEDIUM;
		op->ob_spec.button->bt_smchar = '0';
		op->ob_spec.button->bt_callbk = NULL;
		op->ob_spec.button->bt_data = NULL;
		break;
	case G_XBAR:
		if ((op->ob_spec.bar = (BARINFO *) malloc(sizeof(BARINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.bar->ba_callbk = NULL;
		op->ob_spec.bar->ba_data = NULL;
		op->ob_spec.bar->ba_curr = NIL;
		op->ob_spec.bar->ba_rcurr = NIL;
		op->ob_spec.bar->ba_first = 0;
		op->ob_spec.bar->ba_num = 0;
		break;
	case G_XALPHSLIDER:
		if ((op->ob_spec.alphaslider = (SLALPHINFO *) malloc(sizeof(SLALPHINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.alphaslider->slname[0] = '\0';
		op->ob_spec.alphaslider->sliderx = 0;
		op->ob_spec.alphaslider->slidery = 0;
		op->ob_spec.alphaslider->mainstr = " ";
		op->ob_spec.alphaslider->extstr = " ";
		op->ob_spec.alphaslider->mainspaces = 1;
		op->ob_spec.alphaslider->extspaces = 1;
		op->ob_spec.alphaslider->table = "abcd";
		op->ob_spec.alphaslider->fontid = FNT_MEDIUM;
		op->ob_spec.alphaslider->charwidth = FNT_MWIDTH;
		op->ob_spec.alphaslider->charheight = FNT_MHEIGHT;
		op->ob_spec.alphaslider->cursor_index = 0;
		op->ob_spec.alphaslider->extflag = 1;
		op->ob_spec.alphaslider->data = NULL;
		op->ob_spec.alphaslider->callbk = NULL;
		break;
	case G_XFLTSLIDER:
		if ((op->ob_spec.floatslider = (SLFLTINFO *) malloc(sizeof(SLFLTINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.floatslider->slname[0] = '\0';
		op->ob_spec.floatslider->sliderx = 0;
		op->ob_spec.floatslider->slidery = 0;
		op->ob_spec.floatslider->intval = 0L;
		op->ob_spec.floatslider->fracval = 0L;
		op->ob_spec.floatslider->intspaces = 5;
		op->ob_spec.floatslider->fracspaces = 5;
		op->ob_spec.floatslider->maxint = 65535;
		op->ob_spec.floatslider->maxfrac = 65535;
		op->ob_spec.floatslider->fontid = FNT_MEDIUM;
		op->ob_spec.floatslider->charwidth = FNT_MWIDTH;
		op->ob_spec.floatslider->charheight = FNT_MHEIGHT;
		op->ob_spec.floatslider->cursor_index = 0;
		op->ob_spec.floatslider->shiftcount = 4;
		op->ob_spec.floatslider->data = NULL;
		op->ob_spec.floatslider->callbk = NULL;
		break;
	case G_XINTSLIDER:
		if ((op->ob_spec.intslider = (SLINTINFO *) malloc(sizeof(SLINTINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.intslider->slname[0] = '\0';
		op->ob_spec.intslider->sliderx = 0;
		op->ob_spec.intslider->slidery = 0;
		op->ob_spec.intslider->intval = 0L;
		op->ob_spec.intslider->intspaces = 5;
		op->ob_spec.intslider->maxint = 65535;
		op->ob_spec.intslider->fontid = FNT_MEDIUM;
		op->ob_spec.intslider->charwidth = FNT_MWIDTH;
		op->ob_spec.intslider->charheight = FNT_MHEIGHT;
		op->ob_spec.intslider->cursor_index = 0;
		op->ob_spec.intslider->changesign = 0;
		op->ob_spec.intslider->signextend = 0;
		op->ob_spec.intslider->data = NULL;
		op->ob_spec.intslider->callbk = NULL;
		break;
	case G_XTXTSLIDER:
		if ((op->ob_spec.textslider = (SLTXTINFO *) malloc(sizeof(SLTXTINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.textslider->slname[0] = '\0';
		op->ob_spec.textslider->sliderx = 0;
		op->ob_spec.textslider->slidery = 0;
		op->ob_spec.textslider->table = NULL;
		op->ob_spec.textslider->maxitems = 0;
		op->ob_spec.textslider->maxlength = 0;
		op->ob_spec.textslider->fontid = FNT_MEDIUM;
		op->ob_spec.textslider->charwidth = FNT_MWIDTH;
		op->ob_spec.textslider->charheight = FNT_MHEIGHT;
		op->ob_spec.textslider->index = 0;
		op->ob_spec.textslider->data = NULL;
		op->ob_spec.textslider->callbk = NULL;
		break;
	case G_XLIST:
		if ((op->ob_spec.list = (LISTINFO *) malloc(sizeof(LISTINFO))) == NULL) {
			return -2;
		}
		xobp = &(op->ob_spec.common->ex_ob);
		op->ob_spec.list->callbk = NULL;
		op->ob_spec.list->scrolled = NULL;
		op->ob_spec.list->data = NULL;
		op->ob_spec.list->name[0] = '\0';
		op->ob_spec.list->index = 0;
		op->ob_spec.list->maxitems = 0;
		op->ob_spec.list->visitems = 0;
		op->ob_spec.list->ncols = 1;
		op->ob_spec.list->titles[0][0] = '\0';
		op->ob_spec.list->cx[0] = 0;
		op->ob_spec.list->fontid = FNT_SMALL;
		op->ob_spec.list->charwidth = FNT_SWIDTH;
		op->ob_spec.list->charheight = FNT_SHEIGHT;
		op->ob_spec.list->type_col = -1;

		break;
	default:
		op->ob_spec.value = 0L;
		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;
		xobp->num_zones = 0;
	}
	ret = ob_varargs(1, tree, parent, child, type, xobp, ap);

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


WORD
ob_varargs(WORD mode, OBJECT * tree,...)
/*
 * mode == 1: xadd mode == 0: xupdate (frees mmemory)
 */
{
	va_list         ap;
	REG OBJECT     *op;
	XOBJECT        *xobp;
	REG UWORD       child;
	UWORD           type;
	UWORD           arg;
	UWORD           parent;
	UWORD           where;
	UWORD           i, d;
	UWORD           tix;	/* title index; */
	UWORD           lflag = FALSE;
	UWORD           uflag = FALSE;
	UWORD           nocol = TRUE;
	BYTE           *s, *t, *p;
	WORD            c;
	LONG            lvalue;

	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_XSPEC:
			d = (WORD) va_arg(ap, WORD);
			switch (d) {
			case T_OBSPEC_FILLCOLOR:
				lvalue = (ULONG) op->ob_spec.value;
				lvalue &= ~0x0fL;
				lvalue |= (ULONG) (((WORD) va_arg(ap, WORD)) & 0x0f);
				op->ob_spec.value = (LONG) 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_height - 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;

			/*
			 * XTEXTEDIT
			 */

		case T_EDIT_NAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = op->ob_spec.textedit->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;

		case T_EDIT_FONTID:
			op->ob_spec.textedit->fontid =
				(WORD) va_arg(ap, WORD);
			break;

		case T_EDIT_MIN:
			op->ob_spec.textedit->min =
				(LONG) va_arg(ap, LONG);
			break;

		case T_EDIT_MAX:
			op->ob_spec.textedit->max =
				(LONG) va_arg(ap, LONG);
			break;

		case T_EDIT_VALUE:
			op->ob_spec.textedit->value =
				(LONG) va_arg(ap, LONG);
			break;

		case T_EDIT_TYPE:
			op->ob_spec.textedit->usage =
				(WORD) va_arg(ap, WORD);
			if (op->ob_spec.textedit->usage)
				op->ob_spec.textedit->cursor = op->ob_spec.textedit->maxsize - 1;
			break;


		case T_EDIT_MAXSIZE:
			op->ob_spec.textedit->maxsize =
				(WORD) va_arg(ap, WORD);
			break;


		case T_EDIT_DATA:
			s = (BYTE *) va_arg(ap, BYTE *);
			if (!mode && op->ob_spec.textedit->data)
				free(op->ob_spec.textedit->data);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			op->ob_spec.textedit->data = t;
			/* we do this because we have problems */
			/* accessing bytes from the ROMulator  */
			break;

		case T_EDIT_CALLBK:
			op->ob_spec.textedit->callbk =
				(LONG(*) (OBJECT *, WORD, EDITINFO *))
				va_arg(ap, LFCTP);
			break;

			/*
			 * XREALSLIDER
			 */

		case T_SLIDE_SLNAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = op->ob_spec.slider->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;

		case T_SLIDE_DEFAULT:
			op->ob_spec.slider->curr =
				(LONG) va_arg(ap, LONG);
			break;

		case T_SLIDE_MIN:
			op->ob_spec.slider->min =
				(LONG) va_arg(ap, LONG);
			break;

		case T_SLIDE_MAX:
			op->ob_spec.slider->max =
				(LONG) va_arg(ap, LONG);
			break;

		case T_SLIDE_FRAC:
			op->ob_spec.slider->frac =
				(WORD) va_arg(ap, WORD);
			break;

		case T_SLIDE_CALLBK:
			op->ob_spec.slider->callbk =
				(LONG(*) (OBJECT *, WORD, SLIDEINFO *))
				va_arg(ap, LFCTP);
			break;


			/*
			 * XPOPUP
			 */

		case T_POP_SLNAME:
			s = (BYTE *) va_arg(ap, BYTE *);
			t = op->ob_spec.popup->slname;
			strncpy(t, s, 18);
			t[19] = '\0';
			break;

		case T_POP_LOCK_STR:
			s = (BYTE *) va_arg(ap, BYTE *);
			if (!mode && op->ob_spec.popup->lock_str)
				free(op->ob_spec.popup->lock_str);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			op->ob_spec.popup->lock_str = t;
			break;
		case T_POP_DATA:
			s = (BYTE *) va_arg(ap, BYTE *);
			if (!mode && op->ob_spec.popup->data)
				free(op->ob_spec.popup->data);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			op->ob_spec.popup->data = t;
			c = 1;
			p = t;
			while (*p)
				if (*p++ == '|')
					c++;
			op->ob_spec.popup->entries = c;
			break;

		case T_POP_FONT:
			op->ob_spec.popup->fontid =
				(WORD) va_arg(ap, WORD);
			break;

		case T_POP_TYPE:
			op->ob_spec.popup->type =
				(WORD) va_arg(ap, WORD);
			break;

		case T_POP_INDEX:
			op->ob_spec.popup->index =
				(WORD) va_arg(ap, WORD);
			break;


		case T_POP_CALLBK:
			op->ob_spec.popup->callbk =
				(LONG(*) (OBJECT *, WORD, POPUPINFO *))
				va_arg(ap, LFCTP);
			break;

		case T_POP_ACTION:
			op->ob_spec.popup->action =
				(VOID(*) (OBJECT *, WORD, POPUPINFO *))
				va_arg(ap, LFCTP);
			break;
			/*
			 * XARROW
			 */

		case T_OB_SPEC:
			tree[child].ob_spec.value = (LONG) va_arg(ap, LONG);
			break;

			/*
			 * XBOXTXT
			 */
		case T_BX_TEXT:
			s = (BYTE *) va_arg(ap, BYTE *);
			if (!mode && op->ob_spec.boxtext->bx_text)
				free(op->ob_spec.boxtext->bx_text);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			op->ob_spec.boxtext->bx_text = t;
			/* we do this because we have problems */
			/* accessing bytes from the ROMulator  */
			break;
		case T_BX_BGCOLOR:
			op->ob_spec.boxtext->bx_bgcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BX_TXTCOLOR:
			op->ob_spec.boxtext->bx_txtcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BX_FONTID:
			op->ob_spec.boxtext->bx_fontid =
				(BYTE) va_arg(ap, WORD);
			break;
		case T_BX_ALIGN:
			op->ob_spec.boxtext->bx_align =
				(BYTE) va_arg(ap, WORD);
			break;
			/*
			 * XBUTTON
			 */
		case T_BT_TEXT:
			s = (BYTE *) va_arg(ap, BYTE *);
			if (!mode && op->ob_spec.button->bt_text)
				free(op->ob_spec.button->bt_text);
			if ((t = malloc((LONG) strlen(s) + 1L)) == NULL)
				return -2;
			strcpy(t, s);
			op->ob_spec.button->bt_text = t;
			/* we do this because we have problems */
			/* accessing bytes from the ROMulator  */
			break;
		case T_BT_BGCOLOR:
			op->ob_spec.button->bt_bgcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BT_TXTCOLOR:
			op->ob_spec.button->bt_txtcolor =
				(WORD) va_arg(ap, WORD);
			break;
		case T_BT_FONTID:
			op->ob_spec.button->bt_fontid =
				(BYTE) va_arg(ap, WORD);
			break;
		case T_BT_SMCHAR:
			op->ob_spec.button->bt_smchar =
				(BYTE) va_arg(ap, WORD);
			break;
		case T_BT_CALLBK:
			op->ob_spec.button->bt_callbk =
				(LONG(*) (OBJECT *, WORD, WORD, WORD, ULONG)) va_arg(ap, LFCTP);
			break;

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

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

	va_end(ap);

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

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

		alpha_char2ix(op->ob_spec.alphaslider->mainstr,
			      op->ob_spec.alphaslider->mainix,
			      op->ob_spec.alphaslider->table);
		alpha_char2ix(op->ob_spec.alphaslider->extstr,
			      op->ob_spec.alphaslider->extix,
			      op->ob_spec.alphaslider->table);

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

		for (i = 1; i < d; i++) {
			op->ob_spec.list->cx[i] =
				op->ob_spec.list->cx[i - 1] + (
			     (1 + strlen(op->ob_spec.list->titles[i - 1])) *
					       op->ob_spec.list->charwidth);
		}
		op->ob_spec.list->cy = 24;
		op->ob_spec.list->visitems = (op->ob_height -
					      op->ob_spec.list->cy) /
			(op->ob_spec.list->charheight + 2);
		if ((op->ob_spec.list->visitems % 2) != 0) {
			op->ob_spec.list->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
	 */
	xobp = &(op->ob_spec.common->ex_ob);

	ret = ob_varargs(0, 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 = op->ob_spec.intslider->intval;
			break;

		case T_SLIDE_DEFAULT:
			lp = va_arg(ap, LONG *);
			*lp = op->ob_spec.slider->curr;
			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;
}

WORD 
CenterString(BYTE * str, WORD w, WORD f)
{
	WORD            font_w[] = {6, 8, 8};

	return ((w - strlen(str) * font_w[f]) / 2);
}

WORD 
GetPopItem(BYTE * data, WORD nr, BYTE * str)
{
	WORD            i, f;
	BYTE           *poi, *end, temp[255];

	/* dos_echo(data); */
	strcpy(temp, data);
	poi = temp;
	i = 0;
	if (nr) {
		while (poi) {
			if (*poi == '|')
				i++;
			poi++;
			if (i == nr)
				break;
		}
	}
	if (*poi) {
		end = poi;
		f = 0;
		while (*end) {
			if (*end == '|') {
				f = 1;
				break;
			}
			end++;
		}
		if (f)
			*end = 0;
		strcpy(str, poi);
		if (f)
			*end = '|';
		return (1);
	}
	return (0);
}


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);
	}
}

WORD 
objc_find(tree, start, x, y)
	OBJECT         *tree;
	WORD            start;
	WORD            x;
	WORD            y;
{
	WORD            o, ox, oy, found;

	found = -1;
	o = tree[start].ob_head;

	do {
		if (tree[o].ob_head != -1)
			found = objc_find(tree, o, x, y);

		if (found >= 0)
			return (found);

		objc_offset(tree, o, &ox, &oy);
		if (x >= ox && x < ox + tree[o].ob_width && y >= oy && y < oy + tree[o].ob_height)
			return (o);

		o = tree[o].ob_next;
	}
	while (o != start);
	return (found);
}
