Browse Source

Merge pull request #1 from Zeda/master

Merge Zeda/Grammer2 master
NonstickAtom785 4 years ago
parent
commit
d1fa6ac50c
13 changed files with 324 additions and 106 deletions
  1. 6 0
      compile
  2. 7 0
      docs/grammer2.5.inc
  3. 65 24
      docs/readme.md
  4. 2 2
      docs/tutorials/drawing.md
  5. 7 0
      src/01.z80
  6. 105 10
      src/cmd/menu.z80
  7. 1 0
      src/gfx/text.z80
  8. 15 0
      src/gfx/tilemap.z80
  9. 2 2
      src/grammer.z80
  10. 7 0
      src/grammer2.5.inc
  11. 66 66
      src/io/menu.z80
  12. 37 0
      src/launch.z80
  13. 4 2
      src/subroutines/chardim.z80

+ 6 - 0
compile

@@ -17,3 +17,9 @@ if [ ! -f "experimental/experimental.z80" ];then
   echo -e "\e[1m\e[37mAssembling Experimental Package\e[0m"
   echo -e "\e[1m\e[37mAssembling Experimental Package\e[0m"
   spasm experimental/experimental.z80 ../bin/EXPRMNTL.8xv -I single
   spasm experimental/experimental.z80 ../bin/EXPRMNTL.8xv -I single
 fi
 fi
+
+# Check for the program launcher
+if [ ! -f "../bin/g250.8xp" ];then
+  echo -e "\e[1m\e[37mAssembling Program Launcher\e[0m"
+  spasm launch.z80 ../bin/g250.8xp
+fi

+ 7 - 0
docs/grammer2.5.inc

@@ -191,6 +191,13 @@ inputflag       = 0
 ModeFlags2      = 35
 ModeFlags2      = 35
 floatmode       = 5
 floatmode       = 5
 
 
+textmode_default  = 0
+textmode_varwidth = 1
+textmode_smallfixed=2
+textmode_Omnicalc = 3
+textmode_OS_small = 4
+textmode_OS_large = 5
+
 
 
 FS_uint8        = 0
 FS_uint8        = 0
 FS_str          = 3
 FS_str          = 3

+ 65 - 24
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       | 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
 | 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)**
 | 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.
 | 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)!**
 | 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.
 | 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:
 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!
 ### Input Vars!
@@ -645,7 +687,6 @@ syntax that tilemaps are stored (stored in rows).
 | Fix Text(    | Use this to set the typewriter delay. The larger the number, the slower the typewriter text is displayed.
 | Fix Text(    | Use this to set the typewriter delay. The larger the number, the slower the typewriter text is displayed.
 | Fix          | See description below.
 | Fix          | See description below.
 | Full         | This is used to set 15MHz mode. Alternatively, if you add a number to the end `Full0` sets 6MHz, `Full1` sets 15MHz, `Full2` toggles the speed. 15MHz is only set if it is possible for the calc. This returns `0` if the previous speed setting was 6MHz, `1` if it was 15MHz.
 | Full         | This is used to set 15MHz mode. Alternatively, if you add a number to the end `Full0` sets 6MHz, `Full1` sets 15MHz, `Full2` toggles the speed. 15MHz is only set if it is possible for the calc. This returns `0` if the previous speed setting was 6MHz, `1` if it was 15MHz.
-
 | Output(      | See description below.
 | Output(      | See description below.
 
 
 ### Fix
 ### Fix
@@ -760,7 +801,7 @@ I have to give special thanks to Yeongjin Nam for their work on writing a
 better tutorial for Grammer and as well Louis Becquey (persalteas) for their work on
 better tutorial for Grammer and as well Louis Becquey (persalteas) for their work on
 writing a french readme/tutorial. Both of them have also made many valuable
 writing a french readme/tutorial. Both of them have also made many valuable
 suggestions that have helped make Grammer what it is right now. Thanks much!
 suggestions that have helped make Grammer what it is right now. Thanks much!
-Thanks to GModder for the suggestions and (many) bug reports that I would not have found otherwise!
+Thanks to @NonstickAtom785 for the suggestions and (many) bug reports that I would not have found otherwise!
 
 
 I also thank Hans Burch for reconstructing Grammer 2 after I lost my work. It must have been a tremendous amount of effort and tedium, and I greatly appreciate it. They've continued to provide valuable feedback about bugs and it has been extremely helpful.
 I also thank Hans Burch for reconstructing Grammer 2 after I lost my work. It must have been a tremendous amount of effort and tedium, and I greatly appreciate it. They've continued to provide valuable feedback about bugs and it has been extremely helpful.
 
 

+ 2 - 2
docs/tutorials/drawing.md

@@ -948,8 +948,8 @@ routines will scroll the screen, scrolling in the new data. Available commands:
   - `dir` is 1 for down, 2 for left, 4 for right, 8 for up. To shift up+left,
   - `dir` is 1 for down, 2 for left, 4 for right, 8 for up. To shift up+left,
   you can use a `dir` of 8+2 = 10.
   you can use a `dir` of 8+2 = 10.
 
 
-An easy way to remember the order of the directions is that the follow the order
-of the getKey codes.
+An easy way to remember the order of the directions is that they follow the
+order of the getKey codes.
 
 
 #### Get Tile, Set Tile
 #### Get Tile, Set Tile
 You can read a tile number based on its map coordinates, or set a tile based on
 You can read a tile number based on its map coordinates, or set a tile based on

+ 7 - 0
src/01.z80

@@ -17,6 +17,8 @@ p1_GraphToLCD:
 
 
 call_ix_01:
 call_ix_01:
   jp (ix)
   jp (ix)
+p1_call_hl:
+  jp (hl)
 
 
 pixelOn_pattern:
 pixelOn_pattern:
   call getpixelloc
   call getpixelloc
@@ -177,6 +179,11 @@ jp_prev_page_call:
   pop hl
   pop hl
   jp prev_page_call
   jp prev_page_call
 
 
+p1_chardim:
+  ld hl,chardim
+  ld (prev_page_call_address),hl
+  jp prev_page_call
+
 verify_package:
 verify_package:
 ;A:HL points to the data
 ;A:HL points to the data
 ;BC is the size of the data
 ;BC is the size of the data

+ 105 - 10
src/cmd/menu.z80

@@ -16,7 +16,8 @@ menu_num_items  = menuMem+17  ;2 bytes
 menu_get        = menuMem+19
 menu_get        = menuMem+19
 menu_sel        = menuMem+21
 menu_sel        = menuMem+21
 menu_temp       = menuMem+23
 menu_temp       = menuMem+23
-menuopts        = menuMem+25
+menu_header_get = menuMem+25
+menuopts        = menuMem+27
 menudefault     = TempWord1
 menudefault     = TempWord1
 menutopinit     = TempWord4
 menutopinit     = TempWord4
 
 
@@ -105,16 +106,32 @@ _:
 ;Save the number of elements
 ;Save the number of elements
   ld (menu_num_items),bc
   ld (menu_num_items),bc
 
 
+  push bc
+  call p1_chardim
+  ld a,c
+  ld (font_height),a
+  pop bc
+  ld l,a
+
 ;Now we need to render the menu, but first we'll get the height of the menu in pixels
 ;Now we need to render the menu, but first we'll get the height of the menu in pixels
 ;4+font_height*min(9-int(y/font_height),BC+1
 ;4+font_height*min(9-int(y/font_height),BC+1
+
+;60/font_height-1 is the initial E value
+  ld a,59
+  ld e,-1
+
+  inc e
+  sub l
+  jr nc,$-2
+
   ld a,(textbox_top)
   ld a,(textbox_top)
-  ld e,9
   add a,a
   add a,a
   jr c,cmp_menu_height
   jr c,cmp_menu_height
+  sla l
   .db $FE
   .db $FE
 _:
 _:
   dec e
   dec e
-  sub FONT_HEIGHT*2
+  sub l
   jr nc,-_
   jr nc,-_
 cmp_menu_height:
 cmp_menu_height:
 ;E is the max height
 ;E is the max height
@@ -148,8 +165,9 @@ _:
   ld (menutopinit),hl
   ld (menutopinit),hl
 
 
 ;now do E*FONT_HEIGHT+4, given that it won't overflow 8 bits
 ;now do E*FONT_HEIGHT+4, given that it won't overflow 8 bits
+  ld a,(font_height)
+  ld b,a
   ld a,5
   ld a,5
-  ld b,FONT_HEIGHT
 _:
 _:
   add a,e
   add a,e
   djnz -_
   djnz -_
@@ -160,24 +178,28 @@ _:
   ld d,a
   ld d,a
 
 
   ld ix,menu_command_lookup
   ld ix,menu_command_lookup
+  ld hl,menu_header_getter
+  ld (menu_header_get),hl
 
 
 menu_entry:
 menu_entry:
   ;Set the default graphics buffer
   ;Set the default graphics buffer
-  ld hl,(BufPtr)
-  ld (gbuf_temp),hl
-
+  ; ld hl,(BufPtr)
+  ; ld (gbuf_temp),hl
 
 
 ;save and set the the font method
 ;save and set the the font method
   ld a,(textmode)
   ld a,(textmode)
+  or a
   push af
   push af
-  ld a,2
-  ld (textmode),a
   ld hl,(FontPointer)
   ld hl,(FontPointer)
   push hl
   push hl
+  jr nz,+_
+  ld a,2
+  ld (textmode),a
   ld hl,FontSet
   ld hl,FontSet
   ld (FontPointer),hl
   ld (FontPointer),hl
   xor a
   xor a
   ld (font_ptr_page),a
   ld (font_ptr_page),a
+_:
   ld bc,(textbox_top)
   ld bc,(textbox_top)
   ld hl,(menuheader_ptr)
   ld hl,(menuheader_ptr)
 
 
@@ -193,6 +215,12 @@ menu_entry:
 
 
 fancymenu:
 fancymenu:
 ;header,y,x,h,w,get,sel
 ;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
   call p1_ParseNextFullArg
   ld (menuheader_ptr),bc
   ld (menuheader_ptr),bc
 
 
@@ -216,13 +244,24 @@ fancymenu:
   call p1_ParseNextFullArg
   call p1_ParseNextFullArg
   ld (menu_sel),bc
   ld (menu_sel),bc
 
 
+  call p1_chardim
+  ld a,c
+  ld (font_height),a
+
   ld hl,0
   ld hl,0
   ld (menutopinit),hl
   ld (menutopinit),hl
   ld (menudefault),hl
   ld (menudefault),hl
 
 
   pop de
   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
   ld ix,fancymenu_lookup
-  jr menu_entry
+  jp menu_entry
 
 
 
 
 menu_err:
 menu_err:
@@ -314,3 +353,59 @@ menu_command_select:
   ld bc,(menucur)
   ld bc,(menucur)
   inc bc
   inc bc
   ret
   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

+ 1 - 0
src/gfx/text.z80

@@ -396,6 +396,7 @@ VPutC_OS_small:
   ld b,a
   ld b,a
   ld a,3
   ld a,3
   call OS_font_sub
   call OS_font_sub
+  inc de
   jp VputSCStepIn
   jp VputSCStepIn
 _:
 _:
   ld hl,$0600
   ld hl,$0600

+ 15 - 0
src/gfx/tilemap.z80

@@ -27,6 +27,9 @@ tmap_scroll_left:
   ld a,(hl)
   ld a,(hl)
   cp $2B
   cp $2B
   call z,p1_ParseNextFullArg
   call z,p1_ParseNextFullArg
+  inc c
+  dec c
+  ret z
   ld b,c
   ld b,c
 tmap_scroll_left_loop:
 tmap_scroll_left_loop:
 _:
 _:
@@ -40,6 +43,9 @@ tmap_scroll_right:
   ld a,(hl)
   ld a,(hl)
   cp $2B
   cp $2B
   call z,p1_ParseNextFullArg
   call z,p1_ParseNextFullArg
+  inc c
+  dec c
+  ret z
   ld b,c
   ld b,c
 tmap_scroll_right_loop:
 tmap_scroll_right_loop:
 _:
 _:
@@ -53,6 +59,9 @@ tmap_scroll_down:
   ld a,(hl)
   ld a,(hl)
   cp $2B
   cp $2B
   call z,p1_ParseNextFullArg
   call z,p1_ParseNextFullArg
+  inc c
+  dec c
+  ret z
   ld b,c
   ld b,c
 tmap_scroll_down_loop:
 tmap_scroll_down_loop:
 _:
 _:
@@ -66,6 +75,9 @@ tmap_scroll_up:
   ld a,(hl)
   ld a,(hl)
   cp $2B
   cp $2B
   call z,p1_ParseNextFullArg
   call z,p1_ParseNextFullArg
+  inc c
+  dec c
+  ret z
   ld b,c
   ld b,c
 tmap_scroll_up_loop:
 tmap_scroll_up_loop:
 _:
 _:
@@ -83,6 +95,9 @@ tmap_scroll:
   ld c,1
   ld c,1
   call z,p1_ParseNextFullArg
   call z,p1_ParseNextFullArg
   pop af
   pop af
+  inc c
+  dec c
+  ret z
   ld b,c
   ld b,c
 
 
   rrca
   rrca

+ 2 - 2
src/grammer.z80

@@ -81,7 +81,7 @@ _:
 ProgramAccessStart:
 ProgramAccessStart:
   bcall(_RclAns)
   bcall(_RclAns)
   sub 4
   sub 4
-  jr nz,grazh
+  jr nz,begin_parse
   ex de,hl
   ex de,hl
   ld c,(hl)
   ld c,(hl)
   inc hl
   inc hl
@@ -112,7 +112,7 @@ parse_via_ptr:
   ld (progEnd),hl
   ld (progEnd),hl
   ld h,a \ ld l,a
   ld h,a \ ld l,a
   ld (parseError),hl
   ld (parseError),hl
-grazh:
+begin_parse:
 #ifdef include_interrupt
 #ifdef include_interrupt
   di
   di
   ld a,11
   ld a,11

+ 7 - 0
src/grammer2.5.inc

@@ -191,6 +191,13 @@ inputflag       = 0
 ModeFlags2      = 35
 ModeFlags2      = 35
 floatmode       = 5
 floatmode       = 5
 
 
+textmode_default  = 0
+textmode_varwidth = 1
+textmode_smallfixed=2
+textmode_Omnicalc = 3
+textmode_OS_small = 4
+textmode_OS_large = 5
+
 
 
 FS_uint8        = 0
 FS_uint8        = 0
 FS_str          = 3
 FS_str          = 3

+ 66 - 66
src/io/menu.z80

@@ -1,5 +1,5 @@
 #define Text() call p1_PutTokenText
 #define Text() call p1_PutTokenText
-#define FONT_HEIGHT 6
+font_height = tempword5
 ;#define TEXT_PAD_TOP    ;comment if there is not a row of padding above the text
 ;#define TEXT_PAD_TOP    ;comment if there is not a row of padding above the text
 ;#define TEXTCOORD_YX      ;define if textcoord is Y then X (TI-OS is Y then X for small font, large font and some custom text routines use the opposite)
 ;#define TEXTCOORD_YX      ;define if textcoord is Y then X (TI-OS is Y then X for small font, large font and some custom text routines use the opposite)
 textcoord = textRow
 textcoord = textRow
@@ -99,9 +99,9 @@ menuroutine:
   call draw_header
   call draw_header
   pop bc
   pop bc
 
 
-
 ;Before we do too much, let's establish the top-left textbox boundaries.
 ;Before we do too much, let's establish the top-left textbox boundaries.
-  ld a,FONT_HEIGHT+2
+  ld a,(font_height)
+  add a,2
   add a,c
   add a,c
   ld c,a
   ld c,a
   ld (textbox_top),bc
   ld (textbox_top),bc
@@ -113,7 +113,7 @@ menuroutine:
   ld hl,(menudefault)
   ld hl,(menudefault)
   ld (menucur),hl
   ld (menucur),hl
 
 
-  ;need t set menu selection to:
+  ;need to set menu selection to:
   ;   (textbox_top-1)+(menucur-menutop)*fontheight
   ;   (textbox_top-1)+(menucur-menutop)*fontheight
   ;  =(textbox_top-1)+(HL-DE)*fontheight
   ;  =(textbox_top-1)+(HL-DE)*fontheight
   ; or a
   ; or a
@@ -160,7 +160,9 @@ menu_render_0:
   ld a,h
   ld a,h
   sub b
   sub b
   ld d,a
   ld d,a
-  ld e,FONT_HEIGHT+1
+  ld a,(font_height)
+  ld e,a
+  inc e
   dec d
   dec d
   push de
   push de
   push bc
   push bc
@@ -214,35 +216,37 @@ menu_render_sub_loop:
   pop bc
   pop bc
   ret c
   ret c
   ld de,(textcoord)
   ld de,(textcoord)
-  push de
   push bc
   push bc
+  push de
   Text()
   Text()
-  pop bc
   pop de
   pop de
+  ld a,(font_height)
+  ld c,a
 #ifdef TEXTCOORD_YX
 #ifdef TEXTCOORD_YX
-  ld a,FONT_HEIGHT
   add a,d
   add a,d
   ld d,a
   ld d,a
   ld a,(textbox_bottom)
   ld a,(textbox_bottom)
+  sub c
 #ifdef TEXT_PAD_TOP
 #ifdef TEXT_PAD_TOP
-  sub FONT_HEIGHT+2
+  sub 2
 #else
 #else
-  sub FONT_HEIGHT+1
+  dec a
 #endif
 #endif
   cp d
   cp d
 #else
 #else
-  ld a,FONT_HEIGHT
   add a,e
   add a,e
   ld e,a
   ld e,a
   ld a,(textbox_bottom)
   ld a,(textbox_bottom)
+  sub c
 #ifdef TEXT_PAD_TOP
 #ifdef TEXT_PAD_TOP
-  sub FONT_HEIGHT+2
+  sub d
 #else
 #else
-  sub FONT_HEIGHT+1
+  dec a
 #endif
 #endif
   cp e
   cp e
 #endif
 #endif
   ld (textcoord),de
   ld (textcoord),de
+  pop bc
   inc bc
   inc bc
   jr nc,menu_render_sub_loop
   jr nc,menu_render_sub_loop
   ret
   ret
@@ -259,15 +263,12 @@ menu_arrow:
 ;check arrow keys
 ;check arrow keys
   dec a
   dec a
   jr z,menu_down
   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
   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 would select oob
 ;   if next element exists
 ;   if next element exists
@@ -289,7 +290,11 @@ menu_up:
   ld hl,(textbox_top)
   ld hl,(textbox_top)
   cp l
   cp l
   jr z,+_
   jr z,+_
-  sub FONT_HEIGHT
+  ld e,a
+  ld a,(font_height)
+  ld d,a
+  ld a,e
+  sub d
   ld (menuselection),a
   ld (menuselection),a
   scf
   scf
   ret
   ret
@@ -311,13 +316,17 @@ menu_down:
   pop hl
   pop hl
   ret c
   ret c
   ld (menucur),hl
   ld (menucur),hl
-
+  ld a,(font_height)
+  ld e,a
   ld a,(menuselection)
   ld a,(menuselection)
-  add a,FONT_HEIGHT+FONT_HEIGHT+1
+  add a,e
+  add a,e
+  inc a
   ld hl,(textbox_bottom)
   ld hl,(textbox_bottom)
   cp l
   cp l
   jr nc,+_
   jr nc,+_
-  sub FONT_HEIGHT+1
+  sub e
+  dec a
   ld (menuselection),a
   ld (menuselection),a
   scf
   scf
   ret
   ret
@@ -333,7 +342,7 @@ menu_scroll:
 
 
   push af
   push af
   call gettextbox
   call gettextbox
-  ld h,FONT_HEIGHT
+  ld hl,(font_height-1)
   pop af
   pop af
 _:
 _:
   push af
   push af
@@ -381,17 +390,26 @@ gettextbox:
   dec b
   dec b
   ret
   ret
 ;These change to the next menu header
 ;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:
 draw_header:
 ;Set up textcoord
 ;Set up textcoord
@@ -424,45 +442,27 @@ draw_header:
   sub b
   sub b
   ld d,a
   ld d,a
   dec b
   dec b
-  ld e,FONT_HEIGHT+1
+  ld a,(font_height)
+  ld e,a
+  inc e
   rect_Erase()
   rect_Erase()
 
 
 
 
 ;Verify that the header element is valid, wrap if needed
 ;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
 ;now draw the header
   Text()
   Text()
   or a
   or a
   ret
   ret
 
 
+menu_header_getter:
+  ld hl,(menuheader_ptr)
+  xor a
+  ret
+
 reset_menu_cursor:
 reset_menu_cursor:
   ld hl,0
   ld hl,0
   ld (menutop),hl
   ld (menutop),hl

+ 37 - 0
src/launch.z80

@@ -0,0 +1,37 @@
+; This program launches Grammer2.
+; If the input is a string, this assumes it is the name of the program to execute.
+; Otherwise, this starts an in-line parser.
+
+#include "grammer2.5.inc"
+_FindApp        = 4C4Eh
+.db $BB,$6D
+.org $9D95
+
+; move the app name into OP1
+  ld hl,app_name
+  rst rMov9ToOP1
+
+  bcall(_FindApp) ; locate the app
+  ret c           ; exit if it isn't found
+
+; Now A is the page that the app is on, but we need to save the current page so
+; that we can restore it later.
+  ld b,a              ; save A
+  in a,(6)            ; Get the current page
+  ld (page_restore),a ; save it to our restore location (self-modifying code)
+  ld a,b              ; get the app's page in A again
+  out (6),a           ; write the app's page
+
+; Grammer already contains a routine to parse Ans and execute code accordingly,
+; so all we need to do is call ProgramAccessStart
+  call ProgramAccessStart
+
+;restore the page
+  .db $3E     ;start of `ld a,*`
+page_restore:
+  .db 0       ;dummy value, this gets overwritten
+  out (6),a
+  ret
+
+app_name:
+  .db $14,"Grammer",0

+ 4 - 2
src/subroutines/chardim.z80

@@ -5,13 +5,15 @@ chardim:
 ;Destroys: A
 ;Destroys: A
   ld b,a
   ld b,a
   ld a,(textmode)
   ld a,(textmode)
+  or a
+  jr z,grammer_small_size
   dec a
   dec a
   jr z,var_width_size
   jr z,var_width_size
   dec a
   dec a
-  jr z,OS_large_size
-  dec a
   jr z,grammer_small_size
   jr z,grammer_small_size
   dec a
   dec a
+  jr z,OS_large_size
+  dec a
   jr z,OS_small_size
   jr z,OS_small_size
 OS_large_size:
 OS_large_size:
   ld bc,$0608
   ld bc,$0608