/************************************************************************/
/*	File:	doodle.c						*/
/************************************************************************/
/*									*/
/*		     GGGGG        EEEEEEEE     MM      MM		*/
/*		   GG             EE           MMMM  MMMM		*/
/*		   GG   GGG       EEEEE        MM  MM  MM		*/
/*		   GG   GG        EE           MM      MM		*/
/*		     GGGGG        EEEEEEEE     MM      MM		*/
/*									*/
/************************************************************************/
/*									*/
/*									*/
/*   The  source code  contained in  this listing is a non-copyrighted	*/
/*   work which  can be  freely used.  In applications of  this source	*/
/*   code you  are requested to  acknowledge Digital Research, Inc. as	*/
/*   the originator of portions of this code.	The code was		*/
/*   originally developed by them for the IBM PC.			*/
/*									*/
/*	ATARI ADAPTATION IN COLOR BY HARRY KOONS			*/
/*		VERSION 1.1B	7/11/85					*/
/*									*/
/*	If you find this program of value, I would appreciate a		*/
/*	contribution of $20 for the time and effort I have spent in	*/
/*	making it work on the Atari 520 ST.				*/
/*									*/
/*	Harry Koons							*/
/*	1123 Oakfair Lane						*/
/*	Harbor City, CA 90710						*/
/*									*/
/************************************************************************/


/*

Page*/
/*------------------------------*/
/*	includes		*/
/*------------------------------*/
#ifndef __GNUC__
#include "define.h"				/* misc. definitions	*/
#include "osbind.h"				/* gemdos bindings	*/
#include "portab.h"	 			/* portable coding conv	*/
/* #include "machine.h"  */  			/* machine dependent	*/
#include "obdefs.h"				/* object definitions	*/
#include "gemdefs.h"				/* misc gem definitions */
#include "taddr.h"				/* tree address macros	*/
#include "vdibind.h"				/* vdi binding structs	*/
#include "b:doodle.h"				/* doodle apl resource  */
#else
#define __OLD_WAY__
#include <osbind.h>				/* gemdos bindings	*/
#include <gemfast.h>				/* misc gem definitions */
#include <aesbind.h>				/* aes binding structs	*/
#include <vdibind.h>				/* vdi binding structs	*/
#include <string.h>				/* string library       */
#include "portab.h"	 			/* portable coding conv	*/
#include "taddr.h"				/* tree address macros	*/
#include "doodle.h"				/* doodle apl resource  */

#define WF_HSLSIZ	WF_HSLSIZE
#define WF_VSLSIZ	WF_VSLSIZE
#endif

/*------------------------------*/
/*	defines			*/
/*------------------------------*/


#define	DESK		0

#define END_UPDATE	0
#define	BEG_UPDATE	1

#define SHADE0		0
#define SHADE1		1
#define SHADE2		2
#define SHADE3		3
#define SHADE4		4
#define SHADE5		5
#define SHADE6		6
#define SHADE7		7
#define SHADE8		8
#define SHADE9		9
#define SHADE10		10
#define SHADE11		11
#define SHADE12		12
#define SHADE13		13
#define SHADE14		14
#define SHADE15		15



#define	PEN_FINE	1
#define	PEN_MEDIUM	5
#define	PEN_BROAD	9



/*------------------------------*/
/*	Macros			*/
/*------------------------------*/

#define LLGET(x) (*((LONG*)(x)))
#define LLSET(x,y) (*((LONG*)(x))=y)
#define LWGET(x) ((WORD)*((WORD*)(x)))
#define LWSET(x,y) (*((WORD*)(x))=y)
#define YSCALE(x) umul_div(x, scrn_xsize, scrn_ysize)
#define TE_TXTLEN(x) (x + 24)
#define ADDR /**/
/* #define GLOBAL */
/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Data Structures			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	Extrnl Data Structures	*/
/*------------------------------*/

UWORD	dos_err;	/* no longer external  */


/*------------------------------*/
/*	Global Data Structures	*/
/*------------------------------*/
#ifndef __GNUC__
GLOBAL WORD	contrl[11];		/* control inputs		*/
GLOBAL WORD	intin[80];		/* max string length		*/
GLOBAL WORD	ptsin[256];		/* polygon fill points		*/
GLOBAL WORD	intout[45];		/* open workstation output	*/
GLOBAL WORD	ptsout[12];
#endif

/*------------------------------*/
/*	Local Data Structures	*/
/*------------------------------*/

WORD	gl_wchar;			/* character width		*/
WORD	gl_hchar;			/* character height		*/
WORD	gl_wbox;			/* box (cell) width		*/
WORD	gl_hbox;			/* box (cell) height		*/
WORD	gl_hspace;			/* height of space between lines*/
WORD	gem_handle;			/* GEM vdi handle		*/
WORD	vdi_handle;			/* doodle vdi handle		*/
WORD	work_out[57];			/* open virt workstation values	*/
GRECT	scrn_area;			/* whole scrn area		*/
GRECT	work_area;			/* drawing area of main window  */
GRECT	undo_area;			/* area equal to work_area	*/
GRECT	save_area;			/* save area for full/unfulling */
WORD	gl_rmsg[8];			/* message buffer		*/
LONG	ad_rmsg;			/* LONG pointer to message bfr	*/
LONG	gl_menu;			/* menu tree address		*/
WORD	gl_apid;			/* application ID		*/
WORD	gl_xfull;			/* full window 'x'		*/
WORD	gl_yfull;			/* full window 'y'		*/
WORD	gl_wfull;			/* full window 'w'		*/
WORD	gl_hfull;			/* full window 'h'		*/
WORD	scrn_width;			/* scrn width in pixels	*/
WORD	scrn_height;			/* scrn height in pixels	*/
WORD	scrn_planes;			/* number of color planes	*/
WORD	scrn_xsize;			/* width of one pixel		*/
WORD	scrn_ysize;			/* height of one pixel		*/
UWORD	m_out = FALSE;			/* mouse in/out of window flag	*/
WORD	ev_which;			/* event multi return state(s)	*/
UWORD	mousex, mousey;			/* mouse x,y position		*/
UWORD	bstate, bclicks;		/* button state, & # of clicks	*/
UWORD	kstate, kreturn;		/* key state and keyboard char	*/
MFDB	undo_mfdb;			/* undo buffer mmry frm def blk */
MFDB	scrn_mfdb;			/* scrn memory form defn blk	*/
LONG	buff_size;			/* buffer size req'd for scrn	*/
LONG	buff_location;			/* scrn buffer pointer		*/
WORD	dodle_whndl;			/* doodle window handle		*/
BOOLEAN	dood_fill = FALSE;		/* fill or draw flag		*/
BOOLEAN first_fill = FALSE;		/* to set background color	*/
WORD	dodle_shade = SHADE1;		/* doodle current pen shade	*/
WORD	pen_ink = SHADE1;		/* current ink shade		*/
WORD	bkgr_color = SHADE0;		/* current background shade	*/
WORD	bkgr_next = SHADE0;		/* next background shade	*/
WORD	dodle_pen = 1;			/* doodle current pen width	*/
WORD	dodle_height = 4;		/* doodle current char height	*/
WORD	char_fine;			/* character height for fine	*/
WORD	char_medium;			/* character height for medium	*/
WORD	char_broad;			/* character height for broad	*/
WORD	monumber = 5;			/* mouse form number		*/
LONG	mofaddr = 0x0L;			/* mouse form address		*/
WORD	file_handle;			/* file handle -> pict ld/sv	*/
BYTE	file_name[64] = "";		/* current pict file name	*/
BOOLEAN	key_input;			/* key inputting state		*/
WORD	key_xbeg;			/* x position for line beginning*/
WORD	key_ybeg;			/* y position for line beginning*/
WORD	key_xcurr;			/* current x position		*/
WORD	key_ycurr;			/* current y position		*/
					/* doodle window title		*/
BYTE	*wdw_title = " Dr Doodle Window ";

/*

Page*/
/*------------------------------*/
/*	Mouse Data Structures	*/
/*------------------------------*/

WORD	erase_broad[37] =		/* mouse form for broad eraser	*/
{
	7, 7, 1, 0, 1,
	0x0000, 0x0000, 0x0000, 0x0000,	/* mask */
	0x0000, 0x1ff0, 0x1ff0, 0x1ff0,
	0x1ff0, 0x1ff0, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,	/* data */
	0x7ffc, 0x600c, 0x600c, 0x600c,
	0x600c, 0x600c, 0x7ffc, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000
};
WORD	erase_medium[37] =		/* mouse form for medium eraser	*/
{
	7, 7, 1, 0, 1,
	0x0000, 0x0000, 0x0000, 0x0000,	/* mask */
	0x0000, 0x0000, 0x07c0, 0x07c0,
	0x07c0, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,	/* data */
	0x0000, 0x1ff0, 0x1830, 0x1830,
	0x1830, 0x1ff0, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000
};
WORD	erase_fine[37] =		/* mouse form for fine eraser	*/
{
	7, 7, 1, 0, 1,
	0x0000, 0x0000, 0x0000, 0x0000,	/* mask */
	0x0000, 0x0000, 0x0000, 0x0100,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,	/* data */
	0x0000, 0x0000, 0x07c0, 0x06c0,
	0x07c0, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000
};



/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Local Procedures			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	min			*/
/*------------------------------*/
WORD
min(a, b)			/* return min of two values */
WORD		a, b;
{
	return( (a < b) ? a : b );
}


/*------------------------------*/
/*	max			*/
/*------------------------------*/
WORD
max(a, b)			/* return max of two values */
WORD		a, b;
{
	return( (a > b) ? a : b );
}


/*------------------------------*/
/*	string_addr		*/
/*------------------------------*/
LONG
string_addr(which)		/* returns a tedinfo LONG string addr	*/
WORD	which;
{
	LONG	where;

	rsrc_gaddr(R_STRING, which, &where);
	return (where);
} 


/*------------------------------*/
/*	rc_equal		*/
/*------------------------------*/
WORD
rc_equal(p1, p2)		/* tests for two rectangles equal	*/
GRECT		*p1, *p2;
{
	if ((p1->g_x != p2->g_x) ||
	    (p1->g_y != p2->g_y) ||
	    (p1->g_w != p2->g_w) ||
	    (p1->g_h != p2->g_h))
		return(FALSE);
	return(TRUE);
}



/*------------------------------*/
/*	rc_copy			*/
/*------------------------------*/
WORD
rc_copy(psbox, pdbox)		/* copy source to destination rectangle	*/
GRECT	*psbox;
GRECT	*pdbox;
{
	pdbox->g_x = psbox->g_x;
	pdbox->g_y = psbox->g_y;
	pdbox->g_w = psbox->g_w;
	pdbox->g_h = psbox->g_h;
}


/*------------------------------*/
/*	rc_intersect		*/
/*------------------------------*/
WORD
rc_intersect(p1, p2)		/* compute intersect of two rectangles	*/
GRECT		*p1, *p2;
{
	WORD		tx, ty, tw, th;

	tw = min(p2->g_x + p2->g_w, p1->g_x + p1->g_w);
	th = min(p2->g_y + p2->g_h, p1->g_y + p1->g_h);
	tx = max(p2->g_x, p1->g_x);
	ty = max(p2->g_y, p1->g_y);
	p2->g_x = tx;
	p2->g_y = ty;
	p2->g_w = tw - tx;
	p2->g_h = th - ty;
	return( (tw > tx) && (th > ty) );
}


/*------------------------------*/
/*	inside			*/
/*------------------------------*/
UWORD
inside(x, y, pt)		/* determine if x,y is in rectangle	*/
UWORD		x, y;
GRECT		*pt;
{
	if ( (x >= pt->g_x) && (y >= pt->g_y) &&
	    (x < pt->g_x + pt->g_w) && (y < pt->g_y + pt->g_h) )
		return(TRUE);
	else
		return(FALSE);
} /* inside */


/*------------------------------*/
/*	grect_to_array		*/
/*------------------------------*/
VOID
grect_to_array(area, array)	/* convert x,y,w,h to upr lt x,y and	*/
GRECT	*area;			/*		      lwr rt x,y	*/
WORD	*array;
{
	*array++ = area->g_x;
	*array++ = area->g_y;
	*array++ = area->g_x + area->g_w - 1;
	*array = area->g_y + area->g_h - 1;
}


/*------------------------------*/
/*	rast_op			*/
/*------------------------------*/
VOID
rast_op(mode, s_area, s_mfdb, d_area, d_mfdb)	/* bit block level trns	*/
WORD	mode;
GRECT	*s_area, *d_area;
MFDB	*s_mfdb, *d_mfdb;
{
	WORD	pxy[8];

	grect_to_array(s_area, pxy);
	grect_to_array(d_area, &pxy[4]);
	vro_cpyfm(vdi_handle, mode, pxy, s_mfdb, d_mfdb);
}


/*------------------------------*/
/*	do_open			*/
/*------------------------------*/
VOID
do_open(wh, org_x, org_y, x, y, w, h)	/* grow and open specified wdw	*/
WORD	wh;
WORD	org_x, org_y;
WORD	x, y, w, h;
{
	graf_growbox(org_x, org_y, 21, 21, x, y, w, h);
	wind_open(wh, x, y, w, h);
}


/*------------------------------*/
/*	do_close		*/
/*------------------------------*/
VOID
do_close(wh, org_x, org_y)	/* close and shrink specified window	*/
WORD	wh;
WORD	org_x, org_y;
{
	WORD	x, y, w, h;

	wind_get(wh, WF_CURRXYWH, &x, &y, &w, &h);
	wind_close(wh);
	graf_shrinkbox(org_x, org_y, 21, 21, x, y, w, h);
}


/*------------------------------*/
/*	hndl_dial		*/
/*------------------------------*/
WORD
hndl_dial(tree, def, x, y, w, h)	/* center, display and get input*/
LONG	tree;				/*   from specified dialogue box*/
WORD	def;
WORD	x, y, w, h;
{
	WORD	xdial, ydial, wdial, hdial;
	WORD	exit_obj;

	form_center(tree, &xdial, &ydial, &wdial, &hdial);
	form_dial(0, x, y, w, h, xdial, ydial, wdial, hdial);
	form_dial(1, x, y, w, h, xdial, ydial, wdial, hdial);
	objc_draw(tree, ROOT, MAX_DEPTH, xdial, ydial, wdial, hdial);
	exit_obj = form_do(tree, def);
	form_dial(2, x, y, w, h, xdial, ydial, wdial, hdial);
	form_dial(3, x, y, w, h, xdial, ydial, wdial, hdial);
	return (exit_obj);
}


/*------------------------------*/
/*	set_clip		*/
/*------------------------------*/
VOID
set_clip(clip_flag, s_area)	/* set clip to specified area	*/
WORD	clip_flag;
GRECT	*s_area;
{
	WORD	pxy[4];

	grect_to_array(s_area, pxy);
	vs_clip(vdi_handle, clip_flag, pxy);
}


/*------------------------------*/
/*	align_x			*/
/*------------------------------*/
WORD
align_x(x)		/* forces word alignment for column position	*/
WORD	x;		/*   rounding to nearest word			*/
{
	/*	return((x & 0xfff0) + ((x & 0x000c) ? 0x0010 : 0));	IBM */
	return(x);	/* ATARI	*/	
}	


/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Work Area Management		     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	set_work		*/
/*------------------------------*/
VOID
set_work(slider_update)		/* update undo area, clamping to page	*/
BOOLEAN	slider_update;		/*   edges, and updt sliders if req'd	*/
{
	WORD	i;

	wind_get(dodle_whndl, WF_WORKXYWH,
	&work_area.g_x, &work_area.g_y,
	&work_area.g_w, &work_area.g_h);

	undo_area.g_w = work_area.g_w;
	undo_area.g_h = work_area.g_h;
	/**/					/* clamp work area to page edges */
	if ((i = undo_mfdb.fwp - (undo_area.g_x + undo_area.g_w)) < 0)
		undo_area.g_x += i;
	if ((i = undo_mfdb.fh - (undo_area.g_y + undo_area.g_h)) < 0)
		undo_area.g_y += i;

	if (slider_update)
	{
		wind_set(dodle_whndl, WF_HSLIDE, umul_div(undo_area.g_x, 1000,
			undo_mfdb.fwp - undo_area.g_w), 0, 0, 0);
		wind_set(dodle_whndl, WF_VSLIDE, umul_div(undo_area.g_y, 1000,
			undo_mfdb.fh - undo_area.g_h), 0, 0, 0);
		wind_set(dodle_whndl, WF_HSLSIZ, umul_div(work_area.g_w, 1000,
			undo_mfdb.fwp), 0, 0, 0);
		wind_set(dodle_whndl, WF_VSLSIZ, umul_div(work_area.g_h, 1000,
			undo_mfdb.fh), 0, 0, 0);
	}

	undo_area.g_x = align_x(undo_area.g_x);
	/* only use portion of work_area on scrn	*/
	rc_intersect(&scrn_area, &work_area);
	undo_area.g_w = work_area.g_w;
	undo_area.g_h = work_area.g_h;
}


/*------------------------------*/
/*	save_work		*/
/*------------------------------*/
VOID
save_work()			/* copy work_area to undo_area buffer	*/
{
	GRECT	tmp_area;

	rc_copy(&work_area,&tmp_area);
	rc_intersect(&scrn_area,&tmp_area);
	graf_mouse(M_OFF, 0x0L);
	rast_op(3, &tmp_area, &scrn_mfdb, &undo_area, &undo_mfdb);
	graf_mouse(M_ON, 0x0L);
}


/*------------------------------*/
/*	restore_work		*/
/*------------------------------*/
VOID
restore_work()			/* restore work_area from undo_area	*/
{
	GRECT	tmp_area;

	rc_copy(&work_area,&tmp_area);
	rc_intersect(&scrn_area,&tmp_area);
	graf_mouse(M_OFF, 0x0L);
	rast_op(3, &undo_area, &undo_mfdb, &tmp_area, &scrn_mfdb);
	graf_mouse(M_ON, 0x0L);
}


/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Object Tree Manipulation		     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	do_obj			*/
/*------------------------------*/
VOID
do_obj(tree, which, bit)	/* set specified bit in object state	*/
LONG	tree;
WORD	which, bit;
{
	WORD	state;

	state = LWGET(OB_STATE(which));
	LWSET(OB_STATE(which), state | bit);
}


/*------------------------------*/
/*	undo_obj		*/
/*------------------------------*/
VOID
undo_obj(tree, which, bit)	/* clear specified bit in object state	*/
LONG	tree;
WORD	which, bit;
{
	WORD	state;

	state = LWGET(OB_STATE(which));
	LWSET(OB_STATE(which), state & ~bit);
}

/*------------------------------*/
/*	sel_obj			*/
/*------------------------------*/
VOID
sel_obj(tree, which)		/* turn on selected bit of spcfd object	*/
LONG	tree;
WORD	which;
{
	do_obj(tree, which, SELECTED);
}


/*------------------------------*/
/*	desel_obj		*/
/*------------------------------*/
VOID
desel_obj(tree, which)		/* turn off selected bit of spcfd object*/
LONG	tree;
WORD	which;
{
	undo_obj(tree, which, SELECTED);
}


/*------------------------------*/
/*	enab_menu		*/
/*------------------------------*/
VOID
enab_menu(which)		/* enable specified menu item	*/
WORD	which;
{
	undo_obj(gl_menu, which, DISABLED);
}

/*------------------------------*/
/*	objc_xywh		*/
/*------------------------------*/
VOID
objc_xywh(tree, obj, p)		/* get x,y,w,h for specified object	*/
LONG	tree;
WORD	obj;
GRECT	*p;
{
	objc_offset(tree, obj, &p->g_x, &p->g_y);
	p->g_w = LWGET(OB_WIDTH(obj));
	p->g_h = LWGET(OB_HEIGHT(obj));
}


/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    File Path Name Functions		     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	dial_name		*/
/*------------------------------*/
WORD
dial_name ( name )		/* dialogue box input filename	*/
BYTE	*name;
{		    
	LONG	tree ;
	LONG	ted_addr ;
	BYTE	c ;	
	WORD	i, j;
	GRECT	box;


	objc_xywh(gl_menu, DOODFILE, &box);
	rsrc_gaddr( R_TREE, DOODSVAD, &tree) ;
	ted_addr = LLGET(OB_SPEC(DOODNAME));
	LLSET( ted_addr, ADDR(name) ) ;
	LWSET( TE_TXTLEN(ted_addr),8);
	name[0] = '\0';
	if (hndl_dial(tree, DOODNAME, box.g_x, box.g_y, box.g_w, box.g_h) == DOODSOK)
	{
		i =
		    j =  0;
		while (TRUE)
		{
			c = name[i++];
			if (!c) 
				break ;
			if ( (c != ' ') && (c != '_') )
				name[j++] = c ;
		}
		if ( *name )
			strcpy( &name[j], ".DOO" ) ;
		desel_obj(tree, DOODSOK);
		return ((WORD) *name);
	}
	else
	{
		desel_obj(tree, DOODSCNL);
		return (FALSE);
	}
}


/*------------------------------*/
/*	get_path		*/
/*------------------------------*/
VOID
get_path(tmp_path, spec)	/* get directory path name	*/
BYTE	*tmp_path, *spec;
{
	WORD	cur_drv;

	cur_drv = Dgetdrv();
	tmp_path[0] = cur_drv + 'A';
	tmp_path[1] = ':';
	tmp_path[2] = '\\';
        Dgetpath(ADDR(&tmp_path[3]), cur_drv+1);
	if ((int)strlen(tmp_path) > 3)
		strcat(tmp_path, "\\");
	else
		tmp_path[2] = '\0';
	strcat(tmp_path, spec);
}


/*------------------------------*/
/*	add_file_name		*/
/*------------------------------*/
VOID
add_file_name(dname, fname)	/* replace name at end of input file spec*/
BYTE	*dname, *fname;
{
	BYTE	c;
	WORD	ii;


	ii = (int)strlen(dname);
	while (ii && (((c = dname[ii-1])  != '\\') && (c != ':')))
		ii--;
	dname[ii] = '\0';
	strcat(dname, fname);
}


/*------------------------------*/
/*	get_file		*/
/*------------------------------*/
WORD
get_file(loop)			/* use file selector to get input file	*/
BOOLEAN	loop;
{
	WORD	fs_iexbutton;
	BYTE	fs_iinsel[13];

	while (TRUE)
	{
		get_path(file_name, "*.DOO");
		fs_iinsel[0] = '\0';

		fsel_input(ADDR(file_name), ADDR(fs_iinsel), &fs_iexbutton);
		if (fs_iexbutton)
		{
			add_file_name(file_name, fs_iinsel);
			file_handle = Fopen(ADDR(file_name),2);
			dos_err = (file_handle < 0) ? -1 : 0;
			if (!loop || (loop && !dos_err))
				return(1);
		}
		else
			return (0);
	}
} /* get_file */


/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Soft Cursor Support			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	cursor			*/
/*------------------------------*/
VOID
cursor(color)			/* turn cursor on,  color = pen_ink	*/
WORD	color;			/*   or cursor off, color = bkgr_color	*/
{
	WORD	pxy[4];

	pxy[0] = key_xcurr + 1;
	pxy[1] = key_ycurr + gl_hspace;
	pxy[2] = key_xcurr + 1;
	pxy[3] = key_ycurr - gl_hbox;

	vsl_color(vdi_handle,color);
	vswr_mode(vdi_handle,MD_REPLACE);
	vsl_type (vdi_handle,IP_1PATT);
	vsl_width (vdi_handle,PEN_FINE);
	v_pline(vdi_handle, 2, pxy);
}


/*------------------------------*/
/*	curs_on			*/
/*------------------------------*/
VOID
curs_on()			/* turn 'soft' cursor 'on'	*/
{
	cursor(pen_ink);
}

/*------------------------------*/
/*	curs_off		*/
/*------------------------------*/
VOID
curs_off()			/* turn 'soft' cursor 'off'	*/
{
	cursor(bkgr_color);
}


/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Menu Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hdl_menu		*/
/*------------------------------*/
WORD
hdl_menu(title, item)
WORD 	title, item;
{
	WORD	done;
	WORD	me_creturn;

	graf_mouse(ARROW, 0x0L);
	done = FALSE;
	switch (title) {
	case DOODDESK:
		if (item == DOODINFO)
			do_about();
		break;

	case DOODFILE:
		switch (item)
		{
		case DOODLOAD:
			do_load(TRUE);
			break;
		case DOODSAVE:
			do_sav();
			break;
		case DOODSVAS:
			do_savas();
			break;
		case DOODABAN:
			file_handle = Fopen(ADDR(file_name),2);
			do_load(FALSE);
			break;
		case DOODQUIT:
			done = TRUE;
			break;
		}

	case DOODOPTS:
		switch (item)
		{
		case DOODPENS:
			do_penselect();
			break;
		case DOODERAP:
			do_erase();
			first_fill = TRUE;
			break;
		}

	case DOODCOLR:
		switch (item)
		{
		case COLOR0:
			pen_ink = SHADE0;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR0, SELECTED);
			break;
		case COLOR1:
			pen_ink = SHADE1;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR1, SELECTED);
			break;
		case COLOR2:
			pen_ink = SHADE2;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR2, SELECTED);
			break;
		case COLOR3:
			pen_ink = SHADE3;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR3, SELECTED);
			break;
		case COLOR4:
			pen_ink = SHADE4;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR4, SELECTED);
			break;
		case COLOR5:
			pen_ink = SHADE5;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR5, SELECTED);
			break;
		case COLOR6:
			pen_ink = SHADE6;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR6, SELECTED);
			break;
		case COLOR7:
			pen_ink = SHADE7;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR7, SELECTED);
			break;
		case COLOR8:
			pen_ink = SHADE8;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR8, SELECTED);
			break;
		case COLOR9:
			pen_ink = SHADE9;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR9, SELECTED);
			break;
		case COLOR10:
			pen_ink = SHADE10;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR10, SELECTED);
			break;
		case COLOR11:
			pen_ink = SHADE11;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR11, SELECTED);
			break;
		case COLOR12:
			pen_ink = SHADE12;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR12, SELECTED);
			break;
		case COLOR13:
			pen_ink = SHADE13;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR13, SELECTED);
			break;
		case COLOR14:
			pen_ink = SHADE14;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR14, SELECTED);
			break;
		case COLOR15:
			pen_ink = SHADE15;
			do_clnormal();
			me_creturn = menu_icheck (gl_menu, COLOR15, SELECTED);
			break;
		}

		dodle_shade = pen_ink;

	}
	menu_tnormal(gl_menu,title,TRUE);
	graf_mouse(monumber, mofaddr);
	return (done);
}


/*------------------------------*/
/*	do_clnormal		*/
/*------------------------------*/
VOID
do_clnormal()	/*	set all color checks to NORMAL in color menu	*/
{
	WORD	me_creturn;

	me_creturn = menu_icheck(gl_menu, COLOR0, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR1, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR2, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR3, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR4, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR5, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR6, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR7, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR8, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR9, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR10, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR11, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR12, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR13, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR14, NORMAL);
	me_creturn = menu_icheck(gl_menu, COLOR15, NORMAL);
}

/*------------------------------*/
/*	do_about		*/
/*------------------------------*/
VOID
do_about()			/* display Doodle Info... 	*/
{
	LONG	tree;
	GRECT	box;

	objc_xywh(gl_menu, DOODDESK, &box);
	rsrc_gaddr(R_TREE, DOODINFD, &tree);
	hndl_dial(tree, 0, box.g_x, box.g_y, box.g_w, box.g_h);
	desel_obj(tree, DOODOK);
}


/*------------------------------*/
/*	do_load			*/
/*------------------------------*/
VOID
do_load(need_name)		/* load doodle picture file	*/
BOOLEAN	need_name;
{
	if (!need_name || get_file(TRUE))
	{
		if (!dos_err)
		{
			Fread(file_handle, buff_size,buff_location);
			Fclose(file_handle);
			enab_menu(DOODSAVE);
			enab_menu(DOODABAN);
			restore_work();
		}
	}
}


/*------------------------------*/
/*	do_sav			*/
/*------------------------------*/
VOID
do_sav()			/* save current named doodle picture	*/
{
	if (*file_name)
	{
		file_handle = Fopen(ADDR(file_name),2);
		dos_err = (file_handle < 0) ? 1 : 0;
		if (dos_err)
			file_handle = Fcreate(ADDR(file_name),0);
		else
		{
			if (form_alert(1, string_addr(DOODOVWR)) == 2)
				return;
		}
		Fwrite(file_handle, buff_size, buff_location);
		enab_menu(DOODSAVE);
		enab_menu(DOODABAN);
		Fclose(file_handle);
	}
}


/*------------------------------*/
/*	do_sav_as		*/
/*------------------------------*/
VOID
do_savas()			/* save doodle picture as named	*/
{
	BYTE	name[13];

	if (dial_name(&name[0]))
	{
		add_file_name(file_name, name);
		do_sav();
	}
}


/*------------------------------*/
/*	do_penselect		*/
/*------------------------------*/
VOID
do_penselect()			/* use dialogue box to input selection	*/
{				/*   of specified pen/eraser		*/
	WORD	exit_obj;
	LONG	tree;
	GRECT	box;

	objc_xywh(gl_menu, DOODPENS, &box);
	rsrc_gaddr(R_TREE, DOODPEND, &tree);
	/**/			/* first setup current selection state	*/
	if (dodle_pen == PEN_FINE)
	{
		sel_obj(tree, DOODFINE);
		desel_obj(tree, DOODMED);
		desel_obj(tree, DOODBRD);
	}
	else
		if (dodle_pen == PEN_MEDIUM)
		{
			sel_obj(tree, DOODMED);
			desel_obj(tree, DOODFINE);
			desel_obj(tree, DOODBRD);
		}
		else
		{
			sel_obj(tree, DOODBRD);
			desel_obj(tree, DOODFINE);
			desel_obj(tree, DOODMED);
		}
	if (dodle_shade == pen_ink && dood_fill == FALSE)
	{
		sel_obj(tree, DOODPEN);
		desel_obj(tree, DOODERSR);
		desel_obj(tree, DOODFILL);
	}
	else if (dodle_shade == pen_ink && dood_fill == TRUE)
	{
		desel_obj(tree, DOODPEN);
		desel_obj(tree, DOODERSR);
		sel_obj(tree, DOODFILL);
	}
	else
	{
		desel_obj(tree, DOODPEN);
		sel_obj(tree, DOODERSR);
		desel_obj(tree, DOODFILL);
	}

	/* get dialogue box input	*/

	exit_obj = hndl_dial(tree, 0, box.g_x, box.g_y, box.g_w, box.g_h);
	if (exit_obj == DOODPSOK)
	{
		if (LWGET(OB_STATE(DOODFINE)) & SELECTED)
		{
			dodle_pen = PEN_FINE;
			dodle_height = char_fine;
		}
		else
			if (LWGET(OB_STATE(DOODMED)) & SELECTED)
			{
				dodle_pen = PEN_MEDIUM;
				dodle_height = char_medium;
			}
			else
			{
				dodle_pen = PEN_BROAD;
				dodle_height = char_broad;
			}
		if (LWGET(OB_STATE(DOODPEN)) & SELECTED)
		{
			dodle_shade = pen_ink;
			monumber = 5;
			mofaddr = 0x0L;
			dood_fill = FALSE;
		}
		else if (LWGET(OB_STATE(DOODERSR)) & SELECTED)
		{
			dodle_shade = bkgr_color;
			monumber = 255;
			mofaddr = (dodle_pen == PEN_FINE) ? ADDR((BYTE *)erase_fine) :
			(dodle_pen == PEN_MEDIUM) ? ADDR((BYTE *)erase_medium) :
			ADDR((BYTE *)erase_broad);
			dood_fill = FALSE;
		}
		else
		{
			dodle_shade = pen_ink;
			monumber = POINT_HAND;
			mofaddr = 0x0L;
			dood_fill = TRUE;
		}

		desel_obj(tree, DOODPSOK);
	}
	else
		desel_obj(tree, DOODCNCL);
}


/*------------------------------*/
/*	do_erase		*/
/*------------------------------*/
VOID
do_erase()			/* clear the scrn and the undo buffer	*/
{
	WORD	fo_aexbttn;

	fo_aexbttn = form_alert(0, string_addr(ERASEWRN));

	if (fo_aexbttn == 1)
	{
		rast_op(0, &scrn_area, &scrn_mfdb, &scrn_area, &undo_mfdb);
		restore_work();
	}
}
/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Keyboard Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hndl_keyboard		*/
/*------------------------------*/
WORD
hndl_keyboard()
{
	WORD	i;
	BYTE	str[2];

	if ((str[0] = kreturn) == 0x03)
		return(TRUE);
	graf_mouse(M_OFF, 0x0L);
	if (!key_input)
	{
		vsl_color(vdi_handle,dodle_shade);
		vswr_mode(vdi_handle,MD_TRANS);
		vsl_type (vdi_handle,IP_1PATT);
		vst_height(vdi_handle, dodle_height,
		&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
		gl_hspace = gl_hbox - gl_hchar;
		set_clip(TRUE, &work_area);
		graf_mkstate(&key_xbeg, &key_ybeg, &i, &i);
		key_xcurr = ++key_xbeg;
		key_ycurr = --key_ybeg;
	}
	else

	/*	curs_off();	remove from color version 6/30/85	*/

	str[1] = '\0';
	if (str[0] == 0x1A)
	{
		save_work();
		graf_mouse(M_ON, 0x0L);
		return(key_input = FALSE);
	}
	else
		if (str[0] == 0x0D)
		{
			key_ycurr += gl_hbox + gl_hspace;
			key_xcurr = key_xbeg;
		}
		else
			if (str[0] == 0x08)
			{
				if (key_input && (key_xcurr != key_xbeg))
				{
					for (i = 0; i < gl_wbox; i++)
					{
						key_xcurr--;
					/*	curs_off();	*/
					}
				}
			}
			else
				if ((str[0] >= ' ') && (str[0] <= 'z'))
				{
					str[1] = '\0';
					vswr_mode(vdi_handle, MD_TRANS);
					vst_color(vdi_handle, pen_ink);
					v_gtext(vdi_handle, key_xcurr,
					key_ycurr, str);
					key_xcurr += gl_wbox;
				}
	if (!key_input)
	{
		key_input = TRUE;
	}
	/*	curs_on();	remove from color version 6/30/85  */
	graf_mouse(M_ON, 0x0L);
	return(FALSE);
}



/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Message Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hdl_message		*/
/*------------------------------*/
/*MLOCAL*/	BOOLEAN	hdl_message()
{
	BOOLEAN	done; 
	WORD	wdw_hndl;

	done = FALSE;
	wdw_hndl = gl_rmsg[3];
	switch( gl_rmsg[0] )
	{
	case MN_SELECTED:
		done = hdl_menu(wdw_hndl, gl_rmsg[4]);
		break;

	case WM_REDRAW:
		do_redraw(wdw_hndl, (GRECT *) &gl_rmsg[4]);
		break;

	case WM_TOPPED:
		wind_set(wdw_hndl, WF_TOP, 0, 0, 0, 0);
		break;
	case WM_CLOSED:
		done = TRUE;
		break;
	case WM_FULLED:
		do_full(wdw_hndl);
		break;
	case WM_ARROWED:
		switch(gl_rmsg[4])
		{
		case WA_UPPAGE:
			undo_area.g_y = max(undo_area.g_y - undo_area.g_h, 0);
			break;
		case WA_DNPAGE:
			undo_area.g_y += undo_area.g_h;
			break;
		case WA_UPLINE:
			undo_area.g_y = max(undo_area.g_y - YSCALE(16), 0);
			break;
		case WA_DNLINE:
			undo_area.g_y += YSCALE(16);
			break;
		case WA_LFPAGE:
			undo_area.g_x = max(undo_area.g_x-undo_area.g_w, 0);
			break;
		case WA_RTPAGE:
			undo_area.g_x += undo_area.g_w;
			break;
		case WA_LFLINE:
			undo_area.g_x = max(undo_area.g_x - 16, 0);
			break;
		case WA_RTLINE:
			undo_area.g_x += 16;
			break;
		}
		set_work(TRUE);
		restore_work();
		break;
	case WM_HSLID:
		undo_area.g_x = align_x(umul_div(undo_mfdb.fwp - undo_area.g_w,
		gl_rmsg[4], 1000));
		wind_set(dodle_whndl, WF_HSLIDE, umul_div(undo_area.g_x, 1000,
		undo_mfdb.fwp - undo_area.g_w), 0, 0, 0);
		restore_work();
		break;
	case WM_VSLID:
		undo_area.g_y = umul_div(undo_mfdb.fh - undo_area.g_h,
		gl_rmsg[4],1000);
		wind_set(dodle_whndl, WF_VSLIDE, umul_div(undo_area.g_y, 1000,
		undo_mfdb.fh - undo_area.g_h), 0, 0, 0);
		restore_work();
		break;
	case WM_SIZED:
		wind_set(wdw_hndl, WF_CURRXYWH, align_x(gl_rmsg[4]) - 1,
		gl_rmsg[5], gl_rmsg[6], gl_rmsg[7]);
		set_work(TRUE);
		break;
	case WM_MOVED:
		gl_rmsg[4] = align_x(gl_rmsg[4]);
		wind_set(wdw_hndl, WF_CURRXYWH, align_x(gl_rmsg[4]) - 1,
		gl_rmsg[5], gl_rmsg[6], gl_rmsg[7]);
		set_work(FALSE);
		break;
	} /* switch */
	return(done);
} /* hdl_mesag */

/*------------------------------*/
/*	do_redraw		*/
/*------------------------------*/
VOID
do_redraw(wh, area)		/* redraw specified area from undo bfr	*/
WORD	wh;
GRECT	*area;
{
	GRECT	box;
	GRECT	dirty_source, dirty_dest;

	graf_mouse(M_OFF, 0x0L);

	wind_get(wh, WF_FIRSTXYWH, &box.g_x, &box.g_y, &box.g_w, &box.g_h);
	while ( box.g_w && box.g_h )
	{
		if (rc_intersect(area, &box))
		{
			if (wh == dodle_whndl)
			{
				rc_copy(&box, &dirty_dest);
				if (rc_intersect(&work_area, &dirty_dest))
				{
					dirty_source.g_x = (dirty_dest.g_x - work_area.g_x)
						+ undo_area.g_x;
					dirty_source.g_y = (dirty_dest.g_y - work_area.g_y)
						+ undo_area.g_y;
					dirty_source.g_w = dirty_dest.g_w;
					dirty_source.g_h = dirty_dest.g_h;
					rast_op(3, &dirty_source, &undo_mfdb,
					&dirty_dest, &scrn_mfdb);
				}
			}
		}
		wind_get(wh, WF_NEXTXYWH, &box.g_x, &box.g_y, &box.g_w, &box.g_h);
	}
	graf_mouse(M_ON, 0x0L);
}

/*------------------------------*/
/*	do_full			*/
/*------------------------------*/
VOID
do_full(wh)	/* depending on current window state, either make window*/
WORD	wh;	/*   full size -or- return to previous shrunken size	*/
{
	GRECT	prev;
	GRECT	curr;
	GRECT	full;

	graf_mouse(M_OFF,0x0L);
	wind_get(wh, WF_CURRXYWH, &curr.g_x, &curr.g_y, &curr.g_w, &curr.g_h);
	wind_get(wh, WF_PREVXYWH, &prev.g_x, &prev.g_y, &prev.g_w, &prev.g_h);
	wind_get(wh, WF_FULLXYWH, &full.g_x, &full.g_y, &full.g_w, &full.g_h);
	if ( rc_equal(&curr, &full) )
	{					/* is full now so change*/
		/**/					/*   to previous	*/
		graf_shrinkbox(prev.g_x, prev.g_y, prev.g_w, prev.g_h,
			full.g_x, full.g_y, full.g_w, full.g_h);
		wind_set(wh, WF_CURRXYWH, prev.g_x, prev.g_y, prev.g_w, prev.g_h);
		rc_copy(&save_area, &undo_area);
		set_work(TRUE);
		if ((prev.g_x == full.g_x) && (prev.g_y == full.g_y))
			do_redraw(wh, &work_area);
	}
	else
	{					/* is not full so make	*/
		/**/					/*   it full		*/
		rc_copy(&undo_area, &save_area);
		graf_growbox(curr.g_x, curr.g_y, curr.g_w, curr.g_h,
			full.g_x, full.g_y, full.g_w, full.g_h);
		wind_set(wh, WF_CURRXYWH, full.g_x, full.g_y, full.g_w, full.g_h);
		set_work(TRUE);
	}
	graf_mouse(M_ON,0x0L);
}
/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Mouse Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hdl_mouse		*/
/*------------------------------*/
WORD
hdl_mouse()
{
	BOOLEAN	done;

	if (m_out)
		graf_mouse(ARROW, 0x0L);
	else
		graf_mouse(monumber, mofaddr);

	m_out = !m_out;
	done = FALSE;
	return(done);
}


/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Button Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hndl_button		*/
/*------------------------------*/
WORD
hndl_button()
{
	WORD	done;

	done = FALSE;
	if (inside(mousex, mousey, &work_area))
	{
		if (dood_fill == TRUE)
			do_fill(mousex, mousey);
		else
			draw_pencil(mousex, mousey);
	}
	return(done);
}


/*------------------------------*/
/*	draw_pencil		*/
/*------------------------------*/
WORD
draw_pencil(x, y)
UWORD	x, y;
{
	UWORD	pxy[4];
	WORD	done;
	UWORD	mflags;
	UWORD	locount, hicount;
	UWORD	ev_which, bbutton, kstate, kreturn, breturn;

	set_clip(TRUE, &work_area);
	pxy[0] = x;
	pxy[1] = y;

	vsl_color(vdi_handle,dodle_shade);
	vswr_mode(vdi_handle,MD_REPLACE);
	vsl_type (vdi_handle,IP_1PATT);

	if (dodle_shade == pen_ink)
	{
		vsl_width (vdi_handle,dodle_pen);
		vsl_ends(vdi_handle, 2, 2);
		hicount = 0;
		locount = 125;
		mflags = MU_BUTTON | MU_M1 | MU_TIMER;
		graf_mouse(M_OFF, 0x0L);
	}
	else
	{
		vsf_interior(vdi_handle, 1);
		vsf_color(vdi_handle, bkgr_color);
		mflags = MU_BUTTON | MU_M1;
	}

	done = FALSE;
	while (!done)
	{
		ev_which = evnt_multi(mflags,
		0x01, 0x01, 0x00, 
		1, pxy[0], pxy[1], 1, 1,
		0, 0, 0, 0, 0,
		ad_rmsg, locount, hicount,
		&pxy[2], &pxy[3], &bbutton, &kstate,
		&kreturn, &breturn);

		if (ev_which & MU_BUTTON)
		{
			if (!(mflags & MU_TIMER))
				graf_mouse(M_OFF, 0x0L);
			if (dodle_shade == pen_ink)
				v_pline(vdi_handle, 2, (WORD *) pxy);
			else
				eraser((WORD) pxy[2], (WORD) pxy[3]);
			graf_mouse(M_ON, 0x0L);
			done = TRUE;
		}
		else
			if (ev_which & MU_TIMER)
			{
				graf_mouse(M_ON, 0x0L);
				mflags = MU_BUTTON | MU_M1;
			}
			else
			{
				if (!(mflags & MU_TIMER))
					graf_mouse(M_OFF, 0x0L);
				if (dodle_shade == pen_ink)
				{
					v_pline(vdi_handle, 2, (WORD *) pxy);
					mflags = MU_BUTTON | MU_M1 | MU_TIMER;
				}
				else
				{
					eraser((WORD) pxy[2], (WORD) pxy[3]);
					graf_mouse(M_ON,0x0L);
				}
				pxy[0] = pxy[2];
				pxy[1] = pxy[3];
			}
	} /* while */

	set_clip(FALSE, &work_area);
	save_work();
}


/*------------------------------*/
/*	eraser			*/
/*------------------------------*/
VOID
eraser(x, y)			/* erase rectangle of eraser size at x,y */
WORD	x, y;
{
	WORD	erase_xy[4];

	if (dodle_pen == PEN_FINE)
	{
		erase_xy[0] = x - 2;
		erase_xy[1] = y - 1;
		erase_xy[2] = x + 2;
		erase_xy[3] = y + 1;
	}
	else
		if (dodle_pen == PEN_MEDIUM)
		{
			erase_xy[0] = x - 4;
			erase_xy[1] = y - 2;
			erase_xy[2] = x + 4;
			erase_xy[3] = y + 2;
		}
		else
		{
			erase_xy[0] = x - 6;
			erase_xy[1] = y - 3;
			erase_xy[2] = x + 6;
			erase_xy[3] = y + 3;
		}
	vr_recfl(vdi_handle, erase_xy);
}

/*----------------------------------------------*/
/*	do_fill		HK 6/30/85		*/
/*----------------------------------------------*/
WORD
do_fill(x, y)
WORD x, y;
{
	WORD	index;

	vsf_interior(vdi_handle, IP_1PATT);
	vsf_color(vdi_handle, pen_ink);
	index = -1;	/* for complete fill */

	graf_mouse(M_OFF, 0x0L);
	v_contourfill(vdi_handle, x, y, index);
	save_work();
	graf_mouse(M_ON, 0x0L);
	
	if (first_fill == TRUE)
	{
		bkgr_color = pen_ink;
		first_fill = FALSE;
	}
}

/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Doodle Event Handler		     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/

/*------------------------------*/
/*	dodle			*/
/*------------------------------*/
dodle()
{
	BOOLEAN	done;

	key_input = FALSE;
	done = FALSE;
	while( !done )		/* loop handling user input until done	*/
	{
		ev_which = evnt_multi(MU_BUTTON | MU_MESAG | MU_M1 | MU_KEYBD,
		0x02, 0x01, 0x01, 
		m_out,
		(UWORD) work_area.g_x, (UWORD) work_area.g_y,
		(UWORD) work_area.g_w, (UWORD) work_area.g_h,
		0, 0, 0, 0, 0,
		ad_rmsg, 0, 0, 
		&mousex, &mousey, &bstate, &kstate,
		&kreturn, &bclicks);

		wind_update(BEG_UPDATE);

		if (!(ev_which & MU_KEYBD))
		{
			if (key_input)
			{
/*				curs_off();	*/
				key_input = FALSE;
				save_work();
			}
		}

		if (ev_which & MU_BUTTON)
			done = hndl_button();

		if (ev_which & MU_M1)
			done = hdl_mouse();

		if (ev_which & MU_MESAG)
			done = hdl_message();

		if (ev_which & MU_KEYBD)
			done = hndl_keyboard();

		wind_update(END_UPDATE);
	}
}
/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Termination				     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	dodle_term		*/
/*------------------------------*/
dodle_term(term_type)
WORD	term_type;
{
	switch (term_type)	/* NOTE: all cases fall through		*/
	{
		case (0 /* normal termination */):
			do_close(dodle_whndl, gl_wfull/2, gl_hfull/2);
			wind_delete(dodle_whndl);
		case (3):
			menu_bar(0x0L, FALSE);
			Mfree(undo_mfdb.mp);
		case (2):
			v_clsvwk( vdi_handle );
		case (1):
			appl_exit();
		case (4):
			break;
	}
}

/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Initialization			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	dodle_init		*/
/*------------------------------*/
WORD
dodle_init()
{
	WORD	work_in[11];
	WORD	i;
	WORD	me_creturn;
	gl_apid = appl_init();			/* initialize libraries	*/
	if (gl_apid == -1)
		return(4);
	wind_update(BEG_UPDATE);
	graf_mouse(HOURGLASS, 0x0L);
	if (!rsrc_load( ADDR("DOODLE.RSC") ))
	{
		graf_mouse(ARROW, 0x0L);
		form_alert(1,
		ADDR("[3][Fatal Error !|DOODLE.RSC|File Not Found][ Abort ]"));
		return(1);
	}
	/* open virtual workstation */
	/* allocate undo buffer	*/
	for (i=0; i<10; i++)
	{
		work_in[i]=1;
	}
	work_in[10]=2;

	gem_handle = graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
	vdi_handle = gem_handle;
	v_opnvwk(work_in,&vdi_handle,work_out);

	if (vdi_handle == 0)
		return(1);

	scrn_width = work_out[0] + 1;
	scrn_height = work_out[1] + 1;
	scrn_xsize = work_out[3];
	scrn_ysize = work_out[4];

	char_fine = work_out[46];
	char_medium = work_out[48];
	char_broad = char_medium * 2;

	vq_extnd(vdi_handle, 1, work_out);
	scrn_planes = work_out[4];

	undo_mfdb.fwp = scrn_width;
	undo_mfdb.fww = undo_mfdb.fwp>>4;
	undo_mfdb.fh = scrn_height;
	undo_mfdb.np = scrn_planes;
	undo_mfdb.ff = 0;

	buff_size = (LONG)(undo_mfdb.fwp>>3) *
	    (LONG)undo_mfdb.fh *
	    (LONG)undo_mfdb.np;
	buff_location =
	    undo_mfdb.mp  = Malloc(buff_size);
	if (undo_mfdb.mp == 0)
		return(2);
	scrn_area.g_x = 0;
	scrn_area.g_y = 0;
	scrn_area.g_w = scrn_width;
	scrn_area.g_h = scrn_height;
	scrn_mfdb.mp = 0x0L;

	rc_copy(&scrn_area, &undo_area);
	rast_op(0, &undo_area, &scrn_mfdb, &undo_area, &undo_mfdb);

	ad_rmsg = ADDR((BYTE *) &gl_rmsg[0]);

	wind_get(DESK, WF_WORKXYWH, &gl_xfull, &gl_yfull, &gl_wfull, &gl_hfull);

	/* initialize menu	*/
	rsrc_gaddr(R_TREE, DOODMENU, &gl_menu);
	do_clnormal();
	me_creturn = menu_icheck (gl_menu, COLOR1, SELECTED);

	/* show menu		*/
	menu_bar(gl_menu, TRUE);	

	dodle_whndl = wind_create(0x0fef, gl_xfull - 1, gl_yfull,
	gl_wfull, gl_hfull);
	if (dodle_whndl == -1)
	{
		form_alert(1, string_addr(DOODNWDW));
		return(3);
	}

	graf_mouse(HOURGLASS, 0x0L);
	wind_set(dodle_whndl, WF_NAME,
	" Dr. Doodle Window ", 0, 0);
	gl_xfull = align_x(gl_xfull);
	do_open(dodle_whndl, gl_wfull/2, gl_hfull/2, align_x(gl_xfull),
		gl_yfull, gl_wfull, gl_hfull);
	wind_get(dodle_whndl, WF_WORKXYWH,
	&work_area.g_x, &work_area.g_y,
	&work_area.g_w, &work_area.g_h);

	set_work(TRUE);
	rc_copy (&undo_area, &save_area);

	graf_mouse(ARROW,0x0L);
	wind_update(END_UPDATE);
	return(0);
}
/*

Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Main Program			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	main()			*/
/*------------------------------*/
main()
{
	WORD	term_type;

	if (!(term_type = dodle_init()))
		dodle();
	dodle_term(term_type);
}

/*
* umul_div() 
*/

int umul_div(m1, m2, d1)
unsigned int m1;
unsigned int m2;
unsigned int d1;
{
	unsigned int x;

	x = m2;
	x = x << 1;
	x *= m1;
	x /= d1;
	x += 1;
	x = x >> 1;

	return(x);
}
