/* vdu.c - VDU driver interface $Id: vdu.c,v 0.2 1997/03/28 03:17:44 tjchol01 Exp $ Authors: Andrew Trevorrow, Ian Dall, Geoffrey Tobin, Tomasz J. Cholewo */ #include "dvgt.h" #include "vdu.h" #include "options.h" #include "screenio.h" /* Exported via "vdu.h" */ boolean vdu_clears_lines; /* Can current VDU clear a single line? */ int maxy, lineht, dragdown; boolean havesentxy; static int oldhiy; /* for remembering old address in SendXY */ static int oldhix, oldloy, charwidth; /* set by LoadFont and used in ShowChar */ static int loadedsize; /* remember alpha size set by last TEK4010LoadFont; VT640, VIS500/550 VDUs don't actually need to worry about this, since they use non-TEK4010 fonts to draw in dialogue region. VIS240, however, uses alpha mode font. */ static int charsize; /* used to select alpha character size */ /*--------------------------------------------------------------------*/ static void Graphic () { WriteChar (GS); /* switch to graphics mode */ } /* Graphic */ /*--------------------------------------------------------------------*/ static void Alpha () { WriteChar (US); /* switch to alphanumeric mode */ } /* Alpha */ /*--------------------------------------------------------------------*/ void SendXY (int x, int y) { /* Translates the given screen address into 4 bytes. havesentxy is used to minimize the number of bytes sent: after the first 4 bytes have been sent, subsequent bytes that don't change need not be sent (except for the low x byte which is always sent). If the high x byte changes then the low y byte must also be sent. */ int hiy, loy, hix, lox; boolean sendhix; /* we assume y is in [0..maxy] and x is in [0..1023] */ hiy = y / 32 + ' '; hix = x / 32 + ' '; loy = (y & 31) + '`'; lox = (x & 31) + '@'; if (havesentxy) { if (hiy != oldhiy) { WriteChar (hiy); oldhiy = hiy; } sendhix = (hix != oldhix); if (loy != oldloy || sendhix) { WriteChar (loy); oldloy = loy; } if (sendhix) { WriteChar (hix); oldhix = hix; } WriteChar (lox); } else { /* SYSDEP: We _assume_ XON/XOFF flow control is _enabled_, to avoid data loss. */ WriteChar (hiy); oldhiy = hiy; WriteChar (loy); oldloy = loy; WriteChar (hix); oldhix = hix; WriteChar (lox); havesentxy = true; /* send first 4 bytes */ } } /* SendXY */ /*--------------------------------------------------------------------*/ void ClearTextLine (int line) { /* Do nothing as NCSA Telnet (version 2.3.0.3) can only clear the entire screen in tek4010 and NOT just a line. Live with the overwriting. In any case, the next DisplayPage will clear and rewrite the status lines. */ } /* ClearTextLine */ /*--------------------------------------------------------------------*/ void ResetVDU () { WriteChar (CAN); WriteChar (CAN); } /* ResetVDU */ /*--------------------------------------------------------------------*/ void StartText () { Alpha (); } /* StartText */ /*--------------------------------------------------------------------*/ void MoveToTextLine (int line) { /* Move cursor to start of given line using lineht. At the end of this routine we must be in alpha mode, and ready to display characters in the default charsize. */ Graphic (); SendXY (0, maxy - line * lineht + 1); textcolumn = 0; WriteChar (ESC); /* reset alpha character size */ WriteChar ('0'); charsize = 0; charwidth = 13; Alpha (); /* back to alpha mode */ } /* MoveToTextLine */ /*--------------------------------------------------------------------*/ void ClearScreen () { #ifdef NCSA_TELNET WriteChar (ESC); WriteChar (FF); /* erase graphics and put in alpha mode */ #endif Graphic (); WriteChar (ESC); /* erase graphics and put in alpha mode */ WriteChar (FF); havesentxy = false; /* ESC FF will home cursor */ charsize = 0; /* ESC FF resets character size */ charwidth = 13; } /* ClearScreen */ /*--------------------------------------------------------------------*/ void StartGraphics () { if (charsize != loadedsize) { /* graphics mode was interrupted */ charsize = loadedsize; dragdown = (charsize + 1) * 5; /* used by VIS500/550 ShowChar */ Graphic (); WriteChar (ESC); WriteChar (charsize + '0'); /* recall last LoadFont character size */ } Graphic (); havesentxy = false; /* safer to send all bytes anew */ } /* StartGraphics */ /*--------------------------------------------------------------------*/ void LoadFont (char *fontname, int fontsize, double mag, double hscale, double vscale) { /* Use the given fontsize to select an appropriate character size (based on horizontal scaling only!) for future TEK4010ShowChar calls. */ int newsize; /* convert fontsize into scaled screen pixels using mag and hscale */ fontsize = (int) (fontsize * mag * hscale + 0.5); /* Choose one of the 4 alpha mode character sizes based on fontsize: charsize max chars/line relative size fontsize range 0 80 x1 0..40 1 40 x2 41..80 2 26 x3 81..120 3 20 x4 121... The fontsize ranges were chosen by trial and error. */ if (fontsize < 41) { newsize = 0; charwidth = 13; /* 1024/80 = 12.8 */ } else if (fontsize < 81) { newsize = 1; charwidth = 26; /* 1024/40 = 25.6 */ } else if (fontsize < 121) { newsize = 2; charwidth = 40; /* 1024/26 = 39.4 */ } else { newsize = 3; charwidth = 52; /* 1024/20 = 51.2 */ } loadedsize = newsize; /* remember in case graphics mode is interrupted */ if (charsize != newsize) { /* change character size */ charsize = newsize; WriteChar (ESC); WriteChar (charsize + '0'); } /* Alpha character reference pts on some emulating VDUs (VIS500/550) are below baselines to allow for descenders. Such VDUs can use dragdown to drag baselines down to TeX reference pts when calling TEK4010ShowChar. */ dragdown = (charsize + 1) * 5; /* used by VIS500/550 TEK4010ShowChar */ Graphic (); /* must return from LoadFont in graphics mode */ } /* LoadFont */ /*--------------------------------------------------------------------*/ void ShowChar (int screenh, int screenv, char ch) { /* Show the given Terse character (mapped to ASCII) at the given ref pt. We use the charwidth set by last TEK4010LoadFont call. */ char newch; /* = TeXtoASCII[ch] */ /* shift character left if it will overlap right edge of screen */ if (screenh + charwidth > 1023) screenh = 1023 - charwidth; /* We no longer _assume_ TEK4010StartGraphics, TEK4010LoadFont, or last TEK4010ShowChar has just sent GS */ Graphic (); SendXY (screenh, maxy - screenv); /* move cursor to ref pt */ Alpha (); /* enter alpha mode */ /* We use TeXtoASCII to map ch into a comparable ASCII character, apart from most of the ? characters which we attempt to simulate. */ newch = TeXtoASCII[ch - NUL]; if (newch != '?') { /* newch is similar to TeX ch */ WriteChar (newch); } else { /* attempt to display something other than ? */ switch (ch) { case 0xb: /* ff, fi, fl, ffi, ffl */ case 0xc: case 0xd: case 0xe: case 0xf: WriteChar ('f'); /* only simulate rest of ligature if room at right edge */ if (screenh + charwidth * 2 <= 1023) { Graphic (); SendXY (screenh + charwidth, maxy - screenv); Alpha (); switch (ch) { case 0xb: /* ff */ WriteChar ('f'); break; case 0xc: /* fi */ WriteChar ('i'); break; case 0xd: /* fl */ WriteChar ('l'); break; case 0xe: case 0xf: WriteChar ('f'); /* only simulate rest of ligature if room at right edge */ if (screenh + charwidth * 3 <= 1023) { Graphic (); SendXY (screenh + charwidth * 2, maxy - screenv); Alpha (); if (ch == 0xe) /* ffi */ WriteChar ('i'); else /* if (ch == 0xf) */ /* ffl */ WriteChar ('l'); } /* fi */ break; } /* switch */ } /* fi */ break; case 0x19: /* German sharp S */ WriteChar ('B'); break; case 0x1a: /* diphthongs: ae, oe, AE, OE */ case 0x1b: case 0x1d: case 0x1e: switch (ch) { case 0x1a: /* ae */ WriteChar ('a'); break; case 0x1b: /* oe */ WriteChar ('o'); break; case 0x1d: /* AE */ WriteChar ('A'); break; case 0x1e: /* OE */ WriteChar ('O'); break; } if (screenh + charwidth * 2 <= 1023) { Graphic (); SendXY (screenh + charwidth, maxy - screenv); Alpha (); switch (ch) { case 0x1a: /* ae */ case 0x1b: /* oe */ WriteChar ('e'); break; case 0x1d: /* AE */ case 0x1e: /* OE */ WriteChar ('E'); break; } } break; case 0x1c: /* Scandinavian slashed o and O */ case 0x1f: switch (ch) { case 0x1c: /* o/ */ WriteChar ('o'); break; case 0x1f: /* O/ */ WriteChar ('O'); break; } Graphic (); SendXY (screenh, maxy - screenv); /* overwrite */ Alpha (); WriteChar ('/'); break; case 0x20: /* Polish suppressed l and L */ WriteChar ('\''); break; case '?': /* question mark */ WriteChar ('?'); default: /* WriteChar ('?'); */ /* show hexadecimal character code, instead of question mark: */ WriteChar ('\\'); /* only simulate rest of ligature if room at right edge */ if (screenh + charwidth * 3 <= 1023) { String outstr; /* ample size */ Graphic (); SendXY (screenh + charwidth * 2, maxy - screenv); Alpha (); sprintf (outstr, "%.2x", ch); WriteChar (outstr[0]); WriteChar (outstr[1]); } break; } /* switch */ } /* fi */ Graphic (); /* must return from ShowChar in graphics mode */ } /* ShowChar */ /*--------------------------------------------------------------------*/ void ShowRectangle (int screenh, int screenv, int width, int height, char ch) { /* Display the given rectangle (_without_ using the given black pixel character). DVItoVDU ensures that the top left position is visible, and that the given dimensions do not go beyond the window edges. */ int i, endpt; /* DVItoVDU ensures width and height > 0 */ if (height < width) { /* show row vectors */ endpt = screenh + width - 1; for (i = 0; i < height; i++) { Graphic (); SendXY (screenh, maxy - screenv - i); /* move cursor to start of row */ SendXY (endpt, maxy - screenv - i); /* draw vector to end of row */ } } else { /* show column vectors */ endpt = maxy - screenv - height + 1; for (i = 0; i < width; i++) { Graphic (); SendXY (screenh + i, maxy - screenv); /* move cursor to start of column */ SendXY (screenh + i, endpt); /* draw vector to end of column */ } } } /* ShowRectangle */ /*--------------------------------------------------------------------*/ void InitVDU () { vdu_clears_lines = false; havesentxy = false; /* for first SendXY call */ charsize = 0; /* the default character size */ loadedsize = charsize; /* for first TEK4010StartGraphics call */ charwidth = 13; /* 1024 / 80 = 12.8 */ maxy = 779; /* some VDUs may want to change this */ lineht = 26; /* 30 text lines; 26 * 30 = 780 */ textlinewidth = 80; /* text characters per line */ /* The dialog region will be the top 4 text lines in Tek mode: Line 1 = DVI status line, Line 2 = window status line, Line 3 = message line, Line 4 = command line. The window region will be text lines 5 to 33 in TEK mode. gt - in NCSA Telnet in TEK mode on my monitor (Viewsonic 5E VGA), only 30 lines fit. If we use line 33, it wraps around! */ /* The following line numbers assume NCSA Telnet is in VT100 mode. */ DVIstatusl = 1; /* DVItoVDU assumes top text line = 1 */ windowstatusl = 2; messagel = 3; commandl = 4; #ifdef VIJAY_BOTTOML bottoml = 33; /* also number of text lines on screen */ #else /* according to gt's experience */ bottoml = 30; /* also number of text lines on screen */ #endif /* The following values assume NCSA Telnet is emulating a Tektronix 4010. Note that windowv must be given a value using DVItoVDU's coordinate scheme, where top left pixel is (0,0). */ /* Approx. height, in TEK4010 pixels, of 4 text lines, viz. 92 (i.e. ~ 4 * 780/34), does not work in the case of NCSA Telnet's Tek mode. Value 115 arrived at by pure trial and error. */ windowv = 115; windowh = 0; windowht = 780 - windowv; windowwd = 1024; textlinewidth = 72; /* text characters per line - a guess */ WriteChar (GS); } /* InitTEK4010emu */ /*--------------------------------------------------------------------*/ /* end vdu.c */