Browse Source

Allowing menus with multiple headers. Related to request #45

Zeda Thomas 4 years ago
parent
commit
d09e41dd05
4 changed files with 173 additions and 71 deletions
  1. 64 22
      docs/readme.md
  2. 2 0
      src/01.z80
  3. 74 2
      src/cmd/menu.z80
  4. 33 47
      src/io/menu.z80

+ 64 - 22
docs/readme.md

@@ -382,8 +382,9 @@ Or to jump backwards:
 | getKey       | This returns a value from 0 to 56 that is the current key press. You can use [this chart](#keycodes) for values.
 | getKey(      | `getKey(` will allow you to see if a key is being pressed. For example, `getKey(9` will return `1` if enter is pressed
 | Input        | This allows you to input a string. The pointer to the string is returned. (this is not a permanent location, the data will be overwritten the next time Input is used). To get a value input from the user, you can use `expr(` : `expr(Input →A`. This will store the result to A. `Input` can also take an optional string input. The input string will be displayed after what the user is typing. If you execute this code, I think it'll explain it better. It's honestly pretty cool for a calculator. **See below for information on the [Input vars!](#input-vars)**
-| Menu(        | ~~*This may require the included appvar, GramPkg, to be on your calc (in RAM or archived).*~~ Syntax is, `Menu(y,x,w,"Title","Item0","Item1","Item2","Exit`. It basically makes a pop-up style menu, returning the number of the selected item. Returns 0 if exited due to `[CLEAR]` or `[ON]`. ***Note:** you can append an optional last argument that starts with `'` to specify a default option. For example, if the last argument is `'3` then the third option will be selected by default.*
-| Menu('       | Draws a menu that queries Grammer subroutines for the content to render. Syntax is `Menu('"Title",y,x,height,width,GET_ELEMENT_ptr,SELECT_ELEMENT_ptr`. The subroutine for GET_ELEMENT will receive the index in Ans. Return 0 if out-of-bounds, else return a pointer to the string to draw. The subroutine for SELECT_ELEMENT will receive the index in Ans. Modify this as you want, the result will be returned as the result of the menu. Returns 0 if exited due to `[CLEAR]` or `[ON]`. |
+| Menu(        | ~~*This may require the included appvar, GramPkg, to be on your calc (in RAM or archived).*~~ Syntax is, `Menu(y,x,w,"Title","Item0","Item1","Item2","Exit`. It basically makes a pop-up style menu, returning the number of the selected item. Returns 0 if exited due to `[CLEAR]` or `[ON]`. ***Note:** you can append an optional last argument that starts with `'` to specify a default option. For example, if the last argument is `'3` then the third option will be selected by default.* ***NOTE:** You can't use font mode 0 for this; instead the menu routine will convert to font mode 2.*
+| Menu('       | Draws a menu that queries Grammer subroutines for the content to render. Syntax is `Menu('"Title",y,x,height,width,GET_ELEMENT_ptr,SELECT_ELEMENT_ptr`. The subroutine for GET_ELEMENT will receive the index in Ans. Return 0 if out-of-bounds, else return a pointer to the string to draw. The subroutine for SELECT_ELEMENT will receive the index in Ans, and the header number in `Ɵ'`. Modify this as you want, the result will be returned as the result of the menu. Returns 0 if exited due to `[CLEAR]` or `[ON]`. ***NOTE:** You can't use font mode 0 for this; instead the menu routine will convert to font mode 2.*|
+| Menu(''      | This works like `Menu('`, but when you put `'` in front of the header argument, `Menu('` will instead interpret it as a pointer to a routine. The routine will take a value in Ans, the current header, and that routine should return the appropriate string. Return 0 if out-of-bounds. |
 | Ans          | This will return the value of the previous line.
 | expr(        | This will compute a string as a line of code (useful with `Input`). **See below for more info on [`expr(`](#expr-examples)!**
 | inString(    | This is similar to the TI-BASIC command. This will return the location of a sub-string. The inputs are where to start searching and the string to search for: `inString(SearchStart,SearchString[,maxlength]`. The size of the input string is returned in `Ɵ'` and if there was no match found, 0 is returned.
@@ -397,28 +398,69 @@ Menu(1,1,16,"Title","ITEM 1","ITEM 2","ITEM 3→M
 
 And here is an example using callbacks:
 ```
-Lbl "GET→A
-Lbl "SEL→B
-Menu('"Title",2,33,59,30,A,B→M
-Text('0,0,M
-Stop
-
-
-.GET
-→X<26
-If !
-End
-"ITEM A→Z
-int(Z+5,X+65
-Z
-End
-
-
-.SEL
-+1
-End
+:Lbl "GET→A
+:Lbl "SEL→B
+:Menu('"HEAD",2,33,59,30,A,B→M
+:Text('0,0,M
+:Stop
+:
+:.GET
+:→X<26
+:If !
+:End
+:"ITEM A→Z
+:int(Z+5,X+65
+:Z
+:End
+:
+:.SEL
+:+1
+:End
 ```
 
+Or a more complicated menu that has three headers (use left/right):
+```
+:Lbl "GET→A
+:Lbl "SEL→B
+:Lbl "HEAD→C
+:Menu(''C,2,28,59,40,A,B→M
+:Text('0,0,M
+:Stop
+:
+:
+:.HEAD
+:→X<3
+:If !
+:End
+:If X=0
+:" STRING>
+:If X=1
+:"<PIC>
+:If X=2
+:"<GDB
+:End
+:
+:
+:.GET
+:→X<10
+:If !
+:End
+:Ɵ'
+:If =0
+:"Str
+:If =1
+:"Pic0
+:If =2
+:"GDB0
+:→Z
+:int(+3,X+48
+:Z
+:End
+:
+:.SEL
+:+1
+:End
+```
 
 
 ### Input Vars!

+ 2 - 0
src/01.z80

@@ -17,6 +17,8 @@ p1_GraphToLCD:
 
 call_ix_01:
   jp (ix)
+p1_call_hl:
+  jp (hl)
 
 pixelOn_pattern:
   call getpixelloc

+ 74 - 2
src/cmd/menu.z80

@@ -16,7 +16,8 @@ menu_num_items  = menuMem+17  ;2 bytes
 menu_get        = menuMem+19
 menu_sel        = menuMem+21
 menu_temp       = menuMem+23
-menuopts        = menuMem+25
+menu_header_get = menuMem+25
+menuopts        = menuMem+27
 menudefault     = TempWord1
 menutopinit     = TempWord4
 
@@ -177,6 +178,8 @@ _:
   ld d,a
 
   ld ix,menu_command_lookup
+  ld hl,menu_header_getter
+  ld (menu_header_get),hl
 
 menu_entry:
   ;Set the default graphics buffer
@@ -212,6 +215,12 @@ _:
 
 fancymenu:
 ;header,y,x,h,w,get,sel
+  inc hl
+  ld a,(hl)
+  cp $AE
+  push af
+  jr nz,$+5
+  ld (parsePtr),hl
   call p1_ParseNextFullArg
   ld (menuheader_ptr),bc
 
@@ -244,8 +253,15 @@ fancymenu:
   ld (menudefault),hl
 
   pop de
+
+  pop af
+  ld hl,menu_header_getter
+  jr nz,$+5
+  ld hl,menu_header_get_cb
+  ld (menu_header_get),hl
+
   ld ix,fancymenu_lookup
-  jr menu_entry
+  jp menu_entry
 
 
 menu_err:
@@ -337,3 +353,59 @@ menu_command_select:
   ld bc,(menucur)
   inc bc
   ret
+
+menu_header_get_cb:
+;save the current parsePtr
+  ld hl,(parsePtr)
+  push hl
+
+;save Ans and replace with the current cursor
+  ld hl,(Ans)
+  push hl
+
+;save thetaprime
+  ld hl,(ThetaPrimeVar)
+  push hl
+
+;Save the text coordinates
+  ld hl,(TextRow)
+  push hl
+
+;Set "Ans"
+  ld c,a
+  ld b,0
+
+;now set the location to start parsing at
+  ld hl,(menuheader_ptr)
+  ld (parsePtr),hl
+
+;set Ans
+  ld (Ans),bc
+
+;Now parse
+  call p1_ParserNext
+
+;Restore text coordinates
+  pop hl
+  ld (TextRow),hl
+
+;restore thetaprimevar
+  pop hl
+  ld (ThetaPrimeVar),hl
+
+;restore Ans
+  pop hl
+  ld (Ans),hl
+
+;restore parsePtr
+  pop hl
+  ld (parsePtr),hl
+
+;return 0 if failed
+  ld h,b
+  ld l,c
+  ld a,b
+  or c
+  ret nz
+  ld hl,s_null
+  ret

+ 33 - 47
src/io/menu.z80

@@ -263,15 +263,12 @@ menu_arrow:
 ;check arrow keys
   dec a
   jr z,menu_down
-  sub 3
-  scf
+  dec a
+  jp z,menu_left
+  dec a
+  jp z,menu_right
+  add a,-1      ;sets the carry flag if it is not a keypress
   ret nz
-  ; dec a
-  ; jr z,menu_left
-  ; dec a
-  ; jr z,menu_right
-  ; add a,-1      ;sets the carry flag if it is not a keypress
-  ; ret nz
 
 ;if would select oob
 ;   if next element exists
@@ -393,17 +390,26 @@ gettextbox:
   dec b
   ret
 ;These change to the next menu header
-; menu_left:
-
-  ; ld a,(menuheader_cur)
-  ; dec a
-  ; jr +_
-; menu_right:
-;   ld a,(menuheader_cur)
-;   inc a
-; _:
-;   ld (menuheader_cur),a
-;   call reset_menu_cursor
+menu_left:
+  ld a,(menuheader_cur)
+  dec a
+  ld hl,(menu_header_get)
+  call p1_call_hl
+  ret z
+  ld a,(menuheader_cur)
+  dec a
+  jr +_
+menu_right:
+  ld a,(menuheader_cur)
+  inc a
+  ld hl,(menu_header_get)
+  call p1_call_hl
+  ret z
+  ld a,(menuheader_cur)
+  inc a
+_:
+  ld (menuheader_cur),a
+  call reset_menu_cursor
 
 draw_header:
 ;Set up textcoord
@@ -443,40 +449,20 @@ draw_header:
 
 
 ;Verify that the header element is valid, wrap if needed
-  ld hl,(menuheader_ptr)
-;   ld a,(menuheader_cur)
-;   cp (hl)
-;   jr c,+_
-;   inc a
-;   jr nz,$+5
-;   ;cycle to the last header
-;   ld a,(hl)
-;   dec a
-;   .db $FE
-;   ;cycle to the first header
-;   xor a
-;   ld (menuheader_cur),a
-; _:
-;
-; ;A is the header to seek
-;   ld bc,0   ;using CPIR, want to make sure it doesn't exit too soon!
-;   inc hl    ;point to the first header
-;   or a
-;   jr draw_header_loopend
-; draw_header_loop:
-;   push af
-;   xor a
-;   cpir
-;   pop af
-;   dec a
-; draw_header_loopend:
-;   jr nz,draw_header_loop
+  ld a,(menuheader_cur)
+  ld hl,(menu_header_get)
+  call p1_call_hl
 
 ;now draw the header
   Text()
   or a
   ret
 
+menu_header_getter:
+  ld hl,(menuheader_ptr)
+  xor a
+  ret
+
 reset_menu_cursor:
   ld hl,0
   ld (menutop),hl