/* vt100vdu.c - 20:21 GMT +10:00 Sat 12 Jun 1993 - modifier Geoffrey Tobin */

/* Generic VDU driver - uses BSD curses to drive any text terminal */

#include <curses.h>
#include "config.h"
#include "globals.h"
#include "screenio.h"
#include "vdu.h"

Static int cursrow, curscol;   /* VT100ShowChar remembers cursor location */

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

Void VT100StartText (VOID)
{
  /* We are about to draw text in dialogue region. */
  /* VT100 treats text and graphics the same, so do nothing */
}
/* VT100StartText */

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

#ifdef __STDC__
Void VT100MoveAbs (int row, int col)
#else
Void VT100MoveAbs (row, col)
  int row; int col;
#endif
{
  /* Move cursor to given screen position. */

  WriteChar (ESC);
  WriteChar ('[');
  WriteInt (row);
  WriteChar (';');
  WriteInt (col);
  WriteChar ('H');
  textcolumn = col - 1;  /* textcolumn = 0 at start of line, where col = 1 */
}
/* VT100MoveAbs */

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

#define MoveAbs(X,Y) VT100MoveAbs(X,Y)

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

#ifdef __STDC__
Void VT100MoveToTextLine (int line)
#else
Void VT100MoveToTextLine (line)
  int line;
#endif
{
  /* Move current position to start of given line. */

  MoveAbs (line, 1);
}
/* VT100MoveToTextLine */

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

#ifdef __STDC__
Void VT100ClearTextLine (int line)
#else
Void VT100ClearTextLine (line)
  int line;
#endif
{
  /* Erase given line; note that DVItoVDU does not assume anything about the
     current position at the end of this routine.
  */

  MoveAbs (line, 1);
  /* erase to end of line */
  WriteChar (ESC);
  WriteString ("[K");
}
/* VT100ClearTextLine */

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

Void VT100ClearScreen (VOID)
{
  /* erase entire screen */

  WriteChar (ESC);
  WriteString ("[2J");
}
/* VT100ClearScreen */

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

Void VT100StartGraphics (VOID)
{
  /* We are about to draw in window region.
     VT100 makes no distinction between text and graphics.
     All we do is reset the current cursor position to some undefined state
     for use in the next VT100ShowChar call.
  */

  cursrow = 0;
}
/* VT100StartGraphics */

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

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

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

#ifdef __STDC__
Void VT100ShowChar (int screenh, int screenv, Char ch)
#else
Void VT100ShowChar (screenh, screenv, ch)
  int screenh, screenv;
  Char ch;
#endif
{
  /* Show the given Terse character (mapped to ASCII) at the given position.
     We remember the cursor position (cursrow,curscol) so we can reduce the
     output bytes needed to position the next Terse character.
     VT100StartGraphics 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 VT100ShowChar 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)
    {
      amount = curscol - screenh;
      WriteChar (ESC);
      WriteChar ('[');
      if (amount > 1)  /* default is 1 col */
      {
	WriteInt (amount);
	curscol += 1 - amount;   /* no need if amount = 1 */
      }
      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 */
  WriteChar (TeXtoASCII[ch - NUL]);

  /* move cursor left */
  /* move cursor right */
}
/* VT100ShowChar */

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

#ifdef __STDC__
Void VT100ShowRectangle (int screenh, int screenv, int width, int height,
                         Char ch)
#else
Void VT100ShowRectangle (screenh, screenv, width, height, ch)
  int screenh; int screenv;  /* top left pixel */
  int width; int height;     /* size of rectangle */
  Char ch;                   /* black pixel */
#endif
{
  /* Display the given rectangle using the given black pixel character.
     DVItoVDU ensures the entire rectangle is visible.
  */

  int i, j;

  ch = TeXtoASCII[ch - NUL];   /* first convert TeX ch to ASCII */
  screenh++;
  for (i = 1; i <= height; i++)
  {
    /* adding 1 to screenv here */
    MoveAbs (screenv + i, screenh);   /* move cursor to start of next row */
    for (j = 1; j <= width; j++)
      WriteChar (ch);
  }
}
/* VT100ShowRectangle */

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

Void VT100ResetVDU (VOID)
{
  /* no need to do anything */
}
/* VT100ResetVDU */

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

Void InitGeneric (VOID)
{
  /* The main program only calls this routine after it has parsed the command
     line and successfully opened the given DVI file.
  */

  /* initialize the VDU parameters */

  if (initscr() == ERR) {
    printf(stderr, "Error initializing curses!");

  DVIstatusl = 1;
  windowstatusl = 2;
  messagel = 3;
  commandl = 4;
  bottoml = LINES;   /* = number of text lines */

  textlinewidth = COLS;  /* text characters per line */

  windowh = 0;
  windowv = 4;
  windowwd = COLS;
  windowht = LINES - 4;

  MoveToTextLine = GenericMoveToTextLine;
  ClearTextLine  = GenericClearTextLine;
  ClearScreen    = GenericClearScreen;
  StartText      = GenericStartText;
  StartGraphics  = GenericStartGraphics;
  LoadFont       = GenericLoadFont;
  ShowChar       = GenericShowChar;
  ShowRectangle  = GenericShowRectangle;
  ResetVDU       = GenericResetVDU;

}  /*InitGeneric */

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

/* end genericvdu.c */
