;***************************************************************************
; This program is an example of how to add a Rexx implementation to any
; program using the rexxapp.library.  The original Freedraw program (without
; REXX) is from Fred Fish Disk 1. The rexxapp.library is based upon a C module
; by Radical Eye Software which was modified and down-coded to a 68000 shared
; library.
; All the REXX stuff is bracketed by IFNE TALKTOREXX, so you can identify it
; easily.  If you assemble with TALKTOREXX equ 0, you will get the default
; program with no REXX port. The REXX port on this program increases the
; executable slightly, but a lot of functionality comes with that. You can draw
; from Rexx, spawn macros from Rexx, etc.  But go to the next TALKTOREXX for
; more information. To run a rexx macro on startup, simply give that rexx macro
; as part of the command line, as in "freedraw sample" or "freedraw bspline 20
; 100 20 20 280 20 280 100". All modifications are placed in the public domain.
;
; Note that I did not do much more than just run the original C through a
; compiler to produce this assembly module. I did not think it worthwhile to
; optimize the example, although the rexxapp.library is a very tight Rexx
; interface.

TALKTOREXX	equ	1

;**********************************************************************
;               FreeDraw - PD graphics for Amiga           
;
; This is an extremely simple graphics editor which works in the windowing
; environment of the Amiga.  It is very limited in features. The basic idea of
; this program is to provide some minimal image editing functions which can be
; used to develop images for other programs.  I know there will be a lot of
; Paint There are only two menu topics in this version, so using it is really
; quite easy.  Boxes are not allowed to be drawn in areas outside of the window
; where border gadgets are located, and the pen-draw mode also clips to these
; same boundaries. If you have begun to draw a box by clicking the left button
; while the cursor is located in the FreeDraw window, then you can cancel that
; box by clicking the right button. In the pen mode pressing and holding the
; left button will draw.  Colors are selected by simply releasing the menu
; button over the desired color in the Color menu. The erase feature always
; clears the window to the currently selected color. This is no gem of
; programming style, but you're getting it for the right price so be patient
; with its design flaws. New versions will appear here on BIX as soon as I can
; get them in shape for release.  I apologize to anyone who objects to my lack
; of coding grace, but I just want to get the project off the ground, and
; improvements will be forthcoming.  There are a lot of comments, but I didn't
; know what needed to be made clear so I just commented everything.             
;
;Rick Ross 11/14/85

	OBJFILE	"rad:freedraw.o"
	ADDSYM
	SMALLOBJ

	;from small.lib or amiga.lib
	XREF	_LVOWindowToBack,_LVOWindowToFront,_LVOCloseWindow,_LVOOpenWindow
	XREF	_LVOSetMenuStrip,_LVOClearMenuStrip,_LVOSetWindowTitles
	XREF	_LVOGetMsg,_LVOReplyMsg,_LVOWait
	XREF	_LVOOpenLibrary,_LVOOldOpenLibrary,_LVOCloseLibrary
	XREF	_LVODraw,_LVOMove,_LVOSetAPen,_LVORectFill,_LVOSetDrMd

	;from StartUp.o
	XREF	_exit,_SysBase,_DOSBase

	;from Rexx App lib
_LVOSetRexxPort		equ	-30
_LVOReceiveRexx		equ	-36
_LVOFreeRexxPort	equ	-42
_LVOSendRexxCmd		equ	-48
_LVOASyncRexxCmd	equ	-54
_LVOSyncRexxCmd		equ	-60
_LVOSetupResults	equ	-66

;**************************************************************
;DrawBox - Simple routine to draw an unfilled rectangle 
;
;It accepts the  coordinates of the top-left and lower-right points of the
;rectangle, a pointer to the Window structure, and the color in which to render
;the rectangle.  The current FgPen color of the window is preserved thru the
;call. No clipping is done.
;
;DrawBox(topleftx, toplefty, lowrightx, lowrighty, window, color )

	XDEF	DrawBox
DrawBox:
	link	a5,#0
	movea.l	_GfxBase,a6
	movem.l	d2/a2,-(sp)
;---save window's FgPen
	movea.l	24(a5),a0
	movea.l	50(a0),a2	;RastPort
	move.b	25(a2),d2
;---set draw color for box
	move.l	28(a5),d0
	movea.l	a2,a1
	jsr	_LVOSetAPen(a6)
;---move to top-left point
	move.l	12(a5),d1
	move.l	8(a5),d0
	movea.l	a2,a1
	jsr	_LVOMove(a6)
;---Draw to each of the four corners of the box
	move.l	12(a5),d1
	move.l	16(a5),d0
	movea.l	a2,a1
	jsr	_LVODraw(a6)
	move.l	20(a5),d1
	move.l	16(a5),d0
	movea.l	a2,a1
	jsr	_LVODraw(a6)
	move.l	20(a5),d1
	move.l	8(a5),d0
	movea.l	a2,a1
	jsr	_LVODraw(a6)
	move.l	12(a5),d1
	move.l	8(a5),d0
	movea.l	a2,a1
	jsr	_LVODraw(a6)
;---restore old FgPen
	moveq	#0,d0
	move.b	d2,d0
	movea.l	a2,a1
	jsr	_LVOSetAPen(a6)
	movem.l	(sp)+,d2/a2
	unlk	a5
	rts

;**************************************************************
;The following function initializes the structure arrays
;needed to provide the Color menu topic.
;
;InitColorItems(depth)
;		 d0
;
;depth is the number of bit-planes in window

	XDEF	InitColorItems
InitColorItems:
	movem.l	d2/d3/d4/d5,-(sp)
;---get # of colors allowed for this depth
	move.w	d0,d4
	lea	_palette,a0
	adda.w	d0,a0
	moveq	#0,d2
	move.b	(a0),d2
	lea	_coloritem,a0
	lea	_colorimage,a1
	moveq	#0,d3
	bra	2$
;=============== Init Next Item ===============
;coloritem[n].NextItem = &coloritem[n+1]
1$	lea	34(a0),a6
	move.l	a6,(a0)+
;the next two items might be changed for when bit-planes is greater than 2
;coloritem[n].LeftEdge = 2 + CW * (n % 4)
	move.l	d3,d0
	moveq	#4,d1
	divu.w	d1,d0
	move.w	d0,d5
	swap	d0
	moveq	#40,d1
	mulu.w	d1,d0
	addq.w	#2,d0
	move.w	d0,(a0)+
;coloritem[n].TopEdge = CH * (n / 4)
	moveq	#25,d1
	mulu.w	d1,d5
	move.w	d5,(a0)+
;coloritem[n].Width = CW
	move.w	#40,(a0)+
;coloritem[n].Height = CH
	move.w	#25,(a0)+
;coloritem[n].Flags = ITEMSTUFF
	move.w	#144,(a0)+
;coloritem[n].MutualExclude = 0
	clr.l	(a0)+
;coloritem[n].ItemFill = (APTR)&colorimage[n]
	move.l	a1,(a0)+
;coloritem[n].SelectFill = NULL
	clr.l	(a0)+
;coloritem[n].Command = 0
	clr.w	(a0)+
;coloritem[n].SubItem = NULL
	clr.l	(a0)+
;coloritem[n].NextSelect = 0
	clr.w	(a0)+
;=============== Init next Image ===============
;colorimage[n].LeftEdge = 1
	move.w	#1,(a1)+
;colorimage[n].TopEdge = 1
	move.w	#1,(a1)+
;colorimage[n].Width = CW-2
	move.w	#38,(a1)+
;colorimage[n].Height = CH-2
	move.w	#23,(a1)+
;colorimage[n].Depth = depth
	move.w	d4,(a1)+
;colorimage[n].ImageData = NULL
	clr.l	(a1)+
;colorimage[n].PlanePick = 0
	clr.b	(a1)+
;colorimage[n].PlaneOnOff = n
	move.b	d3,(a1)+
;colorimage[n].NextImage = 0
	clr.l	(a1)+
	addq.w	#1,d3
2$	Dbra	d2,1$(pc)
;coloritem[colors-1].NextItem = NULL (needed for last item in list)
	clr.l	-34(a0)
	movem.l	(sp)+,d2/d3/d4/d5
	rts

;******************************************************
;*                   Main Program                     *
;*                                                    *
;*      This is the main body of the program.         *
;******************************************************

	XDEF	_main
_main:
	link	a5,#-310
;---DrawColor = 1  (initial drawing color)
	move.b	#1,-5(a5)
;---OldBRX = 30, OldBRY = 30  (point coords used for boxes)
	move.w	#30,-8(a5)
	move.w	#30,-10(a5)
;---TLX = 20, TLY = 20  (initial top-left point coords)
	move.w	#20,-12(a5)
	move.w	#20,-14(a5)
;---MouseMoved = FALSE   (indicates new mouse position ready)
	clr.w	-38(a5)
;---ClipIt = FALSE    (are new point coords out of bounds?)
	clr.w	-40(a5)
;---ClippedLast = FALSE    (was last PenDraw operation clipped?)
	clr.w	-42(a5)
;---PenMode = FALSE    (indicates PenDraw mode is set)
	clr.w	-44(a5)
;---PenDown = FALSE     (if mouse moved, then should it draw?)
	clr.w	-46(a5)
;---RubberBox = FALSE    (are we currently rubberbanding a box?)
	clr.w	-48(a5)
;---FilledBox = FALSE   (should boxes be filled when drawn?)
	clr.w	-50(a5)
;---Open Graphics
	movea.l	_SysBase,a6
	lea	GfxName,a1
	jsr	_LVOOldOpenLibrary(a6)
	move.l	d0,_GfxBase
;---Open Intuition
	lea	IntuiName,a1
	jsr	_LVOOldOpenLibrary(a6)
	move.l	d0,_IntuitionBase

	IFNE	TALKTOREXX
;---Open RexxApp lib
	lea	RexxName,a1
	moveq	#0,d0
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,_rexxBase
	beq	CLSE2
	ENDIF

;---Try to open new window for application
	lea	_NewWindow,a0
	movea.l	_IntuitionBase,a6
	jsr	_LVOOpenWindow(a6)
	move.l	d0,_Window
	beq	CLSE
;set initial clipping boundaries from the values found in the window
;structure for border dimensions
	bsr	SetBounds
;initialize Color menu arrays
	moveq	#2,d0
	bsr	InitColorItems
;SetMenuStrip( Window, &menu[0] )
	lea	_menu1,a1
	move.l	_Window,a0
	movea.l	_IntuitionBase,a6
	jsr	_LVOSetMenuStrip(a6)
;set initial draw mode JAM1 and color
	moveq	#0,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetDrMd(a6)
;SetAPen( Window->RPort, DrawColor )
	moveq	#0,d0
	move.b	-5(a5),d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	jsr	_LVOSetAPen(a6)

;==================================================================
	IFNE TALKTOREXX
;For rexx, we open up a Rexx port, and send out the first command, if there
;was one, that the user typed on the CLI line. We send it out asynchronously
;(ie as a macro for the ARexx server to execute). Arexx will load the script
;(ie our command string will be the name of the script) and execute it (ie
;send ARexx msgs to the target task). It just so happens that all the demo
;ARexx scripts that we wrote use Freedraw itself as the target task. In
;other words, we are sending out a Rexxmsg which will cause the ARexx server
;to execute a script which sends ARexx msgs to Freedraw. This is how a self-
;running demo of a program might be implemented. We could have written some
;scripts to control other products, which Freedraw could start up as so:
	move.l	8(a5),d2
	movea.l	12(a5),a2
	addq.l	#4,a2
;---Save a5, and set it up as the base of our RexxData
	move.l	a5,-(sp)
	lea	_rexxPort,a5
;---rexxMask = SetRexxPort()
	movea.l	_rexxBase,a6
	lea		RXname,a1
	jsr	_LVOSetRexxPort(a6)
	beq.s	4$		;an error in setting up the port
;---append all the args from the CLI into 1 string with spaces between each arg
	subq.l	#2,d2		;don't count the name of the program
	bcs.s	5$
	lea	ArexxCmdStr,a1	;here's where we'll make our Arexx scriptname
1$	movea.l	(a2)+,a0
2$	move.b	(a0)+,(a1)+
	bne.s	2$
	move.b	#' ',-1(a1)
	clr.b	(a1)
	dbra	d2,1$
;---Send this command string out as a macro (ie asyncRexxCmd)
	lea	ArexxCmdStr,a0
	jsr	_LVOASyncRexxCmd(a6)
;---If an error in sending out Rexxmsg, print the returned err msg to window
	bne.s	5$
4$	;---null-term error string in a0
	bsr	printRexxErr
;---Restore a5
5$	movea.l	(sp)+,a5
	ENDIF

;Everything the program needs is now initialized and put in place.  The
;program enters the following loop and processes message continuously as they
;are received from Intuition. I guess this loop is the real workhorse of the
;program.  By the way, the loop control variable KeepGoing remains TRUE until a
;CLOSEWINDOW message is received. At that point it goes FALSE, and the program
;cleans up and exits.
;   while( KeepGoing )
.37	tst.w	_KeepGoing
	beq	.38
;stay here until a message is received from Intuition or REXX port
	movea.l	_Window,a0
	movea.l	86(a0),a1

	IFNE	TALKTOREXX
	move.l	RexxMask,d0	;If ARexx, use the mask that the lib setup
	ENDIF
	IFEQ	TALKTOREXX
	moveq	#0,d0
	ENDIF

	move.b	15(a1),d1
	bset.l	d1,d0
	movea.l	_SysBase,a6
	jsr	_LVOWait(a6)

	IFNE	TALKTOREXX
;---see if any REXX msgs to handle (safe to call even if Rexx port not setup)
;   If there are any ARexx msgs, receiveRexx will handle them by calling our
;   ErrorVector for msgs that WE sent out (ie the msg that started up the
;   whole, initial script process), or by calling myDispatch() for msgs that
;   some other task sends us (ie the ARexx server will be sending us msgs when
;   it executes that script file, or another program could be sending msgs to
;   our FreeDraw _rexxPort).
	move.l	a5,-(sp)
	lea	_rexxPort,a5	;setup a5 as base of Rexx data section
	movea.l	_rexxBase,a6
	jsr	_LVOReceiveRexx(a6)
	movea.l	(sp)+,a5
	ENDIF

;---MouseMoved = FALSE   (clear this flag each time thru loop)
	clr.w	-38(a5)
;---get next IntuiMsg at window
.39	movea.l	_Window,a0
	movea.l	86(a0),a0
	movea.l	_SysBase,a6
	jsr	_LVOGetMsg(a6)
	move.l	d0,-4(a5)
	beq	.40
	movea.l	d0,a1
	move.l	20(a1),-18(a5)
;code = NewMessage->Code
	move.w	24(a1),-20(a5)
;x = Window->MouseX
	move.l	_Window,a0
	move.w	14(a0),-22(a5)
;y = Window->MouseY
	move.w	12(a0),-24(a5)
;Reply the IntuiMessage
	jsr	_LVOReplyMsg(a6)
;Examine point coords from message received and set the clipping flag if out
;of bounds. If user was drawing in PenMode when message was received, then the
;ClippedLast flag should also be set to indicate this to the next draw oper-
;ation.
;if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY )) if( PenDown )
	move.w	-22(a5),d0
	cmp.w	_MinX,d0
	blt.s	.43
	move.w	-22(a5),d0
	cmp.w	_MaxX,d0
	bgt.s	.43
	move.w	-24(a5),d0
	cmp.w	_MinY,d0
	blt.s	.43
	move.w	-24(a5),d0
	cmp.w	_MaxY,d0
	ble.s	.42
.43	moveq	#1,d0
	bra.s	.44
.42	moveq	#0,d0
.44	move.w	d0,-40(a5)
	beq	.41
;ClippedLast = TRUE
	tst.w	-46(a5)
	beq.s	.41
	move.w	#1,-42(a5)
;enter switch on type of message received
.41	move.l	-18(a5),d0
	subq.l	#2,d0
	beq.s	.49
	subq.l	#6,d0
	beq.s	.51
	subq.l	#8,d0
	beq.s	.48
	sub.l	#240,d0
	beq	.66
	sub.l	#256,d0
	beq.s	.50
	sub.l	#523776,d0
	beq	.82
	bra	.39
;========================case MOUSEMOVE:
;Don't really do anything with this one
;until any other, more important, messages
;are received and processed.
;MouseMoved = TRUE
.48	move.w	#1,-38(a5)
	bra	.39
;========================case NEWSIZE:
.49	bsr	SetBounds
	bra	.39
;========================case CLOSEWINDOW:
;User is ready to quit, so indicate that execution should terminate
;with next iteration of the IDCMP loop.
.50	clr.w	_KeepGoing
	bra	.39
;=======================case MOUSEBUTTONS:
;A number of things could have happened here, and further examination of data
;received from message is needed to determine what action should be taken.
;The code variable holds important info about what actually caused the message
;to be sent in the first place.
.51	move.w	-20(a5),d0
	subi.w	#104,d0
	beq.s	.55
	subq.w	#1,d0
	beq	.64
	subi.w	#127,d0
	bne	.39
;case SELECTUP:
;User was holding down the left button and just released it. The PenMode
;flag variables are set accordingly. The pen can no longer be down, and
;ClippedLast is reset for next time.
;PenDown = ClippedLast = FALSE
.54	clr.w	-42(a5)
	clr.w	-46(a5)
	bra	.39
;case SELECTDOWN:
;User has pressed the left button, and
;several differnt actions may need to
;be taken.  If the ClipIt value is TRUE,
;then no action should be taken at all.
;
;if( ClipIt ) break;
.55	tst.w	-40(a5)
	bne	.39
;If user is currently in PenMode, then set up to draw when MOUSEMOVED messages
;are received until a subsequent SELECTUP message comes in.
;if( PenMode )
	tst.w	-44(a5)
	beq	.56
;PenDown = TRUE
	move.w	#1,-46(a5)
;ClippedLast = FALSE
	clr.w	-42(a5)
;make sure to set appropriate mode, JAM1
	moveq	#0,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetDrMd(a6)
;and establish initial position to draw
	moveq	#0,d1
	move.w	-24(a5),d1
	moveq	#0,d0
	move.w	-22(a5),d0
	move.l	_Window,a0
	move.l	50(a0),a1
	jsr	_LVOMove(a6)
	bra	.39
;If user is currently rubberbanding a box, then a SELECTDOWN message means it
;is time to stop rubberbanding and actually draw it. The following code will
;be executed if this is the case, and it will determine if a filled box is
;needed before rendering.
;if( RubberBox )
.56	tst.w	-48(a5)
	beq	.57
;set draw mode back to JAM1 since it is now currently set to COMPLEMENT
	moveq	#0,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetDrMd(a6)
;RubberBox = FALSE  (turn off rubberbanding)
	clr.w	-48(a5)
;Restore the condition of the RMBTRAP bit in the Window structure's Flags
;member.  Menubutton events will not be received by this loop.
	movea.l	_Window,a0
	bclr.b	#0,25(a0)
;RectFill is not condusive to the smooth execution of programs if arguments are
;out of order, so this code sorts them in preparation for the call.
;if( FilledBox )
	tst.w	-50(a5)
	beq	.58
;first sort the x-coords
;if TLX < OldBRX
	move.w	-12(a5),d0
	cmp.w	-8(a5),d0
	bge.s	.59
;x1 = TLX,  x2 = OldBRX
	move.w	-12(a5),-26(a5)
	move.w	-8(a5),-30(a5)
	bra.s	.60
;x1 = OldBRX,  x2 = TLX
.59	move.w	-8(a5),-26(a5)
	move.w	-12(a5),-30(a5)
;then sort the y-coords
;if TLY < OldBRY
.60	move.w	-14(a5),d0
	cmp.w	-10(a5),d0
	bge.s	.61
;y1 = TLY;  y2 = OldBRY
	move.w	-14(a5),-28(a5)
	move.w	-10(a5),-32(a5)
	bra.s	.62
;y1 = OldBRY;  y2 = TLY
.61	move.w	-10(a5),-28(a5)
	move.w	-14(a5),-32(a5)
; now generate the filled rectangle
;RectFill( Window->RPort, (long)x1, (long)y1,(long)x2, (long)y2 )
.62	moveq	#0,d3
	move.w	-32(a5),d3
	moveq	#0,d2
	move.w	-30(a5),d2
	moveq	#0,d1
	move.w	-28(a5),d1
	moveq	#0,d0
	move.w	-26(a5),d0
	move.l	_Window,a0
	move.l	50(a0),a1
	jsr	_LVORectFill(a6)
	bra	.39
;FilledBox not set, so draw hollow box
;DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor )
.58	moveq	#0,d0
	move.b	-5(a5),d0
	move.l	d0,-(sp)
	move.l	_Window,-(sp)
	moveq	#0,d0
	move.w	-10(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-8(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-14(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-12(a5),d0
	move.l	d0,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
	bra	.39
;If execution comes here, then PenMode was
;not set and user was not rubberbanding.
;SELECTDOWN therefore indicates to start the
;rubberbanding process at this point. The
;initial coords are set to the values we
;received when the GetMsg() was executed.
;TLX = OldBRX = x,  TLY = OldBRY = y
.57	move.w	-22(a5),-8(a5)
	move.w	-22(a5),-12(a5)
	move.w	-24(a5),-10(a5)
	move.w	-24(a5),-14(a5)
;set to render in COMPLEMENT mode
	moveq	#2,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetDrMd(a6)
;/* set flag to indicate we are now rubberbanding */
;RubberBox = TRUE
	move.w	#1,-48(a5)
;This instruction indicates to Intuition that we now wish to receive a message
;each time the Menubutton is pressed. This is how we hijack the right button
;for temporary use as a Cancel button instead of a Menubutton.
;Window->Flags |= RMBTRAP
	move.l	_Window,a0
	bset.b	#0,25(a0)
;render the initial rubberbox and exit
;DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor )
	moveq	#0,d0
	move.b	-5(a5),d0
	move.l	d0,-(sp)
	move.l	_Window,-(sp)
	moveq	#0,d0
	move.w	-10(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-8(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-14(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-12(a5),d0
	move.l	d0,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
	bra	.39
;=======================case MENUDOWN:
;WE only receive this message class if
;the RMBTRAP flag bit has been set, so
;it always means that we should cancel
;the box which is currently rubberbanding.
;turn the flag off */
;RubberBox = FALSE
.64	clr.w	-48(a5)
;restore control of menubutton to Intuition */
;Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
	move.l	_Window,a0
	bclr.b	#0,25(a0)
;erase (by double XOR'ing) the current
;rubberbox and exit switch.
;DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
	moveq	#0,d0
	move.b	-5(a5),d0
	move.l	d0,-(sp)
	move.l	_Window,-(sp)
	moveq	#0,d0
	move.w	-10(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-8(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-14(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-12(a5),d0
	move.l	d0,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
	bra	.39
;=======================case MENUPICK:
;A menu event has taken place and is ready to be processed. Examine the code
;variable received from the message to determine what action should be taken.
;The first check is for code=MENUNULL, which means that nothing should be done.
.66	cmp.w	#-1,-20(a5)
	beq	.39
;get menu and item numbers from code
;MenuNum = MENUNUM( code )
	moveq	#31,d0
	and.w	-20(a5),d0
	move.w	d0,-34(a5)
;ItemNum = ITEMNUM( code )
	move.w	-20(a5),d1
	lsr.w	#5,d1
	and.w	#63,d1
	move.w	d1,-36(a5)
;determine appropriate action by menu number
;switch ( MenuNum )
	tst.w	d0
	beq.s	.70
	subq.w	#1,d0
	beq.s	.71
	bra	.39
;case 0:
;Menu 0 is the Color menu. The item number indicates which new color to set.
;DrawColor = ItemNum
.70	moveq	#0,d0
	move.b	d1,d0
	move.b	d0,-5(a5)
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetAPen(a6)
	bra	.39
;case 1:
;Menu 1 is the DrawMode menu. The item number indicates what to do.
;NOTE: Since we cannot have received this message if we were rubberbanding,
;then there is no need to clean up before changing drawing modes.
.71	move.w	d1,d0
	beq.s	.74
	subq.w	#1,d1
	beq.s	.75
	subq.w	#1,d1
	beq.s	.76
	subq.w	#1,d1
	bne	.39
;case 3:
;set flag variables for PenMode
;PenMode = TRUE;
.77	move.w	#1,-44(a5)
	bra	.39
;case 1: set flag variables for hollow box */
;PenMode = FALSE;
.75	clr.w	-44(a5)
;FilledBox = FALSE;
	clr.w	-50(a5)
	bra	.39
;case 2: set flag variables for filled box
;PenMode = FALSE
.76	clr.w	-44(a5)
;FilledBox = TRUE
	move.w	#1,-50(a5)
	bra	.39
;case 0: Erase window to current color 
;---set JAM1
.74	moveq	#0,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetDrMd(a6)
;RectFill( Window->RPort, (long)MinX, (long)MinY,(long)MaxX, (long)MaxY);
	moveq	#0,d3
	move.w	_MaxY,d3
	moveq	#0,d2
	move.w	_MaxX,d2
	moveq	#0,d1
	move.w	_MinY,d1
	moveq	#0,d0
	move.w	_MinX,d0
	move.l	_Window,a0
	move.l	50(a0),a1
	jsr	_LVORectFill(a6)
	bra	.39
;============case INACTIVEWINDOW:
.82
;User has de-selected our window, so a
;little bit of cleaning up may be needed
;to prevent untoward events when he comes
;back to it.
;erase any outstanding rubberbox */
;if( RubberBox )
;DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor)
	tst.w	-48(a5)
	beq	.83
	moveq	#0,d0
	move.b	-5(a5),d0
	move.l	d0,-(sp)
	move.l	_Window,-(sp)
	moveq	#0,d0
	move.w	-10(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-8(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-14(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-12(a5),d0
	move.l	d0,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
;reset all the flafg variables */
;PenDown = ClippedLast = RubberBox = FALSE;
.83
	clr.w	-48(a5)
	clr.w	-42(a5)
	clr.w	-46(a5)
;return possibly diverted menubutton events to Big I
;Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
	move.l	_Window,a0
	bclr.b	#0,25(a0)
	bra	.39
;============================================================
;There are no more messages waiting at the IDCMP port, so we can now proceed
;to process any MOUSEMOVED message we may have received.
;if( MouseMoved && !ClipIt)
.40	tst.w	-38(a5)
	beq	.37
	tst.w	-40(a5)
	bne	.37
;the mouse did move, and we don't need to clip
;check first if we are drawing in PenMode
;if( PenDown )
	tst.w	-46(a5)
	beq	.88
;We have to examine if we clipped the
;last PenMode draw operation.  If we did,
;then this is the first move back into
;window boundaries, so we mov instead of
;drawing.
;if( ClippedLast )
	tst.w	-42(a5)
	beq	.89
;ClippedLast = FALSE;         /* reset this flag 
	clr.w	-42(a5)
	moveq	#0,d1
	move.w	-24(a5),d1
	moveq	#0,d0
	move.w	-22(a5),d0
	move.l	_Window,a0
	move.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOMove(a6)
	bra	.37
;Draw( Window->RPort, (long)x, (long)y ); /* draw to x,y coords
.89	moveq	#0,d1
	move.w	-24(a5),d1
	moveq	#0,d0
	move.w	-22(a5),d0
	move.l	_Window,a0
	move.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVODraw(a6)
	bra	.37
;We weren't in PenMode, but we still might
;be rubberbanding a box.  If so, then we
;should erase the current rubberbox and
;draw a new one with the new mouse coords.
;
;if( RubberBox )
.88	tst.w	-48(a5)
	beq	.37
;erase the old rubberbox - draw mode is COMPLEMENT
;DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
	moveq	#0,d0
	move.b	-5(a5),d0
	move.l	d0,-(sp)
	move.l	_Window,-(sp)
	moveq	#0,d0
	move.w	-10(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-8(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-14(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-12(a5),d0
	move.l	d0,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
;assign new values to box coords */
;OldBRX = x;  OldBRY = y;
	move.w	-22(a5),-8(a5)
	move.w	-24(a5),-10(a5)
;and draw the new rubberbox */ 
;DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
	moveq	#0,d0
	move.b	-5(a5),d0
	move.l	d0,-(sp)
	move.l	_Window,-(sp)
	moveq	#0,d0
	move.w	-10(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-8(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-14(a5),d0
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	-12(a5),d0
	move.l	d0,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
	bra	.37
;====================== PROGRAM CLEANUP AND EXIT ========================
.38
;It must be time to quit, so we have to clean up and exit.

	IFNE TALKTOREXX
;With Rexx, we need to bring the port down.  You must call freeRexxPort before
;doing any exit() for programs that have multiple paths to exit.
	move.l	a5,-(sp)
	lea	_rexxPort,a5
	movea.l	_rexxBase,a6
	jsr	_LVOFreeRexxPort(a6)
	movea.l	(sp)+,a5
	ENDIF

;---Clear our MenuStrip
	movea.l	_Window,a0
	movea.l	_IntuitionBase,a6
	jsr	_LVOClearMenuStrip(a6)
;---Close our Window
	move.l	_Window,a0
	jsr	_LVOCloseWindow(a6)
;---Close the RexxApp lib
CLSE	movea.l	_SysBase,a6

	IFNE	TALKTOREXX
	movea.l	_rexxBase,a1
	jsr	_LVOCloseLibrary(a6)
	ENDIF

;---Close Graphics and Intuition
CLSE2	movea.l	_IntuitionBase,a1
	jsr	_LVOCloseLibrary(a6)
	movea.l	_GfxBase,a1
	jsr	_LVOCloseLibrary(a6)
;---exit the program
	pea	1
	jsr	_exit
	add.w	#4,sp
	unlk	a5
	rts

SetBounds:
;---MinX = Window->BorderLeft
	move.l	_Window,a0
	move.b	54(a0),d0
	ext.w	d0
	move.w	d0,_MinX
;---MinY = Window->BorderTop
	move.b	55(a0),d0
	ext.w	d0
	move.w	d0,_MinY
;---MaxX = Window->Width - Window->BorderRight - 1
	move.w	8(a0),d0
	move.b	56(a0),d1
	ext.w	d1
	sub.w	d1,d0
	subq.w	#1,d0
	move.w	d0,_MaxX
;---MaxY = Window->Height - Window->BorderBottom - 1
	move.w	10(a0),d0
	move.b	57(a0),d1
	ext.w	d1
	sub.w	d1,d0
	subq.w	#1,d0
	move.w	d0,_MaxY
	rts

	IFNE TALKTOREXX

;Now we get into the actual code necessary for our REXX port; functions
;that do the real work.  Note that this program was not structured
;particularly nicely for Rexx. I had to write each of these functions.
;Many programs have these subroutines already in place. They are called
;as part of the event loop.  This program, however, just has one big
;IDCMP loop in main with different actions . . .

;********************************************************************
;This is our REXX dispatch function. This is called whenever some other appli-
;cation has sent us an Arexx msg with a command that our program understands.
;The ARexx app lib has already determined which command, and set up a3 as
;the address of the appropriate handler. We now check to make sure a Window
;currently exists.  Then, we store away the `current color' and change it to
;Rexx's current color, call our handler function, and then restore the color.
;If our handler replies, it sets userreplied to indicate that. If the parse and
;everything else was successful, we send an rm_Result of 0 (via setupResults).
;Otherwise, we send a failure of 20 to ARexx server to indicate that the args
;were messed up. We always return TRUE, because we don't have an instance of
;needing to hold onto a Rexxmsg after we use it here. Note that we must not
;alter register a5, but a2, a3, and a4 are OK to scratch.
;
;myDispatch(Rexxmsg, asscListVector, string, RexxDataBase)
;		a2	a3		a4	a5

	XDEF	myDispatch
myDispatch:
;---Make sure that our window is open
	move.l	_Window,d0
	beq.s	1$
;---Initially, error = 0 (indicate no error with getting args from Argstring)
	clr.l	error
;---Initially, no returned Result string
	clr.l	ResultStr
;---Save window's current PenA
	move.l	d4,-(sp)
	movea.l	d0,a0
	movea.l	50(a0),a1
	moveq	#0,d4
	move.b	25(a1),d4
;---Set PenA to currrexxcolor
	move.l	_currrexxcolor,d0
	movea.l	_GfxBase,a6
	jsr	_LVOSetAPen(a6)
;---Call our vector for this rexx command
	movea.l	a4,a0	;put Argstring in a0 too
	jsr	(a3)
;---Restore PenA
	move.l	d4,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOSetAPen(a6)
	move.l	(sp)+,d4
;---if error = 0 (success), SetupResults(Rexxmsg, 0, 0, ResultStr)
	movea.l	ResultStr,a0
	move.l	error,d0	;primary return
	bne.s	1$
	moveq	#0,d1
3$	movea.l	a2,a1
	movea.l	_rexxBase,a6
	jsr	_LVOSetupResults(a6)
;---Tell the lib to reply it now
	moveq	#1,d0
	rts
;---ERROR: SetupResults(Rexxmsg, error, 10, NULL)
1$	moveq	#10,d1
	suba.l	a0,a0		;no return Argstring
	bra.s	3$

;*******************************************************
;This handler sets the current rexx color.
;
;rexxcolor(Rexxmsg, string)
;		a2   a0,a4

	XDEF	rexxcolor
rexxcolor:
;---Get 1 number from the ascii string
	bsr.s	getnm
	move.l	d0,_currrexxcolor
rxout	rts

;***********************************************************************
;This function takes an address of a string (in a0), parses the next number
;(ie converts the next ascii digits into a numeric value), returns it in d0,
;and advances a0 to point to the next char after the last ascii digit. If
;there are no ascii digits in the string at all (if we called this function
;then we must have expected some), then set error to indicate an error in
;this ARexx supplied string (ie there's an arg missing from this ARexx line).
;
;number,string = getnm(string)
; d0	 a0		a0

	XDEF	getnm
getnm:
;---value = 0
	moveq	#0,d0
	moveq	#0,d1
;---If between '0' to '9'
2$	move.b	(a0)+,d1
	beq.s	3$
	subi.b	#'0',d1
	bcs.s	2$
	cmp.b	#9,d1
	bhi.s	2$
5$	mulu.w	#10,d0
	add.l	d1,d0
	move.b	(a0)+,d1
	beq.s	6$
	subi.b	#'0',d1
	bcs.s	6$
	cmp.b	#9,d1
	bls.s	5$
	subq.l	#1,a0
4$	rts
;---No ascii chars to convert
3$	move.b	#20,error+3	;indicate an error upon return to myDispatch of level 20
6$	subq.l	#1,a0
	rts

;**********************************************************************
;This function trys to find `numArgs' numeric arguments in the command
;string, and stuffs them into the args array.
;
;parseargs(string, numArgs)
;	     a0	     d0

	XDEF	parseargs
parseargs:
	move.l	d4,-(sp)
	move.l	d0,d4
	lea	Points,a1
	bra.s	2$
1$	bsr.s	getnm
	move.l	d0,(a1)+
2$	dbra	d4,1$(pc)
	move.l	(sp)+,d4
	rts

;***********************************************************************
;This function silently clips the x and y values of the passed Point
;structure to the current window bounds. My Point is defined as so:
;
;X	 dc.l	[x pixel position of the Point]
;Y	 dc.l	[y pixel position]
;
;clipxy(LineStruct)
;	  a0

	XDEF	clipxy
clipxy:
;---Check that Rectangle[leftX] > MinX
	moveq	#0,d1
	move.w	_MinX,d1
	move.l	(a0),d0
	cmp.l	d0,d1
	bls.s	1$
	move.l	d1,d0
;---Check that Rectangle[leftX] < MaxX
1$	move.w	_MaxX,d1
	cmp.l	d0,d1
	bcc.s	2$
	move.l	d1,d0
2$	move.l	d0,(a0)+
;---Check that Rectangle[topY] > MinY
	move.w	_MinY,d1
	move.l	(a0),d0
	cmp.l	d0,d1
	bls.s	3$
	move.l	d1,d0
;---Check that Rectangle[topY] < MaxY
3$	move.w	_MaxY,d1
	cmp.l	d0,d1
	bcc.s	4$
	move.l	d1,d0
4$	move.l	d0,(a0)+
	rts

;*************************************************************************
; This gets 4 numbers from the passed ascii string and stores them in the
; Rectangle array (4 LONGS). It then clips the Rec to the window dimensions.
;
;leftX	 dc.l	[the left x pixel position of the rectangle]
;topY	 dc.l	[the upper y pixel position]
;rightX  dc.l	[the right x]
;bottomY dc.l	[the bottom y pixel position]
;
;Note that I treat the Rectangle structure as two adjacent Point structures
;
;GetBoxCoords(string)
;		a0

GetBoxCoords:
;---Parse 4 numbers from the ARexx string into a Rectangle structure
	moveq	#4,d0
	bsr.s	parseargs
;---Check the leftX and topY coords
	lea	Points,a0
	bsr.s	clipxy
;---Now check the rightX and bottomY coords
	bra.s	clipxy

;***********************************************************
;This handler parses 4 numbers into Rectangle struct and draws a wireframe box.
;
;rexxbox(Rexxmsg, string)

	XDEF	rexxbox
rexxbox:
	bsr.s	GetBoxCoords
;DrawBox(args[0], args[1], args[2], args[3], Window, currrexxcolor)
	move.l	_currrexxcolor,-(sp)
	move.l	_Window,-(sp)
	move.l	Points+12,-(sp)
	move.l	Points+8,-(sp)
	move.l	Points+4,-(sp)
	move.l	Points,-(sp)
	bsr	DrawBox
	lea	24(sp),sp
	unlk	a5
	rts

;******************************************************************
; This handler parses 4 numbers into Rectangle struct and draws a filled box.
;
; rexxfbox(Rexxmsg, string)

	XDEF	rexxfbox
rexxfbox:
	movem.l	d2/d3,-(sp)
	bsr.s	GetBoxCoords
;---Get 4 corners and error check
	move.l	Points+12,d3
	move.l	Points+8,d2
	move.l	Points+4,d1
	move.l	Points,d0
	cmp.l	d2,d0
	bls.s	1$
	exg.l	d0,d2
1$	cmp.l	d3,d1
	ble.s	2$
	exg.l	d1,d3
;---Draw box
2$	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVORectFill(a6)
	movem.l	(sp)+,d2/d3
	rts

;*********************************************************************
;This handler grabs four numbers from the Rexxstring and draws a line
;We interprete the 4 numbers as X and Y pixel start positions, and X and Y end
;positions.
;
;rexxline(Rexxmsg, string)

	XDEF	rexxline
rexxline:
	bsr	GetBoxCoords
;---Move to start position
	move.l	Points+4,d1
	move.l	Points,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	movea.l	_GfxBase,a6
	jsr	_LVOMove(a6)
;---Draw to end position
	move.l	Points+12,d1
	move.l	Points+8,d0
	movea.l	_Window,a0
	movea.l	50(a0),a1
	jmp	_LVODraw(a6)

;**********************************************************
;This handler pops the window to front.
;
;rexxtofront(Rexxmsg, string)

	XDEF	rexxtofront
rexxtofront:
	movea.l	_Window,a0
	movea.l	_IntuitionBase,a6
	jmp	_LVOWindowToFront(a6)

;******************************************************************
;This handler pops the window to back.
;
;rexxtoback(Rexxmsg, string)

	XDEF	rexxtoback
rexxtoback:
	movea.l	_Window,a0
	movea.l	_IntuitionBase,a6
	jmp	_LVOWindowToBack(a6)

;***************************************************************
;This handler sets the exit flag.
;
;rexxexit(Rexxmsg, string)

	XDEF	rexxexit
rexxexit:
	clr.w	_KeepGoing
	suba.l	a0,a0		;no returned Result string
	rts

;**************************************************************
;This handler returns the version of the program.
;
;rexxversion(Rexxmsg, string)

	XDEF	rexxversion
rexxversion:
;---Setup the address of VERSION as the returned Argstring
;   Note that this is our only example of returning a Result string
	lea	VERSION,a0
	move.l	a0,ResultStr
	rts

;***********************************************************************
;This handler sends the rest of the command asynchronously, allowing us to
;run macros in parallel. Note that the App lib strips leading whitespace from
;the Argstring, so we don't have to do that here.
;
;rexxspawn(Rexxmsg, string)

	XDEF	rexxspawn
rexxspawn:
	;string in a0
	movea.l	_rexxBase,a6
	jmp	_LVOASyncRexxCmd(a6)

;*************************************************************************
; The error routine for Rexxmsgs that we sent out and were returned with an
; error. The error message is in a0 and the error code is in d0. Let's just
; print out the message in the title bar.

printRexxErr:
	movea.l	_IntuitionBase,a6
	movea.l	a0,a1
	movea.l	_Window,a0
	move.l	a2,-(sp)
	suba.l	a2,a2
	jsr	_LVOSetWindowTitles(a6)
	movea.l	(sp)+,a2
	rts

;*************************************************************************
; The Result routine for Rexxmsgs that we sent out and were returned success-
; fully. The Result string is in a0 (or NULL if none) and the Result1 code is
; in d0. Let's just print out the message in the title bar (if not 0) since
; we really don't have any rexx handlers that expect returned strings.

doResult:
	move.l	a0,d1
	bne.s	printRexxErr
	rts

	ENDIF

;	SECTION	FDdata,DATA	;some asms may need this uncommented

_Window		dc.l	0
_MinX		dc.w	0
_MinY		dc.w	0
_MaxX		dc.w	0
_MaxY		dc.w	0
_KeepGoing	dc.w	1	;when this is a 0, we exit

	XDEF	_IntuitionBase,_GfxBase
_IntuitionBase	dc.l	0
_GfxBase	dc.l	0

; This is the Window structure declaration. Nothing fancy is going on here,
;but note the Flags and IDCMPFlags members of the structure define which
;messages will be sent by Intuition.  I haven't used them all and if you want
;to change the settings you should probably do it here instead of using
;ModifyIDCMP later.

	XDEF	_NewWindow
_NewWindow:
	dc.w	10,10,600,180
	dc.b	0,1
;CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK | NEWSIZE | INACTIVEWINDOW
	dc.l	$8031a
;WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE
	dc.l	$120f
	dc.l	0,0
	dc.l	WindowTitle
	dc.l	0,0
	dc.w	100,35,-1,-1
	dc.w	1

;****************************** MENUS ********************************

_menu1	dc.l	_menu2
	dc.w	10,0,50,10,1
	dc.l	Color
	dc.l	_coloritem
	dc.w	0,0,0,0
_menu2	dc.l	0
	dc.w	65,0,85,10,1
	dc.l	DrawMode
	dc.l	EraseItem
	dc.w	0,0,0,0

;================= Menu Items For DrawMode Menu =================

EraseItem:
	dc.l	HollowItem
	dc.w	0,0,112,10
	dc.w	146		;ITEMTEXT|ITEMENABLED|HIGHBOX
	dc.l	0
	dc.l	EraseText
	dc.l	0
	dc.b	0,0
	dc.l	0
	dc.w	0
HollowItem:
	dc.l	FilledItem
	dc.w	0,10,112,10
	dc.w	146
	dc.l	0
	dc.l	HollowBoxText
	dc.l	0
	dc.b	0,0
	dc.l	0
	dc.w	0
FilledItem:
	dc.l	PenItem
	dc.w	0,20,112,10
	dc.w	146
	dc.l	0
	dc.l	FilledBoxText
	dc.l	0
	dc.b	0,0
	dc.l	0
	dc.w	0
PenItem:
	dc.l	0
	dc.w	0,30,112,10
	dc.w	146
	dc.l	0
	dc.l	PenDrawText
	dc.l	0
	dc.b	0,0
	dc.l	0
	dc.w	0

EraseText:
	dc.b	0,1,1,0
	dc.w	0,1
	dc.l	0,EraseAll,0
HollowBoxText:
	dc.b	0,1,1,0
	dc.w	0,1
	dc.l	0,HollowBox,0
FilledBoxText:
	dc.b	0,1,1,0
	dc.w	0,1
	dc.l	0,FilledBox,0
PenDrawText:
	dc.b	0,1,1,0
	dc.w	0,1
	dc.l	0,PenDraw,0

;******************************************************
;               Color Select Menu                     *
;                                                     *
;    This is where the menu for color selection is    *
; defined.  It should be flexible enough to allow for *
; increased palette sizes, but this version is only   *
; for the 4-color mode of the WorkBench screen.       *

_coloritem	ds.b	136
_colorimage	ds.b	80
;array of palette sizes to correspond with depth of window in bit-planes
_palette	dc.b	0,2,4,8,16,32


	IFNE TALKTOREXX

;These first 6 variables are only needed by this program and are not required
;by the Rexx App lib. (ie they exist merely for the use of FreeDraw's ARexx
;handlers)

;the base of rexxapp.library
_rexxBase	dc.l	0

;A buffer into which we place the user's command string for ARexx
ArexxCmdStr	ds.b 256

;The address of the Result string
ResultStr	dc.l 0

;What color is *rexx* drawing in?
_currrexxcolor	dc.l	1

;what args did we see to this function? MAX 4 LONGS
Points		ds.l	4

;was argument parsing successful? A 0 if so, a 1 for error
error		dc.l	0

;******************************** RexxData *********************************
; This part is the mandatory data section needed by the Rexx App lib. Whenever
; you call a function in this library, register a5 must be setup with the base
; of this data block (ie  lea  _rexxPort,a5). The data must be in this order
; up to the end of the association list! Note that the association list can
; be any length as long as it ends with a 0 LONG.
;
; For another program, you will need to alter the command association list
; (and the strings for it). Also, change RexxMacroExt and RXname. If you call
; your Dispatch, Error, and Result vector routines the same as I did, then you
; won't need to alter the variables dispatchFunc, ErrorVector and ResultVector.

;These are the offsets from the base of the data (ie from _rexxPort)
mr_RexxPort	equ	0  ;The imbedded RexxPort (to be setup by SetRexxPort)
mr_RxName	equ	10 ;DO NOT ALTER
mr_RxSig	equ	15 ;DO NOT ALTER
mr_RxTask	equ	16 ;DO NOT ALTER
mr_Flags	equ	32 ;DO NOT ALTER the highest 4 bits (4-7)
mr_MsgsOut	equ	33 ;how many RexxMsgs this app created and has not received back (DO NOT ALTER)
mr_Exten	equ	34 ;the extension for invoking Rexx scripts
mr_Func		equ	38 ;a routine to handle received RexxMsg's from some other application
mr_RxsLib	equ	42 ;the lib base of ARexx server library (DO NOT ALTER)
mr_ErrorV	equ	46 ;a routine for error return of a RexxMsg the app created and sent
mr_Return	equ	50 ;a routine for successful return of a RexxMsg the app created and sent
mr_RexxMask	equ	54 ;signal mask of the Rexx port's mp_SigBit
mr_UserData	equ	58 ;for application's use
mr_AsscList	equ	62 ;the imbedded association list

	CNOP	0,2
	XDEF	_rexxPort
;Our Rexx port
_rexxPort:
	dc.l 0,0
	dc.b 4,0
	dc.l RXname
	dc.b 0
	dc.b -1	;This is negative (bit 7 set) whenever our port isn't set up
	dc.l 0
rxmsg	dc.l rxmsg+4
	dc.l 0
	dc.l rxmsg
	dc.b 0	;DO NOT ALTER THESE LAST 2 BYTES OF THE PORT
	dc.b 0

;extension is the address of a null-term file extension string for ARexx macros
;invoked by this program.  If not 0, any `primitive' not in the association
;list will be sent out to ARexx for interpretation, thus allowing macro
;programs to work just like primitives. If you do not want this behavior,
;supply a 0 here, and those commands not specified in your association list
;will be sent back to ARexx with an error value of RXERRORNOCMD. It should be
;noted that extension should point to a nulled string if no particular
;extention is desired. Here, I've set it to point to 'fd',0
extension	dc.l	RexxMacroExt

;dispatchFunc is the address of the app's Dispatch function.  This function
;will *only* be called by the library when the application calls ReceiveRexx().
;Anytime a command match is found in the association list, this function will
;be called with 3 arguments--- the Rexx message that was received (a2), a
;pointer to the association jmp vector in a3 (ie the handler to be executed),
;and the Argstring in a4 (ARG0) stripped of the command.  This function should
;return a 1 if the message is to be replied to by the lib or a 0 if not. If
;not, the application itself is responsible for replying the message later via
;Exec's ReplyMsg(). Otherwise, the library ALWAYS takes care of properly
;replying all messages. (Freedraw lets the lib take care of all replies. Unless
;you need to hold onto a Rexxmsg and consequently "put the Rexx script to
;sleep" until you reply it later, you'll let the lib take care of replies.
;Also, the app should setup the return values with SetupResults().
dispatchFunc	dc.l	myDispatch

;Address of rexxsyslib.library (DO NOT ALTER)
_RexxSysBase	dc.l	0

;This routine is called when each msg that the application created and sent out
;is returned with an error. It is passed an appropriate error message in a0,
;and the error code in d0. Typically, this routine needs to do nothing more
;than print the message for the user. You must supply at least a dummy routine.
ErrorVector	dc.l	printRexxErr

;This routine is called when each msg that the application created and sent out
;is returned successfully. It is passed any returned Result string in a0,
;and the Result1 code in d0. This routine may do various things with the
;Result1 string or code depending upon which function initially sent the
;message out. You must supply at least a dummy routine.
ResultVector	dc.l	doResult

;The mask of our rexxPort's SigBit (used by our app to wait for Arexx msgs)
RexxMask	dc.l	0

;The application can do anything with this
		dc.l	0

;Here is our command association list. This is simply a table of LONGS. Each
;two LONGS is an entry for a REXX command. For example, the first 2 LONGS in
;the table are for the first REXX command. Remember that REXX commands are
;null-terminated strings. The first LONG is the address of the command string.
;For example, in our command association list for FreeDraw, the first long
;points to the string "color". The next LONG is the address of the function
;that implements the REXX command. For example, the next LONG points to the
;function, rexxcolor. Now whenever we receive a REXX msg with its command
;string being "color", we jsr to the function, rexxcolor. This is the way the
;Rexx app lib determines whether a received Rexxmsg holds a legitimate command
;for our application. For another program, you simply make a new association
;list (and write the respective handlers). This list MUST end with a 0 LONG.
;Please note that your command strings must also be lower case letters (and
;only letters with no imbedded spaces). You will probably also write a new
;dispatch function (modeled after myDispatch), since you may need to do other
;things besides change window colors, check for an open window, etc like what
;FreeDraw needs to do with its ARexx implementation.

	XDEF	myAsscList
myAsscList:
;"color"
	dc.l	color
	dc.l	rexxcolor
;"box"
	dc.l	box
	dc.l	rexxbox
;"fbox"
	dc.l	fbox
	dc.l	rexxfbox
;"line"
	dc.l	line
	dc.l	rexxline
;"tofront"
	dc.l	tofront
	dc.l	rexxtofront
;"toback"
	dc.l	toback
	dc.l	rexxtoback
;"exit"
	dc.l	exit
	dc.l	rexxexit
;"version"
	dc.l	version
	dc.l	rexxversion
;"spawn"
	dc.l	spawn
	dc.l	rexxspawn
;END OF LIST
	dc.l	0

;The following data can be placed anywhere, and will change for another application

;These are the command strings that we will accept ARexx msgs for
color	dc.b	'color',0
box	dc.b	'box',0
fbox	dc.b	'fbox',0
line	dc.b	'line',0
version	dc.b	'version',0
spawn	dc.b	'spawn',0
exit	dc.b	'exit',0
tofront	dc.b	'tofront',0
toback	dc.b	'toback',0

;This is the name of our Rexx port, and is used with the ADDRESS command
;within a Rexx macro to find this app's rexx port. This must be unique for
;every Rexx application. Note that if the user runs 2 copies of FreeDraw,
;the second port's name will be "freedraw2". Also, note that we have an extra
;null byte on the end of our name. THIS EXTRA BYTE IS REQUIRED!
RXname		dc.b	'freedraw',0,0

RexxMacroExt	dc.b	'fd',0		;the macro extention desired for ARexx

RexxName	dc.b	'rexxapp.library',0

	ENDIF

;********************** END OF MANDATORY REXX DATA **********************

GfxName		dc.b	'graphics.library',0
IntuiName	dc.b	'intuition.library',0
VERSION		dc.b	'Freedraw 0.01 by Richard M. Ross',0
WindowTitle	dc.b	'AMIGA FreeDraw 0.01',0
Color		dc.b	'Color',0
DrawMode	dc.b	'DrawMode',0
EraseAll	dc.b	'Erase All',0
HollowBox	dc.b	'Hollow Box',0
FilledBox	dc.b	'Filled Box',0
PenDraw		dc.b	'Pen Draw',0

	END
