;
; menu.s
;
; RISC OS menu handling facilities (TMA)
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sapphire library.
;
; Sapphire is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; Sapphire is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Sapphire.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

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

		GET	sapphire:event
		GET	sapphire:libOpts
		GET	sapphire:sapphire
		GET	sapphire:string
		GET	sapphire:fastMove
		GET	sapphire:msgs
		GET	sapphire:help

;----- Useful values --------------------------------------------------------

mFlag_tearoff	EQU	(1<<1)			;Menu has a tearoff bar
mFlag_makeMe	EQU	(1<<2)			;Recreate menu on adjust
mFlag_maxHeight	EQU	(1<<3)			;Menu has a maximum height

mFlag_indirect	EQU	(1<<0)			;Item text is indirected
mFlag_shortcut	EQU	(1<<1)			;Item has a keyboard shortcut
mFlag_iShortcut	EQU	(1<<2)			;Item has an indirected S/C
mFlag_shade	EQU	(1<<3)			;Item is shadable
mFlag_iShade	EQU	(1<<4)			;Item is inverse shadable
mFlag_switch	EQU	(1<<5)			;Item is a switch
mFlag_radio	EQU	(1<<6)			;Item is a radio item
mFlag_sprite	EQU	(1<<7)			;Menu item has a sprite
mFlag_halfSize	EQU	(1<<8)			;Sprite is halfsize
mFlag_subWarn	EQU	(1<<9)			;Warn client if submenu warn
mFlag_subMenu	EQU	(1<<10)			;Item has menu to be opened

mFlag_R12	EQU	(1<<16)			;Use R12 for runtime data
mFlag_noWarn	EQU	(1<<17)			;Don't warn on shaded items
mFlag_ruleOff	EQU	(1<<18)			;Put a ruleoff after item
mFlag_noTrans	EQU	(1<<19)			;Don't translate messages

mFlag_end	EQU	(1<<31)			;No more items

; --- Event types ---

mEvent_select	EQU	0			;Normal menu selection
						;  R1 == index of item
mEvent_arrow	EQU	1			;Sub menu warning
						;  R1 == index of item
mEvent_deleted	EQU	2			;Menu has been deleted
mEvent_help	EQU	3			;Menu help requested
						;  R1 == ndex of item
						;  R2 == ptr to packed itmdef

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- menu__createTitle ---
;
; On entry:	R0 == pointer to menu title definition
;		R1 == event handler to use (not used here)
;		R2 == R10 value to use
;		R3 == R12 value to use
;		R4 == pointer to menu stack area
;		R5 == pointer into stack to build definition
;		R9 == workspace pointer
;
; On exit:	R0 == points to first word after table
;		R1-R4 == preserved
;		R5 == next free word in stack after defintion
;
; Use:		This call creates the title part of a WIMP menu from
;		a menu definition table (assuming that it has a menu
;		title definition).

menu__createTitle ROUT

		STMFD	R13!,{R1-R4,R6-R8,R14}	;Stack some registers

		STMDB	R4,{R0-R3}		;Store information in stack
		LDR	R7,[R0],#4		;Get flags
		MOV	R8,R2			;Use R10 for runtime data
		TST	R7,#mFlag_R12		;Should we use R12?
		MOVNE	R8,R3			;Yes, set R8 = R3 then
		TST	R7,#mFlag_indirect	;Is the title indirected
		LDRNE	R6,[R0],#4		;Yes -- load the offset
		LDRNE	R6,[R6,R8]		;...find new pointer
		BNE	%05			;...and jump the next bit

		MOV	R6,R0			;Get the text pointer
00		LDRB	R8,[R0],#1		;Get a byte
		CMP	R8,#0			;Was it the last character?
		BNE	%00			;No -- keep looking
		ADD	R0,R0,#3		;Word align
		BIC	R0,R0,#3		;Oh yes indeedy

05		MOV	R2,R0			;Remember this pointer
		MOV	R0,R6			;Point to the message
		TST	R7,#mFlag_noTrans	;Do we translate the string?
		BLEQ	msgs_lookup		;Yes -- lookup the message
		MOV	R6,R0			;Remember new pointer
		BL	str_len			;Get the length of the text
		STRGT	R0,menu__maxLen		;Yes -- store new length
		TST	R7,#mFlag_makeMe	;Is the menu recreatable?
		LDMNEIA	R2!,{R8}		;Yes -- read it
		TST	R7,#mFlag_maxHeight	;Is there a maximum height
		LDMNEIA	R2!,{R8}		;Yes -- read it

		; --- Now enter data into stack ---

		BL	menu__checkOverflow	;Make sure there's room
		MOV	R0,R5			;Copy to here...
		MOV	R1,R6			;...this string
		BL	str_cpy			;Do the copy
		ADD	R5,R5,#12		;Point past 12 bytes
		MOV	R0,R2			;Get the pointer back
		LDR	R4,=&00070207		;Colours
		MOV	R6,#40			;Don't know width yet
		MOV	R7,#44			;Item height
		MOV	R8,#0			;Gap between items
		STMIA	R5!,{R4,R6-R8}		;Store information

		; --- Return thankfully ---

		LDMFD	R13!,{R1-R4,R6-R8,PC}^

		LTORG

; --- menu_create ---
;
; On entry:	R0 == pointer to menu definition table
;		R1 == event handler to use
;		R2 == R10 value for handler
;		R3 == R12 value for handler
;
; On exit:	--
;
; Use:		Creates a menu from the given menu definition
;		table. If this call is called more than once before
;		a menu is opened then the menu definiton are concatenated
;		into a large menu. Only the first menu title read is
;		taken notice of. Notice therefore, that the call doesn't
;		actually open a menu.

		EXPORT	menu_create
menu_create	ROUT

		STMFD	R13!,{R0-R12,R14}	;Stack some registers
		WSPACE	menu__wSpace,R9		;Find my workspace

		MOV	R12,#0			;Number of items so far

		; --- Do we need to read the menu title? ---

		LDR	R4,menu__flags		;Get the flags word
		TST	R4,#mFlag__creating	;Is this the first menu
		BEQ	%00menu_create		;Yes -- set up things

		; --- We are already creating a menu ---

		LDR	R6,menu__begin		;Get beginning of real menu
		TST	R4,#mFlag__tOnly	;Has just the title been done
		SUBNE	R4,R6,#24		;Yes -- block already there
		LDR	R5,menu__end		;Get the end marker
		LDMNEIA	R13,{R0-R3}		;Reclaim useful values
		STMNEFD	R13!,{R0}		;Pointer to item definitions
		BNE	%05menu_create		;Now read the items

		SUB	R1,R6,#4		;Copy from here..
		ADD	R0,R1,#20		;...to here
		SUB	R2,R5,R1		;...this much
		BL	fastMove		;Do the copy
		ADD	R5,R5,#20		;Increment end pointer
		MOV	R4,R1			;Write header here
		ADD	R6,R6,#20		;The new beginning
		STR	R6,menu__begin		;Store new value
		LDMIA	R13,{R0-R3}		;Reclaim useful values
		STMFD	R13!,{R0}		;Pointer to item definitions
		B	%05menu_create		;Go through the items

		; --- We are creating a new menu ---

00menu_create	STR	R12,menu__maxLen	;Max length so far
		TST	R4,#mFlag__wasSub	;Was last event a submenu?
		LDREQ	R4,menu__stack		;No -- Get the stack address
		LDRNE	R4,menu__prevMenu	;Yes - start of previous menu
		LDRNE	R5,[R4]			;...get length of menu
		ADDNE	R4,R4,R5		;Start new menu here
		STR	R4,menu__start		;The menu start (incl. defn)

		ADD	R5,R4,#44		;Where to start adding defns
		ADD	R4,R4,#20		;Where to write the header
		MOV	R6,#0			;The last header marker
		STR	R6,[R5,#-4]		;Store it nicely
		STR	R5,menu__begin		;Store the begin pointer
		BL	menu__createTitle	;Create the title
		STMFD	R13!,{R0}		;Pointer to item definitions

		; --- Now go through the menu items ---
		;
                ; At this point, R4 points to the menu header to write to,
                ; R5 points into the stack at the position that the next
                ; items should be written to. R0 points to the next menu
                ; item.

05menu_create	LDR	R7,[R0],#4		;Get flags
		TST	R7,#mFlag_end		;Any more items?
		BNE	%40menu_create		;Nope -- branch ahead
		MOV	R8,R2			;Use R10 for runtime data
		TST	R7,#mFlag_R12		;Should we use R12?
		MOVNE	R8,R3			;Yes, set R8 = R3 then
		TST	R7,#mFlag_indirect	;Is the text indirected
		LDRNE	R6,[R0],#4		;Yes -- load the offset
		LDRNE	R6,[R6,R8]		;...find new pointer
		BNE	%07menu_create		;...and jump the next bit

		MOV	R6,R0			;Point to the string
06menu_create	LDRB	R1,[R0],#1		;Get a byte
		CMP	R1,#0			;Was it the last character?
		BNE	%06menu_create		;No -- keep looking
		ADD	R0,R0,#3		;Word align
		BIC	R0,R0,#3		;Oh yes indeedy

		; --- So, we have an item ---

07menu_create	MOV	R2,R0			;Remember this pointer
		MOV	R0,R6			;Point to the message
		TST	R7,#mFlag_noTrans	;Do we translate the string?
		BLEQ	msgs_lookup		;Yes -- lookup the message
		MOV	R6,R0			;Remember new pointer
		BL	str_len			;Get the length of the text
		TST	R7,#mFlag_sprite	;Is there a sprite too?
		ADDNE	R0,R0,#2		;Yes -- add 42 to the length
		LDR	R1,menu__maxLen		;Get maximum length so far
		CMP	R0,R1			;Is new text longer?
		STRGT	R0,menu__maxLen		;Yes -- store new length
		MOV	R0,R2			;Get the offset back
		MOV	R1,#24			;The WIMP item flags so far
		LDR	R2,=&7000131		;The icon flags so far

		TST	R7,#mFlag_shade		;Is it shadable?
		BEQ	%10menu_create		;No -- jump this code
		BL	%99			;Do a bit specification
		ORRCS	R2,R2,#(1<<22)		;Set the 'shaded' bit

10menu_create	TST	R7,#mFlag_iShade	;Is it inverse shadable?
		BEQ	%15menu_create		;No -- jump this code
		BL	%99			;Do a bit specification
		ORRCC	R2,R2,#(1<<22)		;Set the 'shaded' bit

15menu_create	TST	R7,#mFlag_switch	;Is it a switch?
		BEQ	%20menu_create		;No -- jump this code
		BL	%99			;Do a bit specification
		ORRCS	R1,R1,#1		;Set the tick flag

20menu_create	TST	R7,#mFlag_radio		;Is is a radio type?
		BEQ	%23menu_create		;No -- try next type
		LDMIA	R0!,{R10,R14}		;Get offset and selector
		ADD	R10,R10,R8		;Get real offset
		LDR	R10,[R10]		;Get the word there
		CMP	R10,R14			;It is the same as selector?
		ORREQ	R1,R1,#1		;Yes -- set the tick flag

23menu_create	TST	R7,#mFlag_sprite	;Does item contain a sprite?
		BEQ	%25menu_create		;No -- try next type
		LDR	R10,[R0],#4		;Get the sprite name pointer
		ORR	R2,R2,#2		;Set the 'sprite' bit
		STR	R10,menu__sprite	;Store the sprite pointer

25menu_create	TST	R7,#mFlag_halfSize	;Make sprite half size?
		ORRNE	R2,R2,#(1<<11)		;Yeap -- set the bit

		TST	R7,#mFlag_noWarn	;Don't open subs if shaded?
		BICNE	R1,R1,#16		;Clear relevant bit

		TST	R7,#mFlag_ruleOff	;Put a rule off here?
		ORRNE	R1,R1,#2		;Yes -- set the bit up

		; --- Now store this information in the block ---

		BL	menu__checkOverflow	;Make sure there's room
		MOV	R10,R2			;Put the icon flags in R10
		MOV	R2,#-1			;No submenu yet
		TST	R7,#mFlag_subMenu	;Automatic sub menu?
  		LDMNEIA	R0!,{R2,R14}		;Yes -- get menu pointer
		TST	R7,#mFlag_subWarn	;Submenu warning required
		MOVNE	R2,#1			;Yeap -- put non -1 value in
		STMIA	R5!,{R1,R2,R10}		;Splodge!
		TST	R10,#2			;Is the sprite bit set?
		MOVEQ	R10,#-1			;No -- no validation
		LDRNE	R10,menu__sprite	;Yes -- point to sprite name
		MOV	R14,#255		;Buffer length
		STMIA	R5!,{R6,R10,R14}	;Icon data -- splodge!

		; --- Now, keep searching for icons ---

		ADD	R12,R12,#1		;Increment item count
		ADD	R1,R13,#8		;Point to useful values
		LDMIA	R1,{R1-R3}		;Load back useful values
		B	%05menu_create		;Keep looking

		; --- All the icons have been found, tidy up ---

40menu_create	LDR	R0,menu__flags		;Get my flags word
		CMP	R12,#0			;Did we create any items?
		ORREQ	R0,R0,#mFlag__tOnly	;Yes -- set the flag
		BICNE	R0,R0,#mFlag__tOnly	;No -- clear the flag
		ORR	R0,R0,#mFlag__creating	;We are creating a menu
		STR	R0,menu__flags		;Store updated flags
		STR	R12,[R4],#4		;Store number of items
		STR	R5,menu__end		;The end pointer
		LDR	R6,menu__start		;Get the start
		SUB	R7,R5,R6		;Get the length
		STR	R7,[R6]			;Store in the header
		LDMFD	R13!,{R5}		;First item pointer
		LDMFD	R13!,{R0-R3}		;Load some stuff
		MOV	R14,R0			;Remember user R0
		MOV	R0,R5			;Pointer to first item defn
		STMIA	R4!,{R0-R3}		;Store them in the header
		MOV	R0,R14			;Preserve R0

		; --- And return to the client ---

		LDMFD	R13!,{R4-R12,PC}^	;Return to client

		; --- Do a bit specification ---

99		STMFD	R13!,{R14}		;Save a register
		LDR	R10,[R0],#4		;Get the next word
		ADD	R14,R8,R10,LSR#5	;Get the offset
		LDR	R14,[R14]		;And the byte there
		AND	R10,R10,#31		;Clear bit we don't want
		ADD	R10,R10,#1		;Correct for shifting
		MOVS	R14,R14,LSR R10		;Shift that bit into carry
		LDMFD	R13!,{PC}		;And return to caller

		LTORG

; --- menu__checkOverflow ---
;
; On entry:	R5 == offset in menu stack for creating next item
;
; On exit:	--
;
; Use:		Checks to see if there's enough room in the menu stack for
;		a new menu item or header.

menu__checkOverflow ROUT

		STMFD	R13!,{R14}		;Save some registers
		LDR	R14,menu__stackEnd	;Find the end of the stack
		SUB	R14,R14,#64		;Allow a nice bit of space
		CMP	R14,R5			;Do we have enough space?
		LDMGEFD	R13!,{PC}^		;Yes -- return then

		LDR	R14,menu__flags		;Get my flags word
		AND	R14,R14,#mFlag__inited	;Reset all the flags
		STR	R14,menu__flags		;Store updated flags
		MOV	R1,#-1			;An invalid menu pointer
		SWI	XWimp_CreateMenu	;Close the current menu tree
		ADR	R0,menu__noMem		;Point to error message
		BL	msgs_error		;Translate the error message
		SWI	OS_GenerateError	;And generate the error

menu__noMem	DCD	1
		DCB	"mSOVF",0

		LTORG

; --- menu__recreate ---
;
; On entry:	R1 == pointer to list of menu hits
;		R9 == pointer to workspace
;
; On exit:	--
;
; Use:		Called to recreate the menu definition after an adjust
;		click was made on a menu.

menu__recreate	ROUT

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

		MOV	R10,R1			;We need this list
		LDR	R12,menu__stack		;Point to first menu header
00		LDR	R0,[R10],#4		;Load a menu hit (ignore 1st)
		CMP	R0,#-1			;Is this the end?
		BEQ	%90			;Yes -- finish

		LDR	R0,[R12,#4]		;Get the title defn pointer
		LDR	R2,[R0],#4		;Get the flags word
		MOV	R6,R0			;Point to the text
		TST	R2,#mFlag_R12		;Do we use R12?
		LDREQ	R7,[R12,#12]		;No -- use R10 value
		LDRNE	R7,[R12,#16]		;Yes -- use R12 value

		TST	R2,#mFlag_indirect	;Is the text indirected?
		LDRNE	R6,[R0]			;Yes -- get the offset
		LDRNE	R6,[R7,R6]		;...load indirected pointer
		BL	menu__skipText		;Skip past the text
		STMFD	R13!,{R10}		;Save this R10 value
		TST	R2,#mFlag_makeMe	;Is it a 'makeme' type
		BEQ	%01			;No -- skip this bit
		LDR	R5,[R10]		;Get the next hit
		CMP	R5,#-1			;Are we at the last menu
		BNE	%01			;No -- ignore this function
		LDR	R5,[R0],#4		;Get the 'make me' function

		; --- Recreate the menu over the top of the old one ---

		MOV	R6,#0			;Set the new length
		STR	R6,[R12]		;Store this length in field
		LDR	R6,menu__flags		;Get my flags word
		ORR	R6,R6,#mFlag__wasSub	;Fool menu_create
		STR	R6,menu__flags		;Store the modified flags
		STR	R12,menu__prevMenu	;Make this the previous menu
		MOV	R14,PC			;Set up the return address
		MOV	PC,R5			;Branch to the function
		ORR	R6,R6,#mFlag__recreating ;We're recreating
		STR	R6,menu__flags		;Store the modified flags
		STR	R12,menu__start		;Update this menu
		MOV	R2,R6			;Put the flags in R2
		BL	menu__open		;Set the menu up properley
		BIC	R6,R6,#mFlag__creating	;We're not really creating
		STR	R6,menu__flags		;Store the modified flags
		B	%90			;Tidy up and return

01		MOV	R0,R6			;Point to the text
		TST	R2,#mFlag_noTrans	;Do we translate the string?
		BLEQ	msgs_lookup		;Yes -- lookup the message
		MOV	R6,R0			;Remember new pointer
		BL	str_len			;Get the length of the text
		STR	R0,menu__maxLen		;Store max length

		; --- Go through the items changing the flags ---
		;
		; We have to use three pointers, one to keep track of
		; the real WIMP icon so that we can alter it, one
		; to keep track of our position in the users block, and
		; one to keep track of which header we are using!

		; --- Find the first real item ---

		MOV	R0,R12			;Point to menu defn
		BL	menu__locateFirst	;Locate the first item
		MOV	R3,R0			;Use R3 instead
		STMFD	R13!,{R3}		;Stack this pointer
		SUB	R0,R3,#28		;Point the the menu header
		MOV	R1,R6			;The text string
		BL	str_cpy			;Copy the title across
		MOV	R14,#7			;Might have trashed colour
		STRB	R14,[R3,#12-28]		;So store colour back ;-)

		; --- Set up the pointer to the first header ---

		ADD	R1,R12,#20		;Point to first header
05		LDR	R8,[R1,#12]		;Get the R10 value
		LDR	R10,[R1,#16]		;Get the R12 value

		; --- Finally locate the users definition ---

		LDR	R0,[R1,#4]		;Get the pointer

		; --- Now go through the list ---

06		LDR	R2,[R0],#4		;Get the flags word
		TST	R2,#mFlag_end		;No more items?
		BNE	%20			;No -- try for more
		LDR	R4,[R3,#0]		;Load the item flags
		MOV	R7,R8			;Use R10 value
		TST	R2,#mFlag_R12		;Do we use R12?
		MOVNE	R7,R10			;Yes -- set up R7
		MOV	R5,R0			;Pointer to the text
		TST	R2,#mFlag_indirect	;Is the text indirected?
		LDRNE	R0,[R0]			;Yes -- get the offset
		LDRNE	R0,[R7,R0]		;...load indirected pointer
		TST	R2,#mFlag_noTrans	;Do we translate the string?
		BLEQ	msgs_lookup		;Yes -- lookup the message
		STR	R0,[R3,#12]		;Store the new text pointer
		BL	str_len			;Get the length
		TST	R2,#mFlag_sprite		;Is there a sprite?
		ADDNE	R0,R0,#2		;Yes -- allow for it
		LDR	R6,menu__maxLen		;Get the current max length
		CMP	R0,R6			;Is new length longer?
		STRGT	R0,menu__maxLen		;Yes, store this
		MOV	R0,R5			;Get current offset back
		BL	menu__skipText		;Skip the text part
07		TST	R2,#mFlag_shade		;Is it shadable?
		BEQ	%10			;No -- jump this code
		BL	%99			;Do a bit specification
		LDR	R5,[R3,#8]		;Get the icon flags
		ORRCS	R5,R5,#(1<<22)		;Set the 'shaded' bit
		BICCC	R5,R5,#(1<<22)		;Or maybe clear it
		STR	R5,[R3,#8]		;Put them back

10		TST	R2,#mFlag_iShade	;Is it inverse shadable?
		BEQ	%11			;No -- jump this code
		BL	%99			;Do a bit specification
		LDR	R5,[R3,#8]		;Get the icon flags
		ORRCC	R5,R5,#(1<<22)		;Set the 'shaded' bit
		BICCS	R5,R5,#(1<<22)		;Or maybe clear it
		STR	R5,[R3,#8]		;Put them back

11		TST	R2,#mFlag_switch	;Is it a switch
		BEQ	%12			;No -- jump this code
		BL	%99			;Do a bit specification
		ORRCS	R4,R4,#1		;Set the tick flag
		BICCC	R4,R4,#1		;Or maybe clear it

12		TST	R2,#mFlag_radio		;Is is a radio type?
		BEQ	%13			;No -- jump this code
		LDMIA	R0!,{R5,R6}		;Get offset and selector
		ADD	R5,R5,R7		;Get real offset
		LDR	R5,[R5]			;Get the word there
		CMP	R5,R6			;It is the same as selector?
		ORREQ	R4,R4,#1		;Yes -- set the tick flag
		BICNE	R4,R4,#1		;No -- clear it

13		TST	R2,#mFlag_sprite	;Is there a sprite?
		ADDNE	R0,R0,#4		;Yes -- skip the pointer

		TST	R2,#mFlag_subMenu	;Automatic submenu?
		ADDNE	R0,R0,#8		;Yes -- skip those fields

		STR	R4,[R3,#0]		;Store the item flags back
		ADD	R3,R3,#24		;Point to next real icon
		B	%06			;Try another icon

		; --- Try more items from next header ---

20		ADD	R1,R1,#20		;Point to next header
		LDR	R0,[R1]			;Get the item count
		CMP	R0,#0			;Is there one?
		BNE	%05			;...and do it

		; --- Now move onto next menu ---

		LDMFD	R13!,{R3}		;Get the first item pointer
		LDR	R0,menu__maxLen		;Get the menu with
		ADD	R0,R0,#1		;Add a character width
		MOV	R0,R0,LSL#4		;Multiply width by 16
		STR	R0,[R3,#-12]		;Store in menu width field
		LDR	R0,[R12]		;Get the length
		ADD	R12,R12,R0		;Point to the next menu
		LDMFD	R13!,{R10}		;Load menu hit pointer
		B	%00			;And keep looking

		; --- We have apparently finished now ---

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

		; --- Calculate a bit specification ---

99		LDR	R5,[R0],#4		;Get the next word
		ADD	R6,R7,R5,LSR#5		;Get the offset
		LDR	R6,[R6]			;And the byte there
		AND	R5,R5,#31		;Clear bits we don't want
		ADD	R5,R5,#1		;Correct for shifting
		MOVS	R6,R6,LSR R5		;Shift that bit into carry
		MOV	PC,R14			;Return from subroutine

		LTORG

; --- menu__locateFirst ---
;
; On entry:	R0 == pointer to my menu defn
;
; On exit:	R0 == pointer to first item in menu
;		R1 == Number of items in menu
;
; Use:		Given a pointer to a menu definition (my type, not
;		WIMP), it returns a pointer to the first item, and
;		a count of the number of items in the menu.

menu__locateFirst
		ROUT

		STMFD	R13!,{R2-R6,R14}	;Stack some registers

		MOV	R1,#0			;Item count
		ADD	R0,R0,#20		;Point past length/re-create
00		LDMIA	R0!,{R2,R3,R4,R5,R6}	;Load menu data
		CMP	R2,#0			;Is this the last item?
		ADDNE	R1,R1,R2		;No -- increment item count
		BNE	%00			;Keep searching
		ADD	R0,R0,#12		;Point to the first item
		LDMFD	R13!,{R2-R6,PC}^	;Return to caller

		LTORG

; --- menu__height ---
;
; On entry:	R1 == pointer to real menu block
;
; On exit:	R0 == height of menu
;
; Use:		Calculates the height of a WIMP menu, from its data structure

menu__height	ROUT

		STMFD	R13!,{R1-R2,R14}	;Stack some registers

		MOV	R0,#0			;The height so far
		ADD	R1,R1,#28		;Point to the first item
00		ADD	R0,R0,#44		;Increment the height
		LDR	R2,[R1]			;Get the flags word
		TST	R2,#2			;Is there a dotted line?
		ADDNE	R0,R0,#24		;Yes -- add 24 to height
		TST	R2,#&80			;Is this the last item?
		ADDEQ	R1,R1,#24		;No -- point to next item
		BEQ	%00			;...and keep counting

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

		LTORG

; --- menu__open ---
;
; On entry:	R2 == modules flags word
;		R9 == workspace pointer
;
; On exit:	--
;
; Use:		Opens the next menu in the right place

menu__open	ROUT

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

		LDR	R0,menu__start		;Point to current menu
		BL	menu__locateFirst	;Find the first item
		SUB	R1,R1,#1		;0 index item count
		MOV	R1,R1,LSL#3		;Multiple no. of items by 8
	 	RSB	R1,R1,R1,LSL#2		;And the by 3
	 	ADD	R1,R0,R1		;Point to last item
	 	LDR	R3,[R1]			;Load the flags word
		ORR	R3,R3,#&80		;Set 'Last item' bit
		BIC	R3,R3,#2		;No ruleoff here
		STR	R3,[R1]			;Store the flags back

		SUB	R1,R0,#28		;Point to real menu structure
		LDR	R0,menu__maxLen		;Get the longest text length
		MOV	R0,R0,LSL#4		;Multiply by 16
		ADD	R0,R0,#16		;Add one for luck
		STR	R0,[R1,#16]		;Store the width
		MOV	R4,R2			;Remember flags word
		TST	R4,#mFlag__recreating	;Are we recreating a menu
		LDMNEFD	R13!,{R0-R4,PC}^	;Yes -- Return
		ADR	R2,menu__coords		;Point to coords block
		LDMIA	R2,{R2,R3}		;Get the x and y coords

		; --- Ensure Y position is correct on icon bar ---

		TST	R4,#mFlag__iBar		;Was it on the icon bar?
		BLNE	menu__height		;Calculate the menu height
		ADDNE	R3,R0,#96		;This is the Y position

		TST	R4,#mFlag__wasSub	;Is it a submenu?
		BEQ	%90			;No -- create a normal menu
		LDR	R0,menu__prevMenu	;Get menu from which it came
		ADD	R0,R0,#20		;Point to the first header
50menu__open	LDR	R14,[R0],#4		;Get the number of items
		CMP	R14,#0			;Any more headers?
		ADDNE	R0,R0,#16		;Yes -- point to next one
		BNE	%50menu__open		;...and keep looking
		ADD	R0,R0,#28		;Point to first item
		LDR	R14,menu__prevItem	;Get the previous item hit
		MOV	R14,R14,LSL#3		;Multiply item hit by 8
	 	RSB	R14,R14,R14,LSL#2	;And then by 3
	 	ADD	R0,R0,R14		;Point to the item
	 	STR	R1,[R0,#4]		;Store pointer in menu field
		SWI	Wimp_CreateSubMenu	;Create sub menu
		LDMFD	R13!,{R0-R4,PC}^	;Return

90menu__open	SUB	R2,R2,#64		;No -- correct X position
		SWI	Wimp_CreateMenu		;...create the menu
		ORR	R4,R4,#mFlag__opened	;Set the opened bit
		STR	R4,menu__flags		;Store the modified flags
		LDMFD	R13!,{R0-R4,PC}^	;Return

		LTORG

; --- menu__skipText ---
;
; On entry:	R0 == pointer to text field
;		R2 == item flags for this item
;
; On exit:	R0 == pointer to first data field after the text
;
; Use:		Skips text part of an icon definition

menu__skipText	ROUT

		STMFD	R13!,{R14}		;Stack registers

		TST	R2,#mFlag_indirect	;Is it indirected?
		ADDNE	R0,R0,#4		;Yes -- just skip a word
		LDMNEFD	R13!,{PC}^		;And return

00		LDRB	R14,[R0],#1		;Get a character
		CMP	R14,#0			;Is it a NULL
		BNE	%00			;No, keep looking
		ADD	R0,R0,#3		;Word align R0
		BIC	R0,R0,#3		;Complete aligning
		LDMFD	R13!,{PC}^		;And return

		LTORG

; --- menu__findItem ---
;
; On entry:	R0 == pointer to menu definition (my kind)
;		R1 == Item number to locate
;
; On exit:	R0 == pointer to the item definition
;		R1 == pointer to header entry for this item
;		R2 == index for this item (to pass to handler)
;
; Use:		Locates the given item from a created menu definition,
;		and also finds the header entry for it

menu__findItem	ROUT

		STMFD	R13!,{R3,R4,R14}	;Stack some registers

		ADD	R0,R0,#20		;Point to first header
		MOV	R2,#0			;Item so far
00		LDR	R3,[R0]			;Number of items header's for
		MOV	R4,R2			;Number so far
		ADD	R2,R2,R3		;Increment my count
		CMP	R1,R2			;Is this the relevant header?
		ADDGE	R0,R0,#20		;No -- point to next header
		BGE	%00			;...and keep looking

		; --- We have located the relevant header ---

		SUBS	R3,R1,R4		;Calculate item index
		STMFD	R13!,{R3}		;Store it on the stack
		MOV	R1,R0			;Point to header for user
		LDR	R0,[R1,#4]		;Find definition pointer
10		LDMEQFD	R13!,{R2-R4,PC}^	;Yes -- return to caller
		LDR	R2,[R0],#4		;Load the flags
		BL	menu__skipText		;Skip the text
		TST	R2,#mFlag_shade		;Is there a shade field
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_iShade	;Is there a ishade field
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_switch	;Is there a switch field
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_radio		;Are there radio fields
		ADDNE	R0,R0,#8		;Yes -- skip them
		TST	R2,#mFlag_sprite	;Is there a sprite pointer?
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_subMenu	;Automatic submenu?
		ADDNE	R0,R0,#8		;Yes -- skip fields
		SUBS	R3,R3,#1		;Decrement the count
		B	%10			;Keep searching

		LTORG

; --- menu__dispatch ---
;
; On entry:	R0 == event type to send
;		R1 == pointer to menu hits
;
; On exit:	--
;
; Use:		Called to dispatch a menu hit event

menu__dispatch	ROUT

		STMFD	R13!,{R0-R3,R10,R12,R14}

		MOV	R3,R0			;Remember event to send
		LDR	R0,menu__stack		;Point to first menu header
00		LDR	R2,[R1,#4]!		;Load a menu hit (ignore 1st)
		CMP	R2,#-1			;Is this the end?
		BEQ	%10			;Yes -- branch ahead
		LDR	R2,[R0]			;Get the length
		ADD	R0,R0,R2		;Point to the next menu
		B	%00			;And keep looking
10		LDR	R1,[R1,#-4]		;Get the item number
		BL	menu__findItem		;Point to item and header
		MOV	R14,R0			;Keep the item pointer
		ADD	R1,R1,#8		;Point to the event handler
		MOV	R0,R3			;Get the event type
		LDMFD	R1,{R3,R10,R12}		;Get the values
		MOV	R1,R2			;The indexed item number
		MOV	R2,R14			;Pass item address in R2
		CMP	R3,#0			;Sanity check
		MOV	R14,PC			;Set up return address
		MOVNE	PC,R3			;Jump to the event handler

		LDMFD	R13!,{R0-R3,R10,R12,PC}^ ;Return

		LTORG

; --- menu__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 poll word
;
; On exit:	--
;
; Use:		Call as an event pre-filter. Its purpose is to open
;		a previously created menu in the right place.

menu__preFilter	ROUT

		STMFD	R13!,{R0-R2,R9,R14}	;Stack some registers
		MOV	R9,R12			;Get workspace pointer in R9

		LDR	R2,menu__flags		;Get my flags word
		TST	R2,#mFlag__creating	;Are we creating a menu?
		BEQ 	%90menu__preFilter	;No -- return then
		TST	R2,#mFlag__wasSub	;Is this from a sub menu?
		BNE	%70menu__preFilter	;Yes -- just open the menu

		; --- Set up menu coordinates and things ---

		BL	event_last		;Get the last event
		CMP	R0,#6			;Mouse click?
		BEQ	%50menu__preFilter	;Yes -- deal with it

		; --- Open over the mouse pointer then ---

		MOV	R14,R2			;Preserve flags word
		SUB	R13,R13,#20		;Get a block for me
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetPointerInfo	;Get pointer information
		LDMIA	R1,{R0,R1}		;Get coords out of block
		ADR	R2,menu__coords		;Point to coords block
		STMIA	R2,{R0,R1}		;Store them in the block
		ADD	R13,R13,#20		;Get stack back
		MOV	R2,R14			;Get flags back
		B	%70menu__preFilter	;Open the menu

		; --- Deal with button click ---

50		MOV	R14,R2			;Preserve flags word
		LDR	R0,[R1,#12]		;Get the window handle
		CMP	R0,#-2			;Is it the icon bar
		BNE	%60menu__preFilter	;No -- jump
		ORR	R14,R14,#mFlag__iBar	;Set relevent bit
		STR	R14,menu__flags		;Store the flags back
60		ADR	R2,menu__coords		;Point to coords block
		LDMIA	R1,{R0,R1}		;Get x and y coords
		STMIA	R2,{R0,R1}		;Store them in the block
		MOV	R2,R14			;Get flags word back

		; --- Open the menu,then ---

70		BL	menu__open		;Yes -- open the menu
90		LDR	R2,menu__flags		;Get new flags
		AND	R2,R2,#mFlag__inited+mFlag__opened
		STR	R2,menu__flags		;Store the new flags
		LDMFD	R13!,{R0-R2,R9,PC}^	;Return to caller

		LTORG

; --- menu__postFilter ---
;
; On entry:	R0 == wimp event
;		R1 == pointer to block
;
; On exit:	--
;
; Use:		Called as an event post filter to catch menu related events

menu__postFilter
		ROUT

		; --- Are we at all interested? ---

		STMFD	R13!,{R9,R14}		;Store R9 value
		MOV	R9,R12			;Get the workspace pointer
		LDR	R14,menu__flags		;Get the menu flags
		TST	R14,#mFlag__opened	;Do we have a menu open?
		LDMEQFD	R13!,{R9,PC}^		;No -- ignore it then

		CMP	R0,#9			;Menu click?
		BEQ	%20			;Yes -- deal with that
		CMP	R0,#17			;User_Message
		CMPNE	R0,#18			;User_Message_Recorded
		BNE	%90			;No -- tidy up a bit

		; --- It was a message, are we interested? ---
		;
		; Note that we are allowed to corrupt R12

		STMFD	R13!,{R0-R2}		;Stack some registers
		LDR	R0,=&400C0		;Menu warning
		LDR	R12,[R1,#16]		;Get the message type
		CMP	R0,R12			;Is it menu warning?
		BEQ	%05			;Yes -- deal with it
		LDR	R0,=&400C9		;Menus deleted
		CMP	R0,R12			;Is that the message?
		BEQ	%03			;Yes -- deal with it
		LDR	R0,=&502		;Help request
		CMP	R0,R12			;Is that the message?
		LDMNEFD	R13!,{R0-R2}		;No -- Get registers
		BNE	%90			;...and tidy up a bit

		; --- There was a help request ---

		STMFD	R13!,{R3,R10,R12}	;We need these
		SUB	R13,R13,#40		;Get a buffer
		MOV	R0,#1			;Get state give window/icon
		ADD	R1,R1,#32		;Point to window/icon handle
		LDMIA	R1,{R2,R3}		;Get them
		LDR	R14,menu__twin		;Get the dbmn address
		LDR	R14,[R14,#twin_trans]	;Get the transient dbox
		CMP	R14,R2			;Are they the same
		BEQ	%02			;Yes -- forget it
		MOV	R1,R13			;Use this buffer
		SWI	XWimp_GetMenuState	;Get the menu state
		BVS	%02			;If failed, return
		LDR	R0,[R1,#0]		;First first menu index
		CMP	R0,#-1			;Is it on our menu?
		BEQ	%02			;No -- skip forward
		MOV	R0,#mEvent_help		;Set the event type
		BL	menu__dispatch		;Dispatch the event

		; --- Return to caller ---

02		ADD	R13,R13,#40		;Reclaim my stack
		LDMFD	R13!,{R3,R10,R12}	;Get these values back
		LDMFD	R13!,{R0-R2}		;Get registers
		B	%90			;...and tidy up a bit

		; --- There was a menus deleted message ---

03		STMFD	R13!,{R10,R12}		;We need these
		LDR	R0,menu__flags		;Get the flags word
		BIC	R0,R0,#mFlag__opened	;Well,it's closed now
		STR	R0,menu__flags		;Store the flags back
		LDR	R0,menu__stack		;Find the top level menu
		ADD	R0,R0,#8		;Point to the handler
		LDMIA	R0,{R2,R10,R12}		;Get handler and R10/R12
		MOV	R0,#mEvent_deleted	;Set the event type
		CMP	R2,#0			;Sanity check
		MOV	R14,PC			;Set the return address
		MOVNE	PC,R2			;Call the handler
04		LDMFD	R13!,{R10,R12}		;Get these values back
		LDMFD	R13!,{R0-R2}		;Get registers
		B	%90			;...and tidy up a bit

		; --- It was a submenu warning ---

05		LDR	R0,menu__flags		;Get the flags
		ORR	R0,R0,#mFlag__wasSub	;It was a menu warning
		STR	R0,menu__flags		;Put the flags back
		ADR	R0,menu__coords		;Point to my coords block
		ADD	R1,R1,#24		;Point to the (x,y) to use
		LDMIA	R1!,{R2,R12}		;Load x and y
		STMIA	R0,{R2,R12}		;And store them usefully

		; --- We now need to find the menu in question ---

		LDR	R0,menu__stack		;Point to first menu header
05		LDR	R2,[R1,#4]!		;Load a menu hit (ignore 1st)
		CMP	R2,#-1			;Is this the end?
		BEQ	%10			;Yes -- branch ahead
		LDR	R2,[R0]			;Get the length
		ADD	R0,R0,R2		;Point to the next menu
		B	%05			;And keep looking
10		STR	R0,menu__prevMenu	;Store this pointer
		LDR	R1,[R1,#-4]		;Get the item number
		STR	R1,menu__prevItem	;Store the item number

		; --- Now we need to create the submenu if we need to ---

		BL	menu__findItem		;Point to the item definition
		LDR	R2,[R0],#4		;Get the flags word
		TST	R2,#mFlag_subMenu	;Automatic menu?
		BNE	%15			;Yes -- deal with it

		; --- Here we must just tell the user ---
		;
		; R0 == pointer to the menu item definition+4
		; R1 == pointer to the menu header for this item
		; R2 == item flags

		MOV	R0,#mEvent_arrow	;Set the event type
		LDR	R1,[R13,#4]		;Get the message block
		ADD	R1,R1,#32		;Point to the menu hit list
		BL	menu__dispatch		;Dispatch the event
		LDMFD	R13!,{R0-R2,R9,PC}^	;Return to caller

		; --- We must automatically open the menu ---

15		BL	menu__skipText		;Skip the item text
		TST	R2,#mFlag_switch	;Is there a switch field
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_shade		;Is there a shade field
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_iShade	;Is there a ishade field
		ADDNE	R0,R0,#4		;Yes -- skip it
		TST	R2,#mFlag_radio		;Are there radio fields
		ADDNE	R0,R0,#8		;Yes -- skip them
		TST	R2,#mFlag_sprite	;Is there a sprite?
		ADDNE	R0,R0,#4		;Yes -- skip pointer
		ADD	R1,R1,#12		;Point to R10,R12 for item
		LDMIA	R1,{R2,R3}		;Use these values again
		LDMIA	R0,{R0,R1}		;Get menu pointer & handler
		BL	menu_create		;Create this menu

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

		; --- Deal with menu selection ---

20		STMFD	R13!,{R0-R2}		;Stack some registers
		BIC	R14,R14,#mFlag__opened	;Say the menu just closed
		STR	R14,menu__flags		;Save these flags back

		; --- Set up the dbmn flag word ---

		LDR	R2,menu__twin		;Locate dbmn area
		LDR	R14,[R2,#twin_flags]	;Get the flags word
		ORR	R14,R14,#twinFlag_recrt	;We are going to recreate it
		STR	R14,[R2,#twin_flags]	;Store the flags back

		; --- Dispatch the event ---

		MOV	R0,#mEvent_select	;Set the event type
		BL	menu__dispatch		;Dispatch the event

		LDR	R14,[R2,#twin_flags]	;Get the flags word back
		TST	R14,#twinFlag_recrt	;Do we still need to recreate
		LDMEQFD	R13!,{R0-R2}		;No -- get registers back
		BEQ	%90			;...and tidy up

		; --- Recreate the menu if we need to ---

		SUB	R13,R13,#20		;Get a block
		MOV	R1,R13			;Point to it
		SWI	Wimp_GetPointerInfo	;Get pointer information
		LDR	R1,[R1,#8]		;Get the button state
		TST	R1,#1			;Was Adjust clicked?
		ADD	R13,R13,#20		;Get the stack back
		LDMEQFD	R13!,{R0-R2}		;No -- get registers back
		BEQ	%90			;...and tidy up
		LDMIB	R13,{R1}		;Get the menu hit list back
		BL	menu__recreate		;Recreate the menu
		LDR	R1,menu__stack		;Get the stack pointer
		ADD	R1,R1,#20		;Point to the first header
25		LDR	R0,[R1],#4		;Get the number of items
		CMP	R0,#0			;Any more headers?
		ADDNE	R1,R1,#16		;Yes -- point to next one
		BNE	%25			;...and keep looking
		SWI	Wimp_CreateMenu		;Recreate the menu
		LDR	R14,menu__flags		;Load the menu flags again
		ORR	R14,R14,#mFlag__opened	;The menu is still open
		STR	R14,menu__flags		;Save the flags back

		LDMFD	R13!,{R0-R2}		;Get registers back
		B	%90			;And tidy up

		; --- Tidy up on a non-submenu warning event ---

90		LDR	R12,menu__flags		;Get the flags
		BIC	R12,R12,#mFlag__wasSub	;It was not a menu warning
		STR	R12,menu__flags		;Put the flags back
		LDMFD	R13!,{R9,PC}^		;Return to caller

		LTORG

; --- menu_help ---
;
; On entry:	R0 == pointer to base message tag
;		R1 == index of menu item
;
; On exit:	--
;
; Use:		Adds a string to the help message found by adding the menu
;		item number to the base message tag.

		EXPORT	menu_help
menu_help	ROUT

		CMP	R1,#0			;Is the menu item sane?
		MOVLTS	PC,R14			;No -- don't trust Tim
		STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R1,R0			;Point to base message tag
		MOV	R0,R11			;Point to scratchpad
		BL	str_cpy			;Add the string in there
		MOV	R1,R0			;Point to terminating null
		MOV	R2,#25			;Should be 25 bytes left over
		LDR	R0,[R13,#4]		;Get his item number
		SWI	OS_ConvertInteger4	;Tack it on the end
		MOV	R0,R11			;Point to the message tag
		BL	msgs_lookup		;Translate it nicely
		BL	help_add		;Add it to the help string
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- menu_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the menu system.

		EXPORT	menu_init
menu_init	ROUT

		STMFD	R13!,{R0-R3,R9,R14}	;Stack some registers
		WSPACE	menu__wSpace,R9		;Locate my workspace

		; --- Are we already initialised? ---

		LDR	R0,menu__flags		;Get my flags
		TST	R0,#mFlag__inited	;Are we initialised?
		LDMNEFD	R13!,{R0-R3,R9,PC}^	;Yes -- return

		ORR	R0,R0,#mFlag__inited	;Set initialised flag
		STR	R0,menu__flags		;And store them back

		; --- Ensure that event is initialised ---

		BL	event_init		;Initialise it

		; --- Set up my menu stack ---

		LDR	R0,menu__optName	;Get the option block name
		BL	libOpts_find		;Try to find the block
		LDRCS	R3,[R0,#0]		;If found, load stack size
		MOVCC	R3,#2048		;Otherwise use default 2K
		MOV	R0,#2			;Allocate memory
		BL	sapphire_heapAddr	;Find the heap address
		SWI	OS_Heap			;Allocate the stack
		STR	R2,menu__stack		;Store this value
		ADD	R3,R3,R2		;The end of the menu stack
		STR	R3,menu__stackEnd	;The menu stack end

		; --- Set up the filters ---

		ADR	R0,menu__preFilter	;Point to the filter
		MOV	R1,R9			;Use this workspace
		BL	event_preFilter		;Add the pre filter

		ADR	R0,menu__postFilter	;Point to the filter
		MOV	R1,R9			;Use this workspace
		BL	event_postFilter	;Add the post filter

		; --- Locate the TWIN global area ---

		LDR	R0,menu__TWIN		;Load the global area name
		MOV	R1,#twin_size		;Load the area's size
		BL	sapphire_global		;Find the area's address
		STR	R0,menu__twin		;Store the address away

		MOVCC	R1,#0			;Clear the global area
		MOVCC	R2,#0
		MOVCC	R14,#0
		STMCCIA	R0,{R1,R2,R14}		;Store zeroes all over it

		; --- And return peacefully ---

		LDMFD	R13!,{R0-R3,R9,PC}^	;Return to caller

menu__optName	DCB	"MENU"
menu__TWIN	DCB	"TWIN"

		LTORG

menu__wSpace	DCD	0

;----- Global area layouts --------------------------------------------------

; --- TWIN global area ---
;
; See transWin for more details

		^	0
twin_flags	#	4			;Various flags for things
twin_trans	#	4			;Handle of transient window
twin_tmsHook	#	4			;Hook for TMS
twin_size	#	4

twinFlag_recrt	EQU	(1<<0)			;Do we want to recreate?

;----- Workspace ------------------------------------------------------------

		^	0,R9
menu__wStart	#	0

menu__flags	#	4			;Flags word

mFlag__inited	EQU	(1<<0)			;We are initialised
mFlag__creating	EQU	(1<<1)			;We are creating a menu
mFlag__wasSub	EQU	(1<<2)			;Last event was sub menu warn
mFlag__tOnly	EQU	(1<<4)			;Only the title has been done
mFlag__iBar	EQU	(1<<5)			;The click was on icon bar
mFlag__recreating EQU	(1<<6)			;We are recreating a menu
mFlag__opened	EQU	(1<<7)			;I have a menu opened

menu__stack	#	4			;Pointer to the menu stack
menu__stackEnd	#	4			;The end of the menu stack
menu__start	#	4			;Start of current menu defn
menu__begin	#	4			;Pointer to real menu
menu__end	#	4			;The end of the menu

menu__maxLen	#	4			;Maximum length of items
menu__sprite	#	4			;Pointer to a sprite name
menu__coords	#	8			;(x,y) coords to open menu at
menu__prevMenu	#	4			;Menu from which warning came
menu__prevItem	#	4			;Menu from which warning came
menu__twin	#	4			;Pointer to DBMN global area

menu__wSize	EQU	{VAR}-menu__wStart

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	menu__wSize		;Workspace size
		DCD	menu__wSpace		;Workspace pointer
		DCD	0			;Scratchpad size
		DCD	menu_init		;Initialisation

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

		END
