ソースを参照

Merge pull request #1 from Zeda/master

Merge Zeda/Grammer2 master
NonstickAtom785 4 年 前
コミット
d1fa6ac50c
13 ファイル変更324 行追加106 行削除
  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"
   spasm experimental/experimental.z80 ../bin/EXPRMNTL.8xv -I single
 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
 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_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(      | `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!
@@ -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          | 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.
-
 | Output(      | See description below.
 
 ### 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
 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!
-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.
 

+ 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,
   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
 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:
   jp (ix)
+p1_call_hl:
+  jp (hl)
 
 pixelOn_pattern:
   call getpixelloc
@@ -177,6 +179,11 @@ jp_prev_page_call:
   pop hl
   jp prev_page_call
 
+p1_chardim:
+  ld hl,chardim
+  ld (prev_page_call_address),hl
+  jp prev_page_call
+
 verify_package:
 ;A:HL points to 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_sel        = menuMem+21
 menu_temp       = menuMem+23
-menuopts        = menuMem+25
+menu_header_get = menuMem+25
+menuopts        = menuMem+27
 menudefault     = TempWord1
 menutopinit     = TempWord4
 
@@ -105,16 +106,32 @@ _:
 ;Save the number of elements
   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
 ;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 e,9
   add a,a
   jr c,cmp_menu_height
+  sla l
   .db $FE
 _:
   dec e
-  sub FONT_HEIGHT*2
+  sub l
   jr nc,-_
 cmp_menu_height:
 ;E is the max height
@@ -148,8 +165,9 @@ _:
   ld (menutopinit),hl
 
 ;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 b,FONT_HEIGHT
 _:
   add a,e
   djnz -_
@@ -160,24 +178,28 @@ _:
   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
-  ld hl,(BufPtr)
-  ld (gbuf_temp),hl
-
+  ; ld hl,(BufPtr)
+  ; ld (gbuf_temp),hl
 
 ;save and set the the font method
   ld a,(textmode)
+  or a
   push af
-  ld a,2
-  ld (textmode),a
   ld hl,(FontPointer)
   push hl
+  jr nz,+_
+  ld a,2
+  ld (textmode),a
   ld hl,FontSet
   ld (FontPointer),hl
   xor a
   ld (font_ptr_page),a
+_:
   ld bc,(textbox_top)
   ld hl,(menuheader_ptr)
 
@@ -193,6 +215,12 @@ menu_entry:
 
 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
 
@@ -216,13 +244,24 @@ fancymenu:
   call p1_ParseNextFullArg
   ld (menu_sel),bc
 
+  call p1_chardim
+  ld a,c
+  ld (font_height),a
+
   ld hl,0
   ld (menutopinit),hl
   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:
@@ -314,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

+ 1 - 0
src/gfx/text.z80

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

+ 15 - 0
src/gfx/tilemap.z80

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

+ 2 - 2
src/grammer.z80

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

+ 7 - 0
src/grammer2.5.inc

@@ -191,6 +191,13 @@ inputflag       = 0
 ModeFlags2      = 35
 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_str          = 3

+ 66 - 66
src/io/menu.z80

@@ -1,5 +1,5 @@
 #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 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
@@ -99,9 +99,9 @@ menuroutine:
   call draw_header
   pop bc
 
-
 ;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
   ld c,a
   ld (textbox_top),bc
@@ -113,7 +113,7 @@ menuroutine:
   ld hl,(menudefault)
   ld (menucur),hl
 
-  ;need t set menu selection to:
+  ;need to set menu selection to:
   ;   (textbox_top-1)+(menucur-menutop)*fontheight
   ;  =(textbox_top-1)+(HL-DE)*fontheight
   ; or a
@@ -160,7 +160,9 @@ menu_render_0:
   ld a,h
   sub b
   ld d,a
-  ld e,FONT_HEIGHT+1
+  ld a,(font_height)
+  ld e,a
+  inc e
   dec d
   push de
   push bc
@@ -214,35 +216,37 @@ menu_render_sub_loop:
   pop bc
   ret c
   ld de,(textcoord)
-  push de
   push bc
+  push de
   Text()
-  pop bc
   pop de
+  ld a,(font_height)
+  ld c,a
 #ifdef TEXTCOORD_YX
-  ld a,FONT_HEIGHT
   add a,d
   ld d,a
   ld a,(textbox_bottom)
+  sub c
 #ifdef TEXT_PAD_TOP
-  sub FONT_HEIGHT+2
+  sub 2
 #else
-  sub FONT_HEIGHT+1
+  dec a
 #endif
   cp d
 #else
-  ld a,FONT_HEIGHT
   add a,e
   ld e,a
   ld a,(textbox_bottom)
+  sub c
 #ifdef TEXT_PAD_TOP
-  sub FONT_HEIGHT+2
+  sub d
 #else
-  sub FONT_HEIGHT+1
+  dec a
 #endif
   cp e
 #endif
   ld (textcoord),de
+  pop bc
   inc bc
   jr nc,menu_render_sub_loop
   ret
@@ -259,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
@@ -289,7 +290,11 @@ menu_up:
   ld hl,(textbox_top)
   cp l
   jr z,+_
-  sub FONT_HEIGHT
+  ld e,a
+  ld a,(font_height)
+  ld d,a
+  ld a,e
+  sub d
   ld (menuselection),a
   scf
   ret
@@ -311,13 +316,17 @@ menu_down:
   pop hl
   ret c
   ld (menucur),hl
-
+  ld a,(font_height)
+  ld e,a
   ld a,(menuselection)
-  add a,FONT_HEIGHT+FONT_HEIGHT+1
+  add a,e
+  add a,e
+  inc a
   ld hl,(textbox_bottom)
   cp l
   jr nc,+_
-  sub FONT_HEIGHT+1
+  sub e
+  dec a
   ld (menuselection),a
   scf
   ret
@@ -333,7 +342,7 @@ menu_scroll:
 
   push af
   call gettextbox
-  ld h,FONT_HEIGHT
+  ld hl,(font_height-1)
   pop af
 _:
   push af
@@ -381,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
@@ -424,45 +442,27 @@ draw_header:
   sub b
   ld d,a
   dec b
-  ld e,FONT_HEIGHT+1
+  ld a,(font_height)
+  ld e,a
+  inc e
   rect_Erase()
 
 
 ;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

+ 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
   ld b,a
   ld a,(textmode)
+  or a
+  jr z,grammer_small_size
   dec a
   jr z,var_width_size
   dec a
-  jr z,OS_large_size
-  dec a
   jr z,grammer_small_size
   dec a
+  jr z,OS_large_size
+  dec a
   jr z,OS_small_size
 OS_large_size:
   ld bc,$0608