DataMuseum.dk

Presents historical artifacts from the history of:

RegneCentralen RC759 "Piccoline"

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RegneCentralen RC759 "Piccoline"

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦2f5cb36d0⟧ TextFile

    Length: 60928 (0xee00)
    Types: TextFile
    Names: »DEMO.C«

Derivation

└─⟦33b70227c⟧ Bits:30003931/GEM_Develop_disk_3_CDOS.imd Disketter indleveret af Steffen Jensen (Piccolo/Piccoline)
    └─⟦this⟧ »DEMO.C« 
└─⟦f18477172⟧ Bits:30003931/GEM_Develop_disk_1_CDOS.imd Disketter indleveret af Steffen Jensen (Piccolo/Piccoline)
    └─⟦this⟧ »SAMP\DEMO.C« 

TextFile

/************************************************************************/
/*	File:	demo.c            					*/
/************************************************************************/
/*									*/
/*		     GGGGG        EEEEEEEE     MM      MM		*/
/*		   GG             EE           MMMM  MMMM		*/
/*		   GG   GGG       EEEEE        MM  MM  MM		*/
/*		   GG   GG        EE           MM      MM		*/
/*		     GGGGG        EEEEEEEE     MM      MM		*/
/*									*/
/************************************************************************/
/*									*/
/*			  +--------------------------+			*/
/*			  ø Digital Research, Inc.   ø			*/
/*			  ø 60 Garden Court	     ø			*/
/*			  ø Monterey, CA.     93940  ø			*/
/*			  +--------------------------+			*/
/*									*/
/*   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 this code.					*/
/*									*/
/*   Author:	Tom Rolander, Tim Oren					*/
/*   PRODUCT:	GEM Sample Application					*/
/*   Module:	DEMO.C							*/
/*   Version:	2.1 							*/
/*   Modified:  Mitch Smith,    April 25, 1986				*/
/*									*/
/************************************************************************/

/*
\f


Page*/
/*------------------------------*/
/*	includes		*/
/*------------------------------*/

#include "portab.h"				/* portable coding conv	*/
#include "machine.h"				/* machine depndnt conv	*/
#include "obdefs.h"				/* object definitions	*/
#include "treeaddr.h"				/* tree address macros	*/
#include "gembind.h"				/* gem binding structs	*/
#include "demo.h" 				/* demo  apl  resource  */
/**/						/*   file offsets	*/

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

#define	ARROW		0  		/* mouse forms		 */
#define	HOUR_GLASS	2

#define	DESK		0 		/* Desktop window handle */

#define END_UPDATE	0   		/* Window Update Flags	 */
#define	BEG_UPDATE	1

#define	PEN_INK		BLACK
#define	PEN_ERASER	WHITE

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

#define X_FWD		0x0100		/* extended object types */
#define X_BAK		0x0200		/* used with scrolling	 */
#define X_SEL		0x0300		/* selectors		 */
#define N_COLORS	15L

#define YSCALE(x)	UMUL_DIV(x, scrn_xsize, scrn_ysize) 

#define TE_TXTLEN(x)    (x + 24)   	/* TEDINFO text length	 */

#define BI_PDATA(x)	(x)		/* BITBLK - image data	 */
#define BI_WB(x)	(x + 4)  	/*  width in bytes	 */
#define BI_HL(x)	(x + 6)  	/*  height - scan lines  */

#define	IB_PMASK(x)	(x)  		/* ICONBLK - icon mask	 */
#define	IB_PDATA(x)	(x + 4) 	/*  icon data		 */
#define	IB_WB(x)	(x + 22)    	/*  width in pixels 	 */
#define	IB_HL(x)	(x + 24) 	/*  height - scan lines  */

/*------------------------------*/
/*	External Functions	*/
/*------------------------------*/

EXTERN LONG	dos_alloc(); 		/* in DOSBIND.C		 */

	
/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Data Structures			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


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

EXTERN	UWORD	DOS_ERR; 		/* in DOSBIND.C			*/
EXTERN	LONG	drawaddr;		/* in FARDRAW.ASM		*/

/*------------------------------*/
/*	Global Data Structures	*/
/*------------------------------*/

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Å;


/*------------------------------*/
/*	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;			/* demo vdi handle		*/
WORD	work_outÆ57Å;			/* open virt workstation values	*/
GRECT	scrn_area;			/* whole screen 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;			/* screen width in pixels	*/
WORD	scrn_height;			/* screen 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;			/* screen memory form defn blk	*/
LONG	buff_size;			/* buffer size req'd for screen	*/
LONG	buff_location;			/* screen buffer pointer	*/
WORD	demo_whndl;			/* demo window handle		*/
WORD	demo_shade = PEN_INK;		/* demo current pen shade	*/
WORD	pen_shade = PEN_INK;		/* saved pen shade		*/
WORD	demo_pen = 1;			/* demo current pen width	*/
WORD	demo_height = 4;		/* demo 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	*/
BYTE    nameÆ13Å = "";			/* Save As 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		*/
					/* demo window title		*/
BYTE	*wdw_title = " GEM Demo Window ";

WORD	usercolorÆ2Å = æ1, 0å;
MFDB	userbrush_mfdb; 		/* MFDB for Prog def objects	*/
APPLBLK brushabÆ6Å; 			/* 6 Programmer defined objects	*/
 
LONG	color_selÆN_COLORS+1Å = æ	/* data for scrolling 		*/
/**/					/*  color selector 		*/
	N_COLORS,
	0x31FF1071L,
	0x32FF1072L,
	0x33FF1073L,
	0x34FF1074L,
	0x35FF1075L,
	0x36FF1076L,
	0x37FF1077L,
	0x38FF1078L,
	0x39FF1079L,
	0x41FF107AL,
	0x42FF107BL,
	0x43FF107CL,
	0x44FF107DL,
	0x45FF107EL,
	0x46FF107FL 
å;


/*
\f


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
å;


/*
\f


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			*/
/*------------------------------*/
VOID
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 upper left x,y 	*/
GRECT	*area;			/*  and lower right x,y	for raster ops	*/
WORD	*array;			/*  and for clipping			*/
æ
	*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Å);
					/* pixel for pixel source 	*/
	/**/				/*  to destination copy 	*/
	vro_cpyfm(vdi_handle, mode, pxy, s_mfdb, d_mfdb);  
å

/*------------------------------*/
/*	vdi_fix			*/
/*------------------------------*/
VOID
vdi_fix(pfd, theaddr, wb, h)  	/* set up MFDB for transform		*/
	MFDB		*pfd;
	LONG		theaddr;
	WORD		wb, h;
æ
	pfd->fww = wb >> 1;     	/* # of bytes to words 		*/
	pfd->fwp = wb << 3;  		/* # of bytes to to pixels 	*/
	pfd->fh = h;			/* height in scan lines		*/
	pfd->np = 1; 			/* number of planes		*/
	pfd->mp = theaddr;  		/* memory pointer		*/
å

/*------------------------------*/
/*	vdi_trans		*/
/*------------------------------*/
WORD
vdi_trans(saddr, swb, daddr, dwb, h) 	/* 'on the fly' transform 	*/
	LONG		saddr;
	WORD		swb;
	LONG		daddr;
	WORD		dwb;
	WORD		h;
æ
	MFDB		src, dst;	/* local MFDB			*/

	vdi_fix(&src, saddr, swb, h);
	src.ff = TRUE;			/* standard format 		*/

	vdi_fix(&dst, daddr, dwb, h);
	dst.ff = FALSE;  		/* transform to device 		*/
	/**/				/*  specific format		*/   
	vr_trnfm(vdi_handle, &src, &dst ); 
å

/*------------------------------*/
/*	trans_gimage		*/
/*------------------------------*/
VOID
trans_gimage(tree, obj) 	/* transform bit images and icons	*/
	LONG	tree;
	WORD	obj;
æ
	LONG	taddr, obspec;
	WORD	wb, hl, type;

	obspec = LLGET(OB_SPEC(obj));
	type = LWGET(OB_TYPE(obj)); 
	if ( type == G_ICON )
	æ
		taddr = LLGET(IB_PMASK(obspec)); /* pointer to icon mask*/
		wb = LWGET(IB_WB(obspec));
		wb = wb >> 3;			/* pixels to bytes 	*/
		hl = LWGET(IB_HL(obspec)); 	/* height in scan lines	*/
		vdi_trans(taddr, wb, taddr, wb, hl); /* transform mask	*/

		taddr = LLGET(IB_PDATA(obspec)); /* pointer to icon data*/
	å
	else
	æ
		taddr = LLGET(BI_PDATA(obspec)); /* pointer to image  	*/
		wb = LWGET(BI_WB(obspec));	 /* width in bytes	*/
		hl = LWGET(BI_HL(obspec));  	 /* height in scan lines*/
	å
	vdi_trans(taddr, wb, taddr, wb, hl);	 /* transform image or 	*/
	/**/					 /* icon data 		*/
å

/*------------------------------*/
/*	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_CXYWH, &x, &y, &w, &h);
	wind_close(wh);
	graf_shrinkbox(org_x, org_y, 21, 21, x, y, w, h);
å

/*------------------------------*/
/*	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); 
å

/*------------------------------*/
/*	draw_rect		*/
/*------------------------------*/
VOID
draw_rect(area)   		/* used by dr_code() to draw a 		*/
GRECT	*area;			/* rectangle around pen/eraser 		*/
æ
    	WORD	pxyÆ10Å;

    	pxyÆ0Å = area->g_x;
    	pxyÆ1Å = area->g_y;
    	pxyÆ2Å = area->g_x + area->g_w - 1;
    	pxyÆ3Å = area->g_y + area->g_h - 1;
    	pxyÆ4Å = pxyÆ2Å;
    	pxyÆ5Å = pxyÆ3Å;
    	pxyÆ3Å = pxyÆ1Å;
    	pxyÆ6Å = pxyÆ0Å;
    	pxyÆ7Å = pxyÆ5Å;
    	pxyÆ8Å = pxyÆ0Å;
    	pxyÆ9Å = pxyÆ1Å;
    	v_pline(vdi_handle, 5, 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));
å	

/*------------------------------*/
/*	do_top			*/
/*------------------------------*/
VOID
do_top(wdw_hndl)		/* top the window if not already active	*/
WORD	wdw_hndl;
æ 
	WORD	active, dummy;

	wind_get(wdw_hndl, WF_TOP, &active, &dummy, &dummy, &dummy);
	if ( wdw_hndl != active )   
		wind_set(wdw_hndl, WF_TOP, 0, 0, 0, 0);  
å

	
/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			Advanced Dialog Handling		     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	set_select		*/
/*------------------------------*/
VOID
set_select(tree, obj, init_no, bind, arry)	/* intialize the color	*/ 
LONG	tree, bindÆÅ, arryÆÅ;			/* selector objects in 	*/ 
WORD	obj, init_no;				/* Pen/Eraser Dialog  	*/ 
æ						
	WORD	n, nobj, cobj, count; 

	indir_obj(tree, obj); 			
	bindÆ0Å = LLGET(OB_SPEC(obj)); 		
	LLSET(OB_SPEC(obj), ADDR(bind));	
	bindÆ1Å = ADDR(arry);			

	n = (WORD) arryÆ0Å;			
	count = 0;
	for (cobj = LWGET(OB_HEAD(obj)); cobj != obj; 
	cobj = LWGET(OB_NEXT(cobj)))		
	æ 	/* loop to init color selector with colors 1 to 4 	*/

		indir_obj(tree, cobj);
		LLSET(OB_SPEC(cobj), ADDR( &arryÆcount + 1Å ));
		count = (count + 1) % n;
	å

	nobj = LWGET(OB_NEXT(obj)); 	/* set pointer to current color	*/
	indir_obj(tree, nobj);
	LLSET(OB_SPEC(nobj), ADDR( &arryÆ1 + init_no % nÅ ));
å

/*------------------------------*/
/*	get_select		*/
/*------------------------------*/
WORD
get_select(tree, obj)		/* Get the Current pen color 		*/
LONG	tree;			/* selection. Used after Pen/Eraser    	*/
WORD	obj;			/* Dialog interaction			*/
æ
	WORD	nobj, cobj;
	LONG	bind, arry, temp;

	bind = LLGET(OB_SPEC(obj));
	dir_obj(tree, obj);
	LLSET(OB_SPEC(obj), LLGET(bind));
	arry = LLGET(bind + sizeof(LONG) );

	for (cobj = LWGET(OB_HEAD(obj)); cobj != obj;
	cobj = LWGET(OB_NEXT(cobj)))
	æ
		dir_obj(tree, cobj);
		LLSET(OB_SPEC(cobj), LLGET(LLGET(OB_SPEC(cobj))));
	å

	nobj = LWGET(OB_NEXT(obj));
	dir_obj(tree, nobj);
	temp = LLGET(OB_SPEC(nobj));
	LLSET(OB_SPEC(nobj), LLGET(temp));
	return (WORD) (temp - arry) / sizeof(LONG) - 1;
å

/*------------------------------*/
/*	move_do			*/
/*------------------------------*/
VOID
move_do(tree, obj, inc) 	/* routine to scroll the color selector	*/
LONG	tree;			/*  in the Pen/Eraser Dialog		*/
WORD	obj, inc; 		
æ
	WORD	cobj; 
	LONG	n, bind, arry, limit, obspec;

	obj = get_parent(tree, obj);
	obj = LWGET(OB_NEXT(obj));
	bind = LLGET(OB_SPEC(obj));
	arry = LLGET(bind + sizeof(LONG));
	n = LLGET(arry) * sizeof(LONG);
	limit = arry + n;

	for (cobj = LWGET(OB_HEAD(obj)); cobj != obj;
	cobj = LWGET(OB_NEXT(cobj)))
	æ
		obspec = LLGET(OB_SPEC(cobj));
		obspec += inc * sizeof(LONG);
		while (obspec <= arry øø obspec > limit)
			obspec += n * ((obspec > limit)? -1: 1);
		LLSET(OB_SPEC(cobj), obspec);
	å 
	redraw_do(tree, obj);
å

/*------------------------------*/
/*	redraw_do		*/
/*------------------------------*/
VOID
redraw_do(tree, obj)		/* Routine to draw a specified object 	*/
LONG	tree;			/* in a tree 				*/
æ  				
	GRECT	o;

	objc_xywh(tree, obj, &o);
	o.g_x -= 3; o.g_y -= 3; o.g_w += 6; o.g_h += 6;
	objc_draw(tree, ROOT, MAX_DEPTH, o.g_x, o.g_y, o.g_w, o.g_h);
å

/*------------------------------*/
/*	xtend_do		*/
/*------------------------------*/
WORD
xtend_do(tree, obj, xtype)	/* called by hndl_dial() if extended	*/
LONG	tree;			/* type object is the exit object  	*/
WORD	obj, xtype;		
æ  					
	LONG	obspec;

	switch (xtype) æ
		case X_SEL: 			/* selected color */
			obspec = LLGET(OB_SPEC(obj));
			obj = get_parent(tree, obj);
			obj = LWGET(OB_NEXT(obj));
			LLSET(OB_SPEC(obj), obspec);
			redraw_do(tree, obj);
			break;
		case X_FWD: 			/* forward arrow  */
			move_do(tree, obj, 1);
			redraw_do(tree, obj);
			break;
		case X_BAK: 			/* backward arrow */
			move_do(tree, obj, -1);
			redraw_do(tree, obj);
			break;
		default:
			break;
	å
	return(FALSE);
å

/*------------------------------*/
/*	hndl_dial		*/
/*------------------------------*/
WORD
hndl_dial(tree, def, x, y, w, h)	/* general purpose dialog 	*/
LONG	tree; 				/*  handler. Provides for 	*/
WORD	def;				/*  extended object type 	*/
WORD	x, y, w, h; 			/*  checking and 'local'	*/
æ  					/*  processing of extended 	*/
					/*  type objects		*/

	WORD	xdial, ydial, wdial, hdial, exitobj;
	WORD	xtype;

	form_center(tree, &xdial, &ydial, &wdial, &hdial);  /* returns 	*/
	/**/				/* screen center x,y,w,h	*/
	
	form_dial(0, x, y, w, h, xdial, ydial, wdial, hdial);/* reserves*/
	/**/				/* screen space for dialog box	*/

	form_dial(1, x, y, w, h, xdial, ydial, wdial, hdial);/*  draws 	*/
	/**/				/* expanding box		*/
	
	objc_draw(tree, ROOT, MAX_DEPTH, xdial, ydial, wdial, hdial);

	FOREVER
	æ
		exitobj = form_do(tree, def) & 0x7FFF;
		xtype = LWGET(OB_TYPE(exitobj)) & 0xFF00;
		if (!xtype)  /* is not extended type */
			break;
		if (xtend_do(tree, exitobj, xtype)) 
			break;
	å

	form_dial(2, x, y, w, h, xdial, ydial, wdial, hdial);/* draws a	*/
	/**/				/* shrinking box 		*/
  
	form_dial(3, x, y, w, h, xdial, ydial, wdial, hdial);/* free 	*/
	/**/				/* screen space, causes redraw	*/
	return (exitobj);
å

/*------------------------------*/
/*	dr_code			*/
/*------------------------------*/   
WORD
dr_code(pparms)				/* called by FARDRAW.ASM when 	*/
LONG	pparms; 			/* drawing Programmer Defined	*/
æ					/* objects in Pen/Eraser Dialog */
	PARMBLK		pb;
    	WORD		pxyÆ10Å, hl, wb;
	LONG		taddr;

	LBCOPY(ADDR(&pb), pparms, sizeof(PARMBLK)); /* copy PARMBLK 	*/
    	set_clip(TRUE, (GRECT *) &pb.pb_xc);

	taddr = pb.pb_parm;	/* original obspec 			*/
	userbrush_mfdb.mp = LLGET(BI_PDATA(taddr)); /* point to data	*/
	hl = LWGET(BI_HL(taddr));	/* height in scan lines		*/
	wb = LWGET(BI_WB(taddr));	/* width in bytes		*/

	userbrush_mfdb.fwp = wb << 3; 	/* set up the MFDB 		*/
	userbrush_mfdb.fww = wb >> 1; 	/*  in preparation 		*/
	userbrush_mfdb.fh = hl;		/*  for a transform		*/
	userbrush_mfdb.np = 1;		/*  monochrome assumed		*/
	userbrush_mfdb.ff = 0;		/* Device specific format	*/

	pxyÆ0Å = pxyÆ1Å = 0;
	pxyÆ2Å = (wb << 3) - 1;
	pxyÆ3Å = hl - 1;
	pxyÆ4Å = pb.pb_x; 
	pxyÆ5Å = pb.pb_y;
	pxyÆ6Å = pxyÆ4Å + pb.pb_w - 1;
	pxyÆ7Å = pxyÆ5Å + pb.pb_h - 1;
	
	/* Copy Raster Transparent */
	vrt_cpyfm(vdi_handle, 2, pxy, &userbrush_mfdb, &scrn_mfdb, usercolor);

	if((pb.pb_currstate!=pb.pb_prevstate)øø(pb.pb_currstate&SELECTED))
	æ   	
		if (pb.pb_currstate & SELECTED)
		  	vsl_color(vdi_handle,BLACK);
		else
		  	vsl_color(vdi_handle,WHITE);
		vsl_width(vdi_handle, 1);
		vsl_type(vdi_handle, FIS_SOLID);

		pb.pb_x--;
		pb.pb_y--;
		pb.pb_w++;
		pb.pb_h++;
		draw_rect((GRECT *) &pb.pb_x);
	 å  
	
	set_clip(FALSE, (GRECT *) &work_area);
	return(0); /*  always return 0 from prog def drawing code	*/
å


/*
\f


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(demo_whndl, WF_WXYWH,
	&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 */
	undo_area.g_x = align_x(undo_area.g_x);
	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)
	æ  			/* set slider positions	*/
		wind_set(demo_whndl, WF_HSLIDE, UMUL_DIV(undo_area.g_x,	1000,
			undo_mfdb.fwp - undo_area.g_w), 0, 0, 0);
		wind_set(demo_whndl, WF_VSLIDE, UMUL_DIV(undo_area.g_y, 1000,
			undo_mfdb.fh - undo_area.g_h), 0, 0, 0);
		wind_set(demo_whndl, WF_HSLSIZ, UMUL_DIV(work_area.g_w, 1000,
			undo_mfdb.fwp), 0, 0, 0);
		wind_set(demo_whndl, WF_VSLSIZ, UMUL_DIV(work_area.g_h, 1000,
			undo_mfdb.fh), 0, 0, 0);
	å

	/* only use portion of work_area on screen	*/
	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);/* turn mouse off */
	rast_op(3, &tmp_area, &scrn_mfdb, &undo_area, &undo_mfdb);
	graf_mouse(M_ON, 0x0L);	/* turn mouse on  */
å

/*------------------------------*/
/*	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);
å


/*
\f


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

/*------------------------------*/
/*	disab_menu		*/
/*------------------------------*/
VOID
disab_menu(which)  		/* disable specified menu item		*/
WORD	which;
æ
	do_obj(gl_menu, which, DISABLED);   
å

/*------------------------------*/
/*	unflag_obj		*/
/*------------------------------*/
VOID
unflag_obj(tree, which, bit)
LONG	tree;
WORD	which, bit;
æ
	WORD	flags;

	flags = LWGET(OB_FLAGS(which));
	LWSET(OB_FLAGS(which), flags & übit);
å

/*------------------------------*/
/*	flag_obj		*/
/*------------------------------*/
VOID
flag_obj(tree, which, bit)
LONG	tree;
WORD	which, bit;
æ
	WORD	flags;

	flags = LWGET(OB_FLAGS(which));
	LWSET(OB_FLAGS(which), flags ø bit);
å

/*------------------------------*/
/*	indir_obj		*/
/*------------------------------*/
VOID
indir_obj(tree, which)
LONG	tree;
WORD	which;
æ
	flag_obj(tree, which, INDIRECT);
å

/*------------------------------*/
/*	dir_obj			*/
/*------------------------------*/
VOID
dir_obj(tree, which)
LONG	tree;
WORD	which;
æ
	unflag_obj(tree, which, INDIRECT);
å

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

	if (obj == NIL)
		return (NIL);
	pobj = LWGET(OB_NEXT(obj));
	if (pobj != NIL)
	æ
	  	while( LWGET(OB_TAIL(pobj)) != obj ) 
	  	æ
	    		obj = pobj;
	    		pobj = LWGET(OB_NEXT(obj));
	  	å
	å
	return(pobj);
å 

/*------------------------------*/
/*	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));
å


/*
\f


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, DEMOFILE, &box);
	rsrc_gaddr( R_TREE, DEMOSVAD, &tree) ;
	ted_addr = LLGET(OB_SPEC(DEMONAME));	/* get obspec pointer 	*/
	LLSET( ted_addr, ADDR(name) ) ;		/* set obspec pointer 	*/
	LWSET( TE_TXTLEN(ted_addr),9); 		/* 1 more than 		*/
	nameÆ0Å = 'Ø0';	/* null to clear edit field and position cursor	*/
	
	if (hndl_dial(tree, DEMONAME, box.g_x, box.g_y, box.g_w, box.g_h) 
		== DEMOSOK)
	æ
		i =
		    j =  0;
		while (TRUE)	/* parse filename string */
		æ
			c = nameÆi++Å;
			if (!c) 
				break ; 
			if ( (c != ' ') && (c != '_') )
				nameÆj++Å = c ;
		å
		if ( *name )
			strcpy( &nameÆjÅ, ".DOO" ); /* add extension	*/
		desel_obj(tree, DEMOSOK);
		return (TRUE); 
	å
	else
	æ
		desel_obj(tree, DEMOSCNL);
		return (FALSE);
	å
å

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

	cur_drv = dos_gdrv();
	tmp_pathÆ0Å = cur_drv + 'A';
	tmp_pathÆ1Å = ':';
	tmp_pathÆ2Å = 'ØØ';
	dos_gdir(cur_drv+1, ADDR(&tmp_pathÆ3Å));
	if (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 = 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 = dos_open(ADDR(file_name),2);
			if (!loop øø (loop && !DOS_ERR))
				return(1);
		å
		else   
		æ
			disab_menu(DEMOSAVE);
			disab_menu(DEMOABAN);
			return(0);   
		å
	å
å /* get_file */


/*
\f


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


/*------------------------------*/
/*	cursor			*/
/*------------------------------*/
VOID
cursor(color)			/* turn cursor on,  color = BLACK	*/
WORD	color;			/*   or cursor off, color = WHITE	*/
æ
	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,FIS_SOLID);
	vsl_width (vdi_handle,PEN_FINE);
	graf_mouse(M_OFF, 0x0L);
	set_clip(TRUE, &work_area);
	v_pline(vdi_handle, 2, pxy);
	set_clip(FALSE, &work_area);
	graf_mouse(M_ON, 0x0L);
å

/*------------------------------*/
/*	curs_on			*/
/*------------------------------*/
VOID
curs_on()			/* turn 'soft' cursor 'on'		*/
æ
	cursor(pen_shade);
å

/*------------------------------*/
/*	curs_off		*/
/*------------------------------*/
VOID
curs_off()			/* turn 'soft' cursor 'off'		*/
æ
	cursor(PEN_ERASER);
å


/*
\f


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


/*------------------------------*/
/*	hndl_menu		*/
/*------------------------------*/
WORD
hndl_menu(title, item)
WORD 	title, item;
æ
	WORD	done;

	graf_mouse(ARROW, 0x0L);
	done = FALSE;

	switch (title) æ
	case DEMODESK: /* Desk menu */
		if (item == DEMOINFO)	/* 'About Demo' menu item	*/
			do_about();	
		break;
	case DEMOFILE: /* File menu */
		switch (item)
		æ
		case DEMOLOAD: /* Load File    */
			do_load(TRUE);
			break;
		case DEMOSAVE: /* Save File    */
			do_save();
			break;
		case DEMOSVAS: /* Save File As */
			do_svas();
			break;
		case DEMOABAN: /* Abandon File */
			file_handle = dos_open(ADDR(file_name),2);
			do_load(FALSE);
			break;
		case DEMOQUIT: /* Quit - Exit back to Desktop	*/
			done = TRUE;
			break;
		å

	case DEMOOPTS:	/* Options menu	*/
		switch (item)
		æ
		case DEMOPENS: /* Pen/Eraser Selection 	*/
			do_penselect();
			break;
		case DEMOERAP: /* Erase Picture 	*/
			do_top(demo_whndl);
			do_erase();
			break;
		å
	å
	menu_tnormal(gl_menu,title,TRUE);
	graf_mouse(monumber, mofaddr); 
	return (done);	
å

/*------------------------------*/
/*	do_about		*/
/*------------------------------*/
VOID
do_about()			/* display Demo Info... 		*/
æ
	LONG	tree;
	GRECT	box;

	objc_xywh(gl_menu, DEMODESK, &box);   	/* DESK menu title xywh	*/
	rsrc_gaddr(R_TREE, DEMOINFD, &tree);	/* address of DEMOINFD	*/
	hndl_dial(tree, 0, box.g_x, box.g_y, box.g_w, box.g_h);
	desel_obj(tree, DEMOOK);		/* deselect OK button	*/
å

/*------------------------------*/
/*	do_load			*/
/*------------------------------*/
VOID
do_load(need_name)		/* load demo picture file		*/
BOOLEAN	need_name;
æ
	if (!need_name øø get_file(TRUE))
	æ
		if (!DOS_ERR)
		æ
			dos_read(file_handle, buff_size,buff_location);
			dos_close(file_handle);
			enab_menu(DEMOSAVE);
			enab_menu(DEMOABAN);
			restore_work();
		å
	å
å

/*------------------------------*/
/*	do_save			*/
/*------------------------------*/
WORD
do_save()			/* save current named demo picture	*/
æ
	if (*file_name)
	æ
		file_handle = dos_open(ADDR(file_name),2);
		if (!DOS_ERR) 
		æ 	/* File already exists 	*/
			if (form_alert(1, string_addr(DEMOOVWR)) == 2)
			æ 	/* Cancel - dont't overwrite 	*/
				dos_close(file_handle);
				return(FALSE); 
			å
		å

		if(DOS_ERR) 
			file_handle = dos_create(ADDR(file_name),0); 
		if(DOS_ERR)
		æ 	/* disable Save and Abandon	*/ 
			disab_menu(DEMOSAVE);
			disab_menu(DEMOABAN);
			return(FALSE);
		å
	
		dos_write(file_handle, buff_size, buff_location);
		enab_menu(DEMOSAVE);
		enab_menu(DEMOABAN);
		dos_close(file_handle);
		return(TRUE); 
	å
å

/*------------------------------*/
/*	do_save_as		*/
/*------------------------------*/
VOID
do_svas()			/* save demo picture as named		*/
æ

	if (dial_name(name))
	æ 
		if (nameÆ0Å != 'Ø0')
		æ
			add_file_name(file_name, name);
			do_save(); 
		å
	å
å

/*------------------------------*/
/*	set_pen			*/
/*------------------------------*/
VOID
set_pen(pen, height)		/* set pen width and height 		*/
WORD	pen, height;
æ
	demo_pen = pen;
	demo_height = height;
	monumber = 5;	/* thin cross hair */
	mofaddr = 0x0L;
å

/*------------------------------*/
/*	set_eraser		*/
/*------------------------------*/
VOID
set_eraser(pen, height, eraser) /* set mouse form to eraser		*/
WORD	pen, height;
BYTE	*eraser;
æ
	demo_pen = pen;
	demo_height = height;
	demo_shade = PEN_ERASER;
	monumber = 255;  
	mofaddr = ADDR(eraser);
å		

/*------------------------------*/
/*	set_color		*/
/*------------------------------*/
VOID
set_color(tree, obj, color_num, bind)	/*  Set Pen Color Selection	*/
LONG	tree, *bind;
WORD	obj, color_num;
æ
	set_select(tree, obj, color_num - 1, bind, color_sel);
å

/*------------------------------*/
/*	get_color		*/
/*------------------------------*/
WORD
get_color(tree, obj)			/* Get Pen Color Selection	*/
LONG	tree;
WORD	obj;
æ
	return get_select(tree, obj) + 1;
å

/*------------------------------*/
/*	do_penselect		*/
/*------------------------------*/
VOID
do_penselect()			/* use dialogue box to input selection	*/
æ				/*   of specified pen/eraser		*/
	WORD	exit_obj, psel_obj, color;
	LONG	tree, bindÆ2Å;
	GRECT	box;

	objc_xywh(gl_menu, DEMOPENS, &box);
	rsrc_gaddr(R_TREE, DEMOPEND, &tree);
	/**/			/* first setup current selection state	*/
	switch (demo_pen) æ
		case PEN_FINE:
			sel_obj(tree, (demo_shade != PEN_ERASER)?
				DEMOPFIN: DEMOEFIN);
			break;
		case PEN_MEDIUM:
			sel_obj(tree, (demo_shade != PEN_ERASER)?
				DEMOPMED: DEMOEMED);
			break;
		case PEN_BROAD:
			sel_obj(tree, (demo_shade != PEN_ERASER)?
				DEMOPBRD: DEMOEBRD);
			break;
	å
	set_color(tree, DEMOPCLR, pen_shade, bind);

	/**/				/* get dialogue box input	*/
	exit_obj = hndl_dial(tree, 0, box.g_x, box.g_y, box.g_w, box.g_h);
	for (psel_obj = DEMOPFIN; psel_obj <= DEMOEBRD; psel_obj++)
		if (LWGET(OB_STATE(psel_obj)) & SELECTED)
		æ
			desel_obj(tree, psel_obj);
			break;
		å
	color = get_color(tree, DEMOPCLR);

	if (exit_obj == DEMOPSOK)
	æ
		switch (psel_obj) æ
			case DEMOPFIN:
				set_pen(PEN_FINE, char_fine);
				demo_shade = color;
				break;
			case DEMOPMED:
				set_pen(PEN_MEDIUM, char_medium);
				demo_shade = color;
				break;
			case DEMOPBRD:
				set_pen(PEN_BROAD, char_broad);
				demo_shade = color;
				break;
			case DEMOEFIN:
				set_eraser(PEN_FINE, char_fine, 
					(BYTE *) erase_fine);
				break;
			case DEMOEMED:
				set_eraser(PEN_MEDIUM, char_medium,
					(BYTE *) erase_medium);
				break;
			case DEMOEBRD:
				set_eraser(PEN_BROAD, char_broad,
					(BYTE *) erase_broad);
				break;
		å
		pen_shade = color;
		desel_obj(tree, DEMOPSOK);
	å
	else
		desel_obj(tree, DEMOCNCL);
å

/*------------------------------*/
/*	do_erase		*/
/*------------------------------*/
VOID
do_erase()			/* clear the screen and the undo buffer	*/
æ 
	rast_op(0, &scrn_area, &scrn_mfdb, &scrn_area, &undo_mfdb);
	restore_work();
å


/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Keyboard Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hndl_keyboard		*/
/*------------------------------*/
WORD
hndl_keyboard()
æ
	WORD	i;
	BYTE	strÆ2Å;
	GRECT	lttr, test;


	if ((strÆ0Å = kreturn & 0xff) == 0x03)   /* Ctrl C */
		return(TRUE); 

	graf_mouse(M_OFF, 0x0L);
	if (!key_input)
	æ
		vswr_mode(vdi_handle, MD_REPLACE);
		vst_color(vdi_handle, pen_shade); 
			
		/* set text height, then calculate space between lines 	*/
		vst_height(vdi_handle, demo_height,
			&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
		gl_hspace = gl_hbox - gl_hchar; 
	
		/* set text alignment to left justification, bottom	*/
		vst_alignment(vdi_handle, 0, 3, &i, &i);
		/* get current mouse location, button and keybd state	*/
		graf_mkstate(&key_xbeg, &key_ybeg, &i, &i);

		key_xcurr = ++key_xbeg;
		key_ycurr = --key_ybeg;
	å
	else
		curs_off();
	strÆ1Å = 'Ø0'; 
	if (strÆ0Å == 0x1A)	/* Ctrl Z  */
	æ
		save_work();	/* update undo area from work area	*/
		graf_mouse(M_ON, 0x0L);
		return(key_input = FALSE);
	å
	else
		if (strÆ0Å == 0x0D)	/* carriage return  */
		æ   
			/* adjust x,y */
			key_ycurr += gl_hbox + gl_hspace;
			key_xcurr = key_xbeg;
		å
		else
			if (strÆ0Å == 0x08)	/* backspace  */
			æ
				if (key_input && (key_xcurr != key_xbeg))
				æ /* 'back up' */
					for (i = 0; i < gl_wbox; i++)
					æ
						key_xcurr--;
						curs_off();
					å
				å
			å
			else    
				if ((strÆ0Å >= ' ') && (strÆ0Å <= 'z'))
				æ /* output character so long as it 	*/
			/**/	  /*	fits in the work area		*/

					lttr.g_x = key_xcurr;
					lttr.g_y = key_ycurr - gl_hbox;
					lttr.g_w = gl_wbox;
					lttr.g_h = gl_hbox;
	
					rc_copy(&lttr, &test);
					rc_intersect(&work_area, &test);
					if (!rc_equal(&lttr, &test))
						æ
						graf_mouse(M_ON, 0x0L);
						return (FALSE);
						å
					set_clip(TRUE, &work_area);
					v_gtext(vdi_handle, key_xcurr,
						key_ycurr, str);
					set_clip(FALSE, &work_area); 

					/* update x position */
					key_xcurr += gl_wbox;
				å
	if (!key_input)
	æ
		key_input = TRUE;
	å
	curs_on();
	graf_mouse(M_ON, 0x0L);
	return(FALSE);	
å


/*
\f


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


/*------------------------------*/
/*	hndl_msg		*/
/*------------------------------*/
/*MLOCAL*/	BOOLEAN	hndl_msg()
æ
	BOOLEAN	done; 
	WORD	wdw_hndl;
	GRECT	work;

	done = FALSE;
	wdw_hndl = gl_rmsgÆ3Å; 
	switch( gl_rmsgÆ0Å )
	æ
	case MN_SELECTED:
		done = hndl_menu(wdw_hndl, gl_rmsgÆ4Å);/* Title, Item	*/
		break;
	case WM_REDRAW:
		do_redraw(wdw_hndl, (GRECT *) &gl_rmsgÆ4Å);/* x,y,w,h 	*/
		break;
	case WM_TOPPED:
		if(wdw_hndl == demo_whndl) /* make sure it's my window	*/
			wind_set(wdw_hndl, WF_TOP, 0, 0, 0, 0);
		break;
	case WM_CLOSED:
		done = TRUE;	/* terminate, exit back to DESKTOP.APP	*/
		break;
	case WM_FULLED:
		do_full(wdw_hndl); /* toggle between full and previous	*/
		break;

	case WM_ARROWED:	/* calculate new undo_area x,y		*/
		switch(gl_rmsgÆ4Å) /* requested action	*/
		æ 	
		case WA_UPPAGE:	/* page up	*/
			undo_area.g_y = max(undo_area.g_y - undo_area.g_h, 0);
			break;
		case WA_DNPAGE:	/* page down	*/
			undo_area.g_y += undo_area.g_h;
			break;
		case WA_UPLINE:	/* row up	*/
			undo_area.g_y = max(undo_area.g_y - YSCALE(16), 0);
			break;
		case WA_DNLINE:	/* row down	*/
			undo_area.g_y += YSCALE(16);
			break;
		case WA_LFPAGE:	/* page left	*/
			undo_area.g_x = max(undo_area.g_x - undo_area.g_w, 0);
			break;
		case WA_RTPAGE:	/* page right	*/
			undo_area.g_x += undo_area.g_w; 
			break;
		case WA_LFLINE:	/* column left	*/
			undo_area.g_x = max(undo_area.g_x - 16, 0);
			break;
		case WA_RTLINE:	/* column right	*/
			undo_area.g_x += 16;
			break;
		å
		set_work(TRUE);	/* update slider positions		*/
		restore_work(); /* update screen from undo_area 	*/
		break;

	case WM_HSLID:	/* horizontal slider	*/
		undo_area.g_x = align_x(UMUL_DIV(undo_mfdb.fwp - undo_area.g_w, 
		gl_rmsgÆ4Å, 1000)); 
		set_work(TRUE);
		restore_work();
		break;
	case WM_VSLID:	/* vertical slider	*/
		undo_area.g_y = UMUL_DIV(undo_mfdb.fh - undo_area.g_h,
		gl_rmsgÆ4Å,1000);
		set_work(TRUE);
		restore_work();
		break;

	case WM_SIZED:	/* new window size requested	*/
		/* get work area x,y,w,h		*/
		wind_calc(1, 0x0fef, gl_rmsgÆ4Å, gl_rmsgÆ5Å, gl_rmsgÆ6Å,
			gl_rmsgÆ7Å, &work.g_x, &work.g_y, &work.g_w,
			&work.g_h); 

		work.g_x = align_x(work.g_x);	/* WORD alignment	*/
		work.g_w = align_x(work.g_w); 	/*  for performance 	*/

		/* get border area x, y, w, h	*/
		wind_calc(0, 0x0fef, work.g_x, work.g_y, work.g_w, work.g_h,
			&gl_rmsgÆ4Å, &gl_rmsgÆ5Å, &gl_rmsgÆ6Å, &gl_rmsgÆ7Å); 

		/* set current x,y,w,h - borders, title bar, (info)     */ 
		wind_set(wdw_hndl, WF_CXYWH, gl_rmsgÆ4Å,
			gl_rmsgÆ5Å, gl_rmsgÆ6Å, gl_rmsgÆ7Å);
		set_work(TRUE);	/* update slider positions */
		break;
	case WM_MOVED:	/* user moved the window 			*/
		gl_rmsgÆ4Å = align_x(gl_rmsgÆ4Å);
		wind_set(wdw_hndl, WF_CXYWH, align_x(gl_rmsgÆ4Å) - 1,
		gl_rmsgÆ5Å, gl_rmsgÆ6Å, gl_rmsgÆ7Å);
		set_work(FALSE); /* NO slider update	*/
		break;
	å /* switch */  
	return(done);
å /* hndl_msg */

/*------------------------------*/
/*	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);  	/* turn mouse off		*/

	/* get the coordinates of the first rectangle in the window's	*/
	/**/					/*     rectangle list	*/

	wind_get(wh, WF_FIRSTXYWH, &box.g_x, &box.g_y, &box.g_w, &box.g_h);
	while ( box.g_w && box.g_h ) 
	æ   /* AES returns zero width and height when no more rectangles*/ 
	    if (rc_intersect(area, &box))
	    æ  
	        if (wh == demo_whndl)
		æ
		    /* copy rectangle list x,y,w,h to dirty_dest	*/
   		    rc_copy(&box, &dirty_dest);

		    if (rc_intersect(&work_area, &dirty_dest))
		    æ  
			/*  calculate dirty_source x and y  */
		        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;  

			/* window rectangle w and h to dirty_source	*/
			dirty_source.g_w = dirty_dest.g_w;
			dirty_source.g_h = dirty_dest.g_h; 

			/* pixel for pixel source to dest copy */
			rast_op(3, &dirty_source, &undo_mfdb,
				&dirty_dest, &scrn_mfdb);
		    å
		å
	    å  
	    /* get next rectangle in window's rectangle list		*/
	    wind_get(wh, WF_NEXTXYWH, &box.g_x, &box.g_y, &box.g_w, &box.g_h);
        å  
	/* done walking the rectangle list - turn mouse back on		*/
    	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_CXYWH, &curr.g_x, &curr.g_y, &curr.g_w, &curr.g_h);
	wind_get(wh, WF_PXYWH, &prev.g_x, &prev.g_y, &prev.g_w, &prev.g_h);
	wind_get(wh, WF_FXYWH, &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_CXYWH, prev.g_x, prev.g_y, prev.g_w, prev.g_h);
		rc_copy(&save_area, &undo_area);
	å
	else
	æ					/* is not full so make	*/
		/**/				/*   it full		*/
		rc_copy(&save_area, &undo_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_CXYWH, full.g_x, full.g_y, full.g_w, full.g_h);
	å 

	set_work(TRUE);
	graf_mouse(M_ON,0x0L);
å


/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Mouse Handling			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	hndl_mouse		*/
/*------------------------------*/
WORD
hndl_mouse() 			/* change mouse form depending on 	*/
æ 				/* whether it's in or out of window 	*/
	BOOLEAN	done;
	
	if (m_out)
		graf_mouse(ARROW, 0x0L);
	else
		graf_mouse(monumber, mofaddr);

	m_out = !m_out; 	/* change MU_M1 entry/exit flag 	*/
	done = FALSE;
	return(done); 
å


/*
\f


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


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

	done = FALSE;
	if (inside(mousex, mousey, &work_area))
		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,demo_shade); 	/* set line color	*/
	vswr_mode(vdi_handle,MD_REPLACE); 	/* replace writing mode */
	vsl_type (vdi_handle,FIS_SOLID);  	/* solid line type 	*/

	if (demo_shade != PEN_ERASER)
	æ
		vsl_width (vdi_handle,demo_pen);  /* set line width	*/
		vsl_ends(vdi_handle, 2, 2);       /* rounded end style  */
		hicount = 0;  			  /* MU_TIMER high 	*/
		locount = 125;  		  /*  and low count	*/
		mflags = MU_BUTTON ø MU_M1 ø MU_TIMER;
		graf_mouse(M_OFF, 0x0L);  	  /* turn mouse 'off'	*/
	å
	else
	æ
		vsf_interior(vdi_handle, 1);	/* solid interior fill 	*/
		vsf_color(vdi_handle, WHITE);	/* fill color 		*/
		mflags = MU_BUTTON ø MU_M1;	
	å

	done = FALSE;
	while (!done)
	æ
		ev_which = evnt_multi(mflags, 
		0x01, 0x01, 0x00, /* 1 click, 1 button, button up */
		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 (demo_shade != PEN_ERASER)
				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 (demo_shade != PEN_ERASER)
				æ
					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 (demo_pen == PEN_FINE)		/* 5 x 3 */
	æ
		erase_xyÆ0Å = x - 2;
		erase_xyÆ1Å = y - 1;
		erase_xyÆ2Å = x + 2;
		erase_xyÆ3Å = y + 1;
	å
	else
		if (demo_pen == PEN_MEDIUM)	/* 9 x 5 */
		æ
			erase_xyÆ0Å = x - 4;
			erase_xyÆ1Å = y - 2;
			erase_xyÆ2Å = x + 4;
			erase_xyÆ3Å = y + 2;
		å
		else				/* 13 x 7 */
		æ
			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);
å


/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Demo Event Handler		     	     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/

/*------------------------------*/
/*	demo			*/
/*------------------------------*/
demo()				/* main event multi loop		*/
æ
	BOOLEAN	done;

	key_input = FALSE;
	done = FALSE;
	FOREVER
	æ  	/* wait for           Button ,    Message, 1 Mouse,keyboard */
               /* 		      Event	  Event    Rect    Event    */
	
		ev_which = evnt_multi(MU_BUTTON ø MU_MESAG ø MU_M1 ø MU_KEYBD,
		0x02, 0x01, 0x01, /* 2 clicks, 1 button, button down */
		m_out,  /* entry , work_area x,y,w,h */ 
		(UWORD) work_area.g_x, (UWORD) work_area.g_y,
		(UWORD) work_area.g_w, (UWORD) work_area.g_h, 
		/* mouse rect 2 flags , x,y,w,h */
		0, 0, 0, 0, 0, 
		/* Message buffer, timer low count , high count 	*/
		ad_rmsg, 0, 0,  
		/* mouse posit ,  btn state, r & lshift, Ctrl, Alt 	*/
		&mousex, &mousey, &bstate, &kstate, 
		/* keybd key,# btn clicks */
		&kreturn, &bclicks);

		wind_update(BEG_UPDATE);

		if (!(ev_which & MU_KEYBD))	/* not KEYBD event */
		æ
			if (key_input)		/* key_input TRUE? */
			æ
				curs_off();	/* turn cursor off */
				key_input = FALSE;	
				save_work();	
			å
		å

		if (ev_which & MU_MESAG)   
		if (hndl_msg()) 
			break;  

		if (ev_which & MU_BUTTON)
		if (hndl_button())
			break;

		if (ev_which & MU_M1)
		if (hndl_mouse())
			break;

		if (ev_which & MU_KEYBD)
		if (hndl_keyboard())
			break;

		wind_update(END_UPDATE);
	å
å


/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Termination				     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	demo_term		*/
/*------------------------------*/
demo_term(term_type)
WORD	term_type;
æ
	switch (term_type)	/* NOTE: all cases fall through		*/
	æ
		case (0 /* normal termination */):
			do_close(demo_whndl, gl_wfull/2, gl_hfull/2);
			wind_delete(demo_whndl);
		case (3 /* no window available */):
			menu_bar(0x0L, FALSE);
			dos_free(undo_mfdb.mp);
		case (2 /* not enough memory */): 
			graf_mouse(ARROW, 0x0L);
			v_clsvwk( vdi_handle );
		case (1 /* no .RSC file or no virt wksta */):
			wind_update(END_UPDATE);
			appl_exit();
		case (4 /* appl_init() failed */):
			break;
	å
å


/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Initialization			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/
/*------------------------------*/
/*	pict_init		*/
/*------------------------------*/
VOID 
pict_init()				/* transform IMAGES and ICONS	*/
æ					/*  set up Programmer Defined 	*/
	LONG	tree;			/*  objects			*/
	WORD	tr_obj, nobj;


	rsrc_gaddr(R_TREE, DEMOINFD, &tree);
	trans_gimage(tree, DEMOIMG); 

	rsrc_gaddr(R_TREE, DEMOPEND, &tree);
	for (tr_obj = DEMOPFIN; tr_obj <= DEMOEBRD; tr_obj++)
	æ  	
		/* loop through Pen/Eraser  Dialog objects transforming	*/
		/* them, setting type to G_PROGDEF, establishing the 	*/
		/* address of the drawing code and setting the obspec 	*/
		/* pointer for each 					*/

		trans_gimage(tree, tr_obj);
		LWSET(OB_TYPE(tr_obj), G_PROGDEF); 	
		nobj = tr_obj - DEMOPFIN;
		brushabÆnobjÅ.ab_code = drawaddr;	
		brushabÆnobjÅ.ab_parm = LLGET(OB_SPEC(tr_obj));
		LLSET(OB_SPEC(tr_obj), ADDR(&brushabÆnobjÅ));	
	å
å

/*------------------------------*/
/*	demo_init		*/
/*------------------------------*/
WORD
demo_init()
æ
	WORD	work_inÆ11Å;
	WORD	i;

	gl_apid = appl_init();			/* init application	*/
	if (gl_apid == -1)
		return(4); 

	wind_update(BEG_UPDATE);
	graf_mouse(HOUR_GLASS, 0x0L);
	if (!rsrc_load( ADDR("DEMO.RSC") ))
	æ    	
		/* No Resource File  */
		graf_mouse(ARROW, 0x0L);
		form_alert(1,
		ADDR("Æ3ÅÆFatal Error !øDEMO.RSCøFile Not FoundÅÆ Abort Å"));
		return(1);
	å
	/* open virtual workstation */
	for (i=0; i<10; i++)
	æ
		work_inÆiÅ=1; /* initial defaults: line style,color,etc	*/
	å
	work_inÆ10Å=2;	/* raster coordinates	*/

	/* Get the VDI handle for GEM AES screen workstation */
	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; 		/* # of pixels wide	*/
	scrn_height = work_outÆ1Å + 1; 		/* # of pixels high	*/
	scrn_xsize = work_outÆ3Å;		/* pixel width (microns)*/
	scrn_ysize = work_outÆ4Å;		/* pixel height(microns)*/

	char_fine = work_outÆ46Å;		/* minimum char height	*/
	char_medium = work_outÆ48Å;		/* maximum char height	*/
	char_broad = char_medium * 2; 		

	vq_extnd(vdi_handle, 1, work_out);	/* extended inquire	*/
	scrn_planes = work_outÆ4Å;		/* # of planes		*/

	undo_mfdb.fwp = scrn_width;		/* width in pixels	*/
	undo_mfdb.fww = undo_mfdb.fwp >> 4;	/* width in words	*/
	undo_mfdb.fh = scrn_height;		/* form height		*/
	undo_mfdb.np = scrn_planes; 		/* # of planes		*/
	undo_mfdb.ff = 0;
	
	buff_size = (LONG)(undo_mfdb.fwp>>3) *	/* # of bytes		*/
	    (LONG)undo_mfdb.fh * 		/* form height		*/
	    (LONG)undo_mfdb.np; 		/* # of planes		*/

	buff_location =
	    undo_mfdb.mp  = dos_alloc(buff_size);
	if (undo_mfdb.mp == 0)
		return(2);  			/* not enough memory	*/
	
	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);

	pict_init();	/* transforms & programmer defined objects 	*/
	ad_rmsg = ADDR((BYTE *) &gl_rmsgÆ0Å); /* init message address	*/

	/* Get Desktop work area	*/
	wind_get(DESK, WF_WXYWH, &gl_xfull, &gl_yfull, &gl_wfull, &gl_hfull);

	/* initialize menu    */
	rsrc_gaddr(R_TREE, DEMOMENU, &gl_menu);

	/* show menu	      */
	menu_bar(gl_menu, TRUE);	
	
	/* create window with all components except info line */
	demo_whndl = wind_create(0x0fef, gl_xfull - 1, gl_yfull,
				gl_wfull, gl_hfull);
	if (demo_whndl == -1)
	æ 
		/* No Window Available		   */
		form_alert(1, string_addr(DEMONWDW));
		return(3);
	å

 	wind_set(demo_whndl, WF_NAME, ADDR(wdw_title), 0, 0); 

	gl_xfull = align_x(gl_xfull);
	do_open(demo_whndl, gl_wfull/2, gl_hfull/2, align_x(gl_xfull)-1,
		gl_yfull, gl_wfull, gl_hfull);

	/* get work area of window */
	wind_get(demo_whndl, WF_WXYWH,
	&work_area.g_x, &work_area.g_y,
	&work_area.g_w, &work_area.g_h);

	set_work(TRUE);	/* initial slider positions */
	rc_copy (&undo_area, &save_area);/* save_area used by do_full() */

	graf_mouse(ARROW, 0x0L);
	wind_update(END_UPDATE);
	return(0);	/* successful initialization */
å


/*
\f


Page*/
/************************************************************************/
/************************************************************************/
/****								     ****/
/****			    Main Program			     ****/
/****								     ****/
/************************************************************************/
/************************************************************************/


/*------------------------------*/
/*	GEMAIN			*/
/*------------------------------*/
GEMAIN()
æ
	WORD	term_type;

	if (!(term_type = demo_init()))
		demo();
	demo_term(term_type);
å
«eof»