/* Original Author:         Andrew Trevorrow
   Implementation: Modula-2 under VAX/UNIX 4.2 BSD
   Date Started:   June, 1986

   Description:
   Implements the InitREGIS()procedure that initializes the generic VDU routines
   and parameters used in DVItoVDU.
   DVItoVDU assumes text lines start at 1 and increase down the screen.
   The GIGI (VK100), VT125 and VT240 VDUs use ANSI escape sequences to update
   the screen while DVItoVDU is in text mode, so line positions are the same.
   When updating the window in graphics mode (using ShowChar and ShowRectangle),
   DVItoVDU assumes the top left screen pixel is (0,0); h coordinates increase
   to the right and v coordinates increase down.
   The REGIS coordinate scheme for graphics is exactly the same.

   This version converted to C and ported to BSD and System V UNIX by
   some chaps at Kernel Technology up to September 1989.  Contact
   mjh@uk.co.kernel (Mark J. Hewitt) with bug fixes etc.

   Involved were:	Mark J. Hewitt
   			Dave Dixon
			Marc Hadley
*/

#include "def.h"

static char *sccsid[] = "@(#)regisvdu.c	1.1";

extern Void ANSIClearTextLine(),
            ANSIMoveToTextLine();

Void REGISStartText ();
Void REGISClearScreen ();
Void REGISStartGraphics ();
Void REGISLoadFont ();
Void REGISShowChar ();
Void REGISShowRectangle ();
Void REGISResetVDU ();

unsigned int
              charht,		/* set in LoadFont and used in ShowChar */
              lastv;		/* ShowChar remembers last vertical coordinate */

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

void InitREGIS ()
{
/* The dialogue region is the top 4 lines.
   The window region is the remaining area of the screen.
*/

  DVIstatusl = 1;
  windowstatusl = 2;
  messagel = 3;
  commandl = 4;
  bottoml = 24;
/* DVItoVDU's coordinate scheme is the same as the REGIS scheme. */
  windowh = 0;
  windowv = 80;			/* = height of 4 dialogue lines (better for LoadFont
				   if windowv is a multiple of 10) */
  windowwd = 768;
  windowht = 480 - windowv;
  StartText = REGISStartText;
  MoveToTextLine = ANSIMoveToTextLine;
  ClearTextLine = ANSIClearTextLine;
  ClearScreen = REGISClearScreen;
  StartGraphics = REGISStartGraphics;
  LoadFont = REGISLoadFont;
  ShowChar = REGISShowChar;
  ShowRectangle = REGISShowRectangle;
  ResetVDU = REGISResetVDU;

  (*StartGraphics) ();		/* for following REGIS commands */

/* Set Text and Writing attributes to known initial states. */
/* save current Text attributes; will be restored by ResetVDU */
  WriteString ("T(B)");
/* default character set, no italic slant, direction right, default text size */
  WriteString ("T(A0,I0,D0,S1)");
/* solid fill, no alternate, normal, shading disabled, overlay */
  WriteString ("W(P1,A0,N0,S0,V)");

/* Define some macrographs for frequently used strings in ShowRectangle. */
  WriteString ("@.");		/* clear macrograph storage */
  WriteString ("@:E]W(S1)P[@;");/* @E = enable shading for filled rectangle */
  WriteString ("@:D]W(S0)@;");	/* @D = disable shading */
  WriteString ("@:R]V[]V[+@;");	/* @R = mid part of drawing a row vector */
  WriteString ("@:C]V[]V[,+@;");/* @C = mid part of drawing a column vector */

  (*StartText) ();		/* safer to leave in text mode */
}

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

Void REGISStartText ()
{
/* Note that DVItoVDU will only call MoveToTextLine, ClearTextLine,
   ClearScreen and ResetVDU while in text mode.
   We assume VDU will obey ANSI escape sequences while in text mode.
*/

  Write (ESC);
  Write ('\134');		/* leave graphics mode */
}

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

Void REGISClearScreen ()
{
  Write (ESC);
  WriteString ("[2J");		/* erase entire screen */

/* note that VT125 has a separate graphics plane which we need to erase */

  (*StartGraphics) ();		/* switch to REGIS mode */
  WriteString ("S(E)");		/* erase graphics plane */
  (*StartText) ();		/* exit in text mode */
}

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

Void REGISStartGraphics ()
{
/* Note that DVItoVDU will only call LoadFont, ShowChar and ShowRectangle
   while in graphics mode.
*/

  Write (ESC);
  WriteString ("Pp");		/* enter graphics mode */
  lastv = 999999;		/* undefined value for next ShowChar call */
}

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

/*ARGSUSED*/
Void REGISLoadFont (fontname, fontsize, localmag, hscale, vscale)
char *fontname;
unsigned int  fontsize;
float   localmag, hscale, vscale;

/* Use the given information to select an appropriate character size
   (based on horizontal&&  vertical scaling) for future calls of ShowChar.
*/
{
  unsigned int  wd, ht;		/* we will send T ( Swd Hht ) */

  Write ('T');
  Write ('(');

/* scale fontsize horizontally and choose an appropriate text width */
  wd = (int) (((float) fontsize) * localmag * hscale + 0.5) / 9;
  if (wd > 16)
  {
    wd = 16;			/* wd now in 0,1,2,...,16 */
  }
/* larger widths tend to be too big so adjust accordingly (trial and error) */
  if (wd > 1)
  {
    wd = wd / 2;
  }
  Write ('S');
  WriteCard ((unsigned) wd);

/* scale fontsize vertically and choose an appropriate text height */
  ht = (int) (((float) fontsize) * localmag * vscale + 0.5) / 10;
  if (ht < 1)
  {
    ht = 1;			/* ht must not be 0 */
  }
  else
    if (ht > 16)
    {
      ht = 16;			/* ht now in 1,2,...,16 */
    }
  charht = ht * 10;		/* charht now in 10,20,30,...,160 */
/* restrict charht to <= windowv so screenv-charht in ShowChar will be >= 0 */
  if (charht > ((unsigned) windowv))
  {
    charht = windowv;
    ht = windowv / 10;
  }
/* now reduce charht by one fifth to allow for descenders in ShowChar */
  charht = ((charht * 4) / 5) - 1;/* exact if charht is multiple of 10 */
  Write ('H');
  WriteCard (ht);
/* Note that VT125 and GIGI VDUs sometimes vary the vertical thickness of text
   (only for odd ht values???).  VT240 does not; instead, charht is sometimes
   1 pixel too much and baseline won't agree with Box/Full characters!
*/

  Write (')');
}

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

Void REGISShowChar (screenh, screenv, ch)
unsigned int  screenh, screenv;
char  ch;
/* Show the given Terse character (mapped to ASCII) using the given position.
   We remember the vertical position in lastv so we can reduce the output
   bytes needed to position the next Terse character on the same line.
   StartGraphics resets lastv to an undefined state (= 999999).
*/
{
  char  newch;			/* = TeXtoASCII[ch] */

  Write ('P');
  Write ('[');
  WriteCard (screenh);
/* charht allows for descenders and is used to shift ref pt of REGIS ch
   (top left pixel) so that REGIS and TeX baselines will match.
   LoadFont guarantees that screenv - charht >= 0.
*/
  screenv -= charht;
  if (lastv != screenv)
  {				/* we need to send new vertical coordinate */
    Write (',');
    WriteCard (screenv);
    lastv = screenv;		/* remember for next ShowChar call */
  }
  Write (']');
  Write ('T');
  newch = TeXtoASCII[ch];	/* convert TeX ch to ASCII */
  if (newch != '\'')
  {
    Write ('"');		/* open quoted string */
    if (newch != '?')
    {
    /* newch is similar to TeX ch */
      Write (newch);
    }
    else
    {
    /* attempt to display something other than ? */
      switch (ch)
      {
	case '\013': 
	case '\014': 
	case '\015': 
	case '\016': 
	case '\017':  /* ff, fi, fl, ffi, ffl */ ;
	  {
	    Write ('f');
	  /* REGIS doesn't care if no room at right edge */
	    switch (ch)
	    {
	      case '\013': 
		{
		  Write ('f');
		  break;
		}
	      case '\014': 
		{
		  Write ('i');
		  break;
		}
	      case '\015': 
		{
		  Write ('l');
		  break;
		}
	      case '\016': 
	      case '\017': 
		{
		  Write ('f');
		  if (ch == '\016')
		  {
		    Write ('i');
		  }
		  else
		  {
		    Write ('l');
		  }
		}
	    }
	    break;
	  }
	case '\031': 
	  {
	    Write ('B');
	    break;
	  }			/* German sharp S */
	case '\032': 
	case '\033': 
	case '\035': 
	case '\036': 		/* diphthongs: ae, oe, AE, OE */
	  {
	    switch (ch)
	    {
	      case '\032': 
		{
		  Write ('a');
		  break;
		}
	      case '\033': 
		{
		  Write ('o');
		  break;
		}
	      case '\035': 
		{
		  Write ('A');
		  break;
		}
	      case '\036': 
		{
		  Write ('O');
		  break;
		}
	    }
	    switch (ch)
	    {
	      case '\032': 
	      case '\033': 
		{
		  Write ('e');
		  break;
		}
	      case '\035': 
	      case '\036': 
		{
		  Write ('E');
		  break;
		}
	    }

	case '\040': 
	    {
	      Write ('/');
	      break;
	    }			/* Polish suppressed l and L */
	default: 
	    Write ('?');
	  }
      }
    }
    Write ('\'');		/* close quoted string */
  }
  else
  {
    Write ('"');
    Write ('\'');
    Write ('"');		/* send "'" */
  }
}

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

/*ARGSUSED*/
Void REGISShowRectangle (screenh, screenv, width, height, ch)
unsigned int  screenh, screenv,	/* top left pixel */
              width, height;	/* size of rectangle */
char  ch;			/* black pixel */
/* Display the given rectangle (without using the given black pixel character).
   DVItoVDU ensures the top left position is visible and the given
   dimensions do not go beyond the window edges.
*/

{
  if (height == 1)
  {				/* show row vector */
    Write ('P');
    Write ('[');		/* move cursor to start of row */
    WriteCard (screenh);
    Write (',');
    WriteCard (screenv);
  /* call @R macrograph to draw starting pixel and begin row */
    Write ('@');
    Write ('R');
    WriteCard (width - 1);
    Write (']');
  }
  else
    if (width == 1)
    {				/* show column vector */
      Write ('P');
      Write ('[');		/* move cursor to start of column */
      WriteCard (screenh);
      Write (',');
      WriteCard (screenv);
    /* call @C macrograph to draw starting pixel and begin column */
      Write ('@');
      Write ('C');
      WriteCard (height - 1);
      Write (']');
    }
    else
    {				/* assume height and width > 1 and use shading to
				   fill rectangle */
      Write ('P');
      Write ('[');
      Write (',');		/* position to last row */
      WriteCard (screenv + height - 1);
    /* call @E macrograph to define shading reference line and start position
       command that moves to start of first row */
      Write ('@');
      Write ('E');
      WriteCard (screenh);
      Write (',');
      WriteCard (screenv);
    /* call @R macrograph to draw starting pixel and begin rectangle */
      Write ('@');
      Write ('R');
      WriteCard (width - 1);
    /* call @D macrograph to disable shading */
      Write ('@');
      Write ('D');
    }
}

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

Void REGISResetVDU ()
{
/* We don't do a hardware reset, but leave VDU gracefully. */

  (*StartGraphics) ();		/* for following REGIS commands */
  WriteString ("@.");		/* clear macrograph storage */
  WriteString ("T(E)");		/* restore Text attributes saved in InitREGIS() */
  (*StartText) ();		/* safer to leave in text mode */
}

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