--- title: "Grafix" id: 56683 type: "computer_media" slug: "grafix" url: "http://localhost/computer_media/grafix/" markdown_url: "http://localhost/computer_media/grafix.md" published_at: "2024-09-22T23:31:42+00:00" modified_at: "2026-04-03T07:58:59+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/GRAFIX.png" excerpt: "A 1982 full-screen block-graphic editor packs cursor movement, scrolling, mirroring, and direct memory transfers into a single elegant computed GOSUB dispatch loop." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "KOPAK Creations" slug: "kopak-creations-inc" taxonomy: "post_tag" url: "http://localhost/tag/kopak-creations-inc/" - name: "Nick Godwin" slug: "nick-godwin" taxonomy: "post_tag" url: "http://localhost/tag/nick-godwin/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Art" slug: "art" taxonomy: "genre" url: "http://localhost/type/art/" - name: "Graphics" slug: "graphics" taxonomy: "genre" url: "http://localhost/type/graphics/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Grafix%20%28198x%29%28KOPAK%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1982" producer_company: - id: 11137 title: "Nick Godwin" type: "company" url: "http://localhost/company/nick-godwin/" images: - url: "http://localhost/wp-content/uploads/2024/09/GRAFIX.png" - url: "http://localhost/wp-content/uploads/2024/09/Inst1-4-scaled.jpg" - url: "http://localhost/wp-content/uploads/2024/09/Inst2-4-scaled.jpg" - url: "http://localhost/wp-content/uploads/2024/09/Inst3-scaled.jpg" - url: "http://localhost/wp-content/uploads/2024/09/Inst4-scaled.jpg" - url: "http://localhost/wp-content/uploads/2024/09/Tape-11-scaled.jpg" related_products: - id: 12744 title: "Grafix" type: "product" url: "http://localhost/product/grafix/" - id: 12769 title: "GRAPHIX" type: "product" url: "http://localhost/product/graphix/" media_type_tags: "Art, Graphics" --- This program is a full-screen text and block-graphic editor that stores a 704-character (22×32) canvas in the string variable Z$(704). It supports cursor movement, character placement, SAVE/LOAD of the canvas to a named file, RAMTOP-based POKE/PEEK transfer to address 32000, horizontal and vertical scrolling, a mirror/flip function, find-and-replace for graphic characters, and a configurable print routine using direct POKEs to system variables around address 16529. Navigation and command dispatch are handled by a computed GOSUB (line 210: GOSUB X*30+1000), routing keypress codes to the appropriate handler subroutine. The keypress loop at lines 8900–8902 uses PAUSE 40000 followed by CODE INKEY$ as an efficient non-blocking wait. *** ## Program Analysis ### Program Structure The program is organised as a collection of subroutines scattered across a wide line-number range, with a main loop at lines 200–590 and a dispatch table implemented via a computed `GOSUB`. Lines 1–11 hold short utility subroutines that are called frequently. The initialisation block (lines 100–130) sets up the 704-character canvas string `Z$`, the cursor position `A`, the working string `X$`, and the mode flag `Z`. ### Canvas Layout The editing canvas is a 704-character string (`DIM Z$(704)`, line 100), representing a 22-row × 32-column display. Position `A` is a linear index into this string. Row and column are recovered with integer arithmetic: - Row: `B = INT((A-1)/32)` (line 520) - Column: `A - B*32 - 1` (line 540) The status line at row 21 is used for prompts and is not part of the canvas data. ### Computed GOSUB Dispatch The central command-dispatch mechanism at line 210 is: `GOSUB X*30+1000` where `X` is the raw `CODE` of the last keypress. Each key maps to a handler whose line number equals `X*30+1000`. For example, key code 119 (the clear/home key) maps to line `119*30+1000 = 4570`; the target lines 4538–4540 handle reset. This avoids a long IF/THEN chain and is a well-known BASIC optimisation technique. ### Key Handler Subroutines | Key Code | Target Line | Function | | --- | --- | --- | | 112 (cursor left) | 4360 | Move cursor left one character | | 113 (cursor right) | 4390 | Move cursor right one character | | 114 (cursor down) | 4420 | Move cursor down one row | | 115 (cursor up) | 4450 | Move cursor up one row | | 116 (EXTEND) | 8800 | INPUT a string into `X$` | | 119 (clear) | 4538 | Reset `X` and `X$` | | 216 (SHIFT+Q) | — | Toggle insert/overwrite mode via `Z` | | 226 (SHIFT+S) | 730 | SAVE canvas to named file | | 227 (SHIFT+A) | — | STOP (exit program) | ### Keypress Wait Idiom Lines 8900–8902 implement the standard efficient keypress wait: `PAUSE 40000 / POKE 16437,255 / LET X=CODE INKEY$` The `POKE 16437,255` resets the FRAMES system variable so the PAUSE does not expire prematurely on repeated calls. This yields a responsive input loop without busy-waiting. ### Mode Flag Z `Z` tracks the editor’s insert/cursor mode. Key 216 (SHIFT+Q) toggles it: first press sets `Z=1` (line 240), second press sets `Z=2` (line 230), and line 550 resets it to `Z=1` after each frame. When `Z=1`, the current `X$` is displayed at the cursor position (line 540) without being committed to `Z$`; when `Z<>1` and `X$>""`, `X$` is written into `Z$` (line 490). ### Direct Memory Access Several routines use direct POKEs to system variable addresses: - `POKE 16529,X` — sets the current output stream or print channel character - `POKE 16563,X` and `POKE 16583,X` — configure character codes for the MIX PRINT and PRINT routines respectively - `POKE 16597,B` — stores the file name character for the file-name routine - `POKE 16614,CODE X$(J)` — clears references by character code in the REFS routine The RAMTOP check at line 7580 verifies `PEEK 16388 + 256*PEEK 16389 = 32000` before reading or writing the canvas to/from raw memory at address 32000. If the check fails, the program halts with a message (line 7590–7595). ### Scroll and Mirror Functions Lines 7690–7719 implement four-directional scrolling by slicing and concatenating `Z$`: - Scroll up (A=68): `Z$(33 TO)+Z$(1 TO 32)` - Scroll down (A=132): `Z$(673 TO)+Z$(1 TO 672)` - Scroll left (A=99): `Z$(2 TO)+Z$(1)` - Scroll right (A=101): `Z$(704)+Z$(1 TO 703)` Lines 7720–7739 implement a horizontal mirror of the canvas. The routine reverses character order within each row (stepping `J` from 32 to 1) and uses a lookup string `X$` to translate asymmetric block graphics to their mirrored equivalents, ensuring that graphical characters remain visually correct after reflection. ### Inverse-Video Toggle Lines 7510–7539 invert every character in `Z$` by toggling bit 7 of its character code: characters below 128 gain 128, characters above 127 lose 128 (with a special case for code 192, mapped to 267−128=139 to avoid an out-of-range CHR$). After the pass, the routine resets `X` to 119. ### Find and Replace Lines 7630–7649 implement a simple single-character find-and-replace across the entire canvas: the user inputs the graphic to be replaced (`X$`) and the replacement (`Y$`), then a FOR loop substitutes every matching cell in `Z$`. ### Notable Anomalies - Line 7529 uses `GOTO 7536` to skip the second branch of the inversion loop, but line 7525 contains `NEXT J` and line 7535 also contains `NEXT J`: the loop at 7514 has two `NEXT J` statements on different branches, which means the FOR loop at 7512 is only iterated correctly on the first pass through the non-inverse branch; control then falls through or jumps to line 7536. This is a structural oddity that may cause premature loop termination in the inverse branch. - The subroutine at line 4480 is a bare `GOTO 8700`, delegating entirely to the graphics-input handler without any wrapping logic. - Line 7526 returns immediately if `Y$=""` after the co-ordinate input, but the co-ordinate encoding at line 4528 assumes exactly two characters in `Y$` without bounds checking. ## Source Code ``` 1 GOTO 100 2 IF A$="" THEN LET X=0 3 RETURN 4 LET Z$(J)=D$(J) 5 RETURN 6 LET Z$=B$ 7 RETURN 8 LET A$=Z$ 9 RETURN 10 LET W$="" 11 RETURN 100 DIM Z$(704) 110 LET A=1 120 LET X$="" 130 LET Z=0 200 GOSUB 8900 210 GOSUB X*30+1000 220 IF X=227 THEN STOP 230 IF X=216 AND Z=1 THEN LET Z=2 240 IF X=216 AND Z=0 THEN LET Z=1 250 IF X=226 THEN GOTO 730 490 IF Z<>1 AND X$>"" THEN LET Z$(A TO A+LEN X$-1)=X$ 500 CLS 510 PRINT Z$ 520 LET B=INT ((A-1)/32) 530 IF X<>119 THEN PRINT AT 21,0;CHR$ (B+28);",";CHR$ (A-B*32+27);" " 540 IF Z=1 THEN PRINT AT B,A-B*32-1;X$ 550 IF Z=2 THEN LET Z=1 590 GOTO 200 730 PRINT AT 21,0;"INPUT PROGRAM NAME " 740 INPUT X$ 750 SAVE X$ 760 GOSUB 4538 770 GOTO 500 2890 LET X$=CHR$ X 2899 RETURN 4360 GOSUB 4470 4370 IF A>32 THEN LET A=A-32 4379 RETURN 4390 GOSUB 4470 4400 IF A+L<674 THEN LET A=A+32 4409 RETURN 4420 GOSUB 4470 4430 IF A>L THEN LET A=A-L 4439 RETURN 4450 GOSUB 4470 4460 IF A<706-2*L THEN LET A=A+L 4469 RETURN 4470 LET L=LEN X$ 4475 IF L=0 OR Z=1 THEN LET L=1 4479 RETURN 4480 GOTO 8700 4510 LET Y$="0123456789ABCDEFGHIJKLMNOPQRSTUV" 4512 PRINT AT 0,0;Y$;AT 21,0;Y$ 4514 FOR J=1 TO 21 4516 LET Y$=CHR$ (J+28) 4518 PRINT AT J,0;Y$;AT J,31;Y$ 4520 NEXT J 4522 PRINT AT 21,0;"INPUT CO-ORDS " 4524 INPUT Y$ 4526 IF Y$="" THEN RETURN 4528 LET A=(CODE Y$-28)*32+CODE Y$(2)-27 4529 RETURN 4538 LET X=119 4540 LET X$="" 4599 RETURN 4630 IF Z=1 THEN LET Z=0 7480 RETURN 7510 LET Y$="" 7512 FOR J=1 TO 704 7514 LET X=CODE Z$(J) 7516 IF X<128 THEN GOTO 7520 7518 IF X>127 THEN GOTO 7530 7520 LET Z$(J)=CHR$ (X+128) 7525 NEXT J 7529 GOTO 7536 7530 IF X=192 THEN LET X=267 7532 LET Z$(J)=CHR$ (X-128) 7535 NEXT J 7536 LET X=119 7539 RETURN 7540 PRINT AT 21,0;"MIX PRINT " 7542 GOSUB 8900 7544 IF X<38 OR X>60 THEN RETURN 7546 POKE 16529,X 7548 LET B=X 7550 GOSUB 2 7552 IF X=0 THEN GOTO 7565 7554 POKE 16563,X 7556 FOR J=1 TO 704 7558 IF Z$(J)=" " THEN GOSUB 4 7560 NEXT J 7562 GOTO 4538 7565 PRINT AT 21,0;CHR$ B;"$ NOT ALLOCATED " 7567 GOSUB 8900 7568 LET X=0 7569 RETURN 7570 GOSUB 7580 7572 FOR J=1 TO 704 7574 LET Z$(J)=CHR$ PEEK (32000+J) 7576 NEXT J 7579 RETURN 7580 IF PEEK 16388+256*PEEK 16389<>32000 THEN GOTO 7590 7589 RETURN 7590 PRINT AT 21,0;"RAMTOP <> 32000 " 7595 STOP 7600 GOSUB 7580 7602 FOR J=1 TO 704 7604 POKE 32000+J,CODE Z$(J) 7606 NEXT J 7609 RETURN 7630 PRINT AT 21,0;"INPUT GRAPHIC TO BE REPLACED " 7632 INPUT X$ 7634 CLS 7636 PRINT Z$ 7638 PRINT AT 21,0;"INPUT NEW GRAPHIC " 7640 INPUT Y$ 7642 FOR J=1 TO 704 7644 IF Z$(J)=X$ THEN LET Z$(J)=Y$ 7646 NEXT J 7649 GOTO 4538 7660 PRINT AT 21,0;"PRINT " 7662 GOSUB 8900 7664 IF X<38 OR X>60 THEN RETURN 7666 POKE 16529,X 7668 LET B=X 7670 GOSUB 2 7672 IF X=0 THEN GOTO 7565 7674 POKE 16583,X 7676 LET X=119 7679 GOTO 6 7690 LET B=A 7691 PRINT AT 21,0;"INPUT DIRECTION " 7692 LET X$="" 7694 GOSUB 8900 7696 IF X<112 OR X>115 THEN GOTO 8910 7700 LET A=100 7702 LET L=1 7704 GOSUB X*30+1000 7706 IF A=68 THEN LET Z$=Z$(33 TO )+Z$(1 TO 32) 7708 IF A=132 THEN LET Z$=Z$(673 TO )+Z$(1 TO 672) 7710 IF A=99 THEN LET Z$=Z$(2 TO )+Z$(1) 7712 IF A=101 THEN LET Z$=Z$(704)+Z$(1 TO 703) 7713 CLS 7714 PRINT Z$ 7719 GOTO 7691 7720 LET X$="' ' .. : :.::.:'':.''.##@@ '' . . :: :..:'::''..'@@##" 7721 LET Y$="" 7722 FOR B=0 TO 21 7723 FOR J=32 TO 1 STEP -1 7724 LET Y$=Y$+Z$(32*B+J) 7725 LET X=CODE Y$(LEN Y$) 7726 IF X>0 AND X<9 AND X<>3 OR X>128 AND X<137 AND X<>131 THEN GOSUB 7740 7727 NEXT J 7728 NEXT B 7729 LET Z$=Y$ 7730 LET Y$="" 7731 LET X$="" 7732 LET X=119 7739 RETURN 7740 FOR K=15 TO 28 7741 IF Y$(LEN Y$)=X$(K) THEN GOTO 7745 7742 NEXT K 7744 RETURN 7745 LET Y$(LEN Y$)=X$(K-14) 7749 RETURN 7750 PRINT AT 21,0;"INPUT FILE NAME " 7752 GOSUB 8900 7754 IF X<38 OR X>60 THEN RETURN 7756 POKE 16529,X 7758 LET B=X 7760 GOSUB 2 7762 IF X=0 THEN GOTO 7770 7764 PRINT AT 21,0;"WARNING: ";CHR$ X;"$ IN USE " 7766 GOSUB 8900 7768 IF X<>B THEN RETURN 7770 POKE 16597,B 7772 LET X$="" 7774 LET X=119 7779 GOTO 8 7810 RETURN 7840 DIM Z$(704) 7849 GOTO 4540 7870 PRINT AT 21,0;"REFS TO BE CLEARED (OR ""ALL"")" 7872 INPUT X$ 7874 IF X$="ALL" THEN LET X$="ABCDEFGHIJKLMNOPQRSTUVW" 7876 FOR J=1 TO LEN X$ 7878 POKE 16614,CODE X$(J) 7880 GOSUB 10 7882 NEXT J 7889 GOTO 4540 8700 GOSUB 8900 8710 IF X=121 THEN RETURN 8720 IF X=116 THEN GOTO 8800 8730 IF X<64 THEN GOTO 8790 8740 LET X$="' ' .. : ..'' :% .::.:'':.''.##~~,,!!;;@@"+CHR$ 117+" AND THEN TO "+CHR$ 114+CHR$ 113+CHR$ 112+CHR$ 115+CHR$ 119+""" OR STEP <=<>>= STOP LPRINT SLOW FAST LLIST **" 8750 FOR J=22 TO 42 8760 IF X=CODE X$(J) THEN GOTO 8780 8770 NEXT J 8779 GOTO 4540 8780 LET X$=X$(J-21) 8785 LET X=0 8789 RETURN 8790 LET X$=CHR$ (X+128) 8799 RETURN 8800 INPUT X$ 8809 RETURN 8900 PAUSE 40000 8901 POKE 16437,255 8902 LET X=CODE INKEY$ 8909 RETURN 8910 LET A=B 8919 RETURN 9000 REM COPYRIGHT N.GODWIN 1982 ```