/* vt220vdu.c - 22:01 GMT +10:00 Fri 23 July 1993 - modifier Geoffrey Tobin */

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

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


#define MoveAbs(x,y) VT100MoveAbs(x,y)

#define SO              '\016'
#define SI              '\017'

#define hpixels         1   /* horizontal pixels per char position */
#define vpixels         5   /* vertical pixels per char position */
#define flag            7
#define hscreenmax      131   /* max horizontal char coordinate */
#define vscreenmax      23    /* max vertical char coordinate */


Static int cursrow, curscol;   /* VT220ShowChar remembers cursor location */
Static int rectcount;
/* keeps a count of VT220ShowRectangle calls;
                                 reset in ShowBitmap */
Static int Bitmap[hscreenmax + 1][vscreenmax + 1];


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

#ifdef __STDC__
Static Void MoveQuick (int screenh, int screenv)
#else
Static Void MoveQuick (screenh, screenv)
    int screenh, screenv;
#endif
{
  /* Move cursor to given screen position.
     We remember the cursor position (cursrow, curscol),
     so we can reduce the output bytes needed to do the next MoveQuick.
     VT220StartGraphics resets the position to an undefined state (cursrow = 0).
     We also reset when the cursor reaches the right edge (= windowwd),
     to avoid possibility of any auto wrap.
  */

  int amount;

  /* first translate DVItoVDU coordinates into actual screen location */
  screenh++;
  screenv++;
  if (cursrow == screenv)
  {
    /* The cursor is on the same line as in previous MoveQuick call,
       so we only need to move left or right,
       and probably just a small amount (if at all).
    */

    if (screenh == curscol)   /* cursor in correct location */
      curscol++;   /* cursor will move right when ch written */
    else if (screenh < curscol)
    {
      /* move cursor left */
      amount = curscol - screenh;
      WriteChar (ESC);
      WriteChar ('[');
      if (amount > 1)
      {
        /* default is 1 col */
	WriteInt (amount);
	curscol += 1 - amount;
      }
      WriteChar ('D');
    }
    else
    {
      amount = screenh - curscol;
      WriteChar (ESC);
      WriteChar ('[');
      if (amount > 1)   /* default is 1 col */
	WriteInt (amount);
      curscol += amount + 1;
      WriteChar ('C');
    }
  }
  else
  {
    /* cursrow undefined or ch on a new line */
    MoveAbs (screenv, screenh);
    cursrow = screenv;
    curscol = screenh + 1;   /* cursor will move right when ch written */
  }
  if (screenh == windowwd)   /* ch will be written at right edge */
    cursrow = 0;
  /* so avoid auto wrap next time around */

  /* move cursor right */

  /* at start of a line, textcolumn = 0, curscol = 1 */
  textcolumn = (curscol > 0 ? curscol - 1 : 0);
}
/* MoveQuick */

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

Static Void ClearBitmap (VOID)
{
  /* Clear the Bitmap. */

  int h, v;

  for (v = 4; v <= vscreenmax; v++)   /* ignore dialogue lines 0..3 */
    for (h = 0; h <= hscreenmax; h++)
      Bitmap[h][v] = 0;
}
/* ClearBitmap */

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

Static Void ShowBitmap (VOID)
{
  /* Display only the flagged characters in the Bitmap. */

  int h, v;

  WriteChar (SO);   /* assume only working over 7 bit comm lines */
  for (v = 4; v <= vscreenmax; v++)
  {
    /* ignore dialogue lines */
    for (h = 0; h <= hscreenmax; h++)
    {
      if ((unsigned)flag < 32 && ((1 << flag) & Bitmap[h][v]) != 0)
      {
        /* send flagged character */
	Bitmap[h][v] &= ~(1 << flag);   /* clear flag */
	MoveQuick (h, v);
	WriteChar (byte3(Bitmap[0][0]) + 32);
      }
    }
  }
  WriteChar (SI);   /* assume only working over 7 bit comm lines */
  WriteFlush();
  rectcount = 0;
}
/* ShowBitmap */

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

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

  ShowBitmap();
}
/* VT220StartText */

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

Void VT220ClearScreen (VOID)
{
  VT100ClearScreen();
  ClearBitmap();   /* reset Bitmap */
}
/* VT220ClearScreen */

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

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

  rectcount = 0;
  cursrow = 0;   /* for MoveQuick */
}
/* VT220StartGraphics */

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

#ifdef __STDC__
Void VT220LoadFont (Char * fontname, int fontsize, double mag,
                    double hscale, double vscale)
#else
Void VT220LoadFont (fontname, fontsize, mag, hscale, vscale)
    Char * fontname; int fontsize; double mag;
    double hscale, vscale;
#endif
{
  /* only one character size available on VT220s, so do nothing */
}
/* VT220LoadFont */

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

#ifdef __STDC__
Void VT220ShowChar (int screenh, int screenv, Char ch)
#else
Void VT220ShowChar (screenh, screenv, ch)
    int screenh, screenv;
    Char ch;
#endif
{
  /* Show the given Terse character (mapped to ASCII) at the given position. */

  if (rectcount > 0)   /* flush Bitmap if VT220ShowRectangle/s are pending */
    ShowBitmap();
  MoveQuick (screenh, screenv / vpixels);
  WriteChar (TeXtoASCII[ch - NUL]);
}
/* VT220ShowChar */

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

#ifdef __STDC__
Void VT220ShowRectangle (int screenh, int screenv, int width, int height,
                         Char ch)
#else
Void VT220ShowRectangle (screenh, screenv, width, height, ch)
    int screenh; int screenv;  /* top left pixel */
    int width; int height;     /* size of rectangle */
    Char ch;                   /* black pixel */
#endif
{
  /* Set the given rectangular Bitmap region.
     DVItoVDU ensures the top left position is visible and the given
     dimensions do not go beyond the window edges.
  */

  int h, v, vrow;

  for (v = screenv; v < screenv + height; v++)
  {
    for (h = screenh; h < screenh + width; h++)
    {
      /* set bit h,v in Bitmap */
      vrow = v / vpixels;
      /* include flag so char will be sent */
      Bitmap[h][vrow] |= (1 << (v % vpixels)) | (1 << flag);
    }
  }
  rectcount++;
  /* avoid too much of a pause before flushing Bitmap */
  if (rectcount == 400)
    ShowBitmap();
}
/* VT220ShowRectangle */

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

Static Void LoadPixels (VOID)
{
  /* Down-load the chunky graphics character set into the VT220. */

  /* gt - WARNING:  re ANSI standard C,
		    and Aix C (even Aix "cc") :
          Watch out for trigraphs:  "??nonletter", where nonletter is
	  one of the nine characters =, /, ', (, ), !, <, > or -.
	  See Kernighan & Ritchie (2nd edition, 1988), page 229.
          "??" followed by "/" is a trigraph that occurs below.
  */

  WriteChar (ESC);
  WriteChar ('P');
  WriteString ("1;1;2;3;2;1{&%C");
  WriteString ("BBBBBBBB/????????;");
  WriteString ("KKKKKKKK/????????;");
  WriteString ("NNNNNNNN/????????;");
  WriteString ("oooooooo/????????;");
  WriteString ("rrrrrrrr/????????;");
  WriteString ("{{{{{{{{/????????;");
  WriteString ("~~~~~~~~/????????;");
  WriteString ("????????");  WriteString ("/BBBBBBBB;");
  WriteString ("BBBBBBBB/BBBBBBBB;");
  WriteString ("KKKKKKKK/BBBBBBBB;");
  WriteString ("NNNNNNNN/BBBBBBBB;");
  WriteString ("oooooooo/BBBBBBBB;");
  WriteString ("rrrrrrrr/BBBBBBBB;");
  WriteString ("{{{{{{{{/BBBBBBBB;");
  WriteString ("~~~~~~~~/BBBBBBBB;");
  WriteString ("????????");  WriteString ("/KKKKKKKK;");
  WriteString ("BBBBBBBB/KKKKKKKK;");
  WriteString ("KKKKKKKK/KKKKKKKK;");
  WriteString ("NNNNNNNN/KKKKKKKK;");
  WriteString ("oooooooo/KKKKKKKK;");
  WriteString ("rrrrrrrr/KKKKKKKK;");
  WriteString ("{{{{{{{{/KKKKKKKK;");
  WriteString ("~~~~~~~~/KKKKKKKK;");
  WriteString ("????????");  WriteString ("/NNNNNNNN;");
  WriteString ("BBBBBBBB/NNNNNNNN;");
  WriteString ("KKKKKKKK/NNNNNNNN;");
  WriteString ("NNNNNNNN/NNNNNNNN;");
  WriteString ("oooooooo/NNNNNNNN;");
  WriteString ("rrrrrrrr/NNNNNNNN;");
  WriteString ("{{{{{{{{/NNNNNNNN;");
  WriteString ("~~~~~~~~/NNNNNNNN");
  WriteChar (ESC);
  WriteChar ('\\');   /* ESC \ */
  WriteChar (ESC);
  WriteString (")&%C");
      /* set as G1 character set */
}
/* LoadPixels */

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

Void VT220ResetVDU (VOID)
{
  /* We don't do a hardware reset, but leave VDU in 80 column mode. */

  /* 80 column mode */
  WriteChar (ESC);
  WriteString ("[?3l");

  textlinewidth = 80;  /* text characters per line */
}
/* VT220ResetVDU */

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

Void InitVT220 (VOID)
{
  /* The dialogue region is the top 4 lines.
     The window region is the remaining area of the screen
     (the bottom 20 rows in Bitmap).
  */

  DVIstatusl = 1;
  windowstatusl = 2;
  messagel = 3;
  commandl = 4;
  bottoml = vscreenmax + 1;

  /* DVItoVDU's coordinate scheme is the same as the VT220 scheme. */

  windowh = 0;
  windowv = vpixels * 4;   /* = height of 4 dialogue lines */
  windowwd = hscreenmax + 1;
  windowht = (vscreenmax + 1) * vpixels - windowv;

  MoveToTextLine = VT100MoveToTextLine;
  ClearTextLine = VT100ClearTextLine;
  ClearScreen    = VT220ClearScreen;
  StartText      = VT220StartText;
  StartGraphics  = VT220StartGraphics;
  LoadFont       = VT220LoadFont;
  ShowChar       = VT220ShowChar;
  ShowRectangle  = VT220ShowRectangle;
  ResetVDU       = VT220ResetVDU;
  LoadPixels();

  /* 132 column mode */
  WriteChar (ESC);
  WriteString ("[?3h");

  textlinewidth = 132;  /* text characters per line */
}
/*InitVT220 */

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

/* end vt220vdu.c */
