;
; tmsCreate.s
;
; Creation, recreation and destruction of tearoff menus (TMA)
;
;  1994 Straylight
;

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

		GET	libs:header
		GET	libs:swis

		GET	libs:stream

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

		GET	sapphire:alloc
		GET	sapphire:heap
		GET	sapphire:keyString
		GET	sapphire:msgs
		GET	sapphire:resspr
		GET	sapphire:sapphire
		GET	sapphire:string
		GET	sapphire:wimp
		GET	sapphire:win
		GET	sapphire:winUtils

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

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- tms__bitSpec ---
;
; On entry:	R5 == pointer to base pointer (R10 or R12) for this item
;		R9 == pointer to bit specification to work out
;
; On exit:	R9 has had 4 added to it
;		C set or clear according to settedness of the bit
;
; Use:		Tells you whether a bit specification points at a bit which
;		is set or clear by copying it to the carry flag

tms__bitSpec	ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		LDR	R0,[R9],#4		;Load the specification
		MOV	R14,R0,LSR #5		;Get the offset value
		LDR	R14,[R5,R14]		;Load the flags word out
		AND	R0,R0,#31		;Leave only bit spec bits
		ADD	R0,R0,#1		;To make it nice for shifting
		MOVS	R14,R14,LSR R0		;Copy bit to carry flag
		LDMFD	R13!,{R0,R14}		;Load registers again
		ORRCSS	PC,R14,#C_flag		;Set C if C set
		BICCCS	PC,R14,#C_flag		;Clear C if C clear

		LTORG

; --- tms__findBase ---
;
; On entry:	R2,R3 == R10 and R12 values to pass to event handler
;		R8 == flags word from packed definition
;
; On exit:	R5 == correct base register for this item

tms__findBase	ROUT

		TST	R8,#mFlag_R12		;Is the R12 flag on?
		MOVNE	R5,R3			;Yes -- return R12 value
		MOVEQ	R5,R2			;No -- return R10 value
		MOVS	PC,R14			;Return to caller

		LTORG

; --- tms__checksum ---
;
; On entry:	R2 == pointer to a name
;
; On exit:	R0 == checksum value
;
; Use:		Calculates a checksum value for the given name

tms__checksum	ROUT

		STMFD	R13!,{R2,R14}		;Stack some registers
		MVN	R0,#0			;Start with -1
00		LDRB	R14,[R2],#1		;Load a byte
		CMP	R14,#' '		;Are we at the end?
		EORCS	R0,R14,R0,LSL #2	;Add it on to the sum
		BCS	%00tms__checksum	;No -- keep going then
		LDMFD	R13!,{R2,PC}^		;Return to caller

; --- tms__createTitle ---
;
; On entry:	R9 == pointer to packed title definition
;
; On exit:	R9 == pointer to packed item description
;		R10 == pointer to header structure, filled in and glorious
;		R0, R4-R8 corrupted
;
; Use:		Builds a menu header block

tms__createTitle ROUT

		BIC	R14,R14,#V_flag		;Assume nothing can harm us
		STMFD	R13!,{R14}		;Save link register

		MOV	R0,#hSize		;Get the size we want
		BL	heap_alloc		;Allocate a block for it
		BLCS	alloc_error		;If no memory, get error msg
		LDMVSFD	R13!,{PC}		;And return with V still set
		MOV	R10,R0			;Keep this pointer safe
		STR	R10,tms__creating	;Store this pointer nicely
		STR	R9,[R10,#hDefinition]	;Store pack defn pointer
		MOV	R0,#0			;Also want to zero item blk
		STR	R0,tms__lastItems	;No item blocks created yet
		STR	R0,[R10,#hItems]	;No items attached yet
		STR	R0,[R10,#hKeyWidth]	;No shortcuts found yet
		STR	R0,[R10,#hTextWidth]	;No items yet
		STR	R0,[R10,#hSprWidth]	;No sprites yet
		STR	R0,[R10,#hHandle]	;No window attached yet
		STR	R0,[R10,#hNextTorn]	;Not in torn list
		STR	R0,[R10,#hDbox]		;No dialogue box yet
		STR	R0,[R10,#hFromItem]	;We're not from an item

		MOV	R6,#0			;No flags defined yet

		LDR	R8,[R9],#4		;Load the flags word out
		BL	tms__findBase		;Get the correct base pointer
		TST	R8,#mFlag_indirect	;Is this item indirected?
		BEQ	%00tms__createTitle	;No -- jump on then
		STMFD	R13!,{R1}		;Save a register nicely
		LDR	R1,[R9],#4		;Yes -- find offset nicely
		LDR	R0,[R9],#4		;...and the buffer size
		LDR	R1,[R5,R1]		;...get the pointer out

		BL	heap_alloc		;Allocate some memory
		BLCS	alloc_error		;Get the error message
		MOVCS	R0,R10			;...point to the block
		BLCS	heap_free		;...free the memory
		LDMCSFD	R13!,{R1,PC}		;...and return

		STR	R0,[R10,#hText]		;Store the text pointer
		BL	str_cpy			;Copy the string into buffer
		MOV	R0,R1			;Put the string in R0
		LDMFD	R13!,{R1}		;And restore R1 saved above
		ORR	R6,R6,#hFlag__tIndir	;Title is indirected
		BNE	%10tms__createTitle	;Skip past this next bit

00		MOV	R0,R9			;Point to the message tag
		BL	msgs_lookup		;Translate the message
05		LDRB	R14,[R9],#1		;Get a message string byte
		CMP	R14,#' '		;Is it a terminator?
		BGE	%05tms__createTitle	;No -- get another one
		ADD	R9,R9,#3		;Add 3
		BIC	R9,R9,#3		;And word align the pointer
		STR	R0,[R10,#hText]		;Store the text pointer

		; --- Store the string and get its length ---

10		BL	wimp_strWidth		;Get the string's width
		ADD	R0,R0,#32
		STR	R0,[R10,#hTitleWidth]	;Store as title width

		; --- Now handle other bits of the flags ---

		TST	R8,#mFlag_tearoff	;Are we tearable?
		ORRNE	R6,R6,#hFlag__tearable	;Yes -- set the bit nicely
		TST	R8,#mFlag_global	;Is menu `global'?
		ORRNE	R6,R6,#hFlag__global	;Yes -- set the bit nicely
		STR	R6,[R10,#hFlags]	;Store the flags word
		
		; --- Now check for maximum height ---

		TST	R8,#mFlag_maxHeight	;Is there a maximum height?
		LDRNE	R0,[R9],#4		;Yes -- read it out then
		MOVEQ	R0,#0			;No -- zero is a silly value
		STR	R0,[R10,#hMaxHeight]	;Store in the right place

		; --- Perform any other business ---

		ADD	R0,R10,#hHandler	;Point to the handler bitty
		STMIA	R0,{R1-R3}		;Store the 'handlers' away

90		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- tms_create ---
;
; On entry:	R0 == pointer to a menu block
;		R1 == pointer to event handler for the menu section
;		R2 == R10 value to pass to the event handler
;		R3 == R12 value to pass to the event handler
;
; On exit:	R0 == tearoff handle for this menu
;		May return an error
;
; Use:		Creates a new menu, or adds sections to an existing one.

		EXPORT	tms_create
tms_create	ROUT

		BIC	R14,R14,#V_flag		;Hope there's no error
		STMFD	R13!,{R1-R10,R12,R14}	;Save some registers away
		LDR	R12,=tms__wSpace	;Find my workspace pointer
		WSPACE	[R12]			;And then my workspace
		MOV	R9,R0			;Keep pointer to definition

		; --- Get the menu header we're working on ---

		LDR	R10,tms__creating	;Get the menu header pointer
		CMP	R10,#0			;Is it actually defined?
		BLEQ	tms__createTitle	;No -- go away and create it
		BVS	%99tms_create		;It failed -- return an error

		; --- Update ---
		;
		; OK, the pointer to the first packed item is in R9, and
		; R10 contains a pointer to a menu header.

		LDR	R8,[R9],#4		;Load the item flags word
		TST	R8,#mFlag_end		;Is there only a title?
		MOVNE	R0,R10			;Yes -- return the handle
		LDMNEFD	R13!,{R1-R10,R12,PC}^	;Return to caller nicely

		; --- Now we need to scan through to count the items ---

		MOV	R7,R9			;Current ptr in packed defn
		MOV	R0,#iHdrSize		;Count the fixed-size header
		MOV	R4,#0			;Number of items I've found

00tms_create	TST	R8,#mFlag_indirect	;Is this item indirected?
		ADDNE	R7,R7,#4		;Yes -- skip the offset word
		BNE	%02tms_create		;And skip past the loop

		; --- Skip inline text string ---

01tms_create	LDRB	R14,[R7],#1		;Get a message string byte
		CMP	R14,#' '		;Is it a terminator?
		BGE	%01tms_create		;No -- get another one
		ADD	R7,R7,#3		;Add 3
		BIC	R7,R7,#3		;And word align the pointer

		; --- Now skip other optional blocks ---

02tms_create	TST	R8,#mFlag_shortcut	;Is ther a normal...
		TSTEQ	R8,#mFlag_iShortcut	;...or indirected shortcut?
		ADDNE	R7,R7,#4		;Yes -- skip over it then
		SKPITEM	R8,R7			;Skip past another item
		ADD	R0,R0,#iItemSize	;Add on size for another item
		ADD	R4,R4,#1		;And bump my counter too
		LDR	R8,[R7],#4		;Load the next flags word
		TST	R8,#mFlag_end		;Is this the end yet?
		BEQ	%00tms_create		;Yes -- continue with the fun

		; --- R0 now contains how much we want ---

		BL	heap_alloc		;Allocate the memory now
		BLCS	alloc_error		;If it failed, find an error
		BVS	%99tms_create		;And return it nicely

		; --- Mangle all the list stuff ---

		MOV	R7,R0			;Keep the pointer safely
		LDR	R6,tms__lastItems	;Get the last item block
		CMP	R6,#0			;Is there one defined?
		STRNE	R7,[R6,#iItems]		;Yes -- store in next field
		STREQ	R7,[R10,#hItems]	;No -- store as list head
		STR	R7,tms__lastItems	;This is the new last blk
		MOV	R0,#0			;Want to terminate the list
		STR	R0,[R7,#iItems]		;Store it in the next field
		STR	R0,[R7,#iDbox]		;No dialogue box yet

		; --- Build the item block header ---

		STR	R4,[R7,#iNumber]	;Store item counter
		SUB	R0,R9,#4		;Point to definition start
		STR	R0,[R7,#iDefinition]	;Store in the pointer field
		ADD	R0,R7,#iHandler		;Point to the handler words
		STMIA	R0,{R1-R3}		;Store handler information

		; --- Now we actually want to build the block ---

		LDR	R8,[R9,#-4]		;Load the initial flags again
		ADD	R7,R7,#iHdrSize		;Skip past header part

10tms_create	MOV	R0,#-1			;Get a NULL word
		STR	R0,[R7,#iKeyCode]	;No shortcut yet
		BL	tms__findBase		;Find base workspace register
		TST	R8,#mFlag_indirect	;Is this item indirected?
		LDRNE	R0,[R9],#4		;Yes -- find offset nicely
		LDRNE	R0,[R5,R0]		;And get the pointer out
		BNE	%12tms_create		;Skip past this next bit

		MOV	R0,R9			;Point to the message tag
		BL	msgs_lookup		;Translate the message
11tms_create	LDRB	R14,[R9],#1		;Get a message string byte
		CMP	R14,#' '		;Is it a terminator?
		BGE	%11tms_create		;No -- get another one
		ADD	R9,R9,#3		;Add 2 (we added one in LDRB)
		BIC	R9,R9,#3		;And word align the pointer

		; --- Store the pointer and carry on ---

12tms_create	STR	R0,[R7,#iText]		;Store the text pointer
		BL	wimp_strWidth		;Find the item width
		LDR	R14,[R10,#hTextWidth]	;Load previous text width
		CMP	R0,R14			;Is this bigger?
		STRGT	R0,[R10,#hTextWidth]	;Yes -- store it over

		TST	R8,#mFlag_shortcut	;Is there a menu short cut?
		TSTEQ	R8,#mFlag_iShortcut	;Or an indirected one?
		BEQ	%15tms_create		;No -- jump ahead
		TST	R8,#mFlag_shortcut	;Is there a menu short cut?
		LDRNE	R0,[R9],#4		;Yes -- load out key code
		LDREQ	R0,[R9],#4		;No -- Load offset of code
		LDREQ	R0,[R5,R0]		;...load out key code
		STR	R0,[R7,#iKeyCode]	;Store the key code
		MOV	R1,#1			;Return short version
		BL	keyString		;Find correct string
		BL	wimp_strWidth		;Get the string width
		ADD	R0,R0,#16		;Put a gap on each side
		LDR	R1,[R10,#hKeyWidth]	;Get longest one so far
		CMP	R0,R1			;Is this on longer?
		STRGT	R0,[R10,#hKeyWidth]	;Yes -- store it then

		; --- Severe cleverness warning ---
		;
		; The TST instructions clear Z iff the appropriate bit is
		; on.  tms__bitSpec sets C iff the appropriate bit read from
		; a bit spec is on.  We can actually combine testing for
		; (C && !Z) with the HI condition code.  This saves jumping
		; around a lot.

15tms_create	MOV	R6,#0			;Current flags word

		TST	R8,#mFlag_shade		;Check shadedness bit
		BLNE	tms__bitSpec		;Handle the bit specification
		ORRHI	R6,R6,#iFlag__shaded	;If set, shade the item
		BHI	%13tms_create		;...and jump this next bit

		TST	R8,#mFlag_iShade	;Check shadedness bit
		BLNE	tms__bitSpec		;Handle the bit specification
		ORRNE	R6,R6,#iFlag__shaded	;Set shaded bit anyway
		BICHI	R6,R6,#iFlag__shaded	;Bit clear it again if set!

13tms_create	TST	R8,#mFlag_switch	;Check switchiness bit
		BLNE	tms__bitSpec		;Handle the bit specification
		ORRHI	R6,R6,#iFlag__ticked	;If set, tick it

		TST	R8,#mFlag_radio		;Check radioness bit
		BEQ	%14tms_create		;If not set, skip ahead
		LDMIA	R9!,{R0,R1}		;Load the information out
		LDR	R0,[R5,R0]		;Load the radio specifier
		CMP	R0,R1			;Is this a match made in hvn?
		ORREQ	R6,R6,#iFlag__radio	;Yes -- attach the splodge

		; --- Deal with sprites ---

14tms_create	TST	R8,#mFlag_sprite	;Is there a sprite?
		BEQ	%20tms_create		;No -- jump ahead
		STMFD	R13!,{R2-R6}		;SpriteOp corrupts all these!
		LDMIA	R9!,{R0,R1}		;Load the information out
		LDR	R2,[R5,R0]		;Load the actual sprit addr
		STR	R2,[R7,#iSprName]	;Save the name value
		BL	tms__checksum		;Get the checksum
		STR	R0,[R7,#iSprCsum]	;And store it away
		MOVS	R0,R1			;Get the sprite area
		BLMI	resspr_area		;Negative -- get app's one
		MOV	R1,R0			;Put sprite area in R1 again
		STR	R1,[R7,#iSprArea]	;Save the sprite area
		ORR	R6,R6,#iFlag__sprite	;The item has a sprite
		TST	R8,#mFlag_halfSize	;Should we display at half sz
		ORRNE	R6,R6,#iFlag__halfSize	;Yes -- remember this
		STR	R6,[R13,#16]		;Save this for later

		; --- Find the width of the sprite ---

		CMP	R1,#1			;Are we using WIMP area?
		MOVNE	R0,#256+40		;No -- on user area name
		SWINE	OS_SpriteOp		;...get information
		MOVEQ	R0,#40			;Yes -- info please
		SWIEQ	Wimp_SpriteOp		;Get it then
		MOV	R0,R6			;Get the sprite's mode
		MOV	R1,#4			;Get the XEig factor
		SWI 	OS_ReadModeVariable	;Read the value
		MOV	R3,R3,LSL R2		;Work out the width in OS
		LDR	R0,[R10,#hSprWidth]	;Load current sprite width
		TST	R8,#mFlag_halfSize	;Should we display at half sz
		MOVNE	R3,R3,LSR #1		;Yes -- then divide by 2
		ADD	R3,R3,#16		;Add on a little clearance
		CMP	R3,R0			;Is this bigger than that?
		STRGT	R3,[R10,#hSprWidth]	;Yes -- then overwrite
		LDMFD	R13!,{R2-R6}		;Restore those registers

20tms_create	TST	R8,#mFlag_ruleOff	;Is there a ruleoff here
		ORRNE	R6,R6,#iFlag__dotted	;Yes -- add a dotted line
		TST	R8,#mFlag_subWarn+mFlag_subMenu ;Arrow wanted?
		ORRNE	R6,R6,#iFlag__arrow	;Yes -- add the arrow

		SKIP	mFlag_subMenu,8,R8,R9	;Skip submenu bit nicely

		TST	R8,#mFlag_noWarn	;Do we warn on shaded items?
		ORRNE	R6,R6,#iFlag__noWarn	;No -- remember this

		STR	R6,[R7,#iFlags]		;Store the sussed out flags
		MOV	R6,#0			;A NULL pointer
		STR	R6,[R7,#iSubMenu]	;No sub menu from here
		ADD	R7,R7,#iItemSize	;Point at the next item

		; --- Get the next flags word and loop ---

		LDR	R8,[R9],#4		;Get the next flags word
		TST	R8,#mFlag_end		;Is this an end marker?
		BEQ	%10tms_create		;No -- do the next one

		; --- Return interesting things to caller ---

		MOV	R0,R10			;Give caller my header block
		LDMFD	R13!,{R1-R10,R12,PC}^	;Return to caller nicely

99tms_create	ADD	R2,R0,#4		;Point to the message
		MOVS	R0,R10			;Point to menu header
		BLNE	tms__destroy		;Destroy it if it exists
		ADR	R0,tms__noCreate	;Point to error skeleton
		BL	msgs_error		;Translate the error
		LDMFD	R13!,{R1-R10,R12,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return with the error

		LTORG

tms__noCreate	DCD	1
		DCB	"tmsCCTM:TMS cannot create menu: %s",0

; --- tms__destroy ---
;
; On entry:	R0 == handle of tearoff menu to destroy
;
; On exit:	--
;
; Use:		Zaps a tearoff menu entirely, leaving no survivors

		EXPORT	tms__destroy
tms__destroy	ROUT

		STMFD	R13!,{R0-R4,R14}	;Stack some registers
		MOV	R4,R0			;Preserve menu pointer

		; --- Delete the window, and remove its handler ---

		ADD	R1,R0,#hHandle		;Point to the handle
		SWI	Wimp_CloseWindow	;Close the window
		SWI	Wimp_DeleteWindow	;Then delete it
		LDR	R0,[R4,#hHandle]	;The window handle
		LDR	R1,=tms__eventHandler	;Point to the handler
		MOV	R2,R4			;The handle passed
		MOV	R3,R12			;Workspace passed in R3
		BL	win_removeEventHandler	;Remove the event handler
		LDR	R0,[R4,#hFlags]		;Load the header flags
		TST	R0,#hFlag__tIndir	;Is title indirected?
		LDRNE	R0,[R4,#hText]		;Yes -- load buffer pointer
		BLNE	heap_free		;And free it nicely
		LDR	R1,[R4,#hItems]		;Get the items pointer
		MOV	R0,R4			;Point back to the block
		BL	heap_free		;Free the block

00tms__destroy	MOVS	R0,R1			;Point R0 at the block
		LDMEQFD	R13!,{R0-R4,PC}^	;Return PDQ
		LDR	R1,[R0,#iItems]		;Get the next items pointer
		BL	heap_free		;Free the block
		B	%00tms__destroy		;Keep destorying blocks

		LTORG

; --- tms__width ---
;
; On entry:	R10 == pointer to the menu
;
; On exit:	CS if the width has changed, CC otherwise
;
; Use:		Calculates what the appropriate width fields of the given
;		menu should be.

		EXPORT	tms__width
tms__width	ROUT

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

		MOV	R4,#0			;No sprite width
		MOV	R5,#0			;No text width
		MOV	R6,#0			;No shortcut width
		LDR	R7,[R10,#hTotWidth]	;Get the current width

		LDR	R2,[R10,#hItems]	;Point to the first items
05tms__width	LDR	R3,[R2,#iNumber]	;Load the number of items
		ADD	R8,R2,#iHdrSize		;Point to first item

		; --- Calculate string width ---

10tms__width	LDR	R0,[R8,#iText]		;Load the text pointer
		BL	wimp_strWidth		;Get the strings length
		CMP	R0,R5			;Is it greater?
		MOVGT	R5,R0			;Yes -- remember this then

		; --- Now the shortcut width ---

		LDR	R0,[R8,#iKeyCode]	;Load the key code
		CMP	R0,#-1			;Is there one?
		BEQ	%12tms__width		;No -- jump ahead
		MOV	R1,#1			;Return short version
		BL	keyString		;Find correct string
		BL	wimp_strWidth		;Get the string width
		ADD	R0,R0,#16		;Put a gap on each side
		CMP	R0,R6			;Is this on longer?
		MOVGT	R6,R0			;Yes -- remember that fact

		; --- Finally the sprite width ---

12tms__width	STMFD	R13!,{R2-R6}		;Save some registers
		LDR	R14,[R8,#iFlags]	;Get the flags word
		TST	R14,#iFlag__sprite	;Is there a sprite here?
		LDMEQFD	R13!,{R2-R6}		;No -- restore registers
		BEQ	%15tms__width		;...jump ahead a little
		LDR	R1,[R8,#iSprArea]	;Get the sprite area
		LDR	R2,[R8,#iSprName]	;And the sprite name
		CMP	R1,#1			;Are we using WIMP area?
		MOVNE	R0,#256+40		;No -- on user area name
		SWINE	OS_SpriteOp		;...get information
		MOVEQ	R0,#40			;Yes -- info please
		SWIEQ	Wimp_SpriteOp		;Get it then
		MOV	R0,R6			;Get the sprite's mode
		MOV	R1,#4			;Get the XEig factor
		SWI 	OS_ReadModeVariable	;Read the value
		MOV	R3,R3,LSL R2		;Work out the width in OS
		TST	R14,#iFlag__halfSize	;Should we display at half sz
		MOVNE	R3,R3,LSR #1		;Yes -- then divide by 2
		ADD	R3,R3,#16		;Add on a little clearance
		MOV	R14,R3			;Remember this width
		LDMFD	R13!,{R2-R6}		;Restore those registers
		CMP	R14,R4			;Is this bigger than that?
		MOVGT	R4,R14			;Yes -- use this value then

		; --- Now do other items ---

15tms__width	ADD	R8,R8,#iItemSize	;Point to the next item
		SUBS	R3,R3,#1		;Decrement item count
		BGT	%10tms__width		;More to go -- do them

		LDR	R2,[R2,#iItems]		;Load the next items
		CMP	R2,#0			;Are there any more?
		BNE	%05tms__width		;Yes -- look at them then

		STR	R4,[R10,#hSprWidth]	;Store the sprite width
		STR	R5,[R10,#hTextWidth]	;Store the text width
		STR	R6,[R10,#hKeyWidth]	;And shortcut width too

		ADD	R4,R4,R5		;Add them all together
		ADD	R4,R4,R6		;...
		ADD	R4,R4,#64		;Left and right + 16

		LDR	R0,[R10,#hText]		;Load the title pointer
		BL	wimp_strWidth		;Find the string width
		ADD	R0,R0,#32		;Add on some clearance
		STR	R0,[R10,#hTitleWidth]	;Store the title width
		CMP	R0,R4			;Is this longer than rest?
		MOVGT	R4,R0			;Yes -- use this width

		STR	R4,[R10,#hTotWidth]	;Store new total width

		CMP	R4,R7			;Has the width changed?
		BEQ	%95tms__width		;No -- return

		; --- Change the extent of the window ---

		LDR	R14,[R10,#hHandle]	;Get the window handle
		STR	R14,[R13,#-36]!		;Get me a block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetWindowState	;Get the window state

		SUB	R13,R13,#16		;Get another block
		MOV	R2,#0			;Minimum x extent
		LDR	R3,[R10,#hHeight]	;Get the window height
		RSB	R3,R3,#0		;Minimun y extent
		MOV	R5,#0			;Maximum y extent
		STMIA	R13,{R2-R5}		;Store these in the block
		MOV	R0,R14			;Get the window handle in R0
		MOV	R1,R13			;Point to the block
		SWI	Wimp_SetExtent		;Set the extent

		ADD	R13,R13,#16		;Get the first block back
		LDR	R0,[R13,#4]		;Get visible x0
		ADD	R0,R0,R4		;Calculate x1
		STR	R0,[R13,#12]		;Store the maximum x extent
		MOV	R1,R13			;Point to the block
		SWI	Wimp_OpenWindow		;Open the window

		ADD	R13,R13,#36		;Reclaim the stack

		; --- Force a complete redraw ---
		;
		; It's a shame, but there's nothing else for it.

		LDR	R0,[R10,#hHandle]	;Load the window handle
		MOV	R1,#0			;Left hand side of window
		LDR	R2,[R10,#hHeight]	;Load the window height
		RSB	R2,R2,#0		;Make it nicely negative
		LDR	R3,[R10,#hTotWidth]	;Load the window width
		MOV	R4,#0			;And the top of the window
		SWI	Wimp_ForceRedraw	;Aarggh boo spit spit

90tms__width	LDMFD	R13!,{R0-R8,R14}	;Get registers back
		ORRS	PC,R14,#C_flag		;Return with carry set

95tms__width	LDMFD	R13!,{R0-R8,R14}	;Get registers back
		BICS	PC,R14,#C_flag		;Return with carry clear

		LTORG

; --- tms__check ---
;
; On entry:	R0 == pointer to menu to check
;		R12 == pointer to global tms workspace
;
; On exit:	--
;
; Use:		Checks to see if the given menu needs to be changed, and
;		updates it as appropriate if it does.

tms__check	ROUT

		STMFD	R13!,{R0-R10,R14}	;Stack lots of registers

		STR	R0,tms__recreating	;Store a pointer to this menu
		LDR	R9,[R0,#hDefinition]	;Point to packed header defn
		MOV	R7,R0			;Put structure in R7
		LDR	R8,[R9],#4		;Load the title flags word
		LDR	R2,[R7,#hR10]		;Load R10 value
		LDR	R3,[R7,#hR12]		;And R12 value
		BL	tms__findBase		;Put base in R5
		TST	R8,#mFlag_indirect	;Is the text indirected?
		BEQ	%02tms__check		;No -- just skip over string
		LDR	R0,[R9],#4		;Yes -- find offset
		LDR	R1,[R9],#4		;And buffer length
		LDR	R0,[R5,R0]		;And point to the string

		; --- Compare to find a difference ---

		LDR	R1,[R7,#hText]		;Point to current text string
		BL	str_cmp			;Compare the strings
		LDRNE	R2,[R7,#hHandle]	;Load the window handle
		BLNE	winUtils_setTitle	;And set the title
		B	%05tms__check		;Jump ahead

		; --- Skip over embedded title string ---

02tms__check	LDRB	R14,[R9],#1		;Get a message string byte
		CMP	R14,#' '		;Is it a terminator?
		BGE	%02tms__check		;No -- get another one
		ADD	R9,R9,#3		;Add 3
		BIC	R9,R9,#3		;And word align the pointer

		; --- Now check the items ---

05tms__check	LDR	R6,[R7,#hItems]		;Point to first items
06tms__check	LDR	R2,[R6,#iR10]		;Load R10 value
		LDR	R3,[R6,#iR12]		;And R12 value

		LDR	R9,[R6,#iDefinition]	;Point to packed items defn
		ADD	R7,R6,#iHdrSize		;Point to first item
		LDR	R8,[R9],#4		;Load the flags word
07tms__check	BL	tms__findBase		;Get base in R5
		LDR	R10,[R7,#iFlags]	;Get the existing flags
		BIC	R10,R10,#&FF000000	;Clear redraw flags
		STR	R10,[R7,#iFlags]	;Store them back

		; --- First, compare the text strings ---

		TST	R8,#mFlag_indirect	;Is text indirected?
		BEQ	%10tms__check		;No -- just skip over string
		LDR	R0,[R9],#4		;Yes -- find offset
		LDR	R0,[R5,R0]		;And point to the string

		; --- Compare to find a difference ---

		LDR	R1,[R7,#iText]		;Point to current text string
		BL	str_cmp			;Compare the strings
		ORRNE	R10,R10,#iFlag__newText	;If different, remember it
		STRNE	R0,[R7,#iText]		;And store new text ptr
		B	%11tms__check		;And jump ahead if no change

		; --- Skip over embedded item string ---

10tms__check	LDRB	R14,[R9],#1		;Get a message string byte
		CMP	R14,#' '		;Is it a terminator?
		BGE	%10tms__check		;No -- get another one
		ADD	R9,R9,#3		;Add 3
		BIC	R9,R9,#3		;And word align the pointer

		; --- The shortcut may have changed ---

11tms__check	TST	R8,#mFlag_iShortcut	;Is there a indir. shortcut?
		BEQ	%12tms__check		;No -- skip ahead

		LDR	R0,[R9]			;Get the value
		LDR	R0,[R5,R0]		;Load out the key code
		LDR	R14,[R7,#iKeyCode]	;Load current key code
		CMP	R14,R0			;Has it changed?
		STRNE	R0,[R7,#iKeyCode]	;Yes -- store this value
		ORRNE	R10,R10,#iFlag__newKey	;...queue for redrawing

		; --- Now collect the item flags ---

12tms__check	TST	R8,#mFlag_shortcut	;Is there a shortcut?
		TSTEQ	R8,#mFlag_iShortcut	;Of any kind?
		ADDNE	R9,R9,#4		;Yes -- skip over it

		MOV	R4,#0			;No flags set yet

		TST	R8,#mFlag_shade		;Check shadedness bit
		BLNE	tms__bitSpec		;Handle the bit specification
		ORRHI	R4,R4,#iFlag__shaded	;If set, shade the item
		BHI	%13tms__check		;...and jump this next bit

		TST	R8,#mFlag_iShade	;Check shadedness bit
		BLNE	tms__bitSpec		;Handle the bit specification
		ORRNE	R4,R4,#iFlag__shaded	;Set shaded bit anyway
		BICHI	R4,R4,#iFlag__shaded	;Bit clear it again if set!

13tms__check	TST	R8,#mFlag_switch	;Check switchiness bit
		BLNE	tms__bitSpec		;Handle the bit specification
		ORRHI	R4,R4,#iFlag__ticked	;If set, tick it

		TST	R8,#mFlag_radio		;Check radioness bit
		BEQ	%14tms__check		;If not set, skip ahead
		LDMIA	R9!,{R0,R1}		;Load the information out
		LDR	R0,[R5,R0]		;Load the radio specifier
		CMP	R0,R1			;Is this a match made in hvn?
		ORREQ	R4,R4,#iFlag__radio	;Yes -- attach the splodge

		; --- Now check the sprite ---

14tms__check	TST	R8,#mFlag_sprite	;Is there a sprite here?
		BEQ	%15tms__check		;No skipitty jump aaawhooo
		STMFD	R13!,{R2}		;Don't corrupt R2
		LDR	R2,[R9],#4		;Yes -- load out name ptr ptr
		LDR	R2,[R5,R2]		;And get name ptr
		BL	tms__checksum		;Get the checksum
		LDR	R1,[R7,#iSprCsum]	;Load the current checksum
		CMP	R0,R1			;Has it changed?
		STRNE	R0,[R7,#iSprCsum]	;Yes -- store the new one
		STRNE	R2,[R7,#iSprName]	;...and the new name
		ORRNE	R10,R10,#iFlag__newSpr	;...and queue for redraw
		ADD	R9,R9,#4		;Skip over sprite area
		LDMFD	R13!,{R2}		;Return to caller

15tms__check
		SKIP	mFlag_subMenu,8,R8,R9	;Skip submenu bit nicely

		; --- Have the flags changed? ---

		LDR	R14,[R7,#iFlags]	;Get the current item flags
		AND	R0,R14,#7		;Clear unwanted flags
		CMP	R0,R4			;Have flags changed?

		BIC	R14,R14,#7		;Clear relevant flags
		ORR	R14,R14,R4		;Set new flags up
		MOV	R1,R14			;And remember them

		; --- Update text part ---

		EOR	R14,R0,R4		;Get flags which have changed

		TST	R14,#iFlag__shaded	;Has shaded state changed?
		ORRNE	R10,R10,#&FF000000	;Yes -- redraw the whole item
		TST	R14,#iFlag__ticked+iFlag__radio	;Need to redraw left?
		ORRNE	R10,R10,#iFlag__newTick	;Yes -- then queue an update
		BIC	R10,R10,#7		;Clear these flags
		BIC	R1,R1,#&FF000000	;Clear old update flags
		ORR	R1,R1,R10		;Add in update bits
		STR	R1,[R7,#iFlags]		;Store the new flags

		; --- Check following items ---

20tms__check	ADD	R7,R7,#iItemSize	;Point at the next item
		LDR	R8,[R9],#4		;Load the next flags word
		TST	R8,#mFlag_end		;Have we reached the end?
		BEQ	%07tms__check		;No -- keep check these items

		LDR	R6,[R6,#iItems]		;Point to next group of items
		CMP	R6,#0			;Are there any more?
		BNE	%06tms__check		;Yes -- check them then

		; --- Maybe change menu width ---

		LDR	R10,tms__recreating	;Get the menu ptr
		BL	tms__width		;Recalculate the menu width
		BCS	%90tms__check		;If it redrew it, skip on

		; --- Now redraw items we queued above ---

		MOV	R0,#0			;Only redraw queued bits
		BL	tms__update		;And update the window
90tms__check	LDMFD	R13!,{R0-R10,PC}^	;Return to caller

		LTORG

; --- tms_recreate ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Recreates the existing menu structure, making changes where
;		appropriate.

		EXPORT	tms_recreate
tms_recreate	ROUT

		; --- A note to the wise ---
		;
		; We go through the data for every open tearoff menu, and
		; make any changes that are necessary. These include:
		;
		;   Making the menu wider or narrower, if necessary
		;   Changing textual strings where they are now different
		;   Adding or removing of ticks and blobs
		;   Shading or unshading of items

		STMFD	R13!,{R0,R14}		;Stack some registers
		LDR	R12,=tms__wSpace	;Point to workspace pointer
		WSPACE	[R12]			;Load out workspace pointer

		LDR	R0,tms__current		;Load the current menu ptr
		CMP	R0,#0			;Is there one open?
		BEQ	%10tms_recreate		;No -- look at torn ones
00tms_recreate	BL	tms__check		;Check the menu, make changes
		LDR	R0,[R0,#hSubMenu]	;Get submenu pointer
		CMP	R0,#0			;Is there one?
		BNE	%00tms_recreate		;Yes -- check it then

		; --- Now check the torn off menus ---

10tms_recreate	LDR	R0,tms__tornoffs	;Get first torn off menu
		CMP	R0,#0			;Have we finished yet?
		BEQ	%90tms_recreate		;Yes -- return then
15tms_recreate	BL	tms__check		;Check the menu, make changes
		LDR	R0,[R0,#hNextTorn]	;Get the next torn menu
		CMP	R0,#0			;Have we finished yet?
		BNE	%15tms_recreate		;No -- keep going then

90tms_recreate	LDMFD	R13!,{R0,PC}^		;Return to caller

		LTORG

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

		END
