;
; tmsGlue.s
;
; Supplies underlying tms workings -- filters, window creation etc. (TMA)
;
;  1994 Straylight
;

;----- Standard Header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

		GET	libs:stream

;----- External dependencies ------------------------------------------------

		GET	libs:tearSupt.sh.tearSupt

		GET	sapphire:event
		GET	sapphire:errorBox
		GET	sapphire:heap
		GET	sapphire:mem
		GET	sapphire:sapphire
		GET	sapphire:screen
		GET	sapphire:wimp
		GET	sapphire:win

		; --- Internal header files ----

		GET	sapphire:_tms.tmsGlobal
		GET	sapphire:_tms.tmsMain

;----- Main code ------------------------------------------------------------

		AREA	|Sapphire$$Code|,CODE,READONLY

;----- Window creation ------------------------------------------------------

; --- tms__calcHeight ---
;
; On entry:	R10 == pointer to menu
;
; On exit:	R0 == The height of the menu, including tearoff bar (-ve)
;
; Use:		Calculates the height of the window, and also sets up
;		the yCoord fields in the items

tms__calcHeight	ROUT

		STMFD	R13!,{R1-R3,R14}	;Stack registers
		MOV	R14,R10			;Keep this pointer
		MOV	R0,#0			;The height so far
		LDR	R3,[R14,#hFlags]	;Get the flags word
		TST	R3,#hFlag__tearable	;Is there a tearoff bar?
		SUBNE	R0,R0,#tms__barHeight	;Yes -- allow for it
		LDR	R14,[R14,#hItems]	;Point to the items

00		CMP	R14,#0			;Are we at the end
		RSBEQ	R1,R0,#0		;Get +ve height
		STREQ	R1,[R10,#hHeight]	;And store in height field
		LDMEQFD	R13!,{R1-R3,PC}^	;Yes -- return
		LDR	R1,[R14,#iNumber]	;Get number of items in block
		ADD	R2,R14,#iHdrSize	;Point to the first item
01		LDR	R3,[R2,#iFlags]		;Get the item flags
		STR	R0,[R2,#iyCoord]	;Store this coordinate
		SUB	R0,R0,#44		;The size of one item
		TST	R3,#iFlag__dotted	;Is there a dotted line?
		SUBNE	R0,R0,#24		;Yes -- allow for it
		SUBS	R1,R1,#1		;Decrement item count
		ADDNE	R2,R2,#iItemSize	;Point to the next item
		BNE	%01tms__calcHeight	;...and count it
		LDR	R14,[R14,#iItems]	;If at end -- point to next
		B	%00tms__calcHeight	;...and count the next block

		LTORG

; --- tms__createWindow ---
;
; On entry:	R0 == the menu height (-ve)
;		R10 == pointer to the menu
;
; On exit:	V and R0 == The standard error block, if an error occured
;		R0 == the window handle
;
; Use:		This call will create a window for the given menu. The
;		block pointed to by R10 will be filled in appropriately
;		with the handle.

		EXPORT	tms__createWindow
tms__createWindow ROUT

		BIC	R14,R14,#V_flag		;Assume no error yet
		STMFD	R13!,{R1-R9,R14}	;Stack some registers

		SUB	R13,R13,#88		;Create a block
		MOV	R9,R13			;Point to the block
		MOV	R5,R0			;The menu height
		LDR	R6,[R10,#hMaxHeight]	;Get the maximum height
		CMP	R6,#0			;Is there one?
		BEQ	%05tms__createWindow	;No -- jump this bit
		CMN	R6,R5			;Is actual height greater?
		MVNLE	R5,R6			;Yes -- make it maxHeight
05		ADR	R0,tms__coords		;Point to the coords
		LDMIA	R0,{R0,R3}		;And get them
		LDR	R6,tms__flags		;Get the flags
		TST	R6,#tFlag__iBar		;Is menu from icon bar
		ADDEQ	R1,R3,R5		;No -- miny = maxy-height
		MOVNE	R1,#96			;Yes -- miny = 96
		SUBNE	R3,R1,R5		;...maxy = miny+height
		BNE	%10tms__createWindow	;Jump the next text
		LDR	R6,[R10,#hFlags]	;Get the header flags
		TST	R6,#hFlag__tearable	;Is there a tearoff bar?
		ADDNE	R1,R1,#tms__barHeight	;Yes -- shift up menu
		ADDNE	R3,R3,#tms__barHeight	;Up, up, up we go
10		LDR	R2,[R10,#hSprWidth]	;The sprite width
		LDR	R4,[R10,#hTextWidth]	;The text width
		LDR	R5,[R10,#hKeyWidth]	;The shortcut width
		ADD	R2,R2,R4		;Calculate the width
		ADD	R2,R2,R5		;Oh yes... Pleeeease!
		ADD	R2,R2,#64		;Left/Right edges+16 for luck
		LDR	R14,[R10,#hTitleWidth]	;Get the title width
		CMP	R14,R2			;Is this greater?
		MOVGT	R2,R14			;Yes -- use this later
		STR	R2,[R10,#hTotWidth]	;Remember this value
		ADD	R2,R2,R0		;And offset from x0
		MOV	R4,#0			;Scroll x offset
		MOV	R5,#0			;Scroll y offset
		MOV	R6,#-1			;The behind value
		LDR	R7,=&84000002		;The wimp flags

		; --- Add a scroll bar if we need to ---

		LDR	R14,[R10,#hFlags]	;Get the flags word
		TST	R14,#hFlag__folded	;Is the menu folded?
		BNE	%17tms__createWindow	;Yes -- no bar needed
		LDR	R8,[R10,#hHeight]	;Get the actual height
		LDR	R14,[R10,#hMaxHeight]	;Get the maximum height
		CMP	R14,#0			;Is there one?
		BEQ	%12tms__createWindow	;No -- compare to screen hght
		CMP	R8,R14			;Is it greater than max?
                BGT	%15tms__createWindow	;Yes -- add scroll bar
12		ADD	R8,R8,#50		;Add 50 to actual
		STMFD	R13!,{R0}		;preserve R0
		BL	screen_getInfo		;Get screen information
		LDR	R0,[R0,#screen_height]	;Get the screen height
		CMP	R8,R0			;Is menu taller than screen?
		LDMFD	R13!,{R0}		;Get R0 back
		BLE	%17tms__createWindow	;No -- don't add bar

15		ORR	R7,R7,#(1<<28)		;Give window a scroll bar
		LDR	R14,[R10,#hFlags]	;Get the menu flags
		ORR	R14,R14,#hFlag__scrBar	;There is a scroll bar
		STR	R14,[R10,#hFlags]	;Store the flags back
		B	%20tms__createWindow	;Jump ahead a bit

17		LDR	R14,[R10,#hFlags]	;Get the menu flags
		BIC	R14,R14,#hFlag__scrBar	;There is a scroll bar
		STR	R14,[R10,#hFlags]	;Store the flags back

20		LDR	R8,=&00070207		;Colours
		LDR	R14,=&000c0103		;More colours
		STMIA	R9!,{R0-R8,R14}		;Store in the block
		SUB	R2,R2,R0		;Get the real width back
		MOV	R0,#0			;Workarea x0
		LDR	R1,[R10,#hHeight]	;Get the actual height
		RSB	R1,R1,#0		;Make it -ve
		MOV	R3,#0			;y1 as for above
		LDR	R4,=&00000139		;The title bar flags
		LDR	R5,=&00003000		;The workarea button type
		MOV	R6,#1			;The sprite area to use
		MOV	R7,#0			;Minimum width/height
		STMIA	R9!,{R0-R7}		;Store in the block
		LDR	R0,[R10,#hText]		;Point to the text
		MOV	R1,#-1			;no validation string
		MOV	R2,#&ff			;The buffer length
		MOV	R3,#0			;No items yet
		STMIA	R9!,{R0-R3}		;Store this data
		MOV	R1,R13			;Point to the block
		SWI	XWimp_CreateWindow	;Try to create the window
		ADD	R13,R13,#88		;Get my block back
		LDMVSFD	R13!,{R1-R9,R14}	;On error, get the registers
		ORRVSS	PC,R14,#V_flag		;...and return with error
		STR	R0,[R10,#hHandle]	;Store the handle in menu
		LDMFD	R13!,{R1-R9,PC}^	;And return to caller

		LTORG

;----- Pre and Post fileters ------------------------------------------------

; --- tms__open ---
;
; On entry:	R0 == pointer to menu to open
;
; On exit:	---
;
; Use:		Opens the given tearoff menu in the right place

tms__open	ROUT

		STMFD	R13!,{R0-R3,R10,R14}	;Stack some registers

		; --- Create the window ---

		MOV	R10,R0			;Keep pointer to the menu
		BL	tms__calcHeight		;Work out the height of menu
		BL	tms__createWindow	;Create the window
		MOVVS	R1,#1			;On error -- show 1 icon
		BLVS	errorBox		;...display the error
		BVS	%99tms__open		;...and return to caller

		; --- Set up an event handler for the menu ---

		LDR	R1,=tms__eventHandler	;Point to the event handler
		MOV	R2,R10			;The handle of the menu
		MOV	R3,R12			;R12 value to call with
		BL	win_eventHandler	;Add the handler

		; --- Now, open the window ---

		SUB	R13,R13,#36		;Get a block
		STR	R0,[R13,#0]		;Store the handle in block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetWindowState	;Get the window state
		SWI	Wimp_OpenWindow		;Open the window
		ADD	R13,R13,#36		;Get my block back

		; --- Fill in any extra information ---

		LDR	R0,tms__current		;Get the current transient
		CMP	R0,#0			;Is there one
		STREQ	R10,tms__current	;No -- store this one then
		BLEQ	wimp_taskHandle		;...get the task handle
		BLEQ	tearSupport_opened	;...start tearoffsupt sending
		LDR	R0,tms__prevLevel	;Point to the previous menu
		CMP	R0,#0			;Is there one?
		STRNE	R10,[R0,#hSubMenu]	;Yes -- store in sub menu ptr
		STR	R0,[R10,#hPrevMenu]	;Yes -- Point back to it
		MOV	R0,#0			;Time to set some values
		STR	R0,[R10,#hSelected]	;No item selected yet
		STR	R0,[R10,#hSubMenu]	;No current submenu either

		; --- And return to the caller ---

99tms__open	MOV	R0,#0			;We are no longer creating
		STR	R0,tms__creating	;So say that!
		LDMFD	R13!,{R0-R3,R10,PC}^	;Return

		LTORG

; --- tms__preFilter ---
;
; On entry:	R0 == event mask and flags
;		R1 == pointer to block to use
;		R2 == earliest time to return with NULL event
;		R3 == pointer to fxp_poll word
;
; On exit:	--
;
; Use:		Called as an event pre-filter. Its purpose is to open
;		a previously created menu in the right place.

tms__preFilter	ROUT

		STMFD	R13!,{R0,R14}		;Stack some registers
		LDR	R0,tms__flags		;Get the main flags word
		TST	R0,#tFlag__doFake	;Should we fake a NULL?
		BNE	%10tms__preFilter	;Yes -- jump ahead then

		; --- Open a menu if we need to ---

		LDR	R0,tms__creating	;Point to menu being created
		CMP	R0,#0			;Is there one?
		LDMEQFD	R13!,{R0,PC}^		;No -- return
		BL	tms__open		;Open the menu
		LDMFD	R13!,{R0,PC}^		;And return to the caller

		; --- Fake a NULL event ---

10		BIC	R0,R0,#tFlag__doFake	;Don't fake again
		ORR	R0,R0,#tFlag__faking	;Remember that we're faking
		STR	R0,tms__flags		;Store back the flags
		MOV	R0,#0			;Return event 0 (NULL)
		ADD	R13,R13,#4		;Skip over old event code
		LDMFD	R13!,{R14}		;Load the link back
		ORRS	PC,R14,#C_flag		;And return with carry set

		LTORG

; --- tms__postFilter ---
;
; On entry:	R0 == wimp event
;		R1 == the Wimp_Poll block
;
; On exit:	--
;
; Use:		Called as a post handle by event to look out for clever
;		things such as button clicks

tms__postFilter	ROUT

		STMFD	R13!,{R0-R3,R14}	;Stack some regisr
		CMP	R0,#6			;Was it a button click?
		BEQ	%10tms__postFilter	;Yes -- deal with it
		LDR	R2,tms__flags		;Get the flags
		BIC	R2,R2,#tFlag__iBar	;It wasn't a click on ibar
		STR	R2,tms__flags		;Store the flags back
		CMP	R0,#17			;User_Message?
		CMPNE	R0,#18			;User_Message_Recorded?
		BEQ	%20tms__postFilter	;Yes -- check it out
		LDMFD	R13!,{R0-R3,PC}^	;Return

		; --- Deal with button click ---

10		LDR	R0,[R1,#12]		;Get the window handle
		CMP	R0,#-2			;Is it the icon bar
		LDR	R0,tms__flags		;Get the flags
		ORREQ	R0,R0,#tFlag__iBar	;Yes -- set relevent bit
		BICNE	R0,R0,#tFlag__iBar	;No -- clear it then
		STR	R0,tms__flags		;Store the flags back
		ADR	R2,tms__coords		;Point to coords block
		LDMIA	R1,{R0,R1}		;Get x and y coords
		SUB	R0,R0,#64		;Correct the x coord
		STMIA	R2,{R0,R1}		;Store them in the block
		LDMFD	R13!,{R0-R3,PC}^	;Return

		; --- It was a message ---

20		LDR	R2,[R1,#16]		;Get the message type
		LDR	R0,=&400C1		;Mode change
		CMP	R2,R0			;Is that the message?
		LDRNE	R0,=&400CF		;Fonts changed
		CMPNE	R2,R0			;Check this one too
		BEQ	%30tms__postFilter	;Yes -- deal with it
		LDR	R0,=&4A340		;Button pressed message
		CMP	R2,R0			;Is that the message?
		BEQ	%50tms__postFilter	;Yes -- deal with it
		LDR	R0,=&4A341		;Close menus
		CMP	R2,R0			;Is that the message?
		BEQ	%60tms__postFilter	;Yes -- deal with it
		LDMFD	R13!,{R0-R3,PC}^	;Return

		; --- Mode change message ---

30		LDR	R0,tms__oldHandle	;Get idle event handler hnd
		CMP	R0,#0			;Is there a current handler?
		BLNE	tms__cleanUp		;Yes -- clean up a bit
		LDR	R2,tms__flags		;Get the flags word
		BIC	R2,R2,#tFlag__newFont	;No font change yet
		LDR	R1,tms__fHandle		;Get the old handle
		MOV	R0,#8			;Read the wimp font handle
		SWI	XWimp_ReadSysInfo	;Read if we can
		MOVVS	R0,#0			;If error -- no font
		CMP	R0,R1			;Compare the handles
		ORRNE	R2,R2,#tFlag__newFont	;If different, mark this
		STRNE	R0,tms__fHandle		;...and store new font handle
		STR	R2,tms__flags		;Store new flags
		LDMFD	R13!,{R0-R3,PC}^	;And return

		; --- Button pressed message ---
		;
		; We must check to see if we are clicking on one of
		; our menus, and close our current transient if we're not

50		LDR	R2,[R1,#32]		;Get the window handle
		LDR	R3,tms__currDbox	;Get the current dbox
		CMP	R3,R2			;Is this what we clicked on?
		BEQ	%70tms__postFilter	;Yes -- return then
		LDR	R0,tms__current		;Get the current menu
55		CMP	R0,#0			;Is there one?
		BEQ	%60tms__postFilter	;No -- close transient then
		LDR	R1,[R0,#hHandle]	;Get the window handle
		CMP	R1,R2			;Are they the same
		LDMEQFD	R13!,{R0-R3,PC}^	;Yes -- return
		LDR	R0,[R0,#hSubMenu]	;Get the submenu pointer
		CMP	R0,R3			;Is it the dbox?
		BNE	%55tms__postFilter	;No -- check the submenus

		; --- Close the transient menu then ---

60		LDR	R2,tms__current		;Point to the transient
		CMP	R2,#0			;Is there one?
		LDREQ	R2,tms__currDbox	;No -- load dbox handle
		MOV	R0,R10			;Remember R10 value
		MOV	R10,#0			;We're not over any menu
		BL	tms__closeMenu		;Close the menu
		MOV	R10,R0			;Get R10 value back
70		LDMFD	R13!,{R0-R3,PC}^	;And return to caller

		LTORG

;----- Initialisation -------------------------------------------------------

; --- tms_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the tms (Tearoff Menu System) unit.

		EXPORT	tms_init
tms_init	ROUT

		STMFD	R13!,{R0-R2,R12,R14}	;Stack some registers
		LDR	R12,=tms__wSpace	;Locate my workspace pointer
		WSPACE	[R12]			;And then my workspace

		; --- Return if we are initialised ---

		LDR	R1,tms__flags		;Get the flags word
		TST	R1,#tFlag__inited	;Are we initialised
		LDMNEFD	R13!,{R0-R2,R12,PC}^	;Yes -- return

		; --- Initialise various systems ---

		BL	win_init		;Initialise win
		BL	wimp_init		;And wimp
		BL	heap_init		;And heap

		; --- Set up the workspace values ---

		ORR	R1,R1,#tFlag__inited	;We are initialised now
		BL	wimp_version		;What wimp version is this

		CMP	R0,#300			;RISC OS 3?
		ORRGE	R1,R1,#tFlag__riscos3	;Yes -- remember this fact
		STR	R1,tms__flags		;Store the flags back

		MOV	R0,#8			;Read current wimp font
		SWI	XWimp_ReadSysInfo	;Read it if possible
		MOVVS	R0,#0			;If error -- no font
		STR	R0,tms__fHandle		;Store the handle away
		ADR	R0,tms__zInit		;Point to the correct block
		MOV	R1,#tms__zSize		;Get the size of the area
		MOV	R2,#0			;Fill with zeros
		BL	mem_set			;And do it *very* quickly

		STR	R11,tms__R11		;Save scratchpad address

		; --- Set up the filters ---

		ADR	R0,tms__preFilter	;Point to the routine
		MOV	R1,R12			;Use this R12 value
		BL	event_preFilter		;Add the filter

		ADR	R0,tms__postFilter	;Point to the routine
		MOV	R1,R12			;Use this R12 value
		BL	event_postFilter	;Add the filter

		; --- Set up the global area, and install hook ---

		LDR	R0,tms__TWIN		;Load the global area name
		MOV	R1,#twin_size		;Get the required size
		BL	sapphire_global		;Find its address
		STR	R0,tms__twin		;And store in my workspace
		MOVCC	R1,#0			;Clear the values out...
		MOVCC	R14,#0			;...if not already done
		STMCCIA	R0,{R1,R14}		;Store the zeroes in there
		ADR	R14,tms__hookTbl	;Point to the hook table
		STR	R14,[R0,#twin_tmsHook]	;Save in the hook entry

		; --- Initialise tearSupt ---

		BL	tearSupport_init	;Initialise it

		; --- And return to the user ---

		LDMFD	R13!,{R0-R2,R12,PC}^	;Return to caller

tms__TWIN	DCB	"TWIN"

tms__hookTbl	B	tmsh__subWaiting
		B	tmsh__openSub

		LTORG

;----- That's all, folks ----------------------------------------------------

		END
