cursorLogic.asm - RLH-2110/gbCalc GitHub Wiki

Table of Contents

Overview
CursorArray
CursorHandler
wCursorState vs wCursorPos
Routines
CursotSetPosition

Overview

This file determines the actions of the buttons on the current cursor position, like what to do to when moving left and right or pressing up and down.
It also handles positioning the cursor graphics.

CursorArray

At the start of the file, we create a jump table and a table to index into the jump table. This will be used to determine what we do on certain actions.

	;indexes for the cursor array
	CursorArray::
	dw .cs0, .cs1, .cs2, .cs3, .cs4

	;tilemap offset, inc routine, dec routine, left routine, right routine
	.cs0:
	dw screen + $102, CursorSignToggle, CursorSignToggle, CursorWrapToRight, CursorRight
	.cs1:
	dw screen + $103, CursorNumberInc, CursorNumberDec, CursorNumberLeft, CursorNumberRight
	.cs2:
	dw screen + $109, CursorOperatorInc, CursorOperatorDec, CursorLeft, CursorRight
	.cs3:
	dw screen + $10B, CursorSignToggle, CursorSignToggle, CursorLeft, CursorRight
	.cs4:
	dw screen + $10C, CursorNumberInc, CursorNumberDec, CursorNumberLeft, CursorNumberRight

Here is the same table as a graphic:
TableVisualized

CursorHandler

This routine jumps to the right routine based on the lookup table, the current cursor position, and the value of e (e = what action to do)

here is the head of the routine:

; this subroutine jumps to a subroutine defined in an array thats indexed by the cursor state and the A register
; E: function selector
CursorHandler::
	push af
	push hl
	push bc
	push de


	; note: 
	; [CursorArray+CursorState]->CursorData
	; [CursorData-+offset]->functionPointer

And here we get the new base pointer that points into the right part of the table based onto the cursor address:

	ld hl,CursorArray ; base adress

	;bc = wCursorState (used as an offset)
	ld b, 0
	ld a,[wCursorState] 
	ld c,a


	add hl,bc ; combine base adress with the offset
	add hl,bc ; do it twice, since the data is 2 byte big

	; get pointer to new base adress
	ld c,[hl] ;load lower part of the new base adress
	inc hl
	ld b,[hl] ;load upper part

Here is an example with the previous graphic:
TableVisualizedSR

After that, we save the tile map address of where the cursor is into BC

	;transfer to hl
	ld h,b
	ld l,c

        ;load tilemap adress into bc
	ld c,[hl] ; load lower part
	inc hl
	ld b,[hl] ; load upper part
	dec hl
	push bc ; save tilemap address

Now we index into our selected part of the jump table

ld d,0

	; e * 2 (since the data is 2 bytes long)
	SLA e 

	add hl,de ; apply offset parameter to new base adress

	; get the pointer thats behind the new adress
	ld c,[hl] ;load lower part of the pointer
	inc hl
	ld b,[hl] ;load upper part

	;transfer to hl
	ld h,b
	ld l,c

	;HL now contains the pointer.

Here is another example graphic:
TableVisualizedSRC

here is the rest of the routine, it saved the tile map address of the cursor position into DE and then calls the routine in our jump table.

;get the tilemap adress into de
	pop de
	;call the function
	ld bc,.CursorHanlderReturnAdress
	push bc ; push return adress onto the stack
	jp hl ; call the function pased on the pointer we got

	.CursorHanlderReturnAdress
	pop de
	pop bc 
	pop hl
	pop af
	ret

wCursorState vs wCursorPos

wCursorState keeps track on what element the cursor is, like the first sign, the first number, the operator, ...
However, it does not keep track where the cursor is within a number. It can tell you its number0, but not where in number0

wCursorPos tells you where the cursor is inside a number, but it does not tell you what number it is in. It's just an offset from the start of the number.

Routines

Here I list all the routines. All of them except all registers to be free of use.
DE contains the current screen position of the cursor.

You will often see these routines incrementing the contains of HL, which modifies the tile on screen.
The user input is in fact saved in Video RAM and is only later copied into work ram after we need to do something with the input.

You can see the routines in the file, I just provide an example and then list what routines exist.

This routine flips the sign

; DE: tilemap adress
;! assumes that all registers are free to use. !
CursorSignToggle:
	;load offset io the tile with the number into hl
	ld h,d
	ld l,e
	
	; if it is '+'
	ld a,[hl]
	cp a,tile_add
	jr z,.setMinus ; set it to minus

	;else set it to plus
	ld [hl],tile_add

	call validateInput
	ret
.setMinus	
	ld [hl],tile_sub

	call validateInput
	ret

These routines increment/decrement a digit and wraps around if it over/underflows.
It needs to apply the wCursorPos to the tile map location of the cursor.
CursorNumberInc
CursorNumberDec

these routines increment and decrement the Operator and wrap around on over/underflows
CursorOperatorInc
CursorOperatorDec

These are simple cursor movement routines for everything that's not a number
CursorLeft
CursorRight

There, set the position to the left or the right
CursorWrapToLeft ( unused )
CursorWrapToRight

These routines move the cursor within the number, and if it goes out of the number, it goes to the previous/next cursor state
CursorNumberLeft
CursorNumberRight

CursotSetPosition

This routine removes the old cursor graphics and draws the new ones.
Here is the head of the routine:

; BC:	old cursor pos
; DE:	old cursor state  (D is expected to be zero)
; wCursorState:	new cursor pos
CursotSetPosition:
	push hl
	push af

	; note: 
	; [CursorArray+CursorState]->CursorData
	; [CursorData+0] = normal cursor pos 
	; normal cursor pos + cursor pos = actually cursor pos

We then get the row for the old cursor state to get the old tile map offset

	ld hl,CursorArray ; base adress
	sla e
	add hl,de ; apply offset

	; get the adress we point at.
	ld e,[hl]
	inc hl
	ld d,[hl]

	; load adress into hl
	ld h,d
	ld l,e

	; now load the old default cursor pos
	ld e,[hl]
	inc hl
	ld d,[hl]

Here is a graphic:
TableVisualizedSR
Note: since we address the first element, we don't need to apply any more offsets, so we can just load the old tile map offset into DE.

We then add the old cursor position to the old cursor tile map offset and save the result into HL

	; add the old cursor pos
	ld a, d
	add a,b
	ld d,a 

	ld a, e
	add a,c
	ld e,a 

	;load into HL
	ld h,d
	ld l,e

now we remove the old cursor graphics

	; HL and DL = the adress of the old cursor pos in the tilemap

	ld bc,cursorOffset ; bc = offset of how much the cursor grapics are away from the cursor position

	; remove the lower cursor grapic
	add HL,bc	; apply offset to put hl at the adress of the upper lower grapic
	ld [hl],tile_empty ; set tile to nothing

	;restet hl to cursor position
	ld h,d
	ld l,e



	; remove the upper cursor grapic

	; substact bc and hl (apply offset to put hl at the adress of the upper cursor grapic)
	ld a,l
	sub a,c
	ld l,a

	ld a,h
	sbc a,b ; sub with carry!
	ld h,a

	

	; set tile to nothing
	ld [hl],tile_empty

Now the old graphics have been removed, and we can add the new ones.
But first we need to load the new tile map offset and apply the number position!

	; DE = wCursorState
	ld d,0
	ld a,[wCursorState]
	ld e,a

	ld hl,CursorArray ; base adress
	sla e
	add hl,de ; apply offset

	; get the adress we point at.
	ld e,[hl] 
	inc hl
	ld d,[hl]

	; load adress into hl
	ld h,d
	ld l,e

	; now load the old default cursor pos
	ld e,[hl]
	inc hl
	ld d,[hl]

	; add the new cursor pos
	ld b,e
	ld a,[wCursorPos]
	add a,b
	ld e,a

	;load into HL
	ld h,d
	ld l,e

Now we draw the graphics onto the new position

	; HL and DL = the adress of the new cursor pos in the tilemap

	ld bc,cursorOffset ; bc = offset of how much the cursor grapics are away from the cursor position

	; add the lower cursor grapic
	add HL,bc	; apply offset to put hl at the adress of the upper lower grapic
	ld [hl],lower_cursor

	;restet hl to cursor position
	ld h,d
	ld l,e



	; add the upper cursor grapic

	; substact bc and hl (apply offset to put hl at the adress of the upper cursor grapic)
	ld a,l
	sub a,c
	ld l,a

	ld a,h
	sbc a,b ; sub with carry!
	ld h,a

	ld [hl], upper_cursor


	pop af
	pop hl
	ret