/* aed512vdu.c - 20:15 GMT +10:00 Thu 22 July 1993 - modifier Geoffrey Tobin */

/* From input file "../include/globals.p" */

#include "config.h"
#include "globals.h"
#include "screenio.h"
#include "vdu.h"

#define screenht        512   /* change to 483 for smaller AED screen */

#define ALPHA           '\001'   /* SOH = enter Alpha mode */
#define INTER           '\033'   /* ESC = enter Interpreter mode */

#define SAP             "^"   /* select Alpha parameters for char size */
#define MOV             "Q"
/* move CAP to absolute x,y position;
   CAP = Current Access Position */
#define DVA             "A"
    /* draw vector from CAP to absolute x,y position */
#define DFR             "o"
/* draw filled rectangle with one corner at CAP and
   opposite corner at absolute x,y position */
#define SWC             "C"   /* set current writing colour */
#define SBC             "["   /* set background colour */

#define green           '\002'
    /* my writing colour; better than default red */
#define black           '\0'   /* my background colour; also the default */

#define lineht          9   /* height in pixels of my default text line */
#define charwidth1      6
    /* 5*8 font for dialogue region; 85 chars per line */
#define charwidth2      8    /* normal 7*12 font; 64 chars per line */
#define charwidth3      12   /* double 5*8 font; 42 chars per line */
#define charwidth4      16   /* double 7*12 font; 32 chars per line */


Static int maxy;   /* screenht - 1 */
Static int loadedwidth;   /* remember charwidth set by last AED512LoadFont */
Static int charwidth;   /* used to select Alpha font */


/******************************************************************************/

Void AED512StartText (VOID)
{
  /* We are about to draw text in dialogue region. */

  WriteChar (ALPHA);
}
/* AED512StartText */

/******************************************************************************/

#ifdef __STDC__
Static Void OutputXY (int x, int y)
#else
Static Void OutputXY (x, y)
  int x, y;
#endif
{
  /* Assuming non-mnemonic 8-bit encoding (the default),
     send the 3 bytes representing the given x,y address.
  */

  WriteChar (x / 256 * 16 + y / 256);   /* x11,x10,x9,x8,y11,y10,y9,y8 */
  WriteChar (x & 255);                  /* x7 ,x6 ,   ...          ,x0 */
  WriteChar (y & 255);                  /* y7 ,y6 ,   ...          ,y0 */
}
/* OutputXY */

/******************************************************************************/

Static Void SelectAlphaFont (VOID)
{
  /* Select a new Alpha font depending on the current value of charwidth
     and prepare to display Alpha text.
     charwidth is charwidth1 initially; changed in AED512MoveToTextLine and AED512LoadFont.
  */

  textlinewidth = windowwd / charwidth;  /* text characters per line */

  WriteChar (INTER);
  WriteChar ('^');   /* select Alpha parameters */
  switch (charwidth)
  {
    case charwidth1:
      WriteChar ('1');   /* normal sized */
      WriteChar ('5');   /* 5*8 font */
      WriteChar (charwidth1);   /* default hspace */
      WriteChar (lineht);   /* default vspace */
      break;

    case charwidth2:
      WriteChar ('1');   /* normal sized */
      WriteChar ('7');   /* 7*12 font */
      WriteChar (charwidth2);
      WriteChar ('\015');   /* vspace = 13 */
      break;

    case charwidth3:
      WriteChar ('2');   /* double sized */
      WriteChar ('5');   /* 5*8 font */
      WriteChar (charwidth3);
      WriteChar ('\022');   /* vspace = 18 */
      break;

    case charwidth4:
      WriteChar ('2');   /* double sized */
      WriteChar ('7');   /* 7*12 font */
      WriteChar (charwidth4);
      WriteChar ('\032');   /* vspace = 26 */
      break;

    default:
      WriteString ("Bug in AED512VDU! Illegal charwidth!");
      break;
  }
  WriteChar ('L');   /* Alpha cursor position identical with CAP */
  WriteChar (ALPHA);
}
/* SelectAlphaFont */

/******************************************************************************/

#ifdef __STDC__
Void AED512MoveToTextLine (int line)
#else
Void AED512MoveToTextLine (line)
  int line;
#endif
{
  /* Move to start of given text line; at the end of this routine we must
     be ready to display default Alpha characters.
  */

  WriteChar (INTER);
  WriteChar ('Q');
  OutputXY (0, maxy - line * lineht);
  textcolumn = 0;
  charwidth = charwidth1;   /* use default Alpha font */
  SelectAlphaFont();
}
/* AED512MoveToTextLine */

/******************************************************************************/

#ifdef __STDC__
Void AED512ClearTextLine (int line)
#else
Void AED512ClearTextLine (line)
  int line;
#endif
{

  /* Erase given line; note that DVItoVDU does not assume anything about the
     current position at the end of this routine.
  */
  WriteChar (INTER);
  WriteChar ('C');
  WriteChar (black);   /* set writing colour to background temporarily */
  WriteChar ('Q');     /* set CAP to bottom left corner of text line */
  OutputXY (0, maxy - line * lineht - 2);
                       /* ensure g,j,p... descenders are erased */
  WriteChar ('o');     /* draw filled rectangle to top right corner */
  OutputXY (511, maxy - line * lineht + lineht - 3);
  WriteChar ('C');
  WriteChar (green);   /* back to green */
  WriteChar (ALPHA);   /* safer to leave in Alpha mode */
}
/* AED512ClearTextLine */

/******************************************************************************/

Void AED512ClearScreen (VOID)
{
  WriteChar (INTER);
  WriteChar (FF);
  /* erase screen and return cursor to home position;
     also exits Interpreter */
  /* preferable to ERS = '~' which has some problems setting x,y origin */
}
/* AED512ClearScreen */

/******************************************************************************/

Void AED512StartGraphics (VOID)
{
  /* We are about to draw in window region. */

  if (charwidth != loadedwidth)
  {
    /* graphics mode was interrupted */
    charwidth = loadedwidth;
    SelectAlphaFont();   /* restore font selected in last AED512LoadFont */
  }
  WriteChar (INTER);
}
/* AED512StartGraphics */

/******************************************************************************/

#ifdef __STDC__
Void AED512LoadFont (Char * fontname, int fontsize, double mag,
                     double hscale, double vscale)
#else
Void AED512LoadFont (fontname, fontsize, mag, hscale, vscale)
  Char * fontname;
  int fontsize;
  double mag;
  double hscale, vscale;
#endif
{
  /* AED512 uses the given information to select an appropriate character size
     (based on horizontal scaling only!) for future calls of AED512ShowChar.
     DVItoVDU only calls this routine in graphics mode.
  */

  int newwidth;

  /* convert fontsize into scaled screen pixels using mag and hscale */
  fontsize = (int)(fontsize * mag * hscale + 0.5);
  /* Chooose one of the 4 Alpha mode character sizes based on fontsize:
     charwidth    max chars/line      fontsize range
         1             85                0..20
         2             64               21..40
         3             42               41..60
         4             32               61...
     The fontsize ranges were chosen by trial and error.
  */
  if (fontsize < 21)
    newwidth = charwidth1;
  else if (fontsize < 41)
    newwidth = charwidth2;
  else if (fontsize < 61)
    newwidth = charwidth3;
  else
    newwidth = charwidth4;
  loadedwidth = newwidth;   /* remember for AED512ShowChar */
  if (charwidth != newwidth)
  {
    /* change needed */
    charwidth = newwidth;
    SelectAlphaFont();
  }
  WriteChar (INTER);   /* must exit in graphics mode */
}
/* AED512LoadFont */

/******************************************************************************/

#ifdef __STDC__
Void AED512ShowChar (int screenh, int screenv, Char ch)
#else
Void AED512ShowChar (screenh, screenv, ch)
  int screenh, screenv;
  Char ch;
#endif
{
  /* We show the given character (mapping TeX text character to ASCII)
     using the given reference point and the charwidth selected by the
     last AED512LoadFont.
     DVItoVDU only uses this routine in a Terse display.
     Note that Alpha characters g,j,p,q,y have descenders that fall
     below their reference point; when baselines appear near the
     bottom of the screen, the descenders will wrap to the top.
  */

  Char newch;   /* = TeXtoASCII[ch] */

  /* shift character left if it will overlap right edge of screen */
  if (screenh + charwidth > 511)
    screenh = 511 - charwidth;
  /* DVItoVDU only calls AED512ShowChar in graphics mode */
  WriteChar ('Q');
  OutputXY (screenh, maxy - screenv);   /* move cursor to reference point */

  /* We use TeXtoASCII to map ch into a comparable ASCII character, apart
     from most of the ? characters which we attempt to simulate.
  */

  WriteChar (ALPHA);
  newch = TeXtoASCII[ch - NUL];
  if (newch != '?')
  {
    /* newch is similar to TeX ch */
    WriteChar (newch);
  }
  else
  {
    /* attempt to display something other than ? */
    switch (ch)
    {
      case 11:
      case 12:
      case 13:
      case 14:
      case 15:   /* ff, fi, fl, ffi, ffl */
	WriteChar ('f');
	/* only simulate rest of ligature if room at right edge */
	if (screenh + charwidth * 2 - charwidth / 2 <= 511) {
	  WriteChar (INTER);
	  WriteChar ('Q');
	  OutputXY (screenh + charwidth - charwidth / 2, maxy - screenv);
	  WriteChar (ALPHA);
	  switch (ch)
	  {
	    case 0xb:
	      WriteChar ('f');
	      break;

	    case 0xc:
	      WriteChar ('i');
	      break;

	    case 0xd:
	      WriteChar ('l');
	      break;

	    case 0xe:
	    case 0xf:
	      WriteChar ('f');
	      if (screenh + charwidth * 3 - charwidth / 2 * 2 <= 511)
	      {
		WriteChar (INTER);
		WriteChar ('Q');
		OutputXY (screenh + charwidth * 2 - charwidth / 2 * 2,
	 		  maxy - screenv);
		WriteChar (ALPHA);
		if (ch == '\016')
		  WriteChar ('i');
		else
		  WriteChar ('l');
	      }
	      break;
	  }
	}
	break;

      case 0x19:   /* German sharp S */
	WriteChar ('B');
	break;

      case 0x1a:
      case 0x1b:
      case 0x1d:
      case 0x1e:   /* diphthongs: ae, oe, AE, OE */
	switch (ch) {

	case 0x1a:
	  WriteChar ('a');
	  break;

	case 0x1b:
	  WriteChar ('o');
	  break;

	case 0x1d:
	  WriteChar ('A');
	  break;

	case 0x1e:
	  WriteChar ('O');
	  break;
	}
	if (screenh + charwidth * 2 - charwidth / 2 <= 511)
	{
	  WriteChar (INTER);
	  WriteChar ('Q');
	  OutputXY (screenh + charwidth - charwidth / 2, maxy - screenv);
	  WriteChar (ALPHA);
	  switch (ch)
	  {
	    case 0x1a:
	    case 0x1b:
	      WriteChar ('e');
	      break;

	    case 0x1d:
	    case 0x1e:
	      WriteChar ('E');
	      break;
	  }
	}
	break;

      case 0x20:   /* Polish suppressed l and L */
	WriteChar ('\'');
	break;

      default:
	WriteChar ('?');
	break;
    }
  }
  WriteChar (INTER);   /* must exit in graphics mode */
}
/* AED512ShowChar */

/******************************************************************************/

#ifdef __STDC__
Void AED512ShowRectangle (int screenh, int screenv, int width, int height,
                          Char ch)
#else
Void AED512ShowRectangle (screenh, screenv, width, height, ch)
  int screenh, screenv;  /* top left pixel */
  int width, height;     /* size of rectangle */
  Char ch;               /* black pixel */
#endif
{
  /* Display the given rectangle _without_ using the given
     black pixel character.
     We assume that the top left position is correct,
     and that the given dimensions do not go beyond the screen edges.
     We assume DVItoVDU is in graphics mode.
  */

  int pos;

  if (height == 1)
  {
    /* show row vector */
    pos = maxy - screenv;
    WriteChar ('Q');
    OutputXY (screenh, pos);              /* move cursor to start of row */
    WriteChar ('A');
    OutputXY (screenh + width - 1, pos);  /* draw vector to end of row */
    return;
  }
  if (width == 1)
  {
    /* show column vector */
    WriteChar ('Q');
    OutputXY (screenh, maxy - screenv);   /* move cursor to start of column */
    WriteChar ('A');
    OutputXY (screenh, maxy - screenv - height + 1);
                                    	  /* draw vector to end of column */
    return;
  }
  else
  {
    /* draw filled rectangle */
    /* assume height and width > 1 */
    WriteChar ('Q');
    OutputXY (screenh, maxy - screenv);   /* CAP to top left corner */
    WriteChar ('o');
    OutputXY (screenh + width - 1, maxy - screenv - height + 1);
	/* fill to bottom right corner */
  }
}
/* AED512ShowRectangle */

/******************************************************************************/

Void AED512ResetVDU (VOID)
{
  /* We DON'T reset AED512 to power-up state;
     we leave AED using green as the writing colour,
     and set font back to power-up values.
     Such decisions may not please other AED sites,
     but I was talked into them by our AED users (all 2 of them!).
  */

  WriteChar (INTER);
  WriteChar ('^');    /* select Alpha parameters */
  WriteChar ('1');    /* normal sized */
  WriteChar ('7');    /* 7*12 font */
  WriteChar ('\b');   /* hspace = 8 */
  WriteChar ('\f');   /* vspace = 12 */
  WriteChar ('L');    /* Alpha cursor position identical with CAP */
  WriteChar (ALPHA);  /* exit in Alpha mode */
}
/* AED512ResetVDU */

/******************************************************************************/

Void InitAED512 (VOID)
{
  /* The dialogue region will be the top 4 text lines in Alpha mode.
     The window region will be the remaining screen area.
  */

  DVIstatusl = 1;   /* DVItoVDU assumes top text line = 1 */
  windowstatusl = 2;
  messagel = 3;
  commandl = 4;
  maxy = screenht - 1;
  bottoml = screenht / lineht;   /* number of text lines on AED512 screen */

  windowv = lineht * 4 + 5;      /* height in pixels of dialogue region */
  windowh = 0;
  windowht = screenht - windowv;
  windowwd = 512;

  MoveToTextLine = AED512MoveToTextLine;
  ClearTextLine = AED512ClearTextLine;
  ClearScreen    = AED512ClearScreen;
  StartText      = AED512StartText;
  StartGraphics  = AED512StartGraphics;
  LoadFont       = AED512LoadFont;
  ShowChar       = AED512ShowChar;
  ShowRectangle  = AED512ShowRectangle;
  ResetVDU       = AED512ResetVDU;

  WriteChar (INTER);
  WriteChar ('[');   /* make sure black is the background colour */
  WriteChar (black);
  WriteChar ('C');
      /* change writing colour to green; easier to read than red */
  WriteChar (green);
  WriteChar ('(');   /* programmable option */
  WriteChar ('\006');
  WriteChar ('\001');
  /* override any overlapping TEK4010 commands,
                                 regardless of option switch 4! */
  charwidth = charwidth1;   /* font for dialogue region */
  loadedwidth = charwidth;   /* for first AED512StartGraphics call */

  SelectAlphaFont();
}
/*InitAED512 */

/******************************************************************************/

/* end aed512vdu.c */
