; TitleMenu module, written by Vincent Lefvre
; Freeware.

; $Id: titlemenu 3.4 2003/05/25 11:17:01 vlefevre Exp $

		GET	h:RegNames
		GET	h:SWINames
		GET	h:RCSsupport

		GETVERS	"$Revision: 3.4 $"
		GETDATE	"$Date: 2003/05/25 11:17:01 $"

		GBLS	NAME
NAME		SETS	"TitleMenu"
		GBLS	AUTHOR
AUTHOR		SETS	"Vincent Lefvre"
		GBLS	VERSION
VERSION		SETS	VERS:CC:" (":CC:DATE:CC:")"

N		EQU	18	;Maximum number of menu items.

EventV		EQU	&10	;Event vector.
MouseEvent	EQU	10	;Event: mouse transition.

OpenW		EQU	2
CloseW		EQU	3
MClick		EQU	6
MenuSel		EQU	9
UsrMsg		EQU	17
UsrMsgRec	EQU	18
UsrMsgAck	EQU	19

		GBLS	FOD
FOD		SETS	"Filer_OpenDir "
FNL		EQU	(256-:LEN:FOD):AND:&FC

		GBLS	SDDIR
SDDIR		SETS	"$Dir"
		GBLS	PHELP
PHELP		SETS	".!Help"

		^	0	;Pointer info...
PIMX		#	4	;Mouse X.
PIMY		#	4	;Mouse Y.
PIBS		#	4	;Button state.
PIWH		#	4	;Window handle.
PIIH		#	4	;Icon handle.
PISIZE		#	0

		^	0
		#	4	;Task handle.
		#	8	;Mouse X and Y...
CBFLAG		#	1	;and callback flag.
		#	3	;Unused (corrupted).
MODE		#	1	;Mode.
KEY		#	1	;Special key.
HFLAG		#	1	;Help flag: R11 if Help item, 255 otherwise.
INIT		#	1	;Init flag: 0, then 16.
ODLIST		#	4	;Pointer to Obey$Dir list.
WHANDLE		#	4	;Handle of info window.
BUFF1		#	256	;Buffer 1 (for Wimp_Poll).
BUFF2		#	PISIZE	;Buffer 2 (for the callback routine).
FNAME		#	FNL	;Buffer for filename or user message.
MENU		#	28+24*N	;Buffer for the menu block.
SIZE		#	0

PWH		EQU	BUFF1+PIWH	;Window (under pointer) handle offset.
TB		EQU	PWH+80		;Temporary buffer.
TBSIZE		EQU	BUFF2-TB	;Size of temporary buffer.

; Modes:
;   * bit 0: close icon flag (0: enabled, 1: disabled).
;   * bit 1: preferred menu (0: document menu, 1: application menu).
;   * bit 2: secondary menu flag (0: enabled, 1: disabled).
;   * bit 3: special key flag (0: enabled, 1: disabled).
;   * bit 4: use Obey$Dir value for the application directory.

		AREA	TitleMenu, CODE, PIC, READONLY
		ENTRY

; *************
; Module header
; *************

BaseAddr	DCD	RM_Start  -BaseAddr
		DCD	RM_Init   -BaseAddr
		DCD	RM_Die    -BaseAddr
		DCD	0
		DCD	RM_Title  -BaseAddr
		DCD	RM_Help   -BaseAddr
		DCD	RM_HCtable-BaseAddr
		DCD	0,0,0,0,0
		DCD	RM_Flags  -BaseAddr

RM_Flags	DCD	1		;32-bit compatible.

; *******************
; Initialisation code
; *******************

RM_Init		LDR	R2, [R12]	;R2: pointer to workspace or 0.
		MOV	R5, LR
		TEQ	R2, #0
		BNE	init2		;Branch if re-init.
		MOV	R0, #6		;Executed unless re-init.
		MOV	R3, #SIZE
		SWI	XOS_Module	;Claim.
		MOVVS	PC, R5		;Return with V=1 if not enough memory.
		STR	R2, [R12]	;Pointer to workspace.
init2		MOV	R0, #0
		STR	R0, [R2]	;Reset task handle.
		STR	R0, [R2, #MODE]	;Default mode and default key: 0.
		STR	R0, [R2, #ODLIST] ;Obey$Dir list empty.
		STR	R0, [R2, #WHANDLE] ;Window not yet created.
		ADD	R3, R2, #MODE
		MOV	R1, R10		;Pointer to environment string.
		MOV	R0, #10+(6<<29)
		SWI	XOS_ReadUnsigned
		STRVCB	R2, [R3]	;Set the mode if given.
		SUBS	R0, R0, R0	;Clear V flag.
		MOV	PC, R5

; *****************
; Finalisation code
; *****************

RM_Die		LDR	R6, [R12]	;R6: pointer to workspace.
		LDR	R4, [R6]	;Task handle or 0.
		CMP	R4, #0		;(V = 0.)
		MOVEQ	PC, LR		;Return if 0.
		MOV	R5, LR
		MOV	R0, #13
		MOV	R1, #MouseEvent
		SWI	XOS_Byte	;Disable mouse event.
		MOV	R0, #EventV
		ADR	R1, event_rout
		MOV	R2, R6
		SWI	XOS_Release	;Release the Event vector.
		LDR	R0, [R6, #WHANDLE]
		ADD	R1, R6, #WHANDLE
		TEQ	R0, #0
		SWINE	XWimp_DeleteWindow ;Delete info window if created.
		LDR	R1, task	;"TASK".
		MOV	R0, R4		;Task handle.
		SWI	XWimp_CloseDown
		LDR	R2, [R6, #ODLIST] ;Free Obey$Dir list...
		MOV	R0, #7
		TEQ	R2, #0
free_loop	LDRNE	R3, [R2]	;R3: pointer to next block or 0.
		SWINE	XOS_Module	;Free block R2.
		ADDNES	R2, R3, #0	;(Clear V flag.)
		BNE	free_loop
		MOV	PC, R5		;No more block to free. Return.

; ***************************
; EventV routine and callback
; ***************************

event_rout	TEQ	R0, #MouseEvent
		MOVNE	PC, LR		;Return if not mouse event.
		TST	R3, #2
		MOVEQ	PC, LR		;Return if Menu not pressed.
		STMFD	SP!, {R0-R1,LR}
		LDRB	R14, [R12, #CBFLAG]
		STMIB	R12, {R1-R3}	;Store mouse X, Y and cbflag = true.
		TEQ	R14, #0
		ADREQ	R0, callback
		MOVEQ	R1, R12
		SWIEQ	XOS_AddCallBack
		LDMFD	SP!, {R0-R1,PC}

callback	STMFD	SP!, {R0-R2,LR}
		ADD	R1, R12, #BUFF2
		SWI	XWimp_GetPointerInfo
		LDRB	R2, [R12, #MODE]
		LDR	R0, [R1, #PIIH]	;Icon handle (under the mouse pointer).
		MOVS	R2, R2, LSL #31	;Click over close icon activated?
		CMPEQ	R0, #-3		;Close icon (tested if mode & 1 == 0).
		CMPNE	R0, #-4		;Title bar.
		STRNEB	R2, [R12, #CBFLAG] ;If not, cbflag = false. Else:
		LDREQ	R2, [R12]	;Task handle.
		MOVEQ	R0, #MClick
		SWIEQ	XWimp_SendMessage ;Send a mouse click to oneself.
		LDMFD	SP!, {R0-R2,PC}

; *****************
; TitleMenuODL code
; *****************

ODL		LDR	R6, [R12]	;R6: pointer to workspace.
		MOV	R5, LR
		LDR	R4, [R6, #ODLIST]
		LDR	R3, spaces	;R3: "   ",0.
ODL_loop	CMP	R4, #0		;Pointer to cell or 0.
		MOVEQ	PC, R5		;Return with V=0 if no more cells.
		LDR	R0, [R4, #4]	;Task handle.
		ADD	R1, R6, #BUFF1	;Pointer to buffer.
		MOV	R2, #256	;Size of buffer.
		SWI	XOS_ConvertHex4	;Convert halfword.
		STRVC	R3, [R1]	;"   ",0.
		SWIVC	XOS_Write0	;Write task handle and spaces.
		ADDVC	R0, R4, #8	;Pointer to Obey$Dir value.
		SWIVC	XOS_Write0	;Write Obey$Dir value.
		SWIVC	XOS_NewLine
		LDRVC	R4, [R4, #0]
		BVC	ODL_loop
		MOV	PC, R5		;Return with V=1.

; ********************
; TitleMenuRemove code
; ********************

Remove		MOV	R5, LR
		MOV	R1, R0		;Pointer to string to read.
		MOV	R0, #16+(1<<31)	;Default: base 16.
		SWI	XOS_ReadUnsigned
		MOVVS	PC, R5		;Return with V=1 if error.
		LDR	R6, [R12]	;R6: pointer to workspace.

; Remove task R2 from Obey$Dir list. R5: return address.

remove_task	MOV	R0, R2, LSL #16
		ADD	R1, R6, #ODLIST	;R1: address of pointer to first cell.
		LDR	R2, [R1]	;R2: pointer to first cell.
rmtask_loop	CMP	R2, #0
		MOVEQ	PC, R5		;Return with V=0 if no more cells.
		LDMIA	R2, {R3,R4}	;Read ptr to next cell and task handle.
		TEQ	R0, R4, LSL #16
		MOVNE	R1, R2
		MOVNE	R2, R3
		BNE	rmtask_loop	;Loop until handle found.
		STR	R3, [R1]	;Remove cell R2...
		MOV	R0, #7
		SWI	XOS_Module
		MOV	PC, R5

; **********************
; Desktop_TitleMenu code
; **********************

Desktop		MOV	R5, LR
		MOV	R2, R0
		ADR	R1, RM_Title
		MOV	R0, #2
		SWI	XOS_Module	;Enter TitleMenu.
		MOV	PC, R5

; *********
; Some data
; *********

spaces		DCB	"   ",0
task		DCB	"TASK"
obeydir		DCB	"Obey$Dir",0

RM_Help		DCB	NAME,9,VERSION," by ",AUTHOR,0

Help_Desktop	DCB	"Do not use *",27,0,", use *Desktop instead.",0
Help_Mode	DCB	"*",27,0," sets or",27,32,27,2,NAME," mode.",13
Synt_Mode	DCB	27,30,"<mode>]",0
Help_SKey	DCB	"*",27,0," sets or",27,32,27,2,NAME," special key.",13
Synt_SKey	DCB	27,30,"<key>]",0
Help_ODL	DCB	"*",27,0,27,32,27,2,"Obey$Dir list.",0
Help_Remove	DCB	"*",27,0," removes the handle from",27,2,"Obey$Dir list.",13
Synt_Remove	DCB	27,14,"TaskHandle>",0

		ALIGN
messages	DCD	&400C2	;Message_TaskInitialise.
		DCD	&400C3	;Message_TaskCloseDown. A zero word follows.
url		DCD	0,&4AF80
		DCB	"http://www.vinc17.org/"
urle1		DCB	"acorn/"
urle2

		ALIGN

RM_HCtable	DCB	"Desktop_"
ic0
RM_Title	DCB	NAME,0
		ALIGN
		DCD	Desktop-BaseAddr,0,0,Help_Desktop-BaseAddr
		DCB	NAME,"Mode",0
		ALIGN
		DCD	Mode-BaseAddr,&010100,Synt_Mode-BaseAddr,Help_Mode-BaseAddr
		DCB	NAME,"SKey",0
		ALIGN
		DCD	SKey-BaseAddr,&010100,Synt_SKey-BaseAddr,Help_SKey-BaseAddr
		DCB	NAME,"ODL",0
		ALIGN
		DCD	ODL-BaseAddr,0,0,Help_ODL-BaseAddr
		DCB	NAME,"Remove",0
		ALIGN
		DCD	Remove-BaseAddr,&010101,Synt_Remove-BaseAddr,Help_Remove-BaseAddr

; Note: a zero byte follows.

IX0		EQU	152
IX1		EQU	632
IB		EQU	8
IH		EQU	52
IY		EQU	IB+IH

info_window	DCD	0,0,IX1+IB,IB+5*IY,0,0,-1,&84000012
		DCB	7,2,7,1,3,1,12,0
		DCD	0,-1024,1280,0,&13D,0,1,0
title_data	DCD	0,-1,19,10
icons		DCD	IX0,-1*IY,IX1,-(IB+0*IY),&1700313D,ic0-ref,valstr-ref,0
		DCD	IX0,-2*IY,IX1,-(IB+1*IY),&1700013D,ic1-ref,valstr-ref,0
		DCD	IX0,-3*IY,IX1,-(IB+2*IY),&1700313D,ic2-ref,valstr-ref,0
		DCD	IX0,-4*IY,IX1,-(IB+3*IY),&1700013D,ic3-ref,valstr-ref,0
		DCD	IX0,-5*IY,IX1,-(IB+4*IY),&1700013D,ic4-ref,valstr-ref,0
		DCD	IB,-1*IY+4,IX0-4,-(IB+0*IY+4),&17000211
		DCB	"Name",0,0,0,0,0,0,0,0
		DCD	IB,-2*IY+4,IX0-4,-(IB+1*IY+4),&17000211
		DCB	"Purpose",0,0,0,0,0
		DCD	IB,-3*IY+4,IX0-4,-(IB+2*IY+4),&17000211
		DCB	"Author",0,0,0,0,0,0
		DCD	IB,-4*IY+4,IX0-4,-(IB+3*IY+4),&17000211
		DCB	"Licence",0,0,0,0,0
		DCD	IB,-5*IY+4,IX0-4,-(IB+4*IY+4),&17000211
		DCB	"Version",0,0,0,0,0
about		DCB	"About this program",0
valstr		DCB	"R2",0
ic1		DCB	"Parent directories",0
ic2		DCB	AUTHOR,0
ic3		DCB	"Freeware",0
ic4		DCB	VERSION,0

WINBLOCKSIZE	EQU	about-info_window
		ASSERT	WINBLOCKSIZE <= SIZE-BUFF1

		ALIGN

; ****************
; Module task code
; ****************

RM_Start	LDR	R6, [R12]	;R6: pointer to workspace.

		LDR	R0, [R6]	;Task handle or 0.
		TEQ	R0, #0
		LDRNE	R1, task	;"TASK".
		SWINE	Wimp_CloseDown
		MOVNE	R0, #0
		STRNE	R0, [R6]	;Reset task handle.

		MOV	R0, #300	;Last Wimp version known: 3.00.
		LDR	R1, task	;"TASK".
		ADR	R2, RM_Title
		ADR	R3, messages	;List of the accepted user messages.
		SWI	XWimp_Initialise
		LDRVS	R1, task	;If init failed, try ROS 2.00...
		MOVVS	R0, #200
		SWIVS	XWimp_Initialise
		ADRVS	R3, RM_Title
		SWIVS	OS_ExitAndDie
		STR	R1, [R6]	;Store task handle.

		ADR	R0, info_window	;Create the info window...
		ADD	R1, R6, #BUFF1
		MOV	R2, #WINBLOCKSIZE
copy_winblock	LDR	R3, [R0], #4
		SUBS	R2, R2, #4
		STR	R3, [R1], #4
		BNE	copy_winblock
		ADR	R0, about
		STR	R0, [R6, #BUFF1+title_data-info_window]
ref		ADR	R1, ref
		ADD	R0, R6, #BUFF1+icons+20-info_window
		MOV	R2, #5
addref_loop	LDMIA	R0, {R3,R4}
		SUBS	R2, R2, #1
		ADD	R3, R3, R1
		ADD	R4, R4, R1
		STMIA	R0, {R3,R4}
		ADD	R0, R0, #32
		BNE	addref_loop
		ADD	R1, R6, #BUFF1
		SWI	Wimp_CreateWindow
		STR	R0, [R6, #WHANDLE]

		MOV	R0, #0
		ADR	R1, event_rout
		STRB	R0, [R6, #CBFLAG] ;cbflag = false.
		MOV	R0, #EventV
		MOV	R2, R6
		SWI	OS_Claim	;Claim the Event vector.

		MOV	R0, #14
		MOV	R1, #MouseEvent
		SWI	OS_Byte		;Enable mouse event.

; Wimp_Poll loop...

loop		MOV	R0, #&31	;Mask: &3831.
		ORR	R0, R0, #&3800
		ADD	R1, R6, #BUFF1	;256-byte block.
		SWI	XWimp_Poll
		SWIVS	OS_ExitAndDie
		TEQ	R0, #UsrMsg	;UserMessage?
		TEQNE	R0, #UsrMsgRec	;UserMessage_Recorded?
		BNE	next1		;No, branch.
		LDR	R0, [R1, #16]	;Message code.
		RSBS	R2, R0, #1	;Quit?
ifquit		ADRHI	R3, RM_Title	;Die if quit.
		SWIHI	OS_ExitAndDie
		SUB	R0, R0, #&40000
		TEQ	R0, #&C3	;TaskCloseDown?
		LDREQ	R2, [R1, #4]	;Yes, handle of task closing down,
		ADREQ	R5, loop	;return address,
		BEQ	remove_task	;and call remove_task.
		TEQ	R0, #&C2	;TaskInitialise?
		BNE	loop		;No, loop.
		LDR	R5, [R6, #BUFF1+4] ;Task handle of the starting app.
		LDR	R0, [R6]	;Task handle of TitleMenu.
		MOV	R1, R5, LSL #16
		TEQ	R1, R0, LSL #16
		MOVEQ	R2, #16
		STREQB	R2, [R6, #INIT]	;Set init flag if handles are the same.
		LDR	R0, [R6, #MODE]	;TitleMenu mode and init flag.
		TST	R0, R0, LSR #24	;Branch if not initialised yet or
		BEQ	loop		;if the Obey$Dir list isn't used.
		ADD	R1, R6, #BUFF1+8
		MOV	R2, #248
		MOV	R3, #0
		ADR	R0, obeydir	;"Obey$Dir".
		MOV	R4, #0
		SWI	XOS_ReadVarVal	;Read the Obey$Dir variable.
		BVS	loop		;Loop if variable doesn't exist.
		MOVS	R4, R2		;Variable length.
		BEQ	loop		;Loop if 0.
		MOV	R0, #6
		ADD	R3, R4, #9
		SWI	XOS_Module	;Memory block for the variable.
		BVS	loop		;Loop if error.
		LDR	R0, [R6, #ODLIST] ;Pointer to the Obey$Dir list.
		STR	R2, [R6, #ODLIST] ;New pointer to the Obey$Dir list.
		STMIA	R2!, {R0,R5}	;Store ptr to next cell and handle.
obeydir_loop	LDRB	R0, [R1], #1	;Copy the variable value...
		SUBS	R4, R4, #1
		STRB	R0, [R2], #1
		BNE	obeydir_loop
		STRB	R4, [R2]	;Null byte after the variable value.
		B	loop

next1		TEQ	R0, #OpenW	;Open Window?
		SWIEQ	Wimp_OpenWindow
		BEQ	loop
		TEQ	R0, #CloseW	;Close Window?
		SWIEQ	Wimp_CloseWindow
		BEQ	loop

		TEQ	R0, #MenuSel	;Menu Selection?
		BNE	next2
		LDR	R9, [R1]	;Item number.
		SWI	XWimp_GetPointerInfo
		BVS	selection
		LDR	R3, [R1, #PIBS]
		TST	R3, #1		;Click with Adjust?
		BLNE	create_menu	;Yes, the menu remains open.
selection	SUBS	R9, R9, R11
		BHI	ifquit		;Die if quit.
		LDRNEB	R0, [R6, #HFLAG] ;R0+R9 == 0 --> help item.
		BNE	opendir		;Branch if directory or help item.
		ADR	R0, run_help	;Click on "Info".
		SWI	XWimp_StartTask
		B	loop

run_help	DCB	"/<",NAME,"$Dir>.!Help",0
		ALIGN

next2		SUBS	R0, R0, #MClick	;Mouse click?
		BNE	loop		;No, loop.
		STRB	R0, [R6, #CBFLAG] ;cbflag = false.
		LDR	R0, [R1, #PIIH]	;Icon handle.
		MOV	R2, #-2
		TEQ	R2, R0, ASR #1	;Click on a title bar or a close icon?
		BEQ	title_bar	;Yes, branch.
		BICS	R2, R0, #2	;Click on the name or the author?
		BNE	loop		;No, loop.
		TEQ	R0, #0
		MOVNE	R5, #urle1-url	;... if click on the author.
		MOVEQ	R5, #urle2-url	;... if click on the name.
		ADD	R4, R5, #16
		BIC	R4, R4, #3
		ADR	R3, url
		STR	R4, [R1]	;Length of block.
		ADD	R4, R1, #12
copy_url	LDRB	R0, [R3], #1
		SUBS	R5, R5, #1
		STRB	R0, [R4], #1
		BNE	copy_url
		STRB	R2, [R4]	;0.
		MOV	R0, #UsrMsg
		SWI	XWimp_SendMessage ;Broadcast...
		B	loop

; Click with Menu on a title bar or a close icon...

title_bar	MOV	R10, R0		;-4 if title bar, -3 if close icon.
		LDR	R7, [R6, #PWH]	;R7: handle of window under pointer.
		ADD	R1, R6, #TB	;Temporary buffer.
		MOV	R0, #20
		STR	R0, [R1]	;Length of block.
		MOV	R0, #0
		STR	R0, [R1, #12]	;Your ref = 0.
		MOV	R2, R7
		MOV	R0, #UsrMsgAck
		SWI	XWimp_SendMessage
		BVS	loop
		MOV	R8, R2		;R8: task handle of app under pointer.
		ADD	R1, R6, #PWH+1
		SWI	XWimp_GetWindowInfo
		BVS	loop
		LDR	R0, [R1, #51]	;Work area maximum x.
		CMP	R0, #1<<18
		BLT	window_ok	;Branch if < 2^18 (not a menu).
		LDR	R0, [R1, #31]	;Window flags.
		TST	R0, #3<<24	;Z = 0 if back icon or close icon.
		LDREQB	R0, [R1, #64]	;Window button type.
		TSTEQ	R0, #&F0	;Z = 1 if button type = 0.
		BEQ	loop		;Branch if window is a menu.

; The window under the mouse pointer isn't a menu.
; R7 = window handle. R8 = task handle.
; R10 = -4 if click on title bar, -3 if click on close icon.

window_ok	LDRB	R9, [R6, #MODE]	;R9 = mode.
		TST	R9, #8		;Special key flag?
		BNE	get_file	;Branch if disabled.
		LDRB	R1, [R6, #KEY]	;Special key.
		MOV	R0, #121
		ORR	R1, R1, #&80
		SWI	XOS_Byte	;Keyboard scan.
		BVS	get_file	;Branch if error.
		TEQ	R1, #&FF	;If key pressed:
		EOREQ	R9, R9, #2	;toggle the preferred menu flag.
get_file	BL	menu_pref	;Preferred menu?
		TST	R9, #&80000004
		BMI	file_ok		;Branch if OK.
		BNE	loop		;Branch if secondary menu disabled.
		BL	menu_sec	;Secondary menu?
		TST	R9, #&80000000
		BPL	loop		;Branch if not OK.

; The directory name is in R6 + #FNAME; R3 points to the null byte after it.

file_ok		CMP	R10, #-4
		BEQ	make_menu	;Branch if click on the title bar.

; Click on the close icon...

		MOV	R0, #17
		ADD	R1, R6, #FNAME
		SWI	XOS_File	;Object type.
		BVS	loop		;Loop if error.
		CMP	R0, #2
		BCC	loop		;Loop if not a directory.
		MOV	R9, #-1		;R9 = -1 --> first parent. R0 <> 1.

; Open a directory...

opendir		ADD	R1, R6, #BUFF1
		CMN	R0, R9		;Help item?
		ADREQ	R0, frun	;Yes, copy "Filer_Run "...
		ADRNE	R0, fod		;No, copy "Filer_OpenDir "...
filer_loop	LDRB	R3, [R0], #1
		TEQ	R3, #0
		STRNEB	R3, [R1], #1
		BNE	filer_loop
		ADD	R0, R6, #FNAME
		MOV	R4, #'.'
dir_loop	LDRB	R3, [R0], #1	;Copy the filename...
		STRB	R3, [R1], #1
		TEQ	R3, #0
		BNE	dir_loop
		ADDS	R9, R9, #1
		STRNEB	R4, [R1, #-1]	;Directory separator.
		BNE	dir_loop
		ADD	R0, R6, #BUFF1
		SWI	XWimp_StartTask	;Exec Filer_OpenDir or Filer_Run...
		B	loop

; Click on the title bar...

make_menu	TEQ	R7, #0		;!Help file?
		MOV	R11, #1		;R11 will contain the number of dirs.
		MOV	R10, R3		;Ptr to null byte after the filename.
		MOV	R9, R3		;Ptr to null byte after the filename.
		BNE	is_directory	;Branch if no !Help file.

fname_loop	LDRB	R0, [R9, #-1]!	;Previous character.
		TEQ	R0, #':'
		BEQ	no_more_dir	;Branch if ':'.
		SUBS	R0, R0, #'.'
		BNE	fname_loop	;Loop until '.' (directory separator).
		LDRB	R2, [R9, #1]	;First char of last directory leafname.
		TEQ	R11, #N-2	;Maximum number of directories?
		TEQNE	R2, #'$'	;or last directory = '$'?
		BEQ	no_more_dir	;Yes, branch.
		STRB	R0, [R9]	;Replace the '.' with a null byte.
		ADD	R11, R11, #1
is_directory	MOV	R0, #17
		ADD	R1, R6, #FNAME
		SWI	XOS_File	;Object type.
		BVS	not_found	;Branch if error.
		CMP	R0, #2
		BCS	fname_loop	;Loop while file found.
not_found	MOV	R0, #'.'	;File not found...
		STRB	R0, [R9]	;Restore the '.'
		SUBS	R11, R11, #1	;and the number of directories.
		BEQ	loop		;Loop if no directory.
no_more_dir	MOV	R1, #-1		;Close any menu (useful if a TitleMenu
		SWI	XWimp_CreateMenu ;menu is already open).
		ADR	R1, menu
		ADD	R0, R6, #MENU
		LDMIA	R1!, {R2-R5}	;Copy the beginning of the menu block...
		STMIA	R0!, {R2-R5}
		LDMIA	R1!, {R2-R5}	;R5 = &07000121 (for the first items).
		STMIA	R0!, {R2-R4}
		MOV	R4, #-1
		STRB	R4, [R6, #HFLAG]
menu_loop1	LDRB	R3, [R10, #-1]!
		TEQ	R9, R10
		TEQNE	R3, #0
		BNE	menu_loop1
		TEQ	R7, #0		;Help item?
		STREQB	R11, [R6, #HFLAG]
		MOVNE	R3, #0		;No.
		MOVEQ	R3, #2		;Yes.
		STMIA	R0!, {R3-R5}	;0, -1, &07000121.
		ADD	R2, R10, #1
		ADDEQ	R2, R2, #1	;... if "!Help" item.
		MOVEQ	R7, #1
		STMIA	R0!, {R2-R4}	;Ptr to dirname, 0, -1.
		TEQ	R9, R10
		BNE	menu_loop1
		MOV	R3, #2
		STR	R3, [R0, #-24]
		LDR	R14, [R6, #WHANDLE]
		MOV	R5, #4		;Copy the last two items...
menu_loop2	LDMIA	R1!, {R2-R4}
		STMIA	R0!, {R2-R4}
		SUBS	R5, R5, #1
		BNE	menu_loop2
		STR	R14, [R0, #-44]	;Handle of info window.
		ADR	LR, loop	;Return address for create_menu...

create_menu	LDR	R7, [R6, #BUFF1+PIMX]
		LDR	R8, [R6, #BUFF1+PIMY]
		ADD	R1, R6, #MENU
		SUB	R2, R7, #64
		SUB	R3, R8, #16
		SWI	XWimp_CreateMenu
		MOV	PC, LR

; *********
; Menu data
; *********

menu		DCB	NAME
		%	12-:LEN:NAME
		DCB	7,2,7,0		;Colours.
		DCD	150,44		;Width and height of menu items.
		DCD	0		;Vertical gap.
		DCD	&07000121
menu_info	DCD	0,0,&07000021
		DCB	"Info",0,0,0,0,0,0,0,0
		DCD	&80,-1,&07000021
		DCB	"Quit",0,0,0,0,0,0,0,0

; *********************************
; get_titlefile routine (user mode)
; *********************************

; R0-R5 and R11 may be corrupted. If OK, return with MSB(R9) = 1
; and R3 = pointer to the null byte after the directory name. If
; not, the window block mustn't be altered.

menu_pref	TST	R9, #2		;Preferred menu...
		BNE	get_appdir
get_titlefile	LDR	R0, [R6, #PWH+60] ;Title bar icon flags.
		TST	R0, #1		;Does icon contain text?
		TSTNE	R0, #1<<8	;and is icon indirected?
		MOVEQ	PC, LR		;No, return.

; Indirected title icon containing text...

		LDR	R1, [R6, #PWH+76] ;Pointer to window title.
		MOV	R0, R8		;Task handle of window owner.
		LDR	R2, [R6]	;Task handle of TitleMenu.
		ADD	R3, R6, #FNAME	;Buffer for the filename.
		MOV	R4, #0
		MOV	R5, #FNL-4
clr_buffer	STR	R4, [R3, R5]	;Clear the buffer.
		SUBS	R5, R5, #4
		BCS	clr_buffer
		MOV	R4, #FNL-1	;Buffer length - 1.
		SWI	XWimp_TransferBlock ;Get the window title.
		MOVVS	PC, LR

; R3: window title.
; Test if the first word can be a filename with full path (':' in it).

firstword	LDRB	R0, [R3], #1
		TEQ	R0, #':'
		MOVEQS	R4, #0
		CMP	R0, #' '
		BHI	firstword	;Loop until control or space character.
		TEQ	R4, #0
		MOVNE	PC, LR		;Return if no ':'.

rm_leafname	LDRB	R0, [R3, #-1]!	;Remove the leafname...
		TEQ	R0, #':'
		TEQNE	R0, #'$'
		MOVEQ	PC, LR		;Return if ':' or '$'.
		SUBS	R0, R0, #'.'
		BNE	rm_leafname	;Loop until '.' (directory separator).
		STRB	R0, [R3]	;Replace the '.' with a null byte.
		ORR	R9, R9, #1<<31
		MOV	PC, LR

; ******************
; TitleMenuMode code
; ******************

Mode		LDR	R12, [R12, #0]	;R12: pointer to workspace.
		MOV	R5, LR
		TEQ	R1, #0
		BNE	set_mode
		LDRB	R0, [R12, #MODE] ;Display the mode...
		ADD	R1, R12, #BUFF1
		MOV	R2, #16
		SWI	XOS_ConvertCardinal1
		SWIVC	XOS_Write0
		SWIVC	XOS_NewLine
		MOV	PC, R5

set_mode	MOV	R1, R0		;Set the mode...
		MOV	R0, #10+(6<<29)
		SWI	XOS_ReadUnsigned
		STRVCB	R2, [R12, #MODE]
		MOV	PC, R5

; ******************
; TitleMenuSKey code
; ******************

SKey		LDR	R12, [R12, #0]	;R12: pointer to workspace.
		MOV	R5, LR
		TEQ	R1, #0
		BNE	set_skey
		LDRB	R0, [R12, #KEY]	;Display the special key...
		ADD	R1, R12, #BUFF1
		MOV	R2, #16
		SWI	XOS_ConvertCardinal1
		SWIVC	XOS_Write0
		SWIVC	XOS_NewLine
		MOV	PC, R5

set_skey	MOV	R1, R0		;Set the special key...
		MOV	R2, #&7F	;Must be in the range [0,&7F].
		MOV	R0, #10+(5<<29)
		SWI	XOS_ReadUnsigned
		STRVCB	R2, [R12, #KEY]
		MOV	PC, R5

; ******************************
; get_appdir routine (user mode)
; ******************************

; R0-R5 and R11 may be corrupted. If OK, return with MSB(R9) = 1,
; R3 = pointer to the null byte after the directory name and R7 = 0
; if the !Help exists. If not, the window block mustn't be altered.

menu_sec	TST	R9, #2		;Secondary menu...
		BNE	get_titlefile
get_appdir	TST	R9, #16		;Use Obey$Dir list?
		BEQ	use_taskname	;No, branch.
		ADD	R2, R6, #ODLIST
		MOV	R0, R8, LSL #16
appdir_loop	LDR	R2, [R2, #0]	;Read pointer to next cell.
		TEQ	R2, #0
		BEQ	use_taskname	;Branch if no more cell.
		LDR	R1, [R2, #4]	;Task handle.
		TEQ	R0, R1, LSL #16
		BNE	appdir_loop	;Loop until task handle found.
		ADD	R1, R6, #FNAME
		ADD	R2, R2, #8
		MOV	R11, R1
copy_obeydir	LDRB	R0, [R2], #1	;Copy dirname.
		TEQ	R0, #0
		STRNEB	R0, [R11], #1
		BNE	copy_obeydir
		B	appdir_end

use_taskname	MOV	R0, R8		;Task handle of app under mouse pointer.
		SWI	XTaskManager_TaskNameFromHandle ;R0: task name.
		MOVVS	PC, LR
		ADD	R1, R6, #TB	;Temporary buffer for the variable name.
		MOV	R3, #TBSIZE-1-:LEN:SDDIR
copy_taskname	LDRB	R2, [R0], #1
		SUBS	R3, R3, #1
		MOVCC	PC, LR		;Return if task name too long.
		CMP	R2, #' '
		STRHIB	R2, [R1], #1	;Copy unless space or control char.
		BCS	copy_taskname	;Loop until control character.
		ADR	R0, dir
copy_dir	LDRB	R2, [R0], #1	;Copy "$Dir".
		STRB	R2, [R1], #1
		TEQ	R2, #0
		BNE	copy_dir
		ADD	R0, R6, #TB	;Pointer to variable name.
		ADD	R1, R6, #FNAME	;Buffer for the value (filename).
		MOV	R2, #FNL-1-:LEN:PHELP
		MOV	R3, #0
		MOV	R4, #3
		SWI	XOS_ReadVarVal	;Read variable <taskname>$Dir.
		MOVVS	PC, LR
		ADD	R11, R1, R2	;Pointer to end of variable value.

; Note: R3 <> 0. R1: ptr to dirname. R11: ptr to first byte after dirname.

appdir_end	ADR	R0, help
copy_help	LDRB	R2, [R0], #1	;Copy ".!Help".
		STRB	R2, [R11], #1
		TEQ	R2, #0
		BNE	copy_help
vfy_dir		LDRB	R0, [R1], #1
		TEQ	R0, #':'
		MOVEQ	R3, #0
		CMP	R0, #' '	;Loop until space or control char
		BHI	vfy_dir		;or end of variable value.
		ORRS	R0, R0, R3
		MOVNE	PC, LR		;Return if not a filename.
		ORR	R9, R9, #1<<31
		CMP	R10, #-3	;!Help only if click on title bar...
		MOVNE	R0, #17
		ADDNE	R1, R6, #FNAME
		SWINE	XOS_File	;File !Help found?
		MOVVS	R0, #0		;R0 = 0 if error.
		SUB	R3, R11, #1	;Pointer to null byte after ".!Help".
		TEQNE	R0, #0
		MOVNE	R7, #0		;R7 = 0 if !Help file found.
		STREQB	R0, [R3, #-:LEN:PHELP]! ;No help if file not found.
		MOV	PC, LR

; ****
; Data
; ****

frun		DCB	"Filer_Run ",0
		ALIGN
fod		DCB	FOD,0
dir		DCB	SDDIR,0
help		DCB	PHELP,0

		END
