<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://learn.cemetech.net/index.php?action=history&amp;feed=atom&amp;title=Z80%3AMenu_Routines</id>
	<title>Z80:Menu Routines - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://learn.cemetech.net/index.php?action=history&amp;feed=atom&amp;title=Z80%3AMenu_Routines"/>
	<link rel="alternate" type="text/html" href="http://learn.cemetech.net/index.php?title=Z80:Menu_Routines&amp;action=history"/>
	<updated>2026-06-16T15:50:16Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.3</generator>
	<entry>
		<id>http://learn.cemetech.net/index.php?title=Z80:Menu_Routines&amp;diff=102&amp;oldid=prev</id>
		<title>KermMartian: Created page with &quot;= Basics =  A useful method of having a program interacting with the user is through a menu. However, menu&#039;s fall under a broad category. So what is a menu? A menu must have:...&quot;</title>
		<link rel="alternate" type="text/html" href="http://learn.cemetech.net/index.php?title=Z80:Menu_Routines&amp;diff=102&amp;oldid=prev"/>
		<updated>2016-02-03T21:27:49Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;= Basics =  A useful method of having a program interacting with the user is through a menu. However, menu&amp;#039;s fall under a broad category. So what is a menu? A menu must have:...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= Basics =&lt;br /&gt;
&lt;br /&gt;
A useful method of having a program interacting with the user is through a menu. However, menu&amp;#039;s fall under a broad category. So what is a menu? A menu must have:&lt;br /&gt;
&lt;br /&gt;
* List(s) of possible actions that the user can perform&lt;br /&gt;
* A method of selecting items from the list(s)&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s a chunk of code that will create a simple menu with a header(Test Menu), 4 items (A,B,C, and Quit), and allow the user to select an item. All the other optional stuff will be added later.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ;Hard-coded menu routine&lt;br /&gt;
    ;&lt;br /&gt;
    ;inputs: none&lt;br /&gt;
    ;&lt;br /&gt;
    ;outputs: menu&lt;br /&gt;
    ;&lt;br /&gt;
    ;destroyed: all&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    menuStart:		;Start of menu routine&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)		;Display the Header&lt;br /&gt;
     ld hl,txtHeader&lt;br /&gt;
     call dispHeader&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtItem1			;Display Items&lt;br /&gt;
     call dispItem&lt;br /&gt;
     ld hl,txtItem2&lt;br /&gt;
     call dispItem&lt;br /&gt;
     ld hl,txtItem3&lt;br /&gt;
     call dispItem&lt;br /&gt;
     ld hl,txtItemQuit&lt;br /&gt;
     call dispItem&lt;br /&gt;
     &lt;br /&gt;
    menuLoop:		;Scan key loop to get user input&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     cp k1			;If user pressed 1, do action 1&lt;br /&gt;
     jr z,item1&lt;br /&gt;
    &lt;br /&gt;
     cp k2			;If user pressed 2, do action 2&lt;br /&gt;
     jr z,item2&lt;br /&gt;
    &lt;br /&gt;
     cp k3			;If user pressed 3, do action 3&lt;br /&gt;
     jr z,item3&lt;br /&gt;
    &lt;br /&gt;
     cp k4			;If user pressed 4, quit&lt;br /&gt;
     jr z,quit&lt;br /&gt;
    &lt;br /&gt;
     jr menuLoop		;Else, invalid input. Wait for user to input new key&lt;br /&gt;
    &lt;br /&gt;
    item1:			;Action 1&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
    &lt;br /&gt;
     ld bc,0&lt;br /&gt;
     ld (curRow),bc&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect1&lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     jr menuStart&lt;br /&gt;
    &lt;br /&gt;
    item2:			;Action 2&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
    &lt;br /&gt;
     ld bc,0&lt;br /&gt;
     ld (curRow),bc&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect2&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     jr menuStart&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    item3:			;Action 3&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
    &lt;br /&gt;
     ld bc,0&lt;br /&gt;
     ld (curRow),bc&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect3&lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     jr menuStart&lt;br /&gt;
    &lt;br /&gt;
    quit:			;quit the program&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
     &lt;br /&gt;
    ;dispHeader&lt;br /&gt;
    ;&lt;br /&gt;
    ;displays the header centered and at the top&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: HL points to null-terminating string&lt;br /&gt;
    ;&lt;br /&gt;
    ;Output: text displayed to string, top center right and inverse text &lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: bc,hl&lt;br /&gt;
    ;&lt;br /&gt;
    ;Note: text string must be large text and take up the full line&lt;br /&gt;
    ;(use blank spaces to fill in gaps)&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    dispHeader:				;displays the header centered and at the top&lt;br /&gt;
    &lt;br /&gt;
     ld bc,$0&lt;br /&gt;
     ld (curRow),bc&lt;br /&gt;
    &lt;br /&gt;
     set textInverse,(IY+TextFlags)&lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     res textInverse,(IY+TextFlags)&lt;br /&gt;
    &lt;br /&gt;
     ld hl,0&lt;br /&gt;
     ld (curRow),hl&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
     &lt;br /&gt;
    ;dispItem&lt;br /&gt;
    ;&lt;br /&gt;
    ;displays menu items at the start of the next line&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: HL points to null-terminating string&lt;br /&gt;
    ;&lt;br /&gt;
    ;Output: text displayed&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: all&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    dispItem:				;displays menu items at the start of the next line&lt;br /&gt;
    &lt;br /&gt;
     push hl&lt;br /&gt;
     bcall(_NewLine)&lt;br /&gt;
     pop hl&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
     &lt;br /&gt;
    ;========================================&lt;br /&gt;
    ;data&lt;br /&gt;
    ;========================================&lt;br /&gt;
     &lt;br /&gt;
    txtHeader:&lt;br /&gt;
     .db &amp;quot;   Test  Menu   &amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtItem1:&lt;br /&gt;
     .db &amp;quot;1:A&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtItem2:&lt;br /&gt;
     .db &amp;quot;2:B&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtItem3:&lt;br /&gt;
     .db &amp;quot;3:C&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtSelect1:&lt;br /&gt;
     .db &amp;quot;You have selected A&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtSelect2:&lt;br /&gt;
     .db &amp;quot;You have selected B&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtSelect3:&lt;br /&gt;
     .db &amp;quot;You have selected C&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItemQuit:&lt;br /&gt;
     .db &amp;quot;4:Quit&amp;quot;,0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hopefully from the code you&amp;#039;ll be able to understand the general flow.&lt;br /&gt;
First, the program runs menuStart, which displays the menu header and items to the display with the sub-routines dispHeader and dispItem.&lt;br /&gt;
Once the menu has been displayed, wait for a user input.&lt;br /&gt;
If the user presses &amp;quot;1&amp;quot;, do action 1 (display &amp;quot;You have selected A&amp;quot;)&lt;br /&gt;
If the user presses &amp;quot;2&amp;quot;, do action 2&lt;br /&gt;
If the user presses &amp;quot;3&amp;quot;, do action 3&lt;br /&gt;
If the user presses &amp;quot;4&amp;quot;, quit&lt;br /&gt;
&lt;br /&gt;
For a simple menu, this isn&amp;#039;t too bad. However, it&amp;#039;s bland, and void of features. So, let&amp;#039;s add some features.&lt;br /&gt;
&lt;br /&gt;
= Cursor =&lt;br /&gt;
&lt;br /&gt;
To give the user some convenience, we&amp;#039;ll add a cursor. The cursor allows the user to input up or down and use enter to select an item besides just pressing the corresponding number.&lt;br /&gt;
&lt;br /&gt;
To do so, we&amp;#039;ll need some code that will draw the cursor:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ;curDraw&lt;br /&gt;
    ;&lt;br /&gt;
    ;Draws the cursor&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: C holds the highlighted item&lt;br /&gt;
    ;&lt;br /&gt;
    ;Outputs: Cursor displayed&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: A&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    curDraw:&lt;br /&gt;
     set textInverse,(IY+TextFlags)	;set inverse text&lt;br /&gt;
     &lt;br /&gt;
     xor a&lt;br /&gt;
     ld (curCol),a&lt;br /&gt;
     ld a,c&lt;br /&gt;
     ld (curRow),a&lt;br /&gt;
     &lt;br /&gt;
     add a,$30				;Character offset&lt;br /&gt;
     &lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
     &lt;br /&gt;
     ld a,&amp;#039;:&amp;#039;&lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
    &lt;br /&gt;
     res textInverse,(IY+TextFlags)&lt;br /&gt;
     ret&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And, we&amp;#039;ll also need some code to erase the cursor:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ;curErase&lt;br /&gt;
    ;&lt;br /&gt;
    ;Erase the cursor&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: C highlighted item&lt;br /&gt;
    ;&lt;br /&gt;
    ;Ouputs: Cursor erased&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: A&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    curErase:&lt;br /&gt;
     xor a&lt;br /&gt;
     ld (curCol),a&lt;br /&gt;
     ld a,c&lt;br /&gt;
     ld (curRow),a&lt;br /&gt;
     &lt;br /&gt;
     add a,$30				;Character offset&lt;br /&gt;
     &lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
     &lt;br /&gt;
     ld a,&amp;#039;:&amp;#039;&lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What happens if the user presses up/down/enter? We&amp;#039;ll need to add code to deal with the new key presses.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ;Updated menuloop&lt;br /&gt;
    ;Stuff with asterisks are new&lt;br /&gt;
    &lt;br /&gt;
    *ld c,1*			;add this to menuStart to set initial cursor location&lt;br /&gt;
    &lt;br /&gt;
    menuLoop:		;Scan key loop to get user input&lt;br /&gt;
    &lt;br /&gt;
    *call curDraw*&lt;br /&gt;
    *push bc*			;save C for later&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
    *pop bc*			;we&amp;#039;ll need this for some routines with the new keypresses&lt;br /&gt;
    &lt;br /&gt;
    *cp kup*&lt;br /&gt;
    *jr z, mUp*&lt;br /&gt;
    &lt;br /&gt;
    *cp kdown*&lt;br /&gt;
    *jr z, mDown*&lt;br /&gt;
    &lt;br /&gt;
    *cp kenter*&lt;br /&gt;
    *jr z, selection*&lt;br /&gt;
    &lt;br /&gt;
     cp k1			;If user pressed 1, do action 1&lt;br /&gt;
     jr z,item1&lt;br /&gt;
    &lt;br /&gt;
     cp k2			;If user pressed 2, do action 2&lt;br /&gt;
     jr z,item2&lt;br /&gt;
    &lt;br /&gt;
     cp k3			;If user pressed 3, do action 3&lt;br /&gt;
     jr z,item3&lt;br /&gt;
    &lt;br /&gt;
     cp k4			;If user pressed 4, quit&lt;br /&gt;
     jr z,quit&lt;br /&gt;
    &lt;br /&gt;
     jr menuLoop		;Else, invalid input. Wait for user to input new key&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Move the cursor up:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ;mUp&lt;br /&gt;
    ;&lt;br /&gt;
    ;moves cursor up&lt;br /&gt;
    ;&lt;br /&gt;
    ;inputs: C highlighted item&lt;br /&gt;
    ;&lt;br /&gt;
    ;Ouputs: updated cursor place stored in C&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: A&lt;br /&gt;
    ;&lt;br /&gt;
    ;Notes: still need to call curDraw to re-draw the cursor&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    mUp:&lt;br /&gt;
    &lt;br /&gt;
     call curErase			;erase the cursor&lt;br /&gt;
    &lt;br /&gt;
     ld a,c				;check if the cursor is out of bounds&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr z,menuLoop&lt;br /&gt;
    &lt;br /&gt;
     dec c				;if not, decrease and return&lt;br /&gt;
     jr menuLoop&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...And, down:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ;mDown&lt;br /&gt;
    ;&lt;br /&gt;
    ;moves cursor down&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: C highlighted item&lt;br /&gt;
    ;&lt;br /&gt;
    ;Outputs: updated cursor place sctored in C&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed:&lt;br /&gt;
    ;&lt;br /&gt;
    ;Notes: still need to call curDraw to re-draw the cursor&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    mDown:&lt;br /&gt;
    &lt;br /&gt;
     call curErase			;erase the cursor&lt;br /&gt;
    &lt;br /&gt;
     ld a,c				;check if the cursor is out of bounds&lt;br /&gt;
     cp 4&lt;br /&gt;
     jr z,menuLoop&lt;br /&gt;
    &lt;br /&gt;
     inc c				;if not, increase and return&lt;br /&gt;
     jr menuLoop&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This bit of code will be called when the user presses enter:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    selection:&lt;br /&gt;
    &lt;br /&gt;
     ld a,c&lt;br /&gt;
    &lt;br /&gt;
     cp 1&lt;br /&gt;
     jr z,item1&lt;br /&gt;
    &lt;br /&gt;
     cp 2&lt;br /&gt;
     jr z,item2&lt;br /&gt;
    &lt;br /&gt;
     cp 3&lt;br /&gt;
     jr z,item3&lt;br /&gt;
    &lt;br /&gt;
     jr quit&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;quot;2-D&amp;quot; Menus =&lt;br /&gt;
&lt;br /&gt;
Instead of only having the choice up and down, why not categorize items and then display the categories left to right? An example of this is the OS&amp;#039;s math menu.&lt;br /&gt;
&lt;br /&gt;
[[File:2dmenu.jpg]]&lt;br /&gt;
&lt;br /&gt;
The code for 2 dimensional menus is much more complicated than the standard 1 dimensional menu, but is still manageable for the calculator. Not only do you have to keep track of which item is currently highlighted, you also need to keep track of which group that item is part of.&lt;br /&gt;
&lt;br /&gt;
Since there are enough differences between the code for a 1 dimensional and 2 dimensional menu, I&amp;#039;ll post the code in it&amp;#039;s entirety. Be aware that it&amp;#039;s a lot longer.&lt;br /&gt;
&lt;br /&gt;
This menu has 4 items in each group, with 3 groups.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    menuStart:        ;Start of menu routine&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)        ;Display the Header&lt;br /&gt;
    &lt;br /&gt;
     ld b,1		;Which group is being displayed&lt;br /&gt;
      &lt;br /&gt;
    dispMenu:		;display the menu&lt;br /&gt;
     &lt;br /&gt;
     ld c,1			;Which item is highlighted&lt;br /&gt;
     push bc&lt;br /&gt;
     &lt;br /&gt;
     ld hl,txtHeader		;display the header&lt;br /&gt;
     call dispHeader&lt;br /&gt;
    &lt;br /&gt;
     ld a,b&lt;br /&gt;
     &lt;br /&gt;
     cp 1&lt;br /&gt;
     jr nz,dispMenu2&lt;br /&gt;
     &lt;br /&gt;
     ld b,3&lt;br /&gt;
     ld hl,txtItem1_1            ;Display Items in GA&lt;br /&gt;
     call dispItems&lt;br /&gt;
     &lt;br /&gt;
     jr dispMenu4&lt;br /&gt;
     &lt;br /&gt;
    dispMenu2:&lt;br /&gt;
    &lt;br /&gt;
     cp 2&lt;br /&gt;
     jr nz,dispMenu3&lt;br /&gt;
    &lt;br /&gt;
     ld b,3&lt;br /&gt;
     ld hl,txtItem2_1		;Display Items in GB&lt;br /&gt;
     call dispItems&lt;br /&gt;
     jr dispMenu4&lt;br /&gt;
    &lt;br /&gt;
    dispMenu3:&lt;br /&gt;
    &lt;br /&gt;
     ld b,3&lt;br /&gt;
     ld hl,txtItem3_1		;Display Items in GC&lt;br /&gt;
     call dispItems&lt;br /&gt;
    &lt;br /&gt;
    dispMenu4:			;Since every group has a quit, display it here&lt;br /&gt;
     bcall(_NewLine)&lt;br /&gt;
     ld hl,txtItemQuit&lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     &lt;br /&gt;
     pop bc&lt;br /&gt;
    &lt;br /&gt;
    menuLoop:        ;Scan key loop to get user input&lt;br /&gt;
    &lt;br /&gt;
     call curDraw&lt;br /&gt;
     push bc            ;save BC for later&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     pop bc            ;we&amp;#039;ll need this for some routines with the new keypresses&lt;br /&gt;
    &lt;br /&gt;
     cp kleft&lt;br /&gt;
     jr z,mLeft&lt;br /&gt;
     &lt;br /&gt;
     cp kright&lt;br /&gt;
     jr z,mRight&lt;br /&gt;
    &lt;br /&gt;
     cp kup&lt;br /&gt;
     jr z, mUp&lt;br /&gt;
    &lt;br /&gt;
     cp kdown&lt;br /&gt;
     jr z, mDown&lt;br /&gt;
    &lt;br /&gt;
     cp kenter&lt;br /&gt;
     jr z, selection&lt;br /&gt;
    &lt;br /&gt;
     cp k1            ;If user pressed 1, do action 1&lt;br /&gt;
     jr z,item1&lt;br /&gt;
    &lt;br /&gt;
     cp k2            ;If user pressed 2, do action 2&lt;br /&gt;
     jr z,item2&lt;br /&gt;
    &lt;br /&gt;
     cp k3            ;If user pressed 3, do action 3&lt;br /&gt;
     jp z,item3&lt;br /&gt;
    &lt;br /&gt;
     cp k4            ;If user pressed 4, quit&lt;br /&gt;
     jp z,quit&lt;br /&gt;
    &lt;br /&gt;
     jr menuLoop        ;Else, invalid input. Wait for user to input new key&lt;br /&gt;
    &lt;br /&gt;
    mUp:&lt;br /&gt;
    &lt;br /&gt;
     call curErase            ;erase the cursor&lt;br /&gt;
    &lt;br /&gt;
     ld a,c                ;check if the cursor is out of bounds&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr z,menuLoop&lt;br /&gt;
    &lt;br /&gt;
     dec c                ;if not, decrease and return&lt;br /&gt;
     jr menuLoop&lt;br /&gt;
    &lt;br /&gt;
    mDown:&lt;br /&gt;
    &lt;br /&gt;
     call curErase            ;erase the cursor&lt;br /&gt;
    &lt;br /&gt;
     ld a,c                ;check if the cursor is out of bounds&lt;br /&gt;
     cp 4&lt;br /&gt;
     jr z,menuLoop&lt;br /&gt;
    &lt;br /&gt;
     inc c                ;if not, increase and return&lt;br /&gt;
     jr menuLoop&lt;br /&gt;
    &lt;br /&gt;
    mRight:		;change group&lt;br /&gt;
    &lt;br /&gt;
     ld a,b		;check if already as far right as possible&lt;br /&gt;
     cp 3&lt;br /&gt;
     jr z,menuLoop&lt;br /&gt;
     &lt;br /&gt;
     inc b&lt;br /&gt;
     &lt;br /&gt;
     jp dispMenu&lt;br /&gt;
    &lt;br /&gt;
    mLeft:		;change group&lt;br /&gt;
    &lt;br /&gt;
     ld a,b		;check if already as far right as possible&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr z,menuLoop&lt;br /&gt;
     &lt;br /&gt;
     dec b&lt;br /&gt;
     &lt;br /&gt;
     jp dispMenu&lt;br /&gt;
    &lt;br /&gt;
    selection:&lt;br /&gt;
    &lt;br /&gt;
     ld a,c&lt;br /&gt;
    &lt;br /&gt;
     cp 1&lt;br /&gt;
     jr z,item1&lt;br /&gt;
    &lt;br /&gt;
     cp 2&lt;br /&gt;
     jr z,item2&lt;br /&gt;
    &lt;br /&gt;
     cp 3&lt;br /&gt;
     jr z,item3&lt;br /&gt;
    &lt;br /&gt;
     jp quit&lt;br /&gt;
    &lt;br /&gt;
    item1:            ;Action 1&lt;br /&gt;
    &lt;br /&gt;
     push bc&lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
     pop bc&lt;br /&gt;
    &lt;br /&gt;
     ld de,0&lt;br /&gt;
     ld (curRow),de&lt;br /&gt;
    &lt;br /&gt;
     ld a,b&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr nz,item1B&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect1_1		;action 1 for group A&lt;br /&gt;
     &lt;br /&gt;
     jr item1Done&lt;br /&gt;
    item1B:&lt;br /&gt;
     cp 2&lt;br /&gt;
     jr nz,item1C&lt;br /&gt;
     &lt;br /&gt;
     ld hl,txtSelect2_1		;action 1 for group B&lt;br /&gt;
     &lt;br /&gt;
     jr item1Done&lt;br /&gt;
    &lt;br /&gt;
    item1C:&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect3_1		;action 1 for group C&lt;br /&gt;
    &lt;br /&gt;
    item1Done:&lt;br /&gt;
     bcall(_PutS)			;we&amp;#039;ll display the text now&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     jp menuStart&lt;br /&gt;
    &lt;br /&gt;
    item2:            ;Action 2&lt;br /&gt;
    &lt;br /&gt;
     push bc&lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
     pop bc&lt;br /&gt;
    &lt;br /&gt;
     ld de,0&lt;br /&gt;
     ld (curRow),de&lt;br /&gt;
    &lt;br /&gt;
     ld a,b&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr nz,item2B&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect1_2		;action 2 for group A&lt;br /&gt;
     &lt;br /&gt;
     jr item2Done&lt;br /&gt;
    item2B:&lt;br /&gt;
     cp 2&lt;br /&gt;
     jr nz,item2C&lt;br /&gt;
     &lt;br /&gt;
     ld hl,txtSelect2_2		;action 2 for group B&lt;br /&gt;
     &lt;br /&gt;
     jr item2Done&lt;br /&gt;
    &lt;br /&gt;
    item2C:&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect3_2		;action 2 for group C&lt;br /&gt;
    &lt;br /&gt;
    item2Done:&lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     jp menuStart&lt;br /&gt;
     &lt;br /&gt;
    item3:            ;Action 3&lt;br /&gt;
    &lt;br /&gt;
     push bc&lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
     pop bc&lt;br /&gt;
    &lt;br /&gt;
     ld de,0&lt;br /&gt;
     ld (curRow),de&lt;br /&gt;
    &lt;br /&gt;
     ld a,b&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr nz,item3B&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect1_3		;action 3 for group A&lt;br /&gt;
     &lt;br /&gt;
     jr item2Done&lt;br /&gt;
    item3B:&lt;br /&gt;
     cp 2&lt;br /&gt;
     jr nz,item3C&lt;br /&gt;
     &lt;br /&gt;
     ld hl,txtSelect2_3		;action 3 for group B&lt;br /&gt;
     &lt;br /&gt;
     jr item1Done&lt;br /&gt;
    &lt;br /&gt;
    item3C:&lt;br /&gt;
    &lt;br /&gt;
     ld hl,txtSelect3_3		;action 3 for group C&lt;br /&gt;
    &lt;br /&gt;
    item3Done:&lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     bcall(_GetKey)&lt;br /&gt;
    &lt;br /&gt;
     jp menuStart&lt;br /&gt;
    &lt;br /&gt;
    quit:            ;quit the program&lt;br /&gt;
    &lt;br /&gt;
     bcall(_ClrLCDFull)&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
    &lt;br /&gt;
    ;dispHeader&lt;br /&gt;
    ;&lt;br /&gt;
    ;displays the header centered and at the top&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: HL points to null-terminating string&lt;br /&gt;
    ;&lt;br /&gt;
    ;Output: text displayed, with the current group in inverse text &lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: a,de,hl&lt;br /&gt;
    ;&lt;br /&gt;
    ;Note: text string must be large text and take up the full line&lt;br /&gt;
    ;(use blank spaces to fill in gaps)&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    dispHeader:                ;displays the header centered and at the top&lt;br /&gt;
    &lt;br /&gt;
     ld de,0&lt;br /&gt;
     ld (curRow),de&lt;br /&gt;
    &lt;br /&gt;
     ld a,b&lt;br /&gt;
     cp 1&lt;br /&gt;
     jr nz,dispHeader1&lt;br /&gt;
     set textInverse,(IY+TextFlags)&lt;br /&gt;
    &lt;br /&gt;
    dispHeader1:					;group A&lt;br /&gt;
     &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     res textInverse,(IY+TextFlags)&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     &lt;br /&gt;
     cp 2&lt;br /&gt;
     jr nz,dispHeader2&lt;br /&gt;
     set textInverse,(IY+TextFlags)&lt;br /&gt;
     &lt;br /&gt;
    dispHeader2:					;group B&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     res textInverse,(IY+TextFlags)&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     cp 3&lt;br /&gt;
     jr nz,dispHeader3&lt;br /&gt;
     &lt;br /&gt;
     set textInverse,(IY+TextFlags)&lt;br /&gt;
     &lt;br /&gt;
    dispHeader3:					;group C&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
     res textInverse,(IY+TextFlags)&lt;br /&gt;
     &lt;br /&gt;
     ld hl,0&lt;br /&gt;
     ld (curRow),hl&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
    &lt;br /&gt;
    ;dispItems&lt;br /&gt;
    ;&lt;br /&gt;
    ;displays menu items at the start of the next line&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: HL points to null-terminating string&lt;br /&gt;
    ;&lt;br /&gt;
    ;Output: text displayed&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: all&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    dispItems:                ;displays menu items at the start of the next line&lt;br /&gt;
    &lt;br /&gt;
     push bc&lt;br /&gt;
     push hl&lt;br /&gt;
     bcall(_NewLine)&lt;br /&gt;
     pop hl&lt;br /&gt;
     pop bc&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutS)&lt;br /&gt;
    &lt;br /&gt;
     djnz dispItems&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
    &lt;br /&gt;
    ;curDraw&lt;br /&gt;
    ;&lt;br /&gt;
    ;Draws the cursor&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: C holds the highlighted item&lt;br /&gt;
    ;&lt;br /&gt;
    ;Outputs: Cursor displayed&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: A&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    curDraw:&lt;br /&gt;
     set textInverse,(IY+TextFlags)    ;set inverse text&lt;br /&gt;
    &lt;br /&gt;
     xor a&lt;br /&gt;
     ld (curCol),a&lt;br /&gt;
     ld a,c&lt;br /&gt;
     ld (curRow),a&lt;br /&gt;
    &lt;br /&gt;
     add a,$30                ;Character offset&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
    &lt;br /&gt;
     ld a,&amp;#039;:&amp;#039;&lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
    &lt;br /&gt;
     res textInverse,(IY+TextFlags)&lt;br /&gt;
     ret&lt;br /&gt;
     &lt;br /&gt;
    ;curErase&lt;br /&gt;
    ;&lt;br /&gt;
    ;Erase the cursor&lt;br /&gt;
    ;&lt;br /&gt;
    ;Inputs: C highlighted item&lt;br /&gt;
    ;&lt;br /&gt;
    ;Ouputs: Cursor erased&lt;br /&gt;
    ;&lt;br /&gt;
    ;Destroyed: A&lt;br /&gt;
    ;&lt;br /&gt;
    &lt;br /&gt;
    curErase:&lt;br /&gt;
     xor a&lt;br /&gt;
     ld (curCol),a&lt;br /&gt;
     ld a,c&lt;br /&gt;
     ld (curRow),a&lt;br /&gt;
    &lt;br /&gt;
     add a,$30                ;Character offset&lt;br /&gt;
    &lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
    &lt;br /&gt;
     ld a,&amp;#039;:&amp;#039;&lt;br /&gt;
     bcall(_PutC)&lt;br /&gt;
    &lt;br /&gt;
     ret&lt;br /&gt;
    &lt;br /&gt;
    ;========================================&lt;br /&gt;
    ;data&lt;br /&gt;
    ;========================================&lt;br /&gt;
    &lt;br /&gt;
    txtHeader:&lt;br /&gt;
     .db &amp;quot;GA&amp;quot;,0&lt;br /&gt;
     .db &amp;quot;   &amp;quot;,0&lt;br /&gt;
     .db &amp;quot;GB&amp;quot;,0&lt;br /&gt;
     .db &amp;quot;   &amp;quot;,0&lt;br /&gt;
     .db &amp;quot;GC&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem1_1:&lt;br /&gt;
     .db &amp;quot;1:A1&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem1_2:&lt;br /&gt;
     .db &amp;quot;2:A2&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem1_3:&lt;br /&gt;
     .db &amp;quot;3:A3&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem2_1:&lt;br /&gt;
     .db &amp;quot;1:B1&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem2_2:&lt;br /&gt;
     .db &amp;quot;2:B2&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem2_3:&lt;br /&gt;
     .db &amp;quot;3:B3&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtItem3_1:&lt;br /&gt;
     .db &amp;quot;1:C1&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem3_2:&lt;br /&gt;
     .db &amp;quot;2:C2&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItem3_3:&lt;br /&gt;
     .db &amp;quot;3:C3&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect1_1:&lt;br /&gt;
     .db &amp;quot;You selected A1&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect1_2:&lt;br /&gt;
     .db &amp;quot;You selected A2&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect1_3:&lt;br /&gt;
     .db &amp;quot;You selected A3&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect2_1:&lt;br /&gt;
     .db &amp;quot;You selected B1&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect2_2:&lt;br /&gt;
     .db &amp;quot;You selected B2&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtSelect2_3:&lt;br /&gt;
     .db &amp;quot;You selected B3&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect3_1:&lt;br /&gt;
     .db &amp;quot;You selected C1&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtSelect3_2:&lt;br /&gt;
     .db &amp;quot;You selected C2&amp;quot;,0&lt;br /&gt;
     &lt;br /&gt;
    txtSelect3_3:&lt;br /&gt;
     .db &amp;quot;You selected C3&amp;quot;,0&lt;br /&gt;
    &lt;br /&gt;
    txtItemQuit:&lt;br /&gt;
     .db &amp;quot;4:Quit&amp;quot;,0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Scrolling menus =&lt;br /&gt;
&lt;br /&gt;
What if you have more items than will fit in one screen? A solution to this is to display items on the screen and then when the user scrolls past the limits of the screen, it will &amp;quot;move&amp;quot; the items up and display the other items that wouldn&amp;#039;t fit.&lt;br /&gt;
&lt;br /&gt;
[[File:scrollingmenu.gif]]&lt;br /&gt;
&lt;br /&gt;
= Summary =&lt;br /&gt;
&lt;br /&gt;
There are so many variations of a menu interface that showing them all would be impractical and impossible. Use your imagination and come up with variations, like displaying pictures in the background, having a custom cursor, or anything else you can think of.&lt;br /&gt;
&lt;br /&gt;
{{lowercase}}&lt;br /&gt;
[[Category:Z80 Assembly]]&lt;br /&gt;
[[Category:Z80 Heaven]]&lt;/div&gt;</summary>
		<author><name>KermMartian</name></author>
	</entry>
</feed>