		*********************************
		*                               *
		*   Visual Shell v1.17  10/92   *
		*                               *
		*     by Torsten Jürgeleit      *
		*                               *
		*   assembly support routines   *
		*           part III            *
		*                               *
		*********************************

	NOLIST
	INCLUDE "exec/types.i"
	INCLUDE "exec/ports.i"
	INCLUDE "exec/nodes.i"
	INCLUDE "exec/lists.i"
	INCLUDE "exec/memory.i"
	INCLUDE "libraries/arpbase.i"
	INCLUDE "intuition/intuition.i"
	INCLUDE "equates.i"
	LIST

;---------------------------------------------------------------------------
; External definitions
;---------------------------------------------------------------------------

	XDEF	_hcomp_treq_cursor
	XDEF	_print_dir_tree
	XDEF	_get_tree_node_by_pos
	XDEF	_get_next_column_tree_node
	XDEF	_get_prev_column_tree_node
	XDEF	_build_history_line_list
	XDEF	_print_hreq_lines
	XDEF	_build_hreq_line
	XDEF	_hcomp_hreq_cursor
	XDEF	_scroll_history_req

;---------------------------------------------------------------------------
; External references
;---------------------------------------------------------------------------

	XREF	_IntuitionBase
	XREF	_GfxBase
	XREF	_gadget_buffer
	XREF	_con_device
	XREF	_con_unit
	XREF	_con_window
	XREF	_con_rport
	XREF	_main_task
	XREF	_vsh_port
	XREF	_auto_repeat
	XREF	_show_flag
	XREF	_scroll_flag
	XREF	_vsh_scroll_speed
	XREF	_qualifier
	XREF	_enable_abort
	XREF	_num_lock
	XREF	_key_table
	XREF	_action_table
	XREF	_scroll_flag_table
	XREF	_action
	XREF	_file_req
	XREF	_view_req
	XREF	_history_req
	XREF	_active_freq
	XREF	_line1_buffer
	XREF	_max_line_len
	XREF	_print_dir_info
	XREF	_print_info_line
	XREF	_print_vreq_status
	XREF	_print_quick_view
	XREF	_SPrintf
	XREF	_protection_bits
	XREF	_protection_string
	XREF	_font_data
	XREF	_template_buffer
	XREF	build_text_line
	XREF	write_text

;---------------------------------------------------------------------------
; VOID hcomp_treq_cursor(treq)
;			  a0
;	struct TreeRequest  *treq
; Highlight or de-highlight the cursor line in tree requester
;---------------------------------------------------------------------------
_hcomp_treq_cursor:
	PUSH	d2-d3/a2-a3/a6

	move.l	a0,a2				; a2 := treq
	move.l	_con_rport,a3			; a3 := rastport
	move.l	_GfxBase,a6

	moveq	#RP_COMPLEMENT,d0		; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

	move.l	tr_CursorNode(a2),a0		; a0 := cursor tnode
	move.l	tn_XPos(a0),d0
	sub.l	tr_XPos(a2),d0
	mulu	#MAX_TREE_NODE_NAME_LEN+3,d0
	addq.w	#2,d0
	lsl.w	#3,d0				; d0 * 8
	move.w	tr_Display+d_LeftEdge(a2),d1
	add.w	d1,d0				; x1
	move.l	tn_YPos(a0),d1
	sub.l	tr_YPos(a2),d1
	lsl.w	#3,d1				; d1 * 8
	move.w	tr_Display+d_TopEdge(a2),d2
	add.w	d2,d1				; y1
	move.w	d0,d2
	add.w	#MAX_TREE_NODE_NAME_LEN*8-1,d2	; x2
	move.w	d1,d3
	addq.w	#7,d3				; y2
	move.l	a3,a1
	CALLSYS	RectFill

	moveq	#RP_JAM2,d0			; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

	PULL	d2-d3/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; VOID print_dir_tree(treq)
;		       a0
;	struct TreeRequest  *treq
; Print directory tree
;---------------------------------------------------------------------------
_print_dir_tree
	PUSH	d2-d7/a2-a3/a5-a6

	move.l	a0,a2				; a2 := treq
	move.l	_con_rport,a5			; za5 := rast port
	move.l	_GfxBase,a6

	moveq	#RP_JAM2,d0			; draw mode
	move.l	a5,a1
	CALLSYS	SetDrMd

	moveq	#COLOR1,d0			; front color
	move.l	a5,a1
	CALLSYS	SetAPen

	moveq	#COLOR0,d0			; back color
	move.l	a5,a1
	CALLSYS	SetBPen

	move.w	tr_Display+d_LeftEdge(a2),d6	; d6 := horizontal position
	move.w	tr_Display+d_TopEdge(a2),d7	; d7 := verical position
	moveq	#MAX_TREE_NODE_NAME_LEN+3,d0
	mulu	tr_Columns(a2),d0
	move.l	d0,a5				; a5 := line len

	move.l	tr_YPos(a2),d3			; d3 := ypos
	move.w	tr_Rows(a2),d5
	subq.w	#1,d5				; d5 := rows - 1

pdt_row_loop:
	lea	_line1_buffer,a3		; a3 := text buffer ptr
	move.l	tr_XPos(a2),d2			; d2 := xpos
	move.w	tr_Columns(a2),d4
	subq.w	#1,d4				; d4 := columns - 1

pdt_column_loop:
	bsr	get_tree_node_by_pos

pdt_outside:
	tst.l	d0				; tnode == NULL ?
	bne	pdt_between
	moveq	#MAX_TREE_NODE_NAME_LEN+3-1,d1
	bra	pdt_fill_column1

pdt_between:
	cmp.l	#-1,d0				; tnode == -1 ?
	bne	pdt_node
	move.b	#129,(a3)+			; '|'
	moveq	#MAX_TREE_NODE_NAME_LEN+2-1,d1

pdt_fill_column1:
	moveq	#' ',d0

1$:
	move.b	d0,(a3)+
	dbra	d1,1$
	bra	pdt_next_column

pdt_node:
	move.l	d0,a1				; a1 := tnode
	lea	tr_RootNode(a2),a0		; tnode == root node ?
	cmp.l	a0,a1
	bne	pdt_node_loop

pdt_root_node:
	move.b	#' ',(a3)+
	move.b	#' ',(a3)+
	bra	pdt_insert_name

pdt_node_loop:
	move.l	tn_Node+MLN_SUCC(a1),a0
	tst.l	MLN_SUCC(a0)
	bne	pdt_more_entries

pdt_no_next_entry:
	move.l	tn_Node+MLN_PRED(a1),a0
	tst.l	MLN_PRED(a0)
	bne	pdt_last_entry

pdt_only_one_entry:
	move.b	#128,d0				; only one entry in list '-'
	bra	pdt_insert_delimiter

pdt_last_entry:
	move.b	#132,d0				; last entry in list '`'
	bra	pdt_insert_delimiter

pdt_more_entries:
	move.l	tn_Node+MLN_PRED(a1),a0
	tst.l	MLN_PRED(a0)
	bne	pdt_next_entry

pdt_first_entry:
	move.b	#130,d0				; first entry in list '+'
	bra	pdt_insert_delimiter

pdt_next_entry:
	move.b	#131,d0				; more entries in list '+'

pdt_insert_delimiter:
	move.b	d0,(a3)+
	move.b	#128,(a3)+			; '-'

pdt_insert_name:
	lea	tn_Name(a1),a0
	moveq	#MAX_TREE_NODE_NAME_LEN-1,d1

pdt_insert_name_loop:
	move.b	(a0)+,d0
	beq	pdt_check_list
	move.b	d0,(a3)+
	dbra	d1,pdt_insert_name_loop

pdt_check_list:
	addq.w	#1,d1				; fill one char more
	moveq	#' ',d0
	lea	tn_List(a1),a0
	cmp.l	tn_List+MLH_TAILPRED(a1),a0	; list empty ?
	beq	pdt_fill_column2
	move.b	#128,d0				; '-'

pdt_fill_column2:				; fill rest of column with spaces
	move.b	d0,(a3)+
	dbra	d1,pdt_fill_column2
	cmp.b	#' ',d0				; list empty ?
	beq	pdt_fill_line

pdt_next_node:
	move.l	tn_List+MLH_HEAD(a1),a1		; a1 := first tnode in list
	addq.l	#1,d2				; inc xpos
	dbra	d4,pdt_node_loop		; next column
	bra	pdt_print

pdt_next_column:
	addq.l	#1,d2				; inc xpos
	dbra	d4,pdt_column_loop		; next column
	bra	pdt_print

pdt_fill_line_loop:				; fill rest of line with spaces
	moveq	#MAX_TREE_NODE_NAME_LEN+3-1,d1

pdt_fill_line_column_loop:
	move.b	d0,(a3)+			; fill one column
	dbra	d1,pdt_fill_line_column_loop

pdt_fill_line:
	addq.l	#1,d2				; inc xpos
	dbra	d4,pdt_fill_line_loop		; next column

pdt_print:
	clr.b	(a3)				; mark end of string

	lea	_line1_buffer,a0		; text
	move.w	d6,d0				; x
	move.w	d7,d1				; y
	jsr	write_text

pdt_check_dir_node:
	move.l	tr_DirNode(a2),a3		; a3 := current dir tnode
	cmp.l	tn_YPos(a3),d3			; tn_YPos == ypos ?
	bne	pdt_next_row
	move.l	tn_XPos(a3),d0
	cmp.l	d2,d0				; tn_XPos >= (xpos + max_columns) ?
	bhs	pdt_next_row
	cmp.l	tr_XPos(a2),d0			; tn_XPos < tr_XPos ?
	blo	pdt_next_row

pdt_find_dir_name_end:
	lea	tn_Name(a3),a0			; find end of dir name in line1 buffer
	lea	_line1_buffer,a1
	moveq	#MAX_TREE_NODE_NAME_LEN-1,d1

pdt_find_dir_name_end_loop:
	move.b	(a0)+,d0
	beq	pdt_print_dir_node
	move.b	d0,(a1)+
	dbra	d1,pdt_find_dir_name_end_loop

pdt_print_dir_node:
	clr.b	(a1)				; mark end of current dir name

	moveq	#COLOR2,d0			; new back color
	move.l	_con_rport,a1
	CALLSYS	SetBPen

	lea	_line1_buffer,a0		; text
	move.l	tn_XPos(a3),d0
	sub.l	tr_XPos(a2),d0
	mulu	#MAX_TREE_NODE_NAME_LEN+3,d0
	addq.w	#2,d0
	lsl.w	#3,d0				; d0 * 8
	add.w	d6,d0				; x
	move.w	d7,d1				; y
	jsr	write_text

	moveq	#COLOR0,d0			; old back color
	move.l	_con_rport,a1
	CALLSYS	SetBPen

pdt_next_row:
	addq.l	#1,d3				; inc ypos
	addq.l	#8,d7				; inc vertical position
	dbra	d5,pdt_row_loop

	PULL	d2-d7/a2-a3/a5-a6
	rts

;---------------------------------------------------------------------------
; struct TreeNode  *get_tree_node_by_pos(treq, xpos, ypos)
;					  a0    d0    d1
;	struct TreeRequest  *treq
;	ULONG xpos, ypos
; Get node from directory tree by given position
;---------------------------------------------------------------------------
_get_tree_node_by_pos:
	PUSH	d2-d3/a2

	move.l	a0,a2				; a0 := treq
	move.l	d0,d2				; d2 := xpos
	move.l	d1,d3				; d3 := ypos
	bsr	get_tree_node_by_pos

	PULL	d2-d3/a2
	rts

get_tree_node_by_pos:   ; a2 := treq ptr, d2 := xpos, d3 := ypos
	lea	tr_RootNode(a2),a1		; a1 := parent tnode
	moveq	#0,d1				; save next tnode
	bra	gtp_go_deeper

gtp_loop:
	move.l	tn_Node+MLN_SUCC(a1),a0		; a0 := next tnode in list
	move.l	a0,d1				; save next tnode
	tst.l	tn_Node+MLN_SUCC(a0)		; end of list ?
	beq	gtp_go_deeper
	cmp.l	tn_YPos(a0),d3			; ypos < tn_YPos ?
	blo	gtp_go_deeper
	move.l	a0,a1				; new parent tnode
	bra	gtp_loop

gtp_go_deeper:
	move.l	tn_List+MLH_HEAD(a1),a0		; a0 := first tnode in list
	tst.l	tn_Node+MLN_SUCC(a0)		; empty list ?
	beq	gtp_pos_reached
	cmp.l	tn_XPos(a0),d2			; xpos < tn_XPos ?
	blo	gtp_pos_reached
	move.l	a0,a1				; new parent node
	bra	gtp_loop

gtp_pos_reached:
	cmp.l	tn_XPos(a1),d2			; tn_XPos != xpos ?
	bne 	gtp_pos_outside
	cmp.l	tn_YPos(a1),d3			; tn_YPos == ypos ?
	beq 	gtp_pos_node

gtp_pos_empty:
	tst.l	d1
	beq	gtp_pos_outside			; only valid for root node
	move.l	d1,a0				; a0 := save next tnode
	tst.l	tn_Node+MLN_SUCC(a0)		; last tnode in list ?
	beq	gtp_pos_outside

gtp_pos_between:
	move.l	#-1,d0				; indicates pos between two tree branches
	rts

gtp_pos_outside:
	moveq	#0,d0				; indicates pos outside of tree
	rts

gtp_pos_node:
	move.l	a1,d0				; return tnode
	rts

;---------------------------------------------------------------------------
; struct TreeNode  *get_next_column_tree_node(tnode)
;					       a0
;	struct TreeNode  *tnode
; Get next tree node from given tree node in same column
;---------------------------------------------------------------------------
_get_next_column_tree_node:
	PUSH	d2/a2-a3

	move.l	a0,a3				; a3 := start tnode
	move.l	tn_XPos(a3),d1			; d1 := column
	moveq	#0,d2				; d2 := nearest column
	move.l	a3,a1				; a1 := parent tnode
	sub.l	a2,a2				; a2 := nearest tnode

gnc_get_next:
	move.l	tn_Node+MLN_SUCC(a1),d0
	beq	gnc_get_old			; only valid for root node
	move.l	d0,a0
	tst.l	tn_Node+MLN_SUCC(a0)		; end of list ?
	beq	gnc_go_back
	move.l	a0,a1				; new parent tnode
	bra	gnc_found

gnc_go_back:
	move.l	tn_ParentNode(a1),d0		; root reached ?
	beq	gnc_get_first
	move.l	d0,a1				; new parent tnode

gnc_go_next:
	move.l	tn_Node+MLN_SUCC(a1),d0
	beq	gnc_get_old			; only valid for root node
	move.l	d0,a0
	tst.l	tn_Node+MLN_SUCC(a0)		; end of list ?
	beq	gnc_go_back

gnc_go_deeper:
	move.l	a0,a1				; new parent tnode
	move.l	tn_XPos(a1),d0
	cmp.l	d1,d0				; tn_XPos == column ?
	beq	gnc_found
	cmp.l	d2,d0				; tn_XPos <= nearest_column ?
	bls	gnc_no_nearest
	move.l	a1,a2				; new nearest tnode
	move.l	d0,d2				; new nearest column

gnc_no_nearest:
	move.l	tn_List+MLH_HEAD(a1),a0
	tst.l	tn_Node+MLN_SUCC(a0)		; empty list ?
	bne	gnc_go_deeper
	bra	gnc_go_next

gnc_get_first:
	move.l	tn_List+MLH_HEAD(a3),a0
	tst.l	tn_Node+MLN_SUCC(a0)		; empty list ?
	beq	gnc_get_nearest
	move.l	a0,a1				; go to first tnode in list
	bra	gnc_found

gnc_get_nearest:
	move.l	a2,d0				; nearest tnode found ?
	beq	gnc_get_old
	move.l	a2,a1				; go to nearest pos
	bra	gnc_found

gnc_get_old:
	move.l	a3,a1				; stay at old pos

gnc_found:
	move.l	a1,d0				; return tnode

gnc_exit:
	PULL	d2/a2-a3
	rts

;---------------------------------------------------------------------------
; struct TreeNode  *get_prev_column_tree_node(tnode)
;					       a0
;	struct TreeNode  *tnode
; Get previous tree node from given tree node in same column
;---------------------------------------------------------------------------
_get_prev_column_tree_node:
	PUSH	d2/a2-a3

	move.l	a0,a3				; a3 := start tnode
	move.l	tn_XPos(a3),d1			; d1 := column
	moveq	#0,d2				; d2 := nearest column
	move.l	a3,a1				; a1 := parent tnode
	sub.l	a2,a2				; a2 := nearest tnode

gpc_get_next:
	move.l	tn_Node+MLN_PRED(a1),d0		; empty list ?
	beq	gpc_go_back
	move.l	d0,a0
	tst.l	tn_Node+MLN_PRED(a0)		; start of list ?
	beq	gpc_go_back
	move.l	a0,a1				; new parent tnode
	bra	gpc_found

gpc_go_back:
	move.l	tn_ParentNode(a1),d0		; root reached ?
	beq	gpc_get_nearest
	move.l	d0,a1				; new parent tnode

gpc_go_next:
	move.l	tn_Node+MLN_PRED(a1),d0		; empty list ?
	beq	gpc_go_back
	move.l	d0,a0
	tst.l	tn_Node+MLN_PRED(a0)		; start of list ?
	beq	gpc_go_back

gpc_go_deeper:
	move.l	a0,a1				; new parent tnode
	move.l	tn_XPos(a1),d0
	cmp.l	d1,d0				; tn_XPos == column ?
	beq	gpc_found
	cmp.l	d2,d0				; tn_XPos <= nearest_column ?
	bls	gpc_no_nearest
	move.l	a1,a2				; new nearest tnode
	move.l	d0,d2				; new nearest column

gpc_no_nearest:
	move.l	tn_List+MLH_TAILPRED(a1),a0
	tst.l	tn_Node+MLN_PRED(a0)		; empty list ?
	bne	gpc_go_deeper
	bra	gpc_go_next

gpc_get_nearest:
	move.l	a2,d0				; nearest tnode found ?
	beq	gpc_get_parent
	move.l	a2,a1				; go to nearest pos
	bra	gpc_found

gpc_get_parent:
	move.l	tn_ParentNode(a3),d0
	beq	gpc_get_old
	move.l	d0,a1				; go to first tnode in list
	bra	gpc_found

gpc_get_old:
	move.l	a3,a1				; stay at old pos

gpc_found:
	move.l	a1,d0				; return tnode

gpc_exit:
	PULL	d2/a2-a3
	rts

;---------------------------------------------------------------------------
; BOOL build_history_line_list(hreq)
;				a0
;	struct HistoryRequest  *hreq
; Build history line list with nodes for every line of text
;---------------------------------------------------------------------------
_build_history_line_list:
	PUSH	d2-d4/a2-a3/a5-a6

	move.l	a0,a3				; a3 := hreq ptr
	move.l	4,a6				; a6 := exec base ptr
	moveq	#MLH_SIZE,d0			; alloc mem for line list header
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	CALLSYS	AllocMem
	move.l	d0,hr_Display+d_List(a3)
	beq	bhll_error
	move.l	d0,a5				; a5 := list ptr
	move.l	a5,a0				; init new list
	NEWLIST	a0
	move.l	hr_Buffer(a3),a2		; a2 := buffer ptr
	moveq	#0,d3				; d3 := entry counter
	move.w	_max_line_len,d4		; max num of chars per line

bhll_loop:
	moveq	#0,d2
	move.b	(a2)+,d2			; d2 := BSTR len
	beq	bhll_end_of_buffer		; end of buffer ?

bhll_build_line_node:
	moveq	#LineNode_Sizeof,d0		; alloc mem for line node
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	CALLSYS	AllocMem
	tst.l	d0
	beq	bhll_error
	move.l	d0,a1				; a1 := line node ptr
	move.l	a2,ln_Line(a1)
	add.w	d2,a2				; inc buffer ptr
	cmp.w	d4,d2				; line too long ?
	bls	bhll_insert_line_len
	move.w	d4,d2				; truncate line

bhll_insert_line_len:
	move.w	d2,ln_LineLen(a1)
	addq.l	#1,d3				; inc entry counter
	move.l	a5,a0				; append node to list
	ADDHEAD a0
	bra	bhll_loop

bhll_end_of_buffer:
	move.l	d3,hr_Display+d_NumEntries(a3)	; save num of entries in hreq
	bne	bhll_set_cursor

bhll_clear_cursor:
	move.w	#-1,hr_CursorLine(a3)		; cursor_line := -1
	bra	bhll_success

bhll_set_cursor:
	clr.w	hr_CursorLine(a3)		; cursor_line := 0

bhll_set_pos:
	move.l	MLH_HEAD(a5),a0			; a0 := first line node
	moveq	#1,d0				; d0 := pos

bhll_set_pos_loop:
	tst.l	MLN_SUCC(a0)			; end of list ?
	beq	bhll_success
	move.l	d0,ln_Pos(a0)			; set pos
	addq.l	#1,d0				; inc pos
	move.l	MLN_SUCC(a0),a0			; a0 := next line node
	bra	bhll_set_pos_loop

bhll_success:
	moveq	#1,d0				; return value -> success

bhll_exit:
	PULL	d2-d4/a2-a3/a5-a6
	rts

bhll_error:
	moveq	#0,d0				; return value -> error
	bra	bhll_exit

;---------------------------------------------------------------------------
; VOID print_hreq_lines(hreq, node, line, count)
;			 a0    a1    d0    d1
;	struct HistoryRequest  *hreq
;	struct LineNode        *node
;	USHORT line, count
; Print specified lines of history
;---------------------------------------------------------------------------
_print_hreq_lines:
	PUSH	d2-d7/a2-a3/a5-a6

	move.l	a1,d2				; node == NULL ?
	beq	pvl_exit
	move.l	a0,a2				; a2 := hreq
	move.l	a1,a3				; a3 := node ptr
	move.l	_con_rport,a5			; a5 := rast port
	move.l	_GfxBase,a6			; a6 := gfx base
	move.w	_max_line_len,d4		; d4 := max num of chars per line
	subq.w	#1,d4				; dec num for dbra
	move.w	d0,d5				; d5 := line
	move.w	d1,d6				; d6 := count
	subq.w	#1,d6				; dec count for dbra
	moveq	#VIEW_MODE_ASCII,d7		; d7 := view mode

	moveq	#RP_JAM2,d0			; draw mode
	move.l	a5,a1
	CALLSYS	SetDrMd

	moveq	#COLOR1,d0			; front color
	move.l	a5,a1
	CALLSYS	SetAPen

	moveq	#COLOR0,d0			; back color
	move.l	a5,a1
	CALLSYS	SetBPen

	lea	_line1_buffer,a5

pvl_loop:
	tst.l	MLN_SUCC(a3)			; end of list ?
	beq	pvl_exit

	jsr	build_text_line			; build history line

	move.l	a5,a0				; text
	move.w	hr_Display+d_LeftEdge(a2),d0	; x
	move.w	d5,d1
	lsl.w	#3,d1				; d1 * 8
	add.w	hr_Display+d_TopEdge(a2),d1	; y
	jsr	write_text

	move.l	MLN_SUCC(a3),a3			; next node
	addq.w	#1,d5				; inc line counter
	dbra	d6,pvl_loop

pvl_exit:
	PULL	d2-d7/a2-a3/a5-a6
	rts

;---------------------------------------------------------------------------
; UBYTE *build_hreq_lines(hreq, node, max_line_len)
;			   a0    a1        d0
;	struct HistoryRequest  *hreq
;	struct LineNode        *node
;	USHORT max_line_len
; Build specified line of text as ASCII or hex dump and returns pointer
;---------------------------------------------------------------------------
_build_hreq_line:
	PUSH	d2-d7/a2-a3/a5-a6

	move.l	a0,a2				; a2 := hreq
	move.l	a1,a3				; a3 := node ptr
	lea	_line1_buffer,a5		; a5 := line buffer ptr
	move.w	d0,d4				; d4 := max num of chars per line
	beq	bhl_no_max_line_len
	subq.w	#1,d4				; dec num for dbra

bhl_no_max_line_len:
	moveq	#VIEW_MODE_ASCII,d7		; d7 := mode
	jsr	build_text_line
	move.l	a5,d0				; return pointer to line

	PULL	d2-d7/a2-a3/a5-a6
	rts

;---------------------------------------------------------------------------
; VOID hcomp_hreq_cursor(hreq)
;			  a0
;	struct HistoryRequest  *hreq
; Highlight or de-highlight the cursor line in history requester
;---------------------------------------------------------------------------
_hcomp_hreq_cursor:
	PUSH	a2/a6

	move.l	a0,a2				; a2 := hreq
	move.l	_GfxBase,a6

	bsr	hcomp_hreq_cursor

hfc_exit:
	PULL	a2/a6
	rts

;---------------------------------------------------------------------------
; Input : a2 = hreq ptr
;	  a6 = GfxBase
; Highlight or de-highlight the cursor line in history requester
;---------------------------------------------------------------------------
hcomp_hreq_cursor:
	PUSH	d2-d3/a3

	move.w	hr_CursorLine(a2),d2		; d2 := cursor line
	cmp.w	#-1,d2				; no cursor line ?
	beq	hhc_return
	cmp.w	hr_Display+d_VisibleLines(a2),d2
	bhs	hhc_return

	move.l	_con_rport,a3			; a3 := rast port
	moveq	#RP_COMPLEMENT,d0		; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

	move.w	vr_Display+d_LeftEdge(a2),d0	; x1
	move.w	vr_Display+d_TopEdge(a2),d1
	lsl.w	#3,d2				; d2 * 8
	add.w	d2,d1				; y1
	move.w	vr_Display+d_Width(a2),d2
	add.w	d0,d2				; x2
	move.w	d1,d3
	addq.w	#7,d3				; y2
	move.l	a3,a1
	CALLSYS	RectFill

	moveq	#RP_JAM2,d0			; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

hhc_return:
	PULL	d2-d3/a3
	rts

;---------------------------------------------------------------------------
; VOID scroll_history_req()
; Scroll history list in active historyrequester
;---------------------------------------------------------------------------
_scroll_history_req:
	PUSH	d2-d7/a2-a3/a6			; save regs for scroll routines

	tst.b	_scroll_flag			; check scroll flag
	beq	shr_exit
	lea	_history_req,a2			; a2 := &history_req
	cmp.l	#1,hr_Display+d_NumEntries(a2)	; more than one entries in history list ?
	bls	shr_exit

shr_auto_repeat_loop:
	move.l	_GfxBase,a6
	move.b	_scroll_flag,d1			; d1 := scroll flag
	bclr	#7,d1				; top or bottom ?
	bne	shr_scroll_all
	moveq	#1,d7				; d7 := count
	bclr	#6,d1				; page up or down ?
	beq	shr_scroll_part
	moveq	#0,d7
	move.w	hr_Display+d_VisibleLines(a2),d7	; d7 := count

shr_scroll_part:
	bclr	#0,d1				; scroll up ?
	bne	shr_scroll_part_up
	bclr	#1,d1				; scroll down ?
	beq	shr_exit

shr_scroll_part_down:
	bsr	scroll_hreq_down
	bra	shr_check_auto_repeat

shr_scroll_part_up:
	bsr	scroll_hreq_up
	bra	shr_check_auto_repeat

shr_scroll_all:
	bsr	hcomp_hreq_cursor		; clear old cursor line
	move.l	hr_Display+d_List(a2),a0	; a0 := history list ptr
	move.b	_scroll_flag,d0			; d0 := scroll flag
	btst	#0,d0				; scroll up ?
	beq	shr_scroll_all_down

shr_scroll_all_up:
	move.l	MLH_HEAD(a0),a0
	clr.w	hr_CursorLine(a2)		; cursor at top
	bra	shr_scroll_all_print

shr_scroll_all_down:
	moveq	#0,d0
	move.w	hr_Display+d_VisibleLines(a2),d0
	cmp.l	hr_Display+d_NumEntries(a2),d0	; lesser entries than lines ?
	blo	shr_search_last_entry
	move.l	hr_Display+d_NumEntries(a2),d0	; cursor to last entry
	subq.w	#1,d0
	move.w	d0,hr_CursorLine(a2)
	bra	shr_draw_cursor

shr_search_last_entry:
	move.l	MLH_TAILPRED(a0),a0
	move.w	hr_Display+d_VisibleLines(a2),d0
	subq.w	#2,d0				; dec for dbra

shr_last_entry_loop:
	move.l	MLN_PRED(a0),a0
	dbra	d0,shr_last_entry_loop
	move.w	hr_Display+d_VisibleLines(a2),d0	; cursor at bottom
	subq.w	#1,d0
	move.w	d0,hr_CursorLine(a2)

shr_scroll_all_print:
	move.l	a0,hr_Display+d_FirstVisibleNode(a2)
	move.l	a0,a1					; a1 := node
	move.l	a2,a0					; a0 := hreq
	moveq	#0,d0					; d0 := line
	move.w	hr_Display+d_VisibleLines(a2),d1	; d1 := count
	jsr	_print_hreq_lines			; print whole page

shr_draw_cursor:
	bsr	hcomp_hreq_cursor		; draw new cursor line

shr_check_auto_repeat:
	cmp.b	#SCROLL_SPEED_FAST,_vsh_scroll_speed	; fast scrolling ?
	bne	shr_exit
	tst.b	_auto_repeat			; auto_repeat ?
	beq	shr_exit
	tst.b	_scroll_flag			; check scroll flag
	bne	shr_auto_repeat_loop

shr_exit:
	PULL	d2-d7/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; Input : a2   = history request ptr
;	  a6   = GfxBase
;	  d7.l = scroll count
; Scroll history list of active history requester count times up
;---------------------------------------------------------------------------
scroll_hreq_up:
	moveq	#0,d2
	move.w	hr_Display+d_VisibleLines(a2),d2	; d2 := visible lines
	move.l	hr_Display+d_NumEntries(a2),d3		; d3 := number of entries
	move.l	hr_Display+d_FirstVisibleNode(a2),a3	; check cursor line - count
	moveq	#0,d4
	move.w	hr_CursorLine(a2),d4
	add.l	ln_Pos(a3),d4
	subq.l	#1,d4
	beq	shu_exit			; already at top ?
	bsr	hcomp_hreq_cursor		; clear old cursor line
	cmp.l	d7,d4
	bhi	shu_move_cursor
	cmp.l	#1,ln_Pos(a3)			; already at top ?
	bhi	shu_start_scroll
	clr.w	hr_CursorLine(a2)		; now cursor at top
	bra	shu_draw_cursor

shu_move_cursor:
	move.w	hr_CursorLine(a2),d0		; dec cursor line
	sub.w	d7,d0
	bmi	shu_scroll
	bne	shu_set_cursor			; cursor at top ?
	cmp.l	#1,ln_Pos(a3)			; already at top ?
	bhi	shu_start_scroll

shu_set_cursor:
	move.w	d0,hr_CursorLine(a2)
	bra	shu_draw_cursor

shu_scroll:
	cmp.l	#1,ln_Pos(a3)			; already at top ?
	bls	shu_draw_cursor

shu_start_scroll:
	move.w	d7,d0				; d0 := scroll count
	subq.w	#1,d0				; dec count for dbra

shu_loop:
	cmp.l	#1,ln_Pos(a3)			; top reached ?
	beq	shu_check_count
	move.l	MLN_PRED(a3),a3			; get previous node
	dbra	d0,shu_loop

shu_check_count:
	cmp.w	#1,d7				; paging ?
	bhi	shu_paging

shu_init_scroll:
	move.l	_con_rport,a0			; source rport
	move.l	a0,a1				; dest rport
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	d1,d3				; y2
	move.w	d0,d2				; x2
	move.w	fr_Display+d_Width(a2),d4	; width
	move.w	fr_Display+d_VisibleLines(a2),d5
	lsl.w	#3,d5				; height
	move.w	#$0c0,d6			; minterm
	cmp.b	#SCROLL_SPEED_SLOW,_vsh_scroll_speed
	beq	shu_scroll_slow

shu_scroll_normal:
	addq.w	#8,d3				; y2
	subq.w	#8,d5				; height
	CALLSYS	ClipBlit			; scroll one entry up
	bra	shu_paging

shu_scroll_slow:
	PUSH	d7
	subq.w	#1,d1				; y1
	moveq	#8-1,d7				; d7 := count

1$:
	movem.w	d0-d6,-(sp)
	PUSH	a0-a1
	CALLSYS	ClipBlit			; scroll one scanline up
	PULL	a0-a1
	movem.w	(sp)+,d0-d6
	dbra	d7,1$
	PULL	d7

shu_paging:
	move.l	a2,a0				; a0 := hreq
	move.l	a3,a1				; a1 := node
	moveq	#0,d0				; d0 := line
	move.w	d7,d1				; d1 := count
	jsr	_print_hreq_lines		; print new entry
	move.l	a3,hr_Display+d_FirstVisibleNode(a2)

shu_draw_cursor:
	bsr	hcomp_hreq_cursor		; draw new cursor line

shu_exit:
	rts

;---------------------------------------------------------------------------
; Input : a2   = history request ptr
;	  a6   = GfxBase
;	  d7.l = scroll count
; Scroll history list of active history requester count times down
;---------------------------------------------------------------------------
scroll_hreq_down:
	moveq	#0,d2
	move.w	hr_Display+d_VisibleLines(a2),d2	; d2 := visible lines
	move.l	hr_Display+d_NumEntries(a2),d3		; d3 := number of entries
	move.l	hr_Display+d_FirstVisibleNode(a2),a3	; check cursor line + count
	moveq	#0,d4
	move.w	hr_CursorLine(a2),d4
	add.l	ln_Pos(a3),d4
	cmp.l	d3,d4				; already at bottom ?
	beq	shd_exit
	bsr	hcomp_hreq_cursor		; clear old cursor line
	subq.l	#1,d4
	add.l	d7,d4
	cmp.l	d3,d4
	blo	shd_move_cursor
	move.l	ln_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bls	shd_start_scroll
	cmp.l	d2,d3				; more than one page ?
	bhi	shd_more_pages
	move.w	d3,d0				; now cursor at bottom
	subq.w	#1,d0
	move.w	d0,hr_CursorLine(a2)
	bra	shd_draw_cursor

shd_more_pages:
	move.w	d2,d0				; now cursor at bottom
	subq.w	#1,d0
	move.w	d0,hr_CursorLine(a2)
	bra	shd_scroll

shd_move_cursor:
	move.w	hr_CursorLine(a2),d0		; dec cursor line
	add.w	d7,d0
	move.w	d2,d1
	subq.w	#1,d1				; d1 := visible lines - 1
	cmp.w	d1,d0
	bhi	shd_scroll
	bne	shd_set_cursor			; cursor at bottom ?
	move.l	ln_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bls	shd_start_scroll

shd_set_cursor:
	move.w	d0,hr_CursorLine(a2)
	bra	shd_draw_cursor

shd_scroll:
	move.l	ln_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bhi	shd_draw_cursor

shd_start_scroll:
	move.w	d7,d0				; d0 := scroll count
	subq.w	#1,d0				; dec count for dbra

shd_loop:
	move.l	ln_Pos(a3),d1			; bottom reached ?
	add.l	d2,d1
	cmp.l	d3,d1
	bhi	shd_check_count
	move.l	MLN_SUCC(a3),a3			; get next node
	dbra	d0,shd_loop

shd_check_count:
	cmp.w	#1,d7				; paging ?
	bhi	shd_paging

shd_init_scroll:
	move.l	_con_rport,a0			; source rport
	move.l	a0,a1				; dest rport
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	d1,d3				; y2
	move.w	d0,d2				; x2
	move.w	fr_Display+d_Width(a2),d4	; width
	move.w	fr_Display+d_VisibleLines(a2),d5
	lsl.w	#3,d5				; height
	move.w	#$0c0,d6			; minterm
	cmp.b	#SCROLL_SPEED_SLOW,_vsh_scroll_speed
	beq	shd_scroll_slow

shd_scroll_normal:
	addq.w	#8,d1				; y1
	subq.w	#8,d5				; height
	CALLSYS	ClipBlit			; scroll one entry up
	bra	shd_scroll_end

shd_scroll_slow:
	PUSH	d7
	addq.w	#1,d1				; y1
	moveq	#8-1,d7				; d7 := count

1$:
	movem.w	d0-d6,-(sp)
	PUSH	a0-a1
	CALLSYS	ClipBlit			; scroll one scanline up
	PULL	a0-a1
	movem.w	(sp)+,d0-d6
	dbra	d7,1$
	PULL	d7

shd_scroll_end:
	move.l	a3,a1				; a1 := node
	move.w	hr_Display+d_VisibleLines(a2),d0
	subq.w	#1,d0				; d0 := line
	move.w	d0,d1
	subq.w	#1,d1				; dec for dbra

shd_get_last_line:
	move.l	MLN_SUCC(a1),a1			; get next node
	dbra	d1,shd_get_last_line
	move.w	d7,d1				; d1 := count
	bra	shd_print

shd_paging:
	moveq	#0,d0				; d0 := line
	move.w	d7,d1				; d1 := count
	move.l	a3,a1				; a1 := node

shd_print:
	move.l	a2,a0				; a0 := hreq
	jsr	_print_hreq_lines		; print new entry
	move.l	a3,hr_Display+d_FirstVisibleNode(a2)

shd_draw_cursor:
	bsr	hcomp_hreq_cursor		; draw new cursor line

shd_exit:
	rts
