; ---------------------------------------------------------------------

; Paul Overaa's Amiga Computing Assembler Series - code for instalment 3

; ---------------------------------------------------------------------

NULL			EQU	   0

TRUE			EQU	   1

NM_TITLE		EQU	   1

NM_ITEM			EQU	   2

NM_END			EQU	   0

IDCMP_MENUPICK		EQU     $00000100

MENUNULL		EQU	$FFFFFFFF
		
im_Class		EQU	 $14

im_Code			EQU	 $18

wd_UserPort		EQU	 $56

TAG_DONE		EQU	   0

TAG_END			EQU	   0

WA_BASE			EQU 	$80000063
WA_Left			EQU	WA_BASE+$01
WA_Top			EQU	WA_BASE+$02
WA_Width		EQU	WA_BASE+$03
WA_Height		EQU	WA_BASE+$04
WA_IDCMP		EQU	WA_BASE+$07
WA_Title		EQU	WA_BASE+$0B
WA_DragBar		EQU	WA_BASE+$1F
WA_PubScreen		EQU	WA_BASE+$16

_AbsExecBase		EQU	   4

_LVOOpenLibrary		EQU	-552

_LVOCloseLibrary	EQU	-414

_LVODisplayBeep		EQU	 -96

_LVOLockPubScreen	EQU	-510

_LVOUnlockPubScreen	EQU	-516

_LVOOpenWindowTagList	EQU	-606

_LVOCloseWindow		EQU	 -72

_LVOGetVisualInfoA	EQU	-126

_LVOFreeVisualInfo	EQU	-132

_LVOCreateMenusA	EQU	 -48

_LVOFreeMenus		EQU	 -54

_LVOLayoutMenusA	EQU	 -66

_LVOSetMenuStrip	EQU	-264

_LVOClearMenuStrip	EQU	 -54

_LVOWaitPort		EQU	-384

_LVOGetMsg		EQU	-372

_LVOReplyMsg		EQU	-378

; ---------------------------------------------------------------------

LINKLIB		MACRO
		move.l	a6,-(a7)
		movea.l	\2,a6
		jsr	\1(a6)
		move.l	(a7)+,a6
		ENDM

CALLSYS		MACRO
		LINKLIB	_LVO\1,\2
		ENDM

; ---------------------------------------------------------------------

_main		lea	function_stack,a5	for alloc/dealloc operations
		lea 	lib_names,a2
		lea 	_DOSBase,a3
		move.w	#(5-1),d3		loop counter
.loop		movea.l	(a2)+,a1		library name pointer
		moveq	#0,d0			any version will do
		CALLSYS	OpenLibrary,_AbsExecBase
		move.l	d0,(a3)+		store returned base
		dbeq	d3,.loop

		beq.s	lib_error_exit				
		
		; all libraries are open and available for use.
						
		jsr	LockScreen
		beq.s	closedown

		jsr	GetVisInfo
		beq.s	closedown
		
		jsr	OpenWindow
		beq.s	closedown
		
		jsr	CreateMenu
		beq.s	closedown
		
		jsr	LayoutMenu
		beq.s	closedown

		jsr	InstallMenu
		beq.s	closedown		
			
		; menu is now set up - so we can call the event handler!

		movea.l window_p,a1
		movea.l wd_UserPort(a1),a2	user port address
		jsr	MenuHandler		handle user actions
				

closedown	move.l	(a5)+,d0		retrieve function pointer
		beq.s	lib_normal_exit
		move.l	d0,a0
		jsr	(a0)			and execute routine if it exists!
		bra.s	closedown


lib_normal_exit	lea	lib_base_end,a3		revised label - see text
		moveq	#5,d2			library count
		jsr	CloseLibs		close libraries
		moveq	#0,d0			clear d0 for O/S
		rts				and terminate program

lib_error_exit	moveq	#(5-1),d2		see part 1 mag text
		sub	d3,d2
		jsr	CloseLibs		close libraries
		moveq	#0,d0			clear d0 for O/S
		rts				and terminate program

; ---------------------------------------------------------------------		

; CloseLibs() On entry...

; 	a3 should hold address of the longword location just past 
; 	   that of the first library to close (this is because the 
;	   routine uses a backward reading loop).

; 	d2 should hold count of the number of libraries to close	

CloseLibs	tst.b	d2			test counter
		beq.s	loop_end		
		movea.l	-(a3),a1		get library base
		CALLSYS	CloseLibrary,_AbsExecBase
		subq.b	#1,d2
		bra.s	CloseLibs
loop_end	rts

; ---------------------------------------------------------------------					

; LockScreen() and UnlkScreen() on entry... need no register parameters!


LockScreen	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		lea	workbench_name,a0	pointer to screen name
		CALLSYS	LockPubScreen,_IntuitionBase
		move.l	d0,workbench_p		save returned pointer
		beq.s	.error
		move.l	#UnlkScreen,-(a5)	push deallocation routine address
.error		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

UnlkScreen	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.w	#NULL,a0		screen name not needed
		movea.l	workbench_p,a1		screen to unlock
		CALLSYS	UnlockPubScreen,_IntuitionBase
		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

; ---------------------------------------------------------------------					

; OpenWindow() and ShutWindow() on entry... need no register parameters!


OpenWindow	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.w	#NULL,a0
		lea	tags,a1			start of  tag list
		CALLSYS	OpenWindowTagList,_IntuitionBase
		move.l	d0,window_p		save returned pointer
		beq.s	.error
		move.l	#ShutWindow,-(a5)	push deallocation routine address
.error		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

ShutWindow	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	window_p,a0		window to close
		CALLSYS	CloseWindow,_IntuitionBase
		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

; ---------------------------------------------------------------------					

; GetVisInfo() and FreeVisInfo() on entry... need no register parameters!


GetVisInfo	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	workbench_p,a0		
		movea.w	#TAG_END,a1		no tags
		CALLSYS	GetVisualInfoA,_GadToolsBase
		move.l	d0,visual_info_p	save returned pointer
		beq.s	.error
		move.l	#FreeVisInfo,-(a5)	push deallocation routine address
.error		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

FreeVisInfo	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	visual_info_p,a0	
		CALLSYS	FreeVisualInfo,_GadToolsBase
		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

; ---------------------------------------------------------------------					

; CreateMenu() and FreeMenu() on entry... need no register parameters!


CreateMenu	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		lea	menu,a0
		movea.w	#TAG_END,a1		no tags
		CALLSYS	CreateMenusA,_GadToolsBase
		move.l	d0,menu_p		save returned pointer
		beq.s	.error
		move.l	#FreeMenu,-(a5)		push deallocation routine address
.error		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

FreeMenu	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	menu_p,a0		menu to free
		CALLSYS	FreeMenus,_GadToolsBase
		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

; ---------------------------------------------------------------------					

; LayoutMenu() on entry... needs no register parameters!


LayoutMenu	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	menu_p,a0
		movea.l	visual_info_p,a1
		movea.w	#TAG_END,a2		no tags
		CALLSYS	LayoutMenusA,_GadToolsBase
		tst.l	d0			nothing to deallocate
		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

; ---------------------------------------------------------------------					

; InstallMenu() and RemoveMenu() on entry... need no register parameters!


InstallMenu	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	window_p,a0
		movea.l	menu_p,a1
		CALLSYS	SetMenuStrip,_IntuitionBase
		tst.l	d0
		beq.s	.error
		move.l	#RemoveMenu,-(a5)	push deallocation routine address
.error		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

RemoveMenu	movem.l	a0-a1/d0-d1,-(a7)	preserve regs
		movea.l	window_p,a0		target window
		CALLSYS	ClearMenuStrip,_IntuitionBase
		movem.l	(a7)+,a0-a1/d0-d1	restore regs
		rts

; ---------------------------------------------------------------------					

; Function name:     MenuHandler()

; Purpose:           Handle window's menu events

; Input Parameters:  Address of IDCMP user-port should be in a2. 

; Output parameters: None

; Register Usage:    a0: Used by WaitPort() and GetMsg()  
                     
;                    a1: Used by ReplyMsg()
                     
;                    a2: Holds user-port address

;                    d0: Used by WaitPort() and GetMsg()
                     
;                    d1: Unused but possibly altered by system functions

;                    d2: Used as an exit flag (quit when non-zero)

;		     d3: Used to hold message class field

;		     d4: Used to hold message code field
		     
; Other Notes:       All registers are preserved

; ---------------------------------------------------------------------

MenuHandler   	movem.l	d0-d4/a0-a2,-(a7)	preserve registers
		clr.l	d2			clear exit flag
MenuHandler2	movea.l	a2,a0			port address  
		CALLSYS	WaitPort,_AbsExecBase  
		jsr	GetMessage           
		cmpi.l	#TRUE,d2		exit flag set?
		bne.s	MenuHandler2
		movem.l	(a7)+,d0-d4/a0-a2	restore registers
		rts				logical end of routine

; ---------------------------------------------------------------------
                     
GetMessage	movea.l	a2,a0			get port address in a0
		CALLSYS	GetMsg,_AbsExecBase	get the message
		tst.l	d0
		beq.s	GetMessageExit		did it exist?
		move.l	d0,a1			copy pointer to a1
		move.l	im_Class(a1),d3		copy message class
		move.w	im_Code(a1),d4		copy message code
		CALLSYS	ReplyMsg,_AbsExecBase	then send message back

		cmpi.l	#IDCMP_MENUPICK,d3 	check message class
		bne.s	GetMessage           	skip all non-menu messages
		cmpi.w	#MENUNULL,d4
		beq.s	GetMessage		also skip if MENUNULL

		lsr.w	#5,d4			extract menu item number
		andi.b	#$3F,d4			(will be either 0 or 1)
		beq.s	GetFile
		moveq	#TRUE,d2		set QUIT signal to exit routine 
		bra.s	GetMessage
		
GetFile		jsr	FileHandler
		bra.s	GetMessage		check for more messages!

GetMessageExit	rts				d2 holds exit flag
                     
; ---------------------------------------------------------------------

; WARNING - This routine is NOT yet complete!

FileHandler	movem.l	d0-d4/a0-a2,-(a7)	preserve some registers

		; notice how I've included a call to this dummy 
		; routine at present. This allows me to structure 
		; the GetMessage() code even though the file handler 
		; does not (yet) exist!

		movem.l	(a7)+,d0-d4/a0-a2	restore some registers

		rts
				
; ---------------------------------------------------------------------


_DOSBase	ds.l 1
_GfxBase	ds.l 1
_IntuitionBase	ds.l 1
_GadToolsBase 	ds.l 1
_AslBase	ds.l 1
lib_base_end					;end of library base variables

window_p	ds.l 1
visual_info_p	ds.l 1
menu_p		ds.l 1

tags		dc.l	WA_PubScreen
workbench_p	ds.l	1
		dc.l	WA_Left,0
		dc.l	WA_Top,0
		dc.l	WA_Width,640
		dc.l	WA_Height,200
		dc.l	WA_DragBar,TRUE
		dc.l	WA_IDCMP,IDCMP_MENUPICK
		dc.l	WA_Title,window_name
		dc.l	TAG_DONE,NULL

stack_space	ds.l	5			space will grow as required
function_stack	dc.l	NULL			top of function stack

menu		dc.b	NM_TITLE,0
		dc.l	menu_title,NULL
		dc.w	0
		dc.l	0,NULL
		
		dc.b	NM_ITEM,0
		dc.l	item0,commkey0
		dc.w	0
		dc.l	0,NULL
		
		dc.b	NM_ITEM,0
		dc.l	item1,commkey1
		dc.w	0
		dc.l	0,NULL

		dc.b	NM_END,0
		dc.l	NULL,NULL
		dc.w	0
		dc.l	0,NULL
		

lib_names	dc.l lib1,lib2,lib3,lib4,lib5

lib1		dc.b 'dos.library',NULL
lib2		dc.b 'graphics.library',NULL
lib3		dc.b 'intuition.library',NULL
lib4		dc.b 'gadtools.library',NULL
lib5		dc.b 'asl.library',NULL

workbench_name	dc.b 'Workbench',NULL

window_name	dc.b 'Amiga Computing Assembler Series by Paul Overaa',NULL

menu_title	dc.b 'PROJECT',NULL

item0		dc.b 'Select File...',NULL

commkey0	dc.b 'S',NULL

item1		dc.b 'Quit to Workbench!',NULL

commkey1	dc.b 'Q',NULL

		END

; ---------------------------------------------------------------------


		