;-------------------------------------------------------------------------------
; FATware - firmware and file system driver for ZX Spectrum divIDE interface
; Copyright (c) 2005-2009 Milos Bazelides (baze)
;-------------------------------------------------------------------------------
; This software is provided "as is" without warranties or conditions of any
; kind, either express or implied. In no event shall the author(s) be held
; liable for any damages arising from the use of this software.
; See accompanying "licence.txt" file for copyright and terms of use.
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
InitGui:
;-------------------------------------------------------------------------------

	call	LstResetPagePos
	xor	a
	ld	(MnuPos),a
	call	LstEnterDir
	ret

;-------------------------------------------------------------------------------
SelectVolume:
;-------------------------------------------------------------------------------

	; generate list of rows based on number of volumes

	ld	hl,MnuBuffer
	push	hl
	ld	a,(SysNumVolumes)
$$	ld	(hl),MNI_TEXT
	inc	hl
	dec	a
	jr	nz,$b
	ld	(hl),a

	pop	hl
	ld	de,SelVolDef
	ld	a,(SelVolPos)
	ld	(MnuPos),a
	call	InitMenu

	ld	hl,SelVolCaption
	call	DrawMenuFrame

	; now iterate through volumes and set item texts

	ld	ix,VolDesc
	xor	a
VolLoop	push	af

	xor	a
	ld	(FileName + 3),a
	ld	h,a
	ld	l,a
	rst	30h
	dw	OpenDir
	jr	c,$f

	; find volume ID

	ld	bc,0808h
	rst	30h
	dw	ReadDirEntry
	rst	30h
	dw	FileClose		; MUST NOT CHANGE CARRY !!!
	jr	c,$f

	ld	de,FileName + 10
	ld	hl,FileName + 7
	ld	bc,8
	lddr

$$	ld	a,(ix + vdLetter)
	ld	(FileName),a
	ld	hl,' ' * 256 + ':'
	ld	(FileName + 1),hl

	pop	af
	push	af
	ld	c,0
	ld	hl,FileName
	call	SetItemText

	pop	af
	ld	bc,vdSizeOf
	add	ix,bc
	ld	hl,SysNumVolumes
	inc	a
	cp	(hl)
	jr	c,VolLoop

$$	call	WaitForEvent		; wait for GUI event
	cp	CHR_BREAK
	ret	z
	cp	CHR_ENTER
	jr	nz,$b

	; TODO: make this independent of successive volume letters?

	ld	a,(MnuPos)
	ld	(SelVolPos),a
	add	a,'C'
	rst	30h
	dw	FindVolume
;	ret	c

	ld	(SysCurrVolume),hl

	call	InitGui			; !!!
	ret

;-------------------------------------------------------------------------------
BrowserRedraw:
;-------------------------------------------------------------------------------

	; open current directory (return if there is no free descriptor)

	ld	ix,(SysCurrVolume)
	rst	30h
	dw	OpenCurrentDir
;	ret	c

;	ld	de,(BrwPagePos)		; needed?
;	inc	e
;	call	SetFilePos

	ld	hl,BrwMenuRows
	ld	de,BrwDef
;	ld	a,(MnuPos)
	call	InitMenu

;-------------------------------------------------------------------------------
BrowserPage:
;-------------------------------------------------------------------------------

	ld	hl,BrwCaption
	call	DrawMenuFrame
	call	ListPage

;-------------------------------------------------------------------------------
BrowserEvent:
;-------------------------------------------------------------------------------

	; update status bar

	call	GetCachedEntryAddr
	ld	a,(hl)			; read attributes

	ld	hl,FileName + 6		; use FileName buffer to generate text
	call	MakeAttrString
	ld	c,0
	ld	a,20
	call	SetItemText

	call	WaitForEvent		; wait for GUI event

Event	cp	CHR_DOWN
	jr	nz,BrwRigh

	; don't allow cursor past EOF

	call	GetCachedEntryAddr
	ld	a,(hl)			; read attributes
	inc	a
	call	z,CursorUp
	jr	BrowserEvent

BrwRigh	;cp	CHR_RIGHT
;	jr	nz,BrwLeft
;	jr	BrowserPage

;BrwLeft	cp	CHR_LEFT
;	jr	nz,BrwPgDw
;	jr	BrowserPage

BrwPgDw	cp	CHR_PAGE_DOWN
	jr	nz,BrwPgUp

;	call	IsEOF			; precizny EOF na dire nezafunguje ;/
;	jr	nz,$f
;	call	CursorUp
;	jr	BrowserEvent

$$	call	LstNextPage
	jr	BrowserPage

BrwPgUp	cp	CHR_PAGE_UP
	jr	nz,BrwBrk

	; don't page up on a dir break

	ld	hl,(BrwPagePos)
	ld	a,(hl)
	inc	a
	jr	nz,$f
	call	LstPageUp
	jr	BrowserPage

$$	call	CursorDown
	jr	BrowserEvent

	; both BREAK and ENTER require FileClose

BrwBrk	rst	30h
	dw	FileClose		; MUST NOT CHANGE A !!!

	cp	CHR_BREAK
	ret	z

	cp	'<'			; SS + R
	jr	nz,$f
	rst	0

$$	cp	'"'			; SS + P	;enter pokes!
	jr	nz,$f
	call	PokeMe
	jp	BrowserRedraw


$$	cp	CHR_EDIT
	jr	nz,$f
	call	SelectVolume
	jr	BrowserRedraw

$$	cp	CHR_ENTER
	jr	z,$f
	cp	CHR_SYMB_ENTER
	jr	nz,BrowserEvent

	; is it a directory?

$$	call	GetCachedEntryAddr
	ld	a,(hl)
	dec	l
	and	ATR_DIRECTORY
	ld	a,(hl)			; get file type
	jr	z,BrowserSelect

	; change volume's current directory

	inc	l
	inc	l
	ld	c,(hl)
	inc	l
	ld	b,(hl)
	ld	(ix + vdDirClus + 0),c
	ld	(ix + vdDirClus + 1),b

	; is it ".."?

	sub	FT_DIR_UP
	ld	hl,(BrwPagePos)
	jr	z,$f
	call	LstSubDir
	jp	BrowserRedraw

$$	call	LstDirUp
	jp	BrowserRedraw

;-------------------------------------------------------------------------------
BrowserSelect:
;-------------------------------------------------------------------------------

	inc	l

$$	cp	FT_TAP
	jr	nz,$f

	ld	iy,(SysTapFD)
	rst	30h
	dw	FileClose		; it's OK even if SysTapFD = 0
	rst	30h
	dw	FileOpenRaw
	jp	c,BrowserEvent
	ld	(SysTapFD),iy

	ld	a,(GuiPrevKey)
	cp	CHR_SYMB_ENTER
	ret	nz
	rst	0

$$	cp	FT_SNA
	jr	nz,$f

	rst	30h
	dw	FileOpenRaw
	call	LoadSNA
	; show warning
	jp	BrowserRedraw

$$	cp	FT_Z80
	jr	nz,$f

	rst	30h
	dw	FileOpenRaw
	call	LoadZ80
	; show warning
	jp	BrowserRedraw

$$	cp	FT_SCR
	jr	nz,$f

	rst	30h
	dw	FileOpenRaw
	call	LoadSCR
	jp	BrowserPage

$$	jp	BrowserEvent

;-------------------------------------------------------------------------------
LstResetPagePos:
;-------------------------------------------------------------------------------

	ld	hl,BrwPageHistory
	ld	(BrwPagePos),hl
	ret

;-------------------------------------------------------------------------------
LstAdvancePagePos:
;-------------------------------------------------------------------------------

	ld	hl,BrwPagePos
	ld	a,(hl)
	add	a,8
	jr	c,$f
	ld	(hl),a
	ret

	; scroll buffer on overflow

$$	ld	de,BrwPageHistory
	ld	hl,BrwPageHistory + 8	; sizeof dependent!
	ld	bc,256 - 8
	ldir
	ret

;-------------------------------------------------------------------------------
LstSubDir:
;-------------------------------------------------------------------------------

	; file descriptor is closed at this point
	; TODO: restore PagePos if OpenCurrentDir fails

	call	LstAdvancePagePos

;-------------------------------------------------------------------------------
LstEnterDir:
;-------------------------------------------------------------------------------

	ld	ix,(SysCurrVolume)
	rst	30h
	dw	OpenCurrentDir
;	ret	c

	; skip "." entry for non-root directories (TODO: call IsRootDir)

	ld	a,(iy + fdClus + 0)
	or	(iy + fdClus + 1)
	jr	z,$f
	rst	30h
	dw	ReadDirEntry
;	ret	c

	; store parent cursor position

$$	ld	hl,(BrwPagePos)
	ld	a,(MnuPos)
	ld	(hl),a
	inc	l
	ex	de,hl
	call	GetFilePos

	xor	a
	ld	(MnuPos),a
	rst	30h
	dw	FileClose		; file will get opened again on redraw
	ret

;-------------------------------------------------------------------------------
LstNextPage:
;-------------------------------------------------------------------------------

	call	LstAdvancePagePos

	ld	hl,(BrwPagePos)
	ld	(hl),255		; no directory break
	inc	l
	ex	de,hl			; TODO: use HL as input for GetFilePos?
	call	GetFilePos
	ret

;-------------------------------------------------------------------------------
LstPageUp:
;-------------------------------------------------------------------------------

	; move one entry back if we are not already on top

	ld	hl,BrwPagePos
	ld	a,(hl)
	or	a
	jr	z,$f
	sub	8
	ld	(hl),a
	ret

$$	rst	30h
	dw	FileClose
	call	LstEnterDir
	rst	30h
	dw	OpenCurrentDir	; only needed for BrowserPage
	ret

;-------------------------------------------------------------------------------
LstDirUp:
;-------------------------------------------------------------------------------

	; restore saved cursor position (default 1)

	ld	hl,(BrwPagePos)
	ld	a,(hl)
	ld	(MnuPos),a

	; estabilish a fresh buffer if we are already at the top of buffer
	; (buffer might got scrolled so saved cursor position is no longer valid)

	ld	a,l
	or	a
	jr	z,LstEnterDir
	sub	8
	ld	(BrwPagePos),a
	ret

;-------------------------------------------------------------------------------
ListPage:
;-------------------------------------------------------------------------------

	ld	de,(BrwPagePos)
	inc	e
	call	SetFilePos

	; display one page worth of directory entries

	ld	hl,BrwEntryCache
	ld	(BrwEntryAddr),hl

	xor	a
ReadEnt	push	af

	ld	bc,0800h		; read everything except volume ID
	rst	30h
	dw	FindDirEntry
	jr	nc,PrnEnt

;	or	a
;	jr	nz,...

	; NULL file name and extension and use invalid attribute FFh as marker

	ld	(FileName),a
;	ld	(DirEntry + dirExt),a
	dec	a
	ld	(DirEntry + dirAttr),a
	ld	hl,TxtNULL
	jr	$f

	; display either "directory" or file size

PrnEnt	ld	hl,TxtDirectory
	ld	a,(DirEntry + dirAttr)
	and	ATR_DIRECTORY
	jr	nz,$f

	ld	hl,(DirEntry + dirFileSize + 0)
	ld	de,(DirEntry + dirFileSize + 2)
	ld	a,' '
	rst	30h
	dw	Num32ToASCII
	ld	hl,SysNumber		; include into Num32ToASCII?

$$	pop	af
	push	af
	ld	c,1
	call	SetItemText

	; cache dir entry attributes, size, cluster and file type

	ld	hl,DirEntry + dirAttr
	ld	a,(hl)
	ex	af,af'
	xor	a
	ld	(hl),a			; ASCIIZ-e short extension

	; test for ".."

	ld	hl,(FileName)
	ld	bc,2E2Eh
	sbc	hl,bc
	ld	b,FT_DIR_UP
	jr	z,$f

	; determine file type

	dec	b
	ld	hl,FilExts
CmpExt	push	hl
	ld	de,DirEntry + dirExt
	call	StrCmpNoCase
	pop	hl
	jr	z,$f
	ld	de,4
	add	hl,de
	djnz	CmpExt

$$	ld	hl,(BrwEntryAddr)
	ld	(hl),b
	inc	l
	ex	af,af'
	ld	(hl),a	
	inc	l

	ex	de,hl
	ld	hl,DirEntry + dirFstClusLo
	ld	bc,6
	ldir
	ld	(BrwEntryAddr),de

	; display file name

	pop	af
	push	af
	ld	c,0
	ld	hl,FileName
	call	SetItemText

	pop	af
	inc	a
	cp	19
	jp	c,ReadEnt
	ret

;-------------------------------------------------------------------------------
GetCachedEntryAddr:
;-------------------------------------------------------------------------------

	ld	a,(MnuPos)
;	dec	a
	add	a,a			; entry index * 8 (FAT16-specific)
	add	a,a
	add	a,a
	ld	h,>BrwEntryCache
	ld	l,a
	inc	l			; saves some bytes in code
	ret

;-------------------------------------------------------------------------------
MakeAttrString:
;-------------------------------------------------------------------------------
; Input:
; A - file attributes byte
; HL - string buffer address + 6
;-------------------------------------------------------------------------------

	ld	(hl),0
	ld	de,AtrChar
	ld	c,a
	ld	b,3
$$	call	AtrStor
	djnz	$b
	rr	c
	call	AtrStor
AtrStor	rr	c
	ld	a,(de)
	inc	de
	jr	c,$f
	ld	a,'-'
$$	dec	l
	ld	(hl),a
	ret

AtrChar	db	"RHSDA"

FT_DIR_UP	equ	5	; special file type for ".." (must be first)
FT_TAP		equ	4
FT_SNA		equ	3
FT_Z80		equ	2
FT_SCR		equ	1
FT_NONE		equ	0

FilExts	db	"TAP", 0	; mind the same order as in enum!
	db	"SNA", 0
	db	"Z80", 0
	db	"SCR", 0

;-------------------------------------------------------------------------------
ShowCursor:
;-------------------------------------------------------------------------------

	ld	a,(MnuPos)
	call	GetLineAddr
	inc	l
	ld	(MnuCursorAddr),hl
	push	hl

	; save underlying attributes

	ld	de,MnuAttrBuf
	call	AtrLdir

	; draw cursor

	pop	de
	ld	hl,(MnuColumnAddr)

DrawCur	ld	b,(hl)
	inc	hl
	ld	a,PAP_CYAN | INK_BLACK
$$	ld	(de),a
	inc	e
	djnz	$b

	ld	a,(hl)
	inc	a
	ret	z

	ld	a,PAP_CYAN | INK_WHITE
	ld	(de),a
	inc	e
	jr	DrawCur

;-------------------------------------------------------------------------------
HideCursor:
;-------------------------------------------------------------------------------

	; restore original item attributes

	ld	hl,MnuAttrBuf
	ld	de,(MnuCursorAddr)
AtrLdir	ld	a,(MnuTextWidth)
	ld	b,0
	ld	c,a
	ldir
	ret

;-------------------------------------------------------------------------------
SetItemText:
;-------------------------------------------------------------------------------
; A - row number
; C - column number
; HL - string address
;-------------------------------------------------------------------------------

	; TO DO: sanity check if line is not separator or edit box

	; TODO: colours based on menu item type

	push	hl
	push	af
	call	GetLineAddr

	ld	de,(MnuColumnAddr)
	inc	c
$$	inc	l			; skip left frame / column separator
	dec	c
	jr	z,$f
	ld	a,(de)
	add	a,l
	ld	l,a
	inc	de
	jr	$b

$$	call	AttrToScr
	ld	(SysCursor),hl

	pop	af
	call	GetRowType
	push	af

	and	MNF_MASK
	cp	MNI_BOLD
	ld	a,PAP_WHITE | INK_BLACK | BRIGHT
	jr	nz,$f
	ld	a,PAP_WHITE | INK_RED | BRIGHT
$$	ld	(SysColour),a

	pop	af
	and	MNF_TABBED
	ld	a,(de)			; load column width
	jr	nz,$f
	ld	a,(MnuTextWidth)
$$	ld	b,a
	pop	hl

	ld	de,TempStr			;space in ram to copy rom message as rom will be switched for drawstring routine
;	ld	a,(MnuTextWidth)
	ld	c,a
	ld	b,0
	ldir					
	ld b,a
	ld hl,TempStr

	rst	30h
	dw	PrintString
	ret

;-------------------------------------------------------------------------------
CursorDown:
;-------------------------------------------------------------------------------

	ld	a,(MnuPos)
	inc	a			; this sets non-zero
	ld	hl,MnuRowCount
	cp	(hl)
	jr	nc,PageDwn
	ld	(MnuPos),a

	call	GetRowType
	and	MNF_UNSEL
	jr	nz,CursorDown
	ret

PageDwn	ld	a,(MnuFirstItem)
	ld	(MnuPos),a
	ld	a,CHR_PAGE_DOWN
	or	a			; set non-zero on exit
	ret

;-------------------------------------------------------------------------------
CursorUp:
;-------------------------------------------------------------------------------

	ld	a,(MnuPos)
	sub	1			; sets non-zero on exit
	jr	c,PageUp
	ld	(MnuPos),a

	call	GetRowType
	and	MNF_UNSEL		; skip unselectable items
	jr	nz,CursorUp
	ret

PageUp	ld	a,(MnuLastItem)
	ld	(MnuPos),a
	ld	a,CHR_PAGE_UP
	ret

;-------------------------------------------------------------------------------
GetRowType:
;-------------------------------------------------------------------------------

	ld	hl,(MnuRowAddr)
	add	a,l
	ld	l,a
	jr	nc,$f
	inc	h
$$	ld	a,(hl)
	ret

;-------------------------------------------------------------------------------
InitMenu:
;-------------------------------------------------------------------------------
; Input:
; A - starting cursor position
; HL - address of the (possibly dynamic) row buffer
; DE - address of the other static menu definition
;-------------------------------------------------------------------------------

	; search for first selectable item

	ld	(MnuRowAddr),hl
	ld	a,-1
$$	inc	a
	bit	MNB_UNSEL,(hl)
	inc	hl
	jr	nz,$b
	ld	(MnuFirstItem),a

	; count rows

	ld	b,a
	xor	a
$$	inc	b
	cp	(hl)
	inc	hl
	jr	nz,$b
	ld	a,b
	ld	(MnuRowCount),a

	; search for last selectale item

	dec	hl
$$	dec	a
	dec	hl
	bit	MNB_UNSEL,(hl)
	jr	nz,$b
	ld	(MnuLastItem),a

	; parse column widths

	ex	de,hl
	ld	(MnuColumnAddr),hl
	xor	a
ParsCol	adc	a,(hl)
	inc	hl
	ccf
	jr	c,ParsCol
	ld	(MnuTextWidth),a

	ld	c,a
	ld	a,32 - 1 - 1		; left and right frame
	sub	c
	rra
	ld	c,a

	; calculate screen address

	ld	a,24 - 1 - 1 - 1	; caption, bottom frame, upper frame
	sub	b
	and	11111110b		; "divide" by 2
	add	a,a
	add	a,a
	ld	l,a
	ld	h,22
	add	hl,hl
	add	hl,hl
	ld	a,l
	add	a,c
	ld	l,a
	ld	(MnuAttrAddr),hl
	ret

;-------------------------------------------------------------------------------
DrawMenuFrame:
;-------------------------------------------------------------------------------

	push	hl

	; draw menu caption

	ld	hl,(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl

	ld	a,PAP_BLACK | INK_RED | BRIGHT
	ld	(SysColour),a

	ld	a,14
	rst	30h
	dw	PrintChar
	ld	a,' '
	rst	30h
	dw	PrintChar

	ld	a,PAP_BLACK | INK_WHITE | BRIGHT
	ld	(SysColour),a

	pop	hl
	ld	de,TempStr			;space in ram to copy rom message as rom will be switched for printstring routine
	ld	a,(MnuTextWidth)
	ld	c,a
	ld	b,0
	ldir					
	ld b,a
	ld hl,TempStr
	rst	30h
	dw	PrintString
	; draw top frame

	ld	hl,(MnuAttrAddr)		; optimise this
	call	AttrToScr
	call	DownLine
	ld	(SysCursor),hl

	ld	a,PAP_WHITE | INK_BLACK | BRIGHT
	ld	(SysColour),a

	ld	a,1
	rst	30h
	dw	PrintChar
	ld	c,2
	call	CharFillMenuLine
	ld	a,3
	rst	30h
	dw	PrintChar

	; draw menu lines

	ld	hl,(MnuAttrAddr)
	call	AttrToScr
	call	DownLine
	ld	de,(MnuRowAddr)

	; the way we clear line is type-dependent

ClrLoop	call	DownLine
	ld	(SysCursor),hl

	ld	a,(de)
	or	a
	jr	z,DrwBotm
	and	MNF_MASK

	push	de
	push	hl

ClrText	cp	MNI_TEXT
	jr	z,$f
	cp	MNI_BOLD
	jr	nz,ClrLine

$$	push	de
	ld	a,4
	rst	30h
	dw	PrintChar
	pop	de

	ld	a,(de)
	and	MNF_TABBED
	jr	z,NoTab

	ld	de,(MnuColumnAddr)
$$	ld	a,(de)
	inc	de
	call	AdvanceCursor
	ld	a,(de)
	inc	a
	jr	z,RFrame

	push	de
	ld	a,PAP_WHITE | INK_CYAN | BRIGHT
	ld	(SysColour),a
	ld	a,13
	rst	30h
	dw	PrintChar
	ld	a,PAP_WHITE | INK_BLACK | BRIGHT
	ld	(SysColour),a
	pop	de
	jr	$b

NoTab	;ld	a,4
	;call	PrintChar
	ld	a,(MnuTextWidth)
	call	AdvanceCursor
RFrame	ld	a,5
	jr	ClrNext

ClrLine	cp	MNI_LINE
	jr	nz,ClrBevl

	ld	a,6
	rst	30h
	dw	PrintChar
	ld	c,7
	call	CharFillMenuLine
	ld	a,8
	jr	ClrNext

ClrBevl	cp	MNI_BEVEL
	jr	nz,ClrNext

	ld	a,'|'
	rst	30h
	dw	PrintChar

	ld	a,PAP_WHITE | INK_CYAN | BRIGHT
	ld	(SysColour),a

	ld	c,'-'
	call	CharFillMenuLine

	ld	a,PAP_WHITE | INK_BLACK | BRIGHT
	ld	(SysColour),a

	ld	a,'|'
;	jr	ClrNext

ClrNext	rst	30h
	dw	PrintChar
	pop	hl
	pop	de
	inc	de
	jr	ClrLoop

	; draw bottom frame

DrwBotm	ld	a,9
	rst	30h
	dw	PrintChar
	ld	c,10
	call	CharFillMenuLine
	ld	a,11
	rst	30h
	dw	PrintChar
	ret

;-------------------------------------------------------------------------------
PokeMe:
;-------------------------------------------------------------------------------


	; poke input routine - it is not pretty
;	push	af
;	push	de

;	ld hl,(SysCursor)
;	push	hl

	ld	hl,5a68h;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl

	ld	a,PAP_BLACK | INK_RED | BRIGHT
	ld	(SysColour),a

	ld	a,14
	rst	30h
	dw	PrintChar
	ld	a,' '
	rst	30h
	dw	PrintChar

	ld	a,PAP_BLACK | INK_WHITE | BRIGHT
	ld	(SysColour),a

	ld	hl,PokeCaption
	ld	de,TempStr			;space in ram to copy rom message as rom will be switched for printstring routine
	ld	a,(MnuTextWidth)
	sub 10
	ld	c,a
	ld	b,0
	ldir					
	ld b,a
	ld hl,TempStr
	rst	30h
	dw	PrintString

	ld	a,PAP_WHITE | INK_BLACK | BRIGHT
	ld	(SysColour),a

	ld	hl,5a88h;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl

	ld	a,04
	rst	30h
	dw	PrintChar

	ld	hl,PokeAddrCaption
	ld	de,TempStr			;space in ram to copy rom message as rom will be switched for printstring routine
	ld	a,13
	ld	c,a
	ld	b,0
	ldir					
	ld b,a
	ld hl,TempStr
	rst	30h
	dw	PrintString
	ld	hl,5a8dh;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl
	ld	a,13
	rst	30h
	dw	PrintChar
	ld	hl,5a96h;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl
	ld	hl,PokeValCaption
	ld	de,TempStr			;space in ram to copy rom message as rom will be switched for printstring routine
	ld	a,8
	ld	c,a
	ld	b,0
	ldir					;copy data into 2300
	ld b,a
	ld hl,TempStr
	rst	30h
	dw	PrintString
	ld	hl,5a99h;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl
	ld	a,13
	rst	30h
	dw	PrintChar

	ld	hl,5a9dh;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl

	ld	a,05
	rst	30h
	dw	PrintChar
	ld	hl,5aa8h;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl
	ld	a,09
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,10
	rst	30h
	dw	PrintChar
	ld	a,11
	rst	30h
	dw	PrintChar

	ld hl,(PokeAddr)
	ld a,(hl)
	ld (PokeVal),a		;set starting value to current memory value for selected address

	ld	hl,5a8eh
	ld (PokeCursor),hl


PokeInput

	ld	hl,5a8eh;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl
	ld hl,(PokeAddr)
	ld	de,0
	ld	a,'0'
	rst	30h
	dw	Num32ToASCII
	ld	hl,SysNumber+5		; only want last 5 digits of 10 character string
	ld de,PokeAddrStr
	ld b,0
	ld c,5
	ldir
	ld hl,PokeAddrStr
	ld b,5					;characters to write
	rst	30h
	dw	PrintString

	ld	hl,5a9ah;(MnuAttrAddr)
	call	AttrToScr
	ld	(SysCursor),hl
	ld a,(PokeVal)
	ld l,a
	ld h,0
	ld	de,0
	ld	a,'0'
	rst	30h
	dw	Num32ToASCII
	ld	hl,SysNumber+7		; only want last 3 digits of 10 character string
	ld de,PokeValStr
	ld b,0
	ld c,3
	ldir
	ld hl,PokeValStr
	ld b,3					;characters to write
	rst	30h
	dw	PrintString

	ld hl,(PokeCursor)
	ld a,PAP_BLACK | INK_WHITE
	ld (hl),a


;	call	WaitForEvent		; wait for GUI event
	call	PokeKey

	cp	CHR_BREAK
	jr	z,PokeEscape
	cp	CHR_ENTER
	jr	z,$f
	jp	PokeInput

$$	ld	hl,(PokeAddr)
	ld	a,(PokeVal)
	ld	(hl),a
;	pop	hl
  ;	ld	(SysCursor),hl

;	pop de
;	pop af
PokeEscape
	ret

PokeKey
	call	ReadKey
	halt
	halt

	ld	hl,PokePrevKey
	cp	(hl)
	ld	(hl),a
	inc	hl
	jr	z,PokeKeyDlay
	ld	(hl),12
	jr	PokeIsNoKey

PokeKeyDlay	dec	(hl)
	jr	nz,PokeKey
	inc	(hl)
PokeIsNoKey	or	a
	jr	z,PokeKey

	cp	CHR_SYMBOL			; ignore shifts as single keys
	jr	z,PokeKey
	cp	CHR_CAPS
	jr	z,PokeKey

	ld hl,(PokeCursor)
	ld (PokeOldCursor),hl
	cp	CHR_RIGHT
	jr	nz,$f
PokeCursRight				;label so we can call this as a sub routine
	inc	l
	ld	a,l
	cp	9dh		;far right
	ret	z
	cp	93h		;need to jump from addr to val
	jr	nz,PokeCsrROK
	add	7
	ld l,a
PokeCsrROK
	ld (PokeCursor),hl
	ret

$$	CP CHR_LEFT
	jr	nz,$f
	dec	l
	ld	a,l
	cp	8dh		;far left
	ret	z
	cp	99h		;need to jump from addr to val
	jr	nz,PokeCsrLOK
	sub	7
	ld l,a
PokeCsrLOK
	ld (PokeCursor),hl
	ret

$$	cp	CHR_DOWN
	jr	nz,PokeUP
	call PokeGetAddr	;HL returns with addr to update with new number char
	ld	a,(hl)
	sub 1
	cp	2fh
	jr	nz,$f
	add 1
$$	ld (hl),a
	jr	PokePastKeys
;$$
;	jr	nz,EvnPgU
;	call	CursorDown
;	ret	nz
;	ld	a,CHR_DOWN
;	ret

PokeUP
	cp	CHR_UP
	jr	nz,PokeNum
	call PokeGetAddr	;HL returns with addr to update with new number char
	ld	a,(hl)
	add 1
	cp	3ah
	jr	nz,$f
	sub 1
$$	ld (hl),a
	jr	PokePastKeys

PokeNum
	cp	30h
	jr	c,PokePastKeys
	cp	3ah
	jr	nc,PokePastKeys
	push	af
	call	PokeGetAddr
	pop	af
	ld (hl),a
	ld hl,(PokeCursor)
	call	PokeCursRight

PokePastKeys
	push	af
	call	Strto16Bit
	ld (PokeAddr),ix
	
	ld hl,(PokeOldCursor)
	ld	a,l	;get low byte of cursor
	sub	8eh	;cursor now starts at 0
	cp		6
	jr	nc,$f
	ld hl,(PokeAddr)
	ld a,(hl)
	ld (PokeVal),a		;set starting value to current memory value for selected address
	pop	af
	ret

$$	call	Strto8Bit
	LD__A_XL
	ld (PokeVal),a
	pop	af
	ret

Strto8Bit
	ld hl,PokeValStr
	;HL needs to point to 5 chars from 0 - 9
	ld ix,0	;de will hold value
	dec hl
	jr	hundreds
Strto16Bit
	ld hl,PokeAddrStr
	;HL needs to point to 5 chars from 0 - 9
	ld ix,0	;de will hold value
	ld d,27h
	ld	e,10h		;hex value for 10,000
	ld a,(hl)	;first char 10,000
;	ld a,'4'		;lets test this
	sub '0'		;reduce to value of char
	jr	z,thousands
	ld b,a
$$	add ix,de
	djnz $b

thousands
	ld d,03h
	ld	e,232; e8h		;hex value for 1,000
	inc hl
	ld a,(hl)	;next char 1,000
;	ld a,'6'		;lets test this
	sub '0'		;reduce to value of char
	jr	z,hundreds
	ld b,a
$$	add ix,de
	djnz $b

hundreds
	ld d,00h
	ld	e,64h		;hex value for 100
	inc hl
	ld a,(hl)	;next char 100
;	ld a,'0'		;lets test this
	sub '0'		;reduce to value of char
	jr	z,tens
	ld b,a
$$	add ix,de
	djnz $b

tens
	ld d,00h
	ld	e,0ah		;hex value for 10
	inc hl
	ld a,(hl)	;next char 10
;	ld a,'9'		;lets test this
	sub '0'		;reduce to value of char
	jr	z,ones
	ld b,a
$$	add ix,de
	djnz $b

ones
	ld d,00h
	ld	e,01h		;hex value for 1
	inc hl
	ld a,(hl)	;next char 1
;	ld a,'4'		;lets test this
	sub '0'		;reduce to value of char
	jr	z,str216bitdone
	ld b,a
$$	add ix,de
	djnz $b

str216bitdone
	ret

PokeGetAddr
	ld hl,(PokeCursor)
	ld	a,l	;get low byte of cursor
	sub	8eh	;cursor now starts at 0
	cp		6
	jr	nc,$f
	ld	d,0
	ld	e,a
	ld hl,PokeAddrStr
	add hl,de
	ret
$$	sub	12
	ld	d,0
	ld	e,a
	ld hl,PokeValStr
	add hl,de
	ret
;-------------------------------------------------------------------------------
GetLineAddr:
;-------------------------------------------------------------------------------

	add	a,2			; skip caption and top frame
	add	a,a
	add	a,a
	add	a,a
	ld	l,a
	ld	h,0
	add	hl,hl
	add	hl,hl
	ld	de,(MnuAttrAddr)
	add	hl,de
	ret

CharFillMenuLine:

	ld	a,(MnuTextWidth)
	ld	b,a

;-------------------------------------------------------------------------------
CharFill:
;-------------------------------------------------------------------------------
; Input:
; C - character to fill
; B - number of characters to print
;-------------------------------------------------------------------------------

ChrFill	push	bc
	ld	a,c
	rst	30h
	dw	PrintChar
	pop	bc
	djnz	ChrFill
	ret

;-------------------------------------------------------------------------------
AdvanceCursor:
;-------------------------------------------------------------------------------

	ld	hl,(SysCursor)
	add	a,l
	ld	l,a
	ld	(SysCursor),hl
	ret

;-------------------------------------------------------------------------------
AttrToScr:
;-------------------------------------------------------------------------------

	ld	a,h
	rlca
	rlca
	rlca
	xor	10000010b
	ld	h,a
	ret

;-------------------------------------------------------------------------------
DownLine:
;-------------------------------------------------------------------------------

	ld	a,l
	add	a,32
	ld	l,a
	ret	nc
	ld	a,h
	add	a,8
	ld	h,a
	ret

;-------------------------------------------------------------------------------
DrawMenuCommon:
;-------------------------------------------------------------------------------
; Prints menu item texts for most common one-page, single-column menus.
;-------------------------------------------------------------------------------
; HL - text pointers

	ld	de,(MnuRowAddr)
	ld	bc,0FF00h
DrawRow	inc	b
	ld	a,(de)
	inc	de
	or	a
	ret	z

	; skip bevel and horizontal line

	cp	MNI_BEVEL
	jr	z,DrawRow
	cp	MNI_LINE
	jr	z,DrawRow

	; set colour based on row type

;	cp	MNI_BOLD_UN
	ld	a,PAP_WHITE | INK_BLACK | BRIGHT
	jr	nz,DrawTxt
	ld	a,PAP_WHITE | INK_RED | BRIGHT
DrawTxt	ld	(SysColour),a

	push	bc
	push	de
	ld	e,(hl)
	inc	hl
	ld	d,(hl)
	inc	hl
	push	hl

	ld	a,b
	call	SetItemText
	pop	hl
	pop	de
	pop	bc
	jr	DrawRow

;-------------------------------------------------------------------------------
WaitForEvent:
;-------------------------------------------------------------------------------

	call	ShowCursor

GuiKey	call	ReadKey
	halt
	halt

	ld	hl,GuiPrevKey
	cp	(hl)
	ld	(hl),a
	inc	hl
	jr	z,KeyDlay
	ld	(hl),12
	jr	IsNoKey

KeyDlay	dec	(hl)
	jr	nz,GuiKey
	inc	(hl)
IsNoKey	or	a
	jr	z,GuiKey

	cp	CHR_SYMBOL			; ignore shifts as single keys
	jr	z,GuiKey
	cp	CHR_CAPS
	jr	z,GuiKey

	ex	af,af'
	call	HideCursor
	ex	af,af'

	; process known meta codes

EvnPgD	cp	CHR_DOWN
	jr	nz,EvnPgU
	call	CursorDown
	ret	nz
	ld	a,CHR_DOWN
	ret

EvnPgU	cp	CHR_UP
	jr	nz,Evn
	call	CursorUp
	ret	nz
	ld	a,CHR_UP
	ret

	; TODO: process select on edit boxes etc... GetRowType

Evn
	ret

; The following two functions are bit of a hack. Very filesystem specific
; and very driver specific. Better rewrite this creating some "standard"
; driver API.

;-------------------------------------------------------------------------------
GetFilePos:
;-------------------------------------------------------------------------------
; Input:
; IY - address of file descriptor
; DE - address of buffer where to store file position
;-------------------------------------------------------------------------------

	push	iy
	pop	hl
	ld	bc,fdClus
	add	hl,bc
	jr	$f

;-------------------------------------------------------------------------------
SetFilePos:
;-------------------------------------------------------------------------------
; Input:
; IY - address of file descriptor
; DE - address of buffer where to store file position
;-------------------------------------------------------------------------------

	push	iy
	pop	hl
	ld	bc,fdClus
	add	hl,bc
	ex	de,hl
$$	ld	c,6
	ldir
	ret

;-------------------------------------------------------------------------------
WaitForKey:
;-------------------------------------------------------------------------------

	call	ReadKey
	jr	z,WaitForKey

	ld	b,20
$$	halt
	djnz	$b
	ret

;-------------------------------------------------------------------------------
ReadKey:
;-------------------------------------------------------------------------------

	call	KeyScan
	jr	nz,ReadKey		; accept only valid key combinations
	ld	a,e
	inc	a
	ret	z

	; translate key codes in DE into ASCII character (or meta code)

	ld	hl,KeySing
	ld	a,d
	cp	27h
	jr	nz,$f
	ld	hl,KeyCaps

$$	cp	18h
	jr	nz,$f
	ld	hl,KeySymb

$$	ld	d,0
	add	hl,de
	ld	a,(hl)
	ret

;-------------------------------------------------------------------------------
KeyScan:
;-------------------------------------------------------------------------------

	; this is an exact copy of ZX-ROM keyboard scanning routine

	ld	de,0FFFFh
	ld	bc,0FEFEh
	ld	l,2Fh

KeyLine	in	a,(c)
	cpl
	and	31
	jr	z,KeyNext

	ld	h,a
	ld	a,l

Key3Key	inc	d
	ret	nz
KeyBits	sub	8
	srl	h
	jr	nc,KeyBits
	ld	d,e
	ld	e,a
	jr	nz,Key3Key

KeyNext	dec	l
	rlc	b
	jr	c,KeyLine

	; accept single key with no shift

	ld	a,d
	inc	a
	ret	z

	; accept Caps Shift + key

	cp	28h
	ret	z

	; accept Symbol Shitf + key

	cp	19h
	ret	z

	; accept key + Symbol Shift and swap them

	ld	a,e
	ld	e,d
	ld	d,a
	cp	18h
	ret

; NOTE: We break both ZX and ASCII coding here in order to allow characters
; 0..31 to be displayed as graphics. It doesn't matter though because this
; coding is only used in GUI.

CHR_ENTER	equ	128
CHR_CAPS	equ	129
CHR_SYMBOL	equ	130
CHR_UP		equ	131
CHR_DOWN	equ	132
CHR_LEFT	equ	133
CHR_RIGHT	equ	134
CHR_DELETE	equ	135
CHR_BREAK	equ	136
CHR_EDIT	equ	137
CHR_EXT		equ	138
CHR_CAPSLOCK	equ	139
CHR_CAPS_ENTER	equ	140
CHR_SYMB_ENTER	equ	141

; GUI events

CHR_SELECT	equ	140
CHR_ESCAPE	equ	141
CHR_PAGE_DOWN	equ	142
CHR_PAGE_UP	equ	143

	; table of single keys

KeySing	db	"bhy65tgv"
	db	"nju74rfc"
	db	"mki83edx"
	db	CHR_SYMBOL, "lo92wsz"
	db	" ", CHR_ENTER, "p01qa", CHR_CAPS

	; table of caps-shifted keys (some ZX-specific symbols are of no use)

KeyCaps	db	"BHY", CHR_DOWN, CHR_LEFT, "TGV"
	db	"NJU", CHR_UP, "4RFC"
	db	"MKI", CHR_RIGHT, "3EDX"
	db	CHR_EXT, "LO9", CHR_CAPSLOCK, "WSZ"
	db	CHR_BREAK, CHR_CAPS_ENTER, "P", CHR_DELETE, CHR_EDIT, "QA", CHR_CAPS

	; table of symbol-shifted keys (some ZX-specific symbols are of no use)

KeySymb	db	"*^[&%>}/"
	db	",-]'$<{?"
	db	".+i(#e\\x"
	db	CHR_SYMBOL, "=;)@w|:"
	db	" ", CHR_SYMB_ENTER, """_!q~", CHR_EXT

; menu item types and flags

MNF_UNSEL	equ	80h	; unselectable item flag
MNF_TABBED	equ	40h	; tabbed item flag
MNF_VBEVEL	equ	20h	; has vertical bevel between tabs
MNF_MASK	equ	1Fh	; menu type mask

; bit numbers

MNB_UNSEL	equ	7	; unselectable item flag
MNB_TABBED	equ	6	; tabbed item flag
MNB_VBEVEL	equ	5	; has vertical bevel between tabs

MNI_TEXT	equ	1	; text item
MNI_BOLD	equ	2	; bold text item
MNI_TEXT_BOX	equ	3	; input box (text)
MNI_16BIT_BOX	equ	4	; input box (16-bit number)
MNI_32BIT_BOX	equ	5	; input box (32-bit number)
MNI_BEVEL	equ	6	; horizontal bevel
MNI_LINE	equ	7	; horizontal line

; browser menu definition

BrwMenuRows:

	; lines

	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_TEXT | MNF_TABBED
	db	MNI_LINE | MNF_UNSEL
	db	MNI_TEXT | MNF_UNSEL
	db	0

BrwDef		db	19, 10, 255
BrwCaption	db	"Disk Browser", 0

; volume select window

SelVolDef	db	11, 255
SelVolCaption	db	"Volume", 0

; colour scheme for various menu types

csText		equ	0
csTextCur	equ	1
csTextBold	equ	2
csTextBoldCur	equ	3

csTextDisab	equ	4
csEditBox	equ	5

; browser caches:

; 1 byte  - file type (if recognised)
; 2 bytes - starting cluster
; 1 byte  - attributes
; 4 bytes - file size

TxtDirectory	db	15, 0

PokeCaption	db "Enter Poke",0
PokeAddrCaption	db "Addr",0
PokeValCaption	db "Val",0

