! EDWIN driver for baby Cursor Addressable Terminals with no memory.

%external %routine %spec SIGNAL (%integer E, S, X)
%external %routine %spec TTMODE (%integer PARM)
%external %integer %fn %spec TTGET
%external %routine %spec TTPUT (%integer CH)
%external %routine %spec FLUSH OUTPUT
%external %integer %spec DEVICE

! Control characters
%const %integer ESC = 27, DEL = 127, FF = 12, TAB = 9, BS = 8
%const %integer ERASE 550 = 'K'
%const %integer ERASE 200 = 'v'
%const %integer ERASE 120 = '*'
%own %integer ERASE SCREEN = 'v'

! Screen information
%own %integer DEV = 200; ! 200 52 or 550 or 120
%own %integer SX = 0;    !Current device position
%own %integer SY = 0
%own %integer XR = 79;   !Right hand side of device window
%own %integer YT = 23;   ! Top of dev. window.
%own %integer VIS = 0;   !0 if CVP inside VW
%own %byte %integer STYLE = 0, FONT = 0
%own %integer CU = 0, CD = 0, CL = 0, CR = 0; ! Cursor control chars (set at init)
%const %byte %integer %array AS(0:7) = '*', '-', '#', '+', '*' (*)
%const %integer TCS = 1; ! True char size.
%own %integer UP = 'A', DOWN = 'B', LEFT = 'D', RIGHT = 'C'

%routine DO MOVE
   ! Move to current position
   TTPUT (ESC)
   %if DEV=200 %start
       TTPUT('Y'); TTPUT(23-SY+32); TTPUT(SX+32)
   %finish %else %start
       %if DEV=550 %start
           TTPUT('Y'); TTPUT(SX+32); TTPUT(ESC); TTPUT('X'); TTPUT(23-SY+32)
       %finish %else %start
           TTPUT ('='); TTPUT (32+23-SY); TTPUT (SX+32)
       %finish
   %finish
%end

%dynamic %routine KITTEN (%integer COM, X, Y)
   %switch SW(0:15)

   %routine SWAP (%integer %name A, B)
      %integer C
      C = A;   A = B;   B = C
   %end

   %routine DRAW LINE (%integer TX,TY)
      ! This is algorithm 162 in the Collected Algorithms from CACM.
      !
      ! XYMOVE computes the code string required to move the pen of a
      ! digital incremental X-Y plotter from an initial point (XZ,YZ) to
      ! a terminal point (XN,YN) by the "best" approximation to the
      ! straight line between the points. The permitted elemental pen
      ! movement is to an adjacent point in a plane Cartesian point latice,
      ! diagonal moves permitted. 
   
      ! The Algorithm has been modded to draw lines on Visual 200s.
      ! Using horisontal & vertical lines where possible, otherwise '+'.
      ! or on other terminals by filling character positions.

      %integer A,B,D,E,F,T,I,XMOVE,YMOVE,X,Y
      %own %integer %array XCODE(1:16) = 4,0,0,0,0,0,4,0,4,5,5,5,5,5,4,5 
      %own %integer %array YCODE(1:16) = 1,1,0,1,0,2,2,2,2,2,0,2,0,1,1,1
      ! PY,PX+PY,PX,PX+PY,PX,PX+NY,NY,PX+NY,NY,NY+NX,NX,NX+NY,NX,NX+PY,PY,NX+PY

      %routine MOVE (%integer X,Y)
         %const %integer SPLOGE = 15 ; ! All directions set for non v200 terms.
         %byte %integer %name SP

         DO MOVE
         %if DEV=550 %and STYLE=0 %then TTPUT (ESC) %and TTPUT(DEL) %c
                                  %else TTPUT (AS(STYLE))
         SX = SX + 1 %if X=0
         SX = SX - 1 %if X=5
         SY = SY + 1 %if Y=1
         SY = SY - 1 %if Y=2
      %end

      SWAP (SX, TX) %and SWAP (SY, TY) %if SX > TX; ! Optimise mode.
      MOVE (SX, SY) %and %return %if SX=TX %and SY=TY

      A = TX - SX
      B = TY - SY
      D = A + B
      T = B - A
   
      I = 0
      %if B>=0 %then I=2
      %if D>=0 %then I=I+2
      %if T>=0 %then I=I+2
      %if A>=0 %then I=8-I %else I=I+10
   
      A =  -A %if A<0
      B =  -B %if B<0
      F = A + B 
      D = B - A
      %if D>=0 %then T=A %and D=-D %else T= B
      E = 0
   
      XMOVE = XCODE (I-1)
      YMOVE = YCODE (I-1)
      X = XCODE (I)
      Y = YCODE (I)
      %cycle
         A = D + E
         B = T + E + A
         %if B>=0 %start
             E = A
             F = F - 2
             MOVE (X, Y)
         %finish %else %start
             E = E + T
             F = F - 1
             MOVE (XMOVE, YMOVE)
         %finish
         %exit %if F<=0
      %repeat
      MOVE (TX, TY)
   %end

   %return %unless DEVICE=12
   COM = COM & 15
   -> SW(COM)

SW(0): ! Initialise
       TTMODE (1)
       DEV = X
       ERASE SCREEN = ERASE 550 %if DEV = 550
       ERASE SCREEN = ERASE 200 %if DEV = 200
       ERASE SCREEN = ERASE 120 %if DEV = 120
       ! Set the cursor control characters for device
       %if DEV=200 %start
           CU = 'A';   CD = 'B';   CL = 'D';   CR = 'C'
       %finish %else %start
           %if DEV=550 %start
               CU = DEL;   CD = NL;   CL = BS;   CR = TAB
           %finish %else %start
               CU = 'K'&31;   CD = NL;   CL = BS;   CR = FF
               UP = CU;   DOWN = CD;   LEFT = BS;   RIGHT = CR
           %finish
       %finish
       %return

SW(1): !Terminate
       SX = 0
       SY = 0

SW(2): ! Update
       DO MOVE
       FLUSH OUTPUT
        TTMODE (0) %if COM=1
       %return

SW(3): ! New frame
       TTPUT (30) %if DEV=120
       TTPUT (ESC)
       TTPUT (ERASE SCREEN)
       TTPUT (0) %for Y=0,1,20
       FLUSH OUTPUT
       X = 0
       Y = 0
       -> SW(4)

SW(5): ! Line Abs
       DRAW LINE (X, Y)

SW(4): ! Move Abs
       SX  = X
       SY  = Y
       DO MOVE
       VIS = 0
       %return

SW(6): ! Character
       %return %if VIS#0
       TTPUT (X)
       SX = SX + TCS
       VIS = 1 %if SX>XR
       %return

SW(7): ! Attribute  Change
       STYLE = Y&7 %if X = 1
       %return

SW(8): ! Set lower window bounds
       %return

SW(9): ! Set upper device window bounds
       XR = X
       XR = 79 %if XR>79
       YT = Y
       ! Ignore the YT restriction, as terminal will scroll.
       %return

SW(*):
%end

%dynamic %routine KCURSOR (%integer %name CH,X,Y)

   signal (14, 8, dev)
   TTPUT (7);   TTPUT (7)
   DO MOVE
   FLUSH OUTPUT
   X = SX;   Y = SY;
   %cycle
      CH = TTGET
      %exit %if CH >= ' '; ! Key hit, => return
      %continue %if CH#ESC %and DEV=200
      CH = TTGET %if DEV=200; ! The significant character of the ESC sequence.
      %if CH=CU %start
        Y =Y+1 %if Y<23
         TTPUT (ESC) %unless DEV=120;   TTPUT (UP)
      %finish %else %start
         %if CH=CR %start
                X =X+1 %if X<79
                TTPUT (ESC) %unless DEV=120;   TTPUT (RIGHT)
         %finish %else %start
             %if CH=CL %start
                X =X-1 %if X>0
                 TTPUT (ESC) %unless DEV=120;   TTPUT (LEFT)
             %finish %else %start
                 %if CH=CD %start
                    Y =Y-1 %if Y>0
                     TTPUT (ESC) %unless DEV=120;   TTPUT (DOWN)
                 %finish %else %continue
             %finish
         %finish
     %finish
     FLUSH OUTPUT
   %repeat
%end

%end %of %file

